public static int?GlyphIndexForXOffset <TFont, TGlyph>(this AttributedGlyphRun <TFont, TGlyph> line, TypesettingContext <TFont, TGlyph> context, float offset) where TFont : IFont <TGlyph>
        {
            if (offset < 0)
            {
                return(0);      //Move cursor to index 0
            }
            int   i        = 0;
            float x        = 0;
            var   advances = context.GlyphBoundsProvider.GetAdvancesForGlyphs(line.Font, line.Glyphs.AsForEach(), line.Length).Advances;

            foreach (var(advance, kernAfter) in advances.Zip(line.GlyphInfos.Select(g => g.KernAfterGlyph), ValueTuple.Create))
            {
                if (x <= offset && offset < advance + x)
                {
                    return(i);
                }
                else
                {
                    x += advance + kernAfter;
                    i++;
                    if (offset < x) //If the point is in the kern after this, then the index is the one after this
                    {
                        return(i);
                    }
                }
            }
            return(null);
        }
Example #2
0
        public static float XOffsetForGlyphIndex <TFont, TGlyph>
            (this AttributedGlyphRun <TFont, TGlyph> line, TypesettingContext <TFont, TGlyph> context, int index)
            where TFont : IFont <TGlyph>
        {
            if (index < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(index), index, "The index is negative.");
            }
            int   i        = 0;
            float x        = 0;
            var   advances =
                context.GlyphBoundsProvider.GetAdvancesForGlyphs(line.Font, line.Glyphs, line.Length).Advances;

            foreach (var(advance, kernAfter) in
                     advances.Zip(line.GlyphInfos.Select(g => g.KernAfterGlyph), ValueTuple.Create))
            {
                if (i++ >= index)
                {
                    return(x);
                }
                else
                {
                    x += advance + kernAfter;
                }
            }
            throw new ArgumentOutOfRangeException(nameof(index), index, "The index is beyond the end of the string.");
        }
Example #3
0
        public float GetTypographicWidth(TFont font, AttributedGlyphRun <TFont, TGlyph> run)
        {
            var aString = run.ToNsAttributedString();

            using (var ctLine = new CTLine(aString))
                return((float)ctLine.GetTypographicBounds());
        }
Example #4
0
 public static UIStringAttributes FromAttributedGlyphRun(AttributedGlyphRun <TFont, TGlyph> glyphRun, Color color)
 {
     return(new UIStringAttributes {
         ForegroundColor = color.ToUiColor(),
         Font = UIFont.SystemFontOfSize(glyphRun.Font.PointSize)
     });
 }
        public static NSMutableAttributedString ToNsAttributedString(this AttributedGlyphRun <TFont, TGlyph> glyphRun)
        {
            var font           = glyphRun.Font;
            var text           = glyphRun.Text.ToString();
            var unicodeIndexes = StringInfo.ParseCombiningCharacters(text);
            var attributes     = new CTStringAttributes
            {
                ForegroundColorFromContext = true,
                Font = font.CtFont
            };
            var attributedString = new NSMutableAttributedString(text, attributes);
            var kernedGlyphs     = glyphRun.GlyphInfos;

            for (int i = 0; i < kernedGlyphs.Count; i++)
            {
                var endIndex = (i < unicodeIndexes.Length - 1) ? unicodeIndexes[i + 1] : text.Length;
                var range    = new NSRange(unicodeIndexes[i], endIndex - unicodeIndexes[i]);
                if (kernedGlyphs[i].KernAfterGlyph is var kern && !(kern is 0))
                {
                    attributedString.AddAttribute(CTStringAttributeKey.KerningAdjustment, new NSNumber(kern), range);
                }
                if (kernedGlyphs[i].Foreground is Structures.Color foreground)
                {
                    attributedString.AddAttribute(CTStringAttributeKey.ForegroundColor, ObjCRuntime.Runtime.GetNSObject(foreground.ToCgColor().Handle), range);
                }
            }
            return(attributedString);
        }
        public static NSMutableAttributedString ToNsAttributedString(this AttributedGlyphRun <TFont, TGlyph> glyphRun)
        {
            var font           = glyphRun.Font;
            var text           = glyphRun.Text;
            var unicodeIndexes = StringInfo.ParseCombiningCharacters(text);
            var attributes     = new CTStringAttributes
            {
                ForegroundColorFromContext = true,
                Font = font.CtFont
            };
            var attributedString = new NSMutableAttributedString(text, attributes);
            var kernedGlyphs     = glyphRun.KernedGlyphs;

            for (int i = 0; i < kernedGlyphs.Length; i++)
            {
                var kern = kernedGlyphs[i].KernAfterGlyph;
                if (kern != 0)
                {
                    var endIndex = (i < unicodeIndexes.Length - 1) ? unicodeIndexes[i + 1] : text.Length;
                    var range    = new NSRange(unicodeIndexes[i], endIndex - unicodeIndexes[i]);
                    attributedString.AddAttribute(CTStringAttributeKey.KerningAdjustment, new NSNumber(kern), range);
                }
            }
            return(attributedString);
        }
        public float GetTypographicWidth(TestMathFont font, AttributedGlyphRun <TestMathFont, TGlyph> run)
        {
            int   effectiveLength = GetEffectiveLength(run.Glyphs.ToArray());
            float width           = font.PointSize * effectiveLength * WidthPerCharacterPerFontSize +
                                    run.KernedGlyphs.Sum(g => g.KernAfterGlyph);

            return(width);
        }
