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); }
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."); }
public float GetTypographicWidth(TFont font, AttributedGlyphRun <TFont, TGlyph> run) { var aString = run.ToNsAttributedString(); using (var ctLine = new CTLine(aString)) return((float)ctLine.GetTypographicBounds()); }
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); }
public static CTStringAttributes CtFromAttributedGlyphRun(AttributedGlyphRun <TFont, TGlyph> glyphRun) { return(new CTStringAttributes() { ForegroundColorFromContext = true, Font = glyphRun.Font.CtFont }); }
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); }
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); }
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); }
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); }
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; } }
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); }
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); }
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);