From f85b35227b535bf4785602baa14d503df4f2cd2d Mon Sep 17 00:00:00 2001 From: doodlewind <7312949+doodlewind@users.noreply.github.com> Date: Thu, 10 Apr 2025 08:49:23 +0000 Subject: [PATCH] feat(editor): replace flat layout cache with tree in turbo renderer (#11319) ### TL;DR Refactored the BlockSuite turbo renderer to use a hierarchical tree structure for layouts instead of a flat list, improving rendering accuracy and performance. ### What changed? - Redesigned the layout system to use a tree structure (`ViewportLayoutTree`) that better represents the document hierarchy - Added `blockId` to all layout objects for better tracking and debugging - Updated the layout query mechanism to work with models directly instead of components - Enhanced error handling with more descriptive warnings and error messages - Improved the painting process to traverse the layout tree recursively - Fixed viewport coordinate calculations for more accurate rendering - Updated the worker communication to support the new tree-based layout structure ### Why make this change? The previous flat layout structure didn't properly represent the hierarchical nature of documents, leading to rendering issues with nested blocks. This tree-based approach: 1. Better represents the actual document structure 2. Improves rendering accuracy for nested elements 3. Makes debugging easier with more consistent block identification 4. Provides a more robust foundation for future rendering optimizations 5. Reduces the likelihood of rendering artifacts when scrolling or zooming --- .../list/src/turbo/list-layout-handler.ts | 24 ++- .../list/src/turbo/list-painter.worker.ts | 9 +- .../src/turbo/paragraph-layout-handler.ts | 77 ++++---- .../src/turbo/paragraph-painter.worker.ts | 9 +- .../src/layout/block-layout-provider.ts | 12 +- .../src/painter/painter.worker.ts | 33 ++-- .../gfx/turbo-renderer/src/renderer-utils.ts | 186 +++++++++++------- .../gfx/turbo-renderer/src/turbo-renderer.ts | 23 +-- .../affine/gfx/turbo-renderer/src/types.ts | 27 ++- .../blocksuite/extensions/turbo-renderer.ts | 2 +- 10 files changed, 244 insertions(+), 158 deletions(-) diff --git a/blocksuite/affine/blocks/list/src/turbo/list-layout-handler.ts b/blocksuite/affine/blocks/list/src/turbo/list-layout-handler.ts index b6aff940b..4459dc906 100644 --- a/blocksuite/affine/blocks/list/src/turbo/list-layout-handler.ts +++ b/blocksuite/affine/blocks/list/src/turbo/list-layout-handler.ts @@ -6,8 +6,9 @@ import { segmentSentences, } from '@blocksuite/affine-gfx-turbo-renderer'; import type { Container } from '@blocksuite/global/di'; -import type { GfxBlockComponent } from '@blocksuite/std'; -import { clientToModelCoord } from '@blocksuite/std/gfx'; +import type { EditorHost, GfxBlockComponent } from '@blocksuite/std'; +import { clientToModelCoord, type ViewportRecord } from '@blocksuite/std/gfx'; +import type { BlockModel } from '@blocksuite/store'; import type { ListLayout } from './list-painter.worker'; @@ -21,24 +22,27 @@ export class ListLayoutHandlerExtension extends BlockLayoutHandlerExtension { diff --git a/blocksuite/affine/blocks/list/src/turbo/list-painter.worker.ts b/blocksuite/affine/blocks/list/src/turbo/list-painter.worker.ts index c6a3e7c9e..67de99931 100644 --- a/blocksuite/affine/blocks/list/src/turbo/list-painter.worker.ts +++ b/blocksuite/affine/blocks/list/src/turbo/list-painter.worker.ts @@ -77,10 +77,15 @@ class ListLayoutPainter implements BlockLayoutPainter { return; } - if (!isListLayout(layout)) return; + if (!isListLayout(layout)) { + console.warn( + 'Expected list layout but received different format:', + layout + ); + return; + } const renderedPositions = new Set(); - layout.items.forEach(item => { const fontSize = item.fontSize; const baselineY = getBaseline(fontSize); diff --git a/blocksuite/affine/blocks/paragraph/src/turbo/paragraph-layout-handler.ts b/blocksuite/affine/blocks/paragraph/src/turbo/paragraph-layout-handler.ts index a35b3192c..fd024d7c6 100644 --- a/blocksuite/affine/blocks/paragraph/src/turbo/paragraph-layout-handler.ts +++ b/blocksuite/affine/blocks/paragraph/src/turbo/paragraph-layout-handler.ts @@ -6,8 +6,9 @@ import { segmentSentences, } from '@blocksuite/affine-gfx-turbo-renderer'; import type { Container } from '@blocksuite/global/di'; -import type { GfxBlockComponent } from '@blocksuite/std'; -import { clientToModelCoord } from '@blocksuite/std/gfx'; +import type { EditorHost, GfxBlockComponent } from '@blocksuite/std'; +import { clientToModelCoord, type ViewportRecord } from '@blocksuite/std/gfx'; +import type { BlockModel } from '@blocksuite/store'; import type { ParagraphLayout } from './paragraph-painter.worker'; @@ -21,58 +22,54 @@ export class ParagraphLayoutHandlerExtension extends BlockLayoutHandlerExtension ); } - queryLayout(component: GfxBlockComponent): ParagraphLayout | null { + override queryLayout( + model: BlockModel, + host: EditorHost, + viewportRecord: ViewportRecord + ): ParagraphLayout | null { + const component = host.std.view.getBlock(model.id) as GfxBlockComponent; const paragraphSelector = '.affine-paragraph-rich-text-wrapper [data-v-text="true"]'; - const paragraphNodes = component.querySelectorAll(paragraphSelector); - - if (paragraphNodes.length === 0) return null; - - const viewportRecord = component.gfx.viewport.deserializeRecord( - component.dataset.viewportState - ); - - if (!viewportRecord) return null; + const paragraphNode = component.querySelector(paragraphSelector); + if (!paragraphNode) return null; const { zoom, viewScale } = viewportRecord; const paragraph: ParagraphLayout = { type: 'affine:paragraph', sentences: [], + blockId: model.id, + rect: { x: 0, y: 0, w: 0, h: 0 }, }; - paragraphNodes.forEach(paragraphNode => { - const computedStyle = window.getComputedStyle(paragraphNode); - const fontSizeStr = computedStyle.fontSize; - const fontSize = parseInt(fontSizeStr); + const computedStyle = window.getComputedStyle(paragraphNode); + const fontSizeStr = computedStyle.fontSize; + const fontSize = parseInt(fontSizeStr); - const sentences = segmentSentences(paragraphNode.textContent || ''); - const sentenceLayouts = sentences.map(sentence => { - const sentenceRects = getSentenceRects(paragraphNode, sentence); - const rects = sentenceRects.map(({ text, rect }) => { - const [modelX, modelY] = clientToModelCoord(viewportRecord, [ - rect.x, - rect.y, - ]); - return { - text, - rect: { - x: modelX, - y: modelY, - w: rect.w / zoom / viewScale, - h: rect.h / zoom / viewScale, - }, - }; - }); + const sentences = segmentSentences(paragraphNode.textContent || ''); + const sentenceLayouts = sentences.map(sentence => { + const sentenceRects = getSentenceRects(paragraphNode, sentence); + const rects = sentenceRects.map(({ text, rect }) => { + const [modelX, modelY] = clientToModelCoord(viewportRecord, [ + rect.x, + rect.y, + ]); return { - text: sentence, - rects, - fontSize, + text, + rect: { + x: modelX, + y: modelY, + w: rect.w / zoom / viewScale, + h: rect.h / zoom / viewScale, + }, }; }); - - paragraph.sentences.push(...sentenceLayouts); + return { + text: sentence, + rects, + fontSize, + }; }); - + paragraph.sentences.push(...sentenceLayouts); return paragraph; } diff --git a/blocksuite/affine/blocks/paragraph/src/turbo/paragraph-painter.worker.ts b/blocksuite/affine/blocks/paragraph/src/turbo/paragraph-painter.worker.ts index 4cac0f0e6..17b2b7bd9 100644 --- a/blocksuite/affine/blocks/paragraph/src/turbo/paragraph-painter.worker.ts +++ b/blocksuite/affine/blocks/paragraph/src/turbo/paragraph-painter.worker.ts @@ -73,10 +73,15 @@ class ParagraphLayoutPainter implements BlockLayoutPainter { return; } - if (!isParagraphLayout(layout)) return; // cast to ParagraphLayout + if (!isParagraphLayout(layout)) { + console.warn( + 'Expected paragraph layout but received different format:', + layout + ); + return; + } const renderedPositions = new Set(); - layout.sentences.forEach(sentence => { const fontSize = sentence.fontSize; const baselineY = getBaseline(fontSize); diff --git a/blocksuite/affine/gfx/turbo-renderer/src/layout/block-layout-provider.ts b/blocksuite/affine/gfx/turbo-renderer/src/layout/block-layout-provider.ts index 0017293c2..6c1d5af92 100644 --- a/blocksuite/affine/gfx/turbo-renderer/src/layout/block-layout-provider.ts +++ b/blocksuite/affine/gfx/turbo-renderer/src/layout/block-layout-provider.ts @@ -1,5 +1,7 @@ import { createIdentifier } from '@blocksuite/global/di'; -import type { GfxBlockComponent } from '@blocksuite/std'; +import type { EditorHost } from '@blocksuite/std'; +import type { ViewportRecord } from '@blocksuite/std/gfx'; +import type { BlockModel } from '@blocksuite/store'; import { Extension } from '@blocksuite/store'; import type { BlockLayout, Rect } from '../types'; @@ -8,7 +10,13 @@ export abstract class BlockLayoutHandlerExtension< T extends BlockLayout = BlockLayout, > extends Extension { abstract readonly blockType: string; - abstract queryLayout(component: GfxBlockComponent): T | null; + + abstract queryLayout( + model: BlockModel, + host: EditorHost, + viewportRecord: ViewportRecord + ): T | null; + abstract calculateBound(layout: T): { rect: Rect; subRects: Rect[]; diff --git a/blocksuite/affine/gfx/turbo-renderer/src/painter/painter.worker.ts b/blocksuite/affine/gfx/turbo-renderer/src/painter/painter.worker.ts index 5d1d14f3c..4a1c58043 100644 --- a/blocksuite/affine/gfx/turbo-renderer/src/painter/painter.worker.ts +++ b/blocksuite/affine/gfx/turbo-renderer/src/painter/painter.worker.ts @@ -7,8 +7,9 @@ import type { ExtensionType } from '@blocksuite/store'; import type { BlockLayoutPainter, + BlockLayoutTreeNode, HostToWorkerMessage, - ViewportLayout, + ViewportLayoutTree, WorkerToHostMessage, } from '../types'; @@ -33,8 +34,8 @@ export class ViewportLayoutPainter { private zoom = 1; public provider: ServiceProvider; - getPainter(type: string): BlockLayoutPainter | undefined { - return this.provider.get(BlockPainterProvider(type)); + getPainter(type: string): BlockLayoutPainter | null { + return this.provider.getOptional(BlockPainterProvider(type)); } constructor(extensions: ExtensionType[]) { @@ -66,24 +67,28 @@ export class ViewportLayoutPainter { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); } - paint(layout: ViewportLayout, version: number) { + paint(layout: ViewportLayoutTree, version: number) { const { canvas, ctx } = this; if (!canvas || !ctx) return; - if (layout.rect.w === 0 || layout.rect.h === 0) { - console.warn('empty layout rect'); - return; - } + + this.paintTree(layout, version); + } + + paintTree(layout: ViewportLayoutTree, version: number) { + const { canvas, ctx } = this; + const { overallRect } = layout; + if (!canvas || !ctx) return; this.clearBackground(); - ctx.scale(this.zoom, this.zoom); - layout.blocks.forEach(blockLayout => { - const painter = this.getPainter(blockLayout.type); - if (!painter) return; - painter.paint(ctx, blockLayout, layout.rect.x, layout.rect.y); - }); + const paintNode = (node: BlockLayoutTreeNode) => { + const painter = this.getPainter(node.type); + painter?.paint(ctx, node.layout, overallRect.x, overallRect.y); + node.children.forEach(paintNode); + }; + layout.roots.forEach(root => paintNode(root)); const bitmap = canvas.transferToImageBitmap(); const message: WorkerToHostMessage = { type: 'bitmapPainted', diff --git a/blocksuite/affine/gfx/turbo-renderer/src/renderer-utils.ts b/blocksuite/affine/gfx/turbo-renderer/src/renderer-utils.ts index e26c05436..7c20bca75 100644 --- a/blocksuite/affine/gfx/turbo-renderer/src/renderer-utils.ts +++ b/blocksuite/affine/gfx/turbo-renderer/src/renderer-utils.ts @@ -1,12 +1,14 @@ import type { EditorHost, GfxBlockComponent } from '@blocksuite/std'; -import { - GfxBlockElementModel, - GfxControllerIdentifier, - type Viewport, -} from '@blocksuite/std/gfx'; +import { type Viewport } from '@blocksuite/std/gfx'; +import type { BlockModel } from '@blocksuite/store'; import { BlockLayoutHandlersIdentifier } from './layout/block-layout-provider'; -import type { BlockLayout, RenderingState, ViewportLayout } from './types'; +import type { + BlockLayout, + BlockLayoutTreeNode, + RenderingState, + ViewportLayoutTree, +} from './types'; export function syncCanvasSize(canvas: HTMLCanvasElement, host: HTMLElement) { const hostRect = host.getBoundingClientRect(); @@ -21,33 +23,10 @@ export function syncCanvasSize(canvas: HTMLCanvasElement, host: HTMLElement) { canvas.style.pointerEvents = 'none'; } -function getBlockLayouts(host: EditorHost): BlockLayout[] { - const gfx = host.std.get(GfxControllerIdentifier); - const models = gfx.gfxElements.filter(e => e instanceof GfxBlockElementModel); - const components = models - .map(model => gfx.view.get(model.id)) - .filter(Boolean) as GfxBlockComponent[]; - - const layouts: BlockLayout[] = []; - components.forEach(component => { - const layoutHandlers = host.std.provider.getAll( - BlockLayoutHandlersIdentifier - ); - const handlersArray = Array.from(layoutHandlers.values()); - for (const handler of handlersArray) { - const layout = handler.queryLayout(component); - if (layout) { - layouts.push(layout); - } - } - }); - return layouts; -} - -export function getViewportLayout( +export function getViewportLayoutTree( host: EditorHost, viewport: Viewport -): ViewportLayout { +): ViewportLayoutTree { const zoom = viewport.zoom; let layoutMinX = Infinity; @@ -55,36 +34,106 @@ export function getViewportLayout( let layoutMaxX = -Infinity; let layoutMaxY = -Infinity; - const blockLayouts = getBlockLayouts(host); + const store = host.std.store; + const rootModel = store.root; + + if (!rootModel) { + return { roots: [], overallRect: { x: 0, y: 0, w: 0, h: 0 } }; + } const providers = host.std.provider.getAll(BlockLayoutHandlersIdentifier); const providersArray = Array.from(providers.values()); - blockLayouts.forEach(blockLayout => { - const provider = providersArray.find(p => p.blockType === blockLayout.type); - if (!provider) return; + // Recursive function to build the tree structure + const buildLayoutTreeNode = ( + model: BlockModel, + ancestorViewportState?: string | null + ): BlockLayoutTreeNode | null => { + const baseLayout: BlockLayout = { + blockId: model.id, + type: model.flavour, + rect: { x: 0, y: 0, w: 0, h: 0 }, + }; - const { rect } = provider.calculateBound(blockLayout); + const handler = providersArray.find(p => p.blockType === model.flavour); - layoutMinX = Math.min(layoutMinX, rect.x); - layoutMinY = Math.min(layoutMinY, rect.y); - layoutMaxX = Math.max(layoutMaxX, rect.x + rect.w); - layoutMaxY = Math.max(layoutMaxY, rect.y + rect.h); - }); + // Determine the correct viewport state to use + const component = host.std.view.getBlock(model.id) as GfxBlockComponent; + const currentViewportState = component?.dataset.viewportState; + const effectiveViewportState = + currentViewportState ?? ancestorViewportState; + const defaultViewportState = { + left: 0, + top: 0, + viewportX: 0, + viewportY: 0, + zoom: 1, + viewScale: 1, + }; - const layoutModelCoord = [layoutMinX, layoutMinY]; + const viewportRecord = effectiveViewportState + ? viewport.deserializeRecord(effectiveViewportState) || + defaultViewportState + : defaultViewportState; + + const layoutData = handler?.queryLayout(model, host, viewportRecord); + + if (handler && layoutData) { + const { rect } = handler.calculateBound(layoutData); + baseLayout.rect = rect; + layoutMinX = Math.min(layoutMinX, rect.x); + layoutMinY = Math.min(layoutMinY, rect.y); + layoutMaxX = Math.max(layoutMaxX, rect.x + rect.w); + layoutMaxY = Math.max(layoutMaxY, rect.y + rect.h); + } + + const children: BlockLayoutTreeNode[] = []; + for (const childModel of model.children) { + const childNode = buildLayoutTreeNode(childModel, effectiveViewportState); + if (childNode) { + children.push(childNode); + } + } + + // Create node for this block - ALWAYS return a node + // Return the node structure including the layout (either real or fallback) + return { + blockId: model.id, + type: model.flavour, + layout: layoutData ? { ...baseLayout, ...layoutData } : baseLayout, + children, + }; + }; + + const roots: BlockLayoutTreeNode[] = []; + const rootNode = buildLayoutTreeNode(rootModel); + if (rootNode) { + roots.push(rootNode); + } + + // If no valid layouts were found, use default values + if (layoutMinX === Infinity) { + layoutMinX = 0; + layoutMinY = 0; + layoutMaxX = 0; + layoutMaxY = 0; + } + + // Calculate overall rectangle const w = (layoutMaxX - layoutMinX) / zoom / viewport.viewScale; const h = (layoutMaxY - layoutMinY) / zoom / viewport.viewScale; - const layout: ViewportLayout = { - blocks: blockLayouts, - rect: { - x: layoutModelCoord[0], - y: layoutModelCoord[1], + + const result = { + roots, + overallRect: { + x: layoutMinX, + y: layoutMinY, w: Math.max(w, 0), h: Math.max(h, 0), }, }; - return layout; + + return result; } export function debugLog(message: string, state: RenderingState) { @@ -98,14 +147,15 @@ export function debugLog(message: string, state: RenderingState) { export function paintPlaceholder( host: EditorHost, canvas: HTMLCanvasElement, - layout: ViewportLayout | null, + layout: ViewportLayoutTree | null, viewport: Viewport ) { const ctx = canvas.getContext('2d'); - if (!ctx) return; - if (!layout) return; + if (!ctx || !layout) return; + const dpr = window.devicePixelRatio; - const layoutViewCoord = viewport.toViewCoord(layout.rect.x, layout.rect.y); + const { overallRect } = layout; + const layoutViewCoord = viewport.toViewCoord(overallRect.x, overallRect.y); const offsetX = layoutViewCoord[0]; const offsetY = layoutViewCoord[1]; @@ -120,30 +170,28 @@ export function paintPlaceholder( ); const handlersArray = Array.from(layoutHandlers.values()); - layout.blocks.forEach((blockLayout, blockIndex) => { - ctx.fillStyle = colors[blockIndex % colors.length]; - const renderedPositions = new Set(); - - const handler = handlersArray.find(h => h.blockType === blockLayout.type); - if (!handler) return; - const { subRects } = handler.calculateBound(blockLayout); - - subRects.forEach(rect => { - const x = ((rect.x - layout.rect.x) * viewport.zoom + offsetX) * dpr; - const y = ((rect.y - layout.rect.y) * viewport.zoom + offsetY) * dpr; - + const paintNode = (node: BlockLayoutTreeNode, depth: number = 0) => { + const { layout: nodeLayout, type } = node; + const handler = handlersArray.find(h => h.blockType === type); + if (handler) { + ctx.fillStyle = colors[depth % colors.length]; + const rect = nodeLayout.rect; + const x = ((rect.x - overallRect.x) * viewport.zoom + offsetX) * dpr; + const y = ((rect.y - overallRect.y) * viewport.zoom + offsetY) * dpr; const width = rect.w * viewport.zoom * dpr; const height = rect.h * viewport.zoom * dpr; - const posKey = `${x},${y}`; - if (renderedPositions.has(posKey)) return; ctx.fillRect(x, y, width, height); if (width > 10 && height > 5) { ctx.strokeStyle = 'rgba(150, 150, 150, 0.3)'; ctx.strokeRect(x, y, width, height); } + } - renderedPositions.add(posKey); - }); - }); + if (node.children.length > 0) { + node.children.forEach(childNode => paintNode(childNode, depth + 1)); + } + }; + + layout.roots.forEach(rootNode => paintNode(rootNode)); } diff --git a/blocksuite/affine/gfx/turbo-renderer/src/turbo-renderer.ts b/blocksuite/affine/gfx/turbo-renderer/src/turbo-renderer.ts index b2f100029..59693e6ce 100644 --- a/blocksuite/affine/gfx/turbo-renderer/src/turbo-renderer.ts +++ b/blocksuite/affine/gfx/turbo-renderer/src/turbo-renderer.ts @@ -19,7 +19,7 @@ import { debounceTime } from 'rxjs/operators'; import { debugLog, - getViewportLayout, + getViewportLayoutTree, paintPlaceholder, syncCanvasSize, } from './renderer-utils'; @@ -28,7 +28,7 @@ import type { RendererOptions, RenderingState, TurboRendererConfig, - ViewportLayout, + ViewportLayoutTree, WorkerToHostMessage, } from './types'; @@ -49,7 +49,7 @@ export class ViewportTurboRendererExtension extends GfxExtension { public readonly canvas: HTMLCanvasElement = document.createElement('canvas'); private readonly worker: Worker; private readonly disposables = new DisposableGroup(); - private layoutCacheData: ViewportLayout | null = null; + private layoutCacheData: ViewportLayoutTree | null = null; private layoutVersion = 0; private bitmap: ImageBitmap | null = null; private viewportElement: GfxViewportElement | null = null; @@ -172,9 +172,9 @@ export class ViewportTurboRendererExtension extends GfxExtension { get layoutCache() { if (this.layoutCacheData) return this.layoutCacheData; - const layout = getViewportLayout(this.std.host, this.viewport); + const layoutTree = getViewportLayoutTree(this.std.host, this.viewport); this.debugLog('Layout cache updated'); - return (this.layoutCacheData = layout); + return (this.layoutCacheData = layoutTree); } async refresh() { @@ -248,8 +248,8 @@ export class ViewportTurboRendererExtension extends GfxExtension { type: 'paintLayout', data: { layout, - width: layout.rect.w, - height: layout.rect.h, + width: layout.overallRect.w, + height: layout.overallRect.h, dpr, zoom: this.viewport.zoom, version: currentVersion, @@ -316,17 +316,18 @@ export class ViewportTurboRendererExtension extends GfxExtension { if (!ctx) return; this.clearCanvas(); + const layoutViewCoord = this.viewport.toViewCoord( - layout.rect.x, - layout.rect.y + layout.overallRect.x, + layout.overallRect.y ); ctx.drawImage( bitmap, layoutViewCoord[0] * window.devicePixelRatio, layoutViewCoord[1] * window.devicePixelRatio, - layout.rect.w * window.devicePixelRatio * this.viewport.zoom, - layout.rect.h * window.devicePixelRatio * this.viewport.zoom + layout.overallRect.w * window.devicePixelRatio * this.viewport.zoom, + layout.overallRect.h * window.devicePixelRatio * this.viewport.zoom ); this.debugLog('Bitmap drawn to canvas'); diff --git a/blocksuite/affine/gfx/turbo-renderer/src/types.ts b/blocksuite/affine/gfx/turbo-renderer/src/types.ts index 146efc3e5..efb79be69 100644 --- a/blocksuite/affine/gfx/turbo-renderer/src/types.ts +++ b/blocksuite/affine/gfx/turbo-renderer/src/types.ts @@ -14,13 +14,14 @@ export interface ViewportState { } export interface BlockLayout extends Record { + blockId: string; type: string; - rect?: Rect; -} - -export interface ViewportLayout { - blocks: BlockLayout[]; - rect: Rect; + rect: { + x: number; + y: number; + w: number; + h: number; + }; } export interface TextRect { @@ -60,7 +61,7 @@ export type WorkerToHostMessage = MessageBitmapPainted | MessagePaintError; export type MessagePaint = { type: 'paintLayout'; data: { - layout: ViewportLayout; + layout: ViewportLayoutTree; width: number; height: number; dpr: number; @@ -89,3 +90,15 @@ export interface TurboRendererConfig { } export type HostToWorkerMessage = MessagePaint; + +export interface BlockLayoutTreeNode { + blockId: string; + type: string; + layout: BlockLayout; + children: BlockLayoutTreeNode[]; +} + +export interface ViewportLayoutTree { + roots: BlockLayoutTreeNode[]; + overallRect: BlockLayout['rect']; +} diff --git a/packages/frontend/core/src/blocksuite/extensions/turbo-renderer.ts b/packages/frontend/core/src/blocksuite/extensions/turbo-renderer.ts index 79223e800..48b5eb8dd 100644 --- a/packages/frontend/core/src/blocksuite/extensions/turbo-renderer.ts +++ b/packages/frontend/core/src/blocksuite/extensions/turbo-renderer.ts @@ -7,7 +7,7 @@ import { } from '@blocksuite/affine/gfx/turbo-renderer'; function createPainterWorker() { - const worker = new Worker(getWorkerUrl('turbo-painter-entry.worker.js')); + const worker = new Worker(getWorkerUrl('turbo-painter.worker.js')); return worker; }