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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        /// <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);
        }