Пример #1
0
        /// <summary>
        /// Performs text wrapping returns a list of text lines.
        /// </summary>
        /// <param name="textRuns"></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>
        /// <param name="flowDirection"></param>
        /// <param name="currentLineBreak">The current line break if the line was explicitly broken.</param>
        /// <returns>The wrapped text line.</returns>
        private static TextLineImpl PerformTextWrapping(List <ShapedTextCharacters> textRuns, TextRange textRange,
                                                        double paragraphWidth, TextParagraphProperties paragraphProperties, FlowDirection flowDirection,
                                                        TextLineBreak?currentLineBreak)
        {
            var measuredLength = MeasureLength(textRuns, textRange, paragraphWidth);

            var currentLength = 0;

            var lastWrapPosition = 0;

            var currentPosition = 0;

            for (var index = 0; index < textRuns.Count; index++)
            {
                var currentRun = textRuns[index];

                var lineBreaker = new LineBreakEnumerator(currentRun.Text);

                var breakFound = false;

                while (lineBreaker.MoveNext())
                {
                    if (lineBreaker.Current.Required &&
                        currentLength + lineBreaker.Current.PositionMeasure <= measuredLength)
                    {
                        //Explicit break found
                        breakFound = true;

                        currentPosition = currentLength + lineBreaker.Current.PositionWrap;

                        break;
                    }

                    if (currentLength + lineBreaker.Current.PositionMeasure > measuredLength)
                    {
                        if (paragraphProperties.TextWrapping == TextWrapping.WrapWithOverflow)
                        {
                            if (lastWrapPosition > 0)
                            {
                                currentPosition = lastWrapPosition;

                                breakFound = true;

                                break;
                            }

                            //Find next possible wrap position (overflow)
                            if (index < textRuns.Count - 1)
                            {
                                if (lineBreaker.Current.PositionWrap != currentRun.Text.Length)
                                {
                                    //We already found the next possible wrap position.
                                    breakFound = true;

                                    currentPosition = currentLength + lineBreaker.Current.PositionWrap;

                                    break;
                                }

                                while (lineBreaker.MoveNext() && index < textRuns.Count)
                                {
                                    currentPosition += lineBreaker.Current.PositionWrap;

                                    if (lineBreaker.Current.PositionWrap != currentRun.Text.Length)
                                    {
                                        break;
                                    }

                                    index++;

                                    if (index >= textRuns.Count)
                                    {
                                        break;
                                    }

                                    currentRun = textRuns[index];

                                    lineBreaker = new LineBreakEnumerator(currentRun.Text);
                                }
                            }
                            else
                            {
                                currentPosition = currentLength + lineBreaker.Current.PositionWrap;
                            }

                            breakFound = true;

                            break;
                        }

                        //We overflowed so we use the last available wrap position.
                        currentPosition = lastWrapPosition == 0 ? measuredLength : lastWrapPosition;

                        breakFound = true;

                        break;
                    }

                    if (lineBreaker.Current.PositionMeasure != lineBreaker.Current.PositionWrap)
                    {
                        lastWrapPosition = currentLength + lineBreaker.Current.PositionWrap;
                    }
                }

                if (!breakFound)
                {
                    currentLength += currentRun.Text.Length;

                    continue;
                }

                measuredLength = currentPosition;

                break;
            }

            var splitResult = SplitShapedRuns(textRuns, measuredLength);

            textRange = new TextRange(textRange.Start, measuredLength);

            var remainingCharacters = splitResult.Second;

            var lineBreak = remainingCharacters?.Count > 0 ?
                            new TextLineBreak(currentLineBreak?.TextEndOfLine, flowDirection, remainingCharacters) :
                            null;

            if (lineBreak is null && currentLineBreak?.TextEndOfLine != null)
            {
                lineBreak = new TextLineBreak(currentLineBreak.TextEndOfLine, flowDirection);
            }

            TextLineImpl.SortRuns(splitResult.First);

            var textLine = new TextLineImpl(splitResult.First, textRange, paragraphWidth, paragraphProperties, flowDirection,
                                            lineBreak);

            return(textLine.FinalizeLine());
        }
Пример #2
0
        /// <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)));
        }
Пример #3
0
 /// <summary>
 /// Formats a text line.
 /// </summary>
 /// <param name="textSource">The text source.</param>
 /// <param name="firstTextSourceIndex">The first character index to start the text line from.</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>The formatted line.</returns>
 public abstract TextLine FormatLine(ITextSource textSource, int firstTextSourceIndex, double paragraphWidth,
                                     TextParagraphProperties paragraphProperties);
