|
|
|
@ -184,6 +184,10 @@ namespace Avalonia.Media.TextFormatting |
|
|
|
{ |
|
|
|
characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _); |
|
|
|
|
|
|
|
var offset = Math.Max(0, currentPosition - shapedRun.Text.Start); |
|
|
|
|
|
|
|
characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength); |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
|
|
@ -215,9 +219,11 @@ namespace Avalonia.Media.TextFormatting |
|
|
|
/// <inheritdoc/>
|
|
|
|
public override double GetDistanceFromCharacterHit(CharacterHit characterHit) |
|
|
|
{ |
|
|
|
var characterIndex = characterHit.FirstCharacterIndex + (characterHit.TrailingLength != 0 ? 1 : 0); |
|
|
|
var isTrailingHit = characterHit.TrailingLength > 0; |
|
|
|
var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength; |
|
|
|
var currentDistance = Start; |
|
|
|
var currentPosition = FirstTextSourceIndex; |
|
|
|
var remainingLength = characterIndex - FirstTextSourceIndex; |
|
|
|
|
|
|
|
GlyphRun? lastRun = null; |
|
|
|
|
|
|
|
@ -242,8 +248,10 @@ namespace Avalonia.Media.TextFormatting |
|
|
|
} |
|
|
|
|
|
|
|
//Look for a hit in within the current run
|
|
|
|
if (characterIndex >= textRun.Text.Start && characterIndex <= textRun.Text.Start + textRun.Text.Length) |
|
|
|
if (currentPosition + remainingLength <= currentPosition + textRun.Text.Length) |
|
|
|
{ |
|
|
|
characterHit = new CharacterHit(textRun.Text.Start + remainingLength); |
|
|
|
|
|
|
|
var distance = currentRun.GetDistanceFromCharacterHit(characterHit); |
|
|
|
|
|
|
|
return currentDistance + distance; |
|
|
|
@ -254,28 +262,27 @@ namespace Avalonia.Media.TextFormatting |
|
|
|
{ |
|
|
|
if (_flowDirection == FlowDirection.LeftToRight && (lastRun == null || lastRun.IsLeftToRight)) |
|
|
|
{ |
|
|
|
if (characterIndex <= textRun.Text.Start) |
|
|
|
if (characterIndex <= currentPosition) |
|
|
|
{ |
|
|
|
return currentDistance; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (characterIndex == textRun.Text.Start) |
|
|
|
if (characterIndex == currentPosition) |
|
|
|
{ |
|
|
|
return currentDistance; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (characterIndex == textRun.Text.Start + textRun.Text.Length && |
|
|
|
characterHit.TrailingLength > 0) |
|
|
|
if (characterIndex == currentPosition + textRun.Text.Length && isTrailingHit) |
|
|
|
{ |
|
|
|
return currentDistance + currentRun.Size.Width; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (characterIndex == textRun.Text.Start) |
|
|
|
if (characterIndex == currentPosition) |
|
|
|
{ |
|
|
|
return currentDistance + currentRun.Size.Width; |
|
|
|
} |
|
|
|
@ -286,20 +293,24 @@ namespace Avalonia.Media.TextFormatting |
|
|
|
|
|
|
|
if (nextRun != null) |
|
|
|
{ |
|
|
|
if (characterHit.FirstCharacterIndex == textRun.Text.End && |
|
|
|
nextRun.ShapedBuffer.IsLeftToRight) |
|
|
|
if (nextRun.ShapedBuffer.IsLeftToRight) |
|
|
|
{ |
|
|
|
return currentDistance; |
|
|
|
if (characterIndex == currentPosition + textRun.Text.Length) |
|
|
|
{ |
|
|
|
return currentDistance; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (characterIndex > textRun.Text.End && nextRun.Text.End < textRun.Text.End) |
|
|
|
else |
|
|
|
{ |
|
|
|
return currentDistance; |
|
|
|
if (currentPosition + nextRun.Text.Length == characterIndex) |
|
|
|
{ |
|
|
|
return currentDistance; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (characterIndex > textRun.Text.End) |
|
|
|
if (characterIndex > currentPosition + textRun.Text.Length) |
|
|
|
{ |
|
|
|
return currentDistance; |
|
|
|
} |
|
|
|
@ -329,6 +340,12 @@ namespace Avalonia.Media.TextFormatting |
|
|
|
//No hit hit found so we add the full width
|
|
|
|
currentDistance += textRun.Size.Width; |
|
|
|
currentPosition += textRun.TextSourceLength; |
|
|
|
remainingLength -= textRun.TextSourceLength; |
|
|
|
|
|
|
|
if (remainingLength <= 0) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return currentDistance; |
|
|
|
@ -394,210 +411,299 @@ namespace Avalonia.Media.TextFormatting |
|
|
|
return GetPreviousCaretCharacterHit(characterHit); |
|
|
|
} |
|
|
|
|
|
|
|
public override IReadOnlyList<TextBounds> GetTextBounds(int firstTextSourceCharacterIndex, int textLength) |
|
|
|
private IReadOnlyList<TextBounds> GetTextBoundsLeftToRight(int firstTextSourceIndex, int textLength) |
|
|
|
{ |
|
|
|
if (firstTextSourceCharacterIndex + textLength <= FirstTextSourceIndex) |
|
|
|
{ |
|
|
|
return Array.Empty<TextBounds>(); |
|
|
|
} |
|
|
|
var characterIndex = firstTextSourceIndex + textLength; |
|
|
|
|
|
|
|
var result = new List<TextBounds>(TextRuns.Count); |
|
|
|
var lastDirection = _flowDirection; |
|
|
|
var lastDirection = FlowDirection.LeftToRight; |
|
|
|
var currentDirection = lastDirection; |
|
|
|
|
|
|
|
var currentPosition = FirstTextSourceIndex; |
|
|
|
var currentRect = Rect.Empty; |
|
|
|
var remainingLength = textLength; |
|
|
|
|
|
|
|
var startX = Start; |
|
|
|
double currentWidth = 0; |
|
|
|
var currentRect = Rect.Empty; |
|
|
|
|
|
|
|
//A portion of the line is covered.
|
|
|
|
for (var index = 0; index < TextRuns.Count; index++) |
|
|
|
{ |
|
|
|
var currentRun = TextRuns[index] as DrawableTextRun; |
|
|
|
|
|
|
|
if (currentRun is null) |
|
|
|
if (TextRuns[index] is not DrawableTextRun currentRun) |
|
|
|
{ |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
TextRun? nextRun = null; |
|
|
|
|
|
|
|
if (index + 1 < TextRuns.Count) |
|
|
|
if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) |
|
|
|
{ |
|
|
|
nextRun = TextRuns[index + 1]; |
|
|
|
startX += currentRun.Size.Width; |
|
|
|
|
|
|
|
currentPosition += currentRun.TextSourceLength; |
|
|
|
|
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if (nextRun != null) |
|
|
|
var characterLength = 0; |
|
|
|
var endX = startX; |
|
|
|
|
|
|
|
if (currentRun is ShapedTextCharacters currentShapedRun) |
|
|
|
{ |
|
|
|
switch (nextRun) |
|
|
|
{ |
|
|
|
case ShapedTextCharacters when currentRun is ShapedTextCharacters: |
|
|
|
{ |
|
|
|
if (nextRun.Text.Start < currentRun.Text.Start && firstTextSourceCharacterIndex + textLength < currentRun.Text.End) |
|
|
|
{ |
|
|
|
goto skip; |
|
|
|
} |
|
|
|
var offset = Math.Max(0, firstTextSourceIndex - currentPosition); |
|
|
|
|
|
|
|
if (currentRun.Text.Start >= firstTextSourceCharacterIndex + textLength) |
|
|
|
{ |
|
|
|
goto skip; |
|
|
|
} |
|
|
|
currentPosition += offset; |
|
|
|
|
|
|
|
if (currentRun.Text.Start > nextRun.Text.Start && currentRun.Text.Start < firstTextSourceCharacterIndex) |
|
|
|
{ |
|
|
|
goto skip; |
|
|
|
} |
|
|
|
var startIndex = currentRun.Text.Start + offset; |
|
|
|
|
|
|
|
if (currentRun.Text.End < firstTextSourceCharacterIndex) |
|
|
|
{ |
|
|
|
goto skip; |
|
|
|
} |
|
|
|
var endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( |
|
|
|
currentShapedRun.ShapedBuffer.IsLeftToRight ? |
|
|
|
new CharacterHit(startIndex + remainingLength) : |
|
|
|
new CharacterHit(startIndex)); |
|
|
|
|
|
|
|
goto noop; |
|
|
|
} |
|
|
|
default: |
|
|
|
{ |
|
|
|
goto noop; |
|
|
|
} |
|
|
|
} |
|
|
|
endX += endOffset; |
|
|
|
|
|
|
|
var startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( |
|
|
|
currentShapedRun.ShapedBuffer.IsLeftToRight ? |
|
|
|
new CharacterHit(startIndex) : |
|
|
|
new CharacterHit(startIndex + remainingLength)); |
|
|
|
|
|
|
|
startX += startOffset; |
|
|
|
|
|
|
|
var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); |
|
|
|
var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); |
|
|
|
|
|
|
|
characterLength = Math.Abs(endHit.FirstCharacterIndex + endHit.TrailingLength - startHit.FirstCharacterIndex - startHit.TrailingLength); |
|
|
|
|
|
|
|
skip: |
|
|
|
currentDirection = currentShapedRun.ShapedBuffer.IsLeftToRight ? |
|
|
|
FlowDirection.LeftToRight : |
|
|
|
FlowDirection.RightToLeft; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (currentPosition < firstTextSourceIndex) |
|
|
|
{ |
|
|
|
startX += currentRun.Size.Width; |
|
|
|
currentPosition += currentRun.TextSourceLength; |
|
|
|
} |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
noop: |
|
|
|
if (currentPosition + currentRun.TextSourceLength <= characterIndex) |
|
|
|
{ |
|
|
|
endX += currentRun.Size.Width; |
|
|
|
|
|
|
|
characterLength = currentRun.TextSourceLength; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
var endX = startX; |
|
|
|
var endOffset = 0d; |
|
|
|
if (endX < startX) |
|
|
|
{ |
|
|
|
(endX, startX) = (startX, endX); |
|
|
|
} |
|
|
|
|
|
|
|
switch (currentRun) |
|
|
|
//Lines that only contain a linebreak need to be covered here
|
|
|
|
if(characterLength == 0) |
|
|
|
{ |
|
|
|
case ShapedTextCharacters shapedRun: |
|
|
|
{ |
|
|
|
endOffset = shapedRun.GlyphRun.GetDistanceFromCharacterHit( |
|
|
|
shapedRun.ShapedBuffer.IsLeftToRight ? |
|
|
|
new CharacterHit(firstTextSourceCharacterIndex + textLength) : |
|
|
|
new CharacterHit(firstTextSourceCharacterIndex)); |
|
|
|
characterLength = NewLineLength; |
|
|
|
} |
|
|
|
|
|
|
|
endX += endOffset; |
|
|
|
var runwidth = endX - startX; |
|
|
|
var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runwidth, Height), currentPosition, characterLength, currentRun); |
|
|
|
|
|
|
|
var startOffset = shapedRun.GlyphRun.GetDistanceFromCharacterHit( |
|
|
|
shapedRun.ShapedBuffer.IsLeftToRight ? |
|
|
|
new CharacterHit(firstTextSourceCharacterIndex) : |
|
|
|
new CharacterHit(firstTextSourceCharacterIndex + textLength)); |
|
|
|
if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) |
|
|
|
{ |
|
|
|
currentRect = currentRect.WithWidth(currentWidth + runwidth); |
|
|
|
|
|
|
|
startX += startOffset; |
|
|
|
var textBounds = result[result.Count - 1]; |
|
|
|
|
|
|
|
var characterHit = shapedRun.GlyphRun.IsLeftToRight ? |
|
|
|
shapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _) : |
|
|
|
shapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); |
|
|
|
textBounds.Rectangle = currentRect; |
|
|
|
|
|
|
|
currentPosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength; |
|
|
|
textBounds.TextRunBounds.Add(currentRunBounds); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
currentRect = currentRunBounds.Rectangle; |
|
|
|
|
|
|
|
currentDirection = shapedRun.ShapedBuffer.IsLeftToRight ? |
|
|
|
FlowDirection.LeftToRight : |
|
|
|
FlowDirection.RightToLeft; |
|
|
|
result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds })); |
|
|
|
} |
|
|
|
|
|
|
|
if (nextRun is ShapedTextCharacters nextShaped) |
|
|
|
{ |
|
|
|
if (shapedRun.ShapedBuffer.IsLeftToRight == nextShaped.ShapedBuffer.IsLeftToRight) |
|
|
|
{ |
|
|
|
endOffset = nextShaped.GlyphRun.GetDistanceFromCharacterHit( |
|
|
|
nextShaped.ShapedBuffer.IsLeftToRight ? |
|
|
|
new CharacterHit(firstTextSourceCharacterIndex + textLength) : |
|
|
|
new CharacterHit(firstTextSourceCharacterIndex)); |
|
|
|
currentWidth += runwidth; |
|
|
|
currentPosition += characterLength; |
|
|
|
|
|
|
|
index++; |
|
|
|
if (currentDirection == FlowDirection.LeftToRight) |
|
|
|
{ |
|
|
|
if (currentPosition > characterIndex) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (currentPosition <= firstTextSourceIndex) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
endX += endOffset; |
|
|
|
startX = endX; |
|
|
|
lastDirection = currentDirection; |
|
|
|
remainingLength -= characterLength; |
|
|
|
|
|
|
|
currentRun = nextShaped; |
|
|
|
if (remainingLength <= 0) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (nextShaped.ShapedBuffer.IsLeftToRight) |
|
|
|
{ |
|
|
|
characterHit = nextShaped.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
currentPosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
private IReadOnlyList<TextBounds> GetTextBoundsRightToLeft(int firstTextSourceIndex, int textLength) |
|
|
|
{ |
|
|
|
var characterIndex = firstTextSourceIndex + textLength; |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
|
|
{ |
|
|
|
if (currentPosition + currentRun.TextSourceLength <= firstTextSourceCharacterIndex + textLength) |
|
|
|
{ |
|
|
|
endX += currentRun.Size.Width; |
|
|
|
} |
|
|
|
var result = new List<TextBounds>(TextRuns.Count); |
|
|
|
var lastDirection = FlowDirection.LeftToRight; |
|
|
|
var currentDirection = lastDirection; |
|
|
|
|
|
|
|
if (currentPosition < firstTextSourceCharacterIndex) |
|
|
|
{ |
|
|
|
startX += currentRun.Size.Width; |
|
|
|
} |
|
|
|
var currentPosition = FirstTextSourceIndex; |
|
|
|
var remainingLength = textLength; |
|
|
|
|
|
|
|
currentPosition += currentRun.TextSourceLength; |
|
|
|
var startX = Start + WidthIncludingTrailingWhitespace; |
|
|
|
double currentWidth = 0; |
|
|
|
var currentRect = Rect.Empty; |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
for (var index = TextRuns.Count - 1; index >= 0; index--) |
|
|
|
{ |
|
|
|
if (TextRuns[index] is not DrawableTextRun currentRun) |
|
|
|
{ |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if (endX < startX) |
|
|
|
if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) |
|
|
|
{ |
|
|
|
(endX, startX) = (startX, endX); |
|
|
|
startX -= currentRun.Size.Width; |
|
|
|
|
|
|
|
currentPosition += currentRun.TextSourceLength; |
|
|
|
|
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
var width = endX - startX; |
|
|
|
var characterLength = 0; |
|
|
|
var endX = startX; |
|
|
|
|
|
|
|
if (!MathUtilities.IsZero(width)) |
|
|
|
if (currentRun is ShapedTextCharacters currentShapedRun) |
|
|
|
{ |
|
|
|
if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) |
|
|
|
{ |
|
|
|
currentRect = currentRect.WithWidth(currentRect.Width + width); |
|
|
|
var offset = Math.Max(0, firstTextSourceIndex - currentPosition); |
|
|
|
|
|
|
|
currentPosition += offset; |
|
|
|
|
|
|
|
var startIndex = currentRun.Text.Start + offset; |
|
|
|
|
|
|
|
var endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( |
|
|
|
currentShapedRun.ShapedBuffer.IsLeftToRight ? |
|
|
|
new CharacterHit(startIndex + remainingLength) : |
|
|
|
new CharacterHit(startIndex)); |
|
|
|
|
|
|
|
endX += endOffset - currentShapedRun.Size.Width; |
|
|
|
|
|
|
|
var startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( |
|
|
|
currentShapedRun.ShapedBuffer.IsLeftToRight ? |
|
|
|
new CharacterHit(startIndex) : |
|
|
|
new CharacterHit(startIndex + remainingLength)); |
|
|
|
|
|
|
|
var textBounds = new TextBounds(currentRect, currentDirection); |
|
|
|
startX += startOffset - currentShapedRun.Size.Width; |
|
|
|
|
|
|
|
result[result.Count - 1] = textBounds; |
|
|
|
var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); |
|
|
|
var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); |
|
|
|
|
|
|
|
characterLength = Math.Abs(startHit.FirstCharacterIndex + startHit.TrailingLength - endHit.FirstCharacterIndex - endHit.TrailingLength); |
|
|
|
|
|
|
|
currentDirection = currentShapedRun.ShapedBuffer.IsLeftToRight ? |
|
|
|
FlowDirection.LeftToRight : |
|
|
|
FlowDirection.RightToLeft; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (currentPosition + currentRun.TextSourceLength <= characterIndex) |
|
|
|
{ |
|
|
|
endX -= currentRun.Size.Width; |
|
|
|
} |
|
|
|
else |
|
|
|
|
|
|
|
if (currentPosition < firstTextSourceIndex) |
|
|
|
{ |
|
|
|
startX -= currentRun.Size.Width; |
|
|
|
|
|
|
|
characterLength = currentRun.TextSourceLength; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (endX < startX) |
|
|
|
{ |
|
|
|
(endX, startX) = (startX, endX); |
|
|
|
} |
|
|
|
|
|
|
|
currentRect = new Rect(startX, 0, width, Height); |
|
|
|
//Lines that only contain a linebreak need to be covered here
|
|
|
|
if (characterLength == 0) |
|
|
|
{ |
|
|
|
characterLength = NewLineLength; |
|
|
|
} |
|
|
|
|
|
|
|
result.Add(new TextBounds(currentRect, currentDirection)); |
|
|
|
var runWidth = endX - startX; |
|
|
|
var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runWidth, Height), currentPosition, characterLength, currentRun); |
|
|
|
|
|
|
|
} |
|
|
|
if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) |
|
|
|
{ |
|
|
|
currentRect = currentRect.WithWidth(currentWidth + runWidth); |
|
|
|
|
|
|
|
var textBounds = result[result.Count - 1]; |
|
|
|
|
|
|
|
textBounds.Rectangle = currentRect; |
|
|
|
|
|
|
|
textBounds.TextRunBounds.Add(currentRunBounds); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
currentRect = currentRunBounds.Rectangle; |
|
|
|
|
|
|
|
result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds })); |
|
|
|
} |
|
|
|
|
|
|
|
currentWidth += runWidth; |
|
|
|
currentPosition += characterLength; |
|
|
|
|
|
|
|
if (currentDirection == FlowDirection.LeftToRight) |
|
|
|
{ |
|
|
|
if (currentPosition > firstTextSourceCharacterIndex + textLength) |
|
|
|
if (currentPosition > characterIndex) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (currentPosition <= firstTextSourceCharacterIndex) |
|
|
|
if (currentPosition <= firstTextSourceIndex) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
endX += currentRun.Size.Width - endOffset; |
|
|
|
} |
|
|
|
|
|
|
|
lastDirection = currentDirection; |
|
|
|
startX = endX; |
|
|
|
remainingLength -= characterLength; |
|
|
|
|
|
|
|
if (remainingLength <= 0) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
public override IReadOnlyList<TextBounds> GetTextBounds(int firstTextSourceIndex, int textLength) |
|
|
|
{ |
|
|
|
if (_paragraphProperties.FlowDirection == FlowDirection.LeftToRight) |
|
|
|
{ |
|
|
|
return GetTextBoundsLeftToRight(firstTextSourceIndex, textLength); |
|
|
|
} |
|
|
|
|
|
|
|
return GetTextBoundsRightToLeft(firstTextSourceIndex, textLength); |
|
|
|
} |
|
|
|
|
|
|
|
public TextLineImpl FinalizeLine() |
|
|
|
{ |
|
|
|
_textLineMetrics = CreateLineMetrics(); |
|
|
|
|