diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
index 061949a5c9..9318fcc68e 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
@@ -41,6 +41,156 @@ namespace Avalonia.Media.TextFormatting
return textLine;
}
+ ///
+ /// Measures the number of characters that fits into available width.
+ ///
+ /// The text run.
+ /// The available width.
+ ///
+ internal static int MeasureCharacters(ShapedTextCharacters textCharacters, double availableWidth)
+ {
+ var glyphRun = textCharacters.GlyphRun;
+
+ if (glyphRun.Bounds.Width < availableWidth)
+ {
+ return glyphRun.Characters.Length;
+ }
+
+ var glyphCount = 0;
+
+ var currentWidth = 0.0;
+
+ if (glyphRun.GlyphAdvances.IsEmpty)
+ {
+ var glyphTypeface = glyphRun.GlyphTypeface;
+
+ for (var i = 0; i < glyphRun.GlyphClusters.Length; i++)
+ {
+ var glyph = glyphRun.GlyphIndices[i];
+
+ var advance = glyphTypeface.GetGlyphAdvance(glyph) * glyphRun.Scale;
+
+ if (currentWidth + advance > availableWidth)
+ {
+ break;
+ }
+
+ currentWidth += advance;
+
+ glyphCount++;
+ }
+ }
+ else
+ {
+ foreach (var advance in glyphRun.GlyphAdvances)
+ {
+ if (currentWidth + advance > availableWidth)
+ {
+ break;
+ }
+
+ currentWidth += advance;
+
+ glyphCount++;
+ }
+ }
+
+ if (glyphCount == glyphRun.GlyphIndices.Length)
+ {
+ return glyphRun.Characters.Length;
+ }
+
+ if (glyphRun.GlyphClusters.IsEmpty)
+ {
+ return glyphCount;
+ }
+
+ var firstCluster = glyphRun.GlyphClusters[0];
+
+ var lastCluster = glyphRun.GlyphClusters[glyphCount];
+
+ return lastCluster - firstCluster;
+ }
+
+ ///
+ /// Split a sequence of runs into two segments at specified length.
+ ///
+ /// The text run's.
+ /// The length to split at.
+ /// The split text runs.
+ internal static SplitTextRunsResult SplitTextRuns(IReadOnlyList textRuns, int length)
+ {
+ var currentLength = 0;
+
+ for (var i = 0; i < textRuns.Count; i++)
+ {
+ var currentRun = textRuns[i];
+
+ if (currentLength + currentRun.GlyphRun.Characters.Length < length)
+ {
+ currentLength += currentRun.GlyphRun.Characters.Length;
+ continue;
+ }
+
+ var firstCount = currentRun.GlyphRun.Characters.Length >= 1 ? i + 1 : i;
+
+ var first = new ShapedTextCharacters[firstCount];
+
+ if (firstCount > 1)
+ {
+ for (var j = 0; j < i; j++)
+ {
+ first[j] = textRuns[j];
+ }
+ }
+
+ var secondCount = textRuns.Count - firstCount;
+
+ if (currentLength + currentRun.GlyphRun.Characters.Length == length)
+ {
+ var second = new ShapedTextCharacters[secondCount];
+
+ var offset = currentRun.GlyphRun.Characters.Length > 1 ? 1 : 0;
+
+ if (secondCount > 0)
+ {
+ for (var j = 0; j < secondCount; j++)
+ {
+ second[j] = textRuns[i + j + offset];
+ }
+ }
+
+ first[i] = currentRun;
+
+ return new SplitTextRunsResult(first, second);
+ }
+ else
+ {
+ secondCount++;
+
+ var second = new ShapedTextCharacters[secondCount];
+
+ if (secondCount > 0)
+ {
+ for (var j = 1; j < secondCount; j++)
+ {
+ second[j] = textRuns[i + j];
+ }
+ }
+
+ var split = currentRun.Split(length - currentLength);
+
+ first[i] = split.First;
+
+ second[0] = split.Second;
+
+ return new SplitTextRunsResult(first, second);
+ }
+ }
+
+ return new SplitTextRunsResult(textRuns, null);
+ }
+
///
/// Fetches text runs.
///
@@ -188,7 +338,7 @@ namespace Avalonia.Media.TextFormatting
if (currentWidth + currentRun.GlyphRun.Bounds.Width > availableWidth)
{
- var measuredLength = MeasureText(currentRun, paragraphWidth - currentWidth);
+ var measuredLength = MeasureCharacters(currentRun, paragraphWidth - currentWidth);
var breakFound = false;
@@ -256,77 +406,6 @@ namespace Avalonia.Media.TextFormatting
TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties));
}
- ///
- /// Measures the number of characters that fits into available width.
- ///
- /// The text run.
- /// The available width.
- ///
- internal static int MeasureText(ShapedTextCharacters textCharacters, double availableWidth)
- {
- var glyphRun = textCharacters.GlyphRun;
-
- if (glyphRun.Bounds.Width < availableWidth)
- {
- return glyphRun.Characters.Length;
- }
-
- var glyphCount = 0;
-
- var currentWidth = 0.0;
-
- if (glyphRun.GlyphAdvances.IsEmpty)
- {
- var glyphTypeface = glyphRun.GlyphTypeface;
-
- for (var i = 0; i < glyphRun.GlyphClusters.Length; i++)
- {
- var glyph = glyphRun.GlyphIndices[i];
-
- var advance = glyphTypeface.GetGlyphAdvance(glyph) * glyphRun.Scale;
-
- if (currentWidth + advance > availableWidth)
- {
- break;
- }
-
- currentWidth += advance;
-
- glyphCount++;
- }
- }
- else
- {
- foreach (var advance in glyphRun.GlyphAdvances)
- {
- if (currentWidth + advance > availableWidth)
- {
- break;
- }
-
- currentWidth += advance;
-
- glyphCount++;
- }
- }
-
- if (glyphCount == glyphRun.GlyphIndices.Length)
- {
- return glyphRun.Characters.Length;
- }
-
- if (glyphRun.GlyphClusters.IsEmpty)
- {
- return glyphCount;
- }
-
- var firstCluster = glyphRun.GlyphClusters[0];
-
- var lastCluster = glyphRun.GlyphClusters[glyphCount];
-
- return lastCluster - firstCluster;
- }
-
///
/// Gets the text range that is covered by the text runs.
///
@@ -353,85 +432,6 @@ namespace Avalonia.Media.TextFormatting
return new TextRange(start, end - start);
}
- ///
- /// Split a sequence of runs into two segments at specified length.
- ///
- /// The text run's.
- /// The length to split at.
- /// The split text runs.
- internal static SplitTextRunsResult SplitTextRuns(IReadOnlyList textRuns, int length)
- {
- var currentLength = 0;
-
- for (var i = 0; i < textRuns.Count; i++)
- {
- var currentRun = textRuns[i];
-
- if (currentLength + currentRun.GlyphRun.Characters.Length < length)
- {
- currentLength += currentRun.GlyphRun.Characters.Length;
- continue;
- }
-
- var firstCount = currentRun.GlyphRun.Characters.Length >= 1 ? i + 1 : i;
-
- var first = new ShapedTextCharacters[firstCount];
-
- if (firstCount > 1)
- {
- for (var j = 0; j < i; j++)
- {
- first[j] = textRuns[j];
- }
- }
-
- var secondCount = textRuns.Count - firstCount;
-
- if (currentLength + currentRun.GlyphRun.Characters.Length == length)
- {
- var second = new ShapedTextCharacters[secondCount];
-
- var offset = currentRun.GlyphRun.Characters.Length > 1 ? 1 : 0;
-
- if (secondCount > 0)
- {
- for (var j = 0; j < secondCount; j++)
- {
- second[j] = textRuns[i + j + offset];
- }
- }
-
- first[i] = currentRun;
-
- return new SplitTextRunsResult(first, second);
- }
- else
- {
- secondCount++;
-
- var second = new ShapedTextCharacters[secondCount];
-
- if (secondCount > 0)
- {
- for (var j = 1; j < secondCount; j++)
- {
- second[j] = textRuns[i + j];
- }
- }
-
- var split = currentRun.Split(length - currentLength);
-
- first[i] = split.First;
-
- second[0] = split.Second;
-
- return new SplitTextRunsResult(first, second);
- }
- }
-
- return new SplitTextRunsResult(textRuns, null);
- }
-
internal readonly struct SplitTextRunsResult
{
public SplitTextRunsResult(IReadOnlyList first, IReadOnlyList second)
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
index 92db6b69c4..14602a2560 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
@@ -268,6 +268,11 @@ namespace Avalonia.Media.TextFormatting
}
}
+ ///
+ /// Gets the for current text trimming mode.
+ ///
+ /// The collapsing width.
+ /// The .
private TextCollapsingProperties GetCollapsingProperties(double width)
{
return _textTrimming switch
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs
index 3e3258f38a..423ca9fb7f 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs
@@ -40,8 +40,11 @@ namespace Avalonia.Media.TextFormatting
public abstract TextLineBreak LineBreak { get; }
///
- /// Client to get a boolean value indicates whether a line has been collapsed
+ /// Gets a value that indicates whether the line is collapsed.
///
+ ///
+ /// true, if the line is collapsed; otherwise, false.
+ ///
public abstract bool HasCollapsed { get; }
///
@@ -52,46 +55,49 @@ namespace Avalonia.Media.TextFormatting
public abstract void Draw(DrawingContext drawingContext, Point origin);
///
- /// Client to collapse the line and get a collapsed line that fits for display
+ /// Create a collapsed line based on collapsed text properties.
///
- /// a list of collapsing properties
+ /// A list of
+ /// objects that represent the collapsed text properties.
+ ///
+ /// A value that represents a collapsed line that can be displayed.
+ ///
public abstract TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList);
///
- /// Client to get the character hit corresponding to the specified
- /// distance from the beginning of the line.
+ /// Gets the character hit corresponding to the specified distance from the beginning of the line.
///
- /// distance in text flow direction from the beginning of the line
- /// The
+ /// A value that represents the distance from the beginning of the line.
+ /// The object at the specified distance from the beginning of the line.
public abstract CharacterHit GetCharacterHitFromDistance(double distance);
///
- /// Client to get the distance from the beginning of the line from the specified
+ /// Gets the distance from the beginning of the line to the specified character hit.
/// .
///
- /// of the character to query the distance.
- /// Distance in text flow direction from the beginning of the line.
+ /// The object whose distance you want to query.
+ /// A that represents the distance from the beginning of the line.
public abstract double GetDistanceFromCharacterHit(CharacterHit characterHit);
///
- /// Client to get the next for caret navigation.
+ /// Gets the next character hit for caret navigation.
///
/// The current .
/// The next .
public abstract CharacterHit GetNextCaretCharacterHit(CharacterHit characterHit);
///
- /// Client to get the previous character hit for caret navigation
+ /// Gets the previous character hit for caret navigation.
///
- /// the current character hit
- /// The previous
+ /// The current .
+ /// The previous .
public abstract CharacterHit GetPreviousCaretCharacterHit(CharacterHit characterHit);
///
- /// Client to get the previous character hit after backspacing
+ /// Gets the previous character hit after backspacing.
///
- /// the current character hit
- /// The after backspacing
+ /// The current .
+ /// The after backspacing.
public abstract CharacterHit GetBackspaceCaretCharacterHit(CharacterHit characterHit);
///
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
index 820c943aea..980b1a2d40 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
@@ -47,6 +47,7 @@ namespace Avalonia.Media.TextFormatting
}
}
+ ///
public override TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList)
{
if (collapsingPropertiesList == null || collapsingPropertiesList.Length == 0)
@@ -73,7 +74,7 @@ namespace Avalonia.Media.TextFormatting
if (currentWidth > availableWidth)
{
- var measuredLength = TextFormatterImpl.MeasureText(currentRun, availableWidth);
+ var measuredLength = TextFormatterImpl.MeasureCharacters(currentRun, availableWidth);
var currentBreakPosition = 0;
diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs
index bbcdfe2d8e..c4f9443c3d 100644
--- a/src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs
+++ b/src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs
@@ -4,12 +4,11 @@ using System.Globalization;
namespace Avalonia.Media.TextFormatting
{
///
- /// Properties that can change from one run to the next, such as typeface or foreground brush.
+ /// Provides a set of properties, such as typeface or foreground brush, that can be applied to a TextRun object. This is an abstract class.
///
///
- /// The client provides a concrete implementation of this abstract run properties class. This
- /// allows client to implement their run properties the way that fits with their run formatting
- /// store.
+ /// The text layout client provides a concrete implementation of this abstract class.
+ /// This enables the client to implement text run properties in a way that corresponds with the associated formatting store.
///
public abstract class TextRunProperties : IEquatable
{