From dceae73c6e1426d2a780c8afcebcdfdf1c8f81b6 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Tue, 15 Sep 2026 16:32:07 +0300 Subject: [PATCH] perf(text): preserve coverage across paragraph eviction Keep successful glyph coverage weakly owned by source nodes rather than repeating shaping when dense scans evict native paragraphs. Preserve font/input invalidation and bound pending ID invalidations without increasing native cache limits. Add a dense-preview regression with exact raster comparison and count paragraph builds across all canvas renderers. The previous compiled build rebuilds 3,600 paragraphs over three held frames; the fixed build rebuilds none. --- packages/core/src/canvas/text/index.ts | 11 +- .../core/src/canvas/text/preparation-cache.ts | 35 ++++++ tests/e2e/canvas/dense-text-preview.spec.ts | 101 ++++++++++++++++++ .../dense-text-preview-openpencil-darwin.png | Bin 0 -> 97388 bytes .../canvas/typography-depth-visual.spec.ts | 19 +--- .../canvas/text-preparation-cache.test.ts | 100 ++++++++++++++++- tests/helpers/canvas/text-preparation.ts | 38 +++++++ 7 files changed, 285 insertions(+), 19 deletions(-) create mode 100644 tests/e2e/canvas/dense-text-preview.spec.ts create mode 100644 tests/e2e/canvas/dense-text-preview.spec.ts-snapshots/dense-text-preview-openpencil-darwin.png create mode 100644 tests/helpers/canvas/text-preparation.ts diff --git a/packages/core/src/canvas/text/index.ts b/packages/core/src/canvas/text/index.ts index 0dc783db3..f853daefd 100644 --- a/packages/core/src/canvas/text/index.ts +++ b/packages/core/src/canvas/text/index.ts @@ -134,6 +134,12 @@ function demandRemoteCoverage(r: TextRenderer, node: SceneNode, characters: stri } function observedGlyphReadiness(r: TextRenderer, node: SceneNode): NodeFontReadiness { + if ( + r.fontProvider && + r.textPreparationCache?.hasGlyphCoverage(node, fontManager.generation(), r.fontProvider) + ) + return 'ready' + const missingOccurrences = withPreparedText( r, node, @@ -151,7 +157,10 @@ function observedGlyphReadiness(r: TextRenderer, node: SceneNode): NodeFontReadi return prepared.missingGlyphs } ) - if (missingOccurrences.length === 0) return 'ready' + if (missingOccurrences.length === 0) { + r.textPreparationCache?.recordGlyphCoverage(node) + return 'ready' + } const charactersByScript = new Map() for (const { character, utf16Start } of missingOccurrences) { diff --git a/packages/core/src/canvas/text/preparation-cache.ts b/packages/core/src/canvas/text/preparation-cache.ts index a89b0db19..3eafa39f5 100644 --- a/packages/core/src/canvas/text/preparation-cache.ts +++ b/packages/core/src/canvas/text/preparation-cache.ts @@ -27,6 +27,10 @@ interface Entry extends PreparedText { export class TextPreparationCache { private readonly entries = new Map() private readonly nodeKeys = new Map>() + // A successful coverage check contains no native resources. Keep that result + // independently of paragraph LRU eviction, weakly owned by the source node. + private glyphCoverage = new WeakMap() + private readonly invalidatedCoverage = new Set() private units = 0 private generation = -1 private provider: TypefaceFontProvider | null = null @@ -91,7 +95,36 @@ export class TextPreparationCache { return consume(entry) } + hasGlyphCoverage(node: SceneNode, generation: number, provider: TypefaceFontProvider): boolean { + if (this.generation !== generation || this.provider !== provider) return false + if (this.invalidatedCoverage.delete(node.id)) { + this.glyphCoverage.delete(node) + return false + } + const inputs = this.glyphCoverage.get(node) + if (!inputs) return false + if (PARAGRAPH_INPUT_KEYS.every((prop, index) => inputs[index] === node[prop])) return true + this.glyphCoverage.delete(node) + return false + } + + /** Call only after observing complete coverage with this cache's current font scope. */ + recordGlyphCoverage(node: SceneNode): void { + this.invalidatedCoverage.delete(node.id) + this.glyphCoverage.set( + node, + PARAGRAPH_INPUT_KEYS.map((prop) => node[prop]) + ) + } + deleteNode(id: string): void { + // Invalidation arrives by ID; don't add strong node ownership just to find + // weak observations. Bound pending IDs and conservatively reset on overflow. + this.invalidatedCoverage.add(id) + if (this.invalidatedCoverage.size > this.maxEntries) { + this.glyphCoverage = new WeakMap() + this.invalidatedCoverage.clear() + } const keys = this.nodeKeys.get(id) if (keys) for (const key of keys) this.remove(key) } @@ -100,6 +133,8 @@ export class TextPreparationCache { for (const entry of this.entries.values()) entry.paragraph.delete() this.entries.clear() this.nodeKeys.clear() + this.glyphCoverage = new WeakMap() + this.invalidatedCoverage.clear() this.units = 0 } diff --git a/tests/e2e/canvas/dense-text-preview.spec.ts b/tests/e2e/canvas/dense-text-preview.spec.ts new file mode 100644 index 000000000..f20014842 --- /dev/null +++ b/tests/e2e/canvas/dense-text-preview.spec.ts @@ -0,0 +1,101 @@ +import { expect, test, useEditorSetupWithClear } from '#tests/e2e/fixtures' +import { probeParagraphBuilds } from '#tests/helpers/canvas/text-preparation' + +const editor = useEditorSetupWithClear('/?test&no-rulers&navigation-benchmark') + +test('dense text keeps exact pixels without reshaping unchanged labels during previews', async () => { + const interaction = await editor.page.evaluateHandle(() => { + const store = window.openPencil?.getStore?.() + if (!store) throw new Error('Editor unavailable') + return store.beginInteractiveEdit() + }) + try { + const previewId = await editor.page.evaluate(() => { + const store = window.openPencil?.getStore?.() + if (!store) throw new Error('Editor unavailable') + const page = store.state.currentPageId + const group = store.graph.createNode('FRAME', page, { + name: 'Dense text', + width: 8000, + height: 3600, + fills: [] + }) + // Coverage and drawing formerly needed 1,200 entries in a 1,024-paragraph cache. + for (let i = 0; i < 600; i++) { + store.graph.createNode('TEXT', group.id, { + x: (i % 20) * 400, + y: Math.floor(i / 20) * 120, + width: 380, + height: 110, + fontFamily: 'Inter', + fontWeight: 400, + fontSize: 48, + text: `Label ${i}`, + fills: [{ type: 'SOLID', color: { r: 0, g: 0, b: 0, a: 1 }, opacity: 1, visible: true }] + }) + } + const marker = store.graph.createNode('RECTANGLE', page, { + x: -10000, + y: -10000, + width: 10, + height: 10 + }) + store.clearSelection() + store.setZoomAroundPoint(0.06, 0, 0) + store.pan(-store.state.panX, -store.state.panY) + store.requestRender() + return marker.id + }) + await editor.page.evaluate(() => window.openPencil?.test?.navigation?.waitForSettlement()) + await editor.page.evaluate((id) => { + const store = window.openPencil?.getStore?.() + if (!store?.renderer) throw new Error('Renderer unavailable') + store.renderer.textPreparationCache.clear() + store.graph.updateNodePreview(id, { x: -10004 }) + store.requestRepaint() + }, previewId) + await editor.canvas.waitForRender() + const reference = await editor.canvas.screenshotCanvasRegion(520, 240) + expect(reference).toMatchSnapshot('dense-text-preview.png', { threshold: 0, maxDiffPixels: 0 }) + + // One additional pass lets drawing paragraphs occupy the cache after coverage + // observations have been memoized. Subsequent preview frames must not shape text. + await editor.page.evaluate((id) => { + const store = window.openPencil?.getStore?.() + store?.graph.updateNodePreview(id, { x: -10003 }) + store?.requestRepaint() + }, previewId) + await editor.canvas.waitForRender() + const probe = await probeParagraphBuilds(editor.page) + try { + for (const x of [-10002, -10001, -10000]) { + await editor.page.evaluate( + ({ id, x }) => { + const store = window.openPencil?.getStore?.() + store?.graph.updateNodePreview(id, { x }) + store?.requestRepaint() + }, + { id: previewId, x } + ) + await editor.canvas.waitForRender() + } + expect(await probe.evaluate((probe) => probe.readiness())).toBeGreaterThanOrEqual(1800) + expect(await probe.evaluate((probe) => probe.count())).toBe(0) + const actual = await editor.canvas.screenshotCanvasRegion(520, 240) + expect(actual.equals(reference)).toBe(true) + editor.canvas.assertNoErrors() + } finally { + try { + await probe.evaluate((probe) => probe.restore()) + } finally { + await probe.dispose() + } + } + } finally { + try { + await interaction.evaluate((end) => end()) + } finally { + await interaction.dispose() + } + } +}) diff --git a/tests/e2e/canvas/dense-text-preview.spec.ts-snapshots/dense-text-preview-openpencil-darwin.png b/tests/e2e/canvas/dense-text-preview.spec.ts-snapshots/dense-text-preview-openpencil-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..676a89643b45203ec0c690878511075d8721696d GIT binary patch literal 97388 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 Hnfm+>w|gdI literal 0 HcmV?d00001 diff --git a/tests/e2e/canvas/typography-depth-visual.spec.ts b/tests/e2e/canvas/typography-depth-visual.spec.ts index 4b49b5bdb..130d774e1 100644 --- a/tests/e2e/canvas/typography-depth-visual.spec.ts +++ b/tests/e2e/canvas/typography-depth-visual.spec.ts @@ -1,4 +1,5 @@ import { expect, test, useEditorSetupWithClear } from '#tests/e2e/fixtures' +import { probeParagraphBuilds } from '#tests/helpers/canvas/text-preparation' const editor = useEditorSetupWithClear('/?test&no-chrome&no-rulers') @@ -88,23 +89,7 @@ test('text case vertical alignment and ending truncation', async () => { }, previewId) await editor.canvas.waitForRender() const reference = await editor.canvas.screenshotCanvasRegion() - const preparations = await editor.page.evaluateHandle(() => { - const renderer = window.openPencil?.getStore?.().renderer - if (!renderer) throw new Error('Renderer unavailable') - const builder = renderer.ck.ParagraphBuilder - const original = builder.MakeFromFontProvider - let count = 0 - builder.MakeFromFontProvider = (...args) => { - count++ - return original.apply(builder, args) - } - return { - count: () => count, - restore: () => { - builder.MakeFromFontProvider = original - } - } - }) + const preparations = await probeParagraphBuilds(editor.page) try { for (let step = 0; step < 3; step++) { await editor.page.evaluate( diff --git a/tests/engine/render/canvas/text-preparation-cache.test.ts b/tests/engine/render/canvas/text-preparation-cache.test.ts index c40e5f30b..5070afc6b 100644 --- a/tests/engine/render/canvas/text-preparation-cache.test.ts +++ b/tests/engine/render/canvas/text-preparation-cache.test.ts @@ -1,12 +1,14 @@ import { describe, expect, test } from 'bun:test' -import type { Paragraph } from 'canvaskit-wasm' +import type { CanvasKit, Paragraph } from 'canvaskit-wasm' import { SceneGraph } from '@open-pencil/scene-graph' import { initCanvasKit } from '#cli/headless' +import { buildParagraph, nodeFontReadiness } from '#core/canvas/text' import type { ParagraphNode } from '#core/canvas/text/paragraph-inputs' import { TextPreparationCache } from '#core/canvas/text/preparation-cache' +import { fontManager } from '#core/text/fonts' async function fixture(maxEntries = 8, maxUnits = 1000) { const ck = await initCanvasKit() @@ -53,6 +55,102 @@ async function fixture(maxEntries = 8, maxUnits = 1000) { } describe('text preparation cache', () => { + test('does not repeatedly shape coverage when a dense scan exceeds paragraph capacity', async () => { + const f = await fixture(8) + const data = await Bun.file('public/Inter-Regular.ttf').arrayBuffer() + f.provider.registerFont(data, 'Inter') + fontManager.markLoaded('Inter', 'Regular', data) + let builds = 0 + const ck: CanvasKit = { + ...f.ck, + ParagraphBuilder: { + ...f.ck.ParagraphBuilder, + MakeFromFontProvider( + ...args: Parameters + ) { + builds++ + return f.ck.ParagraphBuilder.MakeFromFontProvider(...args) + } + } + } + const renderer = { + ck, + fontProvider: f.provider, + fontsLoaded: true, + textPreparationCache: f.cache + } + const nodes = Array.from({ length: 6 }, (_, i) => + f.graph.createNode('TEXT', f.node.parentId, { + text: `Label ${i}`, + fontFamily: 'Inter', + fontWeight: 400, + width: 100, + height: 30 + }) + ) + function draw() { + for (const node of nodes) { + expect(nodeFontReadiness(renderer, node)).toBe('ready') + f.cache.use( + node, + 'draw', + fontManager.generation(), + f.provider, + () => buildParagraph(renderer, node), + ({ paragraph }) => paragraph.getHeight() + ) + } + } + try { + draw() + expect(builds).toBe(12) + draw() + const warmBuilds = builds + draw() + expect(builds).toBe(warmBuilds) + f.cache.deleteNode(nodes[0].id) + draw() + expect(builds).toBe(warmBuilds + 2) + f.graph.updateNodePreview(nodes[0].id, { text: 'Edited label' }) + draw() + expect(builds).toBe(warmBuilds + 4) + f.cache.clear() + draw() + expect(builds).toBe(warmBuilds + 16) + } finally { + f.dispose() + } + }) + + test('scopes successful coverage to fonts, inputs and explicit invalidation', async () => { + const f = await fixture(2) + const otherProvider = f.ck.TypefaceFontProvider.Make() + try { + f.use('coverage', 1) + f.cache.recordGlyphCoverage(f.node) + expect(f.cache.hasGlyphCoverage(f.node, 1, f.provider)).toBe(true) + expect(f.cache.hasGlyphCoverage(f.node, 2, f.provider)).toBe(false) + expect(f.cache.hasGlyphCoverage(f.node, 1, otherProvider)).toBe(false) + f.graph.updateNodePreview(f.node.id, { x: 50, rotation: 20 }) + expect(f.cache.hasGlyphCoverage(f.node, 1, f.provider)).toBe(true) + f.graph.updateNodePreview(f.node.id, { width: 80 }) + expect(f.cache.hasGlyphCoverage(f.node, 1, f.provider)).toBe(false) + f.use('coverage', 1) + f.cache.recordGlyphCoverage(f.node) + f.cache.deleteNode('unrelated') + expect(f.cache.hasGlyphCoverage(f.node, 1, f.provider)).toBe(true) + f.cache.deleteNode('another') + f.cache.deleteNode('overflow') + expect(f.cache.hasGlyphCoverage(f.node, 1, f.provider)).toBe(false) + f.cache.recordGlyphCoverage(f.node) + f.use('draw', 2) + expect(f.cache.hasGlyphCoverage(f.node, 2, f.provider)).toBe(false) + } finally { + otherProvider.delete() + f.dispose() + } + }) + test('reuses native paragraphs during movement and invalidates text layout inputs', async () => { const f = await fixture() try { diff --git a/tests/helpers/canvas/text-preparation.ts b/tests/helpers/canvas/text-preparation.ts new file mode 100644 index 000000000..341332034 --- /dev/null +++ b/tests/helpers/canvas/text-preparation.ts @@ -0,0 +1,38 @@ +import type { Page } from '@playwright/test' + +export function probeParagraphBuilds(page: Page) { + return page.evaluateHandle(() => { + const renderers = window.openPencil?.getStore?.().canvasRenderers + if (!renderers?.length) throw new Error('Renderer unavailable') + const restores: Array<() => void> = [] + let count = 0 + let readiness = 0 + for (const builder of new Set(renderers.map((renderer) => renderer.ck.ParagraphBuilder))) { + const original = builder.MakeFromFontProvider + builder.MakeFromFontProvider = (...args) => { + count++ + return original.apply(builder, args) + } + restores.push(() => { + builder.MakeFromFontProvider = original + }) + } + for (const renderer of renderers) { + const original = renderer.nodeFontReadiness + renderer.nodeFontReadiness = (node) => { + readiness++ + return original.call(renderer, node) + } + restores.push(() => { + renderer.nodeFontReadiness = original + }) + } + return { + count: () => count, + readiness: () => readiness, + restore: () => { + for (const restore of restores) restore() + } + } + }) +}