@embedpdf/engine-core 3.0.0-next.14 → 3.0.0-next.16

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 (135) hide show
  1. package/dist/AnnotationList-DcyhF2kU.d.cts +27691 -0
  2. package/dist/AnnotationList-DcyhF2kU.d.ts +27691 -0
  3. package/dist/Change-Ct-dB8D5.cjs +1133 -0
  4. package/dist/Change-Ct-dB8D5.cjs.map +1 -0
  5. package/dist/Change-tMR34hTU.js +978 -0
  6. package/dist/Change-tMR34hTU.js.map +1 -0
  7. package/dist/DocumentRenderService-9IjSQEIU.cjs +121 -0
  8. package/dist/DocumentRenderService-9IjSQEIU.cjs.map +1 -0
  9. package/dist/DocumentRenderService-DFrZ9wfW.js +86 -0
  10. package/dist/DocumentRenderService-DFrZ9wfW.js.map +1 -0
  11. package/dist/{DocumentSecurityService-Ca6EK3-3.d.ts → DocumentSecurityService-D2zA4NKi.d.cts} +100 -112
  12. package/dist/{DocumentSecurityService-CIx1MT0T.d.cts → DocumentSecurityService-YJV9df8P.d.ts} +100 -112
  13. package/dist/LocalDocumentHandle-D02FMm-Z.cjs +53 -0
  14. package/dist/LocalDocumentHandle-D02FMm-Z.cjs.map +1 -0
  15. package/dist/LocalDocumentHandle-DAPdaOt_.js +30 -0
  16. package/dist/LocalDocumentHandle-DAPdaOt_.js.map +1 -0
  17. package/dist/LocalEngine-DBt2-GWF.d.ts +1649 -0
  18. package/dist/LocalEngine-IA9zh3Jh.d.cts +1649 -0
  19. package/dist/PageInsertBlankInput-CXHAM7l6.cjs +17 -0
  20. package/dist/PageInsertBlankInput-CXHAM7l6.cjs.map +1 -0
  21. package/dist/PageInsertBlankInput-DhVYVJ_S.js +12 -0
  22. package/dist/PageInsertBlankInput-DhVYVJ_S.js.map +1 -0
  23. package/dist/authority-BFp6XM04.cjs +2997 -0
  24. package/dist/authority-BFp6XM04.cjs.map +1 -0
  25. package/dist/authority-PuxpGFhJ.js +2506 -0
  26. package/dist/authority-PuxpGFhJ.js.map +1 -0
  27. package/dist/builders-DV62HA3I.js +165 -0
  28. package/dist/builders-DV62HA3I.js.map +1 -0
  29. package/dist/builders-DgTAj_tP.cjs +188 -0
  30. package/dist/builders-DgTAj_tP.cjs.map +1 -0
  31. package/dist/calibrate-DJbi1wuK.cjs +3012 -0
  32. package/dist/calibrate-DJbi1wuK.cjs.map +1 -0
  33. package/dist/calibrate-nQFgCuki.js +2461 -0
  34. package/dist/calibrate-nQFgCuki.js.map +1 -0
  35. package/dist/charmap-Cprti1ta.js +239 -0
  36. package/dist/charmap-Cprti1ta.js.map +1 -0
  37. package/dist/charmap-aYlefQP9.cjs +304 -0
  38. package/dist/charmap-aYlefQP9.cjs.map +1 -0
  39. package/dist/conformance.cjs +18146 -5258
  40. package/dist/conformance.cjs.map +1 -1
  41. package/dist/conformance.d.cts +1024 -170
  42. package/dist/conformance.d.ts +1024 -170
  43. package/dist/conformance.js +18148 -5309
  44. package/dist/conformance.js.map +1 -1
  45. package/dist/format-Bp3QFSH1.cjs +574 -0
  46. package/dist/format-Bp3QFSH1.cjs.map +1 -0
  47. package/dist/format-Dgg428Kb.js +461 -0
  48. package/dist/format-Dgg428Kb.js.map +1 -0
  49. package/dist/index.cjs +342 -116
  50. package/dist/index.d.cts +2 -2
  51. package/dist/index.d.ts +2 -2
  52. package/dist/index.js +14 -5
  53. package/dist/pageRefs-B3ur7Ckm.cjs +51 -0
  54. package/dist/pageRefs-B3ur7Ckm.cjs.map +1 -0
  55. package/dist/pageRefs-DkbuxSCV.js +40 -0
  56. package/dist/pageRefs-DkbuxSCV.js.map +1 -0
  57. package/dist/public.cjs +59 -0
  58. package/dist/public.d.cts +5 -0
  59. package/dist/public.d.ts +5 -0
  60. package/dist/public.js +9 -0
  61. package/dist/resolveAnnotationDraft-7Ke4nV7F.cjs +3646 -0
  62. package/dist/resolveAnnotationDraft-7Ke4nV7F.cjs.map +1 -0
  63. package/dist/resolveAnnotationDraft-CUpf0SMh.js +3167 -0
  64. package/dist/resolveAnnotationDraft-CUpf0SMh.js.map +1 -0
  65. package/dist/{resolver-inAVzsWt.js → resolver-BBggAxQc.js} +298 -145
  66. package/dist/resolver-BBggAxQc.js.map +1 -0
  67. package/dist/{resolver-CYVNV4hn.cjs → resolver-BWSWSF6R.cjs} +351 -144
  68. package/dist/resolver-BWSWSF6R.cjs.map +1 -0
  69. package/dist/runtime-BaDKjxiu.d.ts +1959 -0
  70. package/dist/runtime-CWEuiwbk.d.cts +1959 -0
  71. package/dist/runtime.cjs +986 -297
  72. package/dist/runtime.cjs.map +1 -1
  73. package/dist/runtime.d.cts +5 -1372
  74. package/dist/runtime.d.ts +5 -1372
  75. package/dist/runtime.js +634 -179
  76. package/dist/runtime.js.map +1 -1
  77. package/dist/schema-6S2VmlAj.js +2087 -0
  78. package/dist/schema-6S2VmlAj.js.map +1 -0
  79. package/dist/schema-miH6tWQC.cjs +3046 -0
  80. package/dist/schema-miH6tWQC.cjs.map +1 -0
  81. package/dist/schemas-BE2QGOit.js +1851 -0
  82. package/dist/schemas-BE2QGOit.js.map +1 -0
  83. package/dist/schemas-DljJR9ut.cjs +2798 -0
  84. package/dist/schemas-DljJR9ut.cjs.map +1 -0
  85. package/dist/subtype-CG4WpIRj.js +129 -0
  86. package/dist/subtype-CG4WpIRj.js.map +1 -0
  87. package/dist/subtype-aDt5TFmK.cjs +158 -0
  88. package/dist/subtype-aDt5TFmK.cjs.map +1 -0
  89. package/dist/validation.cjs +578 -0
  90. package/dist/validation.cjs.map +1 -0
  91. package/dist/validation.d.cts +174 -0
  92. package/dist/validation.d.ts +174 -0
  93. package/dist/validation.js +571 -0
  94. package/dist/validation.js.map +1 -0
  95. package/dist/value-BFS1R8ek.cjs +435 -0
  96. package/dist/value-BFS1R8ek.cjs.map +1 -0
  97. package/dist/value-Dhc8eYcx.js +340 -0
  98. package/dist/value-Dhc8eYcx.js.map +1 -0
  99. package/dist/viewport-CHG9qQUb.cjs +671 -0
  100. package/dist/viewport-CHG9qQUb.cjs.map +1 -0
  101. package/dist/viewport-DQR5LyX3.js +540 -0
  102. package/dist/viewport-DQR5LyX3.js.map +1 -0
  103. package/dist/wire.cjs +1242 -420
  104. package/dist/wire.cjs.map +1 -1
  105. package/dist/wire.d.cts +14840 -830
  106. package/dist/wire.d.ts +14840 -830
  107. package/dist/wire.js +985 -261
  108. package/dist/wire.js.map +1 -1
  109. package/package.json +10 -1
  110. package/dist/AbortError-DwuHPK_I.js +0 -27
  111. package/dist/AbortError-DwuHPK_I.js.map +0 -1
  112. package/dist/AbortError-P0RU0Mgg.cjs +0 -38
  113. package/dist/AbortError-P0RU0Mgg.cjs.map +0 -1
  114. package/dist/AnnotationListSnapshot-D9R5n2Kf.d.cts +0 -7101
  115. package/dist/AnnotationListSnapshot-D9R5n2Kf.d.ts +0 -7101
  116. package/dist/Engine-EWWHhEIi.d.ts +0 -1277
  117. package/dist/Engine-FNaAEjfb.d.cts +0 -1277
  118. package/dist/derive-BbsDk_Kz.cjs +0 -880
  119. package/dist/derive-BbsDk_Kz.cjs.map +0 -1
  120. package/dist/derive-DAFJolWu.js +0 -647
  121. package/dist/derive-DAFJolWu.js.map +0 -1
  122. package/dist/format-Bbphf4zR.js +0 -435
  123. package/dist/format-Bbphf4zR.js.map +0 -1
  124. package/dist/format-D_epWlob.cjs +0 -518
  125. package/dist/format-D_epWlob.cjs.map +0 -1
  126. package/dist/resolver-CYVNV4hn.cjs.map +0 -1
  127. package/dist/resolver-inAVzsWt.js.map +0 -1
  128. package/dist/schemas-CFQGvWiu.js +0 -3243
  129. package/dist/schemas-CFQGvWiu.js.map +0 -1
  130. package/dist/schemas-D0g6tKa9.cjs +0 -4694
  131. package/dist/schemas-D0g6tKa9.cjs.map +0 -1
  132. package/dist/viewport-BWeNHZmb.cjs +0 -3503
  133. package/dist/viewport-BWeNHZmb.cjs.map +0 -1
  134. package/dist/viewport-CvMcadfQ.js +0 -3072
  135. package/dist/viewport-CvMcadfQ.js.map +0 -1
