@univerjs/docs 1.0.0-rc.0 → 1.0.1

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.
package/lib/es/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { AlignTypeH, BooleanNumber, BuildTextUtils, ColumnSeparatorType, CommandType, CustomCommandExecutionError, CustomRangeType, DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, DataStreamTreeTokenType, DeleteDirection, DependentOn, Disposable, DisposableCollection, DocumentDataModel, DocumentFlavor, DocxBreakType, DrawingTypeEnum, ErrorService, ICommandService, IConfigService, ILogService, IPermissionService, IResourceManagerService, IUndoRedoService, IUniverInstanceService, Inject, Injector, JSON1, JSONX, LocaleService, MemoryCursor, ObjectPermissionRuleModel, ObjectPermissionService, ObjectRelativeFromH, ObjectRelativeFromV, Optional, PAGE_SIZE, PageOrientType, PaperType, PermissionStatus, Plugin, PositionedObjectLayoutType, RESTORE_INSERTED_PARAGRAPH_IDS, RedoCommandId, RxDisposable, SectionType, TRADITIONAL_DOCUMENT_DEFAULT_MARGIN, TextX, TextXActionType, Tools, UndoCommandId, UniverInstanceType, UpdateDocsAttributeType, composeInterceptors, containsInteriorInsertionOffset, createIdentifier, createInterceptorKey, createParagraphId, createSectionId, generateRandomId, getBlockRangeInterval, getColumnGroupRangeInterval, getParagraphContentStartOffset, getParagraphContentStartOffsets, getRichTextEditPath, getSectionHeaderFooterReferenceKey, getTableRangeInterval, isInternalEditorID, merge, remove, requestImmediateMacroTask, resolveSectionHeaderFooterReference, toDisposable, validateDocBodyStructure, validateDocumentStructure } from "@univerjs/core";
2
- import { DocumentLayoutSession, DocumentSkeleton, DocumentViewModel, FontCache, IRenderManagerService, NORMAL_TEXT_SELECTION_PLUGIN_STYLE, getDocsCustomBlockRenderViewport, getFontStyleString, setDocsCustomBlockRenderViewportProvider } from "@univerjs/engine-render";
1
+ import { AlignTypeH, BooleanNumber, BuildTextUtils, ColumnSeparatorType, CommandType, CustomCommandExecutionError, CustomRangeType, DEFAULT_STYLES, DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, DataStreamTreeTokenType, DeleteDirection, DependentOn, Disposable, DisposableCollection, DocumentDataModel, DocumentFlavor, DocxBreakType, DrawingTypeEnum, ErrorService, ICommandService, IConfigService, ILogService, IPermissionService, IResourceManagerService, IUndoRedoService, IUniverInstanceService, Inject, Injector, JSON1, JSONX, LocaleService, MemoryCursor, ObjectPermissionRuleModel, ObjectPermissionService, ObjectRelativeFromH, ObjectRelativeFromV, Optional, PAGE_SIZE, PageOrientType, PaperType, PermissionStatus, Plugin, PositionedObjectLayoutType, RESTORE_INSERTED_PARAGRAPH_IDS, RedoCommandId, RxDisposable, SectionType, TRADITIONAL_DOCUMENT_DEFAULT_MARGIN, TextX, TextXActionType, Tools, UndoCommandId, UniverInstanceType, UpdateDocsAttributeType, composeInterceptors, containsInteriorInsertionOffset, createIdentifier, createInterceptorKey, createParagraphId, createSectionId, generateRandomId, getBlockRangeInterval, getColumnGroupRangeInterval, getParagraphContentStartOffset, getParagraphContentStartOffsets, getRichTextEditPath, getSdtBindingKey, getSdtBindingValue, getSectionHeaderFooterReferenceKey, getTableRangeInterval, isInternalEditorID, merge, remove, requestImmediateMacroTask, resolveSectionHeaderFooterReference, toDisposable, validateDocBodyStructure, validateDocumentStructure } from "@univerjs/core";
2
+ import { DocumentLayoutSession, DocumentSkeleton, DocumentViewModel, FontCache, IRenderManagerService, NORMAL_TEXT_SELECTION_PLUGIN_STYLE, getDocsCustomBlockRenderViewport, getDocumentLayoutPresentation, getFontStyleString, setDocsCustomBlockRenderViewportProvider } from "@univerjs/engine-render";
3
3
  import { BehaviorSubject, Observable, Subject, shareReplay, takeUntil } from "rxjs";
4
4
  import { UnitAction, UnitObject } from "@univerjs/protocol";
5
5
  import { ChannelService, fromModule, toModule } from "@univerjs/rpc";
@@ -14,7 +14,7 @@ const SetTextSelectionsOperation = {
14
14
  };
15
15
 
16
16
  //#endregion
