From 81ef1fbc45bcf7eed4114d2d98c7d92acb2f50f4 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Wed, 4 Mar 2026 01:02:46 +0300 Subject: [PATCH] Enable halfLeading for text rendering only, not measurement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Figma distributes leading equally above and below text. CanvasKit defaults to ascent-biased leading. halfLeading: true fixes this but must only apply to rendering (drawParagraph), not measureTextNode — otherwise measured sizes change and break grid layouts. --- packages/core/src/renderer.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/core/src/renderer.ts b/packages/core/src/renderer.ts index 9c2055e65..d6690fc5a 100644 --- a/packages/core/src/renderer.ts +++ b/packages/core/src/renderer.ts @@ -1946,7 +1946,7 @@ export class SkiaRenderer { if (this.fontsLoaded && this.fontProvider) { if (this.isNodeFontLoaded(node)) { - const paragraph = this.buildParagraph(node, this.fillPaint.getColor()) + const paragraph = this.buildParagraph(node, this.fillPaint.getColor(), { halfLeading: true }) canvas.drawParagraph(paragraph, 0, 0) paragraph.delete() } else if (node.textPicture) { @@ -1993,7 +1993,7 @@ export class SkiaRenderer { const bounds = ck.LTRBRect(0, 0, node.width || 1e6, node.height || 1e6) const recCanvas = recorder.beginRecording(bounds) - const paragraph = this.buildParagraph(node) + const paragraph = this.buildParagraph(node, undefined, { halfLeading: true }) recCanvas.drawParagraph(paragraph, 0, 0) paragraph.delete() @@ -2005,7 +2005,11 @@ export class SkiaRenderer { return bytes ?? null } - buildParagraph(node: SceneNode, color?: Float32Array): import('canvaskit-wasm').Paragraph { + buildParagraph( + node: SceneNode, + color?: Float32Array, + { halfLeading = false }: { halfLeading?: boolean } = {} + ): import('canvaskit-wasm').Paragraph { const ck = this.ck const baseColor = color ?? ck.BLACK const baseFontSize = node.fontSize || DEFAULT_FONT_SIZE @@ -2022,7 +2026,8 @@ export class SkiaRenderer { }, letterSpacing: node.letterSpacing || 0, decoration: this.textDecorationValue(node.textDecoration), - heightMultiplier: node.lineHeight ? node.lineHeight / baseFontSize : undefined + heightMultiplier: node.lineHeight ? node.lineHeight / baseFontSize : undefined, + halfLeading } }) @@ -2053,7 +2058,8 @@ export class SkiaRenderer { heightMultiplier: (s.lineHeight !== undefined ? s.lineHeight : node.lineHeight) ? (s.lineHeight !== undefined ? s.lineHeight : node.lineHeight)! / (s.fontSize ?? baseFontSize) - : undefined + : undefined, + halfLeading }) ) builder.addText(text.slice(run.start, run.start + run.length))