@mlightcad/mtext-renderer 0.12.1 → 0.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,6 +48,22 @@ export declare class FontManager {
48
48
  missedFonts: Record<string, number>;
49
49
  /** Flag to enable/disable font caching */
50
50
  enableFontCache: boolean;
51
+ /**
52
+ * When true (default), missing fonts are fetched/parsed in the background
53
+ * via {@link requestFont} instead of requiring an open-time preload.
54
+ * Drawing continues with temporary fallbacks until {@link events.fontLoaded}
55
+ * unless {@link awaitFontsBeforeDraw} (or a per-draw override) waits first.
56
+ */
57
+ lazyFontLoading: boolean;
58
+ /**
59
+ * When true, {@link MText.asyncDraw} / {@link Shape.asyncDraw} wait for fonts
60
+ * referenced by the content and style to finish loading before building
61
+ * geometry. Useful with {@link lazyFontLoading} when callers prefer a single
62
+ * draw pass instead of redrawing on {@link events.fontLoaded}.
63
+ *
64
+ * Has no effect when {@link lazyFontLoading} is false (draw already awaits).
65
+ */
66
+ awaitFontsBeforeDraw: boolean;
51
67
  /**
52
68
  * Default fonts to use when a requested font is not found or lacks a glyph.
53
69
  * Insertion order is preserved; earlier entries are tried first.
@@ -66,6 +82,18 @@ export declare class FontManager {
66
82
  /** Event triggered when a font is successfully loaded */
67
83
  fontLoaded: EventManager<FontManagerEventArgs>;
68
84
  };
85
+ /** In-flight {@link requestFont} promises keyed by normalized font name. */
86
+ private fontRequestInFlight;
87
+ /**
88
+ * Fonts whose latest {@link requestFont} finished without registering the
89
+ * face. Prevents per-glyph retry storms until {@link release} clears state.
90
+ */
91
+ private fontRequestFailed;
92
+ /**
93
+ * Bumped by full {@link release} so in-flight loads that complete after a
94
+ * release do not re-register fonts into a cleared manager.
95
+ */
96
+ private loadEpoch;
69
97
  private constructor();
70
98
  /**
71
99
  * Gets the singleton instance of the FontManager
@@ -94,7 +122,7 @@ export declare class FontManager {
94
122
  * ```ts
95
123
  * FontManager.instance.setDefaultFonts('r12r14')
96
124
  * FontManager.instance.setDefaultFonts(['hztxt', 'simsun', 'gdt'])
97
- * FontManager.instance.setDefaultFonts('simkai')
125
+ * FontManager.instance.setDefaultFonts('simsun')
98
126
  * ```
99
127
  */
100
128
  setDefaultFonts(fonts: DefaultFontsPreset): void;
@@ -152,6 +180,21 @@ export declare class FontManager {
152
180
  * @returns Promise that resolves to an array of font load statuses
153
181
  */
154
182
  loadFontsByNames(names: string | readonly string[]): Promise<FontLoadStatus[]>;
183
+ /**
184
+ * Schedules a non-blocking load for a font that is not yet in memory.
185
+ *
186
+ * Concurrent callers for the same name share one in-flight promise.
187
+ * Already-loaded fonts resolve immediately. Safe to call from sync draw
188
+ * paths — do not await from the hot glyph loop.
189
+ */
190
+ requestFont(fontName: string): Promise<FontLoadStatus[]>;
191
+ /**
192
+ * Requests each font name via {@link requestFont} (deduped per name).
193
+ * Callers may ignore the returned promise for fire-and-forget loads, or
194
+ * await it when they need fonts before drawing.
195
+ */
196
+ requestFonts(fontNames: readonly string[]): Promise<FontLoadStatus[]>;
197
+ private normalizeFontName;
155
198
  /**
156
199
  * Parses a user-uploaded font file, registers it for rendering, and stores
157
200
  * it in IndexedDB when {@link enableFontCache} is true.
@@ -102,10 +102,35 @@ export declare class ShxFont extends BaseFont {
102
102
  * Clears layout/code caches and disposes retained shape geometries.
103
103
  */
104
104
  dispose(): void;
105
+ /**
106
+ * Sentinel returned by {@link getCode} when `char` has no representation
107
+ * in this BIGFONT's legacy encoding. Never a real SHX/BIGFONT code point
108
+ * (those are non-negative), so callers can distinguish "cannot encode"
109
+ * from "encodes to some rarely-used code".
110
+ */
111
+ private static readonly NOT_ENCODABLE;
105
112
  /**
106
113
  * Resolves the internal SHX character code for a given Unicode character.
114
+ *
115
+ * For BIGFONT fonts, `char` is converted through a legacy encoding (e.g.
116
+ * GBK) via `iconv-lite`. Characters outside that encoding's repertoire
117
+ * (math/symbol glyphs like the diameter sign, U+2205) are not rejected by
118
+ * `iconv.encode` — it silently substitutes a replacement byte (commonly
119
+ * ASCII `?`, 0x3F). Left unchecked, that byte resolves to the BIGFONT's
120
+ * own, perfectly valid `?` glyph, so `hasChar`/`getCharShape` report a
121
+ * false positive: the caller believes this font renders the character,
122
+ * when it actually renders an unrelated question mark. That masked the
123
+ * real GDT/symbol-font fallback for diameter dimension text stored as a
124
+ * literal U+2205 (mlightcad/cad-viewer#473) — the correct glyph exists in
125
+ * `amgdt.shx`, but the fallback chain in {@link FontManager} never got a
126
+ * chance because this font's bogus "yes" won first.
127
+ *
128
+ * A decode-of-the-encoded-bytes round trip catches this: encoding is lossy
129
+ * exactly when it can't recover the original character.
130
+ *
107
131
  * @param char - The input character.
108
- * @returns The internal SHX code used for lookup.
132
+ * @returns The internal SHX code used for lookup, or {@link NOT_ENCODABLE}
133
+ * when `char` cannot be represented in this font's encoding.
109
134
  */
110
135
  private getCode;
111
136
  }
