summaryrefslogtreecommitdiff
path: root/apps/web/src/lib/text/layout.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/lib/text/layout.ts')
-rw-r--r--apps/web/src/lib/text/layout.ts51
1 files changed, 49 insertions, 2 deletions
diff --git a/apps/web/src/lib/text/layout.ts b/apps/web/src/lib/text/layout.ts
index 75fa7f09..a3badfdc 100644
--- a/apps/web/src/lib/text/layout.ts
+++ b/apps/web/src/lib/text/layout.ts
@@ -14,15 +14,18 @@ export interface TextBlockMeasurement {
maxWidth: number;
}
-type CanvasContext =
+export type TextCanvasContext =
| CanvasRenderingContext2D
| OffscreenCanvasRenderingContext2D;
+const TEXT_DECORATION_THICKNESS_RATIO = 0.07;
+const STRIKETHROUGH_VERTICAL_RATIO = 0.35;
+
export function setCanvasLetterSpacing({
ctx,
letterSpacingPx,
}: {
- ctx: CanvasContext;
+ ctx: TextCanvasContext;
letterSpacingPx: number;
}): void {
if ("letterSpacing" in ctx) {
@@ -177,3 +180,47 @@ export function getTextVisualRect({
height: bottom - top,
};
}
+
+export function drawTextDecoration({
+ ctx,
+ textDecoration,
+ lineWidth,
+ lineY,
+ metrics,
+ scaledFontSize,
+ textAlign,
+}: {
+ ctx: TextCanvasContext;
+ textDecoration: string;
+ lineWidth: number;
+ lineY: number;
+ metrics: TextMetrics;
+ scaledFontSize: number;
+ textAlign: CanvasTextAlign;
+}): void {
+ if (textDecoration === "none" || !textDecoration) return;
+
+ const thickness = Math.max(
+ 1,
+ scaledFontSize * TEXT_DECORATION_THICKNESS_RATIO,
+ );
+ const ascent = getMetricAscent({ metrics, fallbackFontSize: scaledFontSize });
+ const descent = getMetricDescent({
+ metrics,
+ fallbackFontSize: scaledFontSize,
+ });
+
+ let xStart = -lineWidth / 2;
+ if (textAlign === "left") xStart = 0;
+ if (textAlign === "right") xStart = -lineWidth;
+
+ if (textDecoration === "underline") {
+ const underlineY = lineY + descent + thickness;
+ ctx.fillRect(xStart, underlineY, lineWidth, thickness);
+ }
+
+ if (textDecoration === "line-through") {
+ const strikeY = lineY - (ascent - descent) * STRIKETHROUGH_VERTICAL_RATIO;
+ ctx.fillRect(xStart, strikeY, lineWidth, thickness);
+ }
+}