@mlightcad/cad-simple-viewer 1.7.4 → 1.7.5

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.
Files changed (126) hide show
  1. package/README.md +5 -0
  2. package/dist/cad-simple-viewer.js +8578 -7149
  3. package/dist/cad-simple-viewer.umd.cjs +429 -85
  4. package/lib/app/AcApDocManager.d.ts +44 -1
  5. package/lib/app/AcApDocManager.d.ts.map +1 -1
  6. package/lib/app/AcApDocManager.js +126 -1
  7. package/lib/app/AcApDocManager.js.map +1 -1
  8. package/lib/app/AcApOpenDatabaseOptions.d.ts +27 -0
  9. package/lib/app/AcApOpenDatabaseOptions.d.ts.map +1 -1
  10. package/lib/app/AcApOpenFileDialog.d.ts +1 -1
  11. package/lib/app/AcApOpenFileDialog.d.ts.map +1 -1
  12. package/lib/app/AcApOpenFileDialog.js +22 -92
  13. package/lib/app/AcApOpenFileDialog.js.map +1 -1
  14. package/lib/app/AcApOpenFileProfiler.d.ts +14 -0
  15. package/lib/app/AcApOpenFileProfiler.d.ts.map +1 -1
  16. package/lib/app/AcApOpenFileProfiler.js +25 -3
  17. package/lib/app/AcApOpenFileProfiler.js.map +1 -1
  18. package/lib/app/dataSource/AcApDataSource.d.ts +97 -0
  19. package/lib/app/dataSource/AcApDataSource.d.ts.map +1 -0
  20. package/lib/app/dataSource/AcApDataSource.js +2 -0
  21. package/lib/app/dataSource/AcApDataSource.js.map +1 -0
  22. package/lib/app/dataSource/AcApDataSourceManager.d.ts +70 -0
  23. package/lib/app/dataSource/AcApDataSourceManager.d.ts.map +1 -0
  24. package/lib/app/dataSource/AcApDataSourceManager.js +84 -0
  25. package/lib/app/dataSource/AcApDataSourceManager.js.map +1 -0
  26. package/lib/app/dataSource/AcApLocalDataSource.d.ts +25 -0
  27. package/lib/app/dataSource/AcApLocalDataSource.d.ts.map +1 -0
  28. package/lib/app/dataSource/AcApLocalDataSource.js +153 -0
  29. package/lib/app/dataSource/AcApLocalDataSource.js.map +1 -0
  30. package/lib/app/dataSource/AcApUrlDataSource.d.ts +17 -0
  31. package/lib/app/dataSource/AcApUrlDataSource.d.ts.map +1 -0
  32. package/lib/app/dataSource/AcApUrlDataSource.js +214 -0
  33. package/lib/app/dataSource/AcApUrlDataSource.js.map +1 -0
  34. package/lib/app/dataSource/acapBuildDataSourceMenu.d.ts +42 -0
  35. package/lib/app/dataSource/acapBuildDataSourceMenu.d.ts.map +1 -0
  36. package/lib/app/dataSource/acapBuildDataSourceMenu.js +121 -0
  37. package/lib/app/dataSource/acapBuildDataSourceMenu.js.map +1 -0
  38. package/lib/app/dataSource/acapInvokeDataSourceMenuAction.d.ts +17 -0
  39. package/lib/app/dataSource/acapInvokeDataSourceMenuAction.d.ts.map +1 -0
  40. package/lib/app/dataSource/acapInvokeDataSourceMenuAction.js +74 -0
  41. package/lib/app/dataSource/acapInvokeDataSourceMenuAction.js.map +1 -0
  42. package/lib/app/dataSource/acapOpenCenteredPopup.d.ts +13 -0
  43. package/lib/app/dataSource/acapOpenCenteredPopup.d.ts.map +1 -0
  44. package/lib/app/dataSource/acapOpenCenteredPopup.js +35 -0
  45. package/lib/app/dataSource/acapOpenCenteredPopup.js.map +1 -0
  46. package/lib/app/dataSource/acapOpenDataSourceResult.d.ts +13 -0
  47. package/lib/app/dataSource/acapOpenDataSourceResult.d.ts.map +1 -0
  48. package/lib/app/dataSource/acapOpenDataSourceResult.js +90 -0
  49. package/lib/app/dataSource/acapOpenDataSourceResult.js.map +1 -0
  50. package/lib/app/dataSource/acapRunDataSourceMenuAction.d.ts +15 -0
  51. package/lib/app/dataSource/acapRunDataSourceMenuAction.d.ts.map +1 -0
  52. package/lib/app/dataSource/acapRunDataSourceMenuAction.js +74 -0
  53. package/lib/app/dataSource/acapRunDataSourceMenuAction.js.map +1 -0
  54. package/lib/app/dataSource/acapWithDataSourceBusy.d.ts +12 -0
  55. package/lib/app/dataSource/acapWithDataSourceBusy.d.ts.map +1 -0
  56. package/lib/app/dataSource/acapWithDataSourceBusy.js +88 -0
  57. package/lib/app/dataSource/acapWithDataSourceBusy.js.map +1 -0
  58. package/lib/app/dataSource/index.d.ts +11 -0
  59. package/lib/app/dataSource/index.d.ts.map +1 -0
  60. package/lib/app/dataSource/index.js +10 -0
  61. package/lib/app/dataSource/index.js.map +1 -0
  62. package/lib/app/index.d.ts +1 -0
  63. package/lib/app/index.d.ts.map +1 -1
  64. package/lib/app/index.js +1 -0
  65. package/lib/app/index.js.map +1 -1
  66. package/lib/editor/global/AcEdUiTheme.d.ts +10 -1
  67. package/lib/editor/global/AcEdUiTheme.d.ts.map +1 -1
  68. package/lib/editor/global/AcEdUiTheme.js +35 -2
  69. package/lib/editor/global/AcEdUiTheme.js.map +1 -1
  70. package/lib/editor/input/ui/AcEdCommandLine.d.ts.map +1 -1
  71. package/lib/editor/input/ui/AcEdCommandLine.js +7 -7
  72. package/lib/editor/input/ui/AcEdCommandLine.js.map +1 -1
  73. package/lib/i18n/ar/main.d.ts +26 -0
  74. package/lib/i18n/ar/main.d.ts.map +1 -1
  75. package/lib/i18n/ar/main.js +26 -0
  76. package/lib/i18n/ar/main.js.map +1 -1
  77. package/lib/i18n/cs/main.d.ts +26 -0
  78. package/lib/i18n/cs/main.d.ts.map +1 -1
  79. package/lib/i18n/cs/main.js +26 -0
  80. package/lib/i18n/cs/main.js.map +1 -1
  81. package/lib/i18n/en/main.d.ts +26 -0
  82. package/lib/i18n/en/main.d.ts.map +1 -1
  83. package/lib/i18n/en/main.js +26 -0
  84. package/lib/i18n/en/main.js.map +1 -1
  85. package/lib/i18n/tr/main.d.ts +26 -0
  86. package/lib/i18n/tr/main.d.ts.map +1 -1
  87. package/lib/i18n/tr/main.js +26 -0
  88. package/lib/i18n/tr/main.js.map +1 -1
  89. package/lib/i18n/zh/main.d.ts +26 -0
  90. package/lib/i18n/zh/main.d.ts.map +1 -1
  91. package/lib/i18n/zh/main.js +26 -0
  92. package/lib/i18n/zh/main.js.map +1 -1
  93. package/lib/ui/AcUiFileOpenPanel.d.ts +156 -0
  94. package/lib/ui/AcUiFileOpenPanel.d.ts.map +1 -0
  95. package/lib/ui/AcUiFileOpenPanel.js +695 -0
  96. package/lib/ui/AcUiFileOpenPanel.js.map +1 -0
  97. package/lib/ui/icons.d.ts +2 -0
  98. package/lib/ui/icons.d.ts.map +1 -1
  99. package/lib/ui/icons.js +2 -0
  100. package/lib/ui/icons.js.map +1 -1
  101. package/lib/ui/index.d.ts +1 -0
  102. package/lib/ui/index.d.ts.map +1 -1
  103. package/lib/ui/index.js +1 -0
  104. package/lib/ui/index.js.map +1 -1
  105. package/lib/util/AcApTextStyleFontPreload.d.ts +42 -0
  106. package/lib/util/AcApTextStyleFontPreload.d.ts.map +1 -0
  107. package/lib/util/AcApTextStyleFontPreload.js +149 -0
  108. package/lib/util/AcApTextStyleFontPreload.js.map +1 -0
  109. package/lib/util/index.d.ts +1 -0
  110. package/lib/util/index.d.ts.map +1 -1
  111. package/lib/util/index.js +1 -0
  112. package/lib/util/index.js.map +1 -1
  113. package/lib/view/AcTrLayout.d.ts +5 -0
  114. package/lib/view/AcTrLayout.d.ts.map +1 -1
  115. package/lib/view/AcTrLayout.js +11 -0
  116. package/lib/view/AcTrLayout.js.map +1 -1
  117. package/lib/view/AcTrScene.d.ts +7 -0
  118. package/lib/view/AcTrScene.d.ts.map +1 -1
  119. package/lib/view/AcTrScene.js +78 -48
  120. package/lib/view/AcTrScene.js.map +1 -1
  121. package/lib/view/AcTrView2d.d.ts +68 -1
  122. package/lib/view/AcTrView2d.d.ts.map +1 -1
  123. package/lib/view/AcTrView2d.js +311 -124
  124. package/lib/view/AcTrView2d.js.map +1 -1
  125. package/package.json +8 -8
  126. package/src/ui/icons.ts +4 -0