17
- //#region \0@oxc-project+runtime@0.140.0/helpers/esm/typeof.js
17
+ //#region \0@oxc-project+runtime@0.149.0/helpers/esm/typeof.js
18
18
  function _typeof(o) {
19
19
  "@babel/helpers - typeof";
20
20
  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
@@ -25,7 +25,7 @@ function _typeof(o) {
25
25
  }
26
26
 
27
27
  //#endregion
28
- //#region \0@oxc-project+runtime@0.140.0/helpers/esm/toPrimitive.js
28
+ //#region \0@oxc-project+runtime@0.149.0/helpers/esm/toPrimitive.js
29
29
  function toPrimitive(t, r) {
30
30
  if ("object" != _typeof(t) || !t) return t;
31
31
  var e = t[Symbol.toPrimitive];
@@ -38,14 +38,14 @@ function toPrimitive(t, r) {
38
38
  }
39
39
 
40
40
  //#endregion
41
- //#region \0@oxc-project+runtime@0.140.0/helpers/esm/toPropertyKey.js
41
+ //#region \0@oxc-project+runtime@0.149.0/helpers/esm/toPropertyKey.js
42
42
  function toPropertyKey(t) {
43
43
  var i = toPrimitive(t, "string");
44
44
  return "symbol" == _typeof(i) ? i : i + "";
45
45
  }
46
46
 
47
47
  //#endregion
48
- //#region \0@oxc-project+runtime@0.140.0/helpers/esm/defineProperty.js
48
+ //#region \0@oxc-project+runtime@0.149.0/helpers/esm/defineProperty.js
49
49
  function _defineProperty(e, r, t) {
50
50
  return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
51
51
  value: t,
@@ -56,7 +56,7 @@ function _defineProperty(e, r, t) {
56
56
  }
57
57
 
58
58
  //#endregion
59
- //#region \0@oxc-project+runtime@0.140.0/helpers/esm/decorateParam.js
59
+ //#region \0@oxc-project+runtime@0.149.0/helpers/esm/decorateParam.js
60
60
  function __decorateParam(paramIndex, decorator) {
61
61
  return function(target, key) {
62
62
  decorator(target, key, paramIndex);
@@ -64,7 +64,7 @@ function __decorateParam(paramIndex, decorator) {
64
64
  }
65
65
 
66
66
  //#endregion
67
- //#region \0@oxc-project+runtime@0.140.0/helpers/esm/decorate.js
67
+ //#region \0@oxc-project+runtime@0.149.0/helpers/esm/decorate.js
68
68
  function __decorate(decorators, target, key, desc) {
69
69
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
70
70
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -291,9 +291,17 @@ function projectFooter(footer) {
291
291
  * the structured-clone boundary because they do not affect document geometry.
292
292
  */
293
293
  function createDocumentLayoutSnapshot(snapshot) {
294
- const { resources: _resources, body, headers, footers, ...layoutSnapshot } = snapshot;
294
+ const { resources: _resources, body, headers, footers, footnotes, endnotes, ...layoutSnapshot } = snapshot;
295
295
  return {
296
296
  ...layoutSnapshot,
297
+ ...footnotes == null ? {} : { footnotes: Object.fromEntries(Object.entries(footnotes).map(([id, note]) => [id, {
298
+ ...note,
299
+ body: projectDocumentBody(note.body)
300
+ }])) },
301
+ ...endnotes == null ? {} : { endnotes: Object.fromEntries(Object.entries(endnotes).map(([id, note]) => [id, {
302
+ ...note,
303
+ body: projectDocumentBody(note.body)
304
+ }])) },
297
305
  ...body == null ? {} : { body: projectDocumentBody(body) },
298
306
  ...headers == null ? {} : { headers: Object.fromEntries(Object.entries(headers).map(([headerId, header]) => [headerId, projectHeader(header)])) },
299
307
  ...footers == null ? {} : { footers: Object.fromEntries(Object.entries(footers).map(([footerId, footer]) => [footerId, projectFooter(footer)])) }
@@ -366,11 +374,15 @@ function isRichTextEditingMutationParams(value) {
366
374
  return typeof value === "object" && value != null && "unitId" in value && typeof value.unitId === "string" && "actions" in value;
367
375
  }
368
376
  function collectCustomBlockViewports(dataModel) {
369
- var _snapshot$body;
370
377
  const snapshot = dataModel.getSnapshot();
371
378
  const documentStyle = snapshot.documentStyle;
372
379
  const viewports = {};
373
- for (const customBlock of ((_snapshot$body = snapshot.body) === null || _snapshot$body === void 0 ? void 0 : _snapshot$body.customBlocks) ?? []) {
380
+ const bodies = [
381
+ snapshot.body,
382
+ ...Object.values(snapshot.headers ?? {}).map((header) => header.body),
383
+ ...Object.values(snapshot.footers ?? {}).map((footer) => footer.body)
384
+ ];
385
+ for (const customBlock of bodies.flatMap((body) => (body === null || body === void 0 ? void 0 : body.customBlocks) ?? [])) {
374
386
  var _snapshot$drawings, _documentStyle$pageSi;
375
387
  const drawing = (_snapshot$drawings = snapshot.drawings) === null || _snapshot$drawings === void 0 ? void 0 : _snapshot$drawings[customBlock.blockId];
376
388
  if (drawing == null) continue;
@@ -520,19 +532,21 @@ let DocLayoutExecutorService = _DocLayoutExecutorService = class DocLayoutExecut
520
532
  this._executorReady = executorReady;
521
533
  await executorReady;
522
534
  } catch (error) {
523
- const recoveryDiagnostic = error instanceof Error ? error.message : String(error);
524
- this._executor = null;
525
- this._executorReady = null;
526
- this._recoveryFailure = {
527
- diagnostic: recoveryDiagnostic,
528
- unitId
529
- };
530
- this._executorStatus$.next({
531
- state: "recovering",
532
- executor: executor.type,
533
- diagnostic: recoveryDiagnostic,
534
- recoveryUnitId: unitId
535
- });
535
+ if (this._executor === executor) {
536
+ const recoveryDiagnostic = error instanceof Error ? error.message : String(error);
537
+ this._executor = null;
538
+ this._executorReady = null;
539
+ this._recoveryFailure = {
540
+ diagnostic: recoveryDiagnostic,
541
+ unitId
542
+ };
543
+ this._executorStatus$.next({
544
+ state: "recovering",
545
+ executor: executor.type,
546
+ diagnostic: recoveryDiagnostic,
547
+ recoveryUnitId: unitId
548
+ });
549
+ }
536
550
  throw error;
537
551
  }
538
552
  }
@@ -557,7 +571,9 @@ let DocLayoutExecutorService = _DocLayoutExecutorService = class DocLayoutExecut
557
571
  let session = this._sessions.get(unitId);
558
572
  if (session != null && session.sourceMutationRevision !== dataModel.getMutationRevision()) session.needsResnapshot = true;
559
573
  if (session == null || session.needsResnapshot) session = await this._replaceSession(dataModel);
574
+ if (session.disposed || this._executor !== executor || this._getEligibleModel(unitId) !== dataModel) return null;
560
575
  let result = await this._startSynchronizedLayout(executor, session, identity, options, budgetMs);
576
+ if (session.disposed || this._executor !== executor || this._getEligibleModel(unitId) !== dataModel) return null;
561
577
  if (result.status === "not-found" || result.status === "resnapshot-required") {
562
578
  session = await this._replaceSession(dataModel);
563
579
  result = await this._startSynchronizedLayout(executor, session, identity, options, budgetMs);
@@ -595,7 +611,7 @@ let DocLayoutExecutorService = _DocLayoutExecutorService = class DocLayoutExecut
595
611
  unitId,
596
612
  sessionEpoch: session.sessionEpoch
597
613
  }).catch((error) => {
598
- this._logService.error("[DocLayoutExecutorService]: failed to dispose a Worker session.", error);
614
+ if (this._executor === executor) this._logService.error("[DocLayoutExecutorService]: failed to dispose a Worker session.", error);
599
615
  });
600
616
  }
601
617
  this._sessions.clear();
@@ -685,6 +701,7 @@ let DocLayoutExecutorService = _DocLayoutExecutorService = class DocLayoutExecut
685
701
  return result;
686
702
  });
687
703
  session.queue = startTask.then(() => void 0, (error) => {
704
+ if (session.disposed || this._executor !== executor) return;
688
705
  session.needsResnapshot = true;
689
706
  this._logService.error("[DocLayoutExecutorService]: synchronized layout start failed.", error);
690
707
  });
@@ -738,23 +755,25 @@ let DocLayoutExecutorService = _DocLayoutExecutorService = class DocLayoutExecut
738
755
  try {
739
756
  await createTask;
740
757
  } catch (error) {
741
- session.needsResnapshot = true;
742
- throw error;
758
+ if (!session.disposed && this._executor === executor) {
759
+ session.needsResnapshot = true;
760
+ throw error;
761
+ }
743
762
  }
744
763
  return session;
745
764
  }
746
765
  _disposeSession(unitId) {
747
- var _this$_executor3;
748
766
  const session = this._sessions.get(unitId);
749
767
  if (session == null) return;
750
768
  this._markSessionDisposed(session);
751
769
  this._sessions.delete(unitId);
752
770
  this._hydrationSamples.delete(unitId);
753
- (_this$_executor3 = this._executor) === null || _this$_executor3 === void 0 || _this$_executor3.disposeSession({
771
+ const executor = this._executor;
772
+ executor === null || executor === void 0 || executor.disposeSession({
754
773
  unitId,
755
774
  sessionEpoch: session.sessionEpoch
756
775
  }).catch((error) => {
757
- this._logService.error("[DocLayoutExecutorService]: failed to dispose a Worker session.", error);
776
+ if (this._executor === executor) this._logService.error("[DocLayoutExecutorService]: failed to dispose a Worker session.", error);
758
777
  });
759
778
  }
760
779
  _getEligibleModel(unitId) {
@@ -910,7 +929,7 @@ let DocSkeletonManagerService = class DocSkeletonManagerService extends RxDispos
910
929
  supportsIncrementalLayout() {
911
930
  var _this$_context$unit$g;
912
931
  const documentFlavor = (_this$_context$unit$g = this._context.unit.getSnapshot().documentStyle) === null || _this$_context$unit$g === void 0 ? void 0 : _this$_context$unit$g.documentFlavor;
913
- return this._docLayoutExecutorService.getExecutor() != null && !isInternalEditorID(this._context.unitId) && (documentFlavor === DocumentFlavor.TRADITIONAL || documentFlavor === DocumentFlavor.MODERN);
932
+ return this._docLayoutExecutorService.getExecutor() != null && !isInternalEditorID(this._context.unitId) && !getDocumentLayoutPresentation(this._context.unit) && (documentFlavor === DocumentFlavor.TRADITIONAL || documentFlavor === DocumentFlavor.MODERN);
914
933
  }
915
934
  recalculate() {
916
935
  const skeleton = this._skeleton;
@@ -1068,23 +1087,136 @@ function getSegmentType(documentDataModel, segmentId) {
1068
1087
  if ((_documentDataModel$ge = documentDataModel.getSnapshot().notes) === null || _documentDataModel$ge === void 0 ? void 0 : _documentDataModel$ge[segmentId]) return "note";
1069
1088
  return "body";
1070
1089
  }
1071
- function assertValidDocBodyStructure(documentDataModel, segmentId) {
1090
+ function getSnapshotBody(snapshot, segmentId) {
1091
+ var _snapshot$headers, _snapshot$footers, _snapshot$notes;
1092
+ if (!segmentId) return snapshot.body;
1093
+ return ((_snapshot$headers = snapshot.headers) === null || _snapshot$headers === void 0 || (_snapshot$headers = _snapshot$headers[segmentId]) === null || _snapshot$headers === void 0 ? void 0 : _snapshot$headers.body) ?? ((_snapshot$footers = snapshot.footers) === null || _snapshot$footers === void 0 || (_snapshot$footers = _snapshot$footers[segmentId]) === null || _snapshot$footers === void 0 ? void 0 : _snapshot$footers.body) ?? ((_snapshot$notes = snapshot.notes) === null || _snapshot$notes === void 0 || (_snapshot$notes = _snapshot$notes[segmentId]) === null || _snapshot$notes === void 0 ? void 0 : _snapshot$notes.body);
1094
+ }
1095
+ function containsTextXEdit(actions) {
1096
+ const cursor = JSON1.type.readCursor(actions);
1097
+ let found = false;
1098
+ cursor.traverse(null, (component) => {
1099
+ if (component.et === TextX.id) found = true;
1100
+ });
1101
+ return found;
1102
+ }
1103
+ function subtractBaselineIssues(issues, baseline) {
1104
+ const counts = /* @__PURE__ */ new Map();
1105
+ baseline.forEach((issue) => counts.set(issue.code, (counts.get(issue.code) ?? 0) + 1));
1106
+ return issues.filter((issue) => {
1107
+ const count = counts.get(issue.code) ?? 0;
1108
+ if (count === 0) return true;
1109
+ counts.set(issue.code, count - 1);
1110
+ return false;
1111
+ });
1112
+ }
1113
+ function assertValidDocBodyStructure(documentDataModel, segmentId, undoActions) {
1072
1114
  var _documentDataModel$ge2;
1073
1115
  const segmentModel = documentDataModel.getSelfOrHeaderFooterModel(segmentId);
1074
1116
  const body = segmentModel === null || segmentModel === void 0 ? void 0 : segmentModel.getBody();
1075
1117
  if (!body) return;
1076
1118
  const segmentType = getSegmentType(documentDataModel, segmentId);
1119
+ const context = {
1120
+ segmentType,
1121
+ segmentId: segmentId || void 0
1122
+ };
1077
1123
  const note = (_documentDataModel$ge2 = documentDataModel.getSnapshot().notes) === null || _documentDataModel$ge2 === void 0 ? void 0 : _documentDataModel$ge2[segmentId];
1078
1124
  const issues = note ? validateDocumentStructure({ notes: { [segmentId]: note } }) : validateDocBodyStructure(body, {
1079
1125
  segmentType,
1080
1126
  segmentId: segmentId || void 0
1081
1127
  });
1082
1128
  if (!issues.length) return;
1083
- const detail = issues.map((issue) => `${issue.code}${issue.index == null ? "" : `@${issue.index}`}`).join(", ");
1129
+ const snapshot = Tools.deepClone(documentDataModel.getSnapshot());
1130
+ const baselineBody = getSnapshotBody(JSONX.apply(snapshot, undoActions), segmentId);
1131
+ const newIssues = baselineBody ? subtractBaselineIssues(issues, validateDocBodyStructure(baselineBody, context)) : issues;
1132
+ if (!newIssues.length) return;
1133
+ const detail = newIssues.map((issue) => `${issue.code}${issue.index == null ? "" : `@${issue.index}`}`).join(", ");
1084
1134
  const segmentLabel = segmentId ? `${segmentType} ${segmentId}` : segmentType;
1085
1135
  throw new Error(`[DocStructure] ${segmentLabel}: ${detail}`);
1086
1136
  }
1087
- function validateDocStructureMutation(documentDataModel, segmentId, actions, undoActions) {
1137
+ function getLockedSdtContent(body, range) {
1138
+ var _range$properties;
1139
+ if (((_range$properties = range.properties) === null || _range$properties === void 0 ? void 0 : _range$properties.kind) !== "group") return body.dataStream.slice(range.startIndex, range.endIndex + 1);
1140
+ const children = (body.customRanges ?? []).filter((child) => child.rangeType === CustomRangeType.SDT && child.rangeId !== range.rangeId && child.startIndex >= range.startIndex && child.endIndex <= range.endIndex).sort((left, right) => {
1141
+ const position = left.startIndex - right.startIndex || right.endIndex - left.endIndex;
1142
+ if (position || left.rangeId === right.rangeId) return position;
1143
+ return left.rangeId < right.rangeId ? -1 : 1;
1144
+ });
1145
+ const protectedContent = [];
1146
+ let offset = range.startIndex;
1147
+ for (const child of children) {
1148
+ if (child.startIndex < offset) continue;
1149
+ protectedContent.push(body.dataStream.slice(offset, child.startIndex), child.rangeId);
1150
+ offset = child.endIndex + 1;
1151
+ }
1152
+ protectedContent.push(body.dataStream.slice(offset, range.endIndex + 1));
1153
+ return JSON.stringify(protectedContent);
1154
+ }
1155
+ function getRepeatingItemIds(body, section) {
1156
+ const ranges = body.customRanges ?? [];
1157
+ const sectionIndex = ranges.indexOf(section);
1158
+ const nestedSections = ranges.filter((range, index) => {
1159
+ var _range$properties2;
1160
+ return range.rangeType === CustomRangeType.SDT && ((_range$properties2 = range.properties) === null || _range$properties2 === void 0 ? void 0 : _range$properties2.kind) === "repeatingSection" && range.rangeId !== section.rangeId && range.startIndex >= section.startIndex && range.endIndex <= section.endIndex && (range.startIndex > section.startIndex || range.endIndex < section.endIndex || index < sectionIndex);
1161
+ });
1162
+ return ranges.filter((range, index) => {
1163
+ var _range$properties3;
1164
+ return range.rangeType === CustomRangeType.SDT && ((_range$properties3 = range.properties) === null || _range$properties3 === void 0 ? void 0 : _range$properties3.kind) === "repeatingSectionItem" && range.startIndex >= section.startIndex && range.endIndex <= section.endIndex && !nestedSections.some((nested) => nested.startIndex <= range.startIndex && range.endIndex <= nested.endIndex && (nested.startIndex < range.startIndex || range.endIndex < nested.endIndex || index < ranges.indexOf(nested)));
1165
+ }).map((range) => range.rangeId).sort();
1166
+ }
1167
+ function isDocSdtMutationAllowed(documentDataModel, segmentId, actions) {
1168
+ var _previousBody$customR;
1169
+ if (!containsTextXEdit(actions) && isStructurePreservingJSONXEdit(actions, getRichTextEditPath(documentDataModel, segmentId))) return true;
1170
+ const snapshot = documentDataModel.getSnapshot();
1171
+ const previousBody = getSnapshotBody(snapshot, segmentId);
1172
+ const lockedRanges = previousBody === null || previousBody === void 0 || (_previousBody$customR = previousBody.customRanges) === null || _previousBody$customR === void 0 ? void 0 : _previousBody$customR.filter((range) => {
1173
+ var _range$properties4, _range$properties5, _range$properties$rep;
1174
+ return range.rangeType === CustomRangeType.SDT && (((_range$properties4 = range.properties) === null || _range$properties4 === void 0 ? void 0 : _range$properties4.lock) && range.properties.lock !== "unlocked" || ((_range$properties5 = range.properties) === null || _range$properties5 === void 0 ? void 0 : _range$properties5.kind) === "repeatingSection" && ((_range$properties$rep = range.properties.repeatingSection) === null || _range$properties$rep === void 0 ? void 0 : _range$properties$rep.doNotAllowInsertDelete));
1175
+ });
1176
+ if (!previousBody || !(lockedRanges === null || lockedRanges === void 0 ? void 0 : lockedRanges.length)) return true;
1177
+ const candidate = JSONX.apply(Tools.deepClone(snapshot), actions);
1178
+ const currentBody = getSnapshotBody(candidate, segmentId);
1179
+ for (const previous of lockedRanges) {
1180
+ var _previous$properties, _currentBody$customRa, _previous$properties2, _previous$properties$;
1181
+ const lock = (_previous$properties = previous.properties) === null || _previous$properties === void 0 ? void 0 : _previous$properties.lock;
1182
+ const current = currentBody === null || currentBody === void 0 || (_currentBody$customRa = currentBody.customRanges) === null || _currentBody$customRa === void 0 ? void 0 : _currentBody$customRa.find((range) => range.rangeId === previous.rangeId && range.rangeType === CustomRangeType.SDT);
1183
+ const wrapperLocked = lock === "sdtLocked" || lock === "sdtContentLocked";
1184
+ const contentLocked = lock === "contentLocked" || lock === "sdtContentLocked";
1185
+ if (wrapperLocked && !current) return false;
1186
+ if (((_previous$properties2 = previous.properties) === null || _previous$properties2 === void 0 ? void 0 : _previous$properties2.kind) === "repeatingSection" && ((_previous$properties$ = previous.properties.repeatingSection) === null || _previous$properties$ === void 0 ? void 0 : _previous$properties$.doNotAllowInsertDelete) && current && currentBody) {
1187
+ const before = getRepeatingItemIds(previousBody, previous);
1188
+ const after = getRepeatingItemIds(currentBody, current);
1189
+ if (before.length !== after.length || before.some((id, index) => id !== after[index])) return false;
1190
+ }
1191
+ if (contentLocked && current && currentBody) {
1192
+ if (getLockedSdtContent(previousBody, previous) !== getLockedSdtContent(currentBody, current) && !isBoundSdtValueUpdate(snapshot, candidate, previous, current, currentBody)) return false;
1193
+ }
1194
+ }
1195
+ return true;
1196
+ }
1197
+ function isBoundSdtValueUpdate(before, after, previous, current, currentBody) {
1198
+ const key = getSdtBindingKey(previous);
1199
+ const value = getSdtBindingValue(currentBody, current);
1200
+ if (!key || key !== getSdtBindingKey(current) || value === void 0) return false;
1201
+ return [
1202
+ "",
1203
+ ...Object.keys(before.headers ?? {}),
1204
+ ...Object.keys(before.footers ?? {}),
1205
+ ...Object.keys(before.notes ?? {})
1206
+ ].some((segmentId) => {
1207
+ var _previousBody$customR2;
1208
+ const previousBody = getSnapshotBody(before, segmentId);
1209
+ const nextBody = getSnapshotBody(after, segmentId);
1210
+ if (!previousBody || !nextBody) return false;
1211
+ return ((_previousBody$customR2 = previousBody.customRanges) === null || _previousBody$customR2 === void 0 ? void 0 : _previousBody$customR2.some((range) => {
1212
+ var _range$properties6, _range$properties7, _nextBody$customRange;
1213
+ if (range.rangeType !== CustomRangeType.SDT || ((_range$properties6 = range.properties) === null || _range$properties6 === void 0 ? void 0 : _range$properties6.lock) === "contentLocked" || ((_range$properties7 = range.properties) === null || _range$properties7 === void 0 ? void 0 : _range$properties7.lock) === "sdtContentLocked" || getSdtBindingKey(range) !== key) return false;
1214
+ const next = (_nextBody$customRange = nextBody.customRanges) === null || _nextBody$customRange === void 0 ? void 0 : _nextBody$customRange.find((item) => item.rangeType === CustomRangeType.SDT && item.rangeId === range.rangeId);
1215
+ return next != null && getSdtBindingKey(next) === key && getSdtBindingValue(previousBody, range) !== value && getSdtBindingValue(nextBody, next) === value;
1216
+ })) ?? false;
1217
+ });
1218
+ }
1219
+ function validateDocStructureMutation(documentDataModel, segmentId, actions, undoActions, isHistoryReplay = false) {
1088
1220
  const editPath = getRichTextEditPath(documentDataModel, segmentId);
1089
1221
  const preservesStructure = isStructurePreservingJSONXEdit(actions, editPath) && isStructurePreservingJSONXEdit(undoActions, editPath);
1090
1222
  let changesFootnoteStructure = false;
@@ -1093,6 +1225,7 @@ function validateDocStructureMutation(documentDataModel, segmentId, actions, und
1093
1225
  const path = cursor.getPath();
1094
1226
  if (path[0] === "notes" && (path.length <= 2 || path[2] !== "body") || path.includes("customRanges")) changesFootnoteStructure = true;
1095
1227
  if (component.et === TextX.id && Array.isArray(component.e)) for (const action of component.e) {
1228
+ if (isRecord$3(action) && Array.isArray(action.rangeUpdates) && action.rangeUpdates.some((update) => isRecord$3(update) && isRecord$3(update.range) && (update.range.rangeType === CustomRangeType.FOOTNOTE || update.range.rangeType === CustomRangeType.ENDNOTE))) changesFootnoteStructure = true;
1096
1229
  const ranges = isRecord$3(action) && isRecord$3(action.body) ? action.body.customRanges : void 0;
1097
1230
  if (Array.isArray(ranges) && ranges.some((range) => isRecord$3(range) && (range.rangeType === CustomRangeType.FOOTNOTE || range.rangeType === CustomRangeType.ENDNOTE))) changesFootnoteStructure = true;
1098
1231
  }
@@ -1100,7 +1233,7 @@ function validateDocStructureMutation(documentDataModel, segmentId, actions, und
1100
1233
  if (changesFootnoteStructure) {
1101
1234
  const issues = validateDocumentStructure(documentDataModel.getSnapshot());
1102
1235
  if (issues.length > 0) throw new Error(`[DocStructure] ${issues.map((issue) => `${issue.code}@${issue.index ?? issue.segmentId ?? ""}`).join(", ")}`);
1103
- } else if (!preservesStructure) assertValidDocBodyStructure(documentDataModel, segmentId);
1236
+ } else if (!preservesStructure && !isHistoryReplay) assertValidDocBodyStructure(documentDataModel, segmentId, undoActions);
1104
1237
  return preservesStructure && !changesFootnoteStructure;
1105
1238
  }
1106
1239
 
@@ -1156,12 +1289,12 @@ function canRemoveFootnoteReference(actions, references) {
1156
1289
  if (path.length === 1 && component.et === TextX.id && Array.isArray(component.e)) {
1157
1290
  let offset = 0;
1158
1291
  for (const action of component.e) {
1159
- var _action$body;
1292
+ var _action$body, _action$rangeUpdates;
1160
1293
  if (action.t === TextXActionType.DELETE && references.some((reference) => offset <= reference.endIndex && offset + action.len > reference.startIndex)) {
1161
1294
  canRemove = true;
1162
1295
  return;
1163
1296
  }
1164
- if (action.t === TextXActionType.RETAIN && ((_action$body = action.body) === null || _action$body === void 0 ? void 0 : _action$body.customRanges) != null) {
1297
+ if (action.t === TextXActionType.RETAIN && (((_action$body = action.body) === null || _action$body === void 0 ? void 0 : _action$body.customRanges) != null || ((_action$rangeUpdates = action.rangeUpdates) === null || _action$rangeUpdates === void 0 ? void 0 : _action$rangeUpdates.some((update) => references.some((reference) => reference.rangeId === update.rangeId))))) {
1165
1298
  canRemove = true;
1166
1299
  return;
1167
1300
  }
@@ -1192,7 +1325,7 @@ function includeFootnoteCleanup(before, actions) {
1192
1325
  }
1193
1326
  return JSONX.isNoop(cleanup) ? actions : JSONX.compose(actions, cleanup);
1194
1327
  }
1195
- function applyValidatedDocumentActions(documentDataModel, segmentId, actions) {
1328
+ function applyValidatedDocumentActions(documentDataModel, segmentId, actions, isHistoryReplay = false) {
1196
1329
  const before = documentDataModel.getSnapshot();
1197
1330
  const appliedActions = includeFootnoteCleanup(before, actions);
1198
1331
  const undoActions = JSONX.invertWithDoc(appliedActions, before);
@@ -1201,7 +1334,7 @@ function applyValidatedDocumentActions(documentDataModel, segmentId, actions) {
1201
1334
  return {
1202
1335
  actions: appliedActions,
1203
1336
  undoActions,
1204
- preservesStructure: validateDocStructureMutation(documentDataModel, segmentId, appliedActions, undoActions)
1337
+ preservesStructure: validateDocStructureMutation(documentDataModel, segmentId, appliedActions, undoActions, isHistoryReplay)
1205
1338
  };
1206
1339
  } catch (error) {
1207
1340
  documentDataModel.apply(undoActions);
@@ -1268,7 +1401,27 @@ const RichTextEditingMutation = {
1268
1401
  actions: [],
1269
1402
  textRanges: docRanges
1270
1403
  };
1271
- const { actions: appliedActions, undoActions, preservesStructure } = applyValidatedDocumentActions(documentDataModel, segmentId, actions);
1404
+ const isHistoryReplay = trigger === UndoCommandId || trigger === RedoCommandId;
1405
+ if (!isHistoryReplay && !isDocSdtMutationAllowed(documentDataModel, segmentId, actions)) {
1406
+ params.actions = [];
1407
+ return {
1408
+ unitId,
1409
+ actions: [],
1410
+ textRanges: docRanges
1411
+ };
1412
+ }
1413
+ const presentation = getDocumentLayoutPresentation(documentDataModel);
1414
+ const previousLayoutState = presentation === null || presentation === void 0 ? void 0 : presentation.captureState();
1415
+ const { actions: appliedActions, undoActions, preservesStructure } = applyValidatedDocumentActions(documentDataModel, segmentId, actions, isHistoryReplay);
1416
+ if (presentation) try {
1417
+ if (params.layoutState !== void 0) presentation.restoreState(params.layoutState);
1418
+ else presentation.applyActions(appliedActions, documentDataModel.getSnapshot());
1419
+ params.layoutState = presentation.captureState();
1420
+ } catch (error) {
1421
+ documentDataModel.apply(undoActions);
1422
+ presentation.restoreState(previousLayoutState);
1423
+ throw error;
1424
+ }
1272
1425
  params.actions = appliedActions;
1273
1426
  resetDocumentViewModel(documentViewModel, documentDataModel, segmentId, appliedActions, preservesStructure);
1274
1427
  scheduleDocumentSelectionUpdate(docSelectionManagerService, params, isSync);
@@ -1280,12 +1433,14 @@ const RichTextEditingMutation = {
1280
1433
  noHistory,
1281
1434
  debounce,
1282
1435
  redoState: {
1436
+ ...presentation ? { layoutState: params.layoutState } : {},
1283
1437
  actions: appliedActions,
1284
1438
  textRanges,
1285
1439
  options: params.options,
1286
1440
  isEditing
1287
1441
  },
1288
1442
  undoState: {
1443
+ ...presentation ? { layoutState: previousLayoutState } : {},
1289
1444
  actions: undoActions,
1290
1445
  textRanges: prevTextRanges ?? docRanges,
1291
1446
  options: selectionInfo === null || selectionInfo === void 0 ? void 0 : selectionInfo.options,
@@ -1299,6 +1454,7 @@ const RichTextEditingMutation = {
1299
1454
  return {
1300
1455
  unitId,
1301
1456
  actions: undoActions,
1457
+ ...presentation ? { layoutState: previousLayoutState } : {},
1302
1458
  textRanges: docRanges
1303
1459
  };
1304
1460
  }
@@ -1415,7 +1571,7 @@ const DeleteTextCommand = {
1415
1571
  startOffset: start,
1416
1572
  endOffset: end + 1,
1417
1573
  collapsed: false
1418
- }], body));
1574
+ }], body, 0, null, true, docDataModel.getDocumentStyle().documentFlavor));
1419
1575
  const path = getRichTextEditPath(docDataModel, segmentId);
1420
1576
  doMutation.params.actions = appendRemovedDrawingActions(jsonX.editOp(textX.serialize(), path), docDataModel, body, start, end + 1, segmentId);
1421
1577
  const result = commandService.syncExecuteCommand(doMutation.id, doMutation.params);
@@ -2624,7 +2780,7 @@ function composeActions(actions) {
2624
2780
  //#endregion
2625
2781
  //#region package.json
2626
2782
  var name = "@univerjs/docs";
2627
- var version = "1.0.0-rc.0";
2783
+ var version = "1.0.1";
2628
2784
 
2629
2785
  //#endregion
2630
2786
  //#region src/config/config.ts
@@ -3252,6 +3408,20 @@ let DocStateChangeManagerService = class DocStateChangeManagerService extends Rx
3252
3408
  this._initialize();
3253
3409
  this._listenDocStateChange();
3254
3410
  }
3411
+ dispose() {
3412
+ if (this._historyTimer != null) {
3413
+ clearTimeout(this._historyTimer);
3414
+ this._historyTimer = null;
3415
+ }
3416
+ if (this._changeStateCacheTimer != null) {
3417
+ clearTimeout(this._changeStateCacheTimer);
3418
+ this._changeStateCacheTimer = null;
3419
+ }
3420
+ this._historyStateCache.clear();
3421
+ this._changeStateCache.clear();
3422
+ this._docStateChange$.complete();
3423
+ super.dispose();
3424
+ }
3255
3425
  getStateCache(unitId) {
3256
3426
  return {
3257
3427
  history: this._historyStateCache.get(unitId) ?? [],
@@ -3265,6 +3435,10 @@ let DocStateChangeManagerService = class DocStateChangeManagerService extends Rx
3265
3435
  clearHistory(unitId) {
3266
3436
  this._historyStateCache.delete(unitId);
3267
3437
  }
3438
+ flushPendingChanges(unitId) {
3439
+ this._pushHistory(unitId);
3440
+ this._emitChangeState(unitId);
3441
+ }
3268
3442
  _setChangeState(changeState) {
3269
3443
  this._cacheChangeState(changeState, "history");
3270
3444
  this._cacheChangeState(changeState, "collaboration");
@@ -3303,18 +3477,19 @@ let DocStateChangeManagerService = class DocStateChangeManagerService extends Rx
3303
3477
  const cacheStates = stateCache.get(unitId);
3304
3478
  cacheStates === null || cacheStates === void 0 || cacheStates.push(changeState);
3305
3479
  } else stateCache.set(unitId, [changeState]);
3306
- if (debounce) if (type === "history") {
3307
- if (this._historyTimer) clearTimeout(this._historyTimer);
3308
- this._historyTimer = setTimeout(() => {
3309
- cb(unitId);
3310
- }, DEBOUNCE_DELAY);
3311
- } else {
3312
- if (this._changeStateCacheTimer) clearTimeout(this._changeStateCacheTimer);
3313
- this._changeStateCacheTimer = setTimeout(() => {
3314
- cb(unitId);
3315
- }, DEBOUNCE_DELAY);
3316
- }
3317
- else cb(unitId);
3480
+ if (debounce) {
3481
+ if (type === "history") {
3482
+ if (this._historyTimer) clearTimeout(this._historyTimer);
3483
+ this._historyTimer = setTimeout(() => {
3484
+ cb(unitId);
3485
+ }, DEBOUNCE_DELAY);
3486
+ } else {
3487
+ if (this._changeStateCacheTimer) clearTimeout(this._changeStateCacheTimer);
3488
+ this._changeStateCacheTimer = setTimeout(() => {
3489
+ cb(unitId);
3490
+ }, DEBOUNCE_DELAY);
3491
+ }
3492
+ } else cb(unitId);
3318
3493
  }
3319
3494
  _pushHistory(unitId) {
3320
3495
  const undoRedoService = this._undoRedoService;
@@ -3326,6 +3501,8 @@ let DocStateChangeManagerService = class DocStateChangeManagerService extends Rx
3326
3501
  const lastState = cacheStates[len - 1];
3327
3502
  const redoParams = {
3328
3503
  unitId,
3504
+ trigger: RedoCommandId,
3505
+ ...lastState.redoState.layoutState === void 0 ? {} : { layoutState: lastState.redoState.layoutState },
3329
3506
  actions: cacheStates.reduce((acc, cur) => JSONX.compose(acc, cur.redoState.actions), null),
3330
3507
  textRanges: lastState.redoState.textRanges,
3331
3508
  segmentId: lastState.segmentId,
@@ -3334,6 +3511,8 @@ let DocStateChangeManagerService = class DocStateChangeManagerService extends Rx
3334
3511
  };
3335
3512
  const undoParams = {
3336
3513
  unitId,
3514
+ trigger: UndoCommandId,
3515
+ ...firstState.undoState.layoutState === void 0 ? {} : { layoutState: firstState.undoState.layoutState },
3337
3516
  actions: cacheStates.reverse().reduce((acc, cur) => JSONX.compose(acc, cur.undoState.actions), null),
3338
3517
  textRanges: firstState.undoState.textRanges,
3339
3518
  segmentId: firstState.segmentId,
@@ -3487,6 +3666,25 @@ let UniverDocsPlugin = class UniverDocsPlugin extends Plugin {
3487
3666
  this.disposeWithMe(this._injector.get(ObjectPermissionService).registerRuleModel(UnitObject.Document, this._injector.get(DocumentPermissionRuleModel), SetDocumentPermissionRuleMutation.id, SetDocumentPermissionRulesMutation.id));
3488
3667
  this._initializeDependencies();
3489
3668
  this._initializeCommands();
3669
+ this._initializeWordResources();
3670
+ }
3671
+ _initializeWordResources() {
3672
+ for (const pluginName of ["DOC_WORD_STYLES_PLUGIN", "DOC_NOTE_PLUGIN"]) {
3673
+ const resources = /* @__PURE__ */ new Map();
3674
+ this.disposeWithMe({ dispose: () => resources.clear() });
3675
+ this.disposeWithMe(this._injector.get(IResourceManagerService).registerPluginResource({
3676
+ pluginName,
3677
+ businesses: [UniverInstanceType.UNIVER_DOC],
3678
+ parseJson: (data) => data,
3679
+ onLoad: (unitId, data) => {
3680
+ resources.set(unitId, data);
3681
+ },
3682
+ onUnLoad: (unitId) => {
3683
+ resources.delete(unitId);
3684
+ },
3685
+ toJson: (unitId) => resources.get(unitId) ?? ""
3686
+ }));
3687
+ }
3490
3688
  }
3491
3689
  _initializeCommands() {
3492
3690
  [
@@ -3585,6 +3783,12 @@ function collectDocumentFontFamilies(value, families) {
3585
3783
  }
3586
3784
  return;
3587
3785
  }
3786
+ const textStyle = value;
3787
+ if (typeof textStyle.eastAsiaFontFamily === "string" && textStyle.eastAsiaFontFamily.trim()) {
3788
+ const primary = typeof textStyle.ff === "string" && textStyle.ff.trim() ? textStyle.ff : DEFAULT_STYLES.ff;
3789
+ families.add(`${primary}, ${textStyle.eastAsiaFontFamily.trim()}`);
3790
+ families.add(`${textStyle.eastAsiaFontFamily.trim()}, ${primary}, ${textStyle.eastAsiaFontFamily.trim()}`);
3791
+ }
3588
3792
  for (const [key, item] of Object.entries(value)) if (key === "ff" && typeof item === "string") families.add(item);
3589
3793
  else collectDocumentFontFamilies(item, families);
3590
3794
  }
@@ -3598,6 +3802,53 @@ function measureDocumentFontFamilies(families) {
3598
3802
  return FontCache.getNormalLineHeightCache();
3599
3803
  }
3600
3804
 
3805
+ //#endregion
3806
+ //#region src/layout-worker/font-loader.ts
3807
+ /** Owns the same explicitly supplied font faces in the rendering and layout realms. */
3808
+ var DocsLayoutFontLoader = class extends Disposable {
3809
+ constructor(..._args) {
3810
+ super(..._args);
3811
+ _defineProperty(this, "_loading", null);
3812
+ _defineProperty(this, "_fontSet", void 0);
3813
+ _defineProperty(this, "_faces", []);
3814
+ }
3815
+ load(fonts) {
3816
+ this._loading ??= this._load(fonts);
3817
+ return this._loading;
3818
+ }
3819
+ dispose() {
3820
+ for (const face of this._faces) {
3821
+ var _this$_fontSet;
3822
+ (_this$_fontSet = this._fontSet) === null || _this$_fontSet === void 0 || _this$_fontSet.delete(face);
3823
+ }
3824
+ if (this._faces.length > 0) FontCache.invalidateMetrics(() => true);
3825
+ this._faces = [];
3826
+ this._fontSet = void 0;
3827
+ super.dispose();
3828
+ }
3829
+ async _load(fonts) {
3830
+ this.ensureNotDisposed();
3831
+ if (fonts.length === 0) return;
3832
+ const fontSet = typeof document === "undefined" ? globalThis.fonts : document.fonts;
3833
+ if (typeof FontFace === "undefined" || fontSet == null) throw new Error("Document layout requires FontFace support to load the configured fonts.");
3834
+ try {
3835
+ const faces = fonts.map(({ family, source, descriptors }) => {
3836
+ if (!family.trim() || (typeof source === "string" ? !source.trim() : source.byteLength === 0)) throw new TypeError("Document layout font family and source must not be empty.");
3837
+ return new FontFace(family, source, descriptors);
3838
+ });
3839
+ await Promise.all(faces.map((face) => face.load()));
3840
+ this.ensureNotDisposed();
3841
+ this._fontSet = fontSet;
3842
+ this._faces = faces;
3843
+ for (const face of faces) fontSet.add(face);
3844
+ FontCache.invalidateMetrics(() => true);
3845
+ } catch (error) {
3846
+ this.dispose();
3847
+ throw error;
3848
+ }
3849
+ }
3850
+ };
3851
+
3601
3852
  //#endregion
3602
3853
  //#region src/layout-worker/performance-tracker.ts
3603
3854
  const PERFORMANCE_SAMPLE_LIMIT = 2048;
@@ -3710,10 +3961,11 @@ var DocsLayoutWorkerRuntime = class {
3710
3961
  constructor(_performanceTracker = new DocsLayoutWorkerPerformanceTracker()) {
3711
3962
  this._performanceTracker = _performanceTracker;
3712
3963
  _defineProperty(this, "_sessions", /* @__PURE__ */ new Map());
3964
+ _defineProperty(this, "_fontLoader", new DocsLayoutFontLoader());
3713
3965
  _defineProperty(this, "type", "worker");
3714
3966
  }
3715
- initialize() {
3716
- return Promise.resolve();
3967
+ initialize(fontFaces = []) {
3968
+ return this._fontLoader.load(fontFaces);
3717
3969
  }
3718
3970
  async getCapabilities() {
3719
3971
  const metrics = FontCache.getMeasureText(FONT_PROBE_CONTENT, FONT_PROBE_STYLE);
@@ -3801,7 +4053,9 @@ var DocsLayoutWorkerRuntime = class {
3801
4053
  reason: request.reason,
3802
4054
  anchor: request.anchor,
3803
4055
  priorityAnchor: request.priorityAnchor,
3804
- invalidation: request.invalidation
4056
+ invalidation: request.invalidation,
4057
+ modernPageWidth: request.modernPageWidth,
4058
+ modernHorizontalMargin: request.modernHorizontalMargin
3805
4059
  });
3806
4060
  mount.activeGeneration = generation;
3807
4061
  mount.cancelledGeneration = null;
@@ -3923,6 +4177,7 @@ var DocsLayoutWorkerRuntime = class {
3923
4177
  this._performanceTracker.reset(request.unitId);
3924
4178
  }
3925
4179
  dispose() {
4180
+ this._fontLoader.dispose();
3926
4181
  for (const unitId of this._sessions.keys()) this._disposeSession(unitId);
3927
4182
  this._performanceTracker.resetAll();
3928
4183
  }
@@ -3980,10 +4235,21 @@ var DocsLayoutWorkerRuntime = class {
3980
4235
  session.localeService.dispose();
3981
4236
  }
3982
4237
  };
4238
+ var DocsLayoutWorkerChannelService = class extends ChannelService {
4239
+ constructor(protocol, _runtime) {
4240
+ super(protocol);
4241
+ this._runtime = _runtime;
4242
+ }
4243
+ dispose() {
4244
+ this._runtime.dispose();
4245
+ super.dispose();
4246
+ }
4247
+ };
3983
4248
  function startDocsLayoutWorker() {
3984
4249
  const performanceTracker = new DocsLayoutWorkerPerformanceTracker();
3985
- const channelService = new ChannelService(createDocsLayoutWorkerMessageProtocol$1(performanceTracker));
3986
- channelService.registerChannel(DOCS_LAYOUT_WORKER_CHANNEL, fromModule(new DocsLayoutWorkerRuntime(performanceTracker)));
4250
+ const runtime = new DocsLayoutWorkerRuntime(performanceTracker);
4251
+ const channelService = new DocsLayoutWorkerChannelService(createDocsLayoutWorkerMessageProtocol$1(performanceTracker), runtime);
4252
+ channelService.registerChannel(DOCS_LAYOUT_WORKER_CHANNEL, fromModule(runtime));
3987
4253
  return channelService;
3988
4254
  }
3989
4255
 
@@ -4014,10 +4280,11 @@ function createDocsLayoutWorkerMessageProtocol(worker, performanceTracker) {
4014
4280
  };
4015
4281
  }
4016
4282
  var DocsLayoutWorkerClientService = class extends Disposable {
4017
- constructor(_workerFactory, _requestTimeoutMs = DEFAULT_DOCS_LAYOUT_WORKER_REQUEST_TIMEOUT_MS) {
4283
+ constructor(_workerFactory, _requestTimeoutMs = DEFAULT_DOCS_LAYOUT_WORKER_REQUEST_TIMEOUT_MS, _fontFaces = []) {
4018
4284
  super();
4019
4285
  this._workerFactory = _workerFactory;
4020
4286
  this._requestTimeoutMs = _requestTimeoutMs;
4287
+ this._fontFaces = _fontFaces;
4021
4288
  _defineProperty(this, "type", "worker");
4022
4289
  _defineProperty(this, "_worker", null);
4023
4290
  _defineProperty(this, "_channelService", null);
@@ -4026,12 +4293,18 @@ var DocsLayoutWorkerClientService = class extends Disposable {
4026
4293
  _defineProperty(this, "_initialized", false);
4027
4294
  _defineProperty(this, "_performanceTracker", new DocsLayoutWorkerPerformanceTracker());
4028
4295
  _defineProperty(this, "_fontFamilies", /* @__PURE__ */ new Map());
4296
+ _defineProperty(this, "_fontLoader", new DocsLayoutFontLoader());
4297
+ this.disposeWithMe(this._fontLoader);
4029
4298
  this._initialization = this._replaceRuntime();
4030
4299
  }
4031
4300
  initialize() {
4032
4301
  return this._initialization;
4033
4302
  }
4034
- getCapabilities() {
4303
+ get renderingFontsReady() {
4304
+ return this._fontFaces.length > 0 ? this._initialization : void 0;
4305
+ }
4306
+ async getCapabilities() {
4307
+ await this._initialization;
4035
4308
  return this._getRuntime().getCapabilities();
4036
4309
  }
4037
4310
  async recover() {
@@ -4108,13 +4381,22 @@ var DocsLayoutWorkerClientService = class extends Disposable {
4108
4381
  async _replaceRuntime() {
4109
4382
  this._initialized = false;
4110
4383
  this._disposeRuntime();
4384
+ await this._withTimeout(this._fontLoader.load(this._fontFaces), "load rendering fonts");
4385
+ this.ensureNotDisposed();
4111
4386
  const worker = this._workerFactory();
4112
4387
  const channelService = new ChannelService(createDocsLayoutWorkerMessageProtocol(worker, this._performanceTracker));
4113
4388
  this._worker = worker;
4114
4389
  this._channelService = channelService;
4115
4390
  this._runtime = toModule(channelService.requestChannel(DOCS_LAYOUT_WORKER_CHANNEL));
4116
- await this._withTimeout(this._verifyCapabilities(), "verify capabilities");
4117
- this._initialized = true;
4391
+ try {
4392
+ await this._withTimeout(this._runtime.initialize(this._fontFaces), "load Worker fonts");
4393
+ await this._withTimeout(this._verifyCapabilities(), "verify capabilities");
4394
+ this.ensureNotDisposed();
4395
+ this._initialized = true;
4396
+ } catch (error) {
4397
+ if (this._worker === worker) this._disposeRuntime();
4398
+ throw error;
4399
+ }
4118
4400
  }
4119
4401
  _disposeRuntime() {
4120
4402
  var _this$_channelService, _this$_worker;
@@ -4143,7 +4425,7 @@ var DocsLayoutWorkerClientService = class extends Disposable {
4143
4425
  });
4144
4426
  }
4145
4427
  async _verifyCapabilities() {
4146
- const capabilities = await this.getCapabilities();
4428
+ const capabilities = await this._getRuntime().getCapabilities();
4147
4429
  if (capabilities.protocolVersion !== 5) throw new DocsLayoutWorkerCapabilityError("Document layout Worker protocol version mismatch.");
4148
4430
  if (!capabilities.offscreenCanvas || !capabilities.structuredClone) throw new DocsLayoutWorkerCapabilityError("Document layout Worker requires OffscreenCanvas and structured clone support.");
4149
4431
  const mainMetrics = FontCache.getMeasureText(capabilities.fontProbe.content, capabilities.fontProbe.font);
@@ -4168,7 +4450,7 @@ let UniverDocsLayoutWorkerPlugin = class UniverDocsLayoutWorkerPlugin extends Pl
4168
4450
  if (typeof this._config.workerFactory !== "function") throw new TypeError("[UniverDocsLayoutWorkerPlugin]: workerFactory is required.");
4169
4451
  const requestTimeoutMs = this._config.requestTimeoutMs ?? 15e3;
4170
4452
  if (!Number.isFinite(requestTimeoutMs) || requestTimeoutMs <= 0) throw new RangeError("[UniverDocsLayoutWorkerPlugin]: requestTimeoutMs must be a positive finite number.");
4171
- const client = new DocsLayoutWorkerClientService(this._config.workerFactory, requestTimeoutMs);
4453
+ const client = new DocsLayoutWorkerClientService(this._config.workerFactory, requestTimeoutMs, this._config.fontFaces);
4172
4454
  this._injector.add([DocsLayoutWorkerClientService, { useValue: client }]);
4173
4455
  this.disposeWithMe(client);
4174
4456
  this.disposeWithMe(this._layoutExecutorService.register(client));
@@ -4231,7 +4513,8 @@ let DocInterceptorService = class DocInterceptorService extends Disposable {
4231
4513
  }
4232
4514
  fetchThroughInterceptors(name) {
4233
4515
  const key = name;
4234
- return composeInterceptors(this._interceptorsByName.get(key) || []);
4516
+ const interceptors = this._interceptorsByName.get(key);
4517
+ return composeInterceptors(interceptors || []);
4235
4518
  }
4236
4519
  interceptDocumentViewModel(viewModel) {
4237
4520
  const disposableCollection = new DisposableCollection();