Пример #4
0
        /// <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>
        /// <param name="currentLineBreak">The current line break if the line was explicitly broken.</param>
        /// <returns>The wrapped text line.</returns>
        private static TextLine PerformTextWrapping(List <ShapedTextCharacters> textRuns, TextRange textRange,
                                                    double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak currentLineBreak)
        {
            var availableWidth = paragraphWidth;
            var currentWidth   = 0.0;
            var runIndex       = 0;
            var currentLength  = 0;

            while (runIndex < textRuns.Count)
            {
                var currentRun = textRuns[runIndex];

                if (currentWidth + currentRun.Size.Width > availableWidth)
                {
                    var breakFound = false;

                    var currentBreakPosition = 0;

                    if (TryMeasureCharacters(currentRun, paragraphWidth - currentWidth, out var measuredLength))
                    {
                        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;
                            }
                        }
                    }
                    else
                    {
                        // Make sure we wrap at least one character.
                        if (currentLength == 0)
                        {
                            measuredLength = 1;
                        }
                    }

                    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 remainingCharacters = splitResult.Second;

                    if (currentLineBreak?.RemainingCharacters != null)
                    {
                        if (remainingCharacters != null)
                        {
                            remainingCharacters.AddRange(currentLineBreak.RemainingCharacters);
                        }
                        else
                        {
                            remainingCharacters = new List <ShapedTextCharacters>(currentLineBreak.RemainingCharacters);
                        }
                    }

                    var lineBreak = remainingCharacters != null && remainingCharacters.Count > 0 ?
                                    new TextLineBreak(remainingCharacters) :
                                    null;

                    return(new TextLineImpl(splitResult.First, textLineMetrics, lineBreak));
                }

                currentWidth += currentRun.Size.Width;

                currentLength += currentRun.GlyphRun.Characters.Length;

                runIndex++;
            }

            return(new TextLineImpl(textRuns,
                                    TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties),
                                    currentLineBreak?.RemainingCharacters != null ?
                                    new TextLineBreak(currentLineBreak.RemainingCharacters) :
                                    null));
        }
Пример #5
0
        /// <summary>
        /// Performs text trimming and returns a trimmed line.
        /// </summary>
        /// <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>
        /// <param name="textRuns">The text runs to perform the trimming on.</param>
        /// <param name="text">The text that was used to construct the text runs.</param>
        /// <returns></returns>
        private static TextLine PerformTextTrimming(TextPointer text, IReadOnlyList <ShapedTextRun> textRuns,
                                                    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.Style);

                    var measuredLength = MeasureText(currentRun, availableWidth - ellipsisRun.GlyphRun.Bounds.Width);

                    if (textTrimming == TextTrimming.WordEllipsis)
                    {
                        if (measuredLength < text.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 <ShapedTextRun>(splitResult.First.Count + 1);

                    trimmedRuns.AddRange(splitResult.First);

                    trimmedRuns.Add(ellipsisRun);

                    var textLineMetrics =
                        TextLineMetrics.Create(trimmedRuns, paragraphWidth, paragraphProperties.TextAlignment);

                    return(new SimpleTextLine(text.Take(measuredLength), trimmedRuns, textLineMetrics));
                }

                availableWidth -= currentRun.GlyphRun.Bounds.Width;

                runIndex++;
            }

            return(new SimpleTextLine(text, textRuns,
                                      TextLineMetrics.Create(textRuns, paragraphWidth, paragraphProperties.TextAlignment)));
        }