@@ -96,7 +96,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
96
96
  }
97
97
  return to.concat(ar || Array.prototype.slice.call(from));
98
98
  };
99
- import { AcCmUiYieldGate, AcDbAttribute, AcDbBlockReference, acdbHostApplicationServices, AcDbMText, AcDbRasterImage, AcDbRay, AcDbSysVarManager, AcDbViewport, AcDbXline, AcGeBox2d, AcGePoint2d, acgiForegroundColorForBackground, log } from '@mlightcad/data-model';
99
+ import { AcCmUiYieldGate, AcDbAttribute, AcDbBlockReference, acdbHostApplicationServices, AcDbMText, AcDbRasterImage, AcDbRay, AcDbRenderingCache, AcDbSysVarManager, AcDbViewport, AcDbXline, AcGeBox2d, AcGePoint2d, acgiForegroundColorForBackground, log } from '@mlightcad/data-model';
100
100
  import { AcDbSystemVariables } from '@mlightcad/data-model';
101
101
  import { FontManager } from '@mlightcad/mtext-renderer';
102
102
  import { AcTrEntity, AcTrGlyphEntity, AcTrGroup, AcTrMTextRenderer, AcTrRenderer, AcTrViewportView, hasPendingComplexLineTypeGlyphs, setAcTrDrawOrderZAllocator } from '@mlightcad/three-renderer';
@@ -115,6 +115,7 @@ import { acedEntityIntersectsSelectionBox, acedNeedsCrossingGeometryRefine } fro
115
115
  import { isEffectiveSpatialQueryHit } from '../editor/view/AcEdSpatialQueryResult';
116
116
  import { AcTrGeometryUtil } from '../util';
117
117
  import { acapRunDatabaseEdit } from '../util/AcApDatabaseEdit';
118
+ import { collectTextStyleFontNames, planTextStyleFontPreload } from '../util/AcApTextStyleFontPreload';
118
119
  import { ACAP_READING_MODE_BACKGROUND, AcApReadingModeState } from './AcApReadingMode';
119
120
  import { trySelectReviewOverlay, trySelectReviewOverlaysByBox } from './AcEdReviewOverlayPick';
120
121
  import { AcEdViewKeyHandler } from './AcEdViewKeyHandler';
