Skip to content

Commit ec731ad

Browse files
Fix decoration length scaling.
1 parent bdc53f5 commit ec731ad

File tree

2 files changed

+21
-10
lines changed

2 files changed

+21
-10
lines changed

src/SixLabors.Fonts/DecorationPositioningMode.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,21 @@
44
namespace SixLabors.Fonts;
55

66
/// <summary>
7-
/// Controls how text decorations (underline/overline/strikethrough) are positioned.
7+
/// Defines how text decorations (underline, overline, strikethrough) are positioned relative to font metrics.
88
/// </summary>
99
public enum DecorationPositioningMode
1010
{
1111
/// <summary>
12-
/// Browser-like: Use the primary (base) font's metrics for the entire run/line, producing a single,
13-
/// consistent decoration position across mixed fonts and scripts.
12+
/// Uses the primary (base) font's metrics for the entire run or line,
13+
/// ensuring a consistent decoration position across mixed fonts and scripts.
14+
/// Matches typical browser behavior.
1415
/// </summary>
15-
FromPrimaryFont = 0,
16+
PrimaryFont = 0,
1617

1718
/// <summary>
18-
/// Word-like: position each decoration using the active glyph's own font metrics
19-
/// Varies across glyphs/fallback faces within the same line.
19+
/// Uses each glyph's own font metrics to position its decoration.
20+
/// Decoration positions may vary between glyphs and fallback fonts within the same line.
21+
/// Matches typical Microsoft Word behavior.
2022
/// </summary>
21-
PerGlyphFromFont = 1,
23+
GlyphFont = 1,
2224
}

src/SixLabors.Fonts/GlyphMetrics.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,11 +338,18 @@ protected void RenderDecorationsTo(
338338
float scaledPPEM,
339339
TextOptions options)
340340
{
341-
bool perGlyph = options.DecorationPositioningMode == DecorationPositioningMode.PerGlyphFromFont;
341+
bool perGlyph = options.DecorationPositioningMode == DecorationPositioningMode.GlyphFont;
342342
FontMetrics fontMetrics = perGlyph
343343
? this.FontMetrics
344344
: options.Font.FontMetrics;
345345

346+
// The scale factor for the decoration length is treated separately from other factors
347+
// as it is used to scale the length of the decoration line.
348+
// This must always be derived from the glyph's own scale factor to ensure correct length.
349+
Vector2 lengthScaleFactor = this.ScaleFactor;
350+
351+
// These factors determine horizontal and vertical scaling and offset for the decorations.
352+
// and are either per-glyph or derived from the common font metrics.
346353
Vector2 scaleFactor;
347354
Vector2 offset;
348355
if (perGlyph)
@@ -383,12 +390,13 @@ protected void RenderDecorationsTo(
383390
return (Vector2.Zero, Vector2.Zero, 0);
384391
}
385392

393+
Vector2 lengthScale = new Vector2(scaledPPEM) / lengthScaleFactor;
386394
Vector2 scale = new Vector2(scaledPPEM) / scaleFactor;
387395

388396
// Undo the vertical offset applied when laying out the text.
389397
Vector2 scaledOffset = (offset + new Vector2(decoratorPosition, 0)) * scale;
390398

391-
length *= scale.Y;
399+
length *= lengthScale.Y;
392400
thickness *= scale.X;
393401

394402
Vector2 tl = new(scaledOffset.X, scaledOffset.Y);
@@ -421,10 +429,11 @@ protected void RenderDecorationsTo(
421429
return (Vector2.Zero, Vector2.Zero, 0);
422430
}
423431

432+
Vector2 lengthScale = new Vector2(scaledPPEM) / lengthScaleFactor;
424433
Vector2 scale = new Vector2(scaledPPEM) / scaleFactor;
425434
Vector2 scaledOffset = (offset + new Vector2(0, decoratorPosition)) * scale;
426435

427-
length *= scale.X;
436+
length *= lengthScale.X;
428437
thickness *= scale.Y;
429438

430439
Vector2 tl = new(scaledOffset.X, scaledOffset.Y);

0 commit comments

Comments
 (0)