Пример #6
0
        /// <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>
        /// <param name="currentLineBreak">The current line break if the line was explicitly broken.</param>
        /// <returns>The wrapped text line.</returns>
        private static TextLine PerformTextWrapping(List <ShapedTextCharacters> textRuns, TextRange textRange,
                                                    double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak?currentLineBreak)
        {
            var availableWidth = paragraphWidth;
            var currentWidth   = 0.0;
            var measuredLength = 0;

            foreach (var currentRun in textRuns)
            {
                if (currentWidth + currentRun.Size.Width > availableWidth)
                {
                    if (TryMeasureCharacters(currentRun, paragraphWidth - currentWidth, out var count))
                    {
                        measuredLength += count;
                    }

                    break;
                }

                currentWidth += currentRun.Size.Width;

                measuredLength += currentRun.Text.Length;
            }

            var currentLength = 0;

            var lastWrapPosition = 0;

            var currentPosition = 0;

            if (measuredLength == 0 && paragraphProperties.TextWrapping != TextWrapping.WrapWithOverflow)
            {
                measuredLength = 1;
            }
            else
            {
                for (var index = 0; index < textRuns.Count; index++)
                {
                    var currentRun = textRuns[index];

                    var lineBreaker = new LineBreakEnumerator(currentRun.Text);

                    var breakFound = false;

                    while (lineBreaker.MoveNext())
                    {
                        if (lineBreaker.Current.Required &&
                            currentLength + lineBreaker.Current.PositionMeasure <= measuredLength)
                        {
                            breakFound = true;

                            currentPosition = currentLength + lineBreaker.Current.PositionWrap;

                            break;
                        }

                        if ((paragraphProperties.TextWrapping != TextWrapping.WrapWithOverflow || lastWrapPosition != 0) &&
                            currentLength + lineBreaker.Current.PositionMeasure > measuredLength)
                        {
                            if (lastWrapPosition > 0)
                            {
                                currentPosition = lastWrapPosition;
                            }
                            else
                            {
                                currentPosition = currentLength + measuredLength;
                            }

                            breakFound = true;

                            break;
                        }

                        if (currentLength + lineBreaker.Current.PositionWrap >= measuredLength)
                        {
                            currentPosition = currentLength + lineBreaker.Current.PositionWrap;

                            if (index < textRuns.Count - 1 &&
                                lineBreaker.Current.PositionWrap == currentRun.Text.Length)
                            {
                                var nextRun = textRuns[index + 1];

                                lineBreaker = new LineBreakEnumerator(nextRun.Text);

                                if (lineBreaker.MoveNext() &&
                                    lineBreaker.Current.PositionMeasure == 0)
                                {
                                    currentPosition += lineBreaker.Current.PositionWrap;
                                }
                            }

                            breakFound = true;

                            break;
                        }

                        lastWrapPosition = currentLength + lineBreaker.Current.PositionWrap;
                    }

                    if (!breakFound)
                    {
                        currentLength += currentRun.Text.Length;

                        continue;
                    }

                    measuredLength = currentPosition;

                    break;
                }
            }

            var splitResult = SplitTextRuns(textRuns, measuredLength);

            textRange = new TextRange(textRange.Start, measuredLength);

            var remainingCharacters = splitResult.Second;

            var lineBreak = remainingCharacters?.Count > 0 ? new TextLineBreak(remainingCharacters) : null;

            if (lineBreak is null && currentLineBreak?.TextEndOfLine != null)
            {
                lineBreak = new TextLineBreak(currentLineBreak.TextEndOfLine);
            }

            return(new TextLineImpl(splitResult.First, textRange, paragraphWidth, paragraphProperties, lineBreak));
        }