@@ -270,6 +271,16 @@ var AcTrView2d = /** @class */ (function (_super) {
270
271
  * geometry paints incrementally while the open overlay is still visible.
271
272
  */
272
273
  _this._progressiveRendering = false;
274
+ /**
275
+ * When true, open-time convert includes off/frozen-layer entities so HTML
276
+ * export does not need a second convert pass for those entities.
277
+ */
278
+ _this._convertInvisibleLayers = false;
279
+ /**
280
+ * When false, {@link batchConvert} skips cooperative setTimeout yields.
281
+ * Headless CLI sets this false; interactive viewers leave it true.
282
+ */
283
+ _this._cooperativeYield = true;
273
284
  /**
274
285
  * Serial convert queue for progressive opens. Chunks from `entityAppended`
275
286
  * enqueue here and a single drain loop runs {@link batchConvert}, so scene
@@ -342,6 +353,21 @@ var AcTrView2d = /** @class */ (function (_super) {
342
353
  _this._isDirty = true;
343
354
  }
344
355
  });
356
+ /**
357
+ * Promise that resolves when text-style fonts needed by deferred glyph jobs
358
+ * are ready. Shared so concurrent deferred jobs do not each await a long
359
+ * font preload.
360
+ */
361
+ _this._deferredFontsReady = null;
362
+ /** Convert-phase wall timers (ms) for OPENPERF diagnostics. */
363
+ _this._convertPhaseMs = {
364
+ finishGeometry: 0,
365
+ handleGroup: 0,
366
+ addEntity: 0,
367
+ awaitFonts: 0
368
+ };
369
+ /** Last text-style font preload plan (for OPENPERF). */
370
+ _this._fontPreloadDiag = null;
345
371
  _this.animate = function () {
346
372
  var _a;
347
373
  _this._rafId = requestAnimationFrame(_this.animate);
@@ -695,6 +721,59 @@ var AcTrView2d = /** @class */ (function (_super) {
695
721
  _this.resetDeferredGeometryQueue();
696
722
  return _this;
697
723
  }
724
+ AcTrView2d.prototype.ensureDeferredFontsReady = function () {
725
+ var _this = this;
726
+ if (!this._deferredFontsReady) {
727
+ var t0_1 = performance.now();
728
+ // Preset (fallback) + STYLE-table faces must both be ready before glyph
729
+ // bake. Linework convert does not await this promise.
730
+ var ready = Promise.all([
731
+ this.awaitPresetFontsReadySafe(),
732
+ this.awaitTextStyleFontsReady()
733
+ ]).then(function () { return undefined; }, function () { return undefined; });
734
+ this._deferredFontsReady = ready.then(function () {
735
+ _this._convertPhaseMs.awaitFonts += performance.now() - t0_1;
736
+ });
737
+ }
738
+ return this._deferredFontsReady;
739
+ };
740
+ /**
741
+ * Awaits DocManager preset preload when the singleton exists.
742
+ * No-op in unit tests that construct a view without a manager.
743
+ */
744
+ AcTrView2d.prototype.awaitPresetFontsReadySafe = function () {
745
+ return __awaiter(this, void 0, void 0, function () {
746
+ var singleton;
747
+ return __generator(this, function (_a) {
748
+ switch (_a.label) {
749
+ case 0:
750
+ singleton = AcApDocManager;
751
+ if (!singleton._instance) {
752
+ return [2 /*return*/];
753
+ }
754
+ return [4 /*yield*/, singleton._instance.awaitPresetFontsReady()];
755
+ case 1:
756
+ _a.sent();
757
+ return [2 /*return*/];
758
+ }
759
+ });
760
+ });
761
+ };
762
+ /**
763
+ * Returns and resets convert-phase wall timers collected during the last open.
764
+ */
765
+ AcTrView2d.prototype.takeConvertPhaseTimings = function () {
766
+ var snapshot = __assign(__assign({}, this._convertPhaseMs), { fontPreload: this._fontPreloadDiag
767
+ ? __assign({}, this._fontPreloadDiag) : undefined });
768
+ this._convertPhaseMs = {
769
+ finishGeometry: 0,
770
+ handleGroup: 0,
771
+ addEntity: 0,
772
+ awaitFonts: 0
773
+ };
774
+ this._fontPreloadDiag = null;
775
+ return snapshot;
776
+ };
698
777
  AcTrView2d.prototype.getPointerSelectionAction = function (e) {
699
778
  return resolvePointerSelectionAction(e);
700
779
  };
@@ -910,6 +989,32 @@ var AcTrView2d = /** @class */ (function (_super) {
910
989
  enumerable: false,
911
990
  configurable: true
912
991
  });
992
+ Object.defineProperty(AcTrView2d.prototype, "convertInvisibleLayers", {
993
+ /**
994
+ * When true, open-time convert includes off/frozen-layer entities.
995
+ */
996
+ get: function () {
997
+ return this._convertInvisibleLayers;
998
+ },
999
+ set: function (value) {
1000
+ this._convertInvisibleLayers = value;
1001
+ },
1002
+ enumerable: false,
1003
+ configurable: true
1004
+ });
1005
+ Object.defineProperty(AcTrView2d.prototype, "cooperativeYield", {
1006
+ /**
1007
+ * When false, entity convert skips cooperative yields (headless export).
1008
+ */
1009
+ get: function () {
1010
+ return this._cooperativeYield;
1011
+ },
1012
+ set: function (value) {
1013
+ this._cooperativeYield = value;
1014
+ },
1015
+ enumerable: false,
1016
+ configurable: true
1017
+ });
913
1018
  Object.defineProperty(AcTrView2d.prototype, "progressiveOpenStats", {
914
1019
  /**
915
1020
  * Open-convert counters for OPENPROF / palette (cooperative yields during
@@ -2527,6 +2632,8 @@ var AcTrView2d = /** @class */ (function (_super) {
2527
2632
  this._externallyFramedLayouts.clear();
2528
2633
  this._loadingLayouts.clear();
2529
2634
  this._renderer.dispose();
2635
+ // Drop block templates when the scene is torn down (next open / close).
2636
+ AcDbRenderingCache.instance.clear();
2530
2637
  eventBus.emit('missed-data-changed', {});
2531
2638
  };
2532
2639
  /**
@@ -3069,81 +3176,71 @@ var AcTrView2d = /** @class */ (function (_super) {
3069
3176
  *
3070
3177
  * Call when conversion stage `STYLE` ends so the download overlaps later
3071
3178
  * parse stages and linework convert. Does not block the caller — glyph
3072
- * finalize awaits {@link awaitTextStyleFontsReady} instead.
3179
+ * finalize awaits {@link awaitTextStyleFontsReady} (and the open-start
3180
+ * preset gate) instead.
3181
+ *
3182
+ * Drawing-independent preset faces are loaded separately via
3183
+ * {@link AcApDocManager.ensurePresetFontsForOpen} at open start.
3073
3184
  *
3074
3185
  * @param database - Database whose text style table has just been filled.
3075
3186
  */
3076
3187
  AcTrView2d.prototype.startTextStyleFontPreload = function (database) {
3077
- var e_12, _a;
3078
- var _b;
3188
+ var _a, _b;
3079
3189
  var epoch = this._convertEpoch;
3080
3190
  if (this._textStyleFontPreloadEpoch === epoch &&
3081
3191
  this._textStyleFontPreloadPromise) {
3082
3192
  return;
3083
3193
  }
3084
3194
  this._textStyleFontPreloadEpoch = epoch;
3085
- var names = [];
3086
- try {
3087
- var table = database.tables.textStyleTable;
3088
- names = __spreadArray([], __read(((_b = table.fonts) !== null && _b !== void 0 ? _b : [])), false);
3089
- // `fonts` is DXF group 3/4 file names only. TrueType styles store the
3090
- // face on `font` / `extendedFont` (仿宋, SimHei).
3091
- if (table.newIterator) {
3092
- try {
3093
- for (var _c = __values(table.newIterator()), _d = _c.next(); !_d.done; _d = _c.next()) {
3094
- var record = _d.value;
3095
- var style = record.textStyle;
3096
- if (style === null || style === void 0 ? void 0 : style.font)
3097
- names.push(style.font);
3098
- if (style === null || style === void 0 ? void 0 : style.bigFont)
3099
- names.push(style.bigFont);
3100
- if (style === null || style === void 0 ? void 0 : style.extendedFont)
3101
- names.push(style.extendedFont);
3102
- }
3103
- }
3104
- catch (e_12_1) { e_12 = { error: e_12_1 }; }
3105
- finally {
3106
- try {
3107
- if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
3108
- }
3109
- finally { if (e_12) throw e_12.error; }
3110
- }
3111
- }
3112
- }
3113
- catch (_e) {
3114
- names = [];
3115
- }
3116
- // Style fonts alone are not enough: awaitFontsBeforeDraw only *awaits*
3117
- // content/style faces and kicks default/symbol fallbacks in the background.
3118
- // Drawings with empty primary font files (font falls back to the STYLE name)
3119
- // need those fallbacks loaded before the first glyph bake, otherwise Latin
3120
- // (and often all) text is permanently baked as '?'.
3195
+ // Worker mode: do not parse STYLE faces on the main thread (would dual-
3196
+ // parse mesh with workers). Each worker draw awaits its own content/style
3197
+ // faces via awaitFontsBeforeDraw. Preset fallbacks are gated separately
3198
+ // by ensurePresetFontsForOpen (scope: all).
3199
+ //
3200
+ // Main mode: gate deferred glyph jobs on style-table faces only. Unused
3201
+ // preset faces were already started at open — do not re-request here.
3202
+ var styleFonts = collectTextStyleFontNames(database);
3121
3203
  var fallbackFonts = FontManager.instance.getFontsToLoad();
3122
- var preloadNames = __spreadArray([], __read(new Set(__spreadArray(__spreadArray([], __read(names), false), __read(fallbackFonts), false))), false);
3123
- if (preloadNames.length === 0) {
3204
+ var firstDefault = __spreadArray([], __read(FontManager.instance.defaultFonts), false)[0];
3205
+ var plan = planTextStyleFontPreload(styleFonts, fallbackFonts, {
3206
+ firstDefaultFont: firstDefault
3207
+ });
3208
+ var mtextRenderer = AcTrMTextRenderer.getInstance();
3209
+ var parseSite = mtextRenderer.getRenderMode() === 'worker' ? 'worker' : 'main';
3210
+ var singleton = AcApDocManager;
3211
+ var preset = ((_b = (_a = singleton._instance) === null || _a === void 0 ? void 0 : _a.lastPresetFontsForOpen) === null || _b === void 0 ? void 0 : _b.length)
3212
+ ? __spreadArray([], __read(singleton._instance.lastPresetFontsForOpen), false) : __spreadArray([], __read(fallbackFonts), false);
3213
+ this._fontPreloadDiag = {
3214
+ critical: __spreadArray([], __read(plan.critical), false),
3215
+ workerWarm: [],
3216
+ background: [],
3217
+ preset: preset,
3218
+ workerSkipped: 0,
3219
+ parseSite: parseSite
3220
+ };
3221
+ if (parseSite === 'worker') {
3124
3222
  this._textStyleFontPreloadPromise = Promise.resolve();
3125
3223
  return;
3126
3224
  }
3127
- var mtextRenderer = AcTrMTextRenderer.getInstance();
3128
- // Same deadline as AcApDocManager.installFontFileLoadTimeout. Covers both
3129
- // main-thread requestFonts and worker-pool loadFonts so a stalled CDN
3130
- // cannot pin deferred glyph jobs / the open overlay indefinitely.
3225
+ // Same deadline as AcApDocManager.installFontFileLoadTimeout.
3131
3226
  var preloadTimeoutMs = 30000;
3132
- var preload = Promise.all([
3133
- FontManager.instance.requestFonts(preloadNames),
3134
- // Worker isolates have their own FontManager; main-thread requestFonts
3135
- // alone does not populate them before asyncRenderMText.
3136
- mtextRenderer.loadFonts(fallbackFonts)
3137
- ]);
3138
- this._textStyleFontPreloadPromise = Promise.race([
3139
- preload,
3140
- new Promise(function (_, reject) {
3141
- setTimeout(function () {
3142
- reject(new Error("Text-style font preload timed out after ".concat(preloadTimeoutMs, "ms")));
3143
- }, preloadTimeoutMs);
3144
- })
3145
- ]).then(function () { return undefined; }, function () {
3146
- // Glyph draw still falls back via FontManager defaults / '?'.
3227
+ if (plan.critical.length === 0) {
3228
+ this._textStyleFontPreloadPromise = Promise.resolve();
3229
+ return;
3230
+ }
3231
+ var preload = FontManager.instance.requestFonts(plan.critical);
3232
+ this._textStyleFontPreloadPromise = new Promise(function (resolve) {
3233
+ var timer = setTimeout(function () {
3234
+ // Glyph draw still falls back via FontManager defaults / '?'.
3235
+ resolve();
3236
+ }, preloadTimeoutMs);
3237
+ preload.then(function () {
3238
+ clearTimeout(timer);
3239
+ resolve();
3240
+ }, function () {
3241
+ clearTimeout(timer);
3242
+ resolve();
3243
+ });
3147
3244
  });
3148
3245
  };
3149
3246
  /**
@@ -3183,45 +3280,54 @@ var AcTrView2d = /** @class */ (function (_super) {
3183
3280
  */
3184
3281
  AcTrView2d.prototype.finishEntityGeometry = function (threeEntity, _progressive) {
3185
3282
  return __awaiter(this, void 0, void 0, function () {
3186
- var needsGlyphDraw;
3283
+ var t0, isGroup, groupPending, needsGlyphDraw;
3187
3284
  return __generator(this, function (_a) {
3188
3285
  switch (_a.label) {
3189
3286
  case 0:
3190
- needsGlyphDraw = (threeEntity instanceof AcTrGroup &&
3191
- this.groupHasPendingGlyphGeometry(threeEntity)) ||
3287
+ t0 = performance.now();
3288
+ _a.label = 1;
3289
+ case 1:
3290
+ _a.trys.push([1, , 9, 10]);
3291
+ isGroup = threeEntity instanceof AcTrGroup;
3292
+ groupPending = isGroup && this.groupHasPendingGlyphGeometry(threeEntity);
3293
+ needsGlyphDraw = groupPending ||
3192
3294
  hasPendingComplexLineTypeGlyphs(threeEntity) ||
3193
3295
  (threeEntity instanceof AcTrGlyphEntity &&
3194
3296
  !threeEntity.hasDrawableGeometry());
3195
- if (!needsGlyphDraw) return [3 /*break*/, 2];
3196
- return [4 /*yield*/, this.awaitTextStyleFontsReady()];
3197
- case 1:
3198
- _a.sent();
3199
- _a.label = 2;
3297
+ if (!needsGlyphDraw) return [3 /*break*/, 3];
3298
+ return [4 /*yield*/, this.ensureDeferredFontsReady()];
3200
3299
  case 2:
3201
- if (!(threeEntity instanceof AcTrGroup)) return [3 /*break*/, 4];
3300
+ _a.sent();
3301
+ _a.label = 3;
3302
+ case 3:
3303
+ if (!isGroup) return [3 /*break*/, 5];
3202
3304
  // Linework-only INSERTs (no empty glyph shells) skip asyncDraw; spatial
3203
3305
  // boxes are refreshed by syncGroupSpatialBoundsForIndexing after commit.
3204
- if (!this.groupHasPendingGlyphGeometry(threeEntity)) {
3306
+ if (!groupPending) {
3205
3307
  return [2 /*return*/];
3206
3308
  }
3207
3309
  return [4 /*yield*/, threeEntity.asyncDraw()];
3208
- case 3:
3310
+ case 4:
3209
3311
  _a.sent();
3210
3312
  return [2 /*return*/];
3211
- case 4:
3212
- if (!hasPendingComplexLineTypeGlyphs(threeEntity)) return [3 /*break*/, 6];
3213
- return [4 /*yield*/, threeEntity.asyncDraw()];
3214
3313
  case 5:
3314
+ if (!hasPendingComplexLineTypeGlyphs(threeEntity)) return [3 /*break*/, 7];
3315
+ return [4 /*yield*/, threeEntity.asyncDraw()];
3316
+ case 6:
3215
3317
  _a.sent();
3216
3318
  return [2 /*return*/];
3217
- case 6:
3319
+ case 7:
3218
3320
  if (threeEntity.hasDrawableGeometry()) {
3219
3321
  return [2 /*return*/];
3220
3322
  }
3221
3323
  return [4 /*yield*/, threeEntity.asyncDraw()];
3222
- case 7:
3324
+ case 8:
3223
3325
  _a.sent();
3224
- return [2 /*return*/];
3326
+ return [3 /*break*/, 10];
3327
+ case 9:
3328
+ this._convertPhaseMs.finishGeometry += performance.now() - t0;
3329
+ return [7 /*endfinally*/];
3330
+ case 10: return [2 /*return*/];
3225
3331
  }
3226
3332
  });
3227
3333
  });
@@ -3271,8 +3377,8 @@ var AcTrView2d = /** @class */ (function (_super) {
3271
3377
  */
3272
3378
  AcTrView2d.prototype.redrawGlyphEntitiesAfterFontLoad = function (epoch, fontName) {
3273
3379
  return __awaiter(this, void 0, void 0, function () {
3274
- var redrawEpoch, glyphs, _a, _b, layout, glyphs_1, glyphs_1_1, glyph, e_13_1, defaults, normalized_1, msSinceIdle, db;
3275
- var e_14, _c, e_13, _d;
3380
+ var redrawEpoch, glyphs, _a, _b, layout, glyphs_1, glyphs_1_1, glyph, e_12_1, defaults, normalized_1, msSinceIdle, db;
3381
+ var e_13, _c, e_12, _d;
3276
3382
  var _e, _f;
3277
3383
  return __generator(this, function (_g) {
3278
3384
  switch (_g.label) {
@@ -3294,12 +3400,12 @@ var AcTrView2d = /** @class */ (function (_super) {
3294
3400
  });
3295
3401
  }
3296
3402
  }
3297
- catch (e_14_1) { e_14 = { error: e_14_1 }; }
3403
+ catch (e_13_1) { e_13 = { error: e_13_1 }; }
3298
3404
  finally {
3299
3405
  try {
3300
3406
  if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
3301
3407
  }
3302
- finally { if (e_14) throw e_14.error; }
3408
+ finally { if (e_13) throw e_13.error; }
3303
3409
  }
3304
3410
  _g.label = 1;
3305
3411
  case 1:
@@ -3322,14 +3428,14 @@ var AcTrView2d = /** @class */ (function (_super) {
3322
3428
  return [3 /*break*/, 2];
3323
3429
  case 5: return [3 /*break*/, 8];
3324
3430
  case 6:
3325
- e_13_1 = _g.sent();
3326
- e_13 = { error: e_13_1 };
3431
+ e_12_1 = _g.sent();
3432
+ e_12 = { error: e_12_1 };
3327
3433
  return [3 /*break*/, 8];
3328
3434
  case 7:
3329
3435
  try {
3330
3436
  if (glyphs_1_1 && !glyphs_1_1.done && (_d = glyphs_1.return)) _d.call(glyphs_1);
3331
3437
  }
3332
- finally { if (e_13) throw e_13.error; }
3438
+ finally { if (e_12) throw e_12.error; }
3333
3439
  return [7 /*endfinally*/];
3334
3440
  case 8:
3335
3441
  if (glyphs.length > 0) {
@@ -3380,13 +3486,73 @@ var AcTrView2d = /** @class */ (function (_super) {
3380
3486
  });
3381
3487
  };
3382
3488
  AcTrView2d.prototype.groupHasPendingGlyphGeometry = function (group) {
3383
- var pending = false;
3384
- group.traverse(function (child) {
3385
- if (child instanceof AcTrGlyphEntity && !child.hasDrawableGeometry()) {
3386
- pending = true;
3489
+ var e_14, _a;
3490
+ try {
3491
+ // Prefer O(block-def shells). A full THREE.traverse over a mega-block
3492
+ // (100k+ flattened mesh leaves) was dominating scene-convert wall time.
3493
+ for (var _b = __values(group.getSourceEntities()), _c = _b.next(); !_c.done; _c = _b.next()) {
3494
+ var entity = _c.value;
3495
+ if (entity instanceof AcTrGlyphEntity && !entity.hasDrawableGeometry()) {
3496
+ return true;
3497
+ }
3387
3498
  }
3388
- });
3389
- return pending;
3499
+ }
3500
+ catch (e_14_1) { e_14 = { error: e_14_1 }; }
3501
+ finally {
3502
+ try {
3503
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
3504
+ }
3505
+ finally { if (e_14) throw e_14.error; }
3506
+ }
3507
+ return AcTrView2d.directChildrenHavePendingGlyphs(group);
3508
+ };
3509
+ /**
3510
+ * Walks only {@link AcTrEntity} containers for empty glyph shells.
3511
+ *
3512
+ * Skips raw mesh/line leaves under a flattened {@link AcTrGroup} so checking
3513
+ * a whole-floor INSERT is O(glyph shells), not O(all drawable leaves).
3514
+ */
3515
+ AcTrView2d.directChildrenHavePendingGlyphs = function (root) {
3516
+ var e_15, _a;
3517
+ var children = root.children;
3518
+ for (var i = 0; i < children.length; i++) {
3519
+ var child = children[i];
3520
+ if (child instanceof AcTrGlyphEntity) {
3521
+ if (!child.hasDrawableGeometry()) {
3522
+ return true;
3523
+ }
3524
+ continue;
3525
+ }
3526
+ if (child instanceof AcTrGroup) {
3527
+ try {
3528
+ for (var _b = (e_15 = void 0, __values(child.getSourceEntities())), _c = _b.next(); !_c.done; _c = _b.next()) {
3529
+ var entity = _c.value;
3530
+ if (entity instanceof AcTrGlyphEntity &&
3531
+ !entity.hasDrawableGeometry()) {
3532
+ return true;
3533
+ }
3534
+ }
3535
+ }
3536
+ catch (e_15_1) { e_15 = { error: e_15_1 }; }
3537
+ finally {
3538
+ try {
3539
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
3540
+ }
3541
+ finally { if (e_15) throw e_15.error; }
3542
+ }
3543
+ if (AcTrView2d.directChildrenHavePendingGlyphs(child)) {
3544
+ return true;
3545
+ }
3546
+ continue;
3547
+ }
3548
+ if (child instanceof AcTrEntity) {
3549
+ // Nested non-group entity that may still host deferred glyph children.
3550
+ if (AcTrView2d.directChildrenHavePendingGlyphs(child)) {
3551
+ return true;
3552
+ }
3553
+ }
3554
+ }
3555
+ return false;
3390
3556
  };
3391
3557
  /**
3392
3558
  * Runs glyph/group geometry finalize off the main convert loop so other
@@ -3456,6 +3622,8 @@ var AcTrView2d = /** @class */ (function (_super) {
3456
3622
  this._pendingGeometryJobs = 0;
3457
3623
  this._textStyleFontPreloadPromise = null;
3458
3624
  this._textStyleFontPreloadEpoch = -1;
3625
+ this._deferredFontsReady = null;
3626
+ this._fontPreloadDiag = null;
3459
3627
  };
3460
3628
  /**
3461
3629
  * Waits until side-pool glyph/group jobs for the current convert epoch finish.
@@ -3499,7 +3667,7 @@ var AcTrView2d = /** @class */ (function (_super) {
3499
3667
  * paper layouts.
3500
3668
  */
3501
3669
  AcTrView2d.prototype.ensureViewportViews = function (blockTableRecord, layoutView) {
3502
- var e_15, _a;
3670
+ var e_16, _a;
3503
3671
  var iterator = blockTableRecord.newIterator();
3504
3672
  try {
3505
3673
  for (var iterator_2 = __values(iterator), iterator_2_1 = iterator_2.next(); !iterator_2_1.done; iterator_2_1 = iterator_2.next()) {
@@ -3512,12 +3680,12 @@ var AcTrView2d = /** @class */ (function (_super) {
3512
3680
  layoutView.addViewport(viewportView);
3513
3681
  }
3514
3682
  }
3515
- catch (e_15_1) { e_15 = { error: e_15_1 }; }
3683
+ catch (e_16_1) { e_16 = { error: e_16_1 }; }
3516
3684
  finally {
3517
3685
  try {
3518
3686
  if (iterator_2_1 && !iterator_2_1.done && (_a = iterator_2.return)) _a.call(iterator_2);
3519
3687
  }
3520
- finally { if (e_15) throw e_15.error; }
3688
+ finally { if (e_16) throw e_16.error; }
3521
3689
  }
3522
3690
  };
3523
3691
  /**
@@ -3545,7 +3713,7 @@ var AcTrView2d = /** @class */ (function (_super) {
3545
3713
  }
3546
3714
  }
3547
3715
  progressive = this._progressiveRendering && !options.forExport;
3548
- yieldGate = options.forExport
3716
+ yieldGate = options.forExport || !this._cooperativeYield
3549
3717
  ? undefined
3550
3718
  : new AcCmUiYieldGate(AcTrView2d.OPEN_CONVERT_YIELD_BUDGET_MS);
3551
3719
  yieldToEventLoop = function () {
@@ -3579,7 +3747,7 @@ var AcTrView2d = /** @class */ (function (_super) {
3579
3747
  AcTrViewportView.isDefaultPaperSpaceViewport(entity)) {
3580
3748
  return [2 /*return*/, "continue"];
3581
3749
  }
3582
- shouldConvert = options.forExport
3750
+ shouldConvert = options.forExport || this_3._convertInvisibleLayers
3583
3751
  ? this_3._entityDisplay.shouldConvertForExport(entity)
3584
3752
  : this_3._entityDisplay.shouldConvert(entity);
3585
3753
  if (!shouldConvert) {
@@ -3661,6 +3829,7 @@ var AcTrView2d = /** @class */ (function (_super) {
3661
3829
  case 5:
3662
3830
  isExtendBbox_1 = !(entity instanceof AcDbRay || entity instanceof AcDbXline);
3663
3831
  commitEntity = function () { return __awaiter(_this, void 0, void 0, function () {
3832
+ var tAdd;
3664
3833
  var _this = this;
3665
3834
  var _a;
3666
3835
  return __generator(this, function (_b) {
@@ -3684,7 +3853,9 @@ var AcTrView2d = /** @class */ (function (_super) {
3684
3853
  this._inheritedLayerMaterialMapper.remap(threeEntity_1.children, '0', threeEntity_1.layerName);
3685
3854
  }
3686
3855
  }
3856
+ tAdd = performance.now();
3687
3857
  this._scene.addEntity(threeEntity_1, isExtendBbox_1);
3858
+ this._convertPhaseMs.addEntity += performance.now() - tAdd;
3688
3859
  this.applySessionHiddenObjectState(entity.objectId);
3689
3860
  // Release memory occupied by this entity
3690
3861
  threeEntity_1.dispose();
@@ -3797,16 +3968,21 @@ var AcTrView2d = /** @class */ (function (_super) {
3797
3968
  };
3798
3969
  AcTrView2d.prototype.handleGroup = function (group_1, progressive_1) {
3799
3970
  return __awaiter(this, arguments, void 0, function (group, progressive, epoch, convertGen) {
3800
- var objectId, children, objectsGroupByLayer, children_1, children_1_1, child, renderContext, groupObjectId, groupLayerName, groupChildBoxes, aggregateSpatialBbox, registeredChildIndex;
3801
- var e_16, _a;
3971
+ var t0, objectId, children, objectsGroupByLayer_1, children_1, children_1_1, child, renderContext_1, groupObjectId_1, groupLayerName_1, groupChildBoxes_1, aggregateSpatialBbox_1, registeredChildIndex_1;
3972
+ var e_17, _a;
3802
3973
  var _this = this;
3803
3974
  var _b, _c;
3804
3975
  if (epoch === void 0) { epoch = this._convertEpoch; }
3805
3976
  if (convertGen === void 0) { convertGen = 0; }
3806
3977
  return __generator(this, function (_d) {
3807
3978
  switch (_d.label) {
3808
- case 0: return [4 /*yield*/, this.finishEntityGeometry(group, progressive)];
3979
+ case 0:
3980
+ t0 = performance.now();
3981
+ _d.label = 1;
3809
3982
  case 1:
3983
+ _d.trys.push([1, , 3, 4]);
3984
+ return [4 /*yield*/, this.finishEntityGeometry(group, progressive)];
3985
+ case 2:
3810
3986
  _d.sent();
3811
3987
  if (epoch !== this._convertEpoch) {
3812
3988
  group.dispose();
@@ -3820,17 +3996,17 @@ var AcTrView2d = /** @class */ (function (_super) {
3820
3996
  }
3821
3997
  this.syncGroupSpatialBoundsForIndexing(group);
3822
3998
  children = group.children;
3823
- objectsGroupByLayer = new Map();
3999
+ objectsGroupByLayer_1 = new Map();
3824
4000
  children.forEach(function (child) {
3825
4001
  var _a;
3826
4002
  if (child.visible === false) {
3827
4003
  return;
3828
4004
  }
3829
4005
  var layerName = child.userData.layerName;
3830
- if (!objectsGroupByLayer.has(layerName)) {
3831
- objectsGroupByLayer.set(layerName, []);
4006
+ if (!objectsGroupByLayer_1.has(layerName)) {
4007
+ objectsGroupByLayer_1.set(layerName, []);
3832
4008
  }
3833
- (_a = objectsGroupByLayer.get(layerName)) === null || _a === void 0 ? void 0 : _a.push(child);
4009
+ (_a = objectsGroupByLayer_1.get(layerName)) === null || _a === void 0 ? void 0 : _a.push(child);
3834
4010
  });
3835
4011
  // Important:
3836
4012
  // Sometimes one group may contain huge amount of objects (> 100,000). So it is important
@@ -3848,40 +4024,40 @@ var AcTrView2d = /** @class */ (function (_super) {
3848
4024
  child.parent = null;
3849
4025
  }
3850
4026
  }
3851
- catch (e_16_1) { e_16 = { error: e_16_1 }; }
4027
+ catch (e_17_1) { e_17 = { error: e_17_1 }; }
3852
4028
  finally {
3853
4029
  try {
3854
4030
  if (children_1_1 && !children_1_1.done && (_a = children_1.return)) _a.call(children_1);
3855
4031
  }
3856
- finally { if (e_16) throw e_16.error; }
4032
+ finally { if (e_17) throw e_17.error; }
3857
4033
  }
3858
- renderContext = group.renderContext;
3859
- groupObjectId = group.objectId;
3860
- groupLayerName = group.layerName;
4034
+ renderContext_1 = group.renderContext;
4035
+ groupObjectId_1 = group.objectId;
4036
+ groupLayerName_1 = group.layerName;
3861
4037
  // AcDbRenderingCache.draw (and similar paths such as AcDbTable) already call
3862
4038
  // applyMatrix on the group, which updates wcsBbbox and wcsChildBoxes to WCS.
3863
4039
  // Do not multiply group.matrix here — that would double-transform spatial bounds.
3864
4040
  if (process.env.NODE_ENV !== 'production') {
3865
4041
  assertAcTrGroupWcsBboxesConsistent(group);
3866
4042
  }
3867
- groupChildBoxes = group.wcsChildBoxes.map(function (box) { return ({
4043
+ groupChildBoxes_1 = group.wcsChildBoxes.map(function (box) { return ({
3868
4044
  minX: box.minX,
3869
4045
  minY: box.minY,
3870
4046
  maxX: box.maxX,
3871
4047
  maxY: box.maxY,
3872
4048
  id: box.id
3873
4049
  }); });
3874
- aggregateSpatialBbox = groupChildBoxes.length > 0
4050
+ aggregateSpatialBbox_1 = groupChildBoxes_1.length > 0
3875
4051
  ? unionGroupWcsChildBoxes(group)
3876
4052
  : group.wcsBbox.clone();
3877
- if (groupChildBoxes.length > 0) {
3878
- group.wcsBbox = aggregateSpatialBbox.clone();
4053
+ if (groupChildBoxes_1.length > 0) {
4054
+ group.wcsBbox = aggregateSpatialBbox_1.clone();
3879
4055
  }
3880
- registeredChildIndex = false;
3881
- objectsGroupByLayer.forEach(function (objects, layerName) {
4056
+ registeredChildIndex_1 = false;
4057
+ objectsGroupByLayer_1.forEach(function (objects, layerName) {
3882
4058
  // Nested layer-0 may already be resolved to an inner INSERT layer during
3883
4059
  // flatten. Remaining "0" buckets inherit this (outermost) INSERT layer.
3884
- var effectiveLayerName = layerName === '0' ? groupLayerName : layerName;
4060
+ var effectiveLayerName = layerName === '0' ? groupLayerName_1 : layerName;
3885
4061
  // Material remap must still treat authored layer-0 drawables as layer-0
3886
4062
  // ByLayer even when nest resolution already rewrote layerName.
3887
4063
  var sourceLayerForMaterials = objects.some(function (object) {
@@ -3899,23 +4075,23 @@ var AcTrView2d = /** @class */ (function (_super) {
3899
4075
  // render entity per layer bucket but preserve the INSERT object id for all
3900
4076
  // buckets, so selection/highlight still maps back to the same database object.
3901
4077
  // Within each layer bucket, the object id remains unique in scene indexing.
3902
- var entity = new AcTrEntity(renderContext);
4078
+ var entity = new AcTrEntity(renderContext_1);
3903
4079
  // Copy the INSERT matrix exactly — applyMatrix4 decomposes and drops
3904
4080
  // reflections from mirrored block scales.
3905
4081
  entity.matrix.copy(group.matrix);
3906
4082
  entity.matrixAutoUpdate = false;
3907
4083
  entity.matrixWorldNeedsUpdate = true;
3908
- entity.objectId = groupObjectId;
4084
+ entity.objectId = groupObjectId_1;
3909
4085
  entity.ownerId = group.ownerId;
3910
4086
  // If block-definition entities are on layer "0", this bucket now uses the layer
3911
4087
  // of the block reference itself (effectiveLayerName).
3912
4088
  entity.layerName = effectiveLayerName;
3913
- entity.userData.insertLayerName = groupLayerName;
3914
- entity.wcsBbox = aggregateSpatialBbox.clone();
4089
+ entity.userData.insertLayerName = groupLayerName_1;
4090
+ entity.wcsBbox = aggregateSpatialBbox_1.clone();
3915
4091
  var entityUserData = entity.userData;
3916
- if (!registeredChildIndex && groupChildBoxes.length > 0) {
3917
- entityUserData.spatialIndexChildBoxes = groupChildBoxes;
3918
- registeredChildIndex = true;
4092
+ if (!registeredChildIndex_1 && groupChildBoxes_1.length > 0) {
4093
+ entityUserData.spatialIndexChildBoxes = groupChildBoxes_1;
4094
+ registeredChildIndex_1 = true;
3919
4095
  }
3920
4096
  // Important:
3921
4097
  // DO NOT USE spread operator when adding objects because it may be one very large array
@@ -3925,8 +4101,10 @@ var AcTrView2d = /** @class */ (function (_super) {
3925
4101
  }
3926
4102
  entity.updateMatrixWorld(true);
3927
4103
  _this._layerAppearance.refreshTextMaterialsInObjectTree(entity);
4104
+ var tAdd = performance.now();
3928
4105
  _this._scene.addEntity(entity, true);
3929
- _this.applySessionHiddenObjectState(groupObjectId);
4106
+ _this._convertPhaseMs.addEntity += performance.now() - tAdd;
4107
+ _this.applySessionHiddenObjectState(groupObjectId_1);
3930
4108
  entity.dispose();
3931
4109
  });
3932
4110
  group.dispose();
@@ -3936,7 +4114,11 @@ var AcTrView2d = /** @class */ (function (_super) {
3936
4114
  return _this.getDrawingExtents();
3937
4115
  });
3938
4116
  }
3939
- return [2 /*return*/];
4117
+ return [3 /*break*/, 4];
4118
+ case 3:
4119
+ this._convertPhaseMs.handleGroup += performance.now() - t0;
4120
+ return [7 /*endfinally*/];
4121
+ case 4: return [2 /*return*/];
3940
4122
  }
3941
4123
  });
3942
4124
  });
@@ -3983,6 +4165,11 @@ var AcTrView2d = /** @class */ (function (_super) {
3983
4165
  AcTrView2d.prototype.stampEntityProcessingIdle = function () {
3984
4166
  if (this._numOfEntitiesToProcess === 0 && this._pendingGeometryJobs === 0) {
3985
4167
  this._entityProcessingIdleAt = performance.now();
4168
+ // Release block templates after INSERT convert/glyph work finishes.
4169
+ // Clearing at converter END was too early (convert still draining);
4170
+ // keeping templates until the next open kept baked shells in memory and
4171
+ // OOMed large drawings.
4172
+ AcDbRenderingCache.instance.clear();
3986
4173
  }
3987
4174
  };
3988
4175
  /**