Browse Source

Merge branch 'master' into opt-calendar-bench

pull/3651/head
Steven Kirk 6 years ago
committed by GitHub
parent
commit
3f43c3c959
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 60
      src/Avalonia.Controls/TextBlock.cs
  2. 27
      src/Avalonia.Visuals/Media/TextFormatting/SimpleTextFormatter.cs
  3. 16
      src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs

60
src/Avalonia.Controls/TextBlock.cs

@ -20,6 +20,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty<IBrush> BackgroundProperty =
Border.BackgroundProperty.AddOwner<TextBlock>();
/// <summary>
/// Defines the <see cref="Padding"/> property.
/// </summary>
public static readonly StyledProperty<Thickness> PaddingProperty =
Decorator.PaddingProperty.AddOwner<TextBlock>();
// TODO: Define these attached properties elsewhere (e.g. on a Text class) and AddOwner
// them into TextBlock.
@ -29,7 +35,7 @@ namespace Avalonia.Controls
public static readonly AttachedProperty<FontFamily> FontFamilyProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, FontFamily>(
nameof(FontFamily),
defaultValue: FontFamily.Default,
defaultValue: FontFamily.Default,
inherits: true);
/// <summary>
@ -110,20 +116,31 @@ namespace Avalonia.Controls
static TextBlock()
{
ClipToBoundsProperty.OverrideDefaultValue<TextBlock>(true);
AffectsRender<TextBlock>(
BackgroundProperty,
ForegroundProperty,
FontWeightProperty,
FontSizeProperty,
FontStyleProperty);
BackgroundProperty, ForegroundProperty, FontSizeProperty,
FontWeightProperty, FontStyleProperty, TextWrappingProperty,
TextTrimmingProperty, TextAlignmentProperty, FontFamilyProperty,
TextDecorationsProperty, TextProperty, PaddingProperty);
AffectsMeasure<TextBlock>(
FontSizeProperty, FontWeightProperty, FontStyleProperty,
FontFamilyProperty, TextTrimmingProperty, TextProperty,
PaddingProperty);
Observable.Merge(
TextProperty.Changed,
ForegroundProperty.Changed,
TextAlignmentProperty.Changed,
TextWrappingProperty.Changed,
TextTrimmingProperty.Changed,
FontSizeProperty.Changed,
FontStyleProperty.Changed,
FontWeightProperty.Changed
).AddClassHandler<TextBlock>((x, _) => x.OnTextPropertiesChanged());
FontWeightProperty.Changed,
FontFamilyProperty.Changed,
TextDecorationsProperty.Changed,
PaddingProperty.Changed
).AddClassHandler<TextBlock>((x, _) => x.InvalidateTextLayout());
}
/// <summary>
@ -145,6 +162,15 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Gets or sets the padding to place around the <see cref="Text"/>.
/// </summary>
public Thickness Padding
{
get { return GetValue(PaddingProperty); }
set { SetValue(PaddingProperty, value); }
}
/// <summary>
/// Gets or sets a brush used to paint the control's background.
/// </summary>
@ -363,7 +389,9 @@ namespace Avalonia.Controls
context.FillRectangle(background, new Rect(Bounds.Size));
}
TextLayout?.Draw(context.PlatformImpl, new Point());
var padding = Padding;
TextLayout?.Draw(context.PlatformImpl, new Point(padding.Left, padding.Top));
}
/// <summary>
@ -412,6 +440,10 @@ namespace Avalonia.Controls
return new Size();
}
var padding = Padding;
availableSize = availableSize.Deflate(padding);
if (_constraint != availableSize)
{
InvalidateTextLayout();
@ -419,19 +451,17 @@ namespace Avalonia.Controls
_constraint = availableSize;
return TextLayout?.Bounds.Size ?? Size.Empty;
var measuredSize = TextLayout?.Bounds.Size ?? Size.Empty;
return measuredSize.Inflate(padding);
}
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
InvalidateTextLayout();
InvalidateMeasure();
}
private void OnTextPropertiesChanged()
{
InvalidateTextLayout();
InvalidateMeasure();
}
}

27
src/Avalonia.Visuals/Media/TextFormatting/SimpleTextFormatter.cs

@ -201,18 +201,17 @@ namespace Avalonia.Media.TextFormatting
var availableWidth = paragraphWidth;
var currentWidth = 0.0;
var runIndex = 0;
var length = 0;
while (runIndex < textRuns.Count)
{
var currentRun = textRuns[runIndex];
currentWidth += currentRun.GlyphRun.Bounds.Width;
if (currentWidth > availableWidth)
if (currentWidth + currentRun.GlyphRun.Bounds.Width > availableWidth)
{
var measuredLength = MeasureText(currentRun, paragraphWidth);
var measuredLength = MeasureText(currentRun, paragraphWidth - currentWidth);
if (measuredLength < text.End)
if (measuredLength < currentRun.Text.Length)
{
var currentBreakPosition = -1;
@ -241,15 +240,19 @@ namespace Avalonia.Media.TextFormatting
}
}
var splitResult = SplitTextRuns(textRuns, measuredLength);
length += measuredLength;
var splitResult = SplitTextRuns(textRuns, length);
var textLineMetrics =
TextLineMetrics.Create(splitResult.First, paragraphWidth, paragraphProperties.TextAlignment);
return new SimpleTextLine(text.Take(measuredLength), splitResult.First, textLineMetrics);
return new SimpleTextLine(text.Take(length), splitResult.First, textLineMetrics);
}
availableWidth -= currentRun.GlyphRun.Bounds.Width;
currentWidth += currentRun.GlyphRun.Bounds.Width;
length += currentRun.GlyphRun.Characters.Length;
runIndex++;
}
@ -281,12 +284,18 @@ namespace Avalonia.Media.TextFormatting
if (measuredWidth + advance > availableWidth)
{
index--;
break;
}
measuredWidth += advance;
}
if(index < 0)
{
return 0;
}
var cluster = textRun.GlyphRun.GlyphClusters[index];
var characterHit = textRun.GlyphRun.FindNearestCharacterHit(cluster, out _);
@ -355,7 +364,7 @@ namespace Avalonia.Media.TextFormatting
continue;
}
var firstCount = currentRun.GlyphRun.Characters.Length > 1 ? i + 1 : i;
var firstCount = currentRun.GlyphRun.Characters.Length >= 1 ? i + 1 : i;
var first = new ShapedTextRun[firstCount];

16
src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs

@ -233,6 +233,12 @@ namespace Avalonia.Media.TextFormatting
var textLine = TextFormatter.Current.FormatLine(textSource, 0, MaxWidth, _paragraphProperties);
if (!double.IsPositiveInfinity(MaxHeight) && bottom + textLine.LineMetrics.Size.Height > MaxHeight)
{
currentPosition = _text.Length;
break;
}
UpdateBounds(textLine, ref left, ref right, ref bottom);
textLines.Add(textLine);
@ -253,17 +259,17 @@ namespace Avalonia.Media.TextFormatting
{
var emptyTextLine = CreateEmptyTextLine(currentPosition);
if (!double.IsPositiveInfinity(MaxHeight) && bottom + emptyTextLine.LineMetrics.Size.Height > MaxHeight)
{
break;
}
UpdateBounds(emptyTextLine, ref left, ref right, ref bottom);
textLines.Add(emptyTextLine);
break;
}
if (!double.IsPositiveInfinity(MaxHeight) && MaxHeight < Bounds.Height)
{
break;
}
}
Bounds = new Rect(left, 0, right, bottom);

Loading…
Cancel
Save