/// <summary> /// Fetches text runs. /// </summary> /// <param name="textSource">The text source.</param> /// <param name="firstTextSourceIndex">The first text source index.</param> /// <param name="endOfLine"></param> /// <param name="textRange"></param> /// <returns> /// The formatted text runs. /// </returns> private static List <TextCharacters> FetchTextRuns(ITextSource textSource, int firstTextSourceIndex, out TextEndOfLine?endOfLine, out TextRange textRange) { var length = 0; endOfLine = null; var textRuns = new List <TextCharacters>(); var textRunEnumerator = new TextRunEnumerator(textSource, firstTextSourceIndex); while (textRunEnumerator.MoveNext()) { var textRun = textRunEnumerator.Current; if (textRun == null) { break; } switch (textRun) { case TextCharacters textCharacters: { if (TryGetLineBreak(textCharacters, out var runLineBreak)) { var splitResult = new TextCharacters(textCharacters.Text.Take(runLineBreak.PositionWrap), textCharacters.Properties); textRuns.Add(splitResult); length += runLineBreak.PositionWrap; textRange = new TextRange(firstTextSourceIndex, length); return(textRuns); } textRuns.Add(textCharacters); break; } case TextEndOfLine textEndOfLine: endOfLine = textEndOfLine; break; } length += textRun.Text.Length; } textRange = new TextRange(firstTextSourceIndex, length); return(textRuns); }
/// <summary> /// Fetches text runs. /// </summary> /// <param name="textSource">The text source.</param> /// <param name="firstTextSourceIndex">The first text source index.</param> /// <param name="previousLineBreak">Previous line break. Can be null.</param> /// <param name="nextLineBreak">Next line break. Can be null.</param> /// <returns> /// The formatted text runs. /// </returns> private static IReadOnlyList <ShapedTextCharacters> FetchTextRuns(ITextSource textSource, int firstTextSourceIndex, TextLineBreak previousLineBreak, out TextLineBreak nextLineBreak) { nextLineBreak = default; var currentLength = 0; var textRuns = new List <ShapedTextCharacters>(); if (previousLineBreak != null) { foreach (var shapedCharacters in previousLineBreak.RemainingCharacters) { if (shapedCharacters == null) { continue; } textRuns.Add(shapedCharacters); if (TryGetLineBreak(shapedCharacters, out var runLineBreak)) { var splitResult = SplitTextRuns(textRuns, currentLength + runLineBreak.PositionWrap); nextLineBreak = new TextLineBreak(splitResult.Second); return(splitResult.First); } currentLength += shapedCharacters.Text.Length; } } firstTextSourceIndex += currentLength; var textRunEnumerator = new TextRunEnumerator(textSource, firstTextSourceIndex); while (textRunEnumerator.MoveNext()) { var textRun = textRunEnumerator.Current; switch (textRun) { case TextCharacters textCharacters: { var shapeableRuns = textCharacters.GetShapeableCharacters(); foreach (var run in shapeableRuns) { var glyphRun = TextShaper.Current.ShapeText(run.Text, run.Properties.Typeface, run.Properties.FontRenderingEmSize, run.Properties.CultureInfo); var shapedCharacters = new ShapedTextCharacters(glyphRun, run.Properties); textRuns.Add(shapedCharacters); } break; } } if (TryGetLineBreak(textRun, out var runLineBreak)) { var splitResult = SplitTextRuns(textRuns, currentLength + runLineBreak.PositionWrap); nextLineBreak = new TextLineBreak(splitResult.Second); return(splitResult.First); } currentLength += textRun.Text.Length; } return(textRuns); }