/// <inheritdoc/> public override TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList) { if (collapsingPropertiesList == null || collapsingPropertiesList.Length == 0) { return(this); } var collapsingProperties = collapsingPropertiesList[0]; var runIndex = 0; var currentWidth = 0.0; var textRange = TextRange; var collapsedLength = 0; TextLineMetrics textLineMetrics; var shapedSymbol = CreateShapedSymbol(collapsingProperties.Symbol); var availableWidth = collapsingProperties.Width - shapedSymbol.Size.Width; while (runIndex < _textRuns.Count) { var currentRun = _textRuns[runIndex]; currentWidth += currentRun.Size.Width; if (currentWidth > availableWidth) { if (TextFormatterImpl.TryMeasureCharacters(currentRun, availableWidth, out var measuredLength)) { if (collapsingProperties.Style == TextCollapsingStyle.TrailingWord && 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; } } collapsedLength += measuredLength; var splitResult = TextFormatterImpl.SplitTextRuns(_textRuns, collapsedLength); var shapedTextCharacters = new List <ShapedTextCharacters>(splitResult.First.Count + 1); shapedTextCharacters.AddRange(splitResult.First); shapedTextCharacters.Add(shapedSymbol); textRange = new TextRange(textRange.Start, collapsedLength); var shapedWidth = GetShapedWidth(shapedTextCharacters); textLineMetrics = new TextLineMetrics(new Size(shapedWidth, LineMetrics.Size.Height), LineMetrics.TextBaseline, textRange, false); return(new TextLineImpl(shapedTextCharacters, textLineMetrics, TextLineBreak, true)); } availableWidth -= currentRun.Size.Width; collapsedLength += currentRun.GlyphRun.Characters.Length; runIndex++; } textLineMetrics = new TextLineMetrics(LineMetrics.Size.WithWidth(LineMetrics.Size.Width + shapedSymbol.Size.Width), LineMetrics.TextBaseline, TextRange, LineMetrics.HasOverflowed); return(new TextLineImpl(new List <ShapedTextCharacters>(_textRuns) { shapedSymbol }, textLineMetrics, null, true)); }
public static List <ShapedTextCharacters>?Collapse(TextLine textLine, TextCollapsingProperties properties, bool isWordEllipsis) { var shapedTextRuns = textLine.TextRuns as List <ShapedTextCharacters>; if (shapedTextRuns is null) { return(null); } var runIndex = 0; var currentWidth = 0.0; var collapsedLength = 0; var textRange = textLine.TextRange; var shapedSymbol = TextFormatterImpl.CreateSymbol(properties.Symbol, FlowDirection.LeftToRight); if (properties.Width < shapedSymbol.GlyphRun.Size.Width) { return(new List <ShapedTextCharacters>(0)); } var availableWidth = properties.Width - shapedSymbol.Size.Width; while (runIndex < shapedTextRuns.Count) { var currentRun = shapedTextRuns[runIndex]; currentWidth += currentRun.Size.Width; if (currentWidth > availableWidth) { if (currentRun.TryMeasureCharacters(availableWidth, out var measuredLength)) { if (isWordEllipsis && measuredLength < textRange.End) { var currentBreakPosition = 0; var lineBreaker = new LineBreakEnumerator(currentRun.Text); while (currentBreakPosition < measuredLength && lineBreaker.MoveNext()) { var nextBreakPosition = lineBreaker.Current.PositionMeasure; if (nextBreakPosition == 0) { break; } if (nextBreakPosition >= measuredLength) { break; } currentBreakPosition = nextBreakPosition; } measuredLength = currentBreakPosition; } } collapsedLength += measuredLength; var shapedTextCharacters = new List <ShapedTextCharacters>(shapedTextRuns.Count); if (collapsedLength > 0) { var splitResult = TextFormatterImpl.SplitShapedRuns(shapedTextRuns, collapsedLength); shapedTextCharacters.AddRange(splitResult.First); TextLineImpl.SortRuns(shapedTextCharacters); } shapedTextCharacters.Add(shapedSymbol); return(shapedTextCharacters); } availableWidth -= currentRun.Size.Width; collapsedLength += currentRun.GlyphRun.Characters.Length; runIndex++; } return(null); }
public override IReadOnlyList <TextRun>?Collapse(TextLine textLine) { var shapedTextRuns = textLine.TextRuns as List <ShapedTextCharacters>; if (shapedTextRuns is null) { return(null); } var runIndex = 0; var currentWidth = 0.0; var shapedSymbol = TextFormatterImpl.CreateSymbol(Symbol, FlowDirection.LeftToRight); if (Width < shapedSymbol.GlyphRun.Size.Width) { return(new List <ShapedTextCharacters>(0)); } // Overview of ellipsis structure // Prefix length run | Ellipsis symbol | Post split run growing from the end | var availableWidth = Width - shapedSymbol.Size.Width; while (runIndex < shapedTextRuns.Count) { var currentRun = shapedTextRuns[runIndex]; currentWidth += currentRun.Size.Width; if (currentWidth > availableWidth) { currentRun.TryMeasureCharacters(availableWidth, out var measuredLength); var shapedTextCharacters = new List <ShapedTextCharacters>(shapedTextRuns.Count); if (measuredLength > 0) { List <ShapedTextCharacters>?preSplitRuns = null; List <ShapedTextCharacters>?postSplitRuns = null; if (_prefixLength > 0) { var splitResult = TextFormatterImpl.SplitShapedRuns(shapedTextRuns, Math.Min(_prefixLength, measuredLength)); shapedTextCharacters.AddRange(splitResult.First); TextLineImpl.SortRuns(shapedTextCharacters); preSplitRuns = splitResult.First; postSplitRuns = splitResult.Second; } else { postSplitRuns = shapedTextRuns; } shapedTextCharacters.Add(shapedSymbol); if (measuredLength > _prefixLength && postSplitRuns is not null) { var availableSuffixWidth = availableWidth; if (preSplitRuns is not null) { foreach (var run in preSplitRuns) { availableSuffixWidth -= run.Size.Width; } } for (int i = postSplitRuns.Count - 1; i >= 0; i--) { var run = postSplitRuns[i]; if (run.TryMeasureCharactersBackwards(availableSuffixWidth, out int suffixCount, out double suffixWidth)) { availableSuffixWidth -= suffixWidth; if (suffixCount > 0) { var splitSuffix = run.Split(run.TextSourceLength - suffixCount); shapedTextCharacters.Add(splitSuffix.Second !); } } } } } else { shapedTextCharacters.Add(shapedSymbol); } return(shapedTextCharacters); } availableWidth -= currentRun.Size.Width; runIndex++; } return(null); }
public static List <DrawableTextRun>?Collapse(TextLine textLine, TextCollapsingProperties properties, bool isWordEllipsis) { if (textLine.TextRuns is not List <DrawableTextRun> textRuns || textRuns.Count == 0) { return(null); } var runIndex = 0; var currentWidth = 0.0; var collapsedLength = 0; var shapedSymbol = TextFormatterImpl.CreateSymbol(properties.Symbol, FlowDirection.LeftToRight); if (properties.Width < shapedSymbol.GlyphRun.Size.Width) { //Not enough space to fit in the symbol return(new List <DrawableTextRun>(0)); } var availableWidth = properties.Width - shapedSymbol.Size.Width; while (runIndex < textRuns.Count) { var currentRun = textRuns[runIndex]; switch (currentRun) { case ShapedTextCharacters shapedRun: { currentWidth += shapedRun.Size.Width; if (currentWidth > availableWidth) { if (shapedRun.TryMeasureCharacters(availableWidth, out var measuredLength)) { if (isWordEllipsis && measuredLength < textLine.Length) { var currentBreakPosition = 0; var lineBreaker = new LineBreakEnumerator(currentRun.Text); while (currentBreakPosition < measuredLength && lineBreaker.MoveNext()) { var nextBreakPosition = lineBreaker.Current.PositionMeasure; if (nextBreakPosition == 0) { break; } if (nextBreakPosition >= measuredLength) { break; } currentBreakPosition = nextBreakPosition; } measuredLength = currentBreakPosition; } } collapsedLength += measuredLength; var collapsedRuns = new List <DrawableTextRun>(textRuns.Count); if (collapsedLength > 0) { var splitResult = TextFormatterImpl.SplitDrawableRuns(textRuns, collapsedLength); collapsedRuns.AddRange(splitResult.First); } collapsedRuns.Add(shapedSymbol); return(collapsedRuns); } availableWidth -= currentRun.Size.Width; break; } case { } drawableRun: { //The whole run needs to fit into available space if (currentWidth + drawableRun.Size.Width > availableWidth) { var collapsedRuns = new List <DrawableTextRun>(textRuns.Count); if (collapsedLength > 0) { var splitResult = TextFormatterImpl.SplitDrawableRuns(textRuns, collapsedLength); collapsedRuns.AddRange(splitResult.First); } collapsedRuns.Add(shapedSymbol); return(collapsedRuns); } break; } } collapsedLength += currentRun.TextSourceLength; runIndex++; } return(null); }
public override List <DrawableTextRun>?Collapse(TextLine textLine) { if (textLine.TextRuns is not List <DrawableTextRun> textRuns || textRuns.Count == 0) { return(null); } var runIndex = 0; var currentWidth = 0.0; var shapedSymbol = TextFormatterImpl.CreateSymbol(Symbol, FlowDirection.LeftToRight); if (Width < shapedSymbol.GlyphRun.Size.Width) { return(new List <DrawableTextRun>(0)); } // Overview of ellipsis structure // Prefix length run | Ellipsis symbol | Post split run growing from the end | var availableWidth = Width - shapedSymbol.Size.Width; while (runIndex < textRuns.Count) { var currentRun = textRuns[runIndex]; switch (currentRun) { case ShapedTextCharacters shapedRun: { currentWidth += currentRun.Size.Width; if (currentWidth > availableWidth) { shapedRun.TryMeasureCharacters(availableWidth, out var measuredLength); var collapsedRuns = new List <DrawableTextRun>(textRuns.Count); if (measuredLength > 0) { List <DrawableTextRun>?preSplitRuns = null; List <DrawableTextRun>?postSplitRuns; if (_prefixLength > 0) { var splitResult = TextFormatterImpl.SplitDrawableRuns(textRuns, Math.Min(_prefixLength, measuredLength)); collapsedRuns.AddRange(splitResult.First); preSplitRuns = splitResult.First; postSplitRuns = splitResult.Second; } else { postSplitRuns = textRuns; } collapsedRuns.Add(shapedSymbol); if (measuredLength <= _prefixLength || postSplitRuns is null) { return(collapsedRuns); } var availableSuffixWidth = availableWidth; if (preSplitRuns is not null) { foreach (var run in preSplitRuns) { availableSuffixWidth -= run.Size.Width; } } for (var i = postSplitRuns.Count - 1; i >= 0; i--) { var run = postSplitRuns[i]; switch (run) { case ShapedTextCharacters endShapedRun: { if (endShapedRun.TryMeasureCharactersBackwards(availableSuffixWidth, out var suffixCount, out var suffixWidth)) { availableSuffixWidth -= suffixWidth; if (suffixCount > 0) { var splitSuffix = endShapedRun.Split(run.TextSourceLength - suffixCount); collapsedRuns.Add(splitSuffix.Second !); } } break; } } } } else { collapsedRuns.Add(shapedSymbol); } return(collapsedRuns); } break; } } availableWidth -= currentRun.Size.Width; runIndex++; } return(null); }
/// <inheritdoc/> public override TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList) { if (collapsingPropertiesList.Length == 0) { return(this); } var collapsingProperties = collapsingPropertiesList[0]; var runIndex = 0; var currentWidth = 0.0; var textRange = TextRange; var collapsedLength = 0; var shapedSymbol = TextFormatterImpl.CreateSymbol(collapsingProperties.Symbol, _paragraphProperties.FlowDirection); var availableWidth = collapsingProperties.Width - shapedSymbol.GlyphRun.Size.Width; while (runIndex < _textRuns.Count) { var currentRun = _textRuns[runIndex]; currentWidth += currentRun.Size.Width; if (currentWidth > availableWidth) { if (currentRun.TryMeasureCharacters(availableWidth, out var measuredLength)) { if (collapsingProperties.Style == TextCollapsingStyle.TrailingWord && measuredLength < textRange.End) { var currentBreakPosition = 0; var lineBreaker = new LineBreakEnumerator(currentRun.Text); while (currentBreakPosition < measuredLength && lineBreaker.MoveNext()) { var nextBreakPosition = lineBreaker.Current.PositionMeasure; if (nextBreakPosition == 0) { break; } if (nextBreakPosition >= measuredLength) { break; } currentBreakPosition = nextBreakPosition; } measuredLength = currentBreakPosition; } } collapsedLength += measuredLength; var splitResult = TextFormatterImpl.SplitShapedRuns(_textRuns, collapsedLength); var shapedTextCharacters = new List <ShapedTextCharacters>(splitResult.First.Count + 1); shapedTextCharacters.AddRange(splitResult.First); SortRuns(shapedTextCharacters); shapedTextCharacters.Add(shapedSymbol); textRange = new TextRange(textRange.Start, collapsedLength); var textLine = new TextLineImpl(shapedTextCharacters, textRange, _paragraphWidth, _paragraphProperties, _flowDirection, TextLineBreak, true); return(textLine.FinalizeLine()); } availableWidth -= currentRun.Size.Width; collapsedLength += currentRun.GlyphRun.Characters.Length; runIndex++; } return(this); }