@@ -2,6 +2,20 @@ import { FontManager } from '../font';
2
2
  import { StyleManager } from './styleManager';
3
3
  import { ColorSettings, MTextData, MTextLayout, ShapeData, TextStyle } from './types';
4
4
  import * as THREE from 'three';
5
+ /**
6
+ * Options for {@link MText.asyncDraw} / {@link Shape.asyncDraw}.
7
+ */
8
+ export interface MTextDrawOptions {
9
+ /**
10
+ * Wait for fonts referenced by the content/style to finish loading before
11
+ * building geometry.
12
+ *
13
+ * Defaults to `true` when {@link FontManager.lazyFontLoading} is false, or
14
+ * when {@link FontManager.awaitFontsBeforeDraw} is true. Otherwise fonts are
15
+ * scheduled in the background and the first draw may use fallbacks.
16
+ */
17
+ awaitFonts?: boolean;
18
+ }
5
19
  /**
6
20
  * Represents an AutoCAD MText object in Three.js.
7
21
  * This class extends THREE.Object3D to provide MText rendering capabilities,
@@ -60,9 +74,15 @@ export declare class MText extends THREE.Object3D {
60
74
  */
61
75
  dispose(): void;
62
76
  /**
63
- * Draw the MText object. This method loads required fonts on demand and builds the object graph.
77
+ * Draw the MText object.
78
+ *
79
+ * With {@link FontManager.lazyFontLoading} and without awaiting fonts, this
80
+ * schedules downloads in the background and builds geometry immediately with
81
+ * current fallbacks — redraw after {@link FontManager.events.fontLoaded} if
82
+ * you need the final faces. Pass `{ awaitFonts: true }` or set
83
+ * {@link FontManager.awaitFontsBeforeDraw} to wait for referenced fonts first.
64
84
  */
65
- asyncDraw(): Promise<void>;
85
+ asyncDraw(options?: MTextDrawOptions): Promise<void>;
66
86
  /**
67
87
  * Draw the MText object. This method assumes that fonts needed are loaded. If font needed
68
88
  * not found, the default font will be used.
@@ -1,4 +1,5 @@
1
1
  import { FontManager } from '../font';
2
+ import { MTextDrawOptions } from './mtext';
2
3
  import { StyleManager } from './styleManager';
3
4
  import { ColorSettings, MTextLayout, ShapeData, TextStyle } from './types';
4
5
  import * as THREE from 'three';
@@ -18,7 +19,7 @@ export declare class Shape extends THREE.Object3D {
18
19
  get styleManager(): StyleManager;
19
20
  get textStyle(): TextStyle;
20
21
  createLayoutData(): MTextLayout;
21
- asyncDraw(): Promise<void>;
22
+ asyncDraw(options?: MTextDrawOptions): Promise<void>;
22
23
  syncDraw(): void;
23
24
  private createPlacementData;
24
25
  private getFontName;
@@ -22,8 +22,11 @@ export declare class MainThreadRenderer implements MTextBaseRenderer {
22
22
  */
23
23
  setFontUrl(value: string): Promise<void>;
