/// <summary> /// Initializes a new instance of the <see cref="GlyphMetric"/> struct. /// </summary> /// <param name="codePoint">Unicode codepoint of the character.</param> /// <param name="bounds">The bounds.</param> /// <param name="isControlCharacter">Whether the character is a control character.</param> public GlyphMetric(int codePoint, FontRectangle bounds, bool isControlCharacter) { this.Codepoint = codePoint; this.Character = char.ConvertFromUtf32(codePoint); this.Bounds = bounds; this.IsControlCharacter = isControlCharacter; }
internal FontRectangle BoundingBox(Vector2 dpi) { FontRectangle box = this.Glyph.BoundingBox(this.Location * dpi, dpi); if (this.IsWhiteSpace) { box = new FontRectangle(box.X, box.Y, this.Width * dpi.X, box.Height); } return(box); }
internal static FontRectangle GetBounds(IReadOnlyList <GlyphLayout> glyphLayouts, Vector2 dpi) { if (glyphLayouts.Count == 0) { return(FontRectangle.Empty); } bool hasSize = false; float left = int.MaxValue; float top = int.MaxValue; float bottom = int.MinValue; float right = int.MinValue; for (int i = 0; i < glyphLayouts.Count; i++) { GlyphLayout c = glyphLayouts[i]; if (!c.IsControlCharacter) { hasSize = true; FontRectangle box = c.BoundingBox(dpi); if (left > box.Left) { left = box.Left; } if (top > box.Top) { top = box.Top; } if (bottom < box.Bottom) { bottom = box.Bottom; } if (right < box.Right) { right = box.Right; } } } if (!hasSize) { return(FontRectangle.Empty); } float width = right - left; float height = bottom - top; return(new FontRectangle(left, top, width, height)); }
/// <summary> /// Renders the text. /// </summary> /// <param name="text">The text.</param> /// <param name="options">The style.</param> public void RenderText(ReadOnlySpan <char> text, TextOptions options) { IReadOnlyList <GlyphLayout> glyphsToRender = this.layoutEngine.GenerateLayout(text, options); FontRectangle rect = TextMeasurer.GetBounds(glyphsToRender, options.Dpi); this.renderer.BeginText(rect); foreach (GlyphLayout g in glyphsToRender) { if (g.IsWhiteSpace()) { continue; } g.Glyph.RenderTo(this.renderer, g.Location, options); } this.renderer.EndText(); }
internal static FontRectangle GetBounds(IReadOnlyList <GlyphLayout> glyphLayouts, float dpi) { if (glyphLayouts.Count == 0) { return(FontRectangle.Empty); } float left = int.MaxValue; float top = int.MaxValue; float bottom = int.MinValue; float right = int.MinValue; for (int i = 0; i < glyphLayouts.Count; i++) { FontRectangle box = glyphLayouts[i].BoundingBox(dpi); if (left > box.Left) { left = box.Left; } if (top > box.Top) { top = box.Top; } if (bottom < box.Bottom) { bottom = box.Bottom; } if (right < box.Right) { right = box.Right; } } return(FontRectangle.FromLTRB(left, top, right, bottom)); }
/// <summary> /// Initializes a new instance of the <see cref="GlyphBounds"/> struct. /// </summary> /// <param name="codePoint">The Unicode codepoint for the glyph.</param> /// <param name="bounds">The glyph bounds.</param> public GlyphBounds(CodePoint codePoint, FontRectangle bounds) { this.Codepoint = codePoint; this.Bounds = bounds; }
/// <summary> /// Renders the glyph to the render surface in font units relative to a bottom left origin at (0,0) /// </summary> /// <param name="surface">The surface.</param> /// <param name="pointSize">Size of the point.</param> /// <param name="location">The location.</param> /// <param name="dpi">The dpi.</param> /// <param name="lineHeight">The lineHeight the current glyph was draw agains to offset topLeft while calling out to IGlyphRenderer.</param> /// <exception cref="NotSupportedException">Too many control points</exception> public void RenderTo(IGlyphRenderer surface, float pointSize, Vector2 location, Vector2 dpi, float lineHeight) { location = location * dpi; Vector2 firstPoint = Vector2.Zero; Vector2 scaledPoint = dpi * pointSize; FontRectangle box = this.BoundingBox(location, scaledPoint); var paramaters = new GlyphRendererParameters(this, pointSize, dpi); if (surface.BeginGlyph(box, paramaters)) { int startOfContor = 0; int endOfContor = -1; for (int i = 0; i < this.endPoints.Length; i++) { surface.BeginFigure(); startOfContor = endOfContor + 1; endOfContor = this.endPoints[i]; Vector2 prev = Vector2.Zero; Vector2 curr = this.GetPoint(ref scaledPoint, endOfContor) + location; Vector2 next = this.GetPoint(ref scaledPoint, startOfContor) + location; if (this.onCurves[endOfContor]) { surface.MoveTo(curr); } else { if (this.onCurves[startOfContor]) { surface.MoveTo(next); } else { // If both first and last points are off-curve, start at their middle. Vector2 startPoint = (curr + next) / 2; surface.MoveTo(startPoint); } } int length = (endOfContor - startOfContor) + 1; for (int p = 0; p < length; p++) { prev = curr; curr = next; int currentIndex = startOfContor + p; int nextIndex = startOfContor + ((p + 1) % length); int prevIndex = startOfContor + (((length + p) - 1) % length); next = this.GetPoint(ref scaledPoint, nextIndex) + location; if (this.onCurves[currentIndex]) { // This is a straight line. surface.LineTo(curr); } else { Vector2 prev2 = prev; Vector2 next2 = next; if (!this.onCurves[prevIndex]) { prev2 = (curr + prev) / 2; surface.LineTo(prev2); } if (!this.onCurves[nextIndex]) { next2 = (curr + next) / 2; } surface.LineTo(prev2); surface.QuadraticBezierTo(curr, next2); } } surface.EndFigure(); } } surface.EndGlyph(); }