Selaa lähdekoodia

Text hit testing fixes

Benedikt Stebner 3 vuotta sitten
vanhempi
sitoutus
17b9f246f3

+ 11 - 4
src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs

@@ -407,6 +407,7 @@ namespace Avalonia.Media.TextFormatting
             var currentPosition = FirstTextSourceIndex;
             var currentPosition = FirstTextSourceIndex;
             var currentRect = Rect.Empty;
             var currentRect = Rect.Empty;
             var startX = Start;
             var startX = Start;
+            var runStart = startX;
 
 
             //A portion of the line is covered.
             //A portion of the line is covered.
             for (var index = 0; index < TextRuns.Count; index++)
             for (var index = 0; index < TextRuns.Count; index++)
@@ -431,7 +432,7 @@ namespace Avalonia.Media.TextFormatting
                     {
                     {
                         case ShapedTextCharacters when currentRun is ShapedTextCharacters:
                         case ShapedTextCharacters when currentRun is ShapedTextCharacters:
                             {
                             {
-                                if (nextRun.Text.Start < currentRun.Text.Start && firstTextSourceCharacterIndex + textLength < currentRun.Text.End)
+                                if (nextRun.Text.Start < currentRun.Text.Start && firstTextSourceCharacterIndex + textLength < currentRun.Text.End && _flowDirection == FlowDirection.LeftToRight)
                                 {
                                 {
                                     goto skip;
                                     goto skip;
                                 }
                                 }
@@ -480,7 +481,7 @@ namespace Avalonia.Media.TextFormatting
                     case ShapedTextCharacters shapedRun:
                     case ShapedTextCharacters shapedRun:
                         {
                         {
                             endOffset = shapedRun.GlyphRun.GetDistanceFromCharacterHit(
                             endOffset = shapedRun.GlyphRun.GetDistanceFromCharacterHit(
-                                shapedRun.ShapedBuffer.IsLeftToRight ?
+                               shapedRun.ShapedBuffer.IsLeftToRight ?
                                     new CharacterHit(firstTextSourceCharacterIndex + textLength) :
                                     new CharacterHit(firstTextSourceCharacterIndex + textLength) :
                                     new CharacterHit(firstTextSourceCharacterIndex));
                                     new CharacterHit(firstTextSourceCharacterIndex));
 
 
@@ -493,7 +494,7 @@ namespace Avalonia.Media.TextFormatting
 
 
                             startX += startOffset;
                             startX += startOffset;
 
 
-                            var characterHit = shapedRun.GlyphRun.IsLeftToRight ?
+                            var characterHit = _flowDirection == FlowDirection.LeftToRight ?
                                 shapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _) :
                                 shapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _) :
                                 shapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _);
                                 shapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _);
 
 
@@ -580,6 +581,11 @@ namespace Avalonia.Media.TextFormatting
                     {
                     {
                         break;
                         break;
                     }
                     }
+
+                    if (_flowDirection == FlowDirection.RightToLeft)
+                    {
+                        endX += currentRun.Size.Width - endOffset;
+                    }
                 }
                 }
                 else
                 else
                 {
                 {
@@ -591,8 +597,9 @@ namespace Avalonia.Media.TextFormatting
                     endX += currentRun.Size.Width - endOffset;
                     endX += currentRun.Size.Width - endOffset;
                 }
                 }
 
 
-                lastDirection = currentDirection;
                 startX = endX;
                 startX = endX;
+                lastDirection = currentDirection;
+                runStart += currentRun.Size.Width;
             }
             }
 
 
             return result;
             return result;

+ 2 - 2
src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs

@@ -16,7 +16,7 @@ namespace Avalonia.Media.TextFormatting
         {
         {
             Typeface = typeface;
             Typeface = typeface;
             FontRenderingEmSize = fontRenderingEmSize;
             FontRenderingEmSize = fontRenderingEmSize;
-            BidLevel = bidiLevel;
+            BidiLevel = bidiLevel;
             Culture = culture;
             Culture = culture;
             IncrementalTabWidth = incrementalTabWidth;
             IncrementalTabWidth = incrementalTabWidth;
         }
         }
