Esempio n. 1
0
        private bool Run(BiDiTestData testData)
        {
            var bidi = new BidiAlgorithm();

            // Run the algorithm...
            ArraySlice <sbyte> resultLevels;

            bidi.Process(
                testData.Classes,
                ArraySlice <BidiPairedBracketType> .Empty,
                ArraySlice <int> .Empty,
                testData.ParagraphEmbeddingLevel,
                false,
                null,
                null,
                null);

            resultLevels = bidi.ResolvedLevels;

            // Check the results match
            var pass = true;

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

                    if (resultLevels[i] != testData.Levels[i])
                    {
                        pass = false;
                        break;
                    }
                }
            }
            else
            {
                pass = false;
            }

            if (!pass)
            {
                _outputHelper.WriteLine($"Failed line {testData.LineNumber}");
                _outputHelper.WriteLine($"        Data: {string.Join(" ", testData.Classes)}");
                _outputHelper.WriteLine($" Embed Level: {testData.ParagraphEmbeddingLevel}");
                _outputHelper.WriteLine($"    Expected: {string.Join(" ", testData.Levels)}");
                _outputHelper.WriteLine($"      Actual: {string.Join(" ", resultLevels)}");

                return(false);
            }

            return(true);
        }
Esempio n. 2
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);
        }
        /// <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 = new BidiAlgorithm();

            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);
        }