Пример #1
0
        /// <summary>
        /// Shape specified text runs with specified paragraph embedding.
        /// </summary>
        /// <param name="textRuns">The text runs to shape.</param>
        /// <param name="flowDirection">The paragraph embedding level.</param>
        /// <param name="resolvedFlowDirection">The resolved flow direction.</param>
        /// <returns>
        /// A list of shaped text characters.
        /// </returns>
        private static List <ShapedTextCharacters> ShapeTextRuns(List <TextCharacters> textRuns,
                                                                 FlowDirection flowDirection, out FlowDirection resolvedFlowDirection)
        {
            var shapedTextCharacters = new List <ShapedTextCharacters>();

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

            foreach (var textRun in textRuns)
            {
                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;

            foreach (var shapeableRuns in CoalesceLevels(textRuns, biDi.ResolvedLevels))
            {
                for (var index = 0; index < shapeableRuns.Count; index++)
                {
                    var currentRun = shapeableRuns[index];

                    var shapedBuffer = TextShaper.Current.ShapeText(currentRun.Text, currentRun.Properties.Typeface.GlyphTypeface,
                                                                    currentRun.Properties.FontRenderingEmSize, currentRun.Properties.CultureInfo, currentRun.BidiLevel);

                    var shapedCharacters = new ShapedTextCharacters(shapedBuffer, currentRun.Properties);


                    shapedTextCharacters.Add(shapedCharacters);
                }
            }

            return(shapedTextCharacters);
        }
Пример #2
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);
        }
Пример #3
0
        private bool Run(BiDiClassData t)
        {
            var bidi     = new BidiAlgorithm();
            var bidiData = new BidiData(t.ParagraphLevel);

            var text = Encoding.UTF32.GetString(MemoryMarshal.Cast <int, byte>(t.CodePoints).ToArray());

            // Append
            bidiData.Append(text.AsMemory());

            // Act
            for (int i = 0; i < 10; i++)
            {
                bidi.Process(bidiData);
            }

            var resultLevels         = bidi.ResolvedLevels;
            var resultParagraphLevel = bidi.ResolvedParagraphEmbeddingLevel;

            // Assert
            var passed = true;

            if (t.ResolvedParagraphLevel != resultParagraphLevel)
            {
                return(false);
            }

            for (var i = 0; i < t.ResolvedLevels.Length; i++)
            {
                if (t.ResolvedLevels[i] == -1)
                {
                    continue;
                }

                if (t.ResolvedLevels[i] != resultLevels[i])
                {
                    passed = false;
                    break;
                }
            }

            if (passed)
            {
                return(true);
            }

            _outputHelper.WriteLine($"Failed line {t.LineNumber}");

            _outputHelper.WriteLine(
                $"             Code Points: {string.Join(" ", t.CodePoints.Select(x => x.ToString("X4")))}");

            _outputHelper.WriteLine(
                $"      Pair Bracket Types: {string.Join(" ", bidiData.PairedBracketTypes.Select(x => " " + x.ToString()))}");

            _outputHelper.WriteLine(
                $"     Pair Bracket Values: {string.Join(" ", bidiData.PairedBracketValues.Select(x => x.ToString("X4")))}");
            _outputHelper.WriteLine($"             Embed Level: {t.ParagraphLevel}");
            _outputHelper.WriteLine($"    Expected Embed Level: {t.ResolvedParagraphLevel}");
            _outputHelper.WriteLine($"      Actual Embed Level: {resultParagraphLevel}");
            _outputHelper.WriteLine($"          Directionality: {string.Join(" ", bidiData.Classes)}");
            _outputHelper.WriteLine($"         Expected Levels: {string.Join(" ", t.ResolvedLevels)}");
            _outputHelper.WriteLine($"           Actual Levels: {string.Join(" ", resultLevels)}");

            return(false);
        }
Пример #4
0
        /// <summary>
        /// Shape specified text runs with specified paragraph embedding.
        /// </summary>
        /// <param name="textRuns">The text runs to shape.</param>
        /// <param name="flowDirection">The paragraph embedding level.</param>
        /// <param name="resolvedFlowDirection">The resolved flow direction.</param>
        /// <returns>
        /// A list of shaped text characters.
        /// </returns>
        private static List <ShapedTextCharacters> ShapeTextRuns(List <TextCharacters> textRuns,
                                                                 FlowDirection flowDirection, out FlowDirection resolvedFlowDirection)
        {
            var shapedTextCharacters = new List <ShapedTextCharacters>();

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

            foreach (var textRun in textRuns)
            {
                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 shapeableRuns = new List <ShapeableTextCharacters>(textRuns.Count);

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

            for (var index = 0; index < shapeableRuns.Count; index++)
            {
                var currentRun  = shapeableRuns[index];
                var groupedRuns = new List <ShapeableTextCharacters>(2)
                {
                    currentRun
                };
                var text         = currentRun.Text;
                var start        = currentRun.Text.Start;
                var length       = currentRun.Text.Length;
                var bufferOffset = currentRun.Text.BufferOffset;

                while (index + 1 < shapeableRuns.Count)
                {
                    var nextRun = shapeableRuns[index + 1];

                    if (currentRun.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++;

                        currentRun = nextRun;

                        continue;
                    }

                    break;
                }

                shapedTextCharacters.AddRange(ShapeTogether(groupedRuns, text));
            }

            return(shapedTextCharacters);
        }