Example #8
0
 public static CTStringAttributes CtFromAttributedGlyphRun(AttributedGlyphRun <TFont, TGlyph> glyphRun)
 {
     return(new CTStringAttributes()
     {
         ForegroundColorFromContext = true,
         Font = glyphRun.Font.CtFont
     });
 }
Example #9
0
        public void TestGlyphBoundsWithoutM()
        {
            string hello    = "Hello";
            var    font     = new TestFont(10);
            var    provider = TestGlyphBoundsProvider.Instance;
            var    glyphRun = new AttributedGlyphRun <TestFont, TGlyph>(hello, hello, font);
            var    width    = provider.GetTypographicWidth(font, glyphRun);

            Approximately.Equal(width, 25, 0.01);
        }
Example #10
0
        public void TestGlyphBoundsWithM()
        {
            string america  = "America";
            var    font     = new TestFont(10);
            var    provider = TestGlyphBoundsProvider.Instance;
            var    glyphRun = new AttributedGlyphRun <TestFont, TGlyph>(america, america, font);
            var    width    = provider.GetTypographicWidth(font, glyphRun);

            Approximately.Equal(width, 40, 0.01);
        }
Example #11
0
 public void DrawGlyphRunWithOffset(AttributedGlyphRun <TFont, TGlyph> run, PointF offset, Color?color)
 {
     CgContext.TextPosition = new CGPoint
                                  (CgContext.TextPosition.X + offset.X, CgContext.TextPosition.Y + offset.Y);
     if (color.HasValue)
     {
         CgContext.SetFillColor(color.GetValueOrDefault().ToCGColor());
     }
     using var textLine = new CTLine(run.ToNsAttributedString());
     textLine.Draw(CgContext);
 }
 public void DrawGlyphRunWithOffset(AttributedGlyphRun <TFont, TGlyph> run, PointF offset, Color?color)
 {
     DebugWriteLine($"Text {run} {offset.X} {offset.Y}");
     CgContext.TextPosition = new CGPoint(CgContext.TextPosition.X + offset.X, CgContext.TextPosition.Y + offset.Y);
     if (color.HasValue)
     {
         CgContext.SetFillColor(color.Value.ToCgColor());
     }
     using (var textLine = new CTLine(run.ToNsAttributedString()))
         textLine.Draw(CgContext);
 }