@@ -33,7 +33,7 @@ namespace Avalonia.Media.TextFormatting
         /// <summary>
         /// <summary>
         /// Get the bidi level of the text.
         /// Get the bidi level of the text.
         /// </summary>
         /// </summary>
-        public sbyte BidLevel { get; }
+        public sbyte BidiLevel { get; }
 
 
         /// <summary>
         /// <summary>
         /// Get the culture.
         /// Get the culture.

+ 0 - 5
src/Avalonia.Controls/Presenters/TextPresenter.cs

@@ -515,11 +515,6 @@ namespace Avalonia.Controls.Presenters
 
 
         protected override Size MeasureOverride(Size availableSize)
         protected override Size MeasureOverride(Size availableSize)
         {
         {
-            if (string.IsNullOrEmpty(Text))
-            {
-                return new Size();
-            }
-
             _constraint = availableSize;
             _constraint = availableSize;
 
 
             _textLayout = null;
             _textLayout = null;

+ 5 - 1
src/Avalonia.Controls/TextBlock.cs

@@ -631,7 +631,11 @@ namespace Avalonia.Controls
                 return finalSize;
                 return finalSize;
             }
             }
 
 
-            _constraint = new Size(finalSize.Width, double.PositiveInfinity);
+            var scale = LayoutHelper.GetLayoutScale(this);
+
+            var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale);
+
+            _constraint = new Size(finalSize.Deflate(padding).Width, double.PositiveInfinity);
 
 
             _textLayout = null;
             _textLayout = null;
 
 

+ 1 - 1
src/Avalonia.Headless/HeadlessPlatformStubs.cs

@@ -137,7 +137,7 @@ namespace Avalonia.Headless
         {
         {
             var typeface = options.Typeface;
             var typeface = options.Typeface;
             var fontRenderingEmSize = options.FontRenderingEmSize;
             var fontRenderingEmSize = options.FontRenderingEmSize;
-            var bidiLevel = options.BidLevel;
+            var bidiLevel = options.BidiLevel;
 
 
             return new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel);
             return new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel);
         }
         }

+ 1 - 1
src/Skia/Avalonia.Skia/TextShaperImpl.cs

@@ -16,7 +16,7 @@ namespace Avalonia.Skia
         {
         {
             var typeface = options.Typeface;
             var typeface = options.Typeface;
             var fontRenderingEmSize = options.FontRenderingEmSize;
             var fontRenderingEmSize = options.FontRenderingEmSize;
-            var bidiLevel = options.BidLevel;
+            var bidiLevel = options.BidiLevel;
             var culture = options.Culture;
             var culture = options.Culture;
 
 
             using (var buffer = new Buffer())
             using (var buffer = new Buffer())

+ 1 - 1
src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs

@@ -16,7 +16,7 @@ namespace Avalonia.Direct2D1.Media
         {
         {
             var typeface = options.Typeface;
             var typeface = options.Typeface;
             var fontRenderingEmSize = options.FontRenderingEmSize;
             var fontRenderingEmSize = options.FontRenderingEmSize;
-            var bidiLevel = options.BidLevel;
+            var bidiLevel = options.BidiLevel;
             var culture = options.Culture;
             var culture = options.Culture;
 
 
             using (var buffer = new Buffer())
             using (var buffer = new Buffer())

+ 32 - 18
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

@@ -718,31 +718,45 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
             using (Start())
             using (Start())
             {
             {
                 var defaultProperties = new GenericTextRunProperties(Typeface.Default);
                 var defaultProperties = new GenericTextRunProperties(Typeface.Default);
-                var text = "0123".AsMemory();
-                var ltrOptions = new TextShaperOptions(Typeface.Default.GlyphTypeface, 10, 0, CultureInfo.CurrentCulture);
-                var rtlOptions = new TextShaperOptions(Typeface.Default.GlyphTypeface, 10, 1, CultureInfo.CurrentCulture);
-
-                var textRuns = new List<TextRun>
-                {
-                    new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice<char>(text), ltrOptions), defaultProperties),
-                    new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice<char>(text, text.Length, text.Length), ltrOptions), defaultProperties),
-                    new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice<char>(text, text.Length * 2, text.Length), rtlOptions), defaultProperties),
-                    new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice<char>(text, text.Length * 3, text.Length), ltrOptions), defaultProperties)
-                };
-
-
-                var textSource = new FixedRunsTextSource(textRuns);
+                var text = "אאא AAA";
+                var textSource = new SingleBufferTextSource(text, defaultProperties);
 
 
                 var formatter = new TextFormatterImpl();
                 var formatter = new TextFormatterImpl();
 
 
                 var textLine =
                 var textLine =
