diff --git a/blocksuite/affine/blocks/block-paragraph/src/index.ts b/blocksuite/affine/blocks/block-paragraph/src/index.ts index 86bba19416..800f253ef9 100644 --- a/blocksuite/affine/blocks/block-paragraph/src/index.ts +++ b/blocksuite/affine/blocks/block-paragraph/src/index.ts @@ -4,4 +4,4 @@ export * from './paragraph-block.js'; export * from './paragraph-service.js'; export * from './paragraph-spec.js'; export * from './turbo/paragraph-layout-provider.js'; -export * from './turbo/paragraph-painter-config.js'; +export * from './turbo/paragraph-painter.worker.js'; diff --git a/blocksuite/affine/blocks/block-paragraph/src/turbo/paragraph-painter-config.ts b/blocksuite/affine/blocks/block-paragraph/src/turbo/paragraph-painter-config.ts deleted file mode 100644 index 9e2bd43c75..0000000000 --- a/blocksuite/affine/blocks/block-paragraph/src/turbo/paragraph-painter-config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { BlockPainterConfigIdentifier } from '@blocksuite/affine-gfx-turbo-renderer'; -import type { Container } from '@blocksuite/global/di'; -import { Extension } from '@blocksuite/store'; - -export class ParagraphPaintConfigExtension extends Extension { - static override setup(di: Container) { - const config = { - type: 'affine:paragraph', - path: new URL( - '@blocksuite/affine-block-paragraph/turbo-painter', - import.meta.url - ).href, - }; - di.addImpl(BlockPainterConfigIdentifier, config); - } -} diff --git a/blocksuite/affine/blocks/block-paragraph/src/turbo/paragraph-painter.worker.ts b/blocksuite/affine/blocks/block-paragraph/src/turbo/paragraph-painter.worker.ts index 3256b92043..4bed352a06 100644 --- a/blocksuite/affine/blocks/block-paragraph/src/turbo/paragraph-painter.worker.ts +++ b/blocksuite/affine/blocks/block-paragraph/src/turbo/paragraph-painter.worker.ts @@ -39,16 +39,23 @@ function isParagraphLayout(layout: BlockLayout): layout is ParagraphLayout { return layout.type === 'affine:paragraph'; } -export default class ParagraphLayoutPainter implements BlockLayoutPainter { - static readonly font = new FontFace( - 'Inter', - `url(https://fonts.gstatic.com/s/inter/v18/UcCo3FwrK3iLTcviYwYZ8UA3.woff2)` - ); +export class ParagraphLayoutPainter implements BlockLayoutPainter { + private static readonly supportFontFace = + typeof FontFace !== 'undefined' && + typeof self !== 'undefined' && + 'fonts' in self; - static fontLoaded = false; + static readonly font = ParagraphLayoutPainter.supportFontFace + ? new FontFace( + 'Inter', + `url(https://fonts.gstatic.com/s/inter/v18/UcCo3FwrK3iLTcviYwYZ8UA3.woff2)` + ) + : null; + + static fontLoaded = !ParagraphLayoutPainter.supportFontFace; static { - if (typeof self !== 'undefined' && 'fonts' in self) { + if (ParagraphLayoutPainter.supportFontFace && ParagraphLayoutPainter.font) { // @ts-expect-error worker fonts API self.fonts.add(ParagraphLayoutPainter.font); diff --git a/blocksuite/affine/gfx/turbo-renderer/src/index.ts b/blocksuite/affine/gfx/turbo-renderer/src/index.ts index 2d5533a045..5d088a41de 100644 --- a/blocksuite/affine/gfx/turbo-renderer/src/index.ts +++ b/blocksuite/affine/gfx/turbo-renderer/src/index.ts @@ -1,4 +1,5 @@ export * from './layout/block-layout-provider'; +export * from './painter/painter.worker'; export * from './text-utils'; export * from './turbo-renderer'; export * from './types'; 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 b26daaee21..f3a8cd18bd 100644 --- a/blocksuite/affine/gfx/turbo-renderer/src/painter/painter.worker.ts +++ b/blocksuite/affine/gfx/turbo-renderer/src/painter/painter.worker.ts @@ -17,12 +17,19 @@ class BlockPainterRegistry { } } -class ViewportLayoutPainter { +export class ViewportLayoutPainter { private readonly canvas: OffscreenCanvas = new OffscreenCanvas(0, 0); private ctx: OffscreenCanvasRenderingContext2D | null = null; private zoom = 1; public readonly registry = new BlockPainterRegistry(); + constructor(painters: Record) { + Object.entries(painters).forEach(([type, painter]) => { + this.registry.register(type, painter); + }); + self.onmessage = this.handler; + } + setSize(layoutRectW: number, layoutRectH: number, dpr: number, zoom: number) { const width = layoutRectW * dpr * zoom; const height = layoutRectH * dpr * zoom; @@ -66,26 +73,16 @@ class ViewportLayoutPainter { }; self.postMessage(message, { transfer: [bitmap] }); } + + handler = async (e: MessageEvent) => { + const { type, data } = e.data; + switch (type) { + case 'paintLayout': { + const { layout, width, height, dpr, zoom, version } = data; + this.setSize(width, height, dpr, zoom); + this.paint(layout, version); + break; + } + } + }; } - -const painter = new ViewportLayoutPainter(); - -self.onmessage = async (e: MessageEvent) => { - const { type, data } = e.data; - - switch (type) { - case 'paintLayout': { - const { layout, width, height, dpr, zoom, version } = data; - painter.setSize(width, height, dpr, zoom); - painter.paint(layout, version); - break; - } - case 'registerPainter': { - const { painterConfigs } = data; - painterConfigs.forEach(async ({ type, path }) => { - painter.registry.register(type, new (await import(path)).default()); - }); - break; - } - } -}; diff --git a/blocksuite/affine/gfx/turbo-renderer/src/turbo-renderer.ts b/blocksuite/affine/gfx/turbo-renderer/src/turbo-renderer.ts index 7f043c4b7c..9e8ea357d4 100644 --- a/blocksuite/affine/gfx/turbo-renderer/src/turbo-renderer.ts +++ b/blocksuite/affine/gfx/turbo-renderer/src/turbo-renderer.ts @@ -6,7 +6,6 @@ import { type GfxViewportElement, } from '@blocksuite/block-std/gfx'; import type { Container } from '@blocksuite/global/di'; -import { createIdentifier } from '@blocksuite/global/di'; import { DisposableGroup } from '@blocksuite/global/disposable'; import debounce from 'lodash-es/debounce'; @@ -18,9 +17,7 @@ import { syncCanvasSize, } from './renderer-utils'; import type { - BlockPainterConfig, MessagePaint, - MessageRegisterPainter, RendererOptions, RenderingState, TurboRendererConfig, @@ -29,16 +26,12 @@ import type { } from './types'; const debug = false; // Toggle for debug logs -const workerUrl = new URL('./painter/painter.worker.ts', import.meta.url); const defaultOptions: RendererOptions = { zoomThreshold: 1, // With high enough zoom, fallback to DOM rendering debounceTime: 1000, // During this period, fallback to DOM }; -export const BlockPainterConfigIdentifier = - createIdentifier('block-painter-config'); - export const TurboRendererConfigFactory = ConfigExtensionFactory('viewport-turbo-renderer'); @@ -47,13 +40,24 @@ export class ViewportTurboRendererExtension extends GfxExtension { public state: RenderingState = 'inactive'; public readonly canvas: HTMLCanvasElement = document.createElement('canvas'); - private readonly worker: Worker = new Worker(workerUrl, { type: 'module' }); + private readonly worker: Worker; private readonly disposables = new DisposableGroup(); private layoutCacheData: ViewportLayout | null = null; private layoutVersion = 0; private bitmap: ImageBitmap | null = null; private viewportElement: GfxViewportElement | null = null; + constructor(gfx: GfxController) { + super(gfx); + + const id = TurboRendererConfigFactory.identifier; + const config = this.std.getOptional(id); + if (!config) { + throw new Error('TurboRendererConfig not found'); + } + this.worker = config.painterWorkerEntry(); + } + static override extendGfx(gfx: GfxController) { Object.defineProperty(gfx, 'turboRenderer', { get() { @@ -75,13 +79,6 @@ export class ViewportTurboRendererExtension extends GfxExtension { }; } - get painterConfigs() { - const painterConfigMap = this.std.provider.getAll( - BlockPainterConfigIdentifier - ); - return Array.from(painterConfigMap.values()); - } - override mounted() { const mountPoint = document.querySelector('.affine-edgeless-viewport'); if (mountPoint) { @@ -123,13 +120,6 @@ export class ViewportTurboRendererExtension extends GfxExtension { this.disposables.add( this.std.store.slots.blockUpdated.subscribe(() => this.invalidate()) ); - - const painterConfigs = this.painterConfigs; - const message: MessageRegisterPainter = { - type: 'registerPainter', - data: { painterConfigs }, - }; - this.worker.postMessage(message); } override unmounted() { diff --git a/blocksuite/affine/gfx/turbo-renderer/src/types.ts b/blocksuite/affine/gfx/turbo-renderer/src/types.ts index 15c873897a..146efc3e54 100644 --- a/blocksuite/affine/gfx/turbo-renderer/src/types.ts +++ b/blocksuite/affine/gfx/turbo-renderer/src/types.ts @@ -83,20 +83,9 @@ export interface RendererOptions { debounceTime: number; } -export interface BlockPainterConfig { - type: string; - path: string; -} - export interface TurboRendererConfig { options?: Partial; + painterWorkerEntry: () => Worker; } -export type MessageRegisterPainter = { - type: 'registerPainter'; - data: { - painterConfigs: BlockPainterConfig[]; - }; -}; - -export type HostToWorkerMessage = MessagePaint | MessageRegisterPainter; +export type HostToWorkerMessage = MessagePaint; diff --git a/blocksuite/integration-test/src/__tests__/edgeless/viewport-renderer.spec.ts b/blocksuite/integration-test/src/__tests__/edgeless/viewport-renderer.spec.ts index 2d3d35e6f7..52613603b6 100644 --- a/blocksuite/integration-test/src/__tests__/edgeless/viewport-renderer.spec.ts +++ b/blocksuite/integration-test/src/__tests__/edgeless/viewport-renderer.spec.ts @@ -1,13 +1,21 @@ -import { ViewportTurboRendererExtension } from '@blocksuite/affine-gfx-turbo-renderer'; +import { ParagraphLayoutHandlerExtension } from '@blocksuite/affine/blocks/paragraph'; +import { + TurboRendererConfigFactory, + ViewportTurboRendererExtension, +} from '@blocksuite/affine-gfx-turbo-renderer'; import { beforeEach, describe, expect, test } from 'vitest'; import { wait } from '../utils/common.js'; import { addSampleNotes } from '../utils/doc-generator.js'; -import { setupEditor } from '../utils/setup.js'; +import { createPainterWorker, setupEditor } from '../utils/setup.js'; describe('viewport turbo renderer', () => { beforeEach(async () => { const cleanup = await setupEditor('edgeless', [ + ParagraphLayoutHandlerExtension, + TurboRendererConfigFactory({ + painterWorkerEntry: createPainterWorker, + }), ViewportTurboRendererExtension, ]); return cleanup; diff --git a/blocksuite/integration-test/src/__tests__/utils/renderer-entry.ts b/blocksuite/integration-test/src/__tests__/utils/renderer-entry.ts index 9fe51b3719..182cc55be2 100644 --- a/blocksuite/integration-test/src/__tests__/utils/renderer-entry.ts +++ b/blocksuite/integration-test/src/__tests__/utils/renderer-entry.ts @@ -1,7 +1,4 @@ -import { - ParagraphLayoutHandlerExtension, - ParagraphPaintConfigExtension, -} from '@blocksuite/affine/blocks/paragraph'; +import { ParagraphLayoutHandlerExtension } from '@blocksuite/affine/blocks/paragraph'; import { TurboRendererConfigFactory, ViewportTurboRendererExtension, @@ -9,17 +6,13 @@ import { } from '@blocksuite/affine/gfx/turbo-renderer'; import { addSampleNotes } from './doc-generator.js'; -import { setupEditor } from './setup.js'; +import { createPainterWorker, setupEditor } from './setup.js'; async function init() { setupEditor('edgeless', [ ParagraphLayoutHandlerExtension, - ParagraphPaintConfigExtension, TurboRendererConfigFactory({ - options: { - zoomThreshold: 1, - debounceTime: 1000, - }, + painterWorkerEntry: createPainterWorker, }), ViewportTurboRendererExtension, ]); diff --git a/blocksuite/integration-test/src/__tests__/utils/setup.ts b/blocksuite/integration-test/src/__tests__/utils/setup.ts index fac26f4c2b..3ab759dc68 100644 --- a/blocksuite/integration-test/src/__tests__/utils/setup.ts +++ b/blocksuite/integration-test/src/__tests__/utils/setup.ts @@ -99,6 +99,16 @@ async function createEditor( return app; } +export function createPainterWorker() { + const worker = new Worker( + new URL('./turbo-painter-entry.worker.ts', import.meta.url), + { + type: 'module', + } + ); + return worker; +} + export async function setupEditor( mode: DocMode = 'page', extensions: ExtensionType[] = [] diff --git a/blocksuite/integration-test/src/__tests__/utils/turbo-painter-entry.worker.ts b/blocksuite/integration-test/src/__tests__/utils/turbo-painter-entry.worker.ts new file mode 100644 index 0000000000..93dcba993d --- /dev/null +++ b/blocksuite/integration-test/src/__tests__/utils/turbo-painter-entry.worker.ts @@ -0,0 +1,6 @@ +import { ParagraphLayoutPainter } from '@blocksuite/affine-block-paragraph/turbo-painter'; +import { ViewportLayoutPainter } from '@blocksuite/affine-gfx-turbo-renderer/painter'; + +new ViewportLayoutPainter({ + 'affine:paragraph': new ParagraphLayoutPainter(), +}); diff --git a/packages/frontend/core/src/blocksuite/extensions/turbo-painter-entry.worker.ts b/packages/frontend/core/src/blocksuite/extensions/turbo-painter-entry.worker.ts new file mode 100644 index 0000000000..f160f66087 --- /dev/null +++ b/packages/frontend/core/src/blocksuite/extensions/turbo-painter-entry.worker.ts @@ -0,0 +1,6 @@ +import { ParagraphLayoutPainter } from '@blocksuite/affine/blocks/paragraph'; +import { ViewportLayoutPainter } from '@blocksuite/affine/gfx/turbo-renderer'; + +new ViewportLayoutPainter({ + 'affine:paragraph': new ParagraphLayoutPainter(), +}); diff --git a/packages/frontend/core/src/blocksuite/extensions/turbo-renderer.ts b/packages/frontend/core/src/blocksuite/extensions/turbo-renderer.ts index 82dc789204..c8cc85805d 100644 --- a/packages/frontend/core/src/blocksuite/extensions/turbo-renderer.ts +++ b/packages/frontend/core/src/blocksuite/extensions/turbo-renderer.ts @@ -1,21 +1,31 @@ -import { - ParagraphLayoutHandlerExtension, - ParagraphPaintConfigExtension, -} from '@blocksuite/affine/blocks/paragraph'; +import { ParagraphLayoutHandlerExtension } from '@blocksuite/affine/blocks/paragraph'; import { TurboRendererConfigFactory, ViewportTurboRendererExtension, } from '@blocksuite/affine/gfx/turbo-renderer'; +function createPainterWorker() { + const worker = new Worker( + /* webpackChunkName: "turbo-painter-entry" */ new URL( + './turbo-painter-entry.worker.ts', + import.meta.url + ), + { + type: 'module', + } + ); + return worker; +} + export function patchTurboRendererExtension() { return [ ParagraphLayoutHandlerExtension, - ParagraphPaintConfigExtension, TurboRendererConfigFactory({ options: { zoomThreshold: 1, debounceTime: 1000, }, + painterWorkerEntry: createPainterWorker, }), ViewportTurboRendererExtension, ];