|
@@ -56,7 +56,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
public override double Height => _textLineMetrics.Height;
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
- public override int NewLineLength => _textLineMetrics.NewLineLength;
|
|
|
+ public override int NewLineLength => _textLineMetrics.NewlineLength;
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
public override double OverhangAfter => 0;
|
|
@@ -180,7 +180,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
{
|
|
|
var lastRun = _textRuns[_textRuns.Count - 1];
|
|
|
|
|
|
- return GetRunCharacterHit(lastRun, FirstTextSourceIndex + Length - lastRun.TextSourceLength, lastRun.Size.Width);
|
|
|
+ return GetRunCharacterHit(lastRun, FirstTextSourceIndex + Length - lastRun.Length, lastRun.Size.Width);
|
|
|
}
|
|
|
|
|
|
// process hit that happens within the line
|
|
@@ -195,18 +195,18 @@ namespace Avalonia.Media.TextFormatting
|
|
|
if (currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight)
|
|
|
{
|
|
|
var rightToLeftIndex = i;
|
|
|
- currentPosition += currentRun.TextSourceLength;
|
|
|
+ currentPosition += currentRun.Length;
|
|
|
|
|
|
while (rightToLeftIndex + 1 <= _textRuns.Count - 1)
|
|
|
{
|
|
|
- var nextShaped = _textRuns[rightToLeftIndex + 1] as ShapedTextCharacters;
|
|
|
+ var nextShaped = _textRuns[++rightToLeftIndex] as ShapedTextCharacters;
|
|
|
|
|
|
if (nextShaped == null || nextShaped.ShapedBuffer.IsLeftToRight)
|
|
|
{
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- currentPosition += nextShaped.TextSourceLength;
|
|
|
+ currentPosition += nextShaped.Length;
|
|
|
|
|
|
rightToLeftIndex++;
|
|
|
}
|
|
@@ -223,27 +223,26 @@ namespace Avalonia.Media.TextFormatting
|
|
|
if (currentDistance + currentRun.Size.Width <= distance)
|
|
|
{
|
|
|
currentDistance += currentRun.Size.Width;
|
|
|
- currentPosition -= currentRun.TextSourceLength;
|
|
|
+ currentPosition -= currentRun.Length;
|
|
|
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- characterHit = GetRunCharacterHit(currentRun, currentPosition, distance - currentDistance);
|
|
|
-
|
|
|
- break;
|
|
|
+ return GetRunCharacterHit(currentRun, currentPosition, distance - currentDistance);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (currentDistance + currentRun.Size.Width < distance)
|
|
|
+ characterHit = GetRunCharacterHit(currentRun, currentPosition, distance - currentDistance);
|
|
|
+
|
|
|
+ if (i < _textRuns.Count - 1 && currentDistance + currentRun.Size.Width < distance)
|
|
|
{
|
|
|
currentDistance += currentRun.Size.Width;
|
|
|
- currentPosition += currentRun.TextSourceLength;
|
|
|
+
|
|
|
+ currentPosition += currentRun.Length;
|
|
|
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- characterHit = GetRunCharacterHit(currentRun, currentPosition, distance - currentDistance);
|
|
|
-
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -264,10 +263,10 @@ namespace Avalonia.Media.TextFormatting
|
|
|
|
|
|
if (shapedRun.GlyphRun.IsLeftToRight)
|
|
|
{
|
|
|
- offset = Math.Max(0, currentPosition - shapedRun.Text.Start);
|
|
|
+ offset = Math.Max(0, currentPosition - shapedRun.GlyphRun.Metrics.FirstCluster);
|
|
|
}
|
|
|
|
|
|
- characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength);
|
|
|
+ characterHit = new CharacterHit(offset + characterHit.FirstCharacterIndex, characterHit.TrailingLength);
|
|
|
|
|
|
break;
|
|
|
}
|
|
@@ -279,7 +278,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- characterHit = new CharacterHit(currentPosition, run.TextSourceLength);
|
|
|
+ characterHit = new CharacterHit(currentPosition, run.Length);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
@@ -334,14 +333,14 @@ namespace Avalonia.Media.TextFormatting
|
|
|
|
|
|
rightToLeftWidth -= currentRun.Size.Width;
|
|
|
|
|
|
- if (currentPosition + currentRun.TextSourceLength >= characterIndex)
|
|
|
+ if (currentPosition + currentRun.Length >= characterIndex)
|
|
|
{
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- currentPosition += currentRun.TextSourceLength;
|
|
|
+ currentPosition += currentRun.Length;
|
|
|
|
|
|
- remainingLength -= currentRun.TextSourceLength;
|
|
|
+ remainingLength -= currentRun.Length;
|
|
|
|
|
|
i--;
|
|
|
}
|
|
@@ -350,7 +349,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (currentPosition + currentRun.TextSourceLength >= characterIndex &&
|
|
|
+ if (currentPosition + currentRun.Length >= characterIndex &&
|
|
|
TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength, flowDirection, out var distance, out _))
|
|
|
{
|
|
|
return Math.Max(0, currentDistance + distance);
|
|
@@ -358,8 +357,8 @@ namespace Avalonia.Media.TextFormatting
|
|
|
|
|
|
//No hit hit found so we add the full width
|
|
|
currentDistance += currentRun.Size.Width;
|
|
|
- currentPosition += currentRun.TextSourceLength;
|
|
|
- remainingLength -= currentRun.TextSourceLength;
|
|
|
+ currentPosition += currentRun.Length;
|
|
|
+ remainingLength -= currentRun.Length;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
@@ -383,8 +382,8 @@ namespace Avalonia.Media.TextFormatting
|
|
|
|
|
|
//No hit hit found so we add the full width
|
|
|
currentDistance -= currentRun.Size.Width;
|
|
|
- currentPosition += currentRun.TextSourceLength;
|
|
|
- remainingLength -= currentRun.TextSourceLength;
|
|
|
+ currentPosition += currentRun.Length;
|
|
|
+ remainingLength -= currentRun.Length;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -412,16 +411,16 @@ namespace Avalonia.Media.TextFormatting
|
|
|
{
|
|
|
currentGlyphRun = shapedTextCharacters.GlyphRun;
|
|
|
|
|
|
- if (currentPosition + remainingLength <= currentPosition + currentRun.Text.Length)
|
|
|
+ if (currentPosition + remainingLength <= currentPosition + currentRun.Length)
|
|
|
{
|
|
|
- characterHit = new CharacterHit(currentRun.Text.Start + remainingLength);
|
|
|
+ characterHit = new CharacterHit(currentPosition + remainingLength);
|
|
|
|
|
|
distance = currentGlyphRun.GetDistanceFromCharacterHit(characterHit);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- if (currentPosition + remainingLength == currentPosition + currentRun.Text.Length && isTrailingHit)
|
|
|
+ if (currentPosition + remainingLength == currentPosition + currentRun.Length && isTrailingHit)
|
|
|
{
|
|
|
if (currentGlyphRun.IsLeftToRight || flowDirection == FlowDirection.RightToLeft)
|
|
|
{
|
|
@@ -440,7 +439,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- if (characterIndex == currentPosition + currentRun.TextSourceLength)
|
|
|
+ if (characterIndex == currentPosition + currentRun.Length)
|
|
|
{
|
|
|
distance = currentRun.Size.Width;
|
|
|
|
|
@@ -479,17 +478,22 @@ namespace Avalonia.Media.TextFormatting
|
|
|
{
|
|
|
case ShapedTextCharacters shapedRun:
|
|
|
{
|
|
|
- characterHit = shapedRun.GlyphRun.GetNextCaretCharacterHit(characterHit);
|
|
|
+ nextCharacterHit = shapedRun.GlyphRun.GetNextCaretCharacterHit(characterHit);
|
|
|
break;
|
|
|
}
|
|
|
default:
|
|
|
{
|
|
|
- characterHit = new CharacterHit(currentPosition + currentRun.TextSourceLength);
|
|
|
+ nextCharacterHit = new CharacterHit(currentPosition + currentRun.Length);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return characterHit;
|
|
|
+ if (characterHit.FirstCharacterIndex + characterHit.TrailingLength == nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength)
|
|
|
+ {
|
|
|
+ return characterHit;
|
|
|
+ }
|
|
|
+
|
|
|
+ return nextCharacterHit;
|
|
|
}
|
|
|
|
|
|
/// <inheritdoc/>
|
|
@@ -542,200 +546,182 @@ namespace Avalonia.Media.TextFormatting
|
|
|
var characterLength = 0;
|
|
|
var endX = startX;
|
|
|
|
|
|
- var currentShapedRun = currentRun as ShapedTextCharacters;
|
|
|
-
|
|
|
TextRunBounds currentRunBounds;
|
|
|
|
|
|
double combinedWidth;
|
|
|
|
|
|
- if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex)
|
|
|
- {
|
|
|
- startX += currentRun.Size.Width;
|
|
|
-
|
|
|
- currentPosition += currentRun.TextSourceLength;
|
|
|
-
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if (currentShapedRun != null && !currentShapedRun.ShapedBuffer.IsLeftToRight)
|
|
|
+ if (currentRun is ShapedTextCharacters currentShapedRun)
|
|
|
{
|
|
|
- var rightToLeftIndex = index;
|
|
|
- var rightToLeftWidth = currentShapedRun.Size.Width;
|
|
|
+ var firstCluster = currentShapedRun.GlyphRun.Metrics.FirstCluster;
|
|
|
|
|
|
- while (rightToLeftIndex + 1 <= _textRuns.Count - 1 && _textRuns[rightToLeftIndex + 1] is ShapedTextCharacters nextShapedRun)
|
|
|
+ if (currentPosition + currentRun.Length <= firstTextSourceIndex)
|
|
|
{
|
|
|
- if (nextShapedRun == null || nextShapedRun.ShapedBuffer.IsLeftToRight)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
+ startX += currentRun.Size.Width;
|
|
|
|
|
|
- rightToLeftIndex++;
|
|
|
+ currentPosition += currentRun.Length;
|
|
|
|
|
|
- rightToLeftWidth += nextShapedRun.Size.Width;
|
|
|
-
|
|
|
- if (currentPosition + nextShapedRun.TextSourceLength > firstTextSourceIndex + textLength)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- currentShapedRun = nextShapedRun;
|
|
|
+ continue;
|
|
|
}
|
|
|
|
|
|
- startX = startX + rightToLeftWidth;
|
|
|
+ if (currentShapedRun.ShapedBuffer.IsLeftToRight)
|
|
|
+ {
|
|
|
+ var startIndex = firstCluster + Math.Max(0, firstTextSourceIndex - currentPosition);
|
|
|
|
|
|
- currentRunBounds = GetRightToLeftTextRunBounds(currentShapedRun, startX, firstTextSourceIndex, characterIndex, currentPosition, remainingLength);
|
|
|
+ double startOffset;
|
|
|
|
|
|
- remainingLength -= currentRunBounds.Length;
|
|
|
- currentPosition = currentRunBounds.TextSourceCharacterIndex + currentRunBounds.Length;
|
|
|
- endX = currentRunBounds.Rectangle.Right;
|
|
|
- startX = currentRunBounds.Rectangle.Left;
|
|
|
+ double endOffset;
|
|
|
|
|
|
- var rightToLeftRunBounds = new List<TextRunBounds> { currentRunBounds };
|
|
|
+ startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
|
|
|
|
|
|
- for (int i = rightToLeftIndex - 1; i >= index; i--)
|
|
|
- {
|
|
|
- currentShapedRun = TextRuns[i] as ShapedTextCharacters;
|
|
|
+ endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
|
|
|
|
|
|
- if(currentShapedRun == null)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ startX += startOffset;
|
|
|
|
|
|
- currentRunBounds = GetRightToLeftTextRunBounds(currentShapedRun, startX, firstTextSourceIndex, characterIndex, currentPosition, remainingLength);
|
|
|
+ endX += endOffset;
|
|
|
|
|
|
- rightToLeftRunBounds.Insert(0, currentRunBounds);
|
|
|
+ var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _);
|
|
|
|
|
|
- remainingLength -= currentRunBounds.Length;
|
|
|
- startX = currentRunBounds.Rectangle.Left;
|
|
|
+ var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _);
|
|
|
|
|
|
- currentPosition += currentRunBounds.Length;
|
|
|
+ characterLength = Math.Abs(endHit.FirstCharacterIndex + endHit.TrailingLength - startHit.FirstCharacterIndex - startHit.TrailingLength);
|
|
|
+
|
|
|
+ currentDirection = FlowDirection.LeftToRight;
|
|
|
}
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var rightToLeftIndex = index;
|
|
|
+ var rightToLeftWidth = currentShapedRun.Size.Width;
|
|
|
|
|
|
- combinedWidth = endX - startX;
|
|
|
+ while (rightToLeftIndex + 1 <= _textRuns.Count - 1 && _textRuns[rightToLeftIndex + 1] is ShapedTextCharacters nextShapedRun)
|
|
|
+ {
|
|
|
+ if (nextShapedRun == null || nextShapedRun.ShapedBuffer.IsLeftToRight)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- currentRect = new Rect(startX, 0, combinedWidth, Height);
|
|
|
+ rightToLeftIndex++;
|
|
|
|
|
|
- currentDirection = FlowDirection.RightToLeft;
|
|
|
+ rightToLeftWidth += nextShapedRun.Size.Width;
|
|
|
|
|
|
- if (!MathUtilities.IsZero(combinedWidth))
|
|
|
- {
|
|
|
- result.Add(new TextBounds(currentRect, currentDirection, rightToLeftRunBounds));
|
|
|
- }
|
|
|
+ if (currentPosition + nextShapedRun.Length > firstTextSourceIndex + textLength)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- startX = endX;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (currentShapedRun != null)
|
|
|
- {
|
|
|
- var offset = Math.Max(0, firstTextSourceIndex - currentPosition);
|
|
|
+ currentShapedRun = nextShapedRun;
|
|
|
+ }
|
|
|
|
|
|
- currentPosition += offset;
|
|
|
+ startX += rightToLeftWidth;
|
|
|
|
|
|
- var startIndex = currentRun.Text.Start + offset;
|
|
|
+ currentRunBounds = GetRightToLeftTextRunBounds(currentShapedRun, startX, firstTextSourceIndex, characterIndex, currentPosition, remainingLength);
|
|
|
|
|
|
- double startOffset;
|
|
|
- double endOffset;
|
|
|
+ remainingLength -= currentRunBounds.Length;
|
|
|
+ currentPosition = currentRunBounds.TextSourceCharacterIndex + currentRunBounds.Length;
|
|
|
+ endX = currentRunBounds.Rectangle.Right;
|
|
|
+ startX = currentRunBounds.Rectangle.Left;
|
|
|
|
|
|
- if (currentShapedRun.ShapedBuffer.IsLeftToRight)
|
|
|
- {
|
|
|
- startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
|
|
|
+ var rightToLeftRunBounds = new List<TextRunBounds> { currentRunBounds };
|
|
|
|
|
|
- endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
|
|
|
- }
|
|
|
- else
|
|
|
+ for (int i = rightToLeftIndex - 1; i >= index; i--)
|
|
|
{
|
|
|
- endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex));
|
|
|
-
|
|
|
- if (currentPosition < startIndex)
|
|
|
- {
|
|
|
- startOffset = endOffset;
|
|
|
- }
|
|
|
- else
|
|
|
+ if (TextRuns[i] is not ShapedTextCharacters)
|
|
|
{
|
|
|
- startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength));
|
|
|
+ continue;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- startX += startOffset;
|
|
|
+ currentShapedRun = (ShapedTextCharacters)TextRuns[i];
|
|
|
|
|
|
- endX += endOffset;
|
|
|
+ currentRunBounds = GetRightToLeftTextRunBounds(currentShapedRun, startX, firstTextSourceIndex, characterIndex, currentPosition, remainingLength);
|
|
|
|
|
|
- var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _);
|
|
|
- var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _);
|
|
|
+ rightToLeftRunBounds.Insert(0, currentRunBounds);
|
|
|
|
|
|
- characterLength = Math.Abs(endHit.FirstCharacterIndex + endHit.TrailingLength - startHit.FirstCharacterIndex - startHit.TrailingLength);
|
|
|
+ remainingLength -= currentRunBounds.Length;
|
|
|
+ startX = currentRunBounds.Rectangle.Left;
|
|
|
|
|
|
- currentDirection = FlowDirection.LeftToRight;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex)
|
|
|
- {
|
|
|
- startX += currentRun.Size.Width;
|
|
|
+ currentPosition += currentRunBounds.Length;
|
|
|
+ }
|
|
|
|
|
|
- currentPosition += currentRun.TextSourceLength;
|
|
|
+ combinedWidth = endX - startX;
|
|
|
|
|
|
- continue;
|
|
|
- }
|
|
|
+ currentRect = new Rect(startX, 0, combinedWidth, Height);
|
|
|
+
|
|
|
+ currentDirection = FlowDirection.RightToLeft;
|
|
|
|
|
|
- if (currentPosition < firstTextSourceIndex)
|
|
|
+ if (!MathUtilities.IsZero(combinedWidth))
|
|
|
{
|
|
|
- startX += currentRun.Size.Width;
|
|
|
+ result.Add(new TextBounds(currentRect, currentDirection, rightToLeftRunBounds));
|
|
|
}
|
|
|
|
|
|
- if (currentPosition + currentRun.TextSourceLength <= characterIndex)
|
|
|
- {
|
|
|
- endX += currentRun.Size.Width;
|
|
|
+ startX = endX;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (currentPosition + currentRun.Length <= firstTextSourceIndex)
|
|
|
+ {
|
|
|
+ startX += currentRun.Size.Width;
|
|
|
|
|
|
- characterLength = currentRun.TextSourceLength;
|
|
|
- }
|
|
|
+ currentPosition += currentRun.Length;
|
|
|
+
|
|
|
+ continue;
|
|
|
}
|
|
|
|
|
|
- if (endX < startX)
|
|
|
+ if (currentPosition < firstTextSourceIndex)
|
|
|
{
|
|
|
- (endX, startX) = (startX, endX);
|
|
|
+ startX += currentRun.Size.Width;
|
|
|
}
|
|
|
|
|
|
- //Lines that only contain a linebreak need to be covered here
|
|
|
- if (characterLength == 0)
|
|
|
+ if (currentPosition + currentRun.Length <= characterIndex)
|
|
|
{
|
|
|
- characterLength = NewLineLength;
|
|
|
+ endX += currentRun.Size.Width;
|
|
|
+
|
|
|
+ characterLength = currentRun.Length;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- combinedWidth = endX - startX;
|
|
|
+ if (endX < startX)
|
|
|
+ {
|
|
|
+ (endX, startX) = (startX, endX);
|
|
|
+ }
|
|
|
|
|
|
- currentRunBounds = new TextRunBounds(new Rect(startX, 0, combinedWidth, Height), currentPosition, characterLength, currentRun);
|
|
|
+ //Lines that only contain a linebreak need to be covered here
|
|
|
+ if (characterLength == 0)
|
|
|
+ {
|
|
|
+ characterLength = NewLineLength;
|
|
|
+ }
|
|
|
|
|
|
- currentPosition += characterLength;
|
|
|
+ combinedWidth = endX - startX;
|
|
|
|
|
|
- remainingLength -= characterLength;
|
|
|
+ currentRunBounds = new TextRunBounds(new Rect(startX, 0, combinedWidth, Height), currentPosition, characterLength, currentRun);
|
|
|
|
|
|
- startX = endX;
|
|
|
+ currentPosition += characterLength;
|
|
|
|
|
|
- if (currentRunBounds.TextRun != null && !MathUtilities.IsZero(combinedWidth) || NewLineLength > 0)
|
|
|
- {
|
|
|
- if (result.Count > 0 && lastDirection == currentDirection && MathUtilities.AreClose(currentRect.Left, lastRunBounds.Rectangle.Right))
|
|
|
- {
|
|
|
- currentRect = currentRect.WithWidth(currentWidth + combinedWidth);
|
|
|
+ remainingLength -= characterLength;
|
|
|
|
|
|
- var textBounds = result[result.Count - 1];
|
|
|
+ startX = endX;
|
|
|
|
|
|
- textBounds.Rectangle = currentRect;
|
|
|
+ if (currentRunBounds.TextRun != null && !MathUtilities.IsZero(combinedWidth) || NewLineLength > 0)
|
|
|
+ {
|
|
|
+ if (result.Count > 0 && lastDirection == currentDirection && MathUtilities.AreClose(currentRect.Left, lastRunBounds.Rectangle.Right))
|
|
|
+ {
|
|
|
+ currentRect = currentRect.WithWidth(currentWidth + combinedWidth);
|
|
|
|
|
|
- textBounds.TextRunBounds.Add(currentRunBounds);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- currentRect = currentRunBounds.Rectangle;
|
|
|
+ var textBounds = result[result.Count - 1];
|
|
|
|
|
|
- result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds }));
|
|
|
- }
|
|
|
+ textBounds.Rectangle = currentRect;
|
|
|
+
|
|
|
+ textBounds.TextRunBounds.Add(currentRunBounds);
|
|
|
}
|
|
|
+ else
|
|
|
+ {
|
|
|
+ currentRect = currentRunBounds.Rectangle;
|
|
|
|
|
|
- lastRunBounds = currentRunBounds;
|
|
|
+ result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds }));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ lastRunBounds = currentRunBounds;
|
|
|
+
|
|
|
currentWidth += combinedWidth;
|
|
|
|
|
|
if (remainingLength <= 0 || currentPosition >= characterIndex)
|
|
@@ -771,11 +757,11 @@ namespace Avalonia.Media.TextFormatting
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- if (currentPosition + currentRun.TextSourceLength < firstTextSourceIndex)
|
|
|
+ if (currentPosition + currentRun.Length < firstTextSourceIndex)
|
|
|
{
|
|
|
startX -= currentRun.Size.Width;
|
|
|
|
|
|
- currentPosition += currentRun.TextSourceLength;
|
|
|
+ currentPosition += currentRun.Length;
|
|
|
|
|
|
continue;
|
|
|
}
|
|
@@ -789,7 +775,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
|
|
|
currentPosition += offset;
|
|
|
|
|
|
- var startIndex = currentRun.Text.Start + offset;
|
|
|
+ var startIndex = currentPosition;
|
|
|
double startOffset;
|
|
|
double endOffset;
|
|
|
|
|
@@ -827,7 +813,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- if (currentPosition + currentRun.TextSourceLength <= characterIndex)
|
|
|
+ if (currentPosition + currentRun.Length <= characterIndex)
|
|
|
{
|
|
|
endX -= currentRun.Size.Width;
|
|
|
}
|
|
@@ -836,7 +822,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
{
|
|
|
startX -= currentRun.Size.Width;
|
|
|
|
|
|
- characterLength = currentRun.TextSourceLength;
|
|
|
+ characterLength = currentRun.Length;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -905,7 +891,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
|
|
|
currentPosition += offset;
|
|
|
|
|
|
- var startIndex = currentRun.Text.Start + offset;
|
|
|
+ var startIndex = currentPosition;
|
|
|
|
|
|
double startOffset;
|
|
|
double endOffset;
|
|
@@ -1172,12 +1158,12 @@ namespace Avalonia.Media.TextFormatting
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- var characterIndex = codepointIndex - shapedRun.Text.Start;
|
|
|
+ //var characterIndex = codepointIndex - shapedRun.Text.Start;
|
|
|
|
|
|
- if (characterIndex < 0 && shapedRun.ShapedBuffer.IsLeftToRight)
|
|
|
- {
|
|
|
- foundCharacterHit = new CharacterHit(foundCharacterHit.FirstCharacterIndex);
|
|
|
- }
|
|
|
+ //if (characterIndex < 0 && shapedRun.ShapedBuffer.IsLeftToRight)
|
|
|
+ //{
|
|
|
+ // foundCharacterHit = new CharacterHit(foundCharacterHit.FirstCharacterIndex);
|
|
|
+ //}
|
|
|
|
|
|
nextCharacterHit = isAtEnd || characterHit.TrailingLength != 0 ?
|
|
|
foundCharacterHit :
|
|
@@ -1196,7 +1182,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
|
|
|
if (textPosition == currentPosition)
|
|
|
{
|
|
|
- nextCharacterHit = new CharacterHit(currentPosition + currentRun.TextSourceLength);
|
|
|
+ nextCharacterHit = new CharacterHit(currentPosition + currentRun.Length);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
@@ -1205,7 +1191,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- currentPosition += currentRun.TextSourceLength;
|
|
|
+ currentPosition += currentRun.Length;
|
|
|
runIndex++;
|
|
|
}
|
|
|
|
|
@@ -1271,7 +1257,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
}
|
|
|
default:
|
|
|
{
|
|
|
- if (characterIndex == currentPosition + currentRun.TextSourceLength)
|
|
|
+ if (characterIndex == currentPosition + currentRun.Length)
|
|
|
{
|
|
|
previousCharacterHit = new CharacterHit(currentPosition);
|
|
|
|
|
@@ -1282,7 +1268,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- currentPosition -= currentRun.TextSourceLength;
|
|
|
+ currentPosition -= currentRun.Length;
|
|
|
runIndex--;
|
|
|
}
|
|
|
|
|
@@ -1310,18 +1296,25 @@ namespace Avalonia.Media.TextFormatting
|
|
|
{
|
|
|
case ShapedTextCharacters shapedRun:
|
|
|
{
|
|
|
+ var firstCluster = shapedRun.GlyphRun.Metrics.FirstCluster;
|
|
|
+
|
|
|
+ if (firstCluster > codepointIndex)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
if (previousRun is ShapedTextCharacters previousShaped && !previousShaped.ShapedBuffer.IsLeftToRight)
|
|
|
{
|
|
|
if (shapedRun.ShapedBuffer.IsLeftToRight)
|
|
|
{
|
|
|
- if (currentRun.Text.Start >= codepointIndex)
|
|
|
+ if (firstCluster >= codepointIndex)
|
|
|
{
|
|
|
return --runIndex;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- if (codepointIndex > currentRun.Text.Start + currentRun.Text.Length)
|
|
|
+ if (codepointIndex > firstCluster + currentRun.Length)
|
|
|
{
|
|
|
return --runIndex;
|
|
|
}
|
|
@@ -1330,15 +1323,15 @@ namespace Avalonia.Media.TextFormatting
|
|
|
|
|
|
if (direction == LogicalDirection.Forward)
|
|
|
{
|
|
|
- if (codepointIndex >= currentRun.Text.Start && codepointIndex <= currentRun.Text.End)
|
|
|
+ if (codepointIndex >= firstCluster && codepointIndex <= firstCluster + currentRun.Length)
|
|
|
{
|
|
|
return runIndex;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- if (codepointIndex > currentRun.Text.Start &&
|
|
|
- codepointIndex <= currentRun.Text.Start + currentRun.Text.Length)
|
|
|
+ if (codepointIndex > firstCluster &&
|
|
|
+ codepointIndex <= firstCluster + currentRun.Length)
|
|
|
{
|
|
|
return runIndex;
|
|
|
}
|
|
@@ -1349,6 +1342,8 @@ namespace Avalonia.Media.TextFormatting
|
|
|
return runIndex;
|
|
|
}
|
|
|
|
|
|
+ textPosition += currentRun.Length;
|
|
|
+
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -1364,13 +1359,14 @@ namespace Avalonia.Media.TextFormatting
|
|
|
return runIndex;
|
|
|
}
|
|
|
|
|
|
+ textPosition += currentRun.Length;
|
|
|
+
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
runIndex++;
|
|
|
previousRun = currentRun;
|
|
|
- textPosition += currentRun.TextSourceLength;
|
|
|
}
|
|
|
|
|
|
return runIndex;
|
|
@@ -1401,7 +1397,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
case ShapedTextCharacters textRun:
|
|
|
{
|
|
|
var textMetrics =
|
|
|
- new TextMetrics(textRun.Properties.Typeface, textRun.Properties.FontRenderingEmSize);
|
|
|
+ new TextMetrics(textRun.Properties.Typeface.GlyphTypeface, textRun.Properties.FontRenderingEmSize);
|
|
|
|
|
|
if (fontRenderingEmSize < textRun.Properties.FontRenderingEmSize)
|
|
|
{
|
|
@@ -1432,7 +1428,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
{
|
|
|
width = widthIncludingWhitespace + textRun.GlyphRun.Metrics.Width;
|
|
|
trailingWhitespaceLength = textRun.GlyphRun.Metrics.TrailingWhitespaceLength;
|
|
|
- newLineLength = textRun.GlyphRun.Metrics.NewlineLength;
|
|
|
+ newLineLength = textRun.GlyphRun.Metrics.NewLineLength;
|
|
|
}
|
|
|
|
|
|
widthIncludingWhitespace += textRun.GlyphRun.Metrics.WidthIncludingTrailingWhitespace;
|