refactor(editor): invalidate support in turbo renderer (#10368)

refactor(editor): invalidate support in turbo renderer

- Added `invalidate()` method to clear cache and canvas
- Simplified debug pane controls to single invalidate button
- Replaced layout update with refresh debounce on block updates
- Improved cache handling and bitmap drawing flow

refactor: refresh after invalidate
This commit is contained in:
doodlewind
2025-02-23 03:23:20 +00:00
parent f8cabe8bb1
commit 22f9db63bc
4 changed files with 32 additions and 31 deletions
@@ -1,7 +1,4 @@
import { import { type Viewport } from '@blocksuite/block-std/gfx';
GfxControllerIdentifier,
type Viewport,
} from '@blocksuite/block-std/gfx';
import { Pane } from 'tweakpane'; import { Pane } from 'tweakpane';
import { getSentenceRects, segmentSentences } from './text-utils.js'; import { getSentenceRects, segmentSentences } from './text-utils.js';
@@ -109,22 +106,7 @@ export function initTweakpane(
.on('change', ({ value }) => { .on('change', ({ value }) => {
renderer.state = value ? 'paused' : 'monitoring'; renderer.state = value ? 'paused' : 'monitoring';
}); });
debugPane.addButton({ title: 'Invalidate' }).on('click', () => {
debugPane renderer.invalidate();
.addBinding({ keepDOM: true }, 'keepDOM', {
label: 'Keep DOM',
})
.on('change', ({ value }) => {
const container = viewportElement.querySelector('gfx-viewport')!;
(container as HTMLElement).style.display = value ? 'block' : 'none';
});
debugPane.addButton({ title: 'Fit Viewport' }).on('click', () => {
const gfx = renderer.std.get(GfxControllerIdentifier);
gfx.fitToScreen();
});
debugPane.addButton({ title: 'Force Refresh' }).on('click', () => {
renderer.refresh(true).catch(console.error);
}); });
} }
@@ -67,15 +67,17 @@ export class ViewportTurboRendererExtension extends LifeCycleWatcher {
}); });
const debounceOptions = { leading: false, trailing: true }; const debounceOptions = { leading: false, trailing: true };
const debouncedLayoutUpdate = debounce( const debouncedRefresh = debounce(
() => this.updateLayoutCache(), () => {
500, this.refresh().catch(console.error);
},
1000, // During this period, fallback to DOM
debounceOptions debounceOptions
); );
this.disposables.add( this.disposables.add(
this.std.store.slots.blockUpdated.on(() => { this.std.store.slots.blockUpdated.on(() => {
this.clearTile(); this.invalidate();
debouncedLayoutUpdate(); debouncedRefresh();
}) })
); );
} }
@@ -103,21 +105,30 @@ export class ViewportTurboRendererExtension extends LifeCycleWatcher {
} else if (this.canUseBitmapCache()) { } else if (this.canUseBitmapCache()) {
this.drawCachedBitmap(this.layoutCache!); this.drawCachedBitmap(this.layoutCache!);
} else { } else {
// Unneeded most of the time, the DOM query is debounced after block update
if (!this.layoutCache) { if (!this.layoutCache) {
this.updateLayoutCache(); this.updateLayoutCache();
} }
const layout = this.layoutCache!;
await this.paintLayout(this.layoutCache!); await this.paintLayout(layout);
this.drawCachedBitmap(this.layoutCache!); this.drawCachedBitmap(layout);
} }
} }
invalidate() {
this.clearCache();
this.clearCanvas();
}
private updateLayoutCache() { private updateLayoutCache() {
const layout = getViewportLayout(this.std.host, this.viewport); const layout = getViewportLayout(this.std.host, this.viewport);
this.layoutCache = layout; this.layoutCache = layout;
} }
private clearCache() {
this.layoutCache = null;
this.clearTile();
}
private clearTile() { private clearTile() {
if (this.tile) { if (this.tile) {
this.tile.bitmap.close(); this.tile.bitmap.close();
@@ -1,4 +1,7 @@
import { ViewportTurboRendererExtension } from '@blocksuite/affine-shared/viewport-renderer'; import {
ViewportTurboRendererExtension,
ViewportTurboRendererIdentifier,
} from '@blocksuite/affine-shared/viewport-renderer';
import { addSampleNotes } from './doc-generator.js'; import { addSampleNotes } from './doc-generator.js';
import { setupEditor } from './setup.js'; import { setupEditor } from './setup.js';
@@ -7,6 +10,9 @@ async function init() {
setupEditor('edgeless', [ViewportTurboRendererExtension]); setupEditor('edgeless', [ViewportTurboRendererExtension]);
addSampleNotes(doc, 100); addSampleNotes(doc, 100);
doc.load(); doc.load();
const renderer = editor.std.get(ViewportTurboRendererIdentifier);
window.renderer = renderer;
} }
init(); init();
@@ -9,6 +9,7 @@ import { effects } from '../../effects.js';
blocksEffects(); blocksEffects();
effects(); effects();
import type { ViewportTurboRendererExtension } from '@blocksuite/affine-shared/viewport-renderer';
import { import {
CommunityCanvasTextFonts, CommunityCanvasTextFonts,
type DocMode, type DocMode,
@@ -136,5 +137,6 @@ declare global {
doc: Store; doc: Store;
job: Transformer; job: Transformer;
collection: TestWorkspace; collection: TestWorkspace;
renderer: ViewportTurboRendererExtension;
} }
} }