|
|
@@ -130,7 +130,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
first.Add(split.First);
|
|
|
|
|
|
second.Add(split.Second!);
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
for (var j = 1; j < secondCount; j++)
|
|
|
{
|
|
|
@@ -237,7 +237,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
|
|
|
var shaperOptions = new TextShaperOptions(currentRun.Properties!.Typeface.GlyphTypeface,
|
|
|
currentRun.Properties.FontRenderingEmSize,
|
|
|
- shapeableRun.BidiLevel, currentRun.Properties.CultureInfo,
|
|
|
+ shapeableRun.BidiLevel, currentRun.Properties.CultureInfo,
|
|
|
paragraphProperties.DefaultIncrementalTab, paragraphProperties.LetterSpacing);
|
|
|
|
|
|
shapedRuns.AddRange(ShapeTogether(groupedRuns, characterBufferReference, length, shaperOptions));
|
|
|
@@ -478,7 +478,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
{
|
|
|
case ShapedTextRun shapedTextCharacters:
|
|
|
{
|
|
|
- if(shapedTextCharacters.ShapedBuffer.Length > 0)
|
|
|
+ if (shapedTextCharacters.ShapedBuffer.Length > 0)
|
|
|
{
|
|
|
var firstCluster = shapedTextCharacters.ShapedBuffer.GlyphInfos[0].GlyphCluster;
|
|
|
var lastCluster = firstCluster;
|
|
|
@@ -499,7 +499,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
}
|
|
|
|
|
|
measuredLength += currentRun.Length;
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
break;
|
|
|
}
|
|
|
@@ -525,7 +525,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- found:
|
|
|
+ found:
|
|
|
|
|
|
return measuredLength != 0;
|
|
|
}
|
|
|
@@ -565,9 +565,9 @@ namespace Avalonia.Media.TextFormatting
|
|
|
double paragraphWidth, TextParagraphProperties paragraphProperties, FlowDirection resolvedFlowDirection,
|
|
|
TextLineBreak? currentLineBreak)
|
|
|
{
|
|
|
- if(textRuns.Count == 0)
|
|
|
+ if (textRuns.Count == 0)
|
|
|
{
|
|
|
- return CreateEmptyTextLine(firstTextSourceIndex,paragraphWidth, paragraphProperties);
|
|
|
+ return CreateEmptyTextLine(firstTextSourceIndex, paragraphWidth, paragraphProperties);
|
|
|
}
|
|
|
|
|
|
if (!TryMeasureLength(textRuns, paragraphWidth, out var measuredLength))
|
|
|
@@ -583,46 +583,24 @@ namespace Avalonia.Media.TextFormatting
|
|
|
|
|
|
for (var index = 0; index < textRuns.Count; index++)
|
|
|
{
|
|
|
- var currentRun = textRuns[index];
|
|
|
-
|
|
|
- var runText = new CharacterBufferRange(currentRun.CharacterBufferReference, currentRun.Length);
|
|
|
-
|
|
|
- var lineBreaker = new LineBreakEnumerator(runText);
|
|
|
-
|
|
|
var breakFound = false;
|
|
|
|
|
|
- while (lineBreaker.MoveNext())
|
|
|
- {
|
|
|
- if (lineBreaker.Current.Required &&
|
|
|
- currentLength + lineBreaker.Current.PositionMeasure <= measuredLength)
|
|
|
- {
|
|
|
- //Explicit break found
|
|
|
- breakFound = true;
|
|
|
-
|
|
|
- currentPosition = currentLength + lineBreaker.Current.PositionWrap;
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
+ var currentRun = textRuns[index];
|
|
|
|
|
|
- if (currentLength + lineBreaker.Current.PositionMeasure > measuredLength)
|
|
|
- {
|
|
|
- if (paragraphProperties.TextWrapping == TextWrapping.WrapWithOverflow)
|
|
|
+ switch (currentRun)
|
|
|
+ {
|
|
|
+ case ShapedTextRun:
|
|
|
{
|
|
|
- if (lastWrapPosition > 0)
|
|
|
- {
|
|
|
- currentPosition = lastWrapPosition;
|
|
|
+ var runText = new CharacterBufferRange(currentRun.CharacterBufferReference, currentRun.Length);
|
|
|
|
|
|
- breakFound = true;
|
|
|
+ var lineBreaker = new LineBreakEnumerator(runText);
|
|
|
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- //Find next possible wrap position (overflow)
|
|
|
- if (index < textRuns.Count - 1)
|
|
|
+ while (lineBreaker.MoveNext())
|
|
|
{
|
|
|
- if (lineBreaker.Current.PositionWrap != currentRun.Length)
|
|
|
+ if (lineBreaker.Current.Required &&
|
|
|
+ currentLength + lineBreaker.Current.PositionMeasure <= measuredLength)
|
|
|
{
|
|
|
- //We already found the next possible wrap position.
|
|
|
+ //Explicit break found
|
|
|
breakFound = true;
|
|
|
|
|
|
currentPosition = currentLength + lineBreaker.Current.PositionWrap;
|
|
|
@@ -630,51 +608,81 @@ namespace Avalonia.Media.TextFormatting
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- while (lineBreaker.MoveNext() && index < textRuns.Count)
|
|
|
+ if (currentLength + lineBreaker.Current.PositionMeasure > measuredLength)
|
|
|
{
|
|
|
- currentPosition += lineBreaker.Current.PositionWrap;
|
|
|
-
|
|
|
- if (lineBreaker.Current.PositionWrap != currentRun.Length)
|
|
|
+ if (paragraphProperties.TextWrapping == TextWrapping.WrapWithOverflow)
|
|
|
{
|
|
|
- break;
|
|
|
- }
|
|
|
+ if (lastWrapPosition > 0)
|
|
|
+ {
|
|
|
+ currentPosition = lastWrapPosition;
|
|
|
|
|
|
- index++;
|
|
|
+ breakFound = true;
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ //Find next possible wrap position (overflow)
|
|
|
+ if (index < textRuns.Count - 1)
|
|
|
+ {
|
|
|
+ if (lineBreaker.Current.PositionWrap != currentRun.Length)
|
|
|
+ {
|
|
|
+ //We already found the next possible wrap position.
|
|
|
+ breakFound = true;
|
|
|
+
|
|
|
+ currentPosition = currentLength + lineBreaker.Current.PositionWrap;
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (lineBreaker.MoveNext() && index < textRuns.Count)
|
|
|
+ {
|
|
|
+ currentPosition += lineBreaker.Current.PositionWrap;
|
|
|
+
|
|
|
+ if (lineBreaker.Current.PositionWrap != currentRun.Length)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ index++;
|
|
|
+
|
|
|
+ if (index >= textRuns.Count)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ currentRun = textRuns[index];
|
|
|
+
|
|
|
+ runText = new CharacterBufferRange(currentRun.CharacterBufferReference, currentRun.Length);
|
|
|
+
|
|
|
+ lineBreaker = new LineBreakEnumerator(runText);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ currentPosition = currentLength + lineBreaker.Current.PositionWrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ breakFound = true;
|
|
|
|
|
|
- if (index >= textRuns.Count)
|
|
|
- {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- currentRun = textRuns[index];
|
|
|
+ //We overflowed so we use the last available wrap position.
|
|
|
+ currentPosition = lastWrapPosition == 0 ? measuredLength : lastWrapPosition;
|
|
|
|
|
|
- runText = new CharacterBufferRange(currentRun.CharacterBufferReference, currentRun.Length);
|
|
|
+ breakFound = true;
|
|
|
|
|
|
- lineBreaker = new LineBreakEnumerator(runText);
|
|
|
+ break;
|
|
|
}
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- currentPosition = currentLength + lineBreaker.Current.PositionWrap;
|
|
|
- }
|
|
|
|
|
|
- breakFound = true;
|
|
|
+ if (lineBreaker.Current.PositionMeasure != lineBreaker.Current.PositionWrap)
|
|
|
+ {
|
|
|
+ lastWrapPosition = currentLength + lineBreaker.Current.PositionWrap;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
- //We overflowed so we use the last available wrap position.
|
|
|
- currentPosition = lastWrapPosition == 0 ? measuredLength : lastWrapPosition;
|
|
|
-
|
|
|
- breakFound = true;
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (lineBreaker.Current.PositionMeasure != lineBreaker.Current.PositionWrap)
|
|
|
- {
|
|
|
- lastWrapPosition = currentLength + lineBreaker.Current.PositionWrap;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
if (!breakFound)
|
|
|
@@ -694,7 +702,7 @@ namespace Avalonia.Media.TextFormatting
|
|
|
var remainingCharacters = splitResult.Second;
|
|
|
|
|
|
var lineBreak = remainingCharacters?.Count > 0 ?
|
|
|
- new TextLineBreak(currentLineBreak?.TextEndOfLine, resolvedFlowDirection, remainingCharacters) :
|
|
|
+ new TextLineBreak(null, resolvedFlowDirection, remainingCharacters) :
|
|
|
null;
|
|
|
|
|
|
if (lineBreak is null && currentLineBreak?.TextEndOfLine != null)
|