Skip to content

Commit a2b5d0e

Browse files
Update renderers to handle vertically rotated text
1 parent 1d451a2 commit a2b5d0e

2 files changed

Lines changed: 30 additions & 31 deletions

File tree

src/ImageSharp.Drawing/Processing/Processors/Text/RichTextGlyphRenderer.cs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ internal sealed class RichTextGlyphRenderer : BaseGlyphBuilder, IColorGlyphRende
4040
private TextDecorationDetails? currentUnderline;
4141
private TextDecorationDetails? currentStrikout;
4242
private TextDecorationDetails? currentOverline;
43+
private bool currentDecorationsRotated;
4344

4445
// Just enough accuracy to allow for 1/8 px differences which later are accumulated while rendering,
4546
// but do not grow into full px offsets.
@@ -101,7 +102,7 @@ protected override void BeginText(in FontRectangle bounds)
101102
protected override void BeginGlyph(in FontRectangle bounds, in GlyphRendererParameters parameters)
102103
{
103104
this.currentColor = null;
104-
105+
this.currentDecorationsRotated = parameters.LayoutMode.IsVertical() || parameters.LayoutMode.IsVerticalMixed();
105106
this.currentTextRun = parameters.TextRun;
106107
if (parameters.TextRun is RichTextRun drawingRun)
107108
{
@@ -219,41 +220,37 @@ public override void SetDecoration(TextDecorations textDecorations, Vector2 star
219220
}
220221
}
221222

222-
// Clamp the line to whole pixels
223-
Vector2 pad = new(0, thickness * .5F);
224-
Vector2 tl = start - pad;
225-
Vector2 bl = start + pad;
226-
Vector2 tr = end - pad;
227-
228-
tl = ClampToPixel(tl);
229-
bl = ClampToPixel(bl);
230-
tr = ClampToPixel(tr);
231-
232223
// Always respect the pen stroke width if explicitly set.
233-
if (pen is null)
234-
{
235-
thickness = bl.Y - tl.Y;
236-
pen = new SolidPen(this.currentBrush ?? this.defaultBrush, thickness);
237-
}
238-
else
224+
if (pen is not null)
239225
{
240226
thickness = pen.StrokeWidth;
241227
}
242228

229+
// Center the line at the given position.
230+
bool rotated = this.currentDecorationsRotated;
231+
Vector2 pad = rotated ? new(thickness * .5F, 0) : new(0, thickness * .5F);
232+
Vector2 a = start - pad;
233+
Vector2 b = start + pad;
234+
Vector2 d = end - pad;
235+
thickness = rotated ? b.X - a.X : b.Y - a.Y;
236+
237+
pen ??= new SolidPen(this.currentBrush ?? this.defaultBrush, thickness);
238+
243239
// Drawing is always centered around the point so we need to offset by half.
244240
Vector2 offset = Vector2.Zero;
245241
if (textDecorations == TextDecorations.Overline)
246242
{
247243
// CSS overline is drawn above the position, so we need to move it up.
248-
offset = new Vector2(0, -(thickness * .5F));
244+
offset = rotated ? new(thickness * .5F, 0) : new(0, -(thickness * .5F));
249245
}
250246
else if (textDecorations == TextDecorations.Underline)
251247
{
252248
// CSS underline is drawn below the position, so we need to move it down.
253-
offset = new Vector2(0, thickness * .5F);
249+
offset = rotated ? new(-(thickness * .5F), 0) : new(0, thickness * .5F);
254250
}
255251

256-
this.AppendDecoration(ref targetDecoration, tl + offset, tr + offset, pen, thickness);
252+
// Clamp the line to whole pixels
253+
this.AppendDecoration(ref targetDecoration, ClampToPixel(a + offset), ClampToPixel(d + offset), pen, (float)Math.Truncate(thickness));
257254
}
258255

259256
protected override void EndGlyph()

src/ImageSharp.Drawing/Shapes/Text/BaseGlyphBuilder.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -147,30 +147,32 @@ public virtual void SetDecoration(TextDecorations textDecorations, Vector2 start
147147

148148
var renderer = (IGlyphRenderer)this;
149149

150-
Vector2 height = new(0, thickness);
151-
Vector2 tl = start;
152-
Vector2 tr = end;
153-
Vector2 bl = start + height;
154-
Vector2 br = end + height;
150+
// Clamp the line to whole pixels
151+
bool rotated = this.parameters.LayoutMode.IsVertical() || this.parameters.LayoutMode.IsVerticalMixed();
152+
Vector2 pad = rotated ? new(thickness * .5F, 0) : new(0, thickness * .5F);
153+
Vector2 a = start - pad;
154+
Vector2 b = start + pad;
155+
Vector2 c = end + pad;
156+
Vector2 d = end - pad;
155157

156158
// Drawing is always centered around the point so we need to offset by half.
157159
Vector2 offset = Vector2.Zero;
158160
if (textDecorations == TextDecorations.Overline)
159161
{
160162
// CSS overline is drawn above the position, so we need to move it up.
161-
offset = new(0, -(thickness * .5F));
163+
offset = rotated ? new(thickness * .5F, 0) : new(0, -(thickness * .5F));
162164
}
163165
else if (textDecorations == TextDecorations.Underline)
164166
{
165167
// CSS underline is drawn below the position, so we need to move it down.
166-
offset = new Vector2(0, thickness * .5F);
168+
offset = rotated ? new(-(thickness * .5F), 0) : new(0, thickness * .5F);
167169
}
168170

169171
// MoveTo calls StartFigure();
170-
renderer.MoveTo(tl + offset);
171-
renderer.LineTo(bl + offset);
172-
renderer.LineTo(br + offset);
173-
renderer.LineTo(tr + offset);
172+
renderer.MoveTo(a + offset);
173+
renderer.LineTo(b + offset);
174+
renderer.LineTo(c + offset);
175+
renderer.LineTo(d + offset);
174176
renderer.EndFigure();
175177
}
176178
}

0 commit comments

Comments
 (0)