@@ -0,0 +1,3012 @@
1
+ const require_resolveAnnotationDraft = require("./resolveAnnotationDraft-7Ke4nV7F.cjs");
2
+ const require_format = require("./format-Bp3QFSH1.cjs");
3
+ const require_charmap = require("./charmap-aYlefQP9.cjs");
4
+ //#region src/dto/PdfLinkTarget.ts
5
+ /**
6
+ * The action tree the engine writes for a target a write can make: one URI,
7
+ * GoTo or Named action, as a read of it returns it. Links and outline items
8
+ * both write their targets this way.
9
+ */
10
+ function actionTreeOf(target) {
11
+ return {
12
+ root: target.kind === "uri" ? {
13
+ type: "uri",
14
+ subtype: "URI",
15
+ uri: target.uri,
16
+ isMap: false,
17
+ next: []
18
+ } : target.kind === "goto" ? {
19
+ type: "goto",
20
+ subtype: "GoTo",
21
+ destination: target.destination,
22
+ next: []
23
+ } : {
24
+ type: "named",
25
+ subtype: "Named",
26
+ name: target.name,
27
+ next: []
28
+ },
29
+ incomplete: false,
30
+ warningFlags: 0,
31
+ warnings: []
32
+ };
33
+ }
34
+ //#endregion
35
+ //#region src/geometry/printSize.ts
36
+ /**
37
+ * The paper a print picture is sized for, in points: the larger of A4
38
+ * (595 × 842) and Letter (612 × 792) on each side.
39
+ */
40
+ const PRINT_PAPER = {
41
+ long: 842,
42
+ short: 612
43
+ };
44
+ /**
45
+ * The scale (pixels per point) of a print picture of a page `size` points
46
+ * big at `dpi` dots per inch of paper. A page that fits on the paper is
47
+ * drawn at its own size at that DPI; a bigger one gets no more pixels than
48
+ * it needs shrunk to fit, since the printer would throw the rest away. An
49
+ * A0 drawing printed on office paper needs no more; printed at its own
50
+ * size, it needs vectors (the print copy). Portrait or landscape doesn't
51
+ * matter.
52
+ */
53
+ function printScale(size, dpi) {
54
+ const long = Math.max(size.width, size.height);
55
+ const short = Math.min(size.width, size.height);
56
+ const fit = Math.min(1, PRINT_PAPER.long / long, PRINT_PAPER.short / short);
57
+ return dpi / 72 * fit;
58
+ }
59
+ //#endregion
60
+ //#region src/geometry/renderSize.ts
61
+ /**
62
+ * The pixel size of a render: an area of `width` × `height` points, turned
63
+ * by `rotation` (width and height swap on a quarter turn) and sized by
64
+ * `viewport`. A `dpi` viewport sizes a print picture for its paper
65
+ * ({@link printScale}). The local worker allocates exactly this; the cloud
66
+ * client reports it without rendering. `InvalidArg` for a viewport that
67
+ * isn't positive.
68
+ */
69
+ function renderSize(area, rotation, viewport) {
70
+ const swap = rotation === 90 || rotation === 270;
71
+ const baseWidth = swap ? area.height : area.width;
72
+ const baseHeight = swap ? area.width : area.height;
73
+ if (viewport.kind === "width") {
74
+ if (!Number.isFinite(viewport.width) || viewport.width <= 0) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, "render viewport width must be positive");
75
+ const width = Math.max(1, Math.round(viewport.width));
76
+ return {
77
+ width,
78
+ height: Math.max(1, Math.round(width * baseHeight / baseWidth))
79
+ };
80
+ }
81
+ const scale = viewport.kind === "dpi" ? printScale(area, viewport.dpi) : viewport.scale ?? 1;
82
+ if (!Number.isFinite(scale) || scale <= 0) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, "render viewport scale must be positive");
83
+ return {
84
+ width: Math.max(1, Math.round(baseWidth * scale)),
85
+ height: Math.max(1, Math.round(baseHeight * scale))
86
+ };
87
+ }
88
+ //#endregion
89
+ //#region src/geometry/pageTransform.ts
90
+ /**
91
+ * The transform of the image a render with `options` makes of `page`, without
92
+ * rendering: its size, rounding included, and the conversion between page
93
+ * space and its pixels. Takes the page's layout (`doc.pages.list()`).
94
+ * `InvalidArg` for a viewport that isn't positive or a target without area.
95
+ */
96
+ function pageTransform(page, options = {}) {
97
+ const target = options.target;
98
+ return renderAreaTransform(target?.kind === "rect" ? renderTargetArea(target.rect) : {
99
+ x: 0,
100
+ y: 0,
101
+ width: page.size.width,
102
+ height: page.size.height
103
+ }, options);
104
+ }
105
+ /** The transform of a render of `area` with `options`' turn and size. */
106
+ function renderAreaTransform(area, options) {
107
+ const rotation = options.rotation ?? 0;
108
+ const { width, height } = renderSize(area, rotation, options.viewport ?? { kind: "scale" });
109
+ return renderTransform(area, rotation, width, height);
110
+ }
111
+ /**
112
+ * A render target's area with its sides in order, as the renderer takes it.
113
+ * `InvalidArg` for a rect without area, or one that isn't numbers.
114
+ */
115
+ function renderTargetArea(rect) {
116
+ const { x, y, width, height } = rect;
117
+ if (![
118
+ x,
119
+ y,
120
+ width,
121
+ height
122
+ ].every(Number.isFinite) || width === 0 || height === 0) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, "render rect must have positive area");
123
+ return {
124
+ x: Math.min(x, x + width),
125
+ y: Math.min(y, y + height),
126
+ width: Math.abs(width),
127
+ height: Math.abs(height)
128
+ };
129
+ }
130
+ /**
131
+ * The matrix that draws `area` of the page, turned clockwise by `rotation`,
132
+ * onto `width` × `height` pixels. The renderer draws with it.
133
+ */
134
+ function renderMatrix(area, rotation, width, height) {
135
+ const { x, y } = area;
136
+ const w = area.width;
137
+ const h = area.height;
138
+ switch (rotation) {
139
+ case 0: return [
140
+ width / w,
141
+ 0,
142
+ 0,
143
+ height / h,
144
+ -width / w * x,
145
+ -height / h * y
146
+ ];
147
+ case 90: return [
148
+ 0,
149
+ height / w,
150
+ -width / h,
151
+ 0,
152
+ width / h * (y + h),
153
+ -height / w * x
154
+ ];
155
+ case 180: return [
156
+ -width / w,
157
+ 0,
158
+ 0,
159
+ -height / h,
160
+ width / w * (x + w),
161
+ height / h * (y + h)
162
+ ];
163
+ case 270: return [
164
+ 0,
165
+ -height / w,
166
+ width / h,
167
+ 0,
168
+ -width / h * y,
169
+ height / w * (x + w)
170
+ ];
171
+ }
172
+ }
173
+ /** The transform of a render of `area`, turned by `rotation`, drawn onto `width` × `height` pixels. */
174
+ function renderTransform(area, rotation, width, height) {
175
+ const matrix = renderMatrix(area, rotation, width, height);
176
+ const inverse = inverseOf(matrix);
177
+ return {
178
+ width,
179
+ height,
180
+ matrix,
181
+ pageToPixels: ((value) => mapped(matrix, value)),
182
+ pixelsToPage: ((value) => mapped(inverse, value))
183
+ };
184
+ }
185
+ function inverseOf([a, b, c, d, e, f]) {
186
+ const det = a * d - b * c;
187
+ return [
188
+ d / det,
189
+ -b / det,
190
+ -c / det,
191
+ a / det,
192
+ (c * f - d * e) / det,
193
+ (b * e - a * f) / det
194
+ ];
195
+ }
196
+ function mappedPoint(m, { x, y }) {
197
+ return {
198
+ x: m[0] * x + m[2] * y + m[4],
199
+ y: m[1] * x + m[3] * y + m[5]
200
+ };
201
+ }
202
+ /** A point, a box or a quad through `m`. A box stays a box: every turn is a quarter turn. */
203
+ function mapped(m, value) {
204
+ if ("upperLeft" in value) return {
205
+ upperLeft: mappedPoint(m, value.upperLeft),
206
+ upperRight: mappedPoint(m, value.upperRight),
207
+ lowerLeft: mappedPoint(m, value.lowerLeft),
208
+ lowerRight: mappedPoint(m, value.lowerRight)
209
+ };
210
+ if ("width" in value) {
211
+ const from = mappedPoint(m, value);
212
+ const to = mappedPoint(m, {
213
+ x: value.x + value.width,
214
+ y: value.y + value.height
215
+ });
216
+ return {
217
+ x: Math.min(from.x, to.x),
218
+ y: Math.min(from.y, to.y),
219
+ width: Math.abs(to.x - from.x),
220
+ height: Math.abs(to.y - from.y)
221
+ };
222
+ }
223
+ return mappedPoint(m, value);
224
+ }
225
+ //#endregion
226
+ //#region src/geometry/pageSpace.ts
227
+ /** A point in the file's coordinates, in page space. `visible` is the page's visible box. */
228
+ function pagePointOf(point, visible) {
229
+ return {
230
+ x: point.x - visible.left,
231
+ y: visible.top - point.y
232
+ };
233
+ }
234
+ /** A page-space point in the file's coordinates. */
235
+ function pdfPointOf(point, visible) {
236
+ return {
237
+ x: point.x + visible.left,
238
+ y: visible.top - point.y
239
+ };
240
+ }
241
+ /** A normalized rect in the file's coordinates, in page space. */
242
+ function pageBoxOf(rect, visible) {
243
+ return {
244
+ x: rect.left - visible.left,
245
+ y: visible.top - rect.top,
246
+ width: rect.right - rect.left,
247
+ height: rect.top - rect.bottom
248
+ };
249
+ }
250
+ /** A page-space box in the file's coordinates, keys in `normalizePdfRect`'s order. */
251
+ function pdfRectOf(box, visible) {
252
+ const left = box.x + visible.left;
253
+ const top = visible.top - box.y;
254
+ return {
255
+ left,
256
+ right: left + box.width,
257
+ bottom: top - box.height,
258
+ top
259
+ };
260
+ }
261
+ function pageQuadOf(quad, visible) {
262
+ return {
263
+ upperLeft: pagePointOf(quad.upperLeft, visible),
264
+ upperRight: pagePointOf(quad.upperRight, visible),
265
+ lowerLeft: pagePointOf(quad.lowerLeft, visible),
266
+ lowerRight: pagePointOf(quad.lowerRight, visible)
267
+ };
268
+ }
269
+ function pdfQuadOf(quad, visible) {
270
+ return {
271
+ upperLeft: pdfPointOf(quad.upperLeft, visible),
272
+ upperRight: pdfPointOf(quad.upperRight, visible),
273
+ lowerLeft: pdfPointOf(quad.lowerLeft, visible),
274
+ lowerRight: pdfPointOf(quad.lowerRight, visible)
275
+ };
276
+ }
277
+ /** A page-space point flipped into y-up coordinates. */
278
+ const mirroredPoint = (point) => ({
279
+ x: point.x,
280
+ y: -point.y
281
+ });
282
+ /** A y-up point flipped back into page space. */
283
+ const unmirroredPoint = (point) => ({
284
+ x: point.x,
285
+ y: -point.y
286
+ });
287
+ /** A page-space box flipped into a y-up rect. */
288
+ const mirroredRect = (box) => ({
289
+ left: box.x,
290
+ right: box.x + box.width,
291
+ bottom: -(box.y + box.height),
292
+ top: -box.y
293
+ });
294
+ /** A y-up rect flipped back into a page-space box. */
295
+ const unmirroredBox = (rect) => ({
296
+ x: rect.left,
297
+ y: -rect.top,
298
+ width: rect.right - rect.left,
299
+ height: rect.top - rect.bottom
300
+ });
301
+ const mirroredQuad = (quad) => ({
302
+ upperLeft: mirroredPoint(quad.upperLeft),
303
+ upperRight: mirroredPoint(quad.upperRight),
304
+ lowerLeft: mirroredPoint(quad.lowerLeft),
305
+ lowerRight: mirroredPoint(quad.lowerRight)
306
+ });
307
+ const unmirroredQuad = (quad) => ({
308
+ upperLeft: unmirroredPoint(quad.upperLeft),
309
+ upperRight: unmirroredPoint(quad.upperRight),
310
+ lowerLeft: unmirroredPoint(quad.lowerLeft),
311
+ lowerRight: unmirroredPoint(quad.lowerRight)
312
+ });
313
+ //#endregion
314
+ //#region src/dto/PageGeometrySnapshot.ts
315
+ /** Narrowing guard: is this run the rotated (non-upright) variant? */
316
+ function isRotatedGeometryRun(run) {
317
+ return "rotation" in run;
318
+ }
319
+ /**
320
+ * Uniform oriented-cell view over either run variant, in the file's
321
+ * coordinates: the glyph's loose cell as a quad (synthesized from the box
322
+ * corners when the run is upright).
323
+ */
324
+ function glyphLooseQuad(run, index) {
325
+ if (isRotatedGeometryRun(run)) return run.glyphs[index].loose;
326
+ const b = run.glyphs[index].loose;
327
+ return {
328
+ upperLeft: {
329
+ x: b.left,
330
+ y: b.top
331
+ },
332
+ upperRight: {
333
+ x: b.right,
334
+ y: b.top
335
+ },
336
+ lowerLeft: {
337
+ x: b.left,
338
+ y: b.bottom
339
+ },
340
+ lowerRight: {
341
+ x: b.right,
342
+ y: b.bottom
343
+ }
344
+ };
345
+ }
346
+ /**
347
+ * Uniform AABB view over either run variant, in the file's coordinates: the
348
+ * glyph's loose box, or the
349
+ * enclosing bounds of its oriented cell when the run is rotated. The
350
+ * conservative envelope for consumers that genuinely want a box (culling,
351
+ * scroll targets) — never a substitute for handling orientation in geometry
352
+ * that gets drawn.
353
+ */
354
+ function glyphLooseBounds(run, index) {
355
+ if (isRotatedGeometryRun(run)) return require_resolveAnnotationDraft.pdfQuadBounds(run.glyphs[index].loose);
356
+ return run.glyphs[index].loose;
357
+ }
358
+ //#endregion
359
+ //#region src/promise/AbortError.ts
360
+ /**
361
+ * What a cancelled call rejects with: an `EngineError` with code `Aborted`,
362
+ * named `AbortError` like the DOM's, so both `EngineError.is(err,
363
+ * EngineErrorCode.Aborted)` and `err.name === 'AbortError'` recognise it.
364
+ */
365
+ var AbortError = class extends require_format.EngineError {
366
+ constructor(reason) {
367
+ super(require_format.EngineErrorCode.Aborted, reasonMessage(reason));
368
+ require_format._defineProperty(this, "name", "AbortError");
369
+ require_format._defineProperty(this, "reason", void 0);
370
+ this.reason = reason;
371
+ }
372
+ };
373
+ function isAbortError(value) {
374
+ return value instanceof AbortError || value?.name === "AbortError";
375
+ }
376
+ function reasonMessage(reason) {
377
+ if (reason == null) return "aborted";
378
+ if (typeof reason === "string") return reason;
379
+ if (reason instanceof Error) return reason.message || "aborted";
380
+ try {
381
+ return JSON.stringify(reason);
382
+ } catch {
383
+ return "aborted";
384
+ }
385
+ }
386
+ //#endregion
387
+ //#region src/identity/OutlineItemRef.ts
388
+ /** Build the address for an outline item from its object number. */
389
+ function toOutlineItemRef(objectNumber) {
390
+ return {
391
+ kind: "objectNumber",
392
+ objectNumber
393
+ };
394
+ }
395
+ /** Structural equality for two outline item addresses. */
396
+ function outlineItemRefsEqual(a, b) {
397
+ return a.kind === b.kind && a.objectNumber === b.objectNumber;
398
+ }
399
+ //#endregion
400
+ //#region src/resource/BinarySource.ts
401
+ function isBlob$1(value) {
402
+ return typeof Blob !== "undefined" && value instanceof Blob;
403
+ }
404
+ /**
405
+ * Copy a Uint8Array view into a fresh, exactly-sized ArrayBuffer the call
406
+ * owns. Always copies — even when the view spans its whole buffer — because
407
+ * the result may be transferred to a worker (detaching it), and the view is
408
+ * the caller's. Returning `view.buffer` here would let one transfer zero
409
+ * the caller's bytes (a stamp library's Uint8Array became single-use).
410
+ * Callers wanting a zero-copy hand-off need an explicit "give" form, as
411
+ * `pages.insert` has for bare ArrayBuffers; `BinarySource` has none.
412
+ */
413
+ function toOwnedArrayBuffer(view) {
414
+ const copy = new ArrayBuffer(view.byteLength);
415
+ new Uint8Array(copy).set(view);
416
+ return copy;
417
+ }
418
+ /**
419
+ * Resolve any accepted `BinarySource` form into a `WireResource`.
420
+ * Async because Blob bytes can only be read asynchronously.
421
+ */
422
+ async function resolveBinarySource(source) {
423
+ if (source instanceof Uint8Array) return { bytes: toOwnedArrayBuffer(source) };
424
+ if (isBlob$1(source)) {
425
+ const blobName = blobFileName(source);
426
+ return {
427
+ bytes: await source.arrayBuffer(),
428
+ mimeType: source.type || void 0,
429
+ ...blobName !== void 0 ? { name: blobName } : {}
430
+ };
431
+ }
432
+ const { data, mimeType, name } = source;
433
+ const inner = data instanceof Uint8Array ? {
434
+ bytes: toOwnedArrayBuffer(data),
435
+ mimeType: void 0,
436
+ name: void 0
437
+ } : {
438
+ bytes: await data.arrayBuffer(),
439
+ mimeType: data.type || void 0,
440
+ name: blobFileName(data)
441
+ };
442
+ const resolvedName = name ?? inner.name;
443
+ return {
444
+ bytes: inner.bytes,
445
+ ...mimeType ?? inner.mimeType ? { mimeType: mimeType ?? inner.mimeType } : {},
446
+ ...resolvedName !== void 0 ? { name: resolvedName } : {}
447
+ };
448
+ }
449
+ /** A browser `File` is a Blob with a `name` — pick it up so attachment
450
+ * drafts can pass a `File` directly without repeating the file name. */
451
+ function blobFileName(blob) {
452
+ const name = blob.name;
453
+ return typeof name === "string" && name.length > 0 ? name : void 0;
454
+ }
455
+ //#endregion
456
+ //#region src/resource/binaryMetadata.ts
457
+ /**
458
+ * Detect format (and intrinsic dimensions for rasters) of a binary buffer.
459
+ *
460
+ * @returns metadata, or `null` for unsupported/corrupt data
461
+ */
462
+ function sniffBinaryMetadata(buffer) {
463
+ if (buffer.byteLength < 4) return null;
464
+ const bytes = new Uint8Array(buffer);
465
+ if (bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) return parsePng(buffer);
466
+ if (bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return parseJpeg(buffer);
467
+ if (bytes[0] === 37 && bytes[1] === 80 && bytes[2] === 68 && bytes[3] === 70) return { mimeType: "application/pdf" };
468
+ return null;
469
+ }
470
+ function parsePng(buffer) {
471
+ if (buffer.byteLength < 24) return null;
472
+ const view = new DataView(buffer);
473
+ const width = view.getUint32(16);
474
+ const height = view.getUint32(20);
475
+ if (width === 0 || height === 0) return null;
476
+ return {
477
+ mimeType: "image/png",
478
+ width,
479
+ height
480
+ };
481
+ }
482
+ function parseJpeg(buffer) {
483
+ const bytes = new Uint8Array(buffer);
484
+ let offset = 2;
485
+ while (offset + 4 < bytes.byteLength) {
486
+ if (bytes[offset] !== 255) return null;
487
+ const marker = bytes[offset + 1];
488
+ if (marker >= 192 && marker <= 195) {
489
+ if (offset + 9 > bytes.byteLength) return null;
490
+ const view = new DataView(buffer, offset + 5);
491
+ const height = view.getUint16(0);
492
+ const width = view.getUint16(2);
493
+ if (width === 0 || height === 0) return null;
494
+ return {
495
+ mimeType: "image/jpeg",
496
+ width,
497
+ height
498
+ };
499
+ }
500
+ if (marker === 216 || marker === 217) offset += 2;
501
+ else if (marker === 255) offset += 1;
502
+ else {
503
+ const segLen = bytes[offset + 2] << 8 | bytes[offset + 3];
504
+ offset += 2 + segLen;
505
+ }
506
+ }
507
+ return null;
508
+ }
509
+ //#endregion
510
+ //#region src/annotation/resources.ts
511
+ /**
512
+ * Bytes travel beside an annotation's data, never inside it:
513
+ * `create(data, resources)` and `update(ref, patch, resources)`. A read
514
+ * returns the data only. Each role names what the bytes are for; a kind
515
+ * declares the roles it takes (`kinds/<kind>/declaration.ts`).
516
+ */
517
+ /**
518
+ * What bytes beside an annotation's data can be for:
519
+ *
520
+ * - `appearance`: what the box shows before the rotation the data describes,
521
+ * PNG, JPEG or a one-page PDF, scaled into the box as the data's `fit` says.
522
+ * A stamp requires it; on update it replaces the drawing.
523
+ * - `file`: an attached file's exact bytes; its name, MIME type and
524
+ * description are the data's `file`. A file attachment requires it; on
525
+ * update it replaces the bytes.
526
+ */
527
+ const ANNOTATION_RESOURCE_ROLE_NAMES = ["appearance", "file"];
528
+ /**
529
+ * Copy each resource into bytes the write owns: the local engine transfers
530
+ * them to its worker, which detaches the buffer, and the caller's bytes are
531
+ * only borrowed. An appearance that isn't PNG, JPEG or PDF fails here,
532
+ * before anything is sent; the format comes from the bytes.
533
+ */
534
+ async function resolveAnnotationResources(resources) {
535
+ if (!resources) return {};
536
+ for (const role of Object.keys(resources)) if (!ANNOTATION_RESOURCE_ROLE_NAMES.includes(role)) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, `unknown annotation resource '${role}'; expected ${ANNOTATION_RESOURCE_ROLE_NAMES.join(" or ")}`);
537
+ const wire = {};
538
+ for (const role of ANNOTATION_RESOURCE_ROLE_NAMES) {
539
+ const data = resources[role];
540
+ if (data === void 0) continue;
541
+ const bytes = await ownedBytes(data);
542
+ if (role === "appearance" && !sniffBinaryMetadata(bytes)) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, "the appearance resource must be PNG, JPEG or one-page PDF bytes");
543
+ wire[role] = bytes;
544
+ }
545
+ return wire;
546
+ }
547
+ /**
548
+ * A file-attachment create's `file`, completed from its `file` resource when
549
+ * that is a `File` or a `Blob`: the name a `File` brings and the type a
550
+ * `Blob` does, where the data leaves them out. A `Blob` with no type gives
551
+ * none. Other drafts, and bare bytes, pass as they are.
552
+ */
553
+ function withFileFromResource(draft, resources) {
554
+ const data = resources?.file;
555
+ if (draft.subtype !== "file-attachment" || !isBlob(data)) return draft;
556
+ const name = draft.file?.name ?? blobFileName(data);
557
+ if (name === void 0) return draft;
558
+ return {
559
+ ...draft,
560
+ file: {
561
+ ...draft.file,
562
+ name,
563
+ mimeType: draft.file?.mimeType !== void 0 ? draft.file.mimeType : data.type || null
564
+ }
565
+ };
566
+ }
567
+ function hasAnnotationResources(resources) {
568
+ return ANNOTATION_RESOURCE_ROLE_NAMES.some((role) => resources[role] !== void 0);
569
+ }
570
+ /** The buffers of a write's resources: what a worker transfer list hands over. */
571
+ function annotationResourceBuffers(resources) {
572
+ return Object.values(resources).filter((bytes) => bytes !== void 0);
573
+ }
574
+ /**
575
+ * Check a write's resources against its kind: a role the kind doesn't take
576
+ * is refused, and so is a create without a role the kind requires.
577
+ */
578
+ function assertAnnotationResources(subtype, resources, write) {
579
+ const roles = require_resolveAnnotationDraft.ANNOTATION_RESOURCE_ROLES[subtype] ?? {};
580
+ for (const role of ANNOTATION_RESOURCE_ROLE_NAMES) {
581
+ const given = resources?.[role] !== void 0;
582
+ if (given && roles[role] === void 0) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, `a ${subtype} annotation takes no '${role}' resource`);
583
+ if (!given && write === "create" && roles[role] === "required") throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, `creating a ${subtype} annotation needs its '${role}' resource`);
584
+ }
585
+ }
586
+ function isBlob(value) {
587
+ return typeof Blob !== "undefined" && value instanceof Blob;
588
+ }
589
+ async function ownedBytes(data) {
590
+ if (isBlob(data)) return data.arrayBuffer();
591
+ const copy = new ArrayBuffer(data.byteLength);
592
+ new Uint8Array(copy).set(data);
593
+ return copy;
594
+ }
595
+ //#endregion
596
+ //#region src/transfer/bundleLimits.ts
597
+ const DEFAULT_BUNDLE_LIMITS = Object.freeze({
598
+ bundleBytes: 50 * 1024 * 1024,
599
+ manifestBytes: 16 * 1024 * 1024,
600
+ items: 1e4,
601
+ pages: 2e3,
602
+ resources: 2e3,
603
+ resourceBytes: 50 * 1024 * 1024,
604
+ imagePixels: 4e7
605
+ });
606
+ /** The bytes of a bundle's manifest: its pages and rows (`{ pages, items }`) as UTF-8 JSON. */
607
+ function manifestBytesOf(rows) {
608
+ return new TextEncoder().encode(JSON.stringify(rows)).length;
609
+ }
610
+ /** Refuse `value` when it is past the limit named `limit`. */
611
+ function assertWithinLimit(kind, limits, limit, value) {
612
+ const max = limits[limit];
613
+ if (value <= max) return;
614
+ throw new require_format.EngineError(require_format.EngineErrorCode.PayloadTooLarge, `the ${kind} bundle is past its ${limit} limit: ${value} > ${max}`, { details: {
615
+ limit,
616
+ max,
617
+ value
618
+ } });
619
+ }
620
+ //#endregion
621
+ //#region src/transfer/codec.ts
622
+ /** A resource's entry in the file besides its base64: its id, quotes and separators. */
623
+ const RESOURCE_ENTRY_CHARACTERS = 81;
624
+ /** The file's own keys and punctuation. */
625
+ const ENVELOPE_CHARACTERS = 256;
626
+ const A_BUNDLE = {
627
+ annotation: "an annotation bundle",
628
+ form: "a form bundle"
629
+ };
630
+ /**
631
+ * The JSON file of one family's bundles: a bundle whole, to store or
632
+ * download. HTTP carries bundles as multipart instead, without the third
633
+ * base64 adds.
634
+ */
635
+ function bundleCodec(spec) {
636
+ const notABundle = (cause) => new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, `the file is not ${A_BUNDLE[spec.kind]}`, cause === void 0 ? void 0 : { cause });
637
+ return {
638
+ stringify(bundle, options) {
639
+ const limits = options?.limits ?? DEFAULT_BUNDLE_LIMITS;
640
+ const sizes = /* @__PURE__ */ new Map();
641
+ for (const [id, bytes] of Object.entries(bundle.resources)) sizes.set(id, bytes.length);
642
+ spec.assertManifest(bundle, sizes, limits);
643
+ const file = {};
644
+ for (const key of spec.keys) file[key] = bundle[key];
645
+ const resources = {};
646
+ for (const [id, bytes] of Object.entries(bundle.resources)) resources[id] = require_charmap.toBase64(bytes);
647
+ file.resources = resources;
648
+ return JSON.stringify(file);
649
+ },
650
+ async parse(text, options) {
651
+ const limits = options?.limits ?? DEFAULT_BUNDLE_LIMITS;
652
+ const maxLength = Math.ceil(limits.bundleBytes * 4 / 3) + limits.resources * RESOURCE_ENTRY_CHARACTERS + ENVELOPE_CHARACTERS;
653
+ if (text.length > maxLength) throw new require_format.EngineError(require_format.EngineErrorCode.PayloadTooLarge, `the file is ${text.length} characters, more than a bundle within ${limits.bundleBytes} bytes can be`, { details: {
654
+ limit: "bundleBytes",
655
+ max: limits.bundleBytes,
656
+ fileLength: text.length
657
+ } });
658
+ let file;
659
+ try {
660
+ file = JSON.parse(text);
661
+ } catch (error) {
662
+ throw notABundle(error);
663
+ }
664
+ const encoded = typeof file === "object" && file !== null ? file.resources : null;
665
+ if (typeof encoded !== "object" || encoded === null || Array.isArray(encoded)) throw notABundle();
666
+ const sizes = /* @__PURE__ */ new Map();
667
+ for (const [id, value] of Object.entries(encoded)) {
668
+ const size = typeof value === "string" ? require_charmap.decodedLengthOf(value) : null;
669
+ if (size === null) throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, `resource ${id} is not base64`);
670
+ sizes.set(id, size);
671
+ }
672
+ spec.assertManifest(file, sizes, limits);
673
+ const resources = {};
674
+ for (const [id, value] of Object.entries(encoded)) try {
675
+ resources[id] = require_charmap.fromBase64(value);
676
+ } catch (error) {
677
+ throw new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, `resource ${id} is not base64`, { cause: error });
678
+ }
679
+ await require_resolveAnnotationDraft.assertResourceIds(spec.kind, resources);
680
+ const bundle = {};
681
+ for (const key of spec.keys) bundle[key] = file[key];
682
+ bundle.resources = resources;
683
+ return bundle;
684
+ }
685
+ };
686
+ }
687
+ /** The manifest's keys, in the order a file writes them. */
688
+ const ANNOTATION_BUNDLE_KEYS = [
689
+ "format",
690
+ "version",
691
+ "pages",
692
+ "items"
693
+ ];
694
+ const BUNDLE_FIELDS = [...ANNOTATION_BUNDLE_KEYS, "resources"];
695
+ const ITEM_FIELDS = ["data", "resources"];
696
+ /**
697
+ * Check a bundle before anything uses it, the checks cheapest first: its
698
+ * format, its counts and sizes against `limits` (`PayloadTooLarge`), its
699
+ * shape and references (`InvalidArg`), then every resource against its id.
700
+ */
701
+ async function assertAnnotationBundle(bundle, limits = DEFAULT_BUNDLE_LIMITS) {
702
+ const resources = require_resolveAnnotationDraft.isRecord(bundle?.resources) ? bundle.resources : require_resolveAnnotationDraft.invalidBundle("annotation", "no resources");
703
+ const sizes = /* @__PURE__ */ new Map();
704
+ for (const [id, bytes] of Object.entries(resources)) {
705
+ if (!(bytes instanceof Uint8Array)) require_resolveAnnotationDraft.invalidBundle("annotation", `resource ${id} is not bytes`);
706
+ sizes.set(id, bytes.length);
707
+ }
708
+ assertAnnotationBundleManifest(bundle, sizes, limits);
709
+ await require_resolveAnnotationDraft.assertResourceIds("annotation", resources);
710
+ }
711
+ /**
712
+ * The checks that need no resource bytes, only their sizes by id: format
713
+ * and version, counts, sizes, the shape of pages and items, and that items
714
+ * and resources name each other exactly.
715
+ */
716
+ function assertAnnotationBundleManifest(manifest, resourceSizes, limits) {
717
+ if (!require_resolveAnnotationDraft.isRecord(manifest)) require_resolveAnnotationDraft.invalidBundle("annotation", "not an annotation bundle");
718
+ require_resolveAnnotationDraft.assertKnownFields("annotation", "the bundle", manifest, BUNDLE_FIELDS);
719
+ if (manifest.format !== "embedpdf/annotations") require_resolveAnnotationDraft.invalidBundle("annotation", `unknown format ${JSON.stringify(manifest.format)}`);
720
+ if (manifest.version !== 1) require_resolveAnnotationDraft.invalidBundle("annotation", `unknown version ${JSON.stringify(manifest.version)}`);
721
+ const { pages, items } = manifest;
722
+ if (!Array.isArray(pages)) require_resolveAnnotationDraft.invalidBundle("annotation", "pages is not a list");
723
+ if (!Array.isArray(items)) require_resolveAnnotationDraft.invalidBundle("annotation", "items is not a list");
724
+ assertWithinLimit("annotation", limits, "items", items.length);
725
+ assertWithinLimit("annotation", limits, "pages", pages.length);
726
+ assertWithinLimit("annotation", limits, "resources", resourceSizes.size);
727
+ let bundleBytes = manifestBytesOf({
728
+ pages,
729
+ items
730
+ });
731
+ assertWithinLimit("annotation", limits, "manifestBytes", bundleBytes);
732
+ for (const size of resourceSizes.values()) {
733
+ assertWithinLimit("annotation", limits, "resourceBytes", size);
734
+ bundleBytes += size;
735
+ }
736
+ assertWithinLimit("annotation", limits, "bundleBytes", bundleBytes);
737
+ const pageKeys = require_resolveAnnotationDraft.assertBundlePages("annotation", pages);
738
+ const named = /* @__PURE__ */ new Set();
739
+ items.forEach((item, index) => {
740
+ if (!require_resolveAnnotationDraft.isRecord(item) || !require_resolveAnnotationDraft.isRecord(item.data) || typeof item.data.subtype !== "string") require_resolveAnnotationDraft.invalidBundle("annotation", `item ${index} has no annotation data`);
741
+ require_resolveAnnotationDraft.assertKnownFields("annotation", `item ${index}`, item, ITEM_FIELDS);
742
+ const ref = item.data.ref;
743
+ const page = require_resolveAnnotationDraft.isRecord(ref) ? ref.page : void 0;
744
+ if (!require_resolveAnnotationDraft.isBundlePageRef(page) || !pageKeys.has(require_format.encodePageKey(page))) require_resolveAnnotationDraft.invalidBundle("annotation", `item ${index} is on a page the bundle doesn't list`);
745
+ require_resolveAnnotationDraft.assertRowResources("annotation", `item ${index}`, item.resources, ANNOTATION_RESOURCE_ROLE_NAMES, resourceSizes, named);
746
+ });
747
+ require_resolveAnnotationDraft.assertResourcesNamed("annotation", "item", resourceSizes, named);
748
+ }
749
+ //#endregion
750
+ //#region src/transfer/AnnotationTransfer.ts
751
+ /**
752
+ * An annotation bundle as one JSON file, each resource in base64: a bundle
753
+ * whole, to store or download. HTTP carries bundles as multipart instead,
754
+ * without the third base64 adds.
755
+ */
756
+ const AnnotationTransfer = bundleCodec({
757
+ kind: "annotation",
758
+ keys: ANNOTATION_BUNDLE_KEYS,
759
+ assertManifest: assertAnnotationBundleManifest
760
+ });
761
+ //#endregion
762
+ //#region src/dto/Attachment.ts
763
+ /**
764
+ * How much of a file the local engine decodes: a download of a larger file,
765
+ * from either home, is refused with `PayloadTooLarge`, before a small stream
766
+ * that inflates to gigabytes takes the tab down. A file's declared size
767
+ * can't be trusted. The cloud engine has its server's limit.
768
+ */
769
+ const ATTACHMENT_LIMITS = { decodedBytes: 256 * 1024 * 1024 };
770
+ /** The ref of an attachment whose name-tree key you already hold. */
771
+ function toAttachmentRef(key) {
772
+ return {
773
+ kind: "key",
774
+ key
775
+ };
776
+ }
777
+ //#endregion
778
+ //#region src/annotation/appearanceTurn.ts
779
+ /** The kinds drawn about a box that can turn. */
780
+ const BOX_KINDS = /* @__PURE__ */ new Set([
781
+ "square",
782
+ "circle",
783
+ "free-text",
784
+ "stamp",
785
+ "caret"
786
+ ]);
787
+ /**
788
+ * The turn an annotation's appearance raster is drawn without, degrees
789
+ * clockwise, or `null` when the raster is drawn as the page shows it. A box
790
+ * kind drawn turned whose drawing stays inside the turned box (its `rect` is
791
+ * the upright box around it) renders upright over its `box`, for the
792
+ * consumer to turn about the middle of `box`: a new turn needs no new
793
+ * raster. A callout (its line isn't turned) and a drawing that reaches past
794
+ * its box (a cloudy border's bumps) render as the page shows them, placed by
795
+ * `rect`.
796
+ */
797
+ function pdfAppearanceTurnOf(annotation) {
798
+ const { subtype, rect, box, rotation, intent } = annotation;
799
+ if (!BOX_KINDS.has(subtype) || !box || !rotation) return null;
800
+ if (subtype === "free-text" && intent === "free-text-callout") return null;
801
+ return require_resolveAnnotationDraft.isSamePdfRect(require_resolveAnnotationDraft.pdfRectTurnedBounds(box, rotation), rect) ? rotation : null;
802
+ }
803
+ //#endregion
804
+ //#region src/annotation/resolve/applyAnnotationPatch.ts
805
+ /**
806
+ * A resolved patch's fields as a read spells them. Most fields read as they
807
+ * are written; these take a different shape on the way in.
808
+ */
809
+ function readValueOf(name, value, current) {
810
+ if (value === null) return null;
811
+ switch (name) {
812
+ case "reply": {
813
+ const reply = value;
814
+ return {
815
+ to: reply.to,
816
+ type: reply.type ?? "reply"
817
+ };
818
+ }
819
+ case "richText": {
820
+ const input = value;
821
+ const read = current;
822
+ const body = input.body ? {
823
+ ...require_resolveAnnotationDraft.DEFAULT_RICH_TEXT_BODY,
824
+ ...input.body
825
+ } : read?.body ?? require_resolveAnnotationDraft.DEFAULT_RICH_TEXT_BODY;
826
+ return {
827
+ body: {
828
+ ...body,
829
+ color: body.color.toLowerCase()
830
+ },
831
+ paragraphs: input.paragraphs.map((paragraph) => ({
832
+ ...paragraph,
833
+ runs: paragraph.runs.filter((run) => run.text !== "").map((run) => run.style?.color ? {
834
+ ...run,
835
+ style: {
836
+ ...run.style,
837
+ color: run.style.color.toLowerCase()
838
+ }
839
+ } : run)
840
+ }))
841
+ };
842
+ }
843
+ case "file": {
844
+ const written = value;
845
+ return {
846
+ ...current ?? {
847
+ size: null,
848
+ checksum: null,
849
+ createdAt: null,
850
+ modifiedAt: null
851
+ },
852
+ name: written.name,
853
+ mimeType: written.mimeType ?? null,
854
+ description: written.description ?? null
855
+ };
856
+ }
857
+ default: return value;
858
+ }
859
+ }
860
+ /**
861
+ * `current` with a resolved patch's data fields in place, each as a read
862
+ * spells it. Fields the engine works out or stamps itself (a drawn kind's
863
+ * `rect`, the modified date and author) keep
864
+ * the value `current` has: the engine's answer brings the new one. Works in
865
+ * either space: it only moves values by field name.
866
+ */
867
+ function applyResolvedPatch(current, resolved) {
868
+ const owners = require_resolveAnnotationDraft.kindFactsOf(current.subtype)?.owners ?? {};
869
+ const read = current;
870
+ const next = { ...read };
871
+ for (const [name, value] of Object.entries(resolved)) {
872
+ if (name === "subtype" || value === void 0) continue;
873
+ if (owners[name] !== "data") continue;
874
+ next[name] = readValueOf(name, value, read[name]);
875
+ }
876
+ return {
877
+ ...next,
878
+ ...followingReads(current, resolved)
879
+ };
880
+ }
881
+ /**
882
+ * Fields the engine keeps as found, but rewrites when a data field they
883
+ * mirror changes: a link's `target` is the root of its `/A`, so a new target
884
+ * is a new `actions.activate` (and no target, none).
885
+ */
886
+ function followingReads(current, resolved) {
887
+ if (current.subtype !== "link" || resolved.subtype !== "link") return {};
888
+ const target = resolved.target;
889
+ if (target === void 0 || target !== null && target.kind !== "uri" && target.kind !== "goto") return {};
890
+ const { activate: _replaced, ...others } = current.actions ?? {};
891
+ const actions = target === null ? others : {
892
+ ...others,
893
+ activate: actionTreeOf(target)
894
+ };
895
+ return { actions: Object.keys(actions).length > 0 ? actions : null };
896
+ }
897
+ //#endregion
898
+ //#region src/annotation/defaults.ts
899
+ const RED = "#ff0000";
900
+ const BLACK = "#000000";
901
+ const YELLOW = "#ffff00";
902
+ /** Every kind: printed (as Acrobat creates them), no other flag set, normal blending. A popup doesn't print. */
903
+ const BASE = {
904
+ invisible: false,
905
+ hidden: false,
906
+ print: true,
907
+ noZoom: false,
908
+ noRotate: false,
909
+ noView: false,
910
+ readOnly: false,
911
+ locked: false,
912
+ toggleNoView: false,
913
+ lockedContents: false,
914
+ blendMode: "normal"
915
+ };
916
+ /** Shapes and lines: a solid red line, one point wide. */
917
+ const STROKE = {
918
+ ...BASE,
919
+ color: RED,
920
+ opacity: 1,
921
+ strokeWidth: 1,
922
+ borderStyle: "solid"
923
+ };
924
+ const NO_ENDINGS = {
925
+ start: "none",
926
+ end: "none"
927
+ };
928
+ /** Text markup other than a highlight: black. */
929
+ const MARKUP = {
930
+ ...BASE,
931
+ color: BLACK,
932
+ opacity: 1
933
+ };
934
+ const ANNOTATION_DEFAULTS = {
935
+ square: STROKE,
936
+ circle: STROKE,
937
+ line: {
938
+ ...STROKE,
939
+ lineEndings: NO_ENDINGS,
940
+ captionPosition: "inline"
941
+ },
942
+ polygon: STROKE,
943
+ polyline: {
944
+ ...STROKE,
945
+ lineEndings: NO_ENDINGS
946
+ },
947
+ ink: STROKE,
948
+ highlight: {
949
+ ...BASE,
950
+ blendMode: "multiply",
951
+ color: YELLOW,
952
+ opacity: 1
953
+ },
954
+ underline: MARKUP,
955
+ squiggly: MARKUP,
956
+ strikeout: MARKUP,
957
+ caret: {
958
+ ...BASE,
959
+ color: RED,
960
+ opacity: 1
961
+ },
962
+ "free-text": {
963
+ ...BASE,
964
+ contents: "",
965
+ intent: "free-text",
966
+ fontFamily: "helvetica",
967
+ fontSize: 12,
968
+ textAlign: "left",
969
+ verticalAlign: "top",
970
+ color: BLACK,
971
+ fontColor: BLACK,
972
+ opacity: 1,
973
+ strokeWidth: 1,
974
+ borderStyle: "solid"
975
+ },
976
+ text: {
977
+ ...BASE,
978
+ icon: "note",
979
+ open: false,
980
+ color: YELLOW,
981
+ opacity: 1
982
+ },
983
+ "file-attachment": {
984
+ ...BASE,
985
+ icon: "paperclip",
986
+ color: YELLOW,
987
+ opacity: 1
988
+ },
989
+ link: BASE,
990
+ redact: {
991
+ ...BASE,
992
+ quadPoints: [],
993
+ color: RED,
994
+ opacity: 1,
995
+ repeat: false,
996
+ fontFamily: "helvetica",
997
+ fontSize: 12,
998
+ fontColor: BLACK,
999
+ textAlign: "left"
1000
+ },
1001
+ stamp: {
1002
+ ...BASE,
1003
+ fit: "contain",
1004
+ opacity: 1
1005
+ },
1006
+ widget: {
1007
+ ...BASE,
1008
+ strokeWidth: 1,
1009
+ borderStyle: "solid",
1010
+ textAlign: "left"
1011
+ },
1012
+ popup: {
1013
+ ...BASE,
1014
+ print: false,
1015
+ open: false
1016
+ }
1017
+ };
1018
+ /** What a create of `subtype` reads back for each data field it leaves out. */
1019
+ function annotationDefaultsOf(subtype) {
1020
+ return subtype === "unsupported" ? {} : ANNOTATION_DEFAULTS[subtype];
1021
+ }
1022
+ //#endregion
1023
+ //#region src/pageSpace/destinations.ts
1024
+ const boxFor = (page, box) => typeof box === "function" ? box(page) : box;
1025
+ /** An axis value that may keep the current one (`null`) or be left out. */
1026
+ const across = (value, convert) => value == null ? value : convert(value);
1027
+ /**
1028
+ * A destination in the file's coordinates, in page space: for one read by
1029
+ * another PDF tool, before handing it to the viewer. `box` is the `pdfCropBox`
1030
+ * of the page it goes to.
1031
+ */
1032
+ function pageDestinationOf(destination, box) {
1033
+ const { left: boxLeft, top: boxTop } = boxFor(destination.page, box);
1034
+ const x = (left) => across(left, (value) => value - boxLeft);
1035
+ const y = (top) => across(top, (value) => boxTop - value);
1036
+ switch (destination.kind) {
1037
+ case "xyz": {
1038
+ const { left, top, ...rest } = destination;
1039
+ return {
1040
+ ...rest,
1041
+ ..."left" in destination ? { x: x(left) } : {},
1042
+ ..."top" in destination ? { y: y(top) } : {}
1043
+ };
1044
+ }
1045
+ case "fitH":
1046
+ case "fitBH": {
1047
+ const { top, ...rest } = destination;
1048
+ return {
1049
+ ...rest,
1050
+ ..."top" in destination ? { y: y(top) } : {}
1051
+ };
1052
+ }
1053
+ case "fitV":
1054
+ case "fitBV": {
1055
+ const { left, ...rest } = destination;
1056
+ return {
1057
+ ...rest,
1058
+ ..."left" in destination ? { x: x(left) } : {}
1059
+ };
1060
+ }
1061
+ case "fitR": {
1062
+ const { left, bottom, right, top, ...rest } = destination;
1063
+ const lower = Math.min(bottom, top);
1064
+ const upper = Math.max(bottom, top);
1065
+ return {
1066
+ ...rest,
1067
+ x: Math.min(left, right) - boxLeft,
1068
+ y: boxTop - upper,
1069
+ width: Math.abs(right - left),
1070
+ height: upper - lower
1071
+ };
1072
+ }
1073
+ case "fit":
1074
+ case "fitB": return destination;
1075
+ }
1076
+ }
1077
+ /**
1078
+ * A page-space destination in the file's coordinates: for handing one to
1079
+ * another PDF tool. `box` is the `pdfCropBox` of the page it goes to.
1080
+ */
1081
+ function pdfDestinationOf(destination, box) {
1082
+ const { left: boxLeft, top: boxTop } = boxFor(destination.page, box);
1083
+ const left = (x) => across(x, (value) => value + boxLeft);
1084
+ const top = (y) => across(y, (value) => boxTop - value);
1085
+ switch (destination.kind) {
1086
+ case "xyz": {
1087
+ const { x, y, ...rest } = destination;
1088
+ return {
1089
+ ...rest,
1090
+ ..."x" in destination ? { left: left(x) } : {},
1091
+ ..."y" in destination ? { top: top(y) } : {}
1092
+ };
1093
+ }
1094
+ case "fitH":
1095
+ case "fitBH": {
1096
+ const { y, ...rest } = destination;
1097
+ return {
1098
+ ...rest,
1099
+ ..."y" in destination ? { top: top(y) } : {}
1100
+ };
1101
+ }
1102
+ case "fitV":
1103
+ case "fitBV": {
1104
+ const { x, ...rest } = destination;
1105
+ return {
1106
+ ...rest,
1107
+ ..."x" in destination ? { left: left(x) } : {}
1108
+ };
1109
+ }
1110
+ case "fitR": {
1111
+ const { x, y, width, height, ...rest } = destination;
1112
+ const upper = boxTop - y;
1113
+ return {
1114
+ ...rest,
1115
+ left: x + boxLeft,
1116
+ bottom: upper - height,
1117
+ right: x + boxLeft + width,
1118
+ top: upper
1119
+ };
1120
+ }
1121
+ case "fit":
1122
+ case "fitB": return destination;
1123
+ }
1124
+ }
1125
+ function mapLinkTarget(target, convert) {
1126
+ return target.kind === "goto" ? {
1127
+ ...target,
1128
+ destination: convert(target.destination)
1129
+ } : target;
1130
+ }
1131
+ function mapActionNode(node, convert) {
1132
+ const next = node.next.map((child) => mapActionNode(child, convert));
1133
+ return node.type === "goto" ? {
1134
+ ...node,
1135
+ next,
1136
+ destination: convert(node.destination)
1137
+ } : {
1138
+ ...node,
1139
+ next
1140
+ };
1141
+ }
1142
+ function mapActionTree(tree, convert) {
1143
+ return {
1144
+ ...tree,
1145
+ root: tree.root ? mapActionNode(tree.root, convert) : null
1146
+ };
1147
+ }
1148
+ /** An action to write, its destinations converted. */
1149
+ function mapActionWrite(action, convert) {
1150
+ const next = action.next?.map((child) => mapActionWrite(child, convert));
1151
+ const converted = action.type === "goto" ? {
1152
+ ...action,
1153
+ destination: convert(action.destination)
1154
+ } : action;
1155
+ return next ? {
1156
+ ...converted,
1157
+ next
1158
+ } : converted;
1159
+ }
1160
+ /**
1161
+ * A record of triggers as a read has them (trees) or a write takes them
1162
+ * (actions to write, `null` to remove one), its destinations converted.
1163
+ */
1164
+ function mapTriggerActions(triggers, convert) {
1165
+ return Object.fromEntries(Object.entries(triggers).map(([trigger, value]) => {
1166
+ if (value == null) return [trigger, value];
1167
+ return [trigger, "root" in value ? mapActionTree(value, convert) : mapActionWrite(value, convert)];
1168
+ }));
1169
+ }
1170
+ /** Every action tree in a record of triggers (an annotation's, a page's or a field's). */
1171
+ function mapTriggers(triggers, convert) {
1172
+ return Object.fromEntries(Object.entries(triggers).map(([trigger, tree]) => [trigger, tree ? mapActionTree(tree, convert) : tree]));
1173
+ }
1174
+ function mapAnnotationActions(actions, convert) {
1175
+ return mapTriggers(actions, convert);
1176
+ }
1177
+ function mapPageActions(actions, convert) {
1178
+ return mapTriggers(actions, convert);
1179
+ }
1180
+ function mapFieldActions(actions, convert) {
1181
+ return mapTriggers(actions, convert);
1182
+ }
1183
+ function mapDocumentActions(snapshot, convert) {
1184
+ const { nameTreeScripts, openAction, openDestination, ...triggers } = snapshot;
1185
+ return {
1186
+ ...mapTriggers(triggers, convert),
1187
+ nameTreeScripts: nameTreeScripts.map((script) => ({
1188
+ ...script,
1189
+ action: mapActionTree(script.action, convert)
1190
+ })),
1191
+ openAction: openAction ? mapActionTree(openAction, convert) : null,
1192
+ ..."openDestination" in snapshot ? { openDestination: openDestination ? convert(openDestination) : openDestination } : {}
1193
+ };
1194
+ }
1195
+ //#endregion
1196
+ //#region src/pageSpace/measure.ts
1197
+ const withOrigin = (measure, convert) => measure.subtype === "rectilinear" && measure.origin ? {
1198
+ ...measure,
1199
+ origin: convert(measure.origin)
1200
+ } : measure;
1201
+ /** A scale in page space: its origin (`/O`) is a place on the page. */
1202
+ function pageMeasureOf(measure, visible) {
1203
+ return withOrigin(measure, (origin) => pagePointOf(origin, visible));
1204
+ }
1205
+ /** A page-space scale in the file's coordinates. */
1206
+ function pdfMeasureOf(measure, visible) {
1207
+ return withOrigin(measure, (origin) => pdfPointOf(origin, visible));
1208
+ }
1209
+ /** A page's measurement viewports in page space. */
1210
+ function pageViewportsOf(viewports, visible) {
1211
+ return viewports.map((viewport) => ({
1212
+ ...viewport,
1213
+ bbox: pageBoxOf(viewport.bbox, visible),
1214
+ measure: viewport.measure ? pageMeasureOf(viewport.measure, visible) : null
1215
+ }));
1216
+ }
1217
+ //#endregion
1218
+ //#region src/pageSpace/annotations.ts
1219
+ const TO_PAGE = {
1220
+ length: (value) => value,
1221
+ point: (point, { visible }) => pagePointOf(point, visible),
1222
+ points: (points, { visible }) => points.map((point) => pagePointOf(point, visible)),
1223
+ strokes: (strokes, { visible }) => strokes.map((stroke) => stroke.map((point) => pagePointOf(point, visible))),
1224
+ box: (rect, { visible }) => pageBoxOf(rect, visible),
1225
+ quads: (quads, { visible }) => quads.map((quad) => pageQuadOf(quad, visible)),
1226
+ linePoints: (line, { visible }) => ({
1227
+ start: pagePointOf(line.start, visible),
1228
+ end: pagePointOf(line.end, visible)
1229
+ }),
1230
+ calloutLine: (points, { visible }) => points.map((point) => pagePointOf(point, visible)),
1231
+ measure: (measure, { visible }) => pageMeasureOf(measure, visible),
1232
+ linkTarget: (target, { boxOf }) => mapLinkTarget(target, (destination) => pageDestinationOf(destination, boxOf)),
1233
+ actions: (actions, { boxOf }) => mapTriggerActions(actions, (destination) => pageDestinationOf(destination, boxOf))
1234
+ };
1235
+ const TO_PDF = {
1236
+ length: (value) => value,
1237
+ point: (point, { visible }) => pdfPointOf(point, visible),
1238
+ points: (points, { visible }) => points.map((point) => pdfPointOf(point, visible)),
1239
+ strokes: (strokes, { visible }) => strokes.map((stroke) => stroke.map((point) => pdfPointOf(point, visible))),
1240
+ box: (box, { visible }) => pdfRectOf(box, visible),
1241
+ quads: (quads, { visible }) => quads.map((quad) => pdfQuadOf(quad, visible)),
1242
+ linePoints: (line, { visible }) => ({
1243
+ start: pdfPointOf(line.start, visible),
1244
+ end: pdfPointOf(line.end, visible)
1245
+ }),
1246
+ calloutLine: (points, { visible }) => points.map((point) => pdfPointOf(point, visible)),
1247
+ measure: (measure, { visible }) => pdfMeasureOf(measure, visible),
1248
+ linkTarget: (target, { boxOf }) => mapLinkTarget(target, (destination) => pdfDestinationOf(destination, boxOf)),
1249
+ actions: (actions, { boxOf }) => mapTriggerActions(actions, (destination) => pdfDestinationOf(destination, boxOf))
1250
+ };
1251
+ /**
1252
+ * The measured fields of a kind; a kind the engine doesn't know has the base
1253
+ * fields. An update may leave out its kind: a field's name says what it
1254
+ * holds, the same in every kind.
1255
+ */
1256
+ const spacesOf = (subtype) => subtype === void 0 ? require_resolveAnnotationDraft.ANNOTATION_FIELD_SPACES_BY_NAME : require_resolveAnnotationDraft.ANNOTATION_FIELD_SPACES[subtype] ?? require_resolveAnnotationDraft.ANNOTATION_FIELD_SPACES.unsupported;
1257
+ function convertFields(subtype, value, frame, converters) {
1258
+ const spaces = spacesOf(subtype);
1259
+ return Object.fromEntries(Object.entries(value).map(([name, field]) => {
1260
+ const space = spaces[name];
1261
+ if (!space || field == null) return [name, field];
1262
+ const converted = converters[space](field, frame);
1263
+ if (converters === TO_PDF && hasNaN(converted)) throw notInPageSpace(name, space);
1264
+ return [name, converted];
1265
+ }));
1266
+ }
1267
+ /** Whether a converted value has a number that isn't one: a place not given in page space. */
1268
+ function hasNaN(value) {
1269
+ if (typeof value === "number") return Number.isNaN(value);
1270
+ if (typeof value !== "object" || value === null) return false;
1271
+ return Object.values(value).some(hasNaN);
1272
+ }
1273
+ function notInPageSpace(name, space) {
1274
+ const shape = space === "box" ? "{ x, y, width, height }" : "points as { x, y }";
1275
+ return new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, `field '${name}': expected page space, ${shape} from the page's top-left`, { details: { field: name } });
1276
+ }
1277
+ /** A read in page space. `visible` is its page's visible box, in the file's coordinates. */
1278
+ function pageAnnotationOf(annotation, visible, boxOf) {
1279
+ return convertFields(annotation.subtype, annotation, {
1280
+ visible,
1281
+ boxOf
1282
+ }, TO_PAGE);
1283
+ }
1284
+ /** A page-space read in the file's coordinates. */
1285
+ function pdfAnnotationOf(annotation, visible, boxOf) {
1286
+ return convertFields(annotation.subtype, annotation, {
1287
+ visible,
1288
+ boxOf
1289
+ }, TO_PDF);
1290
+ }
1291
+ /** A page-space create in the file's coordinates. */
1292
+ function pdfAnnotationDraftOf(draft, visible, boxOf) {
1293
+ return convertFields(draft.subtype, draft, {
1294
+ visible,
1295
+ boxOf
1296
+ }, TO_PDF);
1297
+ }
1298
+ /** A create in the file's coordinates, in page space. */
1299
+ function pageAnnotationDraftOf(draft, visible, boxOf) {
1300
+ return convertFields(draft.subtype, draft, {
1301
+ visible,
1302
+ boxOf
1303
+ }, TO_PAGE);
1304
+ }
1305
+ /**
1306
+ * A page-space update in the file's coordinates. An update may leave out its
1307
+ * `subtype`; its fields' names say what they hold.
1308
+ */
1309
+ function pdfAnnotationPatchOf(patch, visible, boxOf) {
1310
+ return convertFields(patch.subtype, patch, {
1311
+ visible,
1312
+ boxOf
1313
+ }, TO_PDF);
1314
+ }
1315
+ /** An update in the file's coordinates, in page space. */
1316
+ function pageAnnotationPatchOf(patch, visible, boxOf) {
1317
+ return convertFields(patch.subtype, patch, {
1318
+ visible,
1319
+ boxOf
1320
+ }, TO_PAGE);
1321
+ }
1322
+ //#endregion
1323
+ //#region src/text/layout.ts
1324
+ /**
1325
+ * The canonical text-interaction layout — the one place glyph geometry
1326
+ * becomes hit targets, word/line ranges, and visual-line segments.
1327
+ *
1328
+ * Selection owns gestures and state; search owns matching and cursors;
1329
+ * neither owns segmentation. Both consume this module, so a text range has
1330
+ * exactly one canonical segmentation regardless of how it was produced.
1331
+ *
1332
+ * Everything here works in the file's coordinates (y up), as the engine reads
1333
+ * them. The public layout (`createTextLayout`, `pageSpace/text.ts`) runs this
1334
+ * one on page-space geometry flipped top to bottom and flips its answers
1335
+ * back. The line-merge is adapted from Chromium's
1336
+ * pdf/pdfium/pdfium_range.cc `MergeAdjacentRects` (BSD-licensed, Copyright
1337
+ * 2010 The Chromium Authors); hit-testing mirrors PDFium `GetIndexAtPos`
1338
+ * (exact tight box first, then a tolerance pass).
1339
+ *
1340
+ * Orientation model — frames. Every run belongs to a frame: frame 0 is page
1341
+ * space itself (all upright runs — the dominant case takes a byte-identical
1342
+ * fast path), and each rotated orientation cluster gets an orthonormal frame
1343
+ * in which its text reads upright (baseline +x, ascent +y). Frames are
1344
+ * derived from the semantic edges of the first classifiable glyph's quad —
1345
+ * never from advisory wire fields — and keyed by (baseline direction,
1346
+ * ascent handedness):
1347
+ *
1348
+ * - Rotated and mirrored text become upright inside their frame.
1349
+ * - Shear (fake italic) is deliberately not part of the frame key or the
1350
+ * basis: a sheared run shares the frame of its unsheared neighbours, so
1351
+ * a mixed roman/italic line merges into one segment (Acrobat parity),
1352
+ * and the shear is absorbed as a small in-frame AABB residue. This is
1353
+ * the deterministic, order-independent contract — an affine
1354
+ * (shear-preserving) basis would either fragment mixed lines or make
1355
+ * the roman body's geometry depend on whether an italic run came first.
1356
+ * - Runs of different frames never merge into one line.
1357
+ *
1358
+ * All algorithms run on frame-local boxes; every participating run of a
1359
+ * cluster is transformed through the same frame, so merged coordinates are
1360
+ * always commensurable. Only the output maps back to page space, as
1361
+ * oriented quads.
1362
+ */
1363
+ /** A space or a character with no box ends a word. */
1364
+ const isBoundary = (g) => !!(g.space || g.empty);
1365
+ const isEmpty = (g) => !!g.empty;
1366
+ const CHAR_DISTANCE_FACTOR = 2.5;
1367
+ const FONT_SIZE_RATIO_THRESHOLD = 1.5;
1368
+ const VERTICAL_OVERLAP_THRESHOLD = .8;
1369
+ const LINE_OVERLAP_THRESHOLD = .5;
1370
+ /** Baseline directions within ~0.5° share a frame. */
1371
+ const FRAME_DOT_TOLERANCE = Math.cos(.0087);
1372
+ const EDGE_EPSILON = 1e-6;
1373
+ /**
1374
+ * The layout of a page's geometry in the file's coordinates, for the engine's
1375
+ * own readers. Everything else uses `createTextLayout`, in page space.
1376
+ */
1377
+ function createPdfTextLayout(snapshot) {
1378
+ const layout = buildPageTextLayout(snapshot);
1379
+ const charCount = layout.glyphs.length;
1380
+ const indexOf = (at) => {
1381
+ if (typeof at !== "number") return textGlyphAt(layout, at);
1382
+ return Number.isInteger(at) && at >= 0 && at < charCount ? at : null;
1383
+ };
1384
+ const rangeOf = ([from, to]) => ({
1385
+ start: from,
1386
+ count: to - from + 1
1387
+ });
1388
+ return {
1389
+ charCount,
1390
+ runs: snapshot.runs,
1391
+ charAt: (point) => textGlyphAt(layout, point),
1392
+ wordAt: (at) => {
1393
+ const index = indexOf(at);
1394
+ return index === null ? null : rangeOf(expandTextRangeToWord(layout, index));
1395
+ },
1396
+ lineAt: (at) => {
1397
+ const index = indexOf(at);
1398
+ return index === null ? null : rangeOf(expandTextRangeToLine(layout, index));
1399
+ },
1400
+ segments: (range) => textSegmentsForRange(layout, range.start, range.count),
1401
+ charQuad: (index) => textGlyphQuad(layout, index)
1402
+ };
1403
+ }
1404
+ const IDENTITY_FRAME = {
1405
+ baseline: {
1406
+ x: 1,
1407
+ y: 0
1408
+ },
1409
+ ascent: {
1410
+ x: 0,
1411
+ y: 1
1412
+ }
1413
+ };
1414
+ const toFrame = (f, p) => ({
1415
+ x: p.x * f.baseline.x + p.y * f.baseline.y,
1416
+ y: p.x * f.ascent.x + p.y * f.ascent.y
1417
+ });
1418
+ const fromFrame = (f, p) => ({
1419
+ x: f.baseline.x * p.x + f.ascent.x * p.y,
1420
+ y: f.baseline.y * p.x + f.ascent.y * p.y
1421
+ });
1422
+ const ZERO_RECT = {
1423
+ left: 0,
1424
+ bottom: 0,
1425
+ right: 0,
1426
+ top: 0
1427
+ };
1428
+ /** Frame-local AABB of a page-space cell (exact under the frame's rotation;
1429
+ * shear residue is the documented in-frame envelope). */
1430
+ function frameBoxOfQuad(f, q) {
1431
+ const pts = [
1432
+ q.upperLeft,
1433
+ q.upperRight,
1434
+ q.lowerLeft,
1435
+ q.lowerRight
1436
+ ].map((p) => toFrame(f, p));
1437
+ const xs = pts.map((p) => p.x);
1438
+ const ys = pts.map((p) => p.y);
1439
+ return {
1440
+ left: Math.min(...xs),
1441
+ bottom: Math.min(...ys),
1442
+ right: Math.max(...xs),
1443
+ top: Math.max(...ys)
1444
+ };
1445
+ }
1446
+ /** Find-or-create the frame for a rotated run, keyed by the baseline
1447
+ * direction + ascent handedness of its first classifiable glyph's edges. */
1448
+ function frameForRun(frames, run) {
1449
+ const seed = run.glyphs.find((g) => !isEmpty(g));
1450
+ if (!seed) return 0;
1451
+ const q = seed.loose;
1452
+ const bx = q.upperRight.x - q.upperLeft.x;
1453
+ const by = q.upperRight.y - q.upperLeft.y;
1454
+ const len = Math.hypot(bx, by);
1455
+ if (len <= EDGE_EPSILON) return 0;
1456
+ const baseline = {
1457
+ x: bx / len,
1458
+ y: by / len
1459
+ };
1460
+ const ax = q.upperLeft.x - q.lowerLeft.x;
1461
+ const ay = q.upperLeft.y - q.lowerLeft.y;
1462
+ const sign = baseline.x * ay - baseline.y * ax >= 0 ? 1 : -1;
1463
+ const ascent = {
1464
+ x: -baseline.y * sign,
1465
+ y: baseline.x * sign
1466
+ };
1467
+ for (let i = 0; i < frames.length; i++) {
1468
+ const f = frames[i];
1469
+ const dot = f.baseline.x * baseline.x + f.baseline.y * baseline.y;
1470
+ const sameHandedness = f.ascent.x * ascent.x + f.ascent.y * ascent.y > 0;
1471
+ if (dot >= FRAME_DOT_TOLERANCE && sameHandedness) return i;
1472
+ }
1473
+ frames.push({
1474
+ baseline,
1475
+ ascent
1476
+ });
1477
+ return frames.length - 1;
1478
+ }
1479
+ /**
1480
+ * Flatten a page's geometry snapshot into the canonical layout. Upright runs
1481
+ * copy their wire boxes verbatim (frame 0, wire run rects included); rotated
1482
+ * runs project their glyph cells into their cluster's frame.
1483
+ */
1484
+ function buildPageTextLayout(snapshot) {
1485
+ const glyphs = [];
1486
+ const runs = [];
1487
+ const frames = [IDENTITY_FRAME];
1488
+ for (const run of snapshot.runs) {
1489
+ if (!isRotatedGeometryRun(run)) {
1490
+ for (const g of run.glyphs) glyphs.push({
1491
+ loose: g.loose,
1492
+ tight: g.tight,
1493
+ space: g.space,
1494
+ empty: g.empty
1495
+ });
1496
+ runs.push({
1497
+ start: run.start,
1498
+ count: run.glyphs.length,
1499
+ rect: run.rect,
1500
+ fontSize: run.fontSize,
1501
+ frame: 0
1502
+ });
1503
+ continue;
1504
+ }
1505
+ const frame = frameForRun(frames, run);
1506
+ const f = frames[frame];
1507
+ let runBox = null;
1508
+ for (const g of run.glyphs) {
1509
+ if (isEmpty(g)) {
1510
+ glyphs.push({
1511
+ loose: ZERO_RECT,
1512
+ space: g.space,
1513
+ empty: true
1514
+ });
1515
+ continue;
1516
+ }
1517
+ const loose = frameBoxOfQuad(f, g.loose);
1518
+ const tight = g.tight ? frameBoxOfQuad(f, g.tight) : void 0;
1519
+ glyphs.push({
1520
+ loose,
1521
+ tight,
1522
+ space: g.space
1523
+ });
1524
+ runBox = runBox ? {
1525
+ left: Math.min(runBox.left, loose.left),
1526
+ bottom: Math.min(runBox.bottom, loose.bottom),
1527
+ right: Math.max(runBox.right, loose.right),
1528
+ top: Math.max(runBox.top, loose.top)
1529
+ } : loose;
1530
+ }
1531
+ runs.push({
1532
+ start: run.start,
1533
+ count: run.glyphs.length,
1534
+ rect: runBox ?? ZERO_RECT,
1535
+ fontSize: run.fontSize,
1536
+ frame
1537
+ });
1538
+ }
1539
+ return {
1540
+ glyphs,
1541
+ runs,
1542
+ frames
1543
+ };
1544
+ }
1545
+ const inRect = (r, p) => p.x >= r.left && p.x <= r.right && p.y >= r.bottom && p.y <= r.top;
1546
+ function avgGlyphHeight(layout) {
1547
+ let total = 0;
1548
+ let count = 0;
1549
+ for (const g of layout.glyphs) {
1550
+ if (isEmpty(g)) continue;
1551
+ total += g.loose.top - g.loose.bottom;
1552
+ count++;
1553
+ }
1554
+ return count === 0 ? 0 : total / count;
1555
+ }
1556
+ /** The point expressed in every frame (index-aligned with `layout.frames`).
1557
+ * Frame 0 returns the point itself — no float round-trip on the fast path. */
1558
+ function pointPerFrame(layout, p) {
1559
+ return layout.frames.map((f, i) => i === 0 ? p : toFrame(f, p));
1560
+ }
1561
+ /**
1562
+ * The glyph (char) index at a page-space point, or null when nothing is near
1563
+ * (so callers can show the pointer cursor off-text). PDFium `GetIndexAtPos`:
1564
+ * exact tight-box containment first, then a tolerance pass (closest by
1565
+ * Manhattan distance within `toleranceFactor × average glyph height`). Each
1566
+ * run tests the point in its own frame, so rotated text hit-tests exactly.
1567
+ */
1568
+ function textGlyphAt(layout, point, toleranceFactor = 1.5) {
1569
+ const pts = pointPerFrame(layout, point);
1570
+ for (const run of layout.runs) {
1571
+ const q = pts[run.frame];
1572
+ if (!inRect(run.rect, q)) continue;
1573
+ for (let i = 0; i < run.count; i++) {
1574
+ const g = layout.glyphs[run.start + i];
1575
+ if (inRect(g.tight ?? g.loose, q)) return run.start + i;
1576
+ }
1577
+ }
1578
+ if (toleranceFactor <= 0) return null;
1579
+ const half = avgGlyphHeight(layout) * toleranceFactor / 2;
1580
+ let best = -1;
1581
+ let bestDist = Infinity;
1582
+ for (const run of layout.runs) {
1583
+ const q = pts[run.frame];
1584
+ const r = run.rect;
1585
+ if (q.x < r.left - half || q.x > r.right + half || q.y < r.bottom - half || q.y > r.top + half) continue;
1586
+ for (let i = 0; i < run.count; i++) {
1587
+ const g = layout.glyphs[run.start + i];
1588
+ if (isEmpty(g)) continue;
1589
+ const b = g.tight ?? g.loose;
1590
+ if (q.x < b.left - half || q.x > b.right + half || q.y < b.bottom - half || q.y > b.top + half) continue;
1591
+ const dx = Math.min(Math.abs(q.x - b.left), Math.abs(q.x - b.right));
1592
+ const dy = Math.min(Math.abs(q.y - b.bottom), Math.abs(q.y - b.top));
1593
+ if (dx + dy < bestDist - EDGE_EPSILON) {
1594
+ bestDist = dx + dy;
1595
+ best = run.start + i;
1596
+ }
1597
+ }
1598
+ }
1599
+ return best >= 0 ? best : null;
1600
+ }
1601
+ /** Double-click: the word around `glyph` (walk to space/empty glyphs both ways). */
1602
+ function expandTextRangeToWord(layout, glyph) {
1603
+ const n = layout.glyphs.length;
1604
+ if (glyph < 0 || glyph >= n) return [glyph, glyph];
1605
+ let from = glyph;
1606
+ while (from > 0 && !isBoundary(layout.glyphs[from - 1])) from--;
1607
+ let to = glyph;
1608
+ while (to < n - 1 && !isBoundary(layout.glyphs[to + 1])) to++;
1609
+ return [from, to];
1610
+ }
1611
+ /** Triple-click: the full visual line — same-frame runs whose vertical extent
1612
+ * overlaps the anchor run's. A differently-oriented run is a line boundary. */
1613
+ function expandTextRangeToLine(layout, glyph) {
1614
+ const ri = layout.runs.findIndex((r) => glyph >= r.start && glyph < r.start + r.count);
1615
+ if (ri < 0) return [glyph, glyph];
1616
+ const anchor = layout.runs[ri];
1617
+ const bottom = anchor.rect.bottom;
1618
+ const top = anchor.rect.top;
1619
+ let from = anchor.start;
1620
+ let to = anchor.start + anchor.count - 1;
1621
+ for (let r = ri - 1; r >= 0; r--) {
1622
+ const run = layout.runs[r];
1623
+ if (isZero(run.rect)) continue;
1624
+ if (run.frame !== anchor.frame) break;
1625
+ if (!overlapV(run.rect.bottom, run.rect.top, bottom, top)) break;
1626
+ from = run.start;
1627
+ }
1628
+ for (let r = ri + 1; r < layout.runs.length; r++) {
1629
+ const run = layout.runs[r];
1630
+ if (isZero(run.rect)) continue;
1631
+ if (run.frame !== anchor.frame) break;
1632
+ if (!overlapV(run.rect.bottom, run.rect.top, bottom, top)) break;
1633
+ to = run.start + run.count - 1;
1634
+ }
1635
+ return [from, to];
1636
+ }
1637
+ /**
1638
+ * A single glyph's oriented cell in page space, or null for degenerate
1639
+ * glyphs — the anchor for caret placement at a selection boundary.
1640
+ */
1641
+ function textGlyphQuad(layout, glyph) {
1642
+ const g = layout.glyphs[glyph];
1643
+ if (!g || isEmpty(g)) return null;
1644
+ const b = g.loose;
1645
+ if (b.right <= b.left || b.top <= b.bottom) return null;
1646
+ const run = layout.runs.find((r) => glyph >= r.start && glyph < r.start + r.count);
1647
+ const f = layout.frames[run?.frame ?? 0];
1648
+ return quadOfFrameRect(f, run?.frame ?? 0, b);
1649
+ }
1650
+ /**
1651
+ * Merged visual-line segments for the half-open char range
1652
+ * `[start, start + count)` — the canonical segmentation. Chars
1653
+ * outside the layout are ignored.
1654
+ */
1655
+ function textSegmentsForRange(layout, start, count) {
1656
+ if (count <= 0 || layout.glyphs.length === 0) return [];
1657
+ const lo = Math.max(0, start);
1658
+ const hi = Math.min(layout.glyphs.length - 1, start + count - 1);
1659
+ if (hi < lo) return [];
1660
+ const subRuns = [];
1661
+ for (const run of layout.runs) {
1662
+ const runEnd = run.start + run.count - 1;
1663
+ if (runEnd < lo || run.start > hi) continue;
1664
+ const s = Math.max(lo, run.start);
1665
+ const e = Math.min(hi, runEnd);
1666
+ let left = Infinity;
1667
+ let right = -Infinity;
1668
+ let bottom = Infinity;
1669
+ let top = -Infinity;
1670
+ let charCountAcc = 0;
1671
+ let widthSum = 0;
1672
+ let prevRight = -Infinity;
1673
+ let firstX = 0;
1674
+ let lastX = 0;
1675
+ const flush = () => {
1676
+ if (charCountAcc > 0 && left !== Infinity) subRuns.push({
1677
+ rect: {
1678
+ left,
1679
+ bottom,
1680
+ right,
1681
+ top
1682
+ },
1683
+ charCount: charCountAcc,
1684
+ fontSize: run.fontSize,
1685
+ frame: run.frame,
1686
+ firstX,
1687
+ lastX
1688
+ });
1689
+ left = Infinity;
1690
+ right = -Infinity;
1691
+ bottom = Infinity;
1692
+ top = -Infinity;
1693
+ charCountAcc = 0;
1694
+ widthSum = 0;
1695
+ prevRight = -Infinity;
1696
+ };
1697
+ for (let ci = s; ci <= e; ci++) {
1698
+ const g = layout.glyphs[ci];
1699
+ if (isEmpty(g)) continue;
1700
+ const b = g.loose;
1701
+ if (charCountAcc > 0 && prevRight > -Infinity) {
1702
+ const avg = widthSum / charCountAcc;
1703
+ if (avg > 0 && Math.abs(b.left - prevRight) > CHAR_DISTANCE_FACTOR * avg) flush();
1704
+ }
1705
+ const centerX = (b.left + b.right) / 2;
1706
+ if (charCountAcc === 0) firstX = centerX;
1707
+ lastX = centerX;
1708
+ left = Math.min(left, b.left);
1709
+ right = Math.max(right, b.right);
1710
+ bottom = Math.min(bottom, b.bottom);
1711
+ top = Math.max(top, b.top);
1712
+ charCountAcc++;
1713
+ widthSum += b.right - b.left;
1714
+ prevRight = b.right;
1715
+ }
1716
+ flush();
1717
+ }
1718
+ return mergeAdjacentSubRuns(subRuns).map((m) => materializeSegment(layout, m));
1719
+ }
1720
+ function mergeAdjacentSubRuns(runs) {
1721
+ const out = [];
1722
+ let prev = null;
1723
+ let cur = null;
1724
+ for (const run of runs) {
1725
+ if (prev && cur && prev.frame === run.frame && shouldMerge(prev, run)) cur = {
1726
+ rect: {
1727
+ left: Math.min(cur.rect.left, run.rect.left),
1728
+ bottom: Math.min(cur.rect.bottom, run.rect.bottom),
1729
+ right: Math.max(cur.rect.right, run.rect.right),
1730
+ top: Math.max(cur.rect.top, run.rect.top)
1731
+ },
1732
+ frame: cur.frame,
1733
+ firstX: cur.firstX,
1734
+ lastX: run.lastX
1735
+ };
1736
+ else {
1737
+ if (cur) out.push(cur);
1738
+ cur = {
1739
+ rect: run.rect,
1740
+ frame: run.frame,
1741
+ firstX: run.firstX,
1742
+ lastX: run.lastX
1743
+ };
1744
+ }
1745
+ prev = run;
1746
+ }
1747
+ if (cur && cur.rect.right > cur.rect.left && cur.rect.top > cur.rect.bottom) out.push(cur);
1748
+ return out;
1749
+ }
1750
+ /** Segment quad for a frame-local rect (frame 0: the rect's own corners,
1751
+ * no float round-trip). The frame is y-up, so the upper corners sit at the
1752
+ * frame top. */
1753
+ function quadOfFrameRect(f, frameIndex, r) {
1754
+ if (frameIndex === 0) return {
1755
+ upperLeft: {
1756
+ x: r.left,
1757
+ y: r.top
1758
+ },
1759
+ upperRight: {
1760
+ x: r.right,
1761
+ y: r.top
1762
+ },
1763
+ lowerLeft: {
1764
+ x: r.left,
1765
+ y: r.bottom
1766
+ },
1767
+ lowerRight: {
1768
+ x: r.right,
1769
+ y: r.bottom
1770
+ }
1771
+ };
1772
+ return {
1773
+ upperLeft: fromFrame(f, {
1774
+ x: r.left,
1775
+ y: r.top
1776
+ }),
1777
+ upperRight: fromFrame(f, {
1778
+ x: r.right,
1779
+ y: r.top
1780
+ }),
1781
+ lowerLeft: fromFrame(f, {
1782
+ x: r.left,
1783
+ y: r.bottom
1784
+ }),
1785
+ lowerRight: fromFrame(f, {
1786
+ x: r.right,
1787
+ y: r.bottom
1788
+ })
1789
+ };
1790
+ }
1791
+ function materializeSegment(layout, m) {
1792
+ const frame = layout.frames[m.frame];
1793
+ const quad = quadOfFrameRect(frame, m.frame, m.rect);
1794
+ return {
1795
+ quad,
1796
+ rect: m.frame === 0 ? m.rect : {
1797
+ left: Math.min(quad.upperLeft.x, quad.upperRight.x, quad.lowerLeft.x, quad.lowerRight.x),
1798
+ bottom: Math.min(quad.upperLeft.y, quad.upperRight.y, quad.lowerLeft.y, quad.lowerRight.y),
1799
+ right: Math.max(quad.upperLeft.x, quad.upperRight.x, quad.lowerLeft.x, quad.lowerRight.x),
1800
+ top: Math.max(quad.upperLeft.y, quad.upperRight.y, quad.lowerLeft.y, quad.lowerRight.y)
1801
+ },
1802
+ advance: m.lastX >= m.firstX ? 1 : -1
1803
+ };
1804
+ }
1805
+ function shouldMerge(a, b) {
1806
+ if (a.fontSize != null && b.fontSize != null && a.fontSize > 0 && b.fontSize > 0) {
1807
+ if (Math.max(a.fontSize, b.fontSize) / Math.min(a.fontSize, b.fontSize) > FONT_SIZE_RATIO_THRESHOLD) return false;
1808
+ }
1809
+ if (verticalOverlap(a.rect, b.rect) < VERTICAL_OVERLAP_THRESHOLD) return false;
1810
+ const aw = (a.rect.right - a.rect.left) / a.charCount;
1811
+ const bw = (b.rect.right - b.rect.left) / b.charCount;
1812
+ const aL = a.rect.left - aw;
1813
+ const aR = a.rect.right + aw;
1814
+ const bL = b.rect.left - bw;
1815
+ return aL < b.rect.right + bw && aR > bL;
1816
+ }
1817
+ function verticalOverlap(a, b) {
1818
+ const ah = a.top - a.bottom;
1819
+ const bh = b.top - b.bottom;
1820
+ if (ah <= 0 || bh <= 0) return 0;
1821
+ const u = Math.max(a.top, b.top) - Math.min(a.bottom, b.bottom);
1822
+ if (u === ah || u === bh) return 1;
1823
+ return Math.max(0, Math.min(a.top, b.top) - Math.max(a.bottom, b.bottom)) / u;
1824
+ }
1825
+ const isZero = (r) => r.right === r.left && r.top === r.bottom;
1826
+ function overlapV(bottom1, top1, bottom2, top2) {
1827
+ const u = Math.max(top1, top2) - Math.min(bottom1, bottom2);
1828
+ if (u === 0) return false;
1829
+ return Math.max(0, Math.min(top1, top2) - Math.max(bottom1, bottom2)) / u >= LINE_OVERLAP_THRESHOLD;
1830
+ }
1831
+ //#endregion
1832
+ //#region src/pageSpace/text.ts
1833
+ /**
1834
+ * A character with no box of its own (`empty`) carries a zeroed box or quad
1835
+ * that says so, in either space, and so does a run of nothing but such
1836
+ * characters; it is not a place, so it never converts.
1837
+ */
1838
+ const NO_BOX$1 = {
1839
+ x: 0,
1840
+ y: 0,
1841
+ width: 0,
1842
+ height: 0
1843
+ };
1844
+ const NO_RECT = {
1845
+ left: 0,
1846
+ bottom: 0,
1847
+ right: 0,
1848
+ top: 0
1849
+ };
1850
+ const NO_QUAD = {
1851
+ upperLeft: {
1852
+ x: 0,
1853
+ y: 0
1854
+ },
1855
+ upperRight: {
1856
+ x: 0,
1857
+ y: 0
1858
+ },
1859
+ lowerLeft: {
1860
+ x: 0,
1861
+ y: 0
1862
+ },
1863
+ lowerRight: {
1864
+ x: 0,
1865
+ y: 0
1866
+ }
1867
+ };
1868
+ /** Whether a run has a character with a box of its own. */
1869
+ const hasBox = (run) => run.glyphs.some((glyph) => !glyph.empty);
1870
+ /** A page's text geometry in page space. `visible` is the page's visible box. */
1871
+ function pageGeometryOf(snapshot, visible) {
1872
+ return {
1873
+ ...snapshot,
1874
+ runs: snapshot.runs.map((run) => {
1875
+ const rect = hasBox(run) ? pageBoxOf(run.rect, visible) : NO_BOX$1;
1876
+ if (isRotatedGeometryRun(run)) return {
1877
+ ...run,
1878
+ rect,
1879
+ glyphs: run.glyphs.map(({ loose, tight, ...glyph }) => ({
1880
+ ...glyph,
1881
+ loose: glyph.empty ? NO_QUAD : pageQuadOf(loose, visible),
1882
+ ...tight ? { tight: pageQuadOf(tight, visible) } : {}
1883
+ }))
1884
+ };
1885
+ return {
1886
+ ...run,
1887
+ rect,
1888
+ glyphs: run.glyphs.map(({ loose, tight, ...glyph }) => ({
1889
+ ...glyph,
1890
+ loose: glyph.empty ? NO_BOX$1 : pageBoxOf(loose, visible),
1891
+ ...tight ? { tight: pageBoxOf(tight, visible) } : {}
1892
+ }))
1893
+ };
1894
+ })
1895
+ };
1896
+ }
1897
+ /** A page-space run flipped top to bottom, for the y-up math of the text layout and its helpers. */
1898
+ function mirroredRun(run) {
1899
+ const rect = hasBox(run) ? mirroredRect(run.rect) : NO_RECT;
1900
+ if (isRotatedGeometryRun(run)) return {
1901
+ ...run,
1902
+ rect,
1903
+ glyphs: run.glyphs.map(({ loose, tight, ...glyph }) => ({
1904
+ ...glyph,
1905
+ loose: glyph.empty ? NO_QUAD : mirroredQuad(loose),
1906
+ ...tight ? { tight: mirroredQuad(tight) } : {}
1907
+ }))
1908
+ };
1909
+ return {
1910
+ ...run,
1911
+ rect,
1912
+ glyphs: run.glyphs.map(({ loose, tight, ...glyph }) => ({
1913
+ ...glyph,
1914
+ loose: glyph.empty ? NO_RECT : mirroredRect(loose),
1915
+ ...tight ? { tight: mirroredRect(tight) } : {}
1916
+ }))
1917
+ };
1918
+ }
1919
+ function pageTextSegmentOf(segment, visible) {
1920
+ return {
1921
+ ...segment,
1922
+ quad: pageQuadOf(segment.quad, visible),
1923
+ rect: pageBoxOf(segment.rect, visible)
1924
+ };
1925
+ }
1926
+ /** A search batch in page space: each match measured on its own page. */
1927
+ function pageSearchSliceOf(slice, boxOf) {
1928
+ return {
1929
+ ...slice,
1930
+ matches: slice.matches.map((match) => {
1931
+ const visible = boxOf(match.page);
1932
+ return {
1933
+ ...match,
1934
+ segments: match.segments.map((segment) => pageTextSegmentOf(segment, visible))
1935
+ };
1936
+ })
1937
+ };
1938
+ }
1939
+ /**
1940
+ * The layout of a page's text geometry in page space. It runs the same
1941
+ * layout as the file's coordinates do, on the geometry flipped top to bottom,
1942
+ * and flips each answer back: the flip is exact and the layout doesn't depend
1943
+ * on where the origin is.
1944
+ */
1945
+ function createTextLayout(snapshot) {
1946
+ const layout = createPdfTextLayout({
1947
+ ...snapshot,
1948
+ runs: snapshot.runs.map(mirroredRun)
1949
+ });
1950
+ const at = (value) => typeof value === "number" ? value : mirroredPoint(value);
1951
+ return {
1952
+ charCount: layout.charCount,
1953
+ runs: snapshot.runs,
1954
+ charAt: (point) => layout.charAt(mirroredPoint(point)),
1955
+ wordAt: (value) => layout.wordAt(at(value)),
1956
+ lineAt: (value) => layout.lineAt(at(value)),
1957
+ segments: (range) => layout.segments(range).map((segment) => ({
1958
+ ...segment,
1959
+ quad: unmirroredQuad(segment.quad),
1960
+ rect: unmirroredBox(segment.rect)
1961
+ })),
1962
+ charQuad: (index) => {
1963
+ const quad = layout.charQuad(index);
1964
+ return quad ? unmirroredQuad(quad) : null;
1965
+ }
1966
+ };
1967
+ }
1968
+ //#endregion
1969
+ //#region src/annotation/drawnPoints.ts
1970
+ /**
1971
+ * The points of a line, polyline, polygon or ink as the page shows them: the
1972
+ * upright points a read gives, turned by `rotation` about the middle of their
1973
+ * box. One list for a line (its two ends) or a polygon, one per ink stroke;
1974
+ * `null` for any other kind.
1975
+ */
1976
+ function pdfDrawnPointsOf(annotation) {
1977
+ let sets;
1978
+ switch (annotation.subtype) {
1979
+ case "line":
1980
+ sets = [[annotation.linePoints.start, annotation.linePoints.end]];
1981
+ break;
1982
+ case "polyline":
1983
+ case "polygon":
1984
+ sets = [annotation.vertices];
1985
+ break;
1986
+ case "ink":
1987
+ sets = annotation.inkList.map((stroke) => [...stroke]);
1988
+ break;
1989
+ default: return null;
1990
+ }
1991
+ if (!annotation.rotation) return sets.map((set) => set.map((point) => ({ ...point })));
1992
+ const turn = require_resolveAnnotationDraft.pdfTurnOfUpright(sets.flat(), annotation.rotation);
1993
+ return sets.map((set) => set.map((point) => require_resolveAnnotationDraft.pdfPointTurned(point, turn)));
1994
+ }
1995
+ //#endregion
1996
+ //#region src/annotation/resolve/annotationOfDraft.ts
1997
+ const NO_BOX = {
1998
+ x: 0,
1999
+ y: 0,
2000
+ width: 0,
2001
+ height: 0
2002
+ };
2003
+ /**
2004
+ * A free text's rich text as a read spells it, and the text style it reads
2005
+ * back with: the resolved body over the engine's defaults, and its size,
2006
+ * text color and alignment beside it. The font keeps the name the draft
2007
+ * gave, or the default.
2008
+ */
2009
+ function freeTextReadOf(given, read) {
2010
+ const richText = given.richText;
2011
+ const body = {
2012
+ ...require_resolveAnnotationDraft.DEFAULT_RICH_TEXT_BODY,
2013
+ ...richText?.body
2014
+ };
2015
+ body.color = body.color.toLowerCase();
2016
+ read.richText = {
2017
+ ...read.richText,
2018
+ body
2019
+ };
2020
+ read.fontSize = body.size;
2021
+ read.fontColor = body.color;
2022
+ read.textAlign = body.align;
2023
+ }
2024
+ /**
2025
+ * The annotation a resolved draft creates, as a read spells it: the draft's
2026
+ * data fields, the kind's defaults for those it leaves out, and what
2027
+ * `context` says for the fields the engine owns or stamps. Works in either
2028
+ * space: it only moves values by field name.
2029
+ */
2030
+ function annotationOfResolvedDraft(resolved, context) {
2031
+ const subtype = resolved.subtype;
2032
+ const owners = require_resolveAnnotationDraft.kindFactsOf(subtype)?.owners ?? {};
2033
+ const defaults = annotationDefaultsOf(subtype);
2034
+ const given = resolved;
2035
+ const read = { subtype };
2036
+ for (const [name, owner] of Object.entries(owners)) if (owner === "data" && given[name] !== void 0) read[name] = readValueOf(name, given[name], void 0);
2037
+ else if (owner === "data") read[name] = defaults[name] ?? null;
2038
+ else if (owner === "attribution") read[name] = context.attribution?.[name] ?? null;
2039
+ else read[name] = null;
2040
+ if (read.nm === null && context.nm !== void 0) read.nm = context.nm;
2041
+ read.ref = context.ref;
2042
+ read.page = context.ref.page;
2043
+ read.hasAppearance = !require_resolveAnnotationDraft.UNBAKED_KINDS.has(subtype);
2044
+ if (read.rect === null) read.rect = context.rect ?? given.rect ?? given.box ?? NO_BOX;
2045
+ if (subtype === "free-text") freeTextReadOf(given, read);
2046
+ if (subtype === "link") {
2047
+ const target = given.target;
2048
+ read.actions = target && (target.kind === "uri" || target.kind === "goto") ? { activate: actionTreeOf(target) } : null;
2049
+ }
2050
+ if (subtype === "widget") read.fieldFamily = "unknown";
2051
+ return read;
2052
+ }
2053
+ //#endregion
2054
+ //#region src/pageSpace/helpers.ts
2055
+ /**
2056
+ * The engine's geometry helpers, for page-space values. Each flips its
2057
+ * values top to bottom, runs the helper written for the file's coordinates
2058
+ * (y up), and flips the answer back: exact, and needing no page box, since
2059
+ * none of that math depends on where the origin is.
2060
+ */
2061
+ const mirroredTurn = (turn) => ({
2062
+ degrees: turn.degrees,
2063
+ center: mirroredPoint(turn.center)
2064
+ });
2065
+ const unmirroredTurn = (turn) => ({
2066
+ degrees: turn.degrees,
2067
+ center: unmirroredPoint(turn.center)
2068
+ });
2069
+ /** The box around `points`; a zero box at the origin when there are none. */
2070
+ const pagePointsBounds = (points) => unmirroredBox(require_resolveAnnotationDraft.pdfPointsBounds(points.map(mirroredPoint)));
2071
+ /** `point` turned by `turn`; a negative angle turns it back. */
2072
+ const pagePointTurned = (point, turn) => unmirroredPoint(require_resolveAnnotationDraft.pdfPointTurned(mirroredPoint(point), mirroredTurn(turn)));
2073
+ /** `point` turned back by `turn`. */
2074
+ const pagePointUnturned = (point, turn) => unmirroredPoint(require_resolveAnnotationDraft.pdfPointUnturned(mirroredPoint(point), mirroredTurn(turn)));
2075
+ /** The turn that draws upright `points`: `degrees` about the middle of their box. */
2076
+ const pageTurnOfUpright = (points, degrees) => unmirroredTurn(require_resolveAnnotationDraft.pdfTurnOfUpright(points.map(mirroredPoint), degrees));
2077
+ /** The turn drawn `points` were made with: `degrees` about the middle of their upright box. */
2078
+ const pageTurnOfDrawn = (points, degrees) => unmirroredTurn(require_resolveAnnotationDraft.pdfTurnOfDrawn(points.map(mirroredPoint), degrees));
2079
+ /** The upright box around a quad, whatever its turn or skew. */
2080
+ const pageQuadBounds = (quad) => unmirroredBox(require_resolveAnnotationDraft.pdfQuadBounds(mirroredQuad(quad)));
2081
+ /** A glyph's loose cell as a quad. */
2082
+ const pageGlyphLooseQuad = (run, index) => unmirroredQuad(glyphLooseQuad(mirroredRun(run), index));
2083
+ /** A glyph's loose cell as an upright box. */
2084
+ const pageGlyphLooseBounds = (run, index) => unmirroredBox(glyphLooseBounds(mirroredRun(run), index));
2085
+ /**
2086
+ * The points of a line, polyline, polygon or ink as the page shows them: the
2087
+ * upright points a read gives, turned by `rotation` about the middle of their
2088
+ * box. One list for a line (its two ends) or a polygon, one per ink stroke;
2089
+ * `null` for any other kind.
2090
+ */
2091
+ function drawnPointsOf(annotation) {
2092
+ const flip = (points) => points.map(mirroredPoint);
2093
+ let mirrored;
2094
+ switch (annotation.subtype) {
2095
+ case "line":
2096
+ mirrored = {
2097
+ subtype: "line",
2098
+ rotation: annotation.rotation,
2099
+ linePoints: {
2100
+ start: mirroredPoint(annotation.linePoints.start),
2101
+ end: mirroredPoint(annotation.linePoints.end)
2102
+ }
2103
+ };
2104
+ break;
2105
+ case "polyline":
2106
+ case "polygon":
2107
+ mirrored = {
2108
+ subtype: annotation.subtype,
2109
+ rotation: annotation.rotation,
2110
+ vertices: flip(annotation.vertices)
2111
+ };
2112
+ break;
2113
+ case "ink":
2114
+ mirrored = {
2115
+ subtype: "ink",
2116
+ rotation: annotation.rotation,
2117
+ inkList: annotation.inkList.map(flip)
2118
+ };
2119
+ break;
2120
+ default: return null;
2121
+ }
2122
+ const sets = pdfDrawnPointsOf(mirrored);
2123
+ return sets && sets.map((set) => set.map(unmirroredPoint));
2124
+ }
2125
+ /**
2126
+ * The turn an annotation's appearance raster is drawn without, degrees
2127
+ * clockwise, or `null` when the raster is drawn as the page shows it. A box
2128
+ * kind drawn turned whose drawing stays inside the turned box (its `rect` is
2129
+ * the upright box around it) renders upright over its `box`, for the
2130
+ * consumer to turn about the middle of `box`: a new turn needs no new
2131
+ * raster. A callout (its line isn't turned) and a drawing that reaches past
2132
+ * its box (a cloudy border's bumps) render as the page shows them, placed by
2133
+ * `rect`.
2134
+ */
2135
+ function appearanceTurnOf(annotation) {
2136
+ return pdfAppearanceTurnOf({
2137
+ ...annotation,
2138
+ rect: mirroredRect(annotation.rect),
2139
+ box: annotation.box ? mirroredRect(annotation.box) : annotation.box
2140
+ });
2141
+ }
2142
+ /** Page space with its origin as the file's: turning one into the other is the mirror. */
2143
+ const MIRROR = {
2144
+ left: 0,
2145
+ bottom: 0,
2146
+ right: 0,
2147
+ top: 0
2148
+ };
2149
+ /** Shape fields hold no destinations, so nothing asks for another page's box. */
2150
+ const noOtherPage = () => {
2151
+ throw new Error("a shape field holds no destination");
2152
+ };
2153
+ /**
2154
+ * The shape fields that put `annotation` at `rect`, the rule an update's
2155
+ * `rect` follows (`create({ ...copy, ...shapeForRect(copy, target) })` puts a
2156
+ * copy there).
2157
+ *
2158
+ * - A kind whose shape is its rect (note, file attachment, link, popup,
2159
+ * redaction) takes `rect` as it is.
2160
+ * - A drawn kind has every place it holds mapped from its current `rect` onto
2161
+ * `rect`, each axis on its own, as Acrobat does when a script sets
2162
+ * `annot.rect`: a rect of the same size moves the shape, a bigger one
2163
+ * stretches it. The engine then works out the rect from the shape, so it
2164
+ * can differ a little from `rect` (a stroke keeps its width). A box at a
2165
+ * quarter turn stretches along its own sides, as it stands on the page.
2166
+ *
2167
+ * A drawn kind refuses a rect that would squash it to no width or height, a
2168
+ * rect of another size when it's turned (it can only move) unless it is a
2169
+ * box at a quarter turn, and one when its own rect has no width or height to
2170
+ * stretch. Each refusal is `InvalidArg` on `rect`.
2171
+ */
2172
+ function shapeForRect(annotation, rect) {
2173
+ if (!require_resolveAnnotationDraft.DRAWN_RECT_KINDS.has(annotation.subtype)) return { rect };
2174
+ const read = annotation;
2175
+ const placed = require_resolveAnnotationDraft.pdfShapeForRect(pdfAnnotationOf(Object.fromEntries([
2176
+ "subtype",
2177
+ "rect",
2178
+ ...require_resolveAnnotationDraft.shapeFieldsOf(annotation.subtype)
2179
+ ].filter((name) => read[name] !== void 0).map((name) => [name, read[name]])), MIRROR, noOtherPage), mirroredRect(rect));
2180
+ const { subtype: _kind, ...fields } = pageAnnotationPatchOf({
2181
+ subtype: annotation.subtype,
2182
+ ...placed
2183
+ }, MIRROR, noOtherPage);
2184
+ return fields;
2185
+ }
2186
+ /**
2187
+ * `patch` with its `rect` resolved as the engine resolves it on update (the
2188
+ * same step, `pdfResolveRectCommand`):
2189
+ *
2190
+ * - the rect the annotation reads, sent back, is dropped: nothing moves;
2191
+ * - on a drawn kind, another rect becomes the shape fields that put the
2192
+ * drawing there (`shapeForRect`);
2193
+ * - a new rect with a changed shape field is refused (`InvalidArg` on
2194
+ * `rect`): which of the two to follow would be a guess.
2195
+ *
2196
+ * A kind whose shape is its rect keeps it as a plain field. A viewer runs
2197
+ * this before it merges fields it writes itself, so a `rect` behaves the same
2198
+ * from every door. Values `patch` gives come back as given.
2199
+ */
2200
+ function resolveRectCommand(annotation, patch) {
2201
+ const given = patch;
2202
+ if (given.rect === void 0 || !require_resolveAnnotationDraft.DRAWN_RECT_KINDS.has(annotation.subtype)) return patch;
2203
+ const read = annotation;
2204
+ const shapeNames = require_resolveAnnotationDraft.shapeFieldsOf(annotation.subtype);
2205
+ const pick = (from, names) => Object.fromEntries(names.filter((name) => from[name] !== void 0).map((name) => [name, from[name]]));
2206
+ const { subtype: _kind, ...placed } = pageAnnotationPatchOf(require_resolveAnnotationDraft.pdfResolveRectCommand(pdfAnnotationOf({
2207
+ subtype: annotation.subtype,
2208
+ ...pick(read, ["rect", ...shapeNames])
2209
+ }, MIRROR, noOtherPage), pdfAnnotationPatchOf({
2210
+ subtype: annotation.subtype,
2211
+ ...pick(given, ["rect", ...shapeNames])
2212
+ }, MIRROR, noOtherPage)), MIRROR, noOtherPage);
2213
+ const { rect: _rect, ...rest } = given;
2214
+ const out = { ...rest };
2215
+ for (const [name, value] of Object.entries(placed)) out[name] = given[name] !== void 0 && require_resolveAnnotationDraft.semanticEqual(value, given[name]) ? given[name] : value;
2216
+ return out;
2217
+ }
2218
+ /**
2219
+ * Every page's box is the mirror, so a link's destination makes the round
2220
+ * trip into the file's coordinates and back unchanged, with no real page.
2221
+ */
2222
+ const mirrorEveryPage = () => MIRROR;
2223
+ /**
2224
+ * The patch the engine writes for `patch` on `current`, as a viewer predicts
2225
+ * it: its subtype filled in, and every field that follows from it stated. A
2226
+ * drawn kind's new `rect` becomes the shape fields that put it there, values
2227
+ * sent back as read are dropped, a note's standard review state brings its
2228
+ * state model, a free text's contents and rich text follow each other, a
2229
+ * callout's line stays attached to its moved box, and a measurement's label
2230
+ * follows its points and scale. Values `patch` gives come back as given.
2231
+ *
2232
+ * Throws `InvalidArg` for what the engine refuses without its schemas: a
2233
+ * field the kind doesn't declare, a changed subtype or name, a rect with a
2234
+ * new shape or that isn't finite, and where nothing can follow. The engine
2235
+ * checks the values against the kind's schema when the update reaches it,
2236
+ * and refuses there what this lets through.
2237
+ */
2238
+ function resolveAnnotationPatch(current, patch, options = {}) {
2239
+ const back = pageAnnotationPatchOf(require_resolveAnnotationDraft.pdfPredictAnnotationPatch(pdfAnnotationOf(current, MIRROR, mirrorEveryPage), pdfAnnotationPatchOf({
2240
+ ...patch,
2241
+ subtype: patch.subtype ?? current.subtype
2242
+ }, MIRROR, mirrorEveryPage), options), MIRROR, mirrorEveryPage);
2243
+ const given = patch;
2244
+ for (const name of Object.keys(back)) if (given[name] !== void 0 && require_resolveAnnotationDraft.semanticEqual(back[name], given[name])) back[name] = given[name];
2245
+ return back;
2246
+ }
2247
+ /**
2248
+ * `current` as the engine will read it after `patch`: what a viewer shows
2249
+ * while the write is on its way. Fields the engine works out or stamps itself
2250
+ * (a drawn kind's `rect`, the modified date and author) keep their current
2251
+ * value until the engine's answer brings the new one. A field `patch` leaves
2252
+ * alone keeps its very value.
2253
+ */
2254
+ function applyAnnotationPatch(current, patch, options = {}) {
2255
+ return applyResolvedPatch(current, resolveAnnotationPatch(current, patch, options));
2256
+ }
2257
+ /**
2258
+ * The draft the engine writes for `draft`, as a viewer predicts it: every
2259
+ * field that follows from it stated. A box kind placed by its `rect` states
2260
+ * its `box`, a note's standard review state brings its state model, a free
2261
+ * text's rich text and contents follow each other, and a measurement's label
2262
+ * follows its points and scale. Fields left out stay out: the kind's
2263
+ * defaults (`ANNOTATION_DEFAULTS`) say what they read back. Values `draft`
2264
+ * gives come back as given.
2265
+ *
2266
+ * Throws `InvalidArg` for what the engine refuses without its schemas: a
2267
+ * field the kind doesn't declare, a box kind it can't place, and where
2268
+ * nothing can follow. The engine checks the values against the kind's schema
2269
+ * when the create reaches it, and refuses there what this lets through.
2270
+ */
2271
+ function resolveAnnotationDraft(draft, options = {}) {
2272
+ const back = pageAnnotationDraftOf(require_resolveAnnotationDraft.pdfPredictAnnotationDraft(pdfAnnotationDraftOf(draft, MIRROR, mirrorEveryPage), options), MIRROR, mirrorEveryPage);
2273
+ const given = draft;
2274
+ for (const name of Object.keys(back)) if (given[name] !== void 0 && require_resolveAnnotationDraft.semanticEqual(back[name], given[name])) back[name] = given[name];
2275
+ return back;
2276
+ }
2277
+ /**
2278
+ * The annotation the engine will read back after creating `draft`: what a
2279
+ * viewer shows while the create is on its way. `context` says what the draft
2280
+ * doesn't: the ref and place it will have, who creates it, and, for a kind
2281
+ * whose `rect` the engine works out from its drawing, that box. The draft is
2282
+ * resolved as `resolveAnnotationDraft` does it, without the engine's schema
2283
+ * check: a create the engine refuses leaves the view when it answers.
2284
+ */
2285
+ function annotationOfDraft(draft, context) {
2286
+ return annotationOfResolvedDraft(resolveAnnotationDraft(draft, { describeFont: context.describeFont }), context);
2287
+ }
2288
+ //#endregion
2289
+ //#region src/search/fold.ts
2290
+ /**
2291
+ * Text folding for literal search: the deterministic normalization applied
2292
+ * to both the page text and the needle so that "Café" finds "cafe" and a
2293
+ * line-wrapped "hello\n world" finds "hello world".
2294
+ *
2295
+ * Fold version 1:
2296
+ * - whitespace runs collapse to a single space (any `\s`, including the
2297
+ * spaces some compatibility decompositions emit) — or are dropped
2298
+ * entirely with `dropWhitespace` (ignoreWhitespace),
2299
+ * - each code point is NFKD-decomposed (ligatures split: "fi" → "fi",
2300
+ * "²" → "2"),
2301
+ * - combining marks are stripped unless `keepMarks`,
2302
+ * - case is folded via upper→lower round-trip unless `keepCase` (this
2303
+ * poor-man's full fold catches "ß"→"ss" and "ς"→"σ", which a plain
2304
+ * `toLowerCase` misses).
2305
+ *
2306
+ * Every folded code unit remembers which original code point produced it
2307
+ * (`map`), so match ranges found in folded space translate back to exact
2308
+ * original-text ranges — the property the whole anchor stage rests on.
2309
+ *
2310
+ * Pre-folded corpus artifacts store this fold's output; bump
2311
+ * `SEARCH_FOLD_VERSION` on any semantic change so stored corpora are
2312
+ * rebuilt instead of silently mismatching fresh needles.
2313
+ */
2314
+ /** Version stamp for persisted pre-folded corpus artifacts. */
2315
+ const SEARCH_FOLD_VERSION = 1;
2316
+ const WHITESPACE = /\s/;
2317
+ const MARKS = /\p{M}/gu;
2318
+ function foldText(original, options = {}) {
2319
+ const units = [];
2320
+ const map = [];
2321
+ let lastWasSpace = false;
2322
+ let index = 0;
2323
+ for (const cp of original) {
2324
+ let piece;
2325
+ if (WHITESPACE.test(cp)) piece = " ";
2326
+ else {
2327
+ piece = cp.normalize("NFKD");
2328
+ if (!options.keepMarks) piece = piece.replace(MARKS, "");
2329
+ if (!options.keepCase) piece = piece.toUpperCase().toLowerCase();
2330
+ }
2331
+ for (let u = 0; u < piece.length; u++) {
2332
+ const unit = piece[u];
2333
+ if (WHITESPACE.test(unit)) {
2334
+ if (options.dropWhitespace || lastWasSpace) continue;
2335
+ units.push(" ");
2336
+ map.push(index);
2337
+ lastWasSpace = true;
2338
+ } else {
2339
+ units.push(unit);
2340
+ map.push(index);
2341
+ lastWasSpace = false;
2342
+ }
2343
+ }
2344
+ index += cp.length;
2345
+ }
2346
+ return {
2347
+ folded: units.join(""),
2348
+ map: Uint32Array.from(map),
2349
+ original
2350
+ };
2351
+ }
2352
+ /** Code-unit length of the code point starting at `index` (1 or 2). */
2353
+ function codePointLengthAt(text, index) {
2354
+ const unit = text.charCodeAt(index);
2355
+ if (unit >= 55296 && unit <= 56319 && index + 1 < text.length) {
2356
+ const next = text.charCodeAt(index + 1);
2357
+ if (next >= 56320 && next <= 57343) return 2;
2358
+ }
2359
+ return 1;
2360
+ }
2361
+ /**
2362
+ * Translate a match found in folded space back to a range of the original
2363
+ * text (code units).
2364
+ * The range covers whole original code points: a hit on either folded
2365
+ * half of "fi" spans the full ligature, and a hit ending on a collapsed
2366
+ * space extends only through the first whitespace char of the run (the
2367
+ * remainder is presentation, not match).
2368
+ */
2369
+ function toOriginalRange(folded, foldedStart, foldedLength) {
2370
+ const start = folded.map[foldedStart];
2371
+ const lastOriginal = folded.map[foldedStart + foldedLength - 1];
2372
+ return {
2373
+ start,
2374
+ count: lastOriginal + codePointLengthAt(folded.original, lastOriginal) - start
2375
+ };
2376
+ }
2377
+ //#endregion
2378
+ //#region src/measure/units.ts
2379
+ const METRES = {
2380
+ pt: .0254 / 72,
2381
+ mm: .001,
2382
+ cm: .01,
2383
+ m: 1,
2384
+ km: 1e3,
2385
+ in: .0254,
2386
+ ft: .3048,
2387
+ yd: .9144,
2388
+ mi: 1609.344
2389
+ };
2390
+ const squareOf = (unit) => `${unit}2`;
2391
+ function squareMetres(unit) {
2392
+ return unit === "ha" ? 1e4 : unit === "acre" ? 4046.8564224 : METRES[unit.slice(0, -1)] ** 2;
2393
+ }
2394
+ const areaUnitLabel = (unit) => unit.endsWith("2") ? unit.slice(0, -1) + "²" : unit;
2395
+ //#endregion
2396
+ //#region src/measure/calibrate.ts
2397
+ function invalid(message) {
2398
+ return new require_format.EngineError(require_format.EngineErrorCode.InvalidArg, message);
2399
+ }
2400
+ function positive(value) {
2401
+ if (!Number.isFinite(value) || value <= 0) throw invalid("Calibration requires finite positive lengths and scales");
2402
+ }
2403
+ function build(perPoint, unit, ratio, format) {
2404
+ positive(Math.fround(perPoint));
2405
+ const precision = format.precision ?? 100;
2406
+ if (!Number.isInteger(Math.log10(precision)) || precision < 1 || precision > 1e9) throw invalid("Invalid decimal precision");
2407
+ const areaUnit = format.areaUnit ?? squareOf(unit);
2408
+ const common = {
2409
+ precision,
2410
+ ...format.fixed === void 0 ? {} : { fixed: format.fixed }
2411
+ };
2412
+ const distance = format.imperialFeetInches ? [{
2413
+ unit: "ft",
2414
+ conversion: Math.fround(METRES[unit] / METRES.ft)
2415
+ }, {
2416
+ unit: "in",
2417
+ conversion: 12,
2418
+ fraction: "fraction",
2419
+ precision: format.fractionalPrecision ?? 16,
2420
+ ..."fixed" in common ? { fixed: common.fixed } : {}
2421
+ }] : [{
2422
+ unit,
2423
+ conversion: 1,
2424
+ ...common
2425
+ }];
2426
+ if (format.imperialFeetInches && (!Number.isInteger(distance[1].precision) || distance[1].precision < 1 || distance[1].precision > 2147483647)) throw invalid("Invalid fraction denominator");
2427
+ const measure = {
2428
+ subtype: "rectilinear",
2429
+ ratio,
2430
+ x: [{
2431
+ unit,
2432
+ conversion: Math.fround(perPoint),
2433
+ ...common
2434
+ }],
2435
+ distance,
2436
+ area: [{
2437
+ unit: areaUnitLabel(areaUnit),
2438
+ conversion: Math.fround(METRES[unit] ** 2 / squareMetres(areaUnit)),
2439
+ ...common
2440
+ }]
2441
+ };
2442
+ require_resolveAnnotationDraft.assertWritableMeasure(measure);
2443
+ return measure;
2444
+ }
2445
+ function measureFromKnownLength(userSpaceLength, real, format = {}) {
2446
+ positive(userSpaceLength);
2447
+ positive(real.value);
2448
+ const perPoint = real.value / userSpaceLength;
2449
+ return build(perPoint, real.unit, `1 in = ${Number((perPoint * 72).toPrecision(8))} ${real.unit}`, format);
2450
+ }
2451
+ function measureFromRatio(paper, real, unit, options = {}) {
2452
+ const { userUnit = 1, ...format } = options;
2453
+ positive(paper);
2454
+ positive(real);
2455
+ positive(userUnit);
2456
+ return build(userUnit / 72 * .0254 * (real / paper) / METRES[unit], unit, `${paper}:${real}`, format);
2457
+ }
2458
+ //#endregion
2459
+ Object.defineProperty(exports, "ANNOTATION_DEFAULTS", {
2460
+ enumerable: true,
2461
+ get: function() {
2462
+ return ANNOTATION_DEFAULTS;
2463
+ }
2464
+ });
2465
+ Object.defineProperty(exports, "ANNOTATION_RESOURCE_ROLE_NAMES", {
2466
+ enumerable: true,
2467
+ get: function() {
2468
+ return ANNOTATION_RESOURCE_ROLE_NAMES;
2469
+ }
2470
+ });
2471
+ Object.defineProperty(exports, "ATTACHMENT_LIMITS", {
2472
+ enumerable: true,
2473
+ get: function() {
2474
+ return ATTACHMENT_LIMITS;
2475
+ }
2476
+ });
2477
+ Object.defineProperty(exports, "AbortError", {
2478
+ enumerable: true,
2479
+ get: function() {
2480
+ return AbortError;
2481
+ }
2482
+ });
2483
+ Object.defineProperty(exports, "AnnotationTransfer", {
2484
+ enumerable: true,
2485
+ get: function() {
2486
+ return AnnotationTransfer;
2487
+ }
2488
+ });
2489
+ Object.defineProperty(exports, "DEFAULT_BUNDLE_LIMITS", {
2490
+ enumerable: true,
2491
+ get: function() {
2492
+ return DEFAULT_BUNDLE_LIMITS;
2493
+ }
2494
+ });
2495
+ Object.defineProperty(exports, "METRES", {
2496
+ enumerable: true,
2497
+ get: function() {
2498
+ return METRES;
2499
+ }
2500
+ });
2501
+ Object.defineProperty(exports, "PRINT_PAPER", {
2502
+ enumerable: true,
2503
+ get: function() {
2504
+ return PRINT_PAPER;
2505
+ }
2506
+ });
2507
+ Object.defineProperty(exports, "SEARCH_FOLD_VERSION", {
2508
+ enumerable: true,
2509
+ get: function() {
2510
+ return SEARCH_FOLD_VERSION;
2511
+ }
2512
+ });
2513
+ Object.defineProperty(exports, "actionTreeOf", {
2514
+ enumerable: true,
2515
+ get: function() {
2516
+ return actionTreeOf;
2517
+ }
2518
+ });
2519
+ Object.defineProperty(exports, "annotationDefaultsOf", {
2520
+ enumerable: true,
2521
+ get: function() {
2522
+ return annotationDefaultsOf;
2523
+ }
2524
+ });
2525
+ Object.defineProperty(exports, "annotationOfDraft", {
2526
+ enumerable: true,
2527
+ get: function() {
2528
+ return annotationOfDraft;
2529
+ }
2530
+ });
2531
+ Object.defineProperty(exports, "annotationResourceBuffers", {
2532
+ enumerable: true,
2533
+ get: function() {
2534
+ return annotationResourceBuffers;
2535
+ }
2536
+ });
2537
+ Object.defineProperty(exports, "appearanceTurnOf", {
2538
+ enumerable: true,
2539
+ get: function() {
2540
+ return appearanceTurnOf;
2541
+ }
2542
+ });
2543
+ Object.defineProperty(exports, "applyAnnotationPatch", {
2544
+ enumerable: true,
2545
+ get: function() {
2546
+ return applyAnnotationPatch;
2547
+ }
2548
+ });
2549
+ Object.defineProperty(exports, "applyResolvedPatch", {
2550
+ enumerable: true,
2551
+ get: function() {
2552
+ return applyResolvedPatch;
2553
+ }
2554
+ });
2555
+ Object.defineProperty(exports, "areaUnitLabel", {
2556
+ enumerable: true,
2557
+ get: function() {
2558
+ return areaUnitLabel;
2559
+ }
2560
+ });
2561
+ Object.defineProperty(exports, "assertAnnotationBundle", {
2562
+ enumerable: true,
2563
+ get: function() {
2564
+ return assertAnnotationBundle;
2565
+ }
2566
+ });
2567
+ Object.defineProperty(exports, "assertAnnotationBundleManifest", {
2568
+ enumerable: true,
2569
+ get: function() {
2570
+ return assertAnnotationBundleManifest;
2571
+ }
2572
+ });
2573
+ Object.defineProperty(exports, "assertAnnotationResources", {
2574
+ enumerable: true,
2575
+ get: function() {
2576
+ return assertAnnotationResources;
2577
+ }
2578
+ });
2579
+ Object.defineProperty(exports, "assertWithinLimit", {
2580
+ enumerable: true,
2581
+ get: function() {
2582
+ return assertWithinLimit;
2583
+ }
2584
+ });
2585
+ Object.defineProperty(exports, "bundleCodec", {
2586
+ enumerable: true,
2587
+ get: function() {
2588
+ return bundleCodec;
2589
+ }
2590
+ });
2591
+ Object.defineProperty(exports, "createPdfTextLayout", {
2592
+ enumerable: true,
2593
+ get: function() {
2594
+ return createPdfTextLayout;
2595
+ }
2596
+ });
2597
+ Object.defineProperty(exports, "createTextLayout", {
2598
+ enumerable: true,
2599
+ get: function() {
2600
+ return createTextLayout;
2601
+ }
2602
+ });
2603
+ Object.defineProperty(exports, "drawnPointsOf", {
2604
+ enumerable: true,
2605
+ get: function() {
2606
+ return drawnPointsOf;
2607
+ }
2608
+ });
2609
+ Object.defineProperty(exports, "foldText", {
2610
+ enumerable: true,
2611
+ get: function() {
2612
+ return foldText;
2613
+ }
2614
+ });
2615
+ Object.defineProperty(exports, "glyphLooseBounds", {
2616
+ enumerable: true,
2617
+ get: function() {
2618
+ return glyphLooseBounds;
2619
+ }
2620
+ });
2621
+ Object.defineProperty(exports, "glyphLooseQuad", {
2622
+ enumerable: true,
2623
+ get: function() {
2624
+ return glyphLooseQuad;
2625
+ }
2626
+ });
2627
+ Object.defineProperty(exports, "hasAnnotationResources", {
2628
+ enumerable: true,
2629
+ get: function() {
2630
+ return hasAnnotationResources;
2631
+ }
2632
+ });
2633
+ Object.defineProperty(exports, "isAbortError", {
2634
+ enumerable: true,
2635
+ get: function() {
2636
+ return isAbortError;
2637
+ }
2638
+ });
2639
+ Object.defineProperty(exports, "isRotatedGeometryRun", {
2640
+ enumerable: true,
2641
+ get: function() {
2642
+ return isRotatedGeometryRun;
2643
+ }
2644
+ });
2645
+ Object.defineProperty(exports, "manifestBytesOf", {
2646
+ enumerable: true,
2647
+ get: function() {
2648
+ return manifestBytesOf;
2649
+ }
2650
+ });
2651
+ Object.defineProperty(exports, "mapActionNode", {
2652
+ enumerable: true,
2653
+ get: function() {
2654
+ return mapActionNode;
2655
+ }
2656
+ });
2657
+ Object.defineProperty(exports, "mapActionTree", {
2658
+ enumerable: true,
2659
+ get: function() {
2660
+ return mapActionTree;
2661
+ }
2662
+ });
2663
+ Object.defineProperty(exports, "mapAnnotationActions", {
2664
+ enumerable: true,
2665
+ get: function() {
2666
+ return mapAnnotationActions;
2667
+ }
2668
+ });
2669
+ Object.defineProperty(exports, "mapDocumentActions", {
2670
+ enumerable: true,
2671
+ get: function() {
2672
+ return mapDocumentActions;
2673
+ }
2674
+ });
2675
+ Object.defineProperty(exports, "mapFieldActions", {
2676
+ enumerable: true,
2677
+ get: function() {
2678
+ return mapFieldActions;
2679
+ }
2680
+ });
2681
+ Object.defineProperty(exports, "mapLinkTarget", {
2682
+ enumerable: true,
2683
+ get: function() {
2684
+ return mapLinkTarget;
2685
+ }
2686
+ });
2687
+ Object.defineProperty(exports, "mapPageActions", {
2688
+ enumerable: true,
2689
+ get: function() {
2690
+ return mapPageActions;
2691
+ }
2692
+ });
2693
+ Object.defineProperty(exports, "mapTriggerActions", {
2694
+ enumerable: true,
2695
+ get: function() {
2696
+ return mapTriggerActions;
2697
+ }
2698
+ });
2699
+ Object.defineProperty(exports, "measureFromKnownLength", {
2700
+ enumerable: true,
2701
+ get: function() {
2702
+ return measureFromKnownLength;
2703
+ }
2704
+ });
2705
+ Object.defineProperty(exports, "measureFromRatio", {
2706
+ enumerable: true,
2707
+ get: function() {
2708
+ return measureFromRatio;
2709
+ }
2710
+ });
2711
+ Object.defineProperty(exports, "outlineItemRefsEqual", {
2712
+ enumerable: true,
2713
+ get: function() {
2714
+ return outlineItemRefsEqual;
2715
+ }
2716
+ });
2717
+ Object.defineProperty(exports, "pageAnnotationDraftOf", {
2718
+ enumerable: true,
2719
+ get: function() {
2720
+ return pageAnnotationDraftOf;
2721
+ }
2722
+ });
2723
+ Object.defineProperty(exports, "pageAnnotationOf", {
2724
+ enumerable: true,
2725
+ get: function() {
2726
+ return pageAnnotationOf;
2727
+ }
2728
+ });
2729
+ Object.defineProperty(exports, "pageAnnotationPatchOf", {
2730
+ enumerable: true,
2731
+ get: function() {
2732
+ return pageAnnotationPatchOf;
2733
+ }
2734
+ });
2735
+ Object.defineProperty(exports, "pageBoxOf", {
2736
+ enumerable: true,
2737
+ get: function() {
2738
+ return pageBoxOf;
2739
+ }
2740
+ });
2741
+ Object.defineProperty(exports, "pageDestinationOf", {
2742
+ enumerable: true,
2743
+ get: function() {
2744
+ return pageDestinationOf;
2745
+ }
2746
+ });
2747
+ Object.defineProperty(exports, "pageGeometryOf", {
2748
+ enumerable: true,
2749
+ get: function() {
2750
+ return pageGeometryOf;
2751
+ }
2752
+ });
2753
+ Object.defineProperty(exports, "pageGlyphLooseBounds", {
2754
+ enumerable: true,
2755
+ get: function() {
2756
+ return pageGlyphLooseBounds;
2757
+ }
2758
+ });
2759
+ Object.defineProperty(exports, "pageGlyphLooseQuad", {
2760
+ enumerable: true,
2761
+ get: function() {
2762
+ return pageGlyphLooseQuad;
2763
+ }
2764
+ });
2765
+ Object.defineProperty(exports, "pageMeasureOf", {
2766
+ enumerable: true,
2767
+ get: function() {
2768
+ return pageMeasureOf;
2769
+ }
2770
+ });
2771
+ Object.defineProperty(exports, "pagePointOf", {
2772
+ enumerable: true,
2773
+ get: function() {
2774
+ return pagePointOf;
2775
+ }
2776
+ });
2777
+ Object.defineProperty(exports, "pagePointTurned", {
2778
+ enumerable: true,
2779
+ get: function() {
2780
+ return pagePointTurned;
2781
+ }
2782
+ });
2783
+ Object.defineProperty(exports, "pagePointUnturned", {
2784
+ enumerable: true,
2785
+ get: function() {
2786
+ return pagePointUnturned;
2787
+ }
2788
+ });
2789
+ Object.defineProperty(exports, "pagePointsBounds", {
2790
+ enumerable: true,
2791
+ get: function() {
2792
+ return pagePointsBounds;
2793
+ }
2794
+ });
2795
+ Object.defineProperty(exports, "pageQuadBounds", {
2796
+ enumerable: true,
2797
+ get: function() {
2798
+ return pageQuadBounds;
2799
+ }
2800
+ });
2801
+ Object.defineProperty(exports, "pageQuadOf", {
2802
+ enumerable: true,
2803
+ get: function() {
2804
+ return pageQuadOf;
2805
+ }
2806
+ });
2807
+ Object.defineProperty(exports, "pageSearchSliceOf", {
2808
+ enumerable: true,
2809
+ get: function() {
2810
+ return pageSearchSliceOf;
2811
+ }
2812
+ });
2813
+ Object.defineProperty(exports, "pageTextSegmentOf", {
2814
+ enumerable: true,
2815
+ get: function() {
2816
+ return pageTextSegmentOf;
2817
+ }
2818
+ });
2819
+ Object.defineProperty(exports, "pageTransform", {
2820
+ enumerable: true,
2821
+ get: function() {
2822
+ return pageTransform;
2823
+ }
2824
+ });
2825
+ Object.defineProperty(exports, "pageTurnOfDrawn", {
2826
+ enumerable: true,
2827
+ get: function() {
2828
+ return pageTurnOfDrawn;
2829
+ }
2830
+ });
2831
+ Object.defineProperty(exports, "pageTurnOfUpright", {
2832
+ enumerable: true,
2833
+ get: function() {
2834
+ return pageTurnOfUpright;
2835
+ }
2836
+ });
2837
+ Object.defineProperty(exports, "pageViewportsOf", {
2838
+ enumerable: true,
2839
+ get: function() {
2840
+ return pageViewportsOf;
2841
+ }
2842
+ });
2843
+ Object.defineProperty(exports, "pdfAnnotationDraftOf", {
2844
+ enumerable: true,
2845
+ get: function() {
2846
+ return pdfAnnotationDraftOf;
2847
+ }
2848
+ });
2849
+ Object.defineProperty(exports, "pdfAnnotationOf", {
2850
+ enumerable: true,
2851
+ get: function() {
2852
+ return pdfAnnotationOf;
2853
+ }
2854
+ });
2855
+ Object.defineProperty(exports, "pdfAnnotationPatchOf", {
2856
+ enumerable: true,
2857
+ get: function() {
2858
+ return pdfAnnotationPatchOf;
2859
+ }
2860
+ });
2861
+ Object.defineProperty(exports, "pdfAppearanceTurnOf", {
2862
+ enumerable: true,
2863
+ get: function() {
2864
+ return pdfAppearanceTurnOf;
2865
+ }
2866
+ });
2867
+ Object.defineProperty(exports, "pdfDestinationOf", {
2868
+ enumerable: true,
2869
+ get: function() {
2870
+ return pdfDestinationOf;
2871
+ }
2872
+ });
2873
+ Object.defineProperty(exports, "pdfMeasureOf", {
2874
+ enumerable: true,
2875
+ get: function() {
2876
+ return pdfMeasureOf;
2877
+ }
2878
+ });
2879
+ Object.defineProperty(exports, "pdfPointOf", {
2880
+ enumerable: true,
2881
+ get: function() {
2882
+ return pdfPointOf;
2883
+ }
2884
+ });
2885
+ Object.defineProperty(exports, "pdfQuadOf", {
2886
+ enumerable: true,
2887
+ get: function() {
2888
+ return pdfQuadOf;
2889
+ }
2890
+ });
2891
+ Object.defineProperty(exports, "pdfRectOf", {
2892
+ enumerable: true,
2893
+ get: function() {
2894
+ return pdfRectOf;
2895
+ }
2896
+ });
2897
+ Object.defineProperty(exports, "printScale", {
2898
+ enumerable: true,
2899
+ get: function() {
2900
+ return printScale;
2901
+ }
2902
+ });
2903
+ Object.defineProperty(exports, "renderAreaTransform", {
2904
+ enumerable: true,
2905
+ get: function() {
2906
+ return renderAreaTransform;
2907
+ }
2908
+ });
2909
+ Object.defineProperty(exports, "renderMatrix", {
2910
+ enumerable: true,
2911
+ get: function() {
2912
+ return renderMatrix;
2913
+ }
2914
+ });
2915
+ Object.defineProperty(exports, "renderSize", {
2916
+ enumerable: true,
2917
+ get: function() {
2918
+ return renderSize;
2919
+ }
2920
+ });
2921
+ Object.defineProperty(exports, "renderTargetArea", {
2922
+ enumerable: true,
2923
+ get: function() {
2924
+ return renderTargetArea;
2925
+ }
2926
+ });
2927
+ Object.defineProperty(exports, "renderTransform", {
2928
+ enumerable: true,
2929
+ get: function() {
2930
+ return renderTransform;
2931
+ }
2932
+ });
2933
+ Object.defineProperty(exports, "resolveAnnotationDraft", {
2934
+ enumerable: true,
2935
+ get: function() {
2936
+ return resolveAnnotationDraft;
2937
+ }
2938
+ });
2939
+ Object.defineProperty(exports, "resolveAnnotationPatch", {
2940
+ enumerable: true,
2941
+ get: function() {
2942
+ return resolveAnnotationPatch;
2943
+ }
2944
+ });
2945
+ Object.defineProperty(exports, "resolveAnnotationResources", {
2946
+ enumerable: true,
2947
+ get: function() {
2948
+ return resolveAnnotationResources;
2949
+ }
2950
+ });
2951
+ Object.defineProperty(exports, "resolveBinarySource", {
2952
+ enumerable: true,
2953
+ get: function() {
2954
+ return resolveBinarySource;
2955
+ }
2956
+ });
2957
+ Object.defineProperty(exports, "resolveRectCommand", {
2958
+ enumerable: true,
2959
+ get: function() {
2960
+ return resolveRectCommand;
2961
+ }
2962
+ });
2963
+ Object.defineProperty(exports, "shapeForRect", {
2964
+ enumerable: true,
2965
+ get: function() {
2966
+ return shapeForRect;
2967
+ }
2968
+ });
2969
+ Object.defineProperty(exports, "sniffBinaryMetadata", {
2970
+ enumerable: true,
2971
+ get: function() {
2972
+ return sniffBinaryMetadata;
2973
+ }
2974
+ });
2975
+ Object.defineProperty(exports, "squareMetres", {
2976
+ enumerable: true,
2977
+ get: function() {
2978
+ return squareMetres;
2979
+ }
2980
+ });
2981
+ Object.defineProperty(exports, "squareOf", {
2982
+ enumerable: true,
2983
+ get: function() {
2984
+ return squareOf;
2985
+ }
2986
+ });
2987
+ Object.defineProperty(exports, "toAttachmentRef", {
2988
+ enumerable: true,
2989
+ get: function() {
2990
+ return toAttachmentRef;
2991
+ }
2992
+ });
2993
+ Object.defineProperty(exports, "toOriginalRange", {
2994
+ enumerable: true,
2995
+ get: function() {
2996
+ return toOriginalRange;
2997
+ }
2998
+ });
2999
+ Object.defineProperty(exports, "toOutlineItemRef", {
3000
+ enumerable: true,
3001
+ get: function() {
3002
+ return toOutlineItemRef;
3003
+ }
3004
+ });
3005
+ Object.defineProperty(exports, "withFileFromResource", {
3006
+ enumerable: true,
3007
+ get: function() {
3008
+ return withFileFromResource;
3009
+ }
3010
+ });
3011
+
3012
+ //# sourceMappingURL=calibrate-DJbi1wuK.cjs.map