-                    formatter.FormatLine(textSource, 0, double.PositiveInfinity,
-                        new GenericTextParagraphProperties(defaultProperties));
+                    formatter.FormatLine(textSource, 0, 200,
+                        new GenericTextParagraphProperties(FlowDirection.RightToLeft, TextAlignment.Left, true, true, defaultProperties, TextWrapping.NoWrap, 0, 0));
 
 
-                var textBounds = textLine.GetTextBounds(0, text.Length * 4);
+                var textBounds = textLine.GetTextBounds(0, text.Length);
 
 
-                Assert.Equal(3, textBounds.Count);
+                Assert.Equal(2, textBounds.Count);
                 Assert.Equal(textLine.WidthIncludingTrailingWhitespace, textBounds.Sum(x => x.Rectangle.Width));
                 Assert.Equal(textLine.WidthIncludingTrailingWhitespace, textBounds.Sum(x => x.Rectangle.Width));
+
+                textBounds = textLine.GetTextBounds(0, 4);
+
+                var secondRun = textLine.TextRuns[1] as ShapedTextCharacters;
+
+                Assert.Equal(1, textBounds.Count);
+                Assert.Equal(secondRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width));
+
+                textBounds = textLine.GetTextBounds(4, 3);
+
+                var firstRun = textLine.TextRuns[0] as ShapedTextCharacters;
+
+                Assert.Equal(1, textBounds.Count);
+                Assert.Equal(firstRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width));
+
+                textBounds = textLine.GetTextBounds(0, 5);
+
+                Assert.Equal(2, textBounds.Count);
+
+                Assert.Equal(7.201171875, textBounds[0].Rectangle.Width);
+
+                Assert.Equal(textLine.Start, textBounds[0].Rectangle.Left);
+
+                Assert.Equal(secondRun.Size.Width, textBounds[1].Rectangle.Width);
+
+                Assert.Equal(textLine.Start + firstRun.Size.Width, textBounds[1].Rectangle.Left);
             }
             }
         }
         }
 
 

+ 1 - 1
tests/Avalonia.UnitTests/HarfBuzzTextShaperImpl.cs

@@ -15,7 +15,7 @@ namespace Avalonia.UnitTests
         {
         {
             var typeface = options.Typeface;
             var typeface = options.Typeface;
             var fontRenderingEmSize = options.FontRenderingEmSize;
             var fontRenderingEmSize = options.FontRenderingEmSize;
-            var bidiLevel = options.BidLevel;
+            var bidiLevel = options.BidiLevel;
             var culture = options.Culture;
             var culture = options.Culture;
 
 
             using (var buffer = new Buffer())
             using (var buffer = new Buffer())

+ 1 - 1
tests/Avalonia.UnitTests/MockTextShaperImpl.cs

@@ -11,7 +11,7 @@ namespace Avalonia.UnitTests
         {
         {
             var typeface = options.Typeface;
             var typeface = options.Typeface;
             var fontRenderingEmSize = options.FontRenderingEmSize;
             var fontRenderingEmSize = options.FontRenderingEmSize;
-            var bidiLevel = options.BidLevel;
+            var bidiLevel = options.BidiLevel;
 
 
             var shapedBuffer = new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel);
             var shapedBuffer = new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel);