Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/SixLabors.Fonts/GlyphLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ internal readonly struct GlyphLayout
{
internal GlyphLayout(
Glyph glyph,
Font font,
Vector2 advanceOrigin,
Vector2 glyphOrigin,
Vector2 decorationOrigin,
Expand All @@ -25,6 +26,7 @@ internal GlyphLayout(
int stringIndex)
{
this.Glyph = glyph;
this.Font = font;
this.CodePoint = glyph.GlyphMetrics.CodePoint;
this.AdvanceOrigin = advanceOrigin;
this.GlyphOrigin = glyphOrigin;
Expand All @@ -43,6 +45,11 @@ internal GlyphLayout(
/// </summary>
public Glyph Glyph { get; }

/// <summary>
/// Gets the font used to shape and render this laid-out glyph entry.
/// </summary>
public Font Font { get; }

/// <summary>
/// Gets the code point represented by this glyph.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions src/SixLabors.Fonts/GlyphLayoutData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ internal struct GlyphLayoutData
/// Initializes a new instance of the <see cref="GlyphLayoutData"/> struct.
/// </summary>
/// <param name="metrics">The shaped glyph metrics for this codepoint.</param>
/// <param name="font">The font used to shape and render this entry.</param>
/// <param name="pointSize">The point size at which the glyph is rendered.</param>
/// <param name="scaledAdvance">The scaled advance of this entry.</param>
/// <param name="scaledLineHeight">The scaled line height contributed by this entry.</param>
Expand All @@ -39,6 +40,7 @@ internal struct GlyphLayoutData
/// <param name="hyphenationMarkerIndex">The marker index to use if this entry becomes a selected soft-hyphen break.</param>
public GlyphLayoutData(
IReadOnlyList<FontGlyphMetrics> metrics,
Font font,
float pointSize,
float scaledAdvance,
float scaledLineHeight,
Expand All @@ -57,6 +59,7 @@ public GlyphLayoutData(
int hyphenationMarkerIndex = NoHyphenationMarker)
{
this.Metrics = metrics;
this.Font = font;
this.PointSize = pointSize;
this.ScaledAdvance = scaledAdvance;
this.ScaledLineHeight = scaledLineHeight;
Expand All @@ -81,6 +84,9 @@ public GlyphLayoutData(
/// <summary>Gets the shaped glyph metrics produced for this codepoint (one codepoint may map to several glyphs).</summary>
public IReadOnlyList<FontGlyphMetrics> Metrics { get; }

/// <summary>Gets the font used to shape and render this entry.</summary>
public Font Font { get; }

/// <summary>Gets the point size at which this entry is rendered.</summary>
public float PointSize { get; }

Expand Down
8 changes: 8 additions & 0 deletions src/SixLabors.Fonts/GlyphMetrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,23 @@ public readonly struct GlyphMetrics
/// <param name="advance">The positioned logical advance rectangle for the glyph entry in pixel units.</param>
/// <param name="bounds">The rendered rectangle for the glyph entry in pixel units.</param>
/// <param name="renderableBounds">The union of the positioned logical advance rectangle and rendered rectangle in pixel units.</param>
/// <param name="font">The font used to shape and render the glyph entry.</param>
/// <param name="graphemeIndex">The grapheme index in the original text.</param>
/// <param name="stringIndex">The UTF-16 index in the original text where the glyph entry begins.</param>
internal GlyphMetrics(
CodePoint codePoint,
in FontRectangle advance,
in FontRectangle bounds,
in FontRectangle renderableBounds,
Font font,
int graphemeIndex,
int stringIndex)
{
this.CodePoint = codePoint;
this.Advance = advance;
this.Bounds = bounds;
this.RenderableBounds = renderableBounds;
this.Font = font;
this.GraphemeIndex = graphemeIndex;
this.StringIndex = stringIndex;
}
Expand All @@ -55,6 +58,11 @@ internal GlyphMetrics(
/// </summary>
public FontRectangle RenderableBounds { get; }

/// <summary>
/// Gets the font used to shape and render the glyph entry.
/// </summary>
public Font Font { get; }

/// <summary>
/// Gets the zero-based grapheme index in the original text.
/// </summary>
Expand Down
11 changes: 7 additions & 4 deletions src/SixLabors.Fonts/GlyphPositioningCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public bool TryUpdate(Font font, GlyphSubstitutionCollection collection)
: new(0, 0, metrics.AdvanceWidth, 0);

// Track the number of inserted glyphs at the offset so we can correctly increment our position.
this.glyphs.Insert(i += replacementCount, new(offset, new(shape, true) { Bounds = bounds }, pointSize, metrics.CloneForRendering(shape.TextRun)));
this.glyphs.Insert(i += replacementCount, new(offset, new(shape, true) { Bounds = bounds }, font, pointSize, metrics.CloneForRendering(shape.TextRun)));
replacementCount++;
}
}
Expand Down Expand Up @@ -307,7 +307,7 @@ public bool TryAdd(Font font, GlyphSubstitutionCollection collection)
IsPositioned = true
};

this.glyphs.Add(new(offset, placeholderData, font.Size, placeholderMetrics));
this.glyphs.Add(new(offset, placeholderData, font, font.Size, placeholderMetrics));
continue;
}

Expand Down Expand Up @@ -336,7 +336,7 @@ public bool TryAdd(Font font, GlyphSubstitutionCollection collection)
? new(0, 0, 0, metrics.AdvanceHeight)
: new(0, 0, metrics.AdvanceWidth, 0);

this.glyphs.Add(new(offset, new(data, true) { Bounds = bounds }, font.Size, metrics.CloneForRendering(data.TextRun)));
this.glyphs.Add(new(offset, new(data, true) { Bounds = bounds }, font, font.Size, metrics.CloneForRendering(data.TextRun)));
}

return !hasFallBacks;
Expand Down Expand Up @@ -433,10 +433,11 @@ public bool ShouldProcess(FontMetrics fontMetrics, int index)
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class GlyphPositioningData
{
public GlyphPositioningData(int offset, GlyphShapingData data, float pointSize, FontGlyphMetrics metrics)
public GlyphPositioningData(int offset, GlyphShapingData data, Font font, float pointSize, FontGlyphMetrics metrics)
{
this.Offset = offset;
this.Data = data;
this.Font = font;
this.PointSize = pointSize;
this.Metrics = metrics;
}
Expand All @@ -445,6 +446,8 @@ public GlyphPositioningData(int offset, GlyphShapingData data, float pointSize,

public GlyphShapingData Data { get; set; }

public Font Font { get; set; }

public float PointSize { get; set; }

public FontGlyphMetrics Metrics { get; set; }
Expand Down
8 changes: 8 additions & 0 deletions src/SixLabors.Fonts/GraphemeMetrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public readonly struct GraphemeMetrics
/// <param name="advance">The positioned logical advance rectangle for the grapheme in pixel units.</param>
/// <param name="bounds">The rendered glyph bounds for the grapheme in pixel units.</param>
/// <param name="renderableBounds">The union of the positioned logical advance bounds and rendered glyph bounds in pixel units.</param>
/// <param name="font">The font used to shape and render the grapheme.</param>
/// <param name="graphemeIndex">The grapheme index in the original text.</param>
/// <param name="stringIndex">The UTF-16 index in the original text where the grapheme begins.</param>
/// <param name="bidiLevel">The resolved bidi embedding level.</param>
Expand All @@ -22,6 +23,7 @@ internal GraphemeMetrics(
FontRectangle advance,
FontRectangle bounds,
FontRectangle renderableBounds,
Font font,
int graphemeIndex,
int stringIndex,
int bidiLevel,
Expand All @@ -30,6 +32,7 @@ internal GraphemeMetrics(
this.Advance = advance;
this.Bounds = bounds;
this.RenderableBounds = renderableBounds;
this.Font = font;
this.GraphemeIndex = graphemeIndex;
this.StringIndex = stringIndex;
this.BidiLevel = bidiLevel;
Expand All @@ -51,6 +54,11 @@ internal GraphemeMetrics(
/// </summary>
public FontRectangle RenderableBounds { get; }

/// <summary>
/// Gets the font used to shape and render the grapheme.
/// </summary>
public Font Font { get; }

/// <summary>
/// Gets the zero-based grapheme index in the original text.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions src/SixLabors.Fonts/TextBlock.Visitors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ private struct GraphemeMetricsAccumulator
private int stringIndex;
private int bidiLevel;
private bool isLineBreak;
private Font? font;
private FontRectangle advanceBounds;
private FontRectangle bounds;
private bool hasCurrent;
Expand All @@ -95,6 +96,7 @@ public GraphemeMetricsAccumulator(GraphemeMetrics[] graphemes, float dpi)
this.stringIndex = 0;
this.bidiLevel = 0;
this.isLineBreak = false;
this.font = null;
this.advanceBounds = FontRectangle.Empty;
this.bounds = FontRectangle.Empty;
this.hasCurrent = false;
Expand Down Expand Up @@ -174,6 +176,7 @@ private void Start(
this.stringIndex = glyph.StringIndex;
this.bidiLevel = glyph.BidiLevel;
this.isLineBreak = CodePoint.IsNewLine(glyph.CodePoint);
this.font = glyph.Font;
this.advanceBounds = advanceBounds;
this.bounds = bounds;
this.hasCurrent = true;
Expand All @@ -197,6 +200,7 @@ private bool Flush(out GraphemeMetrics metrics)
this.advanceBounds,
this.bounds,
renderableBounds,
this.font!,
this.graphemeIndex,
this.stringIndex,
this.bidiLevel,
Expand Down Expand Up @@ -750,6 +754,7 @@ public void Visit(in GlyphLayout glyph)
advance,
bounds,
renderableBounds,
glyph.Font,
glyph.GraphemeIndex,
glyph.StringIndex);

Expand Down
17 changes: 16 additions & 1 deletion src/SixLabors.Fonts/TextLayout.LineBreaking.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ VerticalOrientationType.Rotate or
int graphemeCodePointMax = CodePoint.GetCodePointCount(grapheme) - 1;

// For non-decomposed glyphs the length is always 1.
int glyphDataIndex = 0;

for (int i = 0; i < decomposedAdvances.Length; i++)
{
// Determine if this is the last codepoint in the grapheme.
Expand All @@ -277,7 +279,13 @@ VerticalOrientationType.Rotate or
float decomposedAdvance = decomposedAdvances[i];

// Work out the scaled metrics for the glyph.
FontGlyphMetrics metric = metrics[i];
while (glyphData[glyphDataIndex].Data.IsPlaceholder)
{
glyphDataIndex++;
}

GlyphPositioningCollection.GlyphPositioningData positionedGlyph = glyphData[glyphDataIndex];
FontGlyphMetrics metric = positionedGlyph.Metrics;

// Adjust the advance for the last decomposed glyph to add tracking if applicable.
// Tracking should only be added once per grapheme, so only on the last codepoint of the grapheme.
Expand Down Expand Up @@ -357,12 +365,14 @@ VerticalOrientationType.Rotate or
stringIndex,
hyphenationMarkerCodePoint.Value,
shapedText.LayoutMode,
positionedGlyph.Font,
options));
}

// Add our metrics to the line.
textLine.Add(
isDecomposed ? new FontGlyphMetrics[] { metric } : metrics,
positionedGlyph.Font,
pointSize,
decomposedAdvance,
lineHeight,
Expand All @@ -380,6 +390,8 @@ VerticalOrientationType.Rotate or
mode,
options.LineSpacing,
hyphenationMarkerIndex);

glyphDataIndex++;
}

codePointIndex++;
Expand Down Expand Up @@ -548,6 +560,7 @@ private static List<LineBreak> CollectLineBreaks(ReadOnlySpan<char> text, bool i
/// <param name="stringIndex">The UTF-16 source index to map the marker to.</param>
/// <param name="markerCodePoint">The marker codepoint to create.</param>
/// <param name="layoutMode">The layout mode used to calculate marker orientation.</param>
/// <param name="font">The font used to shape and render the marker.</param>
/// <param name="options">The text options used for layout.</param>
/// <returns>The generated marker entry.</returns>
internal static GlyphLayoutData CreateGeneratedMarker(
Expand All @@ -561,6 +574,7 @@ internal static GlyphLayoutData CreateGeneratedMarker(
int stringIndex,
CodePoint markerCodePoint,
LayoutMode layoutMode,
Font font,
TextOptions options)
{
anchorMetric.FontMetrics.TryGetGlyphId(markerCodePoint, out ushort markerGlyphId);
Expand Down Expand Up @@ -624,6 +638,7 @@ VerticalOrientationType.Rotate or

return new GlyphLayoutData(
new FontGlyphMetrics[] { markerMetric },
font,
pointSize,
markerAdvance,
markerLineHeight * options.LineSpacing,
Expand Down
7 changes: 7 additions & 0 deletions src/SixLabors.Fonts/TextLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ private static void LayoutLineHorizontal<TVisitor>(
visitor.Visit(
new GlyphLayout(
new Glyph(metric, data.PointSize),
data.Font,
boundsLocation,
hardBreakGlyphOrigin,
penLocation,
Expand Down Expand Up @@ -590,6 +591,7 @@ private static void LayoutLineHorizontal<TVisitor>(
visitor.Visit(
new GlyphLayout(
new Glyph(metric, data.PointSize),
data.Font,
boundsLocation,
glyphOrigin,
glyphOrigin,
Expand Down Expand Up @@ -770,6 +772,7 @@ private static void LayoutLineVertical<TVisitor>(
visitor.Visit(
new GlyphLayout(
new Glyph(metric, data.PointSize),
data.Font,
boundsLocation,
hardBreakGlyphOrigin,
hardBreakDecorationOrigin,
Expand Down Expand Up @@ -924,6 +927,7 @@ private static void LayoutLineVertical<TVisitor>(
visitor.Visit(
new GlyphLayout(
new Glyph(metric, data.PointSize),
data.Font,
boundsLocation,
glyphOrigin,
decorationOrigin,
Expand Down Expand Up @@ -1103,6 +1107,7 @@ private static void LayoutLineVerticalMixed<TVisitor>(
visitor.Visit(
new GlyphLayout(
new Glyph(metric, data.PointSize),
data.Font,
boundsLocation,
hardBreakGlyphOrigin,
hardBreakDecorationOrigin,
Expand Down Expand Up @@ -1148,6 +1153,7 @@ private static void LayoutLineVerticalMixed<TVisitor>(
visitor.Visit(
new GlyphLayout(
new Glyph(metric, data.PointSize),
data.Font,
boundsLocation,
glyphOrigin,
glyphOrigin,
Expand Down Expand Up @@ -1182,6 +1188,7 @@ private static void LayoutLineVerticalMixed<TVisitor>(
visitor.Visit(
new GlyphLayout(
new Glyph(metric, data.PointSize),
data.Font,
boundsLocation,
glyphOrigin,
decorationOrigin,
Expand Down
5 changes: 5 additions & 0 deletions src/SixLabors.Fonts/TextLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ public int CountGlyphLayouts()
/// Appends a shaped entry to this line, updating the aggregated line-level metrics.
/// </summary>
/// <param name="metrics">The glyph metrics produced by shaping this entry's codepoint.</param>
/// <param name="font">The font used to shape and render this entry.</param>
/// <param name="pointSize">The point size at which the entry is rendered.</param>
/// <param name="scaledAdvance">The scaled advance contributed by this entry.</param>
/// <param name="scaledLineHeight">The scaled line height contributed by this entry (before line-spacing).</param>
Expand All @@ -161,6 +162,7 @@ public int CountGlyphLayouts()
/// <param name="hyphenationMarkerIndex">The marker index to use if this entry becomes a selected soft-hyphen break.</param>
public void Add(
IReadOnlyList<FontGlyphMetrics> metrics,
Font font,
float pointSize,
float scaledAdvance,
float scaledLineHeight,
Expand Down Expand Up @@ -224,6 +226,7 @@ public void Add(

this.data.Add(new(
metrics,
font,
pointSize,
scaledAdvance,
scaledLineHeight,
Expand Down Expand Up @@ -300,6 +303,7 @@ public void AddPlaceholder(
// but they do not consume source grapheme, codepoint, or UTF-16 indexes.
this.Add(
new FontGlyphMetrics[] { placeholderGlyph },
placeholder.Font,
placeholder.PointSize,
placeholderAdvance,
placeholderLineHeight,
Expand Down Expand Up @@ -419,6 +423,7 @@ public void ApplyEllipsisMarker(
anchor.StringIndex,
markerCodePoint,
options.LayoutMode,
anchor.Font,
options);

while (this.data.Count > 0 &&
Expand Down
Loading
Loading