/// <summary> /// Splits the <see cref="TextRun"/> at specified length. /// </summary> /// <param name="length">The length.</param> /// <returns>The split result.</returns> public SplitTextCharactersResult Split(int length) { var glyphCount = 0; var firstCharacters = GlyphRun.Characters.Take(length); var codepointEnumerator = new CodepointEnumerator(firstCharacters); while (codepointEnumerator.MoveNext()) { glyphCount++; } if (GlyphRun.Characters.Length == length) { return(new SplitTextCharactersResult(this, null)); } if (GlyphRun.GlyphIndices.Length == glyphCount) { return(new SplitTextCharactersResult(this, null)); } var firstGlyphRun = new GlyphRun( Properties.Typeface.GlyphTypeface, Properties.FontRenderingEmSize, GlyphRun.GlyphIndices.Take(glyphCount), GlyphRun.GlyphAdvances.Take(glyphCount), GlyphRun.GlyphOffsets.Take(glyphCount), GlyphRun.Characters.Take(length), GlyphRun.GlyphClusters.Take(glyphCount)); var firstTextRun = new ShapedTextCharacters(firstGlyphRun, Properties); var secondGlyphRun = new GlyphRun( Properties.Typeface.GlyphTypeface, Properties.FontRenderingEmSize, GlyphRun.GlyphIndices.Skip(glyphCount), GlyphRun.GlyphAdvances.Skip(glyphCount), GlyphRun.GlyphOffsets.Skip(glyphCount), GlyphRun.Characters.Skip(length), GlyphRun.GlyphClusters.Skip(glyphCount)); var secondTextRun = new ShapedTextCharacters(secondGlyphRun, Properties); return(new SplitTextCharactersResult(firstTextRun, secondTextRun)); }
/// <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)); }