24
24
  /**
25
- * Render MText directly in the main thread asynchronously. It will ensure that default font
26
- * is loaded. And fonts needed in mtext are loaded on demand.
25
+ * Render MText directly in the main thread asynchronously. Fonts referenced by
26
+ * the text/style are scheduled via {@link FontManager.requestFonts} when
27
+ * {@link FontManager.lazyFontLoading} is enabled (unless
28
+ * {@link FontManager.awaitFontsBeforeDraw} waits for them first); otherwise
29
+ * they are awaited.
27
30
  */
28
31
  asyncRenderMText(mtextContent: MTextData, textStyle: TextStyle, colorSettings?: ColorSettings): Promise<MTextObject>;
29
32
  /**
@@ -15,6 +15,10 @@ export declare class UnifiedRenderer {
15
15
  private defaultMode;
16
16
  private workerConfig;
17
17
  private webWorkerConfigured;
18
+ /** Last lazyFontLoading value pushed to the worker pool, if any. */
19
+ private workerLazyFontLoading;
20
+ /** Last awaitFontsBeforeDraw value pushed to the worker pool, if any. */
21
+ private workerAwaitFontsBeforeDraw;
18
22
  /**
19
23
  * Constructor
20
24
  *
@@ -68,6 +72,16 @@ export declare class UnifiedRenderer {
68
72
  * Sets the default font fallback chain on the active renderer and workers.
69
73
  */
70
74
  setDefaultFonts(fonts: DefaultFontsPreset | string | readonly string[]): Promise<void>;
75
+ /**
76
+ * Mirrors {@link FontManager.lazyFontLoading} onto the main thread and any
77
+ * existing worker pool.
78
+ */
79
+ setLazyFontLoading(enabled: boolean): Promise<void>;
80
+ /**
81
+ * Mirrors {@link FontManager.awaitFontsBeforeDraw} onto the main thread and
82
+ * any existing worker pool.
83
+ */
84
+ setAwaitFontsBeforeDraw(enabled: boolean): Promise<void>;
71
85
  /**
72
86
  * Returns font names for a predefined default-font preset.
73
87
  */
@@ -140,6 +140,15 @@ export declare class WebWorkerRenderer implements MTextBaseRenderer {
140
140
  private readyPromise;
141
141
  private isInitialized;
142
142
  private defaultStyleManager;
143
+ /**
144
+ * Fonts known to be present in every worker after an explicit loadFonts or
145
+ * after a lazy fontLoaded was fan-out to the full pool.
146
+ */
147
+ private poolSyncedFonts;
148
+ /** In-flight pool-wide font syncs keyed by normalized font name. */
149
+ private poolFontSyncInFlight;
150
+ /** Fonts already forwarded as main-thread fontLoaded for this pool lifetime. */
151
+ private poolFontLoadedDispatched;
143
152
  constructor(config?: WebWorkerRendererConfig);
144
153
  /**
145
154
  * Used to manage materials used by texts
@@ -151,6 +160,11 @@ export declare class WebWorkerRenderer implements MTextBaseRenderer {
151
160
  * Handles messages coming from any worker.
152
161
  */
153
162
  private handleWorkerMessage;
163
+ /**
164
+ * Ensures every worker has `fontName`, then returns whether the main thread
165
+ * should emit {@link FontManager.events.fontLoaded} for this name.
166
+ */
167
+ private syncFontToWorkerPool;
154
168
  /**
155
169
  * Attaches message and error handlers to a worker.
156
170
  */
@@ -168,6 +182,14 @@ export declare class WebWorkerRenderer implements MTextBaseRenderer {
168
182
  * Syncs the default font fallback chain to all workers.
169
183
  */
170
184
  setDefaultFonts(fonts: readonly string[], symbolFonts: readonly string[]): Promise<void>;
185
+ /**
186
+ * Mirrors {@link FontManager.lazyFontLoading} into every worker isolate.
187
+ */
188
+ setLazyFontLoading(enabled: boolean): Promise<void>;
189
+ /**
190
+ * Mirrors {@link FontManager.awaitFontsBeforeDraw} into every worker isolate.
191
+ */
192
+ setAwaitFontsBeforeDraw(enabled: boolean): Promise<void>;
171
193
  /**
172
194
  * Render MText in one worker and return serialized data asynchronously.
173
195
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mlightcad/mtext-renderer",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
4
4
  "description": "AutoCAD MText renderer based on Three.js",
5
5
  "license": "MIT",
6
6
  "author": "MLight Lee <mlight.lee@outlook.com>",