Example #13
0
        public void TestGlyphBoundsWithoutM()
        {
            string hello    = "Hello";
            var    font     = new TestFont(10);
            var    provider = TestGlyphBoundsProvider.Instance;
            var    glyphRun = new AttributedGlyphRun <TestFont, TGlyph>(hello, hello.EnumerateRunes(), font);

            Assert.All(glyphRun.GlyphInfos, glyphInfo => Assert.Null(glyphInfo.Foreground));
            var width = provider.GetTypographicWidth(font, glyphRun);

            Approximately.Equal(width, 25, 0.01);
        }
Example #14
0
        public void DrawGlyphRunWithOffset(AttributedGlyphRun <TestFont, char> text, PointF point, Structures.Color?color)
        {
            var advance = 0.0;

            foreach (var((glyph, kernAfter, foreground), bounds) in text.GlyphInfos.Zip(
                         TestTypesettingContexts.Instance.GlyphBoundsProvider.GetBoundingRectsForGlyphs(text.Font, text.Glyphs.AsForEach(), text.Length),
                         ValueTuple.Create))
            {
                Checker.ConsoleDrawRectangle(new Rectangle((int)(point.X + trans.X + advance), (int)(point.Y + trans.Y), (int)bounds.Width, (int)bounds.Height), glyph, foreground ?? color);
                advance += bounds.Width + kernAfter;
            }
        }
Example #15
0
        public void TestGlyphBoundsWithM()
        {
            string       america  = "America";
            TestMathFont font     = new TestMathFont(10);
            var          provider = new TestGlyphBoundsProvider();
            var          glyphRun = new AttributedGlyphRun <TestMathFont, TGlyph>
            {
                Font         = font,
                KernedGlyphs = america.Select(c => new KernedGlyph <char>(c)).ToList(),
            };
            var width = provider.GetTypographicWidth(font, glyphRun);

            Assertions.ApproximatelyEqual(width, 40, 0.01);
        }
Example #16
0
        public void TestGlyphBoundsWithoutM()
        {
            string            hello = "Hello";
            MathFont <TGlyph> font  = new MathFont <TGlyph>(10);
            var provider            = new TestGlyphBoundsProvider();
            var glyphRun            = new AttributedGlyphRun <MathFont <TGlyph>, TGlyph>
            {
                Font         = font,
                KernedGlyphs = hello.ToCharArray().Select(c => new KernedGlyph <char>(c)).ToArray(),
            };
            var width = provider.GetTypographicWidth(font, glyphRun);

            Assertions.ApproximatelyEqual(width, 25, 0.01);
        }
Example #17
0
        public TextRunDisplay(
            AttributedGlyphRun <TFont, TGlyph> run,
            Range range,
            TypesettingContext <TFont, TGlyph> context)
        {
            var font = run.Font;

            Run   = run;
            Range = range;
            Width = context.GlyphBoundsProvider.GetTypographicWidth(font, run);
            // Compute ascent and descent
            var rects =
                context.GlyphBoundsProvider.GetBoundingRectsForGlyphs(font, Run.Glyphs, Run.GlyphInfos.Count);

            Ascent  = rects.IsEmpty() ? 0 : rects.Max(rect => rect.Bottom); // Convert to non-flipped naming here,
            Descent = rects.IsEmpty() ? 0 : rects.Max(rect => - rect.Y);
        }
 public float GetTypographicWidth(Fonts fonts, AttributedGlyphRun <Fonts, Glyph> run) =>
 GetAdvancesForGlyphs(fonts, run.Glyphs, run.GlyphInfos.Count).Total
 + run.GlyphInfos.Sum(g => g.KernAfterGlyph);
 public float GetTypographicWidth(TFonts fonts, AttributedGlyphRun <TFonts, Glyph> run) => GetAdvancesForGlyphs(fonts, run.Glyphs.ToArray()).Total + run.KernedGlyphs.Sum(g => g.KernAfterGlyph);
 public float GetTypographicWidth(TestFont font, AttributedGlyphRun <TestFont, TGlyph> run) =>
 font.PointSize * GetEffectiveLength(run.Glyphs) * WidthPerCharacterPerFontSize
 + run.GlyphInfos.Sum(g => g.KernAfterGlyph);