Ejemplo n.º 1
0
 public AdornmentTextRun(HexLinePart linePart)
 {
     Debug2.Assert(linePart.AdornmentElement is not null);
     adornmentElement = linePart.AdornmentElement;
     if (linePart.Span.Length != 0 || adornmentElement.Affinity == VST.PositionAffinity.Successor)
     {
         BreakBefore = LineBreakCondition.BreakPossible;
         BreakAfter  = LineBreakCondition.BreakRestrained;
     }
     else
     {
         BreakBefore = LineBreakCondition.BreakRestrained;
         BreakAfter  = LineBreakCondition.BreakPossible;
     }
     HasFixedSize = true;
     Length       = linePart.ColumnLength;
     Properties   = linePart.TextRunProperties;
 }
Ejemplo n.º 2
0
        public bool Equals(TextRunProperties?other)
        {
            if (ReferenceEquals(null, other))
            {
                return(false);
            }
            if (ReferenceEquals(this, other))
            {
                return(true);
            }

            return(Typeface.Equals(other.Typeface) &&
                   FontRenderingEmSize.Equals(other.FontRenderingEmSize) &&
                   Equals(TextDecorations, other.TextDecorations) &&
                   Equals(ForegroundBrush, other.ForegroundBrush) &&
                   Equals(BackgroundBrush, other.BackgroundBrush) &&
                   Equals(CultureInfo, other.CultureInfo));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Gets a list of <see cref="ShapeableTextCharacters"/>.
        /// </summary>
        /// <returns>The shapeable text characters.</returns>
        internal IReadOnlyList <ShapeableTextCharacters> GetShapeableCharacters(ReadOnlySlice <char> runText, sbyte biDiLevel,
                                                                                ref TextRunProperties?previousProperties)
        {
            var shapeableCharacters = new List <ShapeableTextCharacters>(2);

            while (!runText.IsEmpty)
            {
                var shapeableRun = CreateShapeableRun(runText, Properties, biDiLevel, ref previousProperties);

                shapeableCharacters.Add(shapeableRun);

                runText = runText.Skip(shapeableRun.Text.Length);

                previousProperties = shapeableRun.Properties;
            }

            return(shapeableCharacters);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Coalesces ranges of the same bidi level to form <see cref="ShapeableTextCharacters"/>
        /// </summary>
        /// <param name="textCharacters">The text characters to form <see cref="ShapeableTextCharacters"/> from.</param>
        /// <param name="levels">The bidi levels.</param>
        /// <returns></returns>
        private static IEnumerable <IReadOnlyList <TextRun> > CoalesceLevels(
            IReadOnlyList <TextRun> textCharacters,
            ReadOnlySlice <sbyte> levels)
        {
            if (levels.Length == 0)
            {
                yield break;
            }

            var levelIndex = 0;
            var runLevel   = levels[0];

            TextRunProperties?previousProperties = null;
            TextCharacters?   currentRun         = null;
            var runText = ReadOnlySlice <char> .Empty;

            for (var i = 0; i < textCharacters.Count; i++)
            {
                var j = 0;
                currentRun = textCharacters[i] as TextCharacters;

                if (currentRun == null)
                {
                    var drawableRun = textCharacters[i];

                    yield return(new[] { drawableRun });

                    levelIndex += drawableRun.TextSourceLength;

                    continue;
                }

                runText = currentRun.Text;

                for (; j < runText.Length;)
                {
                    Codepoint.ReadAt(runText, j, out var count);

                    if (levelIndex + 1 == levels.Length)
                    {
                        break;
                    }

                    levelIndex++;
                    j += count;

                    if (j == runText.Length)
                    {
                        yield return(currentRun.GetShapeableCharacters(runText.Take(j), runLevel, ref previousProperties));

                        runLevel = levels[levelIndex];

                        continue;
                    }

                    if (levels[levelIndex] == runLevel)
                    {
                        continue;
                    }

                    // End of this run
                    yield return(currentRun.GetShapeableCharacters(runText.Take(j), runLevel, ref previousProperties));

                    runText = runText.Skip(j);

                    j = 0;

                    // Move to next run
                    runLevel = levels[levelIndex];
                }
            }

            if (currentRun is null || runText.IsEmpty)
            {
                yield break;
            }

            yield return(currentRun.GetShapeableCharacters(runText, runLevel, ref previousProperties));
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Creates a shapeable text run with unique properties.
        /// </summary>
        /// <param name="text">The text to create text runs from.</param>
        /// <param name="defaultProperties">The default text run properties.</param>
        /// <param name="biDiLevel">The bidi level of the run.</param>
        /// <param name="previousProperties"></param>
        /// <returns>A list of shapeable text runs.</returns>
        private static ShapeableTextCharacters CreateShapeableRun(ReadOnlySlice <char> text,
                                                                  TextRunProperties defaultProperties, sbyte biDiLevel, ref TextRunProperties?previousProperties)
        {
            var defaultTypeface  = defaultProperties.Typeface;
            var currentTypeface  = defaultTypeface;
            var previousTypeface = previousProperties?.Typeface;

            if (TryGetShapeableLength(text, currentTypeface, null, out var count, out var script))
            {
                if (script == Script.Common && previousTypeface is not null)
                {
                    if (TryGetShapeableLength(text, previousTypeface.Value, defaultTypeface, out var fallbackCount, out _))
                    {
                        return(new ShapeableTextCharacters(text.Take(fallbackCount),
                                                           defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel));
                    }
                }

                return(new ShapeableTextCharacters(text.Take(count), defaultProperties.WithTypeface(currentTypeface),
                                                   biDiLevel));
            }

            if (previousTypeface is not null)
            {
                if (TryGetShapeableLength(text, previousTypeface.Value, defaultTypeface, out count, out _))
                {
                    return(new ShapeableTextCharacters(text.Take(count),
                                                       defaultProperties.WithTypeface(previousTypeface.Value), biDiLevel));
                }
            }

            var codepoint = Codepoint.ReplacementCodepoint;

            var codepointEnumerator = new CodepointEnumerator(text.Skip(count));

            while (codepointEnumerator.MoveNext())
            {
                if (codepointEnumerator.Current.IsWhiteSpace)
                {
                    continue;
                }

                codepoint = codepointEnumerator.Current;

                break;
            }

            //ToDo: Fix FontFamily fallback
            var matchFound =
                FontManager.Current.TryMatchCharacter(codepoint, defaultTypeface.Style, defaultTypeface.Weight,
                                                      defaultTypeface.Stretch, defaultTypeface.FontFamily, defaultProperties.CultureInfo,
                                                      out currentTypeface);

            if (matchFound && TryGetShapeableLength(text, currentTypeface, defaultTypeface, out count, out _))
            {
                //Fallback found
                return(new ShapeableTextCharacters(text.Take(count), defaultProperties.WithTypeface(currentTypeface),
                                                   biDiLevel));
            }

            // no fallback found
            currentTypeface = defaultTypeface;

            var glyphTypeface = currentTypeface.GlyphTypeface;

            var enumerator = new GraphemeEnumerator(text);

            while (enumerator.MoveNext())
            {
                var grapheme = enumerator.Current;

                if (!grapheme.FirstCodepoint.IsWhiteSpace && glyphTypeface.TryGetGlyph(grapheme.FirstCodepoint, out _))
                {
                    break;
                }

                count += grapheme.Text.Length;
            }

            return(new ShapeableTextCharacters(text.Take(count), defaultProperties, biDiLevel));
        }