/// <inheritdoc cref="TextFormatter.FormatLine"/> public override TextLine FormatLine(ITextSource textSource, int firstTextSourceIndex, double paragraphWidth, TextParagraphProperties paragraphProperties) { var textTrimming = paragraphProperties.TextTrimming; var textWrapping = paragraphProperties.TextWrapping; TextLine textLine; var textRuns = FormatTextRuns(textSource, firstTextSourceIndex, out var textPointer); if (textTrimming != TextTrimming.None) { textLine = PerformTextTrimming(textPointer, textRuns, paragraphWidth, paragraphProperties); } else { if (textWrapping == TextWrapping.Wrap) { textLine = PerformTextWrapping(textPointer, textRuns, paragraphWidth, paragraphProperties); } else { var textLineMetrics = TextLineMetrics.Create(textRuns, paragraphWidth, paragraphProperties.TextAlignment); textLine = new SimpleTextLine(textPointer, textRuns, textLineMetrics); } } return(textLine); }
/// <inheritdoc cref="TextFormatter.FormatLine"/> public override TextLine FormatLine(ITextSource textSource, int firstTextSourceIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak = null) { var textWrapping = paragraphProperties.TextWrapping; var textRuns = FetchTextRuns(textSource, firstTextSourceIndex, previousLineBreak, out var nextLineBreak); var textRange = GetTextRange(textRuns); TextLine textLine; switch (textWrapping) { case TextWrapping.NoWrap: { var textLineMetrics = TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties); textLine = new TextLineImpl(textRuns, textLineMetrics, nextLineBreak); break; } case TextWrapping.WrapWithOverflow: case TextWrapping.Wrap: { textLine = PerformTextWrapping(textRuns, textRange, paragraphWidth, paragraphProperties); break; } default: throw new ArgumentOutOfRangeException(); } return(textLine); }
/// <summary> /// Creates an empty text line. /// </summary> /// <returns>The empty text line.</returns> private TextLine CreateEmptyTextLine(int startingIndex) { var textFormat = _paragraphProperties.DefaultTextStyle.TextFormat; var glyphRun = TextShaper.Current.ShapeText(s_empty, textFormat); var textRuns = new[] { new ShapedTextRun(glyphRun, _paragraphProperties.DefaultTextStyle) }; return(new SimpleTextLine(new TextPointer(startingIndex, 0), textRuns, TextLineMetrics.Create(textRuns, MaxWidth, _paragraphProperties.TextAlignment))); }
/// <summary> /// Creates an empty text line. /// </summary> /// <returns>The empty text line.</returns> private TextLine CreateEmptyTextLine(int startingIndex) { var properties = _paragraphProperties.DefaultTextRunProperties; var glyphRun = TextShaper.Current.ShapeText(new ReadOnlySlice <char>(s_empty, startingIndex, 1), properties.Typeface, properties.FontRenderingEmSize, properties.CultureInfo); var textRuns = new[] { new ShapedTextCharacters(glyphRun, _paragraphProperties.DefaultTextRunProperties) }; return(new TextLineImpl(textRuns, TextLineMetrics.Create(textRuns, new TextRange(startingIndex, 1), MaxWidth, _paragraphProperties))); }
/// <inheritdoc cref="TextFormatter.FormatLine"/> public override TextLine FormatLine(ITextSource textSource, int firstTextSourceIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak = null) { var textTrimming = paragraphProperties.TextTrimming; var textWrapping = paragraphProperties.TextWrapping; TextLine textLine = null; var textRuns = FetchTextRuns(textSource, firstTextSourceIndex, previousLineBreak, out var nextLineBreak); var textRange = GetTextRange(textRuns); if (textTrimming != TextTrimming.None) { textLine = PerformTextTrimming(textRuns, textRange, paragraphWidth, paragraphProperties); } else { switch (textWrapping) { case TextWrapping.NoWrap: { var textLineMetrics = TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties); textLine = new TextLineImpl(textRuns, textLineMetrics, nextLineBreak); break; } case TextWrapping.WrapWithOverflow: case TextWrapping.Wrap: { textLine = PerformTextWrapping(textRuns, textRange, paragraphWidth, paragraphProperties); break; } } } return(textLine); }
/// <summary> /// Performs text wrapping returns a list of text lines. /// </summary> /// <param name="textRuns">The text run's.</param> /// <param name="textRange">The text range that is covered by the text runs.</param> /// <param name="paragraphWidth">The paragraph width.</param> /// <param name="paragraphProperties">The text paragraph properties.</param> /// <returns>The wrapped text line.</returns> private static TextLine PerformTextWrapping(IReadOnlyList <ShapedTextCharacters> textRuns, TextRange textRange, double paragraphWidth, TextParagraphProperties paragraphProperties) { var availableWidth = paragraphWidth; var currentWidth = 0.0; var runIndex = 0; var currentLength = 0; while (runIndex < textRuns.Count) { var currentRun = textRuns[runIndex]; if (currentWidth + currentRun.GlyphRun.Bounds.Width > availableWidth) { var measuredLength = MeasureCharacters(currentRun, paragraphWidth - currentWidth); var breakFound = false; var currentBreakPosition = 0; if (measuredLength < currentRun.Text.Length) { var lineBreaker = new LineBreakEnumerator(currentRun.Text); while (currentBreakPosition < measuredLength && lineBreaker.MoveNext()) { var nextBreakPosition = lineBreaker.Current.PositionWrap; if (nextBreakPosition == 0 || nextBreakPosition > measuredLength) { break; } breakFound = lineBreaker.Current.Required || lineBreaker.Current.PositionWrap != currentRun.Text.Length; currentBreakPosition = nextBreakPosition; } } if (breakFound) { measuredLength = currentBreakPosition; } else { if (paragraphProperties.TextWrapping == TextWrapping.WrapWithOverflow) { var lineBreaker = new LineBreakEnumerator(currentRun.Text.Skip(currentBreakPosition)); if (lineBreaker.MoveNext()) { measuredLength = currentBreakPosition + lineBreaker.Current.PositionWrap; } } } currentLength += measuredLength; var splitResult = SplitTextRuns(textRuns, currentLength); var textLineMetrics = TextLineMetrics.Create(splitResult.First, new TextRange(textRange.Start, currentLength), paragraphWidth, paragraphProperties); var lineBreak = splitResult.Second != null && splitResult.Second.Count > 0 ? new TextLineBreak(splitResult.Second) : null; return(new TextLineImpl(splitResult.First, textLineMetrics, lineBreak)); } currentWidth += currentRun.GlyphRun.Bounds.Width; currentLength += currentRun.GlyphRun.Characters.Length; runIndex++; } return(new TextLineImpl(textRuns, TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties))); }
/// <summary> /// Performs text trimming and returns a trimmed line. /// </summary> /// <param name="textRuns">The text runs to perform the trimming on.</param> /// <param name="textRange">The text range that is covered by the text runs.</param> /// <param name="paragraphWidth">A <see cref="double"/> value that specifies the width of the paragraph that the line fills.</param> /// <param name="paragraphProperties">A <see cref="TextParagraphProperties"/> value that represents paragraph properties, /// such as TextWrapping, TextAlignment, or TextStyle.</param> /// <returns></returns> private static TextLine PerformTextTrimming(IReadOnlyList <ShapedTextCharacters> textRuns, TextRange textRange, double paragraphWidth, TextParagraphProperties paragraphProperties) { var textTrimming = paragraphProperties.TextTrimming; var availableWidth = paragraphWidth; var currentWidth = 0.0; var runIndex = 0; while (runIndex < textRuns.Count) { var currentRun = textRuns[runIndex]; currentWidth += currentRun.GlyphRun.Bounds.Width; if (currentWidth > availableWidth) { var ellipsisRun = CreateEllipsisRun(currentRun.Properties); var measuredLength = MeasureText(currentRun, availableWidth - ellipsisRun.GlyphRun.Bounds.Width); if (textTrimming == TextTrimming.WordEllipsis) { if (measuredLength < textRange.End) { var currentBreakPosition = 0; var lineBreaker = new LineBreakEnumerator(currentRun.Text); while (currentBreakPosition < measuredLength && lineBreaker.MoveNext()) { var nextBreakPosition = lineBreaker.Current.PositionWrap; if (nextBreakPosition == 0) { break; } if (nextBreakPosition > measuredLength) { break; } currentBreakPosition = nextBreakPosition; } measuredLength = currentBreakPosition; } } var splitResult = SplitTextRuns(textRuns, measuredLength); var trimmedRuns = new List <ShapedTextCharacters>(splitResult.First.Count + 1); trimmedRuns.AddRange(splitResult.First); trimmedRuns.Add(ellipsisRun); var textLineMetrics = TextLineMetrics.Create(trimmedRuns, textRange, paragraphWidth, paragraphProperties); return(new TextLineImpl(trimmedRuns, textLineMetrics)); } availableWidth -= currentRun.GlyphRun.Bounds.Width; runIndex++; } return(new TextLineImpl(textRuns, TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties))); }
/// <summary> /// Performs text wrapping returns a list of text lines. /// </summary> /// <param name="paragraphProperties">The text paragraph properties.</param> /// <param name="textRuns">The text run'S.</param> /// <param name="text">The text to analyze for break opportunities.</param> /// <param name="paragraphWidth"></param> /// <returns></returns> private static TextLine PerformTextWrapping(TextPointer text, IReadOnlyList <ShapedTextRun> textRuns, double paragraphWidth, TextParagraphProperties paragraphProperties) { var availableWidth = paragraphWidth; var currentWidth = 0.0; var runIndex = 0; var length = 0; while (runIndex < textRuns.Count) { var currentRun = textRuns[runIndex]; if (currentWidth + currentRun.GlyphRun.Bounds.Width > availableWidth) { var measuredLength = MeasureText(currentRun, paragraphWidth - currentWidth); if (measuredLength < currentRun.Text.Length) { var currentBreakPosition = -1; var lineBreaker = new LineBreakEnumerator(currentRun.Text); while (currentBreakPosition < measuredLength && lineBreaker.MoveNext()) { var nextBreakPosition = lineBreaker.Current.PositionWrap; if (nextBreakPosition == 0) { break; } if (nextBreakPosition > measuredLength) { break; } currentBreakPosition = nextBreakPosition; } if (currentBreakPosition != -1) { measuredLength = currentBreakPosition; } } length += measuredLength; var splitResult = SplitTextRuns(textRuns, length); var textLineMetrics = TextLineMetrics.Create(splitResult.First, paragraphWidth, paragraphProperties.TextAlignment); return(new SimpleTextLine(text.Take(length), splitResult.First, textLineMetrics)); } currentWidth += currentRun.GlyphRun.Bounds.Width; length += currentRun.GlyphRun.Characters.Length; runIndex++; } return(new SimpleTextLine(text, textRuns, TextLineMetrics.Create(textRuns, paragraphWidth, paragraphProperties.TextAlignment))); }