perf(canvas): bound blend and text mask layers

This commit is contained in:
Danila Poyarkov 2026-05-23 01:10:24 +03:00
parent f07d26c50b
commit 0d5db35147
2 changed files with 21 additions and 4 deletions

View file

@ -2,6 +2,7 @@
import type { Canvas, Path } from 'canvaskit-wasm'
import { DROP_HIGHLIGHT_ALPHA, DROP_HIGHLIGHT_STROKE, SECTION_CORNER_RADIUS } from '#core/constants'
import { computeDescendantVisualBounds } from '#core/geometry'
import type { SceneNode, SceneGraph, Fill } from '#core/scene-graph'
import type { Color } from '#core/types'
import { vectorNetworkToCenterlinePath } from '#core/vector'
@ -212,9 +213,22 @@ export function renderNode(
const needsNodeLayer = node.opacity < 1 || needsIsolatedBlendLayer(node.blendMode)
if (needsNodeLayer) {
const bounds = computeDescendantVisualBounds(
[nodeId],
(id) => graph.getNode(id) ?? undefined,
(id) => graph.getAbsolutePosition(id)
)
const layerBounds = bounds
? r.ck.LTRBRect(
bounds.minX - absX,
bounds.minY - absY,
bounds.maxX - absX,
bounds.maxY - absY
)
: r.ck.LTRBRect(0, 0, node.width, node.height)
r.opacityPaint.setAlphaf(node.opacity)
r.opacityPaint.setBlendMode(figmaBlendModeToSkia(r.ck, node.blendMode))
canvas.saveLayer(r.opacityPaint)
canvas.saveLayer(r.opacityPaint, layerBounds)
}
const layerBlur = node.effects.find(
@ -589,11 +603,12 @@ function drawGradientText(
r.effectLayerPaint.setImageFilter(null)
r.effectLayerPaint.setColorFilter(null)
r.effectLayerPaint.setBlendMode(r.ck.BlendMode.SrcOver)
canvas.saveLayer(r.effectLayerPaint)
const bounds = r.ck.LTRBRect(0, paragraphY, node.width, paragraphY + node.height)
canvas.saveLayer(r.effectLayerPaint, bounds)
canvas.drawParagraph(paragraph, 0, paragraphY)
r.effectLayerPaint.setBlendMode(r.ck.BlendMode.SrcIn)
canvas.saveLayer(r.effectLayerPaint)
canvas.saveLayer(r.effectLayerPaint, bounds)
canvas.drawRect(r.ck.LTRBRect(0, 0, node.width, node.height), r.fillPaint)
canvas.restore()
canvas.restore()

View file

@ -1,4 +1,5 @@
import { describe, expect, mock, test } from 'bun:test'
import type { Canvas } from 'canvaskit-wasm'
import { figmaBlendModeToSkia } from '#core/canvas/blend'
@ -123,7 +124,8 @@ describe('canvas blend modes', () => {
expect(renderer.opacityPaint.setAlphaf).toHaveBeenCalledWith(1)
expect(renderer.opacityPaint.setBlendMode).toHaveBeenCalledWith('Multiply')
expect(canvas.saveLayer).toHaveBeenCalledWith(renderer.opacityPaint)
expect(canvas.saveLayer).toHaveBeenCalledWith(renderer.opacityPaint, expect.any(Float32Array))
expect(renderer.ck.LTRBRect).toHaveBeenCalledWith(0, 0, 100, 100)
expect(renderer.renderShape).toHaveBeenCalled()
expect(renderer.opacityPaint.setBlendMode).toHaveBeenLastCalledWith('SrcOver')
})