Example #1
0
        /// <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));
        }
Example #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);
        }
        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);
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
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);
        }