Пример #7
0
        /// <summary>
        /// Shape specified text runs with specified paragraph embedding.
        /// </summary>
        /// <param name="textRuns">The text runs to shape.</param>
        /// <param name="paragraphProperties">The default paragraph properties.</param>
        /// <param name="resolvedFlowDirection">The resolved flow direction.</param>
        /// <returns>
        /// A list of shaped text characters.
        /// </returns>
        private static List <DrawableTextRun> ShapeTextRuns(List <TextRun> textRuns, TextParagraphProperties paragraphProperties,
                                                            out FlowDirection resolvedFlowDirection)
        {
            var flowDirection    = paragraphProperties.FlowDirection;
            var drawableTextRuns = new List <DrawableTextRun>();

            var biDiData = new BidiData((sbyte)flowDirection);

            foreach (var textRun in textRuns)
            {
                if (textRun.Text.IsEmpty)
                {
                    var text = new char[textRun.TextSourceLength];

                    biDiData.Append(text);
                }
                else
                {
                    biDiData.Append(textRun.Text);
                }
            }

            var biDi = BidiAlgorithm.Instance.Value !;

            biDi.Process(biDiData);

            var resolvedEmbeddingLevel = biDi.ResolveEmbeddingLevel(biDiData.Classes);

            resolvedFlowDirection =
                (resolvedEmbeddingLevel & 1) == 0 ? FlowDirection.LeftToRight : FlowDirection.RightToLeft;

            var processedRuns = new List <TextRun>(textRuns.Count);

            foreach (var coalescedRuns in CoalesceLevels(textRuns, biDi.ResolvedLevels))
            {
                processedRuns.AddRange(coalescedRuns);
            }

            for (var index = 0; index < processedRuns.Count; index++)
            {
                var currentRun = processedRuns[index];

                switch (currentRun)
                {
                case DrawableTextRun drawableRun:
                {
                    drawableTextRuns.Add(drawableRun);

                    break;
                }

                case ShapeableTextCharacters shapeableRun:
                {
                    var groupedRuns = new List <ShapeableTextCharacters>(2)
                    {
                        shapeableRun
                    };
                    var text         = currentRun.Text;
                    var start        = currentRun.Text.Start;
                    var length       = currentRun.Text.Length;
                    var bufferOffset = currentRun.Text.BufferOffset;

                    while (index + 1 < processedRuns.Count)
                    {
                        if (processedRuns[index + 1] is not ShapeableTextCharacters nextRun)
                        {
                            break;
                        }

                        if (shapeableRun.CanShapeTogether(nextRun))
                        {
                            groupedRuns.Add(nextRun);

                            length += nextRun.Text.Length;

                            if (start > nextRun.Text.Start)
                            {
                                start = nextRun.Text.Start;
                            }

                            if (bufferOffset > nextRun.Text.BufferOffset)
                            {
                                bufferOffset = nextRun.Text.BufferOffset;
                            }

                            text = new ReadOnlySlice <char>(text.Buffer, start, length, bufferOffset);

                            index++;

                            shapeableRun = nextRun;

                            continue;
                        }

                        break;
                    }

                    var shaperOptions = new TextShaperOptions(currentRun.Properties !.Typeface.GlyphTypeface,
                                                              currentRun.Properties.FontRenderingEmSize,
                                                              shapeableRun.BidiLevel, currentRun.Properties.CultureInfo, paragraphProperties.DefaultIncrementalTab);

                    drawableTextRuns.AddRange(ShapeTogether(groupedRuns, text, shaperOptions));

                    break;
                }
                }
            }

            return(drawableTextRuns);
        }
Пример #8
0
 /// <summary>
 /// Formats a text line.
 /// </summary>
 /// <param name="textSource">The text source.</param>
 /// <param name="firstTextSourceIndex">The first character index to start the text line from.</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>
 /// <param name="previousLineBreak">A <see cref="TextLineBreak"/> value that specifies the text formatter state,
 /// in terms of where the previous line in the paragraph was broken by the text formatting process.</param>
 /// <returns>The formatted line.</returns>
 public abstract TextLine FormatLine(ITextSource textSource, int firstTextSourceIndex, double paragraphWidth,
                                     TextParagraphProperties paragraphProperties, TextLineBreak?previousLineBreak = null);
Пример #9
0
        /// <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 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)
                    {
                        if (paragraphProperties.TextWrapping == TextWrapping.WrapWithOverflow)
                        {
                            var lineBreaker = new LineBreakEnumerator(currentRun.Text.Skip(measuredLength));

                            if (lineBreaker.MoveNext())
                            {
                                measuredLength += lineBreaker.Current.PositionWrap;
                            }
                            else
                            {
                                measuredLength = currentRun.Text.Length;
                            }
                        }
                        else
                        {
                            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,
                                                                 new TextRange(textRange.Start, length), 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;

                length += currentRun.GlyphRun.Characters.Length;

                runIndex++;
            }

            return(new TextLineImpl(textRuns,
                                    TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties)));
        }
Пример #10
0
        /// <summary>
        /// Creates an empty text line.
        /// </summary>
        /// <returns>The empty text line.</returns>
        public static TextLineImpl CreateEmptyTextLine(int firstTextSourceIndex, double paragraphWidth, TextParagraphProperties paragraphProperties)
        {
            var flowDirection = paragraphProperties.FlowDirection;
            var properties    = paragraphProperties.DefaultTextRunProperties;
            var glyphTypeface = properties.Typeface.GlyphTypeface;
            var text          = new ReadOnlySlice <char>(s_empty, firstTextSourceIndex, 1);
            var glyph         = glyphTypeface.GetGlyph(s_empty[0]);
            var glyphInfos    = new[] { new GlyphInfo(glyph, firstTextSourceIndex) };

            var shapedBuffer = new ShapedBuffer(text, glyphInfos, glyphTypeface, properties.FontRenderingEmSize,
                                                (sbyte)flowDirection);

            var textRuns = new List <DrawableTextRun> {
                new ShapedTextCharacters(shapedBuffer, properties)
            };

            return(new TextLineImpl(textRuns, firstTextSourceIndex, 0, paragraphWidth, paragraphProperties, flowDirection).FinalizeLine());
        }