コード例 #1
0
ファイル: SKFontTest.cs プロジェクト: tonymkenu/SkiaSharp
        public void UnicodeGlyphsReturnsTheCorrectNumberOfCharacters()
        {
            const string text      = "🚀";
            var          emojiChar = StringUtilities.GetUnicodeCharacterCode(text, SKTextEncoding.Utf32);

            var typeface = SKFontManager.Default.MatchCharacter(emojiChar);

            Assert.NotNull(typeface);

            using var font = new SKFont();
            font.Typeface  = typeface;

            Assert.Equal(1, font.CountGlyphs(text));
            Assert.Single(font.GetGlyphs(text));
            Assert.NotEqual(0, font.GetGlyphs(text)[0]);
        }
コード例 #2
0
ファイル: SKFontTest.cs プロジェクト: tonymkenu/SkiaSharp
        public void PlainGlyphsReturnsTheCorrectNumberOfCharacters()
        {
            const string text = "Hello World!";

            var font = new SKFont();

            Assert.Equal(text.Length, font.CountGlyphs(text));
            Assert.Equal(text.Length, font.GetGlyphs(text).Length);
        }
コード例 #3
0
ファイル: SKFontTest.cs プロジェクト: tonymkenu/SkiaSharp
        public void MeasureTextMeasuresTheTextForGlyphs()
        {
            var font          = new SKFont();
            var expectedWidth = font.MeasureText("Hello World!");

            var glyphs = font.GetGlyphs("Hello World!");
            var width  = font.MeasureText(glyphs);

            Assert.Equal(expectedWidth, width);
        }
コード例 #4
0
ファイル: SKFontTest.cs プロジェクト: tonymkenu/SkiaSharp
        public void MeasureTextReturnsTheBoundsForGlyphs()
        {
            var font          = new SKFont();
            var expectedWidth = font.MeasureText("Hello World!", out var expectedBounds);

            var glyphs = font.GetGlyphs("Hello World!");
            var width  = font.MeasureText(glyphs, out var bounds);

            Assert.Equal(expectedWidth, width);
            Assert.Equal(expectedBounds, bounds);
        }
コード例 #5
0
        public unsafe void UnicharCountReturnsCorrectCount()
        {
            var text  = new uint[] { 79 };
            var count = text.Length * sizeof(uint);

            using var font = new SKFont();

            fixed(uint *t = text)
            {
                Assert.Equal(1, font.CountGlyphs((IntPtr)t, count, SKTextEncoding.Utf32));

                var glyphs = font.GetGlyphs((IntPtr)t, count, SKTextEncoding.Utf32);

                Assert.Single(glyphs);
            }
        }
コード例 #6
0
ファイル: FontFallback.cs プロジェクト: sebllll/RichTextKit
        public static IEnumerable <Run> GetFontRuns(Slice <int> codePoints, SKTypeface typeface)
        {
            // Get the font manager - we'll use this to select font fallbacks
            var fontManager = SKFontManager.Default;

            // Get glyphs using the top-level typeface
            var glyphs = new ushort[codePoints.Length];
            var font   = new SKFont(typeface);

            font.GetGlyphs(codePoints.AsSpan(), glyphs);

            // Look for subspans that need font fallback (where glyphs are zero)
            int runStart = 0;

            for (int i = 0; i < codePoints.Length; i++)
            {
                // Do we need fallback for this character?
                if (glyphs[i] == 0)
                {
                    // Check if there's a fallback available, if not, might as well continue with the current top-level typeface
                    var subSpanTypeface = fontManager.MatchCharacter(typeface.FamilyName, typeface.FontWeight, typeface.FontWidth, typeface.FontSlant, null, codePoints[i]);
                    if (subSpanTypeface == null)
                    {
                        continue;
                    }

                    // We can do font fallback...

                    // Flush the current top-level run
                    if (i > runStart)
                    {
                        yield return(new Run()
                        {
                            Start = runStart,
                            Length = i - runStart,
                            Typeface = typeface,
                        });
                    }

                    // Count how many unmatched characters
                    var unmatchedStart = i;
                    var unmatchedEnd   = i + 1;
                    while (unmatchedEnd < codePoints.Length && glyphs[unmatchedEnd] == 0)
                    {
                        unmatchedEnd++;
                    }
                    var unmatchedLength = unmatchedEnd - unmatchedStart;

                    // Match the missing characters
                    while (unmatchedLength > 0)
                    {
                        // Find the font fallback using the first character
                        subSpanTypeface = fontManager.MatchCharacter(typeface.FamilyName, typeface.FontWeight, typeface.FontWidth, typeface.FontSlant, null, codePoints[unmatchedStart]);
                        if (subSpanTypeface == null)
                        {
                            unmatchedEnd = unmatchedStart;
                            break;
                        }
                        var subSpanFont = new SKFont(subSpanTypeface);

                        // Get the glyphs over the current unmatched range
                        subSpanFont.GetGlyphs(codePoints.SubSlice(unmatchedStart, unmatchedLength).AsSpan(), new Span <ushort>(glyphs, unmatchedStart, unmatchedLength));

                        // Count how many characters were matched
                        var fallbackStart = unmatchedStart;
                        var fallbackEnd   = unmatchedStart + 1;
                        while (fallbackEnd < unmatchedEnd && glyphs[fallbackEnd] != 0)
                        {
                            fallbackEnd++;
                        }
                        var fallbackLength = fallbackEnd - fallbackStart;

                        // Yield this font fallback run
                        yield return(new Run()
                        {
                            Start = fallbackStart,
                            Length = fallbackLength,
                            Typeface = subSpanTypeface,
                        });

                        // Continue selecting font fallbacks until the entire unmatched ranges has been matched
                        unmatchedStart  += fallbackLength;
                        unmatchedLength -= fallbackLength;
                    }

                    // Move onto the next top level span
                    i        = unmatchedEnd - 1;    // account for i++ on for loop
                    runStart = unmatchedEnd;
                }
            }

            // Flush find run
            if (codePoints.Length > runStart)
            {
                yield return(new Run()
                {
                    Start = runStart,
                    Length = codePoints.Length - runStart,
                    Typeface = typeface,
                });
            }
        }
コード例 #7
0
ファイル: FontFallback.cs プロジェクト: ywscr/RichTextKit
        /// <summary>
        /// Splits a sequence of code points into a series of runs with font fallback applied
        /// </summary>
        /// <param name="codePoints">The code points</param>
        /// <param name="typeface">The preferred typeface</param>
        /// <param name="replacementCharacter">The replacement character to be used for the run</param>
        /// <returns>A sequence of runs with unsupported code points replaced by a selected font fallback</returns>
        public static IEnumerable <Run> GetFontRuns(Slice <int> codePoints, SKTypeface typeface, char replacementCharacter = '\0')
        {
            var font = new SKFont(typeface);

            if (replacementCharacter != '\0')
            {
                var glyph = font.GetGlyph(replacementCharacter);
                if (glyph == 0)
                {
                    var fallbackTypeface = CharacterMatcher.MatchCharacter(typeface.FamilyName, typeface.FontWeight, typeface.FontWidth, typeface.FontSlant, null, replacementCharacter);
                    if (fallbackTypeface != null)
                    {
                        typeface = fallbackTypeface;
                    }
                }

                yield return(new Run()
                {
                    Start = 0,
                    Length = codePoints.Length,
                    Typeface = typeface,
                });

                yield break;
            }

            // Get glyphs using the top-level typeface
            var glyphs = new ushort[codePoints.Length];

            font.GetGlyphs(codePoints.AsSpan(), glyphs);

            // Look for subspans that need font fallback (where glyphs are zero)
            int runStart = 0;

            for (int i = 0; i < codePoints.Length; i++)
            {
                // Do we need fallback for this character?
                if (glyphs[i] == 0)
                {
                    // Check if there's a fallback available, if not, might as well continue with the current top-level typeface
                    var subSpanTypeface = CharacterMatcher.MatchCharacter(typeface.FamilyName, typeface.FontWeight, typeface.FontWidth, typeface.FontSlant, null, codePoints[i]);
                    if (subSpanTypeface == null)
                    {
                        continue;
                    }

                    // Don't fallback for whitespace characters
                    if (UnicodeClasses.BoundaryGroup(codePoints[i]) == WordBoundaryClass.Space)
                    {
                        continue;
                    }

                    // Must be a cluster boundary
                    if (!GraphemeClusterAlgorithm.IsBoundary(codePoints, i))
                    {
                        continue;
                    }

                    // We can do font fallback...

                    // Flush the current top-level run
                    if (i > runStart)
                    {
                        yield return(new Run()
                        {
                            Start = runStart,
                            Length = i - runStart,
                            Typeface = typeface,
                        });
                    }

                    // Count how many unmatched characters
                    var unmatchedStart = i;
                    var unmatchedEnd   = i + 1;
                    while (unmatchedEnd < codePoints.Length &&
                           (glyphs[unmatchedEnd] == 0 || !GraphemeClusterAlgorithm.IsBoundary(codePoints, unmatchedEnd)))
                    {
                        unmatchedEnd++;
                    }
                    var unmatchedLength = unmatchedEnd - unmatchedStart;

                    // Match the missing characters
                    while (unmatchedLength > 0)
                    {
                        // Find the font fallback using the first character
                        subSpanTypeface = CharacterMatcher.MatchCharacter(typeface.FamilyName, typeface.FontWeight, typeface.FontWidth, typeface.FontSlant, null, codePoints[unmatchedStart]);
                        if (subSpanTypeface == null)
                        {
                            unmatchedEnd = unmatchedStart;
                            break;
                        }
                        var subSpanFont = new SKFont(subSpanTypeface);

                        // Get the glyphs over the current unmatched range
                        subSpanFont.GetGlyphs(codePoints.SubSlice(unmatchedStart, unmatchedLength).AsSpan(), new Span <ushort>(glyphs, unmatchedStart, unmatchedLength));

                        // Count how many characters were matched
                        var fallbackStart = unmatchedStart;
                        var fallbackEnd   = unmatchedStart + 1;
                        while (fallbackEnd < unmatchedEnd && glyphs[fallbackEnd] != 0)
                        {
                            fallbackEnd++;
                        }
                        var fallbackLength = fallbackEnd - fallbackStart;

                        // Yield this font fallback run
                        yield return(new Run()
                        {
                            Start = fallbackStart,
                            Length = fallbackLength,
                            Typeface = subSpanTypeface,
                        });

                        // Continue selecting font fallbacks until the entire unmatched ranges has been matched
                        unmatchedStart  += fallbackLength;
                        unmatchedLength -= fallbackLength;
                    }

                    // Move onto the next top level span
                    i        = unmatchedEnd - 1;    // account for i++ on for loop
                    runStart = unmatchedEnd;
                }
            }

            // Flush find run
            if (codePoints.Length > runStart)
            {
                yield return(new Run()
                {
                    Start = runStart,
                    Length = codePoints.Length - runStart,
                    Typeface = typeface,
                });
            }
        }