Accepts .shx / .ttf / .otf / .woff. Cached entries show [cached] in the lists.
-
Lazy Font Loading skips preload and redraws on fontLoaded. Use Release Fonts, then Render to compare.
+
Lazy Font Loading skips preload. Unchecked Await Fonts redraws on fontLoaded; checked waits for fonts before the first draw. Use Release Fonts, then Render to compare.
diff --git a/packages/example/src/exampleFontManager.ts b/packages/example/src/exampleFontManager.ts
index 2100a0d..beed0a2 100644
--- a/packages/example/src/exampleFontManager.ts
+++ b/packages/example/src/exampleFontManager.ts
@@ -62,6 +62,14 @@ export class ExampleFontManager {
return FontManager.instance.lazyFontLoading
}
+ /**
+ * @returns Whether {@link FontManager.awaitFontsBeforeDraw} is currently
+ * enabled.
+ */
+ isAwaitFontsBeforeDraw(): boolean {
+ return FontManager.instance.awaitFontsBeforeDraw
+ }
+
/**
* Mirrors the UI checkbox onto {@link FontManager.lazyFontLoading} and any
* existing worker pool.
@@ -72,6 +80,16 @@ export class ExampleFontManager {
await this.unifiedRenderer.setLazyFontLoading(enabled)
}
+ /**
+ * Mirrors the UI checkbox onto {@link FontManager.awaitFontsBeforeDraw} and
+ * any existing worker pool.
+ *
+ * @param enabled - When true with lazy loading, draw waits for referenced fonts.
+ */
+ async setAwaitFontsBeforeDraw(enabled: boolean): Promise {
+ await this.unifiedRenderer.setAwaitFontsBeforeDraw(enabled)
+ }
+
/**
* Fonts that non-lazy mode should preload for the active preset and selects.
*/
diff --git a/packages/example/src/main.ts b/packages/example/src/main.ts
index 809cb78..595cd79 100644
--- a/packages/example/src/main.ts
+++ b/packages/example/src/main.ts
@@ -122,6 +122,11 @@ class MTextRendererExample {
private readonly defaultFontsPresetSelect: HTMLSelectElement
/** `#lazy-font-loading` — toggles {@link FontManager.lazyFontLoading}. */
private readonly lazyFontLoadingCheckbox: HTMLInputElement
+ /**
+ * `#await-fonts-before-draw` — toggles {@link FontManager.awaitFontsBeforeDraw}
+ * (only meaningful when lazy font loading is on).
+ */
+ private readonly awaitFontsBeforeDrawCheckbox: HTMLInputElement
/** DXF layer name passed in {@link getColorSettings} for ByLayer color resolution. */
private readonly defaultLayerName = '0'
@@ -211,6 +216,9 @@ class MTextRendererExample {
this.lazyFontLoadingCheckbox = document.getElementById(
'lazy-font-loading'
) as HTMLInputElement
+ this.awaitFontsBeforeDrawCheckbox = document.getElementById(
+ 'await-fonts-before-draw'
+ ) as HTMLInputElement
this.fontManager = new ExampleFontManager(
this.unifiedRenderer,
this.statusDiv,
@@ -224,6 +232,11 @@ class MTextRendererExample {
void this.fontManager.setLazyFontLoading(
this.lazyFontLoadingCheckbox.checked
)
+ this.syncAwaitFontsBeforeDrawCheckbox()
+ void this.fontManager.setAwaitFontsBeforeDraw(
+ this.lazyFontLoadingCheckbox.checked &&
+ this.awaitFontsBeforeDrawCheckbox.checked
+ )
FontManager.instance.events.fontLoaded.addEventListener(payload => {
this.onLazyFontLoaded(payload.fontName)
})
@@ -411,6 +424,12 @@ class MTextRendererExample {
await this.applyLazyFontLoadingMode(this.lazyFontLoadingCheckbox.checked)
})
+ this.awaitFontsBeforeDrawCheckbox.addEventListener('change', async () => {
+ await this.applyAwaitFontsBeforeDrawMode(
+ this.awaitFontsBeforeDrawCheckbox.checked
+ )
+ })
+
document.querySelectorAll('.example-btn').forEach(button => {
button.addEventListener('click', async () => {
const exampleType = (button as HTMLElement).dataset
@@ -523,12 +542,18 @@ class MTextRendererExample {
*/
private async applyLazyFontLoadingMode(enabled: boolean): Promise {
await this.fontManager.setLazyFontLoading(enabled)
+ this.syncAwaitFontsBeforeDrawCheckbox()
+ await this.fontManager.setAwaitFontsBeforeDraw(
+ enabled && this.awaitFontsBeforeDrawCheckbox.checked
+ )
if (enabled) {
FontManager.instance.release()
this.unifiedRenderer.terminateWorkers()
await this.fontManager.applyDefaultFontsPreset()
- this.statusDiv.textContent =
- 'Lazy font loading ON — fonts released; next render loads on demand'
+ const awaitFonts = this.awaitFontsBeforeDrawCheckbox.checked
+ this.statusDiv.textContent = awaitFonts
+ ? 'Lazy font loading ON + await — next render waits for fonts, then draws once'
+ : 'Lazy font loading ON — fonts released; next render loads on demand'
this.statusDiv.style.color = '#0f0'
} else {
await this.fontManager.applyDefaultFontsPreset()
@@ -540,6 +565,32 @@ class MTextRendererExample {
await this.renderCurrentContent()
}
+ /**
+ * Enables/disables the Await Fonts checkbox to match Lazy Font Loading, and
+ * keeps {@link FontManager.awaitFontsBeforeDraw} in sync.
+ */
+ private syncAwaitFontsBeforeDrawCheckbox(): void {
+ const lazy = this.lazyFontLoadingCheckbox.checked
+ this.awaitFontsBeforeDrawCheckbox.disabled = !lazy
+ }
+
+ /**
+ * Applies the Await Fonts Before Draw checkbox when lazy loading is enabled.
+ */
+ private async applyAwaitFontsBeforeDrawMode(enabled: boolean): Promise {
+ if (!this.lazyFontLoadingCheckbox.checked) {
+ this.syncAwaitFontsBeforeDrawCheckbox()
+ return
+ }
+ await this.fontManager.setAwaitFontsBeforeDraw(enabled)
+ this.statusDiv.textContent = enabled
+ ? 'Await fonts ON — render waits for download/load, then draws once'
+ : 'Await fonts OFF — render draws with fallbacks, then redraws on fontLoaded'
+ this.statusDiv.style.color = '#0f0'
+ this.beginUserRender()
+ await this.renderCurrentContent()
+ }
+
/**
* Handles {@link FontManager.events.fontLoaded} by scheduling a debounced redraw
* so glyph fallbacks are replaced once background loads finish.
@@ -548,6 +599,10 @@ class MTextRendererExample {
if (!this.fontManager.isLazyFontLoading()) {
return
}
+ // Draw already waited for referenced fonts — no progressive redraw needed.
+ if (this.fontManager.isAwaitFontsBeforeDraw()) {
+ return
+ }
if (!this.lazyFontsLoadedSinceRender.includes(fontName)) {
this.lazyFontsLoadedSinceRender.push(fontName)
}
@@ -1042,8 +1097,12 @@ class MTextRendererExample {
/** Appends lazy/non-lazy and thread mode details to a render status line. */
private formatRenderStatus(base: string, lazy: boolean): string {
- const mode = lazy ? 'lazy' : 'non-lazy'
+ const awaitFonts = this.fontManager.isAwaitFontsBeforeDraw()
+ const mode = lazy ? (awaitFonts ? 'lazy+await' : 'lazy') : 'non-lazy'
const thread = this.renderModeSelect.value
+ if (lazy && awaitFonts) {
+ return `${base} (${mode}, ${thread}) · waited for fonts before draw`
+ }
if (lazy && this.lazyFontsLoadedSinceRender.length > 0) {
return `${base} (${mode}, ${thread}) · loaded [${this.lazyFontsLoadedSinceRender.join(', ')}]`
}
diff --git a/packages/mtext-renderer/package.json b/packages/mtext-renderer/package.json
index 29a5f89..042d17e 100644
--- a/packages/mtext-renderer/package.json
+++ b/packages/mtext-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "@mlightcad/mtext-renderer",
- "version": "0.12.2",
+ "version": "0.12.3",
"description": "AutoCAD MText renderer based on Three.js",
"license": "MIT",
"author": "MLight Lee ",
diff --git a/packages/mtext-renderer/src/font/fontManager.ts b/packages/mtext-renderer/src/font/fontManager.ts
index 6d0c0ea..ab06016 100644
--- a/packages/mtext-renderer/src/font/fontManager.ts
+++ b/packages/mtext-renderer/src/font/fontManager.ts
@@ -76,9 +76,19 @@ export class FontManager {
/**
* When true (default), missing fonts are fetched/parsed in the background
* via {@link requestFont} instead of requiring an open-time preload.
- * Drawing continues with temporary fallbacks until {@link events.fontLoaded}.
+ * Drawing continues with temporary fallbacks until {@link events.fontLoaded}
+ * unless {@link awaitFontsBeforeDraw} (or a per-draw override) waits first.
*/
public lazyFontLoading = true
+ /**
+ * When true, {@link MText.asyncDraw} / {@link Shape.asyncDraw} wait for fonts
+ * referenced by the content and style to finish loading before building
+ * geometry. Useful with {@link lazyFontLoading} when callers prefer a single
+ * draw pass instead of redrawing on {@link events.fontLoaded}.
+ *
+ * Has no effect when {@link lazyFontLoading} is false (draw already awaits).
+ */
+ public awaitFontsBeforeDraw = false
/**
* Default fonts to use when a requested font is not found or lacks a glyph.
* Insertion order is preserved; earlier entries are tried first.
@@ -360,12 +370,14 @@ export class FontManager {
}
/**
- * Fire-and-forget {@link requestFont} for each name (deduped per name).
+ * Requests each font name via {@link requestFont} (deduped per name).
+ * Callers may ignore the returned promise for fire-and-forget loads, or
+ * await it when they need fonts before drawing.
*/
- requestFonts(fontNames: readonly string[]): void {
- for (const name of fontNames) {
- void this.requestFont(name)
- }
+ requestFonts(fontNames: readonly string[]): Promise {
+ return Promise.all(fontNames.map(name => this.requestFont(name))).then(
+ results => results.flat()
+ )
}
private normalizeFontName(fontName: string): string {
diff --git a/packages/mtext-renderer/src/renderer/mtext.ts b/packages/mtext-renderer/src/renderer/mtext.ts
index 4078708..641cffe 100644
--- a/packages/mtext-renderer/src/renderer/mtext.ts
+++ b/packages/mtext-renderer/src/renderer/mtext.ts
@@ -35,6 +35,21 @@ const tempPoint2 = /*@__PURE__*/ new THREE.Vector3()
const tempPoint3 = /*@__PURE__*/ new THREE.Vector3()
const AxisX = /*@__PURE__*/ new THREE.Vector3(1, 0, 0)
+/**
+ * Options for {@link MText.asyncDraw} / {@link Shape.asyncDraw}.
+ */
+export interface MTextDrawOptions {
+ /**
+ * Wait for fonts referenced by the content/style to finish loading before
+ * building geometry.
+ *
+ * Defaults to `true` when {@link FontManager.lazyFontLoading} is false, or
+ * when {@link FontManager.awaitFontsBeforeDraw} is true. Otherwise fonts are
+ * scheduled in the background and the first draw may use fallbacks.
+ */
+ awaitFonts?: boolean
+}
+
/**
* Axis-aligned rectangle (plus baseline) describing the **logical MText frame**
* used to compute attachment-point offsets in {@link MText.loadMText}.
@@ -182,13 +197,15 @@ export class MText extends THREE.Object3D {
}
/**
- * Draw the MText object. Schedules required fonts for background load and
- * builds the object graph immediately with current fallbacks.
+ * Draw the MText object.
*
- * Does not await downloads — callers that need glyphs from newly loaded fonts
- * should redraw after {@link FontManager.events.fontLoaded}.
+ * With {@link FontManager.lazyFontLoading} and without awaiting fonts, this
+ * schedules downloads in the background and builds geometry immediately with
+ * current fallbacks — redraw after {@link FontManager.events.fontLoaded} if
+ * you need the final faces. Pass `{ awaitFonts: true }` or set
+ * {@link FontManager.awaitFontsBeforeDraw} to wait for referenced fonts first.
*/
- async asyncDraw() {
+ async asyncDraw(options?: MTextDrawOptions) {
// Determine fonts used in the mtext string (without extensions)
const fonts = Array.from(MText.getFonts(this._mtextData.text || '', true))
@@ -208,8 +225,17 @@ export class MText extends THREE.Object3D {
}
}
if (fonts.length > 0) {
+ const awaitFonts =
+ options?.awaitFonts ??
+ (!this._fontManager.lazyFontLoading ||
+ this._fontManager.awaitFontsBeforeDraw)
+
if (this._fontManager.lazyFontLoading) {
- this._fontManager.requestFonts(fonts)
+ if (awaitFonts) {
+ await this._fontManager.requestFonts(fonts)
+ } else {
+ void this._fontManager.requestFonts(fonts)
+ }
} else {
await this._fontManager.loadFontsByNames(fonts)
}
diff --git a/packages/mtext-renderer/src/renderer/shape.ts b/packages/mtext-renderer/src/renderer/shape.ts
index 60c08e3..bfc56c5 100644
--- a/packages/mtext-renderer/src/renderer/shape.ts
+++ b/packages/mtext-renderer/src/renderer/shape.ts
@@ -1,7 +1,7 @@
import * as THREE from 'three'
import { FontManager } from '../font'
-import { MText } from './mtext'
+import { MText, MTextDrawOptions } from './mtext'
import { StyleManager } from './styleManager'
import {
ColorSettings,
@@ -62,7 +62,7 @@ export class Shape extends THREE.Object3D {
return { lines: [], chars: [] }
}
- async asyncDraw() {
+ async asyncDraw(options?: MTextDrawOptions) {
const fonts: string[] = []
if (!this._fontsInStyleLoaded) {
for (const key of ['font', 'bigFont', 'extendedFont'] as const) {
@@ -71,8 +71,17 @@ export class Shape extends THREE.Object3D {
}
}
if (fonts.length > 0) {
+ const awaitFonts =
+ options?.awaitFonts ??
+ (!this._fontManager.lazyFontLoading ||
+ this._fontManager.awaitFontsBeforeDraw)
+
if (this._fontManager.lazyFontLoading) {
- this._fontManager.requestFonts(fonts)
+ if (awaitFonts) {
+ await this._fontManager.requestFonts(fonts)
+ } else {
+ void this._fontManager.requestFonts(fonts)
+ }
} else {
await this._fontManager.loadFontsByNames(fonts)
}
diff --git a/packages/mtext-renderer/src/worker/mainThreadRenderer.ts b/packages/mtext-renderer/src/worker/mainThreadRenderer.ts
index 5e789c7..5842049 100644
--- a/packages/mtext-renderer/src/worker/mainThreadRenderer.ts
+++ b/packages/mtext-renderer/src/worker/mainThreadRenderer.ts
@@ -52,7 +52,9 @@ export class MainThreadRenderer implements MTextBaseRenderer {
/**
* Render MText directly in the main thread asynchronously. Fonts referenced by
* the text/style are scheduled via {@link FontManager.requestFonts} when
- * {@link FontManager.lazyFontLoading} is enabled; otherwise they are awaited.
+ * {@link FontManager.lazyFontLoading} is enabled (unless
+ * {@link FontManager.awaitFontsBeforeDraw} waits for them first); otherwise
+ * they are awaited.
*/
async asyncRenderMText(
mtextContent: MTextData,
diff --git a/packages/mtext-renderer/src/worker/mtextWorker.ts b/packages/mtext-renderer/src/worker/mtextWorker.ts
index 149b6df..7b2eddf 100644
--- a/packages/mtext-renderer/src/worker/mtextWorker.ts
+++ b/packages/mtext-renderer/src/worker/mtextWorker.ts
@@ -22,6 +22,7 @@ interface WorkerMessage {
| 'loadFonts'
| 'setDefaultFonts'
| 'setLazyFontLoading'
+ | 'setAwaitFontsBeforeDraw'
| 'setFontUrl'
| 'getAvailableFonts'
| 'getMemoryStats'
@@ -43,6 +44,7 @@ interface WorkerResponse {
| 'loadFonts'
| 'setDefaultFonts'
| 'setLazyFontLoading'
+ | 'setAwaitFontsBeforeDraw'
| 'setFontUrl'
| 'getAvailableFonts'
| 'getMemoryStats'
@@ -162,6 +164,21 @@ self.addEventListener('message', async (event: MessageEvent) => {
break
}
+ case 'setAwaitFontsBeforeDraw': {
+ if (!data) {
+ throw new Error('Missing data for setAwaitFontsBeforeDraw message')
+ }
+ const { enabled } = data as { enabled: boolean }
+ fontManager.awaitFontsBeforeDraw = enabled
+ self.postMessage({
+ type: 'setAwaitFontsBeforeDraw',
+ id,
+ success: true,
+ data: { enabled: fontManager.awaitFontsBeforeDraw }
+ } as WorkerResponse)
+ break
+ }
+
case 'setFontUrl': {
if (!data) throw new Error('Missing data for setFontUrl message')
const { url } = data as { url: string }
diff --git a/packages/mtext-renderer/src/worker/unifiedRenderer.ts b/packages/mtext-renderer/src/worker/unifiedRenderer.ts
index a716574..1fe1f5a 100644
--- a/packages/mtext-renderer/src/worker/unifiedRenderer.ts
+++ b/packages/mtext-renderer/src/worker/unifiedRenderer.ts
@@ -30,6 +30,8 @@ export class UnifiedRenderer {
private webWorkerConfigured = false
/** Last lazyFontLoading value pushed to the worker pool, if any. */
private workerLazyFontLoading: boolean | null = null
+ /** Last awaitFontsBeforeDraw value pushed to the worker pool, if any. */
+ private workerAwaitFontsBeforeDraw: boolean | null = null
/**
* Constructor
*
@@ -73,6 +75,11 @@ export class UnifiedRenderer {
await renderer.setLazyFontLoading(lazy)
this.workerLazyFontLoading = lazy
}
+ const awaitFonts = FontManager.instance.awaitFontsBeforeDraw
+ if (this.workerAwaitFontsBeforeDraw !== awaitFonts) {
+ await renderer.setAwaitFontsBeforeDraw(awaitFonts)
+ this.workerAwaitFontsBeforeDraw = awaitFonts
+ }
return renderer
}
@@ -217,6 +224,18 @@ export class UnifiedRenderer {
}
}
+ /**
+ * Mirrors {@link FontManager.awaitFontsBeforeDraw} onto the main thread and
+ * any existing worker pool.
+ */
+ async setAwaitFontsBeforeDraw(enabled: boolean): Promise {
+ FontManager.instance.awaitFontsBeforeDraw = enabled
+ if (this.webWorkerRenderer) {
+ await this.webWorkerRenderer.setAwaitFontsBeforeDraw(enabled)
+ this.workerAwaitFontsBeforeDraw = enabled
+ }
+ }
+
/**
* Returns font names for a predefined default-font preset.
*/
diff --git a/packages/mtext-renderer/src/worker/webWorkerRenderer.ts b/packages/mtext-renderer/src/worker/webWorkerRenderer.ts
index 72cd3a5..d33b7e8 100644
--- a/packages/mtext-renderer/src/worker/webWorkerRenderer.ts
+++ b/packages/mtext-renderer/src/worker/webWorkerRenderer.ts
@@ -104,11 +104,19 @@ type SetLazyFontLoadingMessage = WorkerMessageBase<
}
>
+type SetAwaitFontsBeforeDrawMessage = WorkerMessageBase<
+ 'setAwaitFontsBeforeDraw',
+ {
+ enabled: boolean
+ }
+>
+
type WorkerMessageTyped =
| RenderMessage
| LoadFontsMessage
| SetDefaultFontsMessage
| SetLazyFontLoadingMessage
+ | SetAwaitFontsBeforeDrawMessage
| SetFontUrlMessage
| GetAvailableFontsMessage
| GetMemoryStatsMessage
@@ -154,6 +162,13 @@ type SetLazyFontLoadingResponse = WorkerResponseBase<
}
>
+type SetAwaitFontsBeforeDrawResponse = WorkerResponseBase<
+ 'setAwaitFontsBeforeDraw',
+ {
+ enabled: boolean
+ }
+>
+
/** Push notification from a worker when a font finishes lazy-loading. */
type FontLoadedNotification = WorkerResponseBase<
'fontLoaded',
@@ -167,6 +182,7 @@ type WorkerResponseTyped =
| LoadFontsResponse
| SetDefaultFontsResponse
| SetLazyFontLoadingResponse
+ | SetAwaitFontsBeforeDrawResponse
| SetFontUrlResponse
| GetAvailableFontsResponse
| GetMemoryStatsResponse
@@ -587,6 +603,20 @@ export class WebWorkerRenderer implements MTextBaseRenderer {
})
}
+ /**
+ * Mirrors {@link FontManager.awaitFontsBeforeDraw} into every worker isolate.
+ */
+ async setAwaitFontsBeforeDraw(enabled: boolean): Promise {
+ FontManager.instance.awaitFontsBeforeDraw = enabled
+ await this.sendMessageToAllWorkers<
+ SetAwaitFontsBeforeDrawMessage,
+ SetAwaitFontsBeforeDrawResponse
+ >({
+ type: 'setAwaitFontsBeforeDraw',
+ data: { enabled }
+ })
+ }
+
/**
* Render MText in one worker and return serialized data asynchronously.
*/
diff --git a/packages/mtext-renderer/test/worker/render-remote-font-loading.test.ts b/packages/mtext-renderer/test/worker/render-remote-font-loading.test.ts
index 6671da7..524ed46 100644
--- a/packages/mtext-renderer/test/worker/render-remote-font-loading.test.ts
+++ b/packages/mtext-renderer/test/worker/render-remote-font-loading.test.ts
@@ -44,7 +44,10 @@ class MockWorker {
} as MessageEvent)
return
}
- if (type === 'setLazyFontLoading') {
+ if (
+ type === 'setLazyFontLoading' ||
+ type === 'setAwaitFontsBeforeDraw'
+ ) {
this.onmessage?.({
data: {
id,
@@ -128,6 +131,7 @@ describe('render remote font loading', () => {
beforeEach(() => {
FontManager.instance.release()
FontManager.instance.lazyFontLoading = true
+ FontManager.instance.awaitFontsBeforeDraw = false
FontManager.instance.defaultFonts = new Set(['simkai'])
FontManager.instance.symbolFonts = new Set(['amgdt'])
loadFontsByNames = vi
@@ -139,6 +143,7 @@ describe('render remote font loading', () => {
afterEach(() => {
loadFontsByNames.mockRestore()
FontManager.instance.lazyFontLoading = true
+ FontManager.instance.awaitFontsBeforeDraw = false
vi.unstubAllGlobals()
vi.stubGlobal('Worker', MockWorker)
})
@@ -200,6 +205,78 @@ describe('render remote font loading', () => {
requestFonts.mockRestore()
})
+ it('MText.asyncDraw awaits requestFonts when awaitFontsBeforeDraw is true', async () => {
+ FontManager.instance.awaitFontsBeforeDraw = true
+ const styleManager = new DefaultStyleManager()
+ let releaseFonts!: () => void
+ const fontsReady = new Promise(resolve => {
+ releaseFonts = resolve
+ })
+ const requestFonts = vi
+ .spyOn(FontManager.instance, 'requestFonts')
+ .mockImplementation(async () => {
+ await fontsReady
+ return []
+ })
+ const mtext = new MText(
+ minimalMTextData,
+ minimalTextStyle,
+ styleManager,
+ FontManager.instance,
+ createDefaultColorSettings()
+ )
+
+ let drawSettled = false
+ const drawPromise = mtext.asyncDraw().then(() => {
+ drawSettled = true
+ })
+
+ await Promise.resolve()
+ expect(drawSettled).toBe(false)
+ expect(requestFonts).toHaveBeenCalledWith(
+ expect.arrayContaining(['arial', 'txt', 'hztxt'])
+ )
+
+ releaseFonts()
+ await drawPromise
+ expect(drawSettled).toBe(true)
+ requestFonts.mockRestore()
+ })
+
+ it('MText.asyncDraw awaits fonts when options.awaitFonts is true', async () => {
+ const styleManager = new DefaultStyleManager()
+ let releaseFonts!: () => void
+ const fontsReady = new Promise(resolve => {
+ releaseFonts = resolve
+ })
+ const requestFonts = vi
+ .spyOn(FontManager.instance, 'requestFonts')
+ .mockImplementation(async () => {
+ await fontsReady
+ return []
+ })
+ const mtext = new MText(
+ minimalMTextData,
+ minimalTextStyle,
+ styleManager,
+ FontManager.instance,
+ createDefaultColorSettings()
+ )
+
+ let drawSettled = false
+ const drawPromise = mtext.asyncDraw({ awaitFonts: true }).then(() => {
+ drawSettled = true
+ })
+
+ await Promise.resolve()
+ expect(drawSettled).toBe(false)
+
+ releaseFonts()
+ await drawPromise
+ expect(drawSettled).toBe(true)
+ requestFonts.mockRestore()
+ })
+
it('MText.asyncDraw still requests style fonts after an empty first draw', async () => {
const styleManager = new DefaultStyleManager()
const requestFonts = vi.spyOn(FontManager.instance, 'requestFonts')
@@ -459,6 +536,25 @@ describe('render remote font loading', () => {
renderer.destroy()
})
+ it('WebWorkerRenderer setAwaitFontsBeforeDraw mirrors flag to all workers', async () => {
+ const renderer = new WebWorkerRenderer({ poolSize: 2, timeOut: 5000 })
+
+ await renderer.setAwaitFontsBeforeDraw(true)
+
+ expect(FontManager.instance.awaitFontsBeforeDraw).toBe(true)
+ for (const worker of workerInstances) {
+ expect(worker.postMessage).toHaveBeenCalledWith(
+ expect.objectContaining({
+ type: 'setAwaitFontsBeforeDraw',
+ data: { enabled: true }
+ })
+ )
+ }
+
+ await renderer.setAwaitFontsBeforeDraw(false)
+ renderer.destroy()
+ })
+
it('WebWorkerRenderer loadFonts delegates font names to all workers', async () => {
const renderer = new WebWorkerRenderer({ poolSize: 2, timeOut: 5000 })