// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.Fonts.Rendering;
using SixLabors.Fonts.Unicode;
namespace SixLabors.Fonts.Tables.Cff {
///
/// Represents a glyph metric from a particular Compact Font Face.
///
internal class CffGlyphMetrics : FontGlyphMetrics
{
private CffGlyphData glyphData;
///
/// Initializes a new instance of the class with text attribute parameters.
///
/// The font metrics.
/// The glyph identifier.
/// The Unicode code point.
/// The CFF glyph data containing the charstring program.
/// The glyph bounding box.
/// The advance width.
/// The advance height.
/// The left side bearing.
/// The top side bearing.
/// The units per em.
/// The text attributes.
/// The text decorations.
/// The glyph type.
internal CffGlyphMetrics(
StreamFontMetrics fontMetrics,
ushort glyphId,
CodePoint codePoint,
CffGlyphData glyphData,
Bounds bounds,
ushort advanceWidth,
ushort advanceHeight,
short leftSideBearing,
short topSideBearing,
ushort unitsPerEM,
TextAttributes textAttributes,
TextDecorations textDecorations,
GlyphType glyphType)
: base(
fontMetrics,
glyphId,
codePoint,
bounds,
advanceWidth,
advanceHeight,
leftSideBearing,
topSideBearing,
unitsPerEM,
textAttributes,
textDecorations,
glyphType)
=> this.glyphData = glyphData;
///
/// Initializes a new instance of the class with offset, scale, and text run parameters.
///
/// The font metrics.
/// The glyph identifier.
/// The Unicode code point.
/// The CFF glyph data containing the charstring program.
/// The glyph bounding box.
/// The advance width.
/// The advance height.
/// The left side bearing.
/// The top side bearing.
/// The units per em.
/// The glyph offset.
/// The scale factor.
/// The text run for rendering.
/// The glyph type.
internal CffGlyphMetrics(
StreamFontMetrics fontMetrics,
ushort glyphId,
CodePoint codePoint,
CffGlyphData glyphData,
Bounds bounds,
ushort advanceWidth,
ushort advanceHeight,
short leftSideBearing,
short topSideBearing,
ushort unitsPerEM,
Vector2 offset,
Vector2 scaleFactor,
TextRun textRun,
GlyphType glyphType)
: base(
fontMetrics,
glyphId,
codePoint,
bounds,
advanceWidth,
advanceHeight,
leftSideBearing,
topSideBearing,
unitsPerEM,
offset,
scaleFactor,
textRun,
glyphType)
=> this.glyphData = glyphData;
///
internal override FontGlyphMetrics CloneForRendering(TextRun textRun)
=> new CffGlyphMetrics(
this.FontMetrics,
this.GlyphId,
this.CodePoint,
this.glyphData,
this.Bounds,
this.AdvanceWidth,
this.AdvanceHeight,
this.LeftSideBearing,
this.TopSideBearing,
this.UnitsPerEm,
this.Offset,
this.ScaleFactor,
textRun,
this.GlyphType);
///
internal override void RenderTo(
IGlyphRenderer renderer,
int graphemeIndex,
Vector2 glyphOrigin,
Vector2 decorationOrigin,
GlyphLayoutMode mode,
TextOptions options)
{
// https://www.unicode.org/faq/unsup_char.html
if (ShouldSkipGlyphRendering(this.CodePoint))
{
return;
}
float pointSize = this.TextRun.Font?.Size ?? options.Font.Size;
float dpi = options.Dpi;
glyphOrigin *= dpi;
decorationOrigin *= dpi;
float scaledPPEM = this.GetScaledSize(pointSize, dpi);
Matrix3x2 rotation = GetRotationMatrix(mode);
FontRectangle box = this.GetBoundingBox(mode, glyphOrigin, scaledPPEM);
GlyphRendererParameters parameters = new(this, this.TextRun, pointSize, dpi, mode, graphemeIndex);
if (renderer.BeginGlyph(in box, in parameters))
{
if (!UnicodeUtility.ShouldRenderWhiteSpaceOnly(this.CodePoint))
{
Vector2 scale = new Vector2(scaledPPEM) / this.ScaleFactor;
// Apply the CFF FontMatrix to convert charstring coordinates to design units.
// The normalized FontMatrix (fontMatrix * unitsPerEM) is identity for the default
// [0.001, 0, 0, 0.001, 0, 0] with upm=1000.
if (this.glyphData.FontMatrix is double[] fm)
{
float upm = this.UnitsPerEm;
scale *= new Vector2((float)(fm[0] * upm), (float)(fm[3] * upm));
}
Vector2 scaledOffset = this.Offset * scale;
this.glyphData.RenderTo(renderer, glyphOrigin, scale, scaledOffset, rotation);
}
renderer.EndGlyph();
this.RenderDecorationsTo(renderer, decorationOrigin, mode, rotation, scaledPPEM, options);
}
}
}
}