Bug 1946184 - Fix computing the CSD margin right after calling HideWindowChrome(...
[gecko.git] / toolkit / components / pdfjs / content / build / pdf.mjs
blobf09b8a5aaeedb33a2ec6b37633a9157adccd862e
1 /**
2  * @licstart The following is the entire license notice for the
3  * JavaScript code in this page
4  *
5  * Copyright 2024 Mozilla Foundation
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * @licend The above is the entire license notice for the
20  * JavaScript code in this page
21  */
23 /******/ // The require scope
24 /******/ var __webpack_require__ = {};
25 /******/ 
26 /************************************************************************/
27 /******/ /* webpack/runtime/define property getters */
28 /******/ (() => {
29 /******/        // define getter functions for harmony exports
30 /******/        __webpack_require__.d = (exports, definition) => {
31 /******/                for(var key in definition) {
32 /******/                        if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
33 /******/                                Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
34 /******/                        }
35 /******/                }
36 /******/        };
37 /******/ })();
38 /******/ 
39 /******/ /* webpack/runtime/hasOwnProperty shorthand */
40 /******/ (() => {
41 /******/        __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
42 /******/ })();
43 /******/ 
44 /************************************************************************/
45 var __webpack_exports__ = globalThis.pdfjsLib = {};
47 // EXPORTS
48 __webpack_require__.d(__webpack_exports__, {
49   AbortException: () => (/* reexport */ AbortException),
50   AnnotationBorderStyleType: () => (/* reexport */ AnnotationBorderStyleType),
51   AnnotationEditorLayer: () => (/* reexport */ AnnotationEditorLayer),
52   AnnotationEditorParamsType: () => (/* reexport */ AnnotationEditorParamsType),
53   AnnotationEditorType: () => (/* reexport */ AnnotationEditorType),
54   AnnotationEditorUIManager: () => (/* reexport */ AnnotationEditorUIManager),
55   AnnotationLayer: () => (/* reexport */ AnnotationLayer),
56   AnnotationMode: () => (/* reexport */ AnnotationMode),
57   AnnotationType: () => (/* reexport */ AnnotationType),
58   ColorPicker: () => (/* reexport */ ColorPicker),
59   DOMSVGFactory: () => (/* reexport */ DOMSVGFactory),
60   DrawLayer: () => (/* reexport */ DrawLayer),
61   FeatureTest: () => (/* reexport */ util_FeatureTest),
62   GlobalWorkerOptions: () => (/* reexport */ GlobalWorkerOptions),
63   ImageKind: () => (/* reexport */ util_ImageKind),
64   InvalidPDFException: () => (/* reexport */ InvalidPDFException),
65   OPS: () => (/* reexport */ OPS),
66   OutputScale: () => (/* reexport */ OutputScale),
67   PDFDataRangeTransport: () => (/* reexport */ PDFDataRangeTransport),
68   PDFDateString: () => (/* reexport */ PDFDateString),
69   PDFWorker: () => (/* reexport */ PDFWorker),
70   PasswordResponses: () => (/* reexport */ PasswordResponses),
71   PermissionFlag: () => (/* reexport */ PermissionFlag),
72   PixelsPerInch: () => (/* reexport */ PixelsPerInch),
73   RenderingCancelledException: () => (/* reexport */ RenderingCancelledException),
74   ResponseException: () => (/* reexport */ ResponseException),
75   SupportedImageMimeTypes: () => (/* reexport */ SupportedImageMimeTypes),
76   TextLayer: () => (/* reexport */ TextLayer),
77   TouchManager: () => (/* reexport */ TouchManager),
78   Util: () => (/* reexport */ Util),
79   VerbosityLevel: () => (/* reexport */ VerbosityLevel),
80   XfaLayer: () => (/* reexport */ XfaLayer),
81   build: () => (/* reexport */ build),
82   createValidAbsoluteUrl: () => (/* reexport */ createValidAbsoluteUrl),
83   fetchData: () => (/* reexport */ fetchData),
84   getDocument: () => (/* reexport */ getDocument),
85   getFilenameFromUrl: () => (/* reexport */ getFilenameFromUrl),
86   getPdfFilenameFromUrl: () => (/* reexport */ getPdfFilenameFromUrl),
87   getXfaPageViewport: () => (/* reexport */ getXfaPageViewport),
88   isDataScheme: () => (/* reexport */ isDataScheme),
89   isPdfFile: () => (/* reexport */ isPdfFile),
90   noContextMenu: () => (/* reexport */ noContextMenu),
91   normalizeUnicode: () => (/* reexport */ normalizeUnicode),
92   setLayerDimensions: () => (/* reexport */ setLayerDimensions),
93   shadow: () => (/* reexport */ shadow),
94   stopEvent: () => (/* reexport */ stopEvent),
95   version: () => (/* reexport */ version)
96 });
98 ;// ./src/shared/util.js
99 const isNodeJS = false;
100 const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
101 const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
102 const LINE_FACTOR = 1.35;
103 const LINE_DESCENT_FACTOR = 0.35;
104 const BASELINE_FACTOR = LINE_DESCENT_FACTOR / LINE_FACTOR;
105 const RenderingIntentFlag = {
106   ANY: 0x01,
107   DISPLAY: 0x02,
108   PRINT: 0x04,
109   SAVE: 0x08,
110   ANNOTATIONS_FORMS: 0x10,
111   ANNOTATIONS_STORAGE: 0x20,
112   ANNOTATIONS_DISABLE: 0x40,
113   IS_EDITING: 0x80,
114   OPLIST: 0x100
116 const AnnotationMode = {
117   DISABLE: 0,
118   ENABLE: 1,
119   ENABLE_FORMS: 2,
120   ENABLE_STORAGE: 3
122 const AnnotationEditorPrefix = "pdfjs_internal_editor_";
123 const AnnotationEditorType = {
124   DISABLE: -1,
125   NONE: 0,
126   FREETEXT: 3,
127   HIGHLIGHT: 9,
128   STAMP: 13,
129   INK: 15,
130   SIGNATURE: 101
132 const AnnotationEditorParamsType = {
133   RESIZE: 1,
134   CREATE: 2,
135   FREETEXT_SIZE: 11,
136   FREETEXT_COLOR: 12,
137   FREETEXT_OPACITY: 13,
138   INK_COLOR: 21,
139   INK_THICKNESS: 22,
140   INK_OPACITY: 23,
141   HIGHLIGHT_COLOR: 31,
142   HIGHLIGHT_DEFAULT_COLOR: 32,
143   HIGHLIGHT_THICKNESS: 33,
144   HIGHLIGHT_FREE: 34,
145   HIGHLIGHT_SHOW_ALL: 35,
146   DRAW_STEP: 41
148 const PermissionFlag = {
149   PRINT: 0x04,
150   MODIFY_CONTENTS: 0x08,
151   COPY: 0x10,
152   MODIFY_ANNOTATIONS: 0x20,
153   FILL_INTERACTIVE_FORMS: 0x100,
154   COPY_FOR_ACCESSIBILITY: 0x200,
155   ASSEMBLE: 0x400,
156   PRINT_HIGH_QUALITY: 0x800
158 const TextRenderingMode = {
159   FILL: 0,
160   STROKE: 1,
161   FILL_STROKE: 2,
162   INVISIBLE: 3,
163   FILL_ADD_TO_PATH: 4,
164   STROKE_ADD_TO_PATH: 5,
165   FILL_STROKE_ADD_TO_PATH: 6,
166   ADD_TO_PATH: 7,
167   FILL_STROKE_MASK: 3,
168   ADD_TO_PATH_FLAG: 4
170 const util_ImageKind = {
171   GRAYSCALE_1BPP: 1,
172   RGB_24BPP: 2,
173   RGBA_32BPP: 3
175 const AnnotationType = {
176   TEXT: 1,
177   LINK: 2,
178   FREETEXT: 3,
179   LINE: 4,
180   SQUARE: 5,
181   CIRCLE: 6,
182   POLYGON: 7,
183   POLYLINE: 8,
184   HIGHLIGHT: 9,
185   UNDERLINE: 10,
186   SQUIGGLY: 11,
187   STRIKEOUT: 12,
188   STAMP: 13,
189   CARET: 14,
190   INK: 15,
191   POPUP: 16,
192   FILEATTACHMENT: 17,
193   SOUND: 18,
194   MOVIE: 19,
195   WIDGET: 20,
196   SCREEN: 21,
197   PRINTERMARK: 22,
198   TRAPNET: 23,
199   WATERMARK: 24,
200   THREED: 25,
201   REDACT: 26
203 const AnnotationReplyType = {
204   GROUP: "Group",
205   REPLY: "R"
207 const AnnotationFlag = {
208   INVISIBLE: 0x01,
209   HIDDEN: 0x02,
210   PRINT: 0x04,
211   NOZOOM: 0x08,
212   NOROTATE: 0x10,
213   NOVIEW: 0x20,
214   READONLY: 0x40,
215   LOCKED: 0x80,
216   TOGGLENOVIEW: 0x100,
217   LOCKEDCONTENTS: 0x200
219 const AnnotationFieldFlag = {
220   READONLY: 0x0000001,
221   REQUIRED: 0x0000002,
222   NOEXPORT: 0x0000004,
223   MULTILINE: 0x0001000,
224   PASSWORD: 0x0002000,
225   NOTOGGLETOOFF: 0x0004000,
226   RADIO: 0x0008000,
227   PUSHBUTTON: 0x0010000,
228   COMBO: 0x0020000,
229   EDIT: 0x0040000,
230   SORT: 0x0080000,
231   FILESELECT: 0x0100000,
232   MULTISELECT: 0x0200000,
233   DONOTSPELLCHECK: 0x0400000,
234   DONOTSCROLL: 0x0800000,
235   COMB: 0x1000000,
236   RICHTEXT: 0x2000000,
237   RADIOSINUNISON: 0x2000000,
238   COMMITONSELCHANGE: 0x4000000
240 const AnnotationBorderStyleType = {
241   SOLID: 1,
242   DASHED: 2,
243   BEVELED: 3,
244   INSET: 4,
245   UNDERLINE: 5
247 const AnnotationActionEventType = {
248   E: "Mouse Enter",
249   X: "Mouse Exit",
250   D: "Mouse Down",
251   U: "Mouse Up",
252   Fo: "Focus",
253   Bl: "Blur",
254   PO: "PageOpen",
255   PC: "PageClose",
256   PV: "PageVisible",
257   PI: "PageInvisible",
258   K: "Keystroke",
259   F: "Format",
260   V: "Validate",
261   C: "Calculate"
263 const DocumentActionEventType = {
264   WC: "WillClose",
265   WS: "WillSave",
266   DS: "DidSave",
267   WP: "WillPrint",
268   DP: "DidPrint"
270 const PageActionEventType = {
271   O: "PageOpen",
272   C: "PageClose"
274 const VerbosityLevel = {
275   ERRORS: 0,
276   WARNINGS: 1,
277   INFOS: 5
279 const OPS = {
280   dependency: 1,
281   setLineWidth: 2,
282   setLineCap: 3,
283   setLineJoin: 4,
284   setMiterLimit: 5,
285   setDash: 6,
286   setRenderingIntent: 7,
287   setFlatness: 8,
288   setGState: 9,
289   save: 10,
290   restore: 11,
291   transform: 12,
292   moveTo: 13,
293   lineTo: 14,
294   curveTo: 15,
295   curveTo2: 16,
296   curveTo3: 17,
297   closePath: 18,
298   rectangle: 19,
299   stroke: 20,
300   closeStroke: 21,
301   fill: 22,
302   eoFill: 23,
303   fillStroke: 24,
304   eoFillStroke: 25,
305   closeFillStroke: 26,
306   closeEOFillStroke: 27,
307   endPath: 28,
308   clip: 29,
309   eoClip: 30,
310   beginText: 31,
311   endText: 32,
312   setCharSpacing: 33,
313   setWordSpacing: 34,
314   setHScale: 35,
315   setLeading: 36,
316   setFont: 37,
317   setTextRenderingMode: 38,
318   setTextRise: 39,
319   moveText: 40,
320   setLeadingMoveText: 41,
321   setTextMatrix: 42,
322   nextLine: 43,
323   showText: 44,
324   showSpacedText: 45,
325   nextLineShowText: 46,
326   nextLineSetSpacingShowText: 47,
327   setCharWidth: 48,
328   setCharWidthAndBounds: 49,
329   setStrokeColorSpace: 50,
330   setFillColorSpace: 51,
331   setStrokeColor: 52,
332   setStrokeColorN: 53,
333   setFillColor: 54,
334   setFillColorN: 55,
335   setStrokeGray: 56,
336   setFillGray: 57,
337   setStrokeRGBColor: 58,
338   setFillRGBColor: 59,
339   setStrokeCMYKColor: 60,
340   setFillCMYKColor: 61,
341   shadingFill: 62,
342   beginInlineImage: 63,
343   beginImageData: 64,
344   endInlineImage: 65,
345   paintXObject: 66,
346   markPoint: 67,
347   markPointProps: 68,
348   beginMarkedContent: 69,
349   beginMarkedContentProps: 70,
350   endMarkedContent: 71,
351   beginCompat: 72,
352   endCompat: 73,
353   paintFormXObjectBegin: 74,
354   paintFormXObjectEnd: 75,
355   beginGroup: 76,
356   endGroup: 77,
357   beginAnnotation: 80,
358   endAnnotation: 81,
359   paintImageMaskXObject: 83,
360   paintImageMaskXObjectGroup: 84,
361   paintImageXObject: 85,
362   paintInlineImageXObject: 86,
363   paintInlineImageXObjectGroup: 87,
364   paintImageXObjectRepeat: 88,
365   paintImageMaskXObjectRepeat: 89,
366   paintSolidColorImageMask: 90,
367   constructPath: 91,
368   setStrokeTransparent: 92,
369   setFillTransparent: 93
371 const PasswordResponses = {
372   NEED_PASSWORD: 1,
373   INCORRECT_PASSWORD: 2
375 let verbosity = VerbosityLevel.WARNINGS;
376 function setVerbosityLevel(level) {
377   if (Number.isInteger(level)) {
378     verbosity = level;
379   }
381 function getVerbosityLevel() {
382   return verbosity;
384 function info(msg) {
385   if (verbosity >= VerbosityLevel.INFOS) {
386     console.log(`Info: ${msg}`);
387   }
389 function warn(msg) {
390   if (verbosity >= VerbosityLevel.WARNINGS) {
391     console.log(`Warning: ${msg}`);
392   }
394 function unreachable(msg) {
395   throw new Error(msg);
397 function assert(cond, msg) {
398   if (!cond) {
399     unreachable(msg);
400   }
402 function _isValidProtocol(url) {
403   switch (url?.protocol) {
404     case "http:":
405     case "https:":
406     case "ftp:":
407     case "mailto:":
408     case "tel:":
409       return true;
410     default:
411       return false;
412   }
414 function createValidAbsoluteUrl(url, baseUrl = null, options = null) {
415   if (!url) {
416     return null;
417   }
418   try {
419     if (options && typeof url === "string") {
420       if (options.addDefaultProtocol && url.startsWith("www.")) {
421         const dots = url.match(/\./g);
422         if (dots?.length >= 2) {
423           url = `http://${url}`;
424         }
425       }
426       if (options.tryConvertEncoding) {
427         try {
428           url = stringToUTF8String(url);
429         } catch {}
430       }
431     }
432     const absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url);
433     if (_isValidProtocol(absoluteUrl)) {
434       return absoluteUrl;
435     }
436   } catch {}
437   return null;
439 function shadow(obj, prop, value, nonSerializable = false) {
440   Object.defineProperty(obj, prop, {
441     value,
442     enumerable: !nonSerializable,
443     configurable: true,
444     writable: false
445   });
446   return value;
448 const BaseException = function BaseExceptionClosure() {
449   function BaseException(message, name) {
450     this.message = message;
451     this.name = name;
452   }
453   BaseException.prototype = new Error();
454   BaseException.constructor = BaseException;
455   return BaseException;
456 }();
457 class PasswordException extends BaseException {
458   constructor(msg, code) {
459     super(msg, "PasswordException");
460     this.code = code;
461   }
463 class UnknownErrorException extends BaseException {
464   constructor(msg, details) {
465     super(msg, "UnknownErrorException");
466     this.details = details;
467   }
469 class InvalidPDFException extends BaseException {
470   constructor(msg) {
471     super(msg, "InvalidPDFException");
472   }
474 class ResponseException extends BaseException {
475   constructor(msg, status, missing) {
476     super(msg, "ResponseException");
477     this.status = status;
478     this.missing = missing;
479   }
481 class FormatError extends BaseException {
482   constructor(msg) {
483     super(msg, "FormatError");
484   }
486 class AbortException extends BaseException {
487   constructor(msg) {
488     super(msg, "AbortException");
489   }
491 function bytesToString(bytes) {
492   if (typeof bytes !== "object" || bytes?.length === undefined) {
493     unreachable("Invalid argument for bytesToString");
494   }
495   const length = bytes.length;
496   const MAX_ARGUMENT_COUNT = 8192;
497   if (length < MAX_ARGUMENT_COUNT) {
498     return String.fromCharCode.apply(null, bytes);
499   }
500   const strBuf = [];
501   for (let i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
502     const chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
503     const chunk = bytes.subarray(i, chunkEnd);
504     strBuf.push(String.fromCharCode.apply(null, chunk));
505   }
506   return strBuf.join("");
508 function stringToBytes(str) {
509   if (typeof str !== "string") {
510     unreachable("Invalid argument for stringToBytes");
511   }
512   const length = str.length;
513   const bytes = new Uint8Array(length);
514   for (let i = 0; i < length; ++i) {
515     bytes[i] = str.charCodeAt(i) & 0xff;
516   }
517   return bytes;
519 function string32(value) {
520   return String.fromCharCode(value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff);
522 function objectSize(obj) {
523   return Object.keys(obj).length;
525 function objectFromMap(map) {
526   const obj = Object.create(null);
527   for (const [key, value] of map) {
528     obj[key] = value;
529   }
530   return obj;
532 function isLittleEndian() {
533   const buffer8 = new Uint8Array(4);
534   buffer8[0] = 1;
535   const view32 = new Uint32Array(buffer8.buffer, 0, 1);
536   return view32[0] === 1;
538 function isEvalSupported() {
539   try {
540     new Function("");
541     return true;
542   } catch {
543     return false;
544   }
546 class util_FeatureTest {
547   static get isLittleEndian() {
548     return shadow(this, "isLittleEndian", isLittleEndian());
549   }
550   static get isEvalSupported() {
551     return shadow(this, "isEvalSupported", isEvalSupported());
552   }
553   static get isOffscreenCanvasSupported() {
554     return shadow(this, "isOffscreenCanvasSupported", typeof OffscreenCanvas !== "undefined");
555   }
556   static get isImageDecoderSupported() {
557     return shadow(this, "isImageDecoderSupported", typeof ImageDecoder !== "undefined");
558   }
559   static get platform() {
560     return shadow(this, "platform", {
561       isMac: navigator.platform.includes("Mac"),
562       isWindows: navigator.platform.includes("Win"),
563       isFirefox: true
564     });
565   }
566   static get isCSSRoundSupported() {
567     return shadow(this, "isCSSRoundSupported", globalThis.CSS?.supports?.("width: round(1.5px, 1px)"));
568   }
570 const hexNumbers = Array.from(Array(256).keys(), n => n.toString(16).padStart(2, "0"));
571 class Util {
572   static makeHexColor(r, g, b) {
573     return `#${hexNumbers[r]}${hexNumbers[g]}${hexNumbers[b]}`;
574   }
575   static scaleMinMax(transform, minMax) {
576     let temp;
577     if (transform[0]) {
578       if (transform[0] < 0) {
579         temp = minMax[0];
580         minMax[0] = minMax[2];
581         minMax[2] = temp;
582       }
583       minMax[0] *= transform[0];
584       minMax[2] *= transform[0];
585       if (transform[3] < 0) {
586         temp = minMax[1];
587         minMax[1] = minMax[3];
588         minMax[3] = temp;
589       }
590       minMax[1] *= transform[3];
591       minMax[3] *= transform[3];
592     } else {
593       temp = minMax[0];
594       minMax[0] = minMax[1];
595       minMax[1] = temp;
596       temp = minMax[2];
597       minMax[2] = minMax[3];
598       minMax[3] = temp;
599       if (transform[1] < 0) {
600         temp = minMax[1];
601         minMax[1] = minMax[3];
602         minMax[3] = temp;
603       }
604       minMax[1] *= transform[1];
605       minMax[3] *= transform[1];
606       if (transform[2] < 0) {
607         temp = minMax[0];
608         minMax[0] = minMax[2];
609         minMax[2] = temp;
610       }
611       minMax[0] *= transform[2];
612       minMax[2] *= transform[2];
613     }
614     minMax[0] += transform[4];
615     minMax[1] += transform[5];
616     minMax[2] += transform[4];
617     minMax[3] += transform[5];
618   }
619   static transform(m1, m2) {
620     return [m1[0] * m2[0] + m1[2] * m2[1], m1[1] * m2[0] + m1[3] * m2[1], m1[0] * m2[2] + m1[2] * m2[3], m1[1] * m2[2] + m1[3] * m2[3], m1[0] * m2[4] + m1[2] * m2[5] + m1[4], m1[1] * m2[4] + m1[3] * m2[5] + m1[5]];
621   }
622   static applyTransform(p, m) {
623     const xt = p[0] * m[0] + p[1] * m[2] + m[4];
624     const yt = p[0] * m[1] + p[1] * m[3] + m[5];
625     return [xt, yt];
626   }
627   static applyInverseTransform(p, m) {
628     const d = m[0] * m[3] - m[1] * m[2];
629     const xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
630     const yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
631     return [xt, yt];
632   }
633   static getAxialAlignedBoundingBox(r, m) {
634     const p1 = this.applyTransform(r, m);
635     const p2 = this.applyTransform(r.slice(2, 4), m);
636     const p3 = this.applyTransform([r[0], r[3]], m);
637     const p4 = this.applyTransform([r[2], r[1]], m);
638     return [Math.min(p1[0], p2[0], p3[0], p4[0]), Math.min(p1[1], p2[1], p3[1], p4[1]), Math.max(p1[0], p2[0], p3[0], p4[0]), Math.max(p1[1], p2[1], p3[1], p4[1])];
639   }
640   static inverseTransform(m) {
641     const d = m[0] * m[3] - m[1] * m[2];
642     return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d, (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];
643   }
644   static singularValueDecompose2dScale(m) {
645     const transpose = [m[0], m[2], m[1], m[3]];
646     const a = m[0] * transpose[0] + m[1] * transpose[2];
647     const b = m[0] * transpose[1] + m[1] * transpose[3];
648     const c = m[2] * transpose[0] + m[3] * transpose[2];
649     const d = m[2] * transpose[1] + m[3] * transpose[3];
650     const first = (a + d) / 2;
651     const second = Math.sqrt((a + d) ** 2 - 4 * (a * d - c * b)) / 2;
652     const sx = first + second || 1;
653     const sy = first - second || 1;
654     return [Math.sqrt(sx), Math.sqrt(sy)];
655   }
656   static normalizeRect(rect) {
657     const r = rect.slice(0);
658     if (rect[0] > rect[2]) {
659       r[0] = rect[2];
660       r[2] = rect[0];
661     }
662     if (rect[1] > rect[3]) {
663       r[1] = rect[3];
664       r[3] = rect[1];
665     }
666     return r;
667   }
668   static intersect(rect1, rect2) {
669     const xLow = Math.max(Math.min(rect1[0], rect1[2]), Math.min(rect2[0], rect2[2]));
670     const xHigh = Math.min(Math.max(rect1[0], rect1[2]), Math.max(rect2[0], rect2[2]));
671     if (xLow > xHigh) {
672       return null;
673     }
674     const yLow = Math.max(Math.min(rect1[1], rect1[3]), Math.min(rect2[1], rect2[3]));
675     const yHigh = Math.min(Math.max(rect1[1], rect1[3]), Math.max(rect2[1], rect2[3]));
676     if (yLow > yHigh) {
677       return null;
678     }
679     return [xLow, yLow, xHigh, yHigh];
680   }
681   static #getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, t, minMax) {
682     if (t <= 0 || t >= 1) {
683       return;
684     }
685     const mt = 1 - t;
686     const tt = t * t;
687     const ttt = tt * t;
688     const x = mt * (mt * (mt * x0 + 3 * t * x1) + 3 * tt * x2) + ttt * x3;
689     const y = mt * (mt * (mt * y0 + 3 * t * y1) + 3 * tt * y2) + ttt * y3;
690     minMax[0] = Math.min(minMax[0], x);
691     minMax[1] = Math.min(minMax[1], y);
692     minMax[2] = Math.max(minMax[2], x);
693     minMax[3] = Math.max(minMax[3], y);
694   }
695   static #getExtremum(x0, x1, x2, x3, y0, y1, y2, y3, a, b, c, minMax) {
696     if (Math.abs(a) < 1e-12) {
697       if (Math.abs(b) >= 1e-12) {
698         this.#getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, -c / b, minMax);
699       }
700       return;
701     }
702     const delta = b ** 2 - 4 * c * a;
703     if (delta < 0) {
704       return;
705     }
706     const sqrtDelta = Math.sqrt(delta);
707     const a2 = 2 * a;
708     this.#getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, (-b + sqrtDelta) / a2, minMax);
709     this.#getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, (-b - sqrtDelta) / a2, minMax);
710   }
711   static bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3, minMax) {
712     if (minMax) {
713       minMax[0] = Math.min(minMax[0], x0, x3);
714       minMax[1] = Math.min(minMax[1], y0, y3);
715       minMax[2] = Math.max(minMax[2], x0, x3);
716       minMax[3] = Math.max(minMax[3], y0, y3);
717     } else {
718       minMax = [Math.min(x0, x3), Math.min(y0, y3), Math.max(x0, x3), Math.max(y0, y3)];
719     }
720     this.#getExtremum(x0, x1, x2, x3, y0, y1, y2, y3, 3 * (-x0 + 3 * (x1 - x2) + x3), 6 * (x0 - 2 * x1 + x2), 3 * (x1 - x0), minMax);
721     this.#getExtremum(x0, x1, x2, x3, y0, y1, y2, y3, 3 * (-y0 + 3 * (y1 - y2) + y3), 6 * (y0 - 2 * y1 + y2), 3 * (y1 - y0), minMax);
722     return minMax;
723   }
725 const PDFStringTranslateTable = (/* unused pure expression or super */ null && ([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2d8, 0x2c7, 0x2c6, 0x2d9, 0x2dd, 0x2db, 0x2da, 0x2dc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192, 0x2044, 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x141, 0x152, 0x160, 0x178, 0x17d, 0x131, 0x142, 0x153, 0x161, 0x17e, 0, 0x20ac]));
726 function stringToPDFString(str) {
727   if (str[0] >= "\xEF") {
728     let encoding;
729     if (str[0] === "\xFE" && str[1] === "\xFF") {
730       encoding = "utf-16be";
731       if (str.length % 2 === 1) {
732         str = str.slice(0, -1);
733       }
734     } else if (str[0] === "\xFF" && str[1] === "\xFE") {
735       encoding = "utf-16le";
736       if (str.length % 2 === 1) {
737         str = str.slice(0, -1);
738       }
739     } else if (str[0] === "\xEF" && str[1] === "\xBB" && str[2] === "\xBF") {
740       encoding = "utf-8";
741     }
742     if (encoding) {
743       try {
744         const decoder = new TextDecoder(encoding, {
745           fatal: true
746         });
747         const buffer = stringToBytes(str);
748         const decoded = decoder.decode(buffer);
749         if (!decoded.includes("\x1b")) {
750           return decoded;
751         }
752         return decoded.replaceAll(/\x1b[^\x1b]*(?:\x1b|$)/g, "");
753       } catch (ex) {
754         warn(`stringToPDFString: "${ex}".`);
755       }
756     }
757   }
758   const strBuf = [];
759   for (let i = 0, ii = str.length; i < ii; i++) {
760     const charCode = str.charCodeAt(i);
761     if (charCode === 0x1b) {
762       while (++i < ii && str.charCodeAt(i) !== 0x1b) {}
763       continue;
764     }
765     const code = PDFStringTranslateTable[charCode];
766     strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
767   }
768   return strBuf.join("");
770 function stringToUTF8String(str) {
771   return decodeURIComponent(escape(str));
773 function utf8StringToString(str) {
774   return unescape(encodeURIComponent(str));
776 function isArrayEqual(arr1, arr2) {
777   if (arr1.length !== arr2.length) {
778     return false;
779   }
780   for (let i = 0, ii = arr1.length; i < ii; i++) {
781     if (arr1[i] !== arr2[i]) {
782       return false;
783     }
784   }
785   return true;
787 function getModificationDate(date = new Date()) {
788   const buffer = [date.getUTCFullYear().toString(), (date.getUTCMonth() + 1).toString().padStart(2, "0"), date.getUTCDate().toString().padStart(2, "0"), date.getUTCHours().toString().padStart(2, "0"), date.getUTCMinutes().toString().padStart(2, "0"), date.getUTCSeconds().toString().padStart(2, "0")];
789   return buffer.join("");
791 let NormalizeRegex = null;
792 let NormalizationMap = null;
793 function normalizeUnicode(str) {
794   if (!NormalizeRegex) {
795     NormalizeRegex = /([\u00a0\u00b5\u037e\u0eb3\u2000-\u200a\u202f\u2126\ufb00-\ufb04\ufb06\ufb20-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufba1\ufba4-\ufba9\ufbae-\ufbb1\ufbd3-\ufbdc\ufbde-\ufbe7\ufbea-\ufbf8\ufbfc-\ufbfd\ufc00-\ufc5d\ufc64-\ufcf1\ufcf5-\ufd3d\ufd88\ufdf4\ufdfa-\ufdfb\ufe71\ufe77\ufe79\ufe7b\ufe7d]+)|(\ufb05+)/gu;
796     NormalizationMap = new Map([["ſt", "Å¿t"]]);
797   }
798   return str.replaceAll(NormalizeRegex, (_, p1, p2) => p1 ? p1.normalize("NFKC") : NormalizationMap.get(p2));
800 function getUuid() {
801   return crypto.randomUUID();
803 const AnnotationPrefix = "pdfjs_internal_id_";
804 function toHexUtil(arr) {
805   if (Uint8Array.prototype.toHex) {
806     return arr.toHex();
807   }
808   return Array.from(arr, num => hexNumbers[num]).join("");
810 function toBase64Util(arr) {
811   if (Uint8Array.prototype.toBase64) {
812     return arr.toBase64();
813   }
814   return btoa(bytesToString(arr));
816 function fromBase64Util(str) {
817   if (Uint8Array.fromBase64) {
818     return Uint8Array.fromBase64(str);
819   }
820   return stringToBytes(atob(str));
822 if (typeof Promise.try !== "function") {
823   Promise.try = function (fn, ...args) {
824     return new Promise(resolve => {
825       resolve(fn(...args));
826     });
827   };
830 ;// ./src/display/display_utils.js
832 const SVG_NS = "http://www.w3.org/2000/svg";
833 class PixelsPerInch {
834   static CSS = 96.0;
835   static PDF = 72.0;
836   static PDF_TO_CSS_UNITS = this.CSS / this.PDF;
838 async function fetchData(url, type = "text") {
839   const response = await fetch(url);
840   if (!response.ok) {
841     throw new Error(response.statusText);
842   }
843   switch (type) {
844     case "arraybuffer":
845       return response.arrayBuffer();
846     case "blob":
847       return response.blob();
848     case "json":
849       return response.json();
850   }
851   return response.text();
853 class PageViewport {
854   constructor({
855     viewBox,
856     userUnit,
857     scale,
858     rotation,
859     offsetX = 0,
860     offsetY = 0,
861     dontFlip = false
862   }) {
863     this.viewBox = viewBox;
864     this.userUnit = userUnit;
865     this.scale = scale;
866     this.rotation = rotation;
867     this.offsetX = offsetX;
868     this.offsetY = offsetY;
869     scale *= userUnit;
870     const centerX = (viewBox[2] + viewBox[0]) / 2;
871     const centerY = (viewBox[3] + viewBox[1]) / 2;
872     let rotateA, rotateB, rotateC, rotateD;
873     rotation %= 360;
874     if (rotation < 0) {
875       rotation += 360;
876     }
877     switch (rotation) {
878       case 180:
879         rotateA = -1;
880         rotateB = 0;
881         rotateC = 0;
882         rotateD = 1;
883         break;
884       case 90:
885         rotateA = 0;
886         rotateB = 1;
887         rotateC = 1;
888         rotateD = 0;
889         break;
890       case 270:
891         rotateA = 0;
892         rotateB = -1;
893         rotateC = -1;
894         rotateD = 0;
895         break;
896       case 0:
897         rotateA = 1;
898         rotateB = 0;
899         rotateC = 0;
900         rotateD = -1;
901         break;
902       default:
903         throw new Error("PageViewport: Invalid rotation, must be a multiple of 90 degrees.");
904     }
905     if (dontFlip) {
906       rotateC = -rotateC;
907       rotateD = -rotateD;
908     }
909     let offsetCanvasX, offsetCanvasY;
910     let width, height;
911     if (rotateA === 0) {
912       offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
913       offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
914       width = (viewBox[3] - viewBox[1]) * scale;
915       height = (viewBox[2] - viewBox[0]) * scale;
916     } else {
917       offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
918       offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
919       width = (viewBox[2] - viewBox[0]) * scale;
920       height = (viewBox[3] - viewBox[1]) * scale;
921     }
922     this.transform = [rotateA * scale, rotateB * scale, rotateC * scale, rotateD * scale, offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY];
923     this.width = width;
924     this.height = height;
925   }
926   get rawDims() {
927     const {
928       userUnit,
929       viewBox
930     } = this;
931     const dims = viewBox.map(x => x * userUnit);
932     return shadow(this, "rawDims", {
933       pageWidth: dims[2] - dims[0],
934       pageHeight: dims[3] - dims[1],
935       pageX: dims[0],
936       pageY: dims[1]
937     });
938   }
939   clone({
940     scale = this.scale,
941     rotation = this.rotation,
942     offsetX = this.offsetX,
943     offsetY = this.offsetY,
944     dontFlip = false
945   } = {}) {
946     return new PageViewport({
947       viewBox: this.viewBox.slice(),
948       userUnit: this.userUnit,
949       scale,
950       rotation,
951       offsetX,
952       offsetY,
953       dontFlip
954     });
955   }
956   convertToViewportPoint(x, y) {
957     return Util.applyTransform([x, y], this.transform);
958   }
959   convertToViewportRectangle(rect) {
960     const topLeft = Util.applyTransform([rect[0], rect[1]], this.transform);
961     const bottomRight = Util.applyTransform([rect[2], rect[3]], this.transform);
962     return [topLeft[0], topLeft[1], bottomRight[0], bottomRight[1]];
963   }
964   convertToPdfPoint(x, y) {
965     return Util.applyInverseTransform([x, y], this.transform);
966   }
968 class RenderingCancelledException extends BaseException {
969   constructor(msg, extraDelay = 0) {
970     super(msg, "RenderingCancelledException");
971     this.extraDelay = extraDelay;
972   }
974 function isDataScheme(url) {
975   const ii = url.length;
976   let i = 0;
977   while (i < ii && url[i].trim() === "") {
978     i++;
979   }
980   return url.substring(i, i + 5).toLowerCase() === "data:";
982 function isPdfFile(filename) {
983   return typeof filename === "string" && /\.pdf$/i.test(filename);
985 function getFilenameFromUrl(url) {
986   [url] = url.split(/[#?]/, 1);
987   return url.substring(url.lastIndexOf("/") + 1);
989 function getPdfFilenameFromUrl(url, defaultFilename = "document.pdf") {
990   if (typeof url !== "string") {
991     return defaultFilename;
992   }
993   if (isDataScheme(url)) {
994     warn('getPdfFilenameFromUrl: ignore "data:"-URL for performance reasons.');
995     return defaultFilename;
996   }
997   const reURI = /^(?:(?:[^:]+:)?\/\/[^/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
998   const reFilename = /[^/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
999   const splitURI = reURI.exec(url);
1000   let suggestedFilename = reFilename.exec(splitURI[1]) || reFilename.exec(splitURI[2]) || reFilename.exec(splitURI[3]);
1001   if (suggestedFilename) {
1002     suggestedFilename = suggestedFilename[0];
1003     if (suggestedFilename.includes("%")) {
1004       try {
1005         suggestedFilename = reFilename.exec(decodeURIComponent(suggestedFilename))[0];
1006       } catch {}
1007     }
1008   }
1009   return suggestedFilename || defaultFilename;
1011 class StatTimer {
1012   started = Object.create(null);
1013   times = [];
1014   time(name) {
1015     if (name in this.started) {
1016       warn(`Timer is already running for ${name}`);
1017     }
1018     this.started[name] = Date.now();
1019   }
1020   timeEnd(name) {
1021     if (!(name in this.started)) {
1022       warn(`Timer has not been started for ${name}`);
1023     }
1024     this.times.push({
1025       name,
1026       start: this.started[name],
1027       end: Date.now()
1028     });
1029     delete this.started[name];
1030   }
1031   toString() {
1032     const outBuf = [];
1033     let longest = 0;
1034     for (const {
1035       name
1036     } of this.times) {
1037       longest = Math.max(name.length, longest);
1038     }
1039     for (const {
1040       name,
1041       start,
1042       end
1043     } of this.times) {
1044       outBuf.push(`${name.padEnd(longest)} ${end - start}ms\n`);
1045     }
1046     return outBuf.join("");
1047   }
1049 function isValidFetchUrl(url, baseUrl) {
1050   throw new Error("Not implemented: isValidFetchUrl");
1052 function noContextMenu(e) {
1053   e.preventDefault();
1055 function stopEvent(e) {
1056   e.preventDefault();
1057   e.stopPropagation();
1059 function deprecated(details) {
1060   console.log("Deprecated API usage: " + details);
1062 class PDFDateString {
1063   static #regex;
1064   static toDateObject(input) {
1065     if (!input || typeof input !== "string") {
1066       return null;
1067     }
1068     this.#regex ||= new RegExp("^D:" + "(\\d{4})" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "([Z|+|-])?" + "(\\d{2})?" + "'?" + "(\\d{2})?" + "'?");
1069     const matches = this.#regex.exec(input);
1070     if (!matches) {
1071       return null;
1072     }
1073     const year = parseInt(matches[1], 10);
1074     let month = parseInt(matches[2], 10);
1075     month = month >= 1 && month <= 12 ? month - 1 : 0;
1076     let day = parseInt(matches[3], 10);
1077     day = day >= 1 && day <= 31 ? day : 1;
1078     let hour = parseInt(matches[4], 10);
1079     hour = hour >= 0 && hour <= 23 ? hour : 0;
1080     let minute = parseInt(matches[5], 10);
1081     minute = minute >= 0 && minute <= 59 ? minute : 0;
1082     let second = parseInt(matches[6], 10);
1083     second = second >= 0 && second <= 59 ? second : 0;
1084     const universalTimeRelation = matches[7] || "Z";
1085     let offsetHour = parseInt(matches[8], 10);
1086     offsetHour = offsetHour >= 0 && offsetHour <= 23 ? offsetHour : 0;
1087     let offsetMinute = parseInt(matches[9], 10) || 0;
1088     offsetMinute = offsetMinute >= 0 && offsetMinute <= 59 ? offsetMinute : 0;
1089     if (universalTimeRelation === "-") {
1090       hour += offsetHour;
1091       minute += offsetMinute;
1092     } else if (universalTimeRelation === "+") {
1093       hour -= offsetHour;
1094       minute -= offsetMinute;
1095     }
1096     return new Date(Date.UTC(year, month, day, hour, minute, second));
1097   }
1099 function getXfaPageViewport(xfaPage, {
1100   scale = 1,
1101   rotation = 0
1102 }) {
1103   const {
1104     width,
1105     height
1106   } = xfaPage.attributes.style;
1107   const viewBox = [0, 0, parseInt(width), parseInt(height)];
1108   return new PageViewport({
1109     viewBox,
1110     userUnit: 1,
1111     scale,
1112     rotation
1113   });
1115 function getRGB(color) {
1116   if (color.startsWith("#")) {
1117     const colorRGB = parseInt(color.slice(1), 16);
1118     return [(colorRGB & 0xff0000) >> 16, (colorRGB & 0x00ff00) >> 8, colorRGB & 0x0000ff];
1119   }
1120   if (color.startsWith("rgb(")) {
1121     return color.slice(4, -1).split(",").map(x => parseInt(x));
1122   }
1123   if (color.startsWith("rgba(")) {
1124     return color.slice(5, -1).split(",").map(x => parseInt(x)).slice(0, 3);
1125   }
1126   warn(`Not a valid color format: "${color}"`);
1127   return [0, 0, 0];
1129 function getColorValues(colors) {
1130   const span = document.createElement("span");
1131   span.style.visibility = "hidden";
1132   document.body.append(span);
1133   for (const name of colors.keys()) {
1134     span.style.color = name;
1135     const computedColor = window.getComputedStyle(span).color;
1136     colors.set(name, getRGB(computedColor));
1137   }
1138   span.remove();
1140 function getCurrentTransform(ctx) {
1141   const {
1142     a,
1143     b,
1144     c,
1145     d,
1146     e,
1147     f
1148   } = ctx.getTransform();
1149   return [a, b, c, d, e, f];
1151 function getCurrentTransformInverse(ctx) {
1152   const {
1153     a,
1154     b,
1155     c,
1156     d,
1157     e,
1158     f
1159   } = ctx.getTransform().invertSelf();
1160   return [a, b, c, d, e, f];
1162 function setLayerDimensions(div, viewport, mustFlip = false, mustRotate = true) {
1163   if (viewport instanceof PageViewport) {
1164     const {
1165       pageWidth,
1166       pageHeight
1167     } = viewport.rawDims;
1168     const {
1169       style
1170     } = div;
1171     const useRound = util_FeatureTest.isCSSRoundSupported;
1172     const w = `var(--scale-factor) * ${pageWidth}px`,
1173       h = `var(--scale-factor) * ${pageHeight}px`;
1174     const widthStr = useRound ? `round(down, ${w}, var(--scale-round-x, 1px))` : `calc(${w})`,
1175       heightStr = useRound ? `round(down, ${h}, var(--scale-round-y, 1px))` : `calc(${h})`;
1176     if (!mustFlip || viewport.rotation % 180 === 0) {
1177       style.width = widthStr;
1178       style.height = heightStr;
1179     } else {
1180       style.width = heightStr;
1181       style.height = widthStr;
1182     }
1183   }
1184   if (mustRotate) {
1185     div.setAttribute("data-main-rotation", viewport.rotation);
1186   }
1188 class OutputScale {
1189   constructor() {
1190     const pixelRatio = window.devicePixelRatio || 1;
1191     this.sx = pixelRatio;
1192     this.sy = pixelRatio;
1193   }
1194   get scaled() {
1195     return this.sx !== 1 || this.sy !== 1;
1196   }
1197   get symmetric() {
1198     return this.sx === this.sy;
1199   }
1201 const SupportedImageMimeTypes = ["image/apng", "image/avif", "image/bmp", "image/gif", "image/jpeg", "image/png", "image/svg+xml", "image/webp", "image/x-icon"];
1203 ;// ./src/display/editor/toolbar.js
1205 class EditorToolbar {
1206   #toolbar = null;
1207   #colorPicker = null;
1208   #editor;
1209   #buttons = null;
1210   #altText = null;
1211   static #l10nRemove = null;
1212   constructor(editor) {
1213     this.#editor = editor;
1214     EditorToolbar.#l10nRemove ||= Object.freeze({
1215       freetext: "pdfjs-editor-remove-freetext-button",
1216       highlight: "pdfjs-editor-remove-highlight-button",
1217       ink: "pdfjs-editor-remove-ink-button",
1218       stamp: "pdfjs-editor-remove-stamp-button",
1219       signature: "pdfjs-editor-remove-signature-button"
1220     });
1221   }
1222   render() {
1223     const editToolbar = this.#toolbar = document.createElement("div");
1224     editToolbar.classList.add("editToolbar", "hidden");
1225     editToolbar.setAttribute("role", "toolbar");
1226     const signal = this.#editor._uiManager._signal;
1227     editToolbar.addEventListener("contextmenu", noContextMenu, {
1228       signal
1229     });
1230     editToolbar.addEventListener("pointerdown", EditorToolbar.#pointerDown, {
1231       signal
1232     });
1233     const buttons = this.#buttons = document.createElement("div");
1234     buttons.className = "buttons";
1235     editToolbar.append(buttons);
1236     const position = this.#editor.toolbarPosition;
1237     if (position) {
1238       const {
1239         style
1240       } = editToolbar;
1241       const x = this.#editor._uiManager.direction === "ltr" ? 1 - position[0] : position[0];
1242       style.insetInlineEnd = `${100 * x}%`;
1243       style.top = `calc(${100 * position[1]}% + var(--editor-toolbar-vert-offset))`;
1244     }
1245     this.#addDeleteButton();
1246     return editToolbar;
1247   }
1248   get div() {
1249     return this.#toolbar;
1250   }
1251   static #pointerDown(e) {
1252     e.stopPropagation();
1253   }
1254   #focusIn(e) {
1255     this.#editor._focusEventsAllowed = false;
1256     stopEvent(e);
1257   }
1258   #focusOut(e) {
1259     this.#editor._focusEventsAllowed = true;
1260     stopEvent(e);
1261   }
1262   #addListenersToElement(element) {
1263     const signal = this.#editor._uiManager._signal;
1264     element.addEventListener("focusin", this.#focusIn.bind(this), {
1265       capture: true,
1266       signal
1267     });
1268     element.addEventListener("focusout", this.#focusOut.bind(this), {
1269       capture: true,
1270       signal
1271     });
1272     element.addEventListener("contextmenu", noContextMenu, {
1273       signal
1274     });
1275   }
1276   hide() {
1277     this.#toolbar.classList.add("hidden");
1278     this.#colorPicker?.hideDropdown();
1279   }
1280   show() {
1281     this.#toolbar.classList.remove("hidden");
1282     this.#altText?.shown();
1283   }
1284   #addDeleteButton() {
1285     const {
1286       editorType,
1287       _uiManager
1288     } = this.#editor;
1289     const button = document.createElement("button");
1290     button.className = "delete";
1291     button.tabIndex = 0;
1292     button.setAttribute("data-l10n-id", EditorToolbar.#l10nRemove[editorType]);
1293     this.#addListenersToElement(button);
1294     button.addEventListener("click", e => {
1295       _uiManager.delete();
1296     }, {
1297       signal: _uiManager._signal
1298     });
1299     this.#buttons.append(button);
1300   }
1301   get #divider() {
1302     const divider = document.createElement("div");
1303     divider.className = "divider";
1304     return divider;
1305   }
1306   async addAltText(altText) {
1307     const button = await altText.render();
1308     this.#addListenersToElement(button);
1309     this.#buttons.prepend(button, this.#divider);
1310     this.#altText = altText;
1311   }
1312   addColorPicker(colorPicker) {
1313     this.#colorPicker = colorPicker;
1314     const button = colorPicker.renderButton();
1315     this.#addListenersToElement(button);
1316     this.#buttons.prepend(button, this.#divider);
1317   }
1318   remove() {
1319     this.#toolbar.remove();
1320     this.#colorPicker?.destroy();
1321     this.#colorPicker = null;
1322   }
1324 class HighlightToolbar {
1325   #buttons = null;
1326   #toolbar = null;
1327   #uiManager;
1328   constructor(uiManager) {
1329     this.#uiManager = uiManager;
1330   }
1331   #render() {
1332     const editToolbar = this.#toolbar = document.createElement("div");
1333     editToolbar.className = "editToolbar";
1334     editToolbar.setAttribute("role", "toolbar");
1335     editToolbar.addEventListener("contextmenu", noContextMenu, {
1336       signal: this.#uiManager._signal
1337     });
1338     const buttons = this.#buttons = document.createElement("div");
1339     buttons.className = "buttons";
1340     editToolbar.append(buttons);
1341     this.#addHighlightButton();
1342     return editToolbar;
1343   }
1344   #getLastPoint(boxes, isLTR) {
1345     let lastY = 0;
1346     let lastX = 0;
1347     for (const box of boxes) {
1348       const y = box.y + box.height;
1349       if (y < lastY) {
1350         continue;
1351       }
1352       const x = box.x + (isLTR ? box.width : 0);
1353       if (y > lastY) {
1354         lastX = x;
1355         lastY = y;
1356         continue;
1357       }
1358       if (isLTR) {
1359         if (x > lastX) {
1360           lastX = x;
1361         }
1362       } else if (x < lastX) {
1363         lastX = x;
1364       }
1365     }
1366     return [isLTR ? 1 - lastX : lastX, lastY];
1367   }
1368   show(parent, boxes, isLTR) {
1369     const [x, y] = this.#getLastPoint(boxes, isLTR);
1370     const {
1371       style
1372     } = this.#toolbar ||= this.#render();
1373     parent.append(this.#toolbar);
1374     style.insetInlineEnd = `${100 * x}%`;
1375     style.top = `calc(${100 * y}% + var(--editor-toolbar-vert-offset))`;
1376   }
1377   hide() {
1378     this.#toolbar.remove();
1379   }
1380   #addHighlightButton() {
1381     const button = document.createElement("button");
1382     button.className = "highlightButton";
1383     button.tabIndex = 0;
1384     button.setAttribute("data-l10n-id", `pdfjs-highlight-floating-button1`);
1385     const span = document.createElement("span");
1386     button.append(span);
1387     span.className = "visuallyHidden";
1388     span.setAttribute("data-l10n-id", "pdfjs-highlight-floating-button-label");
1389     const signal = this.#uiManager._signal;
1390     button.addEventListener("contextmenu", noContextMenu, {
1391       signal
1392     });
1393     button.addEventListener("click", () => {
1394       this.#uiManager.highlightSelection("floating_button");
1395     }, {
1396       signal
1397     });
1398     this.#buttons.append(button);
1399   }
1402 ;// ./src/display/editor/tools.js
1406 function bindEvents(obj, element, names) {
1407   for (const name of names) {
1408     element.addEventListener(name, obj[name].bind(obj));
1409   }
1411 function opacityToHex(opacity) {
1412   return Math.round(Math.min(255, Math.max(1, 255 * opacity))).toString(16).padStart(2, "0");
1414 class IdManager {
1415   #id = 0;
1416   get id() {
1417     return `${AnnotationEditorPrefix}${this.#id++}`;
1418   }
1420 class ImageManager {
1421   #baseId = getUuid();
1422   #id = 0;
1423   #cache = null;
1424   static get _isSVGFittingCanvas() {
1425     const svg = `data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 1 1" width="1" height="1" xmlns="http://www.w3.org/2000/svg"><rect width="1" height="1" style="fill:red;"/></svg>`;
1426     const canvas = new OffscreenCanvas(1, 3);
1427     const ctx = canvas.getContext("2d", {
1428       willReadFrequently: true
1429     });
1430     const image = new Image();
1431     image.src = svg;
1432     const promise = image.decode().then(() => {
1433       ctx.drawImage(image, 0, 0, 1, 1, 0, 0, 1, 3);
1434       return new Uint32Array(ctx.getImageData(0, 0, 1, 1).data.buffer)[0] === 0;
1435     });
1436     return shadow(this, "_isSVGFittingCanvas", promise);
1437   }
1438   async #get(key, rawData) {
1439     this.#cache ||= new Map();
1440     let data = this.#cache.get(key);
1441     if (data === null) {
1442       return null;
1443     }
1444     if (data?.bitmap) {
1445       data.refCounter += 1;
1446       return data;
1447     }
1448     try {
1449       data ||= {
1450         bitmap: null,
1451         id: `image_${this.#baseId}_${this.#id++}`,
1452         refCounter: 0,
1453         isSvg: false
1454       };
1455       let image;
1456       if (typeof rawData === "string") {
1457         data.url = rawData;
1458         image = await fetchData(rawData, "blob");
1459       } else if (rawData instanceof File) {
1460         image = data.file = rawData;
1461       } else if (rawData instanceof Blob) {
1462         image = rawData;
1463       }
1464       if (image.type === "image/svg+xml") {
1465         const mustRemoveAspectRatioPromise = ImageManager._isSVGFittingCanvas;
1466         const fileReader = new FileReader();
1467         const imageElement = new Image();
1468         const imagePromise = new Promise((resolve, reject) => {
1469           imageElement.onload = () => {
1470             data.bitmap = imageElement;
1471             data.isSvg = true;
1472             resolve();
1473           };
1474           fileReader.onload = async () => {
1475             const url = data.svgUrl = fileReader.result;
1476             imageElement.src = (await mustRemoveAspectRatioPromise) ? `${url}#svgView(preserveAspectRatio(none))` : url;
1477           };
1478           imageElement.onerror = fileReader.onerror = reject;
1479         });
1480         fileReader.readAsDataURL(image);
1481         await imagePromise;
1482       } else {
1483         data.bitmap = await createImageBitmap(image);
1484       }
1485       data.refCounter = 1;
1486     } catch (e) {
1487       warn(e);
1488       data = null;
1489     }
1490     this.#cache.set(key, data);
1491     if (data) {
1492       this.#cache.set(data.id, data);
1493     }
1494     return data;
1495   }
1496   async getFromFile(file) {
1497     const {
1498       lastModified,
1499       name,
1500       size,
1501       type
1502     } = file;
1503     return this.#get(`${lastModified}_${name}_${size}_${type}`, file);
1504   }
1505   async getFromUrl(url) {
1506     return this.#get(url, url);
1507   }
1508   async getFromBlob(id, blobPromise) {
1509     const blob = await blobPromise;
1510     return this.#get(id, blob);
1511   }
1512   async getFromId(id) {
1513     this.#cache ||= new Map();
1514     const data = this.#cache.get(id);
1515     if (!data) {
1516       return null;
1517     }
1518     if (data.bitmap) {
1519       data.refCounter += 1;
1520       return data;
1521     }
1522     if (data.file) {
1523       return this.getFromFile(data.file);
1524     }
1525     if (data.blobPromise) {
1526       const {
1527         blobPromise
1528       } = data;
1529       delete data.blobPromise;
1530       return this.getFromBlob(data.id, blobPromise);
1531     }
1532     return this.getFromUrl(data.url);
1533   }
1534   getFromCanvas(id, canvas) {
1535     this.#cache ||= new Map();
1536     let data = this.#cache.get(id);
1537     if (data?.bitmap) {
1538       data.refCounter += 1;
1539       return data;
1540     }
1541     const offscreen = new OffscreenCanvas(canvas.width, canvas.height);
1542     const ctx = offscreen.getContext("2d");
1543     ctx.drawImage(canvas, 0, 0);
1544     data = {
1545       bitmap: offscreen.transferToImageBitmap(),
1546       id: `image_${this.#baseId}_${this.#id++}`,
1547       refCounter: 1,
1548       isSvg: false
1549     };
1550     this.#cache.set(id, data);
1551     this.#cache.set(data.id, data);
1552     return data;
1553   }
1554   getSvgUrl(id) {
1555     const data = this.#cache.get(id);
1556     if (!data?.isSvg) {
1557       return null;
1558     }
1559     return data.svgUrl;
1560   }
1561   deleteId(id) {
1562     this.#cache ||= new Map();
1563     const data = this.#cache.get(id);
1564     if (!data) {
1565       return;
1566     }
1567     data.refCounter -= 1;
1568     if (data.refCounter !== 0) {
1569       return;
1570     }
1571     const {
1572       bitmap
1573     } = data;
1574     if (!data.url && !data.file) {
1575       const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
1576       const ctx = canvas.getContext("bitmaprenderer");
1577       ctx.transferFromImageBitmap(bitmap);
1578       data.blobPromise = canvas.convertToBlob();
1579     }
1580     bitmap.close?.();
1581     data.bitmap = null;
1582   }
1583   isValidId(id) {
1584     return id.startsWith(`image_${this.#baseId}_`);
1585   }
1587 class CommandManager {
1588   #commands = [];
1589   #locked = false;
1590   #maxSize;
1591   #position = -1;
1592   constructor(maxSize = 128) {
1593     this.#maxSize = maxSize;
1594   }
1595   add({
1596     cmd,
1597     undo,
1598     post,
1599     mustExec,
1600     type = NaN,
1601     overwriteIfSameType = false,
1602     keepUndo = false
1603   }) {
1604     if (mustExec) {
1605       cmd();
1606     }
1607     if (this.#locked) {
1608       return;
1609     }
1610     const save = {
1611       cmd,
1612       undo,
1613       post,
1614       type
1615     };
1616     if (this.#position === -1) {
1617       if (this.#commands.length > 0) {
1618         this.#commands.length = 0;
1619       }
1620       this.#position = 0;
1621       this.#commands.push(save);
1622       return;
1623     }
1624     if (overwriteIfSameType && this.#commands[this.#position].type === type) {
1625       if (keepUndo) {
1626         save.undo = this.#commands[this.#position].undo;
1627       }
1628       this.#commands[this.#position] = save;
1629       return;
1630     }
1631     const next = this.#position + 1;
1632     if (next === this.#maxSize) {
1633       this.#commands.splice(0, 1);
1634     } else {
1635       this.#position = next;
1636       if (next < this.#commands.length) {
1637         this.#commands.splice(next);
1638       }
1639     }
1640     this.#commands.push(save);
1641   }
1642   undo() {
1643     if (this.#position === -1) {
1644       return;
1645     }
1646     this.#locked = true;
1647     const {
1648       undo,
1649       post
1650     } = this.#commands[this.#position];
1651     undo();
1652     post?.();
1653     this.#locked = false;
1654     this.#position -= 1;
1655   }
1656   redo() {
1657     if (this.#position < this.#commands.length - 1) {
1658       this.#position += 1;
1659       this.#locked = true;
1660       const {
1661         cmd,
1662         post
1663       } = this.#commands[this.#position];
1664       cmd();
1665       post?.();
1666       this.#locked = false;
1667     }
1668   }
1669   hasSomethingToUndo() {
1670     return this.#position !== -1;
1671   }
1672   hasSomethingToRedo() {
1673     return this.#position < this.#commands.length - 1;
1674   }
1675   cleanType(type) {
1676     if (this.#position === -1) {
1677       return;
1678     }
1679     for (let i = this.#position; i >= 0; i--) {
1680       if (this.#commands[i].type !== type) {
1681         this.#commands.splice(i + 1, this.#position - i);
1682         this.#position = i;
1683         return;
1684       }
1685     }
1686     this.#commands.length = 0;
1687     this.#position = -1;
1688   }
1689   destroy() {
1690     this.#commands = null;
1691   }
1693 class KeyboardManager {
1694   constructor(callbacks) {
1695     this.buffer = [];
1696     this.callbacks = new Map();
1697     this.allKeys = new Set();
1698     const {
1699       isMac
1700     } = util_FeatureTest.platform;
1701     for (const [keys, callback, options = {}] of callbacks) {
1702       for (const key of keys) {
1703         const isMacKey = key.startsWith("mac+");
1704         if (isMac && isMacKey) {
1705           this.callbacks.set(key.slice(4), {
1706             callback,
1707             options
1708           });
1709           this.allKeys.add(key.split("+").at(-1));
1710         } else if (!isMac && !isMacKey) {
1711           this.callbacks.set(key, {
1712             callback,
1713             options
1714           });
1715           this.allKeys.add(key.split("+").at(-1));
1716         }
1717       }
1718     }
1719   }
1720   #serialize(event) {
1721     if (event.altKey) {
1722       this.buffer.push("alt");
1723     }
1724     if (event.ctrlKey) {
1725       this.buffer.push("ctrl");
1726     }
1727     if (event.metaKey) {
1728       this.buffer.push("meta");
1729     }
1730     if (event.shiftKey) {
1731       this.buffer.push("shift");
1732     }
1733     this.buffer.push(event.key);
1734     const str = this.buffer.join("+");
1735     this.buffer.length = 0;
1736     return str;
1737   }
1738   exec(self, event) {
1739     if (!this.allKeys.has(event.key)) {
1740       return;
1741     }
1742     const info = this.callbacks.get(this.#serialize(event));
1743     if (!info) {
1744       return;
1745     }
1746     const {
1747       callback,
1748       options: {
1749         bubbles = false,
1750         args = [],
1751         checker = null
1752       }
1753     } = info;
1754     if (checker && !checker(self, event)) {
1755       return;
1756     }
1757     callback.bind(self, ...args, event)();
1758     if (!bubbles) {
1759       stopEvent(event);
1760     }
1761   }
1763 class ColorManager {
1764   static _colorsMapping = new Map([["CanvasText", [0, 0, 0]], ["Canvas", [255, 255, 255]]]);
1765   get _colors() {
1766     const colors = new Map([["CanvasText", null], ["Canvas", null]]);
1767     getColorValues(colors);
1768     return shadow(this, "_colors", colors);
1769   }
1770   convert(color) {
1771     const rgb = getRGB(color);
1772     if (!window.matchMedia("(forced-colors: active)").matches) {
1773       return rgb;
1774     }
1775     for (const [name, RGB] of this._colors) {
1776       if (RGB.every((x, i) => x === rgb[i])) {
1777         return ColorManager._colorsMapping.get(name);
1778       }
1779     }
1780     return rgb;
1781   }
1782   getHexCode(name) {
1783     const rgb = this._colors.get(name);
1784     if (!rgb) {
1785       return name;
1786     }
1787     return Util.makeHexColor(...rgb);
1788   }
1790 class AnnotationEditorUIManager {
1791   #abortController = new AbortController();
1792   #activeEditor = null;
1793   #allEditors = new Map();
1794   #allLayers = new Map();
1795   #altTextManager = null;
1796   #annotationStorage = null;
1797   #changedExistingAnnotations = null;
1798   #commandManager = new CommandManager();
1799   #copyPasteAC = null;
1800   #currentDrawingSession = null;
1801   #currentPageIndex = 0;
1802   #deletedAnnotationsElementIds = new Set();
1803   #draggingEditors = null;
1804   #editorTypes = null;
1805   #editorsToRescale = new Set();
1806   _editorUndoBar = null;
1807   #enableHighlightFloatingButton = false;
1808   #enableUpdatedAddImage = false;
1809   #enableNewAltTextWhenAddingImage = false;
1810   #filterFactory = null;
1811   #focusMainContainerTimeoutId = null;
1812   #focusManagerAC = null;
1813   #highlightColors = null;
1814   #highlightWhenShiftUp = false;
1815   #highlightToolbar = null;
1816   #idManager = new IdManager();
1817   #isEnabled = false;
1818   #isWaiting = false;
1819   #keyboardManagerAC = null;
1820   #lastActiveElement = null;
1821   #mainHighlightColorPicker = null;
1822   #missingCanvases = null;
1823   #mlManager = null;
1824   #mode = AnnotationEditorType.NONE;
1825   #selectedEditors = new Set();
1826   #selectedTextNode = null;
1827   #signatureManager = null;
1828   #pageColors = null;
1829   #showAllStates = null;
1830   #previousStates = {
1831     isEditing: false,
1832     isEmpty: true,
1833     hasSomethingToUndo: false,
1834     hasSomethingToRedo: false,
1835     hasSelectedEditor: false,
1836     hasSelectedText: false
1837   };
1838   #translation = [0, 0];
1839   #translationTimeoutId = null;
1840   #container = null;
1841   #viewer = null;
1842   #updateModeCapability = null;
1843   static TRANSLATE_SMALL = 1;
1844   static TRANSLATE_BIG = 10;
1845   static get _keyboardManager() {
1846     const proto = AnnotationEditorUIManager.prototype;
1847     const arrowChecker = self => self.#container.contains(document.activeElement) && document.activeElement.tagName !== "BUTTON" && self.hasSomethingToControl();
1848     const textInputChecker = (_self, {
1849       target: el
1850     }) => {
1851       if (el instanceof HTMLInputElement) {
1852         const {
1853           type
1854         } = el;
1855         return type !== "text" && type !== "number";
1856       }
1857       return true;
1858     };
1859     const small = this.TRANSLATE_SMALL;
1860     const big = this.TRANSLATE_BIG;
1861     return shadow(this, "_keyboardManager", new KeyboardManager([[["ctrl+a", "mac+meta+a"], proto.selectAll, {
1862       checker: textInputChecker
1863     }], [["ctrl+z", "mac+meta+z"], proto.undo, {
1864       checker: textInputChecker
1865     }], [["ctrl+y", "ctrl+shift+z", "mac+meta+shift+z", "ctrl+shift+Z", "mac+meta+shift+Z"], proto.redo, {
1866       checker: textInputChecker
1867     }], [["Backspace", "alt+Backspace", "ctrl+Backspace", "shift+Backspace", "mac+Backspace", "mac+alt+Backspace", "mac+ctrl+Backspace", "Delete", "ctrl+Delete", "shift+Delete", "mac+Delete"], proto.delete, {
1868       checker: textInputChecker
1869     }], [["Enter", "mac+Enter"], proto.addNewEditorFromKeyboard, {
1870       checker: (self, {
1871         target: el
1872       }) => !(el instanceof HTMLButtonElement) && self.#container.contains(el) && !self.isEnterHandled
1873     }], [[" ", "mac+ "], proto.addNewEditorFromKeyboard, {
1874       checker: (self, {
1875         target: el
1876       }) => !(el instanceof HTMLButtonElement) && self.#container.contains(document.activeElement)
1877     }], [["Escape", "mac+Escape"], proto.unselectAll], [["ArrowLeft", "mac+ArrowLeft"], proto.translateSelectedEditors, {
1878       args: [-small, 0],
1879       checker: arrowChecker
1880     }], [["ctrl+ArrowLeft", "mac+shift+ArrowLeft"], proto.translateSelectedEditors, {
1881       args: [-big, 0],
1882       checker: arrowChecker
1883     }], [["ArrowRight", "mac+ArrowRight"], proto.translateSelectedEditors, {
1884       args: [small, 0],
1885       checker: arrowChecker
1886     }], [["ctrl+ArrowRight", "mac+shift+ArrowRight"], proto.translateSelectedEditors, {
1887       args: [big, 0],
1888       checker: arrowChecker
1889     }], [["ArrowUp", "mac+ArrowUp"], proto.translateSelectedEditors, {
1890       args: [0, -small],
1891       checker: arrowChecker
1892     }], [["ctrl+ArrowUp", "mac+shift+ArrowUp"], proto.translateSelectedEditors, {
1893       args: [0, -big],
1894       checker: arrowChecker
1895     }], [["ArrowDown", "mac+ArrowDown"], proto.translateSelectedEditors, {
1896       args: [0, small],
1897       checker: arrowChecker
1898     }], [["ctrl+ArrowDown", "mac+shift+ArrowDown"], proto.translateSelectedEditors, {
1899       args: [0, big],
1900       checker: arrowChecker
1901     }]]));
1902   }
1903   constructor(container, viewer, altTextManager, signatureManager, eventBus, pdfDocument, pageColors, highlightColors, enableHighlightFloatingButton, enableUpdatedAddImage, enableNewAltTextWhenAddingImage, mlManager, editorUndoBar, supportsPinchToZoom) {
1904     const signal = this._signal = this.#abortController.signal;
1905     this.#container = container;
1906     this.#viewer = viewer;
1907     this.#altTextManager = altTextManager;
1908     this.#signatureManager = signatureManager;
1909     this._eventBus = eventBus;
1910     eventBus._on("editingaction", this.onEditingAction.bind(this), {
1911       signal
1912     });
1913     eventBus._on("pagechanging", this.onPageChanging.bind(this), {
1914       signal
1915     });
1916     eventBus._on("scalechanging", this.onScaleChanging.bind(this), {
1917       signal
1918     });
1919     eventBus._on("rotationchanging", this.onRotationChanging.bind(this), {
1920       signal
1921     });
1922     eventBus._on("setpreference", this.onSetPreference.bind(this), {
1923       signal
1924     });
1925     eventBus._on("switchannotationeditorparams", evt => this.updateParams(evt.type, evt.value), {
1926       signal
1927     });
1928     this.#addSelectionListener();
1929     this.#addDragAndDropListeners();
1930     this.#addKeyboardManager();
1931     this.#annotationStorage = pdfDocument.annotationStorage;
1932     this.#filterFactory = pdfDocument.filterFactory;
1933     this.#pageColors = pageColors;
1934     this.#highlightColors = highlightColors || null;
1935     this.#enableHighlightFloatingButton = enableHighlightFloatingButton;
1936     this.#enableUpdatedAddImage = enableUpdatedAddImage;
1937     this.#enableNewAltTextWhenAddingImage = enableNewAltTextWhenAddingImage;
1938     this.#mlManager = mlManager || null;
1939     this.viewParameters = {
1940       realScale: PixelsPerInch.PDF_TO_CSS_UNITS,
1941       rotation: 0
1942     };
1943     this.isShiftKeyDown = false;
1944     this._editorUndoBar = editorUndoBar || null;
1945     this._supportsPinchToZoom = supportsPinchToZoom !== false;
1946   }
1947   destroy() {
1948     this.#updateModeCapability?.resolve();
1949     this.#updateModeCapability = null;
1950     this.#abortController?.abort();
1951     this.#abortController = null;
1952     this._signal = null;
1953     for (const layer of this.#allLayers.values()) {
1954       layer.destroy();
1955     }
1956     this.#allLayers.clear();
1957     this.#allEditors.clear();
1958     this.#editorsToRescale.clear();
1959     this.#missingCanvases?.clear();
1960     this.#activeEditor = null;
1961     this.#selectedEditors.clear();
1962     this.#commandManager.destroy();
1963     this.#altTextManager?.destroy();
1964     this.#signatureManager?.destroy();
1965     this.#highlightToolbar?.hide();
1966     this.#highlightToolbar = null;
1967     this.#mainHighlightColorPicker?.destroy();
1968     this.#mainHighlightColorPicker = null;
1969     if (this.#focusMainContainerTimeoutId) {
1970       clearTimeout(this.#focusMainContainerTimeoutId);
1971       this.#focusMainContainerTimeoutId = null;
1972     }
1973     if (this.#translationTimeoutId) {
1974       clearTimeout(this.#translationTimeoutId);
1975       this.#translationTimeoutId = null;
1976     }
1977     this._editorUndoBar?.destroy();
1978   }
1979   combinedSignal(ac) {
1980     return AbortSignal.any([this._signal, ac.signal]);
1981   }
1982   get mlManager() {
1983     return this.#mlManager;
1984   }
1985   get useNewAltTextFlow() {
1986     return this.#enableUpdatedAddImage;
1987   }
1988   get useNewAltTextWhenAddingImage() {
1989     return this.#enableNewAltTextWhenAddingImage;
1990   }
1991   get hcmFilter() {
1992     return shadow(this, "hcmFilter", this.#pageColors ? this.#filterFactory.addHCMFilter(this.#pageColors.foreground, this.#pageColors.background) : "none");
1993   }
1994   get direction() {
1995     return shadow(this, "direction", getComputedStyle(this.#container).direction);
1996   }
1997   get highlightColors() {
1998     return shadow(this, "highlightColors", this.#highlightColors ? new Map(this.#highlightColors.split(",").map(pair => pair.split("=").map(x => x.trim()))) : null);
1999   }
2000   get highlightColorNames() {
2001     return shadow(this, "highlightColorNames", this.highlightColors ? new Map(Array.from(this.highlightColors, e => e.reverse())) : null);
2002   }
2003   setCurrentDrawingSession(layer) {
2004     if (layer) {
2005       this.unselectAll();
2006       this.disableUserSelect(true);
2007     } else {
2008       this.disableUserSelect(false);
2009     }
2010     this.#currentDrawingSession = layer;
2011   }
2012   setMainHighlightColorPicker(colorPicker) {
2013     this.#mainHighlightColorPicker = colorPicker;
2014   }
2015   editAltText(editor, firstTime = false) {
2016     this.#altTextManager?.editAltText(this, editor, firstTime);
2017   }
2018   getSignature(editor) {
2019     this.#signatureManager?.getSignature({
2020       uiManager: this,
2021       editor
2022     });
2023   }
2024   switchToMode(mode, callback) {
2025     this._eventBus.on("annotationeditormodechanged", callback, {
2026       once: true,
2027       signal: this._signal
2028     });
2029     this._eventBus.dispatch("showannotationeditorui", {
2030       source: this,
2031       mode
2032     });
2033   }
2034   setPreference(name, value) {
2035     this._eventBus.dispatch("setpreference", {
2036       source: this,
2037       name,
2038       value
2039     });
2040   }
2041   onSetPreference({
2042     name,
2043     value
2044   }) {
2045     switch (name) {
2046       case "enableNewAltTextWhenAddingImage":
2047         this.#enableNewAltTextWhenAddingImage = value;
2048         break;
2049     }
2050   }
2051   onPageChanging({
2052     pageNumber
2053   }) {
2054     this.#currentPageIndex = pageNumber - 1;
2055   }
2056   focusMainContainer() {
2057     this.#container.focus();
2058   }
2059   findParent(x, y) {
2060     for (const layer of this.#allLayers.values()) {
2061       const {
2062         x: layerX,
2063         y: layerY,
2064         width,
2065         height
2066       } = layer.div.getBoundingClientRect();
2067       if (x >= layerX && x <= layerX + width && y >= layerY && y <= layerY + height) {
2068         return layer;
2069       }
2070     }
2071     return null;
2072   }
2073   disableUserSelect(value = false) {
2074     this.#viewer.classList.toggle("noUserSelect", value);
2075   }
2076   addShouldRescale(editor) {
2077     this.#editorsToRescale.add(editor);
2078   }
2079   removeShouldRescale(editor) {
2080     this.#editorsToRescale.delete(editor);
2081   }
2082   onScaleChanging({
2083     scale
2084   }) {
2085     this.commitOrRemove();
2086     this.viewParameters.realScale = scale * PixelsPerInch.PDF_TO_CSS_UNITS;
2087     for (const editor of this.#editorsToRescale) {
2088       editor.onScaleChanging();
2089     }
2090     this.#currentDrawingSession?.onScaleChanging();
2091   }
2092   onRotationChanging({
2093     pagesRotation
2094   }) {
2095     this.commitOrRemove();
2096     this.viewParameters.rotation = pagesRotation;
2097   }
2098   #getAnchorElementForSelection({
2099     anchorNode
2100   }) {
2101     return anchorNode.nodeType === Node.TEXT_NODE ? anchorNode.parentElement : anchorNode;
2102   }
2103   #getLayerForTextLayer(textLayer) {
2104     const {
2105       currentLayer
2106     } = this;
2107     if (currentLayer.hasTextLayer(textLayer)) {
2108       return currentLayer;
2109     }
2110     for (const layer of this.#allLayers.values()) {
2111       if (layer.hasTextLayer(textLayer)) {
2112         return layer;
2113       }
2114     }
2115     return null;
2116   }
2117   highlightSelection(methodOfCreation = "") {
2118     const selection = document.getSelection();
2119     if (!selection || selection.isCollapsed) {
2120       return;
2121     }
2122     const {
2123       anchorNode,
2124       anchorOffset,
2125       focusNode,
2126       focusOffset
2127     } = selection;
2128     const text = selection.toString();
2129     const anchorElement = this.#getAnchorElementForSelection(selection);
2130     const textLayer = anchorElement.closest(".textLayer");
2131     const boxes = this.getSelectionBoxes(textLayer);
2132     if (!boxes) {
2133       return;
2134     }
2135     selection.empty();
2136     const layer = this.#getLayerForTextLayer(textLayer);
2137     const isNoneMode = this.#mode === AnnotationEditorType.NONE;
2138     const callback = () => {
2139       layer?.createAndAddNewEditor({
2140         x: 0,
2141         y: 0
2142       }, false, {
2143         methodOfCreation,
2144         boxes,
2145         anchorNode,
2146         anchorOffset,
2147         focusNode,
2148         focusOffset,
2149         text
2150       });
2151       if (isNoneMode) {
2152         this.showAllEditors("highlight", true, true);
2153       }
2154     };
2155     if (isNoneMode) {
2156       this.switchToMode(AnnotationEditorType.HIGHLIGHT, callback);
2157       return;
2158     }
2159     callback();
2160   }
2161   #displayHighlightToolbar() {
2162     const selection = document.getSelection();
2163     if (!selection || selection.isCollapsed) {
2164       return;
2165     }
2166     const anchorElement = this.#getAnchorElementForSelection(selection);
2167     const textLayer = anchorElement.closest(".textLayer");
2168     const boxes = this.getSelectionBoxes(textLayer);
2169     if (!boxes) {
2170       return;
2171     }
2172     this.#highlightToolbar ||= new HighlightToolbar(this);
2173     this.#highlightToolbar.show(textLayer, boxes, this.direction === "ltr");
2174   }
2175   addToAnnotationStorage(editor) {
2176     if (!editor.isEmpty() && this.#annotationStorage && !this.#annotationStorage.has(editor.id)) {
2177       this.#annotationStorage.setValue(editor.id, editor);
2178     }
2179   }
2180   #selectionChange() {
2181     const selection = document.getSelection();
2182     if (!selection || selection.isCollapsed) {
2183       if (this.#selectedTextNode) {
2184         this.#highlightToolbar?.hide();
2185         this.#selectedTextNode = null;
2186         this.#dispatchUpdateStates({
2187           hasSelectedText: false
2188         });
2189       }
2190       return;
2191     }
2192     const {
2193       anchorNode
2194     } = selection;
2195     if (anchorNode === this.#selectedTextNode) {
2196       return;
2197     }
2198     const anchorElement = this.#getAnchorElementForSelection(selection);
2199     const textLayer = anchorElement.closest(".textLayer");
2200     if (!textLayer) {
2201       if (this.#selectedTextNode) {
2202         this.#highlightToolbar?.hide();
2203         this.#selectedTextNode = null;
2204         this.#dispatchUpdateStates({
2205           hasSelectedText: false
2206         });
2207       }
2208       return;
2209     }
2210     this.#highlightToolbar?.hide();
2211     this.#selectedTextNode = anchorNode;
2212     this.#dispatchUpdateStates({
2213       hasSelectedText: true
2214     });
2215     if (this.#mode !== AnnotationEditorType.HIGHLIGHT && this.#mode !== AnnotationEditorType.NONE) {
2216       return;
2217     }
2218     if (this.#mode === AnnotationEditorType.HIGHLIGHT) {
2219       this.showAllEditors("highlight", true, true);
2220     }
2221     this.#highlightWhenShiftUp = this.isShiftKeyDown;
2222     if (!this.isShiftKeyDown) {
2223       const activeLayer = this.#mode === AnnotationEditorType.HIGHLIGHT ? this.#getLayerForTextLayer(textLayer) : null;
2224       activeLayer?.toggleDrawing();
2225       const ac = new AbortController();
2226       const signal = this.combinedSignal(ac);
2227       const pointerup = e => {
2228         if (e.type === "pointerup" && e.button !== 0) {
2229           return;
2230         }
2231         ac.abort();
2232         activeLayer?.toggleDrawing(true);
2233         if (e.type === "pointerup") {
2234           this.#onSelectEnd("main_toolbar");
2235         }
2236       };
2237       window.addEventListener("pointerup", pointerup, {
2238         signal
2239       });
2240       window.addEventListener("blur", pointerup, {
2241         signal
2242       });
2243     }
2244   }
2245   #onSelectEnd(methodOfCreation = "") {
2246     if (this.#mode === AnnotationEditorType.HIGHLIGHT) {
2247       this.highlightSelection(methodOfCreation);
2248     } else if (this.#enableHighlightFloatingButton) {
2249       this.#displayHighlightToolbar();
2250     }
2251   }
2252   #addSelectionListener() {
2253     document.addEventListener("selectionchange", this.#selectionChange.bind(this), {
2254       signal: this._signal
2255     });
2256   }
2257   #addFocusManager() {
2258     if (this.#focusManagerAC) {
2259       return;
2260     }
2261     this.#focusManagerAC = new AbortController();
2262     const signal = this.combinedSignal(this.#focusManagerAC);
2263     window.addEventListener("focus", this.focus.bind(this), {
2264       signal
2265     });
2266     window.addEventListener("blur", this.blur.bind(this), {
2267       signal
2268     });
2269   }
2270   #removeFocusManager() {
2271     this.#focusManagerAC?.abort();
2272     this.#focusManagerAC = null;
2273   }
2274   blur() {
2275     this.isShiftKeyDown = false;
2276     if (this.#highlightWhenShiftUp) {
2277       this.#highlightWhenShiftUp = false;
2278       this.#onSelectEnd("main_toolbar");
2279     }
2280     if (!this.hasSelection) {
2281       return;
2282     }
2283     const {
2284       activeElement
2285     } = document;
2286     for (const editor of this.#selectedEditors) {
2287       if (editor.div.contains(activeElement)) {
2288         this.#lastActiveElement = [editor, activeElement];
2289         editor._focusEventsAllowed = false;
2290         break;
2291       }
2292     }
2293   }
2294   focus() {
2295     if (!this.#lastActiveElement) {
2296       return;
2297     }
2298     const [lastEditor, lastActiveElement] = this.#lastActiveElement;
2299     this.#lastActiveElement = null;
2300     lastActiveElement.addEventListener("focusin", () => {
2301       lastEditor._focusEventsAllowed = true;
2302     }, {
2303       once: true,
2304       signal: this._signal
2305     });
2306     lastActiveElement.focus();
2307   }
2308   #addKeyboardManager() {
2309     if (this.#keyboardManagerAC) {
2310       return;
2311     }
2312     this.#keyboardManagerAC = new AbortController();
2313     const signal = this.combinedSignal(this.#keyboardManagerAC);
2314     window.addEventListener("keydown", this.keydown.bind(this), {
2315       signal
2316     });
2317     window.addEventListener("keyup", this.keyup.bind(this), {
2318       signal
2319     });
2320   }
2321   #removeKeyboardManager() {
2322     this.#keyboardManagerAC?.abort();
2323     this.#keyboardManagerAC = null;
2324   }
2325   #addCopyPasteListeners() {
2326     if (this.#copyPasteAC) {
2327       return;
2328     }
2329     this.#copyPasteAC = new AbortController();
2330     const signal = this.combinedSignal(this.#copyPasteAC);
2331     document.addEventListener("copy", this.copy.bind(this), {
2332       signal
2333     });
2334     document.addEventListener("cut", this.cut.bind(this), {
2335       signal
2336     });
2337     document.addEventListener("paste", this.paste.bind(this), {
2338       signal
2339     });
2340   }
2341   #removeCopyPasteListeners() {
2342     this.#copyPasteAC?.abort();
2343     this.#copyPasteAC = null;
2344   }
2345   #addDragAndDropListeners() {
2346     const signal = this._signal;
2347     document.addEventListener("dragover", this.dragOver.bind(this), {
2348       signal
2349     });
2350     document.addEventListener("drop", this.drop.bind(this), {
2351       signal
2352     });
2353   }
2354   addEditListeners() {
2355     this.#addKeyboardManager();
2356     this.#addCopyPasteListeners();
2357   }
2358   removeEditListeners() {
2359     this.#removeKeyboardManager();
2360     this.#removeCopyPasteListeners();
2361   }
2362   dragOver(event) {
2363     for (const {
2364       type
2365     } of event.dataTransfer.items) {
2366       for (const editorType of this.#editorTypes) {
2367         if (editorType.isHandlingMimeForPasting(type)) {
2368           event.dataTransfer.dropEffect = "copy";
2369           event.preventDefault();
2370           return;
2371         }
2372       }
2373     }
2374   }
2375   drop(event) {
2376     for (const item of event.dataTransfer.items) {
2377       for (const editorType of this.#editorTypes) {
2378         if (editorType.isHandlingMimeForPasting(item.type)) {
2379           editorType.paste(item, this.currentLayer);
2380           event.preventDefault();
2381           return;
2382         }
2383       }
2384     }
2385   }
2386   copy(event) {
2387     event.preventDefault();
2388     this.#activeEditor?.commitOrRemove();
2389     if (!this.hasSelection) {
2390       return;
2391     }
2392     const editors = [];
2393     for (const editor of this.#selectedEditors) {
2394       const serialized = editor.serialize(true);
2395       if (serialized) {
2396         editors.push(serialized);
2397       }
2398     }
2399     if (editors.length === 0) {
2400       return;
2401     }
2402     event.clipboardData.setData("application/pdfjs", JSON.stringify(editors));
2403   }
2404   cut(event) {
2405     this.copy(event);
2406     this.delete();
2407   }
2408   async paste(event) {
2409     event.preventDefault();
2410     const {
2411       clipboardData
2412     } = event;
2413     for (const item of clipboardData.items) {
2414       for (const editorType of this.#editorTypes) {
2415         if (editorType.isHandlingMimeForPasting(item.type)) {
2416           editorType.paste(item, this.currentLayer);
2417           return;
2418         }
2419       }
2420     }
2421     let data = clipboardData.getData("application/pdfjs");
2422     if (!data) {
2423       return;
2424     }
2425     try {
2426       data = JSON.parse(data);
2427     } catch (ex) {
2428       warn(`paste: "${ex.message}".`);
2429       return;
2430     }
2431     if (!Array.isArray(data)) {
2432       return;
2433     }
2434     this.unselectAll();
2435     const layer = this.currentLayer;
2436     try {
2437       const newEditors = [];
2438       for (const editor of data) {
2439         const deserializedEditor = await layer.deserialize(editor);
2440         if (!deserializedEditor) {
2441           return;
2442         }
2443         newEditors.push(deserializedEditor);
2444       }
2445       const cmd = () => {
2446         for (const editor of newEditors) {
2447           this.#addEditorToLayer(editor);
2448         }
2449         this.#selectEditors(newEditors);
2450       };
2451       const undo = () => {
2452         for (const editor of newEditors) {
2453           editor.remove();
2454         }
2455       };
2456       this.addCommands({
2457         cmd,
2458         undo,
2459         mustExec: true
2460       });
2461     } catch (ex) {
2462       warn(`paste: "${ex.message}".`);
2463     }
2464   }
2465   keydown(event) {
2466     if (!this.isShiftKeyDown && event.key === "Shift") {
2467       this.isShiftKeyDown = true;
2468     }
2469     if (this.#mode !== AnnotationEditorType.NONE && !this.isEditorHandlingKeyboard) {
2470       AnnotationEditorUIManager._keyboardManager.exec(this, event);
2471     }
2472   }
2473   keyup(event) {
2474     if (this.isShiftKeyDown && event.key === "Shift") {
2475       this.isShiftKeyDown = false;
2476       if (this.#highlightWhenShiftUp) {
2477         this.#highlightWhenShiftUp = false;
2478         this.#onSelectEnd("main_toolbar");
2479       }
2480     }
2481   }
2482   onEditingAction({
2483     name
2484   }) {
2485     switch (name) {
2486       case "undo":
2487       case "redo":
2488       case "delete":
2489       case "selectAll":
2490         this[name]();
2491         break;
2492       case "highlightSelection":
2493         this.highlightSelection("context_menu");
2494         break;
2495     }
2496   }
2497   #dispatchUpdateStates(details) {
2498     const hasChanged = Object.entries(details).some(([key, value]) => this.#previousStates[key] !== value);
2499     if (hasChanged) {
2500       this._eventBus.dispatch("annotationeditorstateschanged", {
2501         source: this,
2502         details: Object.assign(this.#previousStates, details)
2503       });
2504       if (this.#mode === AnnotationEditorType.HIGHLIGHT && details.hasSelectedEditor === false) {
2505         this.#dispatchUpdateUI([[AnnotationEditorParamsType.HIGHLIGHT_FREE, true]]);
2506       }
2507     }
2508   }
2509   #dispatchUpdateUI(details) {
2510     this._eventBus.dispatch("annotationeditorparamschanged", {
2511       source: this,
2512       details
2513     });
2514   }
2515   setEditingState(isEditing) {
2516     if (isEditing) {
2517       this.#addFocusManager();
2518       this.#addCopyPasteListeners();
2519       this.#dispatchUpdateStates({
2520         isEditing: this.#mode !== AnnotationEditorType.NONE,
2521         isEmpty: this.#isEmpty(),
2522         hasSomethingToUndo: this.#commandManager.hasSomethingToUndo(),
2523         hasSomethingToRedo: this.#commandManager.hasSomethingToRedo(),
2524         hasSelectedEditor: false
2525       });
2526     } else {
2527       this.#removeFocusManager();
2528       this.#removeCopyPasteListeners();
2529       this.#dispatchUpdateStates({
2530         isEditing: false
2531       });
2532       this.disableUserSelect(false);
2533     }
2534   }
2535   registerEditorTypes(types) {
2536     if (this.#editorTypes) {
2537       return;
2538     }
2539     this.#editorTypes = types;
2540     for (const editorType of this.#editorTypes) {
2541       this.#dispatchUpdateUI(editorType.defaultPropertiesToUpdate);
2542     }
2543   }
2544   getId() {
2545     return this.#idManager.id;
2546   }
2547   get currentLayer() {
2548     return this.#allLayers.get(this.#currentPageIndex);
2549   }
2550   getLayer(pageIndex) {
2551     return this.#allLayers.get(pageIndex);
2552   }
2553   get currentPageIndex() {
2554     return this.#currentPageIndex;
2555   }
2556   addLayer(layer) {
2557     this.#allLayers.set(layer.pageIndex, layer);
2558     if (this.#isEnabled) {
2559       layer.enable();
2560     } else {
2561       layer.disable();
2562     }
2563   }
2564   removeLayer(layer) {
2565     this.#allLayers.delete(layer.pageIndex);
2566   }
2567   async updateMode(mode, editId = null, isFromKeyboard = false) {
2568     if (this.#mode === mode) {
2569       return;
2570     }
2571     if (this.#updateModeCapability) {
2572       await this.#updateModeCapability.promise;
2573       if (!this.#updateModeCapability) {
2574         return;
2575       }
2576     }
2577     this.#updateModeCapability = Promise.withResolvers();
2578     this.#mode = mode;
2579     if (mode === AnnotationEditorType.NONE) {
2580       this.setEditingState(false);
2581       this.#disableAll();
2582       this._editorUndoBar?.hide();
2583       this.#updateModeCapability.resolve();
2584       return;
2585     }
2586     this.setEditingState(true);
2587     await this.#enableAll();
2588     this.unselectAll();
2589     for (const layer of this.#allLayers.values()) {
2590       layer.updateMode(mode);
2591     }
2592     if (!editId) {
2593       if (isFromKeyboard) {
2594         this.addNewEditorFromKeyboard();
2595       }
2596       this.#updateModeCapability.resolve();
2597       return;
2598     }
2599     for (const editor of this.#allEditors.values()) {
2600       if (editor.annotationElementId === editId) {
2601         this.setSelected(editor);
2602         editor.enterInEditMode();
2603       } else {
2604         editor.unselect();
2605       }
2606     }
2607     this.#updateModeCapability.resolve();
2608   }
2609   addNewEditorFromKeyboard() {
2610     if (this.currentLayer.canCreateNewEmptyEditor()) {
2611       this.currentLayer.addNewEditor();
2612     }
2613   }
2614   updateToolbar(mode) {
2615     if (mode === this.#mode) {
2616       return;
2617     }
2618     this._eventBus.dispatch("switchannotationeditormode", {
2619       source: this,
2620       mode
2621     });
2622   }
2623   updateParams(type, value) {
2624     if (!this.#editorTypes) {
2625       return;
2626     }
2627     switch (type) {
2628       case AnnotationEditorParamsType.CREATE:
2629         this.currentLayer.addNewEditor();
2630         return;
2631       case AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR:
2632         this.#mainHighlightColorPicker?.updateColor(value);
2633         break;
2634       case AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL:
2635         this._eventBus.dispatch("reporttelemetry", {
2636           source: this,
2637           details: {
2638             type: "editing",
2639             data: {
2640               type: "highlight",
2641               action: "toggle_visibility"
2642             }
2643           }
2644         });
2645         (this.#showAllStates ||= new Map()).set(type, value);
2646         this.showAllEditors("highlight", value);
2647         break;
2648     }
2649     for (const editor of this.#selectedEditors) {
2650       editor.updateParams(type, value);
2651     }
2652     for (const editorType of this.#editorTypes) {
2653       editorType.updateDefaultParams(type, value);
2654     }
2655   }
2656   showAllEditors(type, visible, updateButton = false) {
2657     for (const editor of this.#allEditors.values()) {
2658       if (editor.editorType === type) {
2659         editor.show(visible);
2660       }
2661     }
2662     const state = this.#showAllStates?.get(AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL) ?? true;
2663     if (state !== visible) {
2664       this.#dispatchUpdateUI([[AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL, visible]]);
2665     }
2666   }
2667   enableWaiting(mustWait = false) {
2668     if (this.#isWaiting === mustWait) {
2669       return;
2670     }
2671     this.#isWaiting = mustWait;
2672     for (const layer of this.#allLayers.values()) {
2673       if (mustWait) {
2674         layer.disableClick();
2675       } else {
2676         layer.enableClick();
2677       }
2678       layer.div.classList.toggle("waiting", mustWait);
2679     }
2680   }
2681   async #enableAll() {
2682     if (!this.#isEnabled) {
2683       this.#isEnabled = true;
2684       const promises = [];
2685       for (const layer of this.#allLayers.values()) {
2686         promises.push(layer.enable());
2687       }
2688       await Promise.all(promises);
2689       for (const editor of this.#allEditors.values()) {
2690         editor.enable();
2691       }
2692     }
2693   }
2694   #disableAll() {
2695     this.unselectAll();
2696     if (this.#isEnabled) {
2697       this.#isEnabled = false;
2698       for (const layer of this.#allLayers.values()) {
2699         layer.disable();
2700       }
2701       for (const editor of this.#allEditors.values()) {
2702         editor.disable();
2703       }
2704     }
2705   }
2706   getEditors(pageIndex) {
2707     const editors = [];
2708     for (const editor of this.#allEditors.values()) {
2709       if (editor.pageIndex === pageIndex) {
2710         editors.push(editor);
2711       }
2712     }
2713     return editors;
2714   }
2715   getEditor(id) {
2716     return this.#allEditors.get(id);
2717   }
2718   addEditor(editor) {
2719     this.#allEditors.set(editor.id, editor);
2720   }
2721   removeEditor(editor) {
2722     if (editor.div.contains(document.activeElement)) {
2723       if (this.#focusMainContainerTimeoutId) {
2724         clearTimeout(this.#focusMainContainerTimeoutId);
2725       }
2726       this.#focusMainContainerTimeoutId = setTimeout(() => {
2727         this.focusMainContainer();
2728         this.#focusMainContainerTimeoutId = null;
2729       }, 0);
2730     }
2731     this.#allEditors.delete(editor.id);
2732     if (editor.annotationElementId) {
2733       this.#missingCanvases?.delete(editor.annotationElementId);
2734     }
2735     this.unselect(editor);
2736     if (!editor.annotationElementId || !this.#deletedAnnotationsElementIds.has(editor.annotationElementId)) {
2737       this.#annotationStorage?.remove(editor.id);
2738     }
2739   }
2740   addDeletedAnnotationElement(editor) {
2741     this.#deletedAnnotationsElementIds.add(editor.annotationElementId);
2742     this.addChangedExistingAnnotation(editor);
2743     editor.deleted = true;
2744   }
2745   isDeletedAnnotationElement(annotationElementId) {
2746     return this.#deletedAnnotationsElementIds.has(annotationElementId);
2747   }
2748   removeDeletedAnnotationElement(editor) {
2749     this.#deletedAnnotationsElementIds.delete(editor.annotationElementId);
2750     this.removeChangedExistingAnnotation(editor);
2751     editor.deleted = false;
2752   }
2753   #addEditorToLayer(editor) {
2754     const layer = this.#allLayers.get(editor.pageIndex);
2755     if (layer) {
2756       layer.addOrRebuild(editor);
2757     } else {
2758       this.addEditor(editor);
2759       this.addToAnnotationStorage(editor);
2760     }
2761   }
2762   setActiveEditor(editor) {
2763     if (this.#activeEditor === editor) {
2764       return;
2765     }
2766     this.#activeEditor = editor;
2767     if (editor) {
2768       this.#dispatchUpdateUI(editor.propertiesToUpdate);
2769     }
2770   }
2771   get #lastSelectedEditor() {
2772     let ed = null;
2773     for (ed of this.#selectedEditors) {}
2774     return ed;
2775   }
2776   updateUI(editor) {
2777     if (this.#lastSelectedEditor === editor) {
2778       this.#dispatchUpdateUI(editor.propertiesToUpdate);
2779     }
2780   }
2781   updateUIForDefaultProperties(editorType) {
2782     this.#dispatchUpdateUI(editorType.defaultPropertiesToUpdate);
2783   }
2784   toggleSelected(editor) {
2785     if (this.#selectedEditors.has(editor)) {
2786       this.#selectedEditors.delete(editor);
2787       editor.unselect();
2788       this.#dispatchUpdateStates({
2789         hasSelectedEditor: this.hasSelection
2790       });
2791       return;
2792     }
2793     this.#selectedEditors.add(editor);
2794     editor.select();
2795     this.#dispatchUpdateUI(editor.propertiesToUpdate);
2796     this.#dispatchUpdateStates({
2797       hasSelectedEditor: true
2798     });
2799   }
2800   setSelected(editor) {
2801     this.#currentDrawingSession?.commitOrRemove();
2802     for (const ed of this.#selectedEditors) {
2803       if (ed !== editor) {
2804         ed.unselect();
2805       }
2806     }
2807     this.#selectedEditors.clear();
2808     this.#selectedEditors.add(editor);
2809     editor.select();
2810     this.#dispatchUpdateUI(editor.propertiesToUpdate);
2811     this.#dispatchUpdateStates({
2812       hasSelectedEditor: true
2813     });
2814   }
2815   isSelected(editor) {
2816     return this.#selectedEditors.has(editor);
2817   }
2818   get firstSelectedEditor() {
2819     return this.#selectedEditors.values().next().value;
2820   }
2821   unselect(editor) {
2822     editor.unselect();
2823     this.#selectedEditors.delete(editor);
2824     this.#dispatchUpdateStates({
2825       hasSelectedEditor: this.hasSelection
2826     });
2827   }
2828   get hasSelection() {
2829     return this.#selectedEditors.size !== 0;
2830   }
2831   get isEnterHandled() {
2832     return this.#selectedEditors.size === 1 && this.firstSelectedEditor.isEnterHandled;
2833   }
2834   undo() {
2835     this.#commandManager.undo();
2836     this.#dispatchUpdateStates({
2837       hasSomethingToUndo: this.#commandManager.hasSomethingToUndo(),
2838       hasSomethingToRedo: true,
2839       isEmpty: this.#isEmpty()
2840     });
2841     this._editorUndoBar?.hide();
2842   }
2843   redo() {
2844     this.#commandManager.redo();
2845     this.#dispatchUpdateStates({
2846       hasSomethingToUndo: true,
2847       hasSomethingToRedo: this.#commandManager.hasSomethingToRedo(),
2848       isEmpty: this.#isEmpty()
2849     });
2850   }
2851   addCommands(params) {
2852     this.#commandManager.add(params);
2853     this.#dispatchUpdateStates({
2854       hasSomethingToUndo: true,
2855       hasSomethingToRedo: false,
2856       isEmpty: this.#isEmpty()
2857     });
2858   }
2859   cleanUndoStack(type) {
2860     this.#commandManager.cleanType(type);
2861   }
2862   #isEmpty() {
2863     if (this.#allEditors.size === 0) {
2864       return true;
2865     }
2866     if (this.#allEditors.size === 1) {
2867       for (const editor of this.#allEditors.values()) {
2868         return editor.isEmpty();
2869       }
2870     }
2871     return false;
2872   }
2873   delete() {
2874     this.commitOrRemove();
2875     const drawingEditor = this.currentLayer?.endDrawingSession(true);
2876     if (!this.hasSelection && !drawingEditor) {
2877       return;
2878     }
2879     const editors = drawingEditor ? [drawingEditor] : [...this.#selectedEditors];
2880     const cmd = () => {
2881       this._editorUndoBar?.show(undo, editors.length === 1 ? editors[0].editorType : editors.length);
2882       for (const editor of editors) {
2883         editor.remove();
2884       }
2885     };
2886     const undo = () => {
2887       for (const editor of editors) {
2888         this.#addEditorToLayer(editor);
2889       }
2890     };
2891     this.addCommands({
2892       cmd,
2893       undo,
2894       mustExec: true
2895     });
2896   }
2897   commitOrRemove() {
2898     this.#activeEditor?.commitOrRemove();
2899   }
2900   hasSomethingToControl() {
2901     return this.#activeEditor || this.hasSelection;
2902   }
2903   #selectEditors(editors) {
2904     for (const editor of this.#selectedEditors) {
2905       editor.unselect();
2906     }
2907     this.#selectedEditors.clear();
2908     for (const editor of editors) {
2909       if (editor.isEmpty()) {
2910         continue;
2911       }
2912       this.#selectedEditors.add(editor);
2913       editor.select();
2914     }
2915     this.#dispatchUpdateStates({
2916       hasSelectedEditor: this.hasSelection
2917     });
2918   }
2919   selectAll() {
2920     for (const editor of this.#selectedEditors) {
2921       editor.commit();
2922     }
2923     this.#selectEditors(this.#allEditors.values());
2924   }
2925   unselectAll() {
2926     if (this.#activeEditor) {
2927       this.#activeEditor.commitOrRemove();
2928       if (this.#mode !== AnnotationEditorType.NONE) {
2929         return;
2930       }
2931     }
2932     if (this.#currentDrawingSession?.commitOrRemove()) {
2933       return;
2934     }
2935     if (!this.hasSelection) {
2936       return;
2937     }
2938     for (const editor of this.#selectedEditors) {
2939       editor.unselect();
2940     }
2941     this.#selectedEditors.clear();
2942     this.#dispatchUpdateStates({
2943       hasSelectedEditor: false
2944     });
2945   }
2946   translateSelectedEditors(x, y, noCommit = false) {
2947     if (!noCommit) {
2948       this.commitOrRemove();
2949     }
2950     if (!this.hasSelection) {
2951       return;
2952     }
2953     this.#translation[0] += x;
2954     this.#translation[1] += y;
2955     const [totalX, totalY] = this.#translation;
2956     const editors = [...this.#selectedEditors];
2957     const TIME_TO_WAIT = 1000;
2958     if (this.#translationTimeoutId) {
2959       clearTimeout(this.#translationTimeoutId);
2960     }
2961     this.#translationTimeoutId = setTimeout(() => {
2962       this.#translationTimeoutId = null;
2963       this.#translation[0] = this.#translation[1] = 0;
2964       this.addCommands({
2965         cmd: () => {
2966           for (const editor of editors) {
2967             if (this.#allEditors.has(editor.id)) {
2968               editor.translateInPage(totalX, totalY);
2969             }
2970           }
2971         },
2972         undo: () => {
2973           for (const editor of editors) {
2974             if (this.#allEditors.has(editor.id)) {
2975               editor.translateInPage(-totalX, -totalY);
2976             }
2977           }
2978         },
2979         mustExec: false
2980       });
2981     }, TIME_TO_WAIT);
2982     for (const editor of editors) {
2983       editor.translateInPage(x, y);
2984     }
2985   }
2986   setUpDragSession() {
2987     if (!this.hasSelection) {
2988       return;
2989     }
2990     this.disableUserSelect(true);
2991     this.#draggingEditors = new Map();
2992     for (const editor of this.#selectedEditors) {
2993       this.#draggingEditors.set(editor, {
2994         savedX: editor.x,
2995         savedY: editor.y,
2996         savedPageIndex: editor.pageIndex,
2997         newX: 0,
2998         newY: 0,
2999         newPageIndex: -1
3000       });
3001     }
3002   }
3003   endDragSession() {
3004     if (!this.#draggingEditors) {
3005       return false;
3006     }
3007     this.disableUserSelect(false);
3008     const map = this.#draggingEditors;
3009     this.#draggingEditors = null;
3010     let mustBeAddedInUndoStack = false;
3011     for (const [{
3012       x,
3013       y,
3014       pageIndex
3015     }, value] of map) {
3016       value.newX = x;
3017       value.newY = y;
3018       value.newPageIndex = pageIndex;
3019       mustBeAddedInUndoStack ||= x !== value.savedX || y !== value.savedY || pageIndex !== value.savedPageIndex;
3020     }
3021     if (!mustBeAddedInUndoStack) {
3022       return false;
3023     }
3024     const move = (editor, x, y, pageIndex) => {
3025       if (this.#allEditors.has(editor.id)) {
3026         const parent = this.#allLayers.get(pageIndex);
3027         if (parent) {
3028           editor._setParentAndPosition(parent, x, y);
3029         } else {
3030           editor.pageIndex = pageIndex;
3031           editor.x = x;
3032           editor.y = y;
3033         }
3034       }
3035     };
3036     this.addCommands({
3037       cmd: () => {
3038         for (const [editor, {
3039           newX,
3040           newY,
3041           newPageIndex
3042         }] of map) {
3043           move(editor, newX, newY, newPageIndex);
3044         }
3045       },
3046       undo: () => {
3047         for (const [editor, {
3048           savedX,
3049           savedY,
3050           savedPageIndex
3051         }] of map) {
3052           move(editor, savedX, savedY, savedPageIndex);
3053         }
3054       },
3055       mustExec: true
3056     });
3057     return true;
3058   }
3059   dragSelectedEditors(tx, ty) {
3060     if (!this.#draggingEditors) {
3061       return;
3062     }
3063     for (const editor of this.#draggingEditors.keys()) {
3064       editor.drag(tx, ty);
3065     }
3066   }
3067   rebuild(editor) {
3068     if (editor.parent === null) {
3069       const parent = this.getLayer(editor.pageIndex);
3070       if (parent) {
3071         parent.changeParent(editor);
3072         parent.addOrRebuild(editor);
3073       } else {
3074         this.addEditor(editor);
3075         this.addToAnnotationStorage(editor);
3076         editor.rebuild();
3077       }
3078     } else {
3079       editor.parent.addOrRebuild(editor);
3080     }
3081   }
3082   get isEditorHandlingKeyboard() {
3083     return this.getActive()?.shouldGetKeyboardEvents() || this.#selectedEditors.size === 1 && this.firstSelectedEditor.shouldGetKeyboardEvents();
3084   }
3085   isActive(editor) {
3086     return this.#activeEditor === editor;
3087   }
3088   getActive() {
3089     return this.#activeEditor;
3090   }
3091   getMode() {
3092     return this.#mode;
3093   }
3094   get imageManager() {
3095     return shadow(this, "imageManager", new ImageManager());
3096   }
3097   getSelectionBoxes(textLayer) {
3098     if (!textLayer) {
3099       return null;
3100     }
3101     const selection = document.getSelection();
3102     for (let i = 0, ii = selection.rangeCount; i < ii; i++) {
3103       if (!textLayer.contains(selection.getRangeAt(i).commonAncestorContainer)) {
3104         return null;
3105       }
3106     }
3107     const {
3108       x: layerX,
3109       y: layerY,
3110       width: parentWidth,
3111       height: parentHeight
3112     } = textLayer.getBoundingClientRect();
3113     let rotator;
3114     switch (textLayer.getAttribute("data-main-rotation")) {
3115       case "90":
3116         rotator = (x, y, w, h) => ({
3117           x: (y - layerY) / parentHeight,
3118           y: 1 - (x + w - layerX) / parentWidth,
3119           width: h / parentHeight,
3120           height: w / parentWidth
3121         });
3122         break;
3123       case "180":
3124         rotator = (x, y, w, h) => ({
3125           x: 1 - (x + w - layerX) / parentWidth,
3126           y: 1 - (y + h - layerY) / parentHeight,
3127           width: w / parentWidth,
3128           height: h / parentHeight
3129         });
3130         break;
3131       case "270":
3132         rotator = (x, y, w, h) => ({
3133           x: 1 - (y + h - layerY) / parentHeight,
3134           y: (x - layerX) / parentWidth,
3135           width: h / parentHeight,
3136           height: w / parentWidth
3137         });
3138         break;
3139       default:
3140         rotator = (x, y, w, h) => ({
3141           x: (x - layerX) / parentWidth,
3142           y: (y - layerY) / parentHeight,
3143           width: w / parentWidth,
3144           height: h / parentHeight
3145         });
3146         break;
3147     }
3148     const boxes = [];
3149     for (let i = 0, ii = selection.rangeCount; i < ii; i++) {
3150       const range = selection.getRangeAt(i);
3151       if (range.collapsed) {
3152         continue;
3153       }
3154       for (const {
3155         x,
3156         y,
3157         width,
3158         height
3159       } of range.getClientRects()) {
3160         if (width === 0 || height === 0) {
3161           continue;
3162         }
3163         boxes.push(rotator(x, y, width, height));
3164       }
3165     }
3166     return boxes.length === 0 ? null : boxes;
3167   }
3168   addChangedExistingAnnotation({
3169     annotationElementId,
3170     id
3171   }) {
3172     (this.#changedExistingAnnotations ||= new Map()).set(annotationElementId, id);
3173   }
3174   removeChangedExistingAnnotation({
3175     annotationElementId
3176   }) {
3177     this.#changedExistingAnnotations?.delete(annotationElementId);
3178   }
3179   renderAnnotationElement(annotation) {
3180     const editorId = this.#changedExistingAnnotations?.get(annotation.data.id);
3181     if (!editorId) {
3182       return;
3183     }
3184     const editor = this.#annotationStorage.getRawValue(editorId);
3185     if (!editor) {
3186       return;
3187     }
3188     if (this.#mode === AnnotationEditorType.NONE && !editor.hasBeenModified) {
3189       return;
3190     }
3191     editor.renderAnnotationElement(annotation);
3192   }
3193   setMissingCanvas(annotationId, annotationElementId, canvas) {
3194     const editor = this.#missingCanvases?.get(annotationId);
3195     if (!editor) {
3196       return;
3197     }
3198     editor.setCanvas(annotationElementId, canvas);
3199     this.#missingCanvases.delete(annotationId);
3200   }
3201   addMissingCanvas(annotationId, editor) {
3202     (this.#missingCanvases ||= new Map()).set(annotationId, editor);
3203   }
3206 ;// ./src/display/editor/alt_text.js
3208 class AltText {
3209   #altText = null;
3210   #altTextDecorative = false;
3211   #altTextButton = null;
3212   #altTextButtonLabel = null;
3213   #altTextTooltip = null;
3214   #altTextTooltipTimeout = null;
3215   #altTextWasFromKeyBoard = false;
3216   #badge = null;
3217   #editor = null;
3218   #guessedText = null;
3219   #textWithDisclaimer = null;
3220   #useNewAltTextFlow = false;
3221   static #l10nNewButton = null;
3222   static _l10n = null;
3223   constructor(editor) {
3224     this.#editor = editor;
3225     this.#useNewAltTextFlow = editor._uiManager.useNewAltTextFlow;
3226     AltText.#l10nNewButton ||= Object.freeze({
3227       added: "pdfjs-editor-new-alt-text-added-button",
3228       "added-label": "pdfjs-editor-new-alt-text-added-button-label",
3229       missing: "pdfjs-editor-new-alt-text-missing-button",
3230       "missing-label": "pdfjs-editor-new-alt-text-missing-button-label",
3231       review: "pdfjs-editor-new-alt-text-to-review-button",
3232       "review-label": "pdfjs-editor-new-alt-text-to-review-button-label"
3233     });
3234   }
3235   static initialize(l10n) {
3236     AltText._l10n ??= l10n;
3237   }
3238   async render() {
3239     const altText = this.#altTextButton = document.createElement("button");
3240     altText.className = "altText";
3241     altText.tabIndex = "0";
3242     const label = this.#altTextButtonLabel = document.createElement("span");
3243     altText.append(label);
3244     if (this.#useNewAltTextFlow) {
3245       altText.classList.add("new");
3246       altText.setAttribute("data-l10n-id", AltText.#l10nNewButton.missing);
3247       label.setAttribute("data-l10n-id", AltText.#l10nNewButton["missing-label"]);
3248     } else {
3249       altText.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-button");
3250       label.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-button-label");
3251     }
3252     const signal = this.#editor._uiManager._signal;
3253     altText.addEventListener("contextmenu", noContextMenu, {
3254       signal
3255     });
3256     altText.addEventListener("pointerdown", event => event.stopPropagation(), {
3257       signal
3258     });
3259     const onClick = event => {
3260       event.preventDefault();
3261       this.#editor._uiManager.editAltText(this.#editor);
3262       if (this.#useNewAltTextFlow) {
3263         this.#editor._reportTelemetry({
3264           action: "pdfjs.image.alt_text.image_status_label_clicked",
3265           data: {
3266             label: this.#label
3267           }
3268         });
3269       }
3270     };
3271     altText.addEventListener("click", onClick, {
3272       capture: true,
3273       signal
3274     });
3275     altText.addEventListener("keydown", event => {
3276       if (event.target === altText && event.key === "Enter") {
3277         this.#altTextWasFromKeyBoard = true;
3278         onClick(event);
3279       }
3280     }, {
3281       signal
3282     });
3283     await this.#setState();
3284     return altText;
3285   }
3286   get #label() {
3287     return this.#altText && "added" || this.#altText === null && this.guessedText && "review" || "missing";
3288   }
3289   finish() {
3290     if (!this.#altTextButton) {
3291       return;
3292     }
3293     this.#altTextButton.focus({
3294       focusVisible: this.#altTextWasFromKeyBoard
3295     });
3296     this.#altTextWasFromKeyBoard = false;
3297   }
3298   isEmpty() {
3299     if (this.#useNewAltTextFlow) {
3300       return this.#altText === null;
3301     }
3302     return !this.#altText && !this.#altTextDecorative;
3303   }
3304   hasData() {
3305     if (this.#useNewAltTextFlow) {
3306       return this.#altText !== null || !!this.#guessedText;
3307     }
3308     return this.isEmpty();
3309   }
3310   get guessedText() {
3311     return this.#guessedText;
3312   }
3313   async setGuessedText(guessedText) {
3314     if (this.#altText !== null) {
3315       return;
3316     }
3317     this.#guessedText = guessedText;
3318     this.#textWithDisclaimer = await AltText._l10n.get("pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer", {
3319       generatedAltText: guessedText
3320     });
3321     this.#setState();
3322   }
3323   toggleAltTextBadge(visibility = false) {
3324     if (!this.#useNewAltTextFlow || this.#altText) {
3325       this.#badge?.remove();
3326       this.#badge = null;
3327       return;
3328     }
3329     if (!this.#badge) {
3330       const badge = this.#badge = document.createElement("div");
3331       badge.className = "noAltTextBadge";
3332       this.#editor.div.append(badge);
3333     }
3334     this.#badge.classList.toggle("hidden", !visibility);
3335   }
3336   serialize(isForCopying) {
3337     let altText = this.#altText;
3338     if (!isForCopying && this.#guessedText === altText) {
3339       altText = this.#textWithDisclaimer;
3340     }
3341     return {
3342       altText,
3343       decorative: this.#altTextDecorative,
3344       guessedText: this.#guessedText,
3345       textWithDisclaimer: this.#textWithDisclaimer
3346     };
3347   }
3348   get data() {
3349     return {
3350       altText: this.#altText,
3351       decorative: this.#altTextDecorative
3352     };
3353   }
3354   set data({
3355     altText,
3356     decorative,
3357     guessedText,
3358     textWithDisclaimer,
3359     cancel = false
3360   }) {
3361     if (guessedText) {
3362       this.#guessedText = guessedText;
3363       this.#textWithDisclaimer = textWithDisclaimer;
3364     }
3365     if (this.#altText === altText && this.#altTextDecorative === decorative) {
3366       return;
3367     }
3368     if (!cancel) {
3369       this.#altText = altText;
3370       this.#altTextDecorative = decorative;
3371     }
3372     this.#setState();
3373   }
3374   toggle(enabled = false) {
3375     if (!this.#altTextButton) {
3376       return;
3377     }
3378     if (!enabled && this.#altTextTooltipTimeout) {
3379       clearTimeout(this.#altTextTooltipTimeout);
3380       this.#altTextTooltipTimeout = null;
3381     }
3382     this.#altTextButton.disabled = !enabled;
3383   }
3384   shown() {
3385     this.#editor._reportTelemetry({
3386       action: "pdfjs.image.alt_text.image_status_label_displayed",
3387       data: {
3388         label: this.#label
3389       }
3390     });
3391   }
3392   destroy() {
3393     this.#altTextButton?.remove();
3394     this.#altTextButton = null;
3395     this.#altTextButtonLabel = null;
3396     this.#altTextTooltip = null;
3397     this.#badge?.remove();
3398     this.#badge = null;
3399   }
3400   async #setState() {
3401     const button = this.#altTextButton;
3402     if (!button) {
3403       return;
3404     }
3405     if (this.#useNewAltTextFlow) {
3406       button.classList.toggle("done", !!this.#altText);
3407       button.setAttribute("data-l10n-id", AltText.#l10nNewButton[this.#label]);
3408       this.#altTextButtonLabel?.setAttribute("data-l10n-id", AltText.#l10nNewButton[`${this.#label}-label`]);
3409       if (!this.#altText) {
3410         this.#altTextTooltip?.remove();
3411         return;
3412       }
3413     } else {
3414       if (!this.#altText && !this.#altTextDecorative) {
3415         button.classList.remove("done");
3416         this.#altTextTooltip?.remove();
3417         return;
3418       }
3419       button.classList.add("done");
3420       button.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-edit-button");
3421     }
3422     let tooltip = this.#altTextTooltip;
3423     if (!tooltip) {
3424       this.#altTextTooltip = tooltip = document.createElement("span");
3425       tooltip.className = "tooltip";
3426       tooltip.setAttribute("role", "tooltip");
3427       tooltip.id = `alt-text-tooltip-${this.#editor.id}`;
3428       const DELAY_TO_SHOW_TOOLTIP = 100;
3429       const signal = this.#editor._uiManager._signal;
3430       signal.addEventListener("abort", () => {
3431         clearTimeout(this.#altTextTooltipTimeout);
3432         this.#altTextTooltipTimeout = null;
3433       }, {
3434         once: true
3435       });
3436       button.addEventListener("mouseenter", () => {
3437         this.#altTextTooltipTimeout = setTimeout(() => {
3438           this.#altTextTooltipTimeout = null;
3439           this.#altTextTooltip.classList.add("show");
3440           this.#editor._reportTelemetry({
3441             action: "alt_text_tooltip"
3442           });
3443         }, DELAY_TO_SHOW_TOOLTIP);
3444       }, {
3445         signal
3446       });
3447       button.addEventListener("mouseleave", () => {
3448         if (this.#altTextTooltipTimeout) {
3449           clearTimeout(this.#altTextTooltipTimeout);
3450           this.#altTextTooltipTimeout = null;
3451         }
3452         this.#altTextTooltip?.classList.remove("show");
3453       }, {
3454         signal
3455       });
3456     }
3457     if (this.#altTextDecorative) {
3458       tooltip.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-decorative-tooltip");
3459     } else {
3460       tooltip.removeAttribute("data-l10n-id");
3461       tooltip.textContent = this.#altText;
3462     }
3463     if (!tooltip.parentNode) {
3464       button.append(tooltip);
3465     }
3466     const element = this.#editor.getImageForAltText();
3467     element?.setAttribute("aria-describedby", tooltip.id);
3468   }
3471 ;// ./src/display/touch_manager.js
3474 class TouchManager {
3475   #container;
3476   #isPinching = false;
3477   #isPinchingStopped = null;
3478   #isPinchingDisabled;
3479   #onPinchStart;
3480   #onPinching;
3481   #onPinchEnd;
3482   #pointerDownAC = null;
3483   #signal;
3484   #touchInfo = null;
3485   #touchManagerAC;
3486   #touchMoveAC = null;
3487   constructor({
3488     container,
3489     isPinchingDisabled = null,
3490     isPinchingStopped = null,
3491     onPinchStart = null,
3492     onPinching = null,
3493     onPinchEnd = null,
3494     signal
3495   }) {
3496     this.#container = container;
3497     this.#isPinchingStopped = isPinchingStopped;
3498     this.#isPinchingDisabled = isPinchingDisabled;
3499     this.#onPinchStart = onPinchStart;
3500     this.#onPinching = onPinching;
3501     this.#onPinchEnd = onPinchEnd;
3502     this.#touchManagerAC = new AbortController();
3503     this.#signal = AbortSignal.any([signal, this.#touchManagerAC.signal]);
3504     container.addEventListener("touchstart", this.#onTouchStart.bind(this), {
3505       passive: false,
3506       signal: this.#signal
3507     });
3508   }
3509   get MIN_TOUCH_DISTANCE_TO_PINCH() {
3510     return shadow(this, "MIN_TOUCH_DISTANCE_TO_PINCH", 35 / (window.devicePixelRatio || 1));
3511   }
3512   #onTouchStart(evt) {
3513     if (this.#isPinchingDisabled?.()) {
3514       return;
3515     }
3516     if (evt.touches.length === 1) {
3517       if (this.#pointerDownAC) {
3518         return;
3519       }
3520       const pointerDownAC = this.#pointerDownAC = new AbortController();
3521       const signal = AbortSignal.any([this.#signal, pointerDownAC.signal]);
3522       const container = this.#container;
3523       const opts = {
3524         capture: true,
3525         signal,
3526         passive: false
3527       };
3528       const cancelPointerDown = e => {
3529         if (e.pointerType === "touch") {
3530           this.#pointerDownAC?.abort();
3531           this.#pointerDownAC = null;
3532         }
3533       };
3534       container.addEventListener("pointerdown", e => {
3535         if (e.pointerType === "touch") {
3536           stopEvent(e);
3537           cancelPointerDown(e);
3538         }
3539       }, opts);
3540       container.addEventListener("pointerup", cancelPointerDown, opts);
3541       container.addEventListener("pointercancel", cancelPointerDown, opts);
3542       return;
3543     }
3544     if (!this.#touchMoveAC) {
3545       this.#touchMoveAC = new AbortController();
3546       const signal = AbortSignal.any([this.#signal, this.#touchMoveAC.signal]);
3547       const container = this.#container;
3548       const opt = {
3549         signal,
3550         capture: false,
3551         passive: false
3552       };
3553       container.addEventListener("touchmove", this.#onTouchMove.bind(this), opt);
3554       const onTouchEnd = this.#onTouchEnd.bind(this);
3555       container.addEventListener("touchend", onTouchEnd, opt);
3556       container.addEventListener("touchcancel", onTouchEnd, opt);
3557       opt.capture = true;
3558       container.addEventListener("pointerdown", stopEvent, opt);
3559       container.addEventListener("pointermove", stopEvent, opt);
3560       container.addEventListener("pointercancel", stopEvent, opt);
3561       container.addEventListener("pointerup", stopEvent, opt);
3562       this.#onPinchStart?.();
3563     }
3564     stopEvent(evt);
3565     if (evt.touches.length !== 2 || this.#isPinchingStopped?.()) {
3566       this.#touchInfo = null;
3567       return;
3568     }
3569     let [touch0, touch1] = evt.touches;
3570     if (touch0.identifier > touch1.identifier) {
3571       [touch0, touch1] = [touch1, touch0];
3572     }
3573     this.#touchInfo = {
3574       touch0X: touch0.screenX,
3575       touch0Y: touch0.screenY,
3576       touch1X: touch1.screenX,
3577       touch1Y: touch1.screenY
3578     };
3579   }
3580   #onTouchMove(evt) {
3581     if (!this.#touchInfo || evt.touches.length !== 2) {
3582       return;
3583     }
3584     stopEvent(evt);
3585     let [touch0, touch1] = evt.touches;
3586     if (touch0.identifier > touch1.identifier) {
3587       [touch0, touch1] = [touch1, touch0];
3588     }
3589     const {
3590       screenX: screen0X,
3591       screenY: screen0Y
3592     } = touch0;
3593     const {
3594       screenX: screen1X,
3595       screenY: screen1Y
3596     } = touch1;
3597     const touchInfo = this.#touchInfo;
3598     const {
3599       touch0X: pTouch0X,
3600       touch0Y: pTouch0Y,
3601       touch1X: pTouch1X,
3602       touch1Y: pTouch1Y
3603     } = touchInfo;
3604     const prevGapX = pTouch1X - pTouch0X;
3605     const prevGapY = pTouch1Y - pTouch0Y;
3606     const currGapX = screen1X - screen0X;
3607     const currGapY = screen1Y - screen0Y;
3608     const distance = Math.hypot(currGapX, currGapY) || 1;
3609     const pDistance = Math.hypot(prevGapX, prevGapY) || 1;
3610     if (!this.#isPinching && Math.abs(pDistance - distance) <= TouchManager.MIN_TOUCH_DISTANCE_TO_PINCH) {
3611       return;
3612     }
3613     touchInfo.touch0X = screen0X;
3614     touchInfo.touch0Y = screen0Y;
3615     touchInfo.touch1X = screen1X;
3616     touchInfo.touch1Y = screen1Y;
3617     if (!this.#isPinching) {
3618       this.#isPinching = true;
3619       return;
3620     }
3621     const origin = [(screen0X + screen1X) / 2, (screen0Y + screen1Y) / 2];
3622     this.#onPinching?.(origin, pDistance, distance);
3623   }
3624   #onTouchEnd(evt) {
3625     if (evt.touches.length >= 2) {
3626       return;
3627     }
3628     this.#touchMoveAC.abort();
3629     this.#touchMoveAC = null;
3630     this.#onPinchEnd?.();
3631     if (!this.#touchInfo) {
3632       return;
3633     }
3634     stopEvent(evt);
3635     this.#touchInfo = null;
3636     this.#isPinching = false;
3637   }
3638   destroy() {
3639     this.#touchManagerAC?.abort();
3640     this.#touchManagerAC = null;
3641     this.#pointerDownAC?.abort();
3642     this.#pointerDownAC = null;
3643   }
3646 ;// ./src/display/editor/editor.js
3653 class AnnotationEditor {
3654   #accessibilityData = null;
3655   #allResizerDivs = null;
3656   #altText = null;
3657   #disabled = false;
3658   #dragPointerId = null;
3659   #dragPointerType = "";
3660   #keepAspectRatio = false;
3661   #resizersDiv = null;
3662   #lastPointerCoords = null;
3663   #savedDimensions = null;
3664   #focusAC = null;
3665   #focusedResizerName = "";
3666   #hasBeenClicked = false;
3667   #initialRect = null;
3668   #isEditing = false;
3669   #isInEditMode = false;
3670   #isResizerEnabledForKeyboard = false;
3671   #moveInDOMTimeout = null;
3672   #prevDragX = 0;
3673   #prevDragY = 0;
3674   #telemetryTimeouts = null;
3675   #touchManager = null;
3676   _editToolbar = null;
3677   _initialOptions = Object.create(null);
3678   _initialData = null;
3679   _isVisible = true;
3680   _uiManager = null;
3681   _focusEventsAllowed = true;
3682   static _l10n = null;
3683   static _l10nResizer = null;
3684   #isDraggable = false;
3685   #zIndex = AnnotationEditor._zIndex++;
3686   static _borderLineWidth = -1;
3687   static _colorManager = new ColorManager();
3688   static _zIndex = 1;
3689   static _telemetryTimeout = 1000;
3690   static get _resizerKeyboardManager() {
3691     const resize = AnnotationEditor.prototype._resizeWithKeyboard;
3692     const small = AnnotationEditorUIManager.TRANSLATE_SMALL;
3693     const big = AnnotationEditorUIManager.TRANSLATE_BIG;
3694     return shadow(this, "_resizerKeyboardManager", new KeyboardManager([[["ArrowLeft", "mac+ArrowLeft"], resize, {
3695       args: [-small, 0]
3696     }], [["ctrl+ArrowLeft", "mac+shift+ArrowLeft"], resize, {
3697       args: [-big, 0]
3698     }], [["ArrowRight", "mac+ArrowRight"], resize, {
3699       args: [small, 0]
3700     }], [["ctrl+ArrowRight", "mac+shift+ArrowRight"], resize, {
3701       args: [big, 0]
3702     }], [["ArrowUp", "mac+ArrowUp"], resize, {
3703       args: [0, -small]
3704     }], [["ctrl+ArrowUp", "mac+shift+ArrowUp"], resize, {
3705       args: [0, -big]
3706     }], [["ArrowDown", "mac+ArrowDown"], resize, {
3707       args: [0, small]
3708     }], [["ctrl+ArrowDown", "mac+shift+ArrowDown"], resize, {
3709       args: [0, big]
3710     }], [["Escape", "mac+Escape"], AnnotationEditor.prototype._stopResizingWithKeyboard]]));
3711   }
3712   constructor(parameters) {
3713     this.parent = parameters.parent;
3714     this.id = parameters.id;
3715     this.width = this.height = null;
3716     this.pageIndex = parameters.parent.pageIndex;
3717     this.name = parameters.name;
3718     this.div = null;
3719     this._uiManager = parameters.uiManager;
3720     this.annotationElementId = null;
3721     this._willKeepAspectRatio = false;
3722     this._initialOptions.isCentered = parameters.isCentered;
3723     this._structTreeParentId = null;
3724     const {
3725       rotation,
3726       rawDims: {
3727         pageWidth,
3728         pageHeight,
3729         pageX,
3730         pageY
3731       }
3732     } = this.parent.viewport;
3733     this.rotation = rotation;
3734     this.pageRotation = (360 + rotation - this._uiManager.viewParameters.rotation) % 360;
3735     this.pageDimensions = [pageWidth, pageHeight];
3736     this.pageTranslation = [pageX, pageY];
3737     const [width, height] = this.parentDimensions;
3738     this.x = parameters.x / width;
3739     this.y = parameters.y / height;
3740     this.isAttachedToDOM = false;
3741     this.deleted = false;
3742   }
3743   get editorType() {
3744     return Object.getPrototypeOf(this).constructor._type;
3745   }
3746   static get isDrawer() {
3747     return false;
3748   }
3749   static get _defaultLineColor() {
3750     return shadow(this, "_defaultLineColor", this._colorManager.getHexCode("CanvasText"));
3751   }
3752   static deleteAnnotationElement(editor) {
3753     const fakeEditor = new FakeEditor({
3754       id: editor.parent.getNextId(),
3755       parent: editor.parent,
3756       uiManager: editor._uiManager
3757     });
3758     fakeEditor.annotationElementId = editor.annotationElementId;
3759     fakeEditor.deleted = true;
3760     fakeEditor._uiManager.addToAnnotationStorage(fakeEditor);
3761   }
3762   static initialize(l10n, _uiManager) {
3763     AnnotationEditor._l10n ??= l10n;
3764     AnnotationEditor._l10nResizer ||= Object.freeze({
3765       topLeft: "pdfjs-editor-resizer-top-left",
3766       topMiddle: "pdfjs-editor-resizer-top-middle",
3767       topRight: "pdfjs-editor-resizer-top-right",
3768       middleRight: "pdfjs-editor-resizer-middle-right",
3769       bottomRight: "pdfjs-editor-resizer-bottom-right",
3770       bottomMiddle: "pdfjs-editor-resizer-bottom-middle",
3771       bottomLeft: "pdfjs-editor-resizer-bottom-left",
3772       middleLeft: "pdfjs-editor-resizer-middle-left"
3773     });
3774     if (AnnotationEditor._borderLineWidth !== -1) {
3775       return;
3776     }
3777     const style = getComputedStyle(document.documentElement);
3778     AnnotationEditor._borderLineWidth = parseFloat(style.getPropertyValue("--outline-width")) || 0;
3779   }
3780   static updateDefaultParams(_type, _value) {}
3781   static get defaultPropertiesToUpdate() {
3782     return [];
3783   }
3784   static isHandlingMimeForPasting(mime) {
3785     return false;
3786   }
3787   static paste(item, parent) {
3788     unreachable("Not implemented");
3789   }
3790   get propertiesToUpdate() {
3791     return [];
3792   }
3793   get _isDraggable() {
3794     return this.#isDraggable;
3795   }
3796   set _isDraggable(value) {
3797     this.#isDraggable = value;
3798     this.div?.classList.toggle("draggable", value);
3799   }
3800   get isEnterHandled() {
3801     return true;
3802   }
3803   center() {
3804     const [pageWidth, pageHeight] = this.pageDimensions;
3805     switch (this.parentRotation) {
3806       case 90:
3807         this.x -= this.height * pageHeight / (pageWidth * 2);
3808         this.y += this.width * pageWidth / (pageHeight * 2);
3809         break;
3810       case 180:
3811         this.x += this.width / 2;
3812         this.y += this.height / 2;
3813         break;
3814       case 270:
3815         this.x += this.height * pageHeight / (pageWidth * 2);
3816         this.y -= this.width * pageWidth / (pageHeight * 2);
3817         break;
3818       default:
3819         this.x -= this.width / 2;
3820         this.y -= this.height / 2;
3821         break;
3822     }
3823     this.fixAndSetPosition();
3824   }
3825   addCommands(params) {
3826     this._uiManager.addCommands(params);
3827   }
3828   get currentLayer() {
3829     return this._uiManager.currentLayer;
3830   }
3831   setInBackground() {
3832     this.div.style.zIndex = 0;
3833   }
3834   setInForeground() {
3835     this.div.style.zIndex = this.#zIndex;
3836   }
3837   setParent(parent) {
3838     if (parent !== null) {
3839       this.pageIndex = parent.pageIndex;
3840       this.pageDimensions = parent.pageDimensions;
3841     } else {
3842       this.#stopResizing();
3843     }
3844     this.parent = parent;
3845   }
3846   focusin(event) {
3847     if (!this._focusEventsAllowed) {
3848       return;
3849     }
3850     if (!this.#hasBeenClicked) {
3851       this.parent.setSelected(this);
3852     } else {
3853       this.#hasBeenClicked = false;
3854     }
3855   }
3856   focusout(event) {
3857     if (!this._focusEventsAllowed) {
3858       return;
3859     }
3860     if (!this.isAttachedToDOM) {
3861       return;
3862     }
3863     const target = event.relatedTarget;
3864     if (target?.closest(`#${this.id}`)) {
3865       return;
3866     }
3867     event.preventDefault();
3868     if (!this.parent?.isMultipleSelection) {
3869       this.commitOrRemove();
3870     }
3871   }
3872   commitOrRemove() {
3873     if (this.isEmpty()) {
3874       this.remove();
3875     } else {
3876       this.commit();
3877     }
3878   }
3879   commit() {
3880     this.addToAnnotationStorage();
3881   }
3882   addToAnnotationStorage() {
3883     this._uiManager.addToAnnotationStorage(this);
3884   }
3885   setAt(x, y, tx, ty) {
3886     const [width, height] = this.parentDimensions;
3887     [tx, ty] = this.screenToPageTranslation(tx, ty);
3888     this.x = (x + tx) / width;
3889     this.y = (y + ty) / height;
3890     this.fixAndSetPosition();
3891   }
3892   #translate([width, height], x, y) {
3893     [x, y] = this.screenToPageTranslation(x, y);
3894     this.x += x / width;
3895     this.y += y / height;
3896     this._onTranslating(this.x, this.y);
3897     this.fixAndSetPosition();
3898   }
3899   translate(x, y) {
3900     this.#translate(this.parentDimensions, x, y);
3901   }
3902   translateInPage(x, y) {
3903     this.#initialRect ||= [this.x, this.y, this.width, this.height];
3904     this.#translate(this.pageDimensions, x, y);
3905     this.div.scrollIntoView({
3906       block: "nearest"
3907     });
3908   }
3909   drag(tx, ty) {
3910     this.#initialRect ||= [this.x, this.y, this.width, this.height];
3911     const {
3912       div,
3913       parentDimensions: [parentWidth, parentHeight]
3914     } = this;
3915     this.x += tx / parentWidth;
3916     this.y += ty / parentHeight;
3917     if (this.parent && (this.x < 0 || this.x > 1 || this.y < 0 || this.y > 1)) {
3918       const {
3919         x,
3920         y
3921       } = this.div.getBoundingClientRect();
3922       if (this.parent.findNewParent(this, x, y)) {
3923         this.x -= Math.floor(this.x);
3924         this.y -= Math.floor(this.y);
3925       }
3926     }
3927     let {
3928       x,
3929       y
3930     } = this;
3931     const [bx, by] = this.getBaseTranslation();
3932     x += bx;
3933     y += by;
3934     const {
3935       style
3936     } = div;
3937     style.left = `${(100 * x).toFixed(2)}%`;
3938     style.top = `${(100 * y).toFixed(2)}%`;
3939     this._onTranslating(x, y);
3940     div.scrollIntoView({
3941       block: "nearest"
3942     });
3943   }
3944   _onTranslating(x, y) {}
3945   _onTranslated(x, y) {}
3946   get _hasBeenMoved() {
3947     return !!this.#initialRect && (this.#initialRect[0] !== this.x || this.#initialRect[1] !== this.y);
3948   }
3949   get _hasBeenResized() {
3950     return !!this.#initialRect && (this.#initialRect[2] !== this.width || this.#initialRect[3] !== this.height);
3951   }
3952   getBaseTranslation() {
3953     const [parentWidth, parentHeight] = this.parentDimensions;
3954     const {
3955       _borderLineWidth
3956     } = AnnotationEditor;
3957     const x = _borderLineWidth / parentWidth;
3958     const y = _borderLineWidth / parentHeight;
3959     switch (this.rotation) {
3960       case 90:
3961         return [-x, y];
3962       case 180:
3963         return [x, y];
3964       case 270:
3965         return [x, -y];
3966       default:
3967         return [-x, -y];
3968     }
3969   }
3970   get _mustFixPosition() {
3971     return true;
3972   }
3973   fixAndSetPosition(rotation = this.rotation) {
3974     const {
3975       div: {
3976         style
3977       },
3978       pageDimensions: [pageWidth, pageHeight]
3979     } = this;
3980     let {
3981       x,
3982       y,
3983       width,
3984       height
3985     } = this;
3986     width *= pageWidth;
3987     height *= pageHeight;
3988     x *= pageWidth;
3989     y *= pageHeight;
3990     if (this._mustFixPosition) {
3991       switch (rotation) {
3992         case 0:
3993           x = Math.max(0, Math.min(pageWidth - width, x));
3994           y = Math.max(0, Math.min(pageHeight - height, y));
3995           break;
3996         case 90:
3997           x = Math.max(0, Math.min(pageWidth - height, x));
3998           y = Math.min(pageHeight, Math.max(width, y));
3999           break;
4000         case 180:
4001           x = Math.min(pageWidth, Math.max(width, x));
4002           y = Math.min(pageHeight, Math.max(height, y));
4003           break;
4004         case 270:
4005           x = Math.min(pageWidth, Math.max(height, x));
4006           y = Math.max(0, Math.min(pageHeight - width, y));
4007           break;
4008       }
4009     }
4010     this.x = x /= pageWidth;
4011     this.y = y /= pageHeight;
4012     const [bx, by] = this.getBaseTranslation();
4013     x += bx;
4014     y += by;
4015     style.left = `${(100 * x).toFixed(2)}%`;
4016     style.top = `${(100 * y).toFixed(2)}%`;
4017     this.moveInDOM();
4018   }
4019   static #rotatePoint(x, y, angle) {
4020     switch (angle) {
4021       case 90:
4022         return [y, -x];
4023       case 180:
4024         return [-x, -y];
4025       case 270:
4026         return [-y, x];
4027       default:
4028         return [x, y];
4029     }
4030   }
4031   screenToPageTranslation(x, y) {
4032     return AnnotationEditor.#rotatePoint(x, y, this.parentRotation);
4033   }
4034   pageTranslationToScreen(x, y) {
4035     return AnnotationEditor.#rotatePoint(x, y, 360 - this.parentRotation);
4036   }
4037   #getRotationMatrix(rotation) {
4038     switch (rotation) {
4039       case 90:
4040         {
4041           const [pageWidth, pageHeight] = this.pageDimensions;
4042           return [0, -pageWidth / pageHeight, pageHeight / pageWidth, 0];
4043         }
4044       case 180:
4045         return [-1, 0, 0, -1];
4046       case 270:
4047         {
4048           const [pageWidth, pageHeight] = this.pageDimensions;
4049           return [0, pageWidth / pageHeight, -pageHeight / pageWidth, 0];
4050         }
4051       default:
4052         return [1, 0, 0, 1];
4053     }
4054   }
4055   get parentScale() {
4056     return this._uiManager.viewParameters.realScale;
4057   }
4058   get parentRotation() {
4059     return (this._uiManager.viewParameters.rotation + this.pageRotation) % 360;
4060   }
4061   get parentDimensions() {
4062     const {
4063       parentScale,
4064       pageDimensions: [pageWidth, pageHeight]
4065     } = this;
4066     return [pageWidth * parentScale, pageHeight * parentScale];
4067   }
4068   setDims(width, height) {
4069     const [parentWidth, parentHeight] = this.parentDimensions;
4070     const {
4071       style
4072     } = this.div;
4073     style.width = `${(100 * width / parentWidth).toFixed(2)}%`;
4074     if (!this.#keepAspectRatio) {
4075       style.height = `${(100 * height / parentHeight).toFixed(2)}%`;
4076     }
4077   }
4078   fixDims() {
4079     const {
4080       style
4081     } = this.div;
4082     const {
4083       height,
4084       width
4085     } = style;
4086     const widthPercent = width.endsWith("%");
4087     const heightPercent = !this.#keepAspectRatio && height.endsWith("%");
4088     if (widthPercent && heightPercent) {
4089       return;
4090     }
4091     const [parentWidth, parentHeight] = this.parentDimensions;
4092     if (!widthPercent) {
4093       style.width = `${(100 * parseFloat(width) / parentWidth).toFixed(2)}%`;
4094     }
4095     if (!this.#keepAspectRatio && !heightPercent) {
4096       style.height = `${(100 * parseFloat(height) / parentHeight).toFixed(2)}%`;
4097     }
4098   }
4099   getInitialTranslation() {
4100     return [0, 0];
4101   }
4102   #createResizers() {
4103     if (this.#resizersDiv) {
4104       return;
4105     }
4106     this.#resizersDiv = document.createElement("div");
4107     this.#resizersDiv.classList.add("resizers");
4108     const classes = this._willKeepAspectRatio ? ["topLeft", "topRight", "bottomRight", "bottomLeft"] : ["topLeft", "topMiddle", "topRight", "middleRight", "bottomRight", "bottomMiddle", "bottomLeft", "middleLeft"];
4109     const signal = this._uiManager._signal;
4110     for (const name of classes) {
4111       const div = document.createElement("div");
4112       this.#resizersDiv.append(div);
4113       div.classList.add("resizer", name);
4114       div.setAttribute("data-resizer-name", name);
4115       div.addEventListener("pointerdown", this.#resizerPointerdown.bind(this, name), {
4116         signal
4117       });
4118       div.addEventListener("contextmenu", noContextMenu, {
4119         signal
4120       });
4121       div.tabIndex = -1;
4122     }
4123     this.div.prepend(this.#resizersDiv);
4124   }
4125   #resizerPointerdown(name, event) {
4126     event.preventDefault();
4127     const {
4128       isMac
4129     } = util_FeatureTest.platform;
4130     if (event.button !== 0 || event.ctrlKey && isMac) {
4131       return;
4132     }
4133     this.#altText?.toggle(false);
4134     const savedDraggable = this._isDraggable;
4135     this._isDraggable = false;
4136     this.#lastPointerCoords = [event.screenX, event.screenY];
4137     const ac = new AbortController();
4138     const signal = this._uiManager.combinedSignal(ac);
4139     this.parent.togglePointerEvents(false);
4140     window.addEventListener("pointermove", this.#resizerPointermove.bind(this, name), {
4141       passive: true,
4142       capture: true,
4143       signal
4144     });
4145     window.addEventListener("touchmove", stopEvent, {
4146       passive: false,
4147       signal
4148     });
4149     window.addEventListener("contextmenu", noContextMenu, {
4150       signal
4151     });
4152     this.#savedDimensions = {
4153       savedX: this.x,
4154       savedY: this.y,
4155       savedWidth: this.width,
4156       savedHeight: this.height
4157     };
4158     const savedParentCursor = this.parent.div.style.cursor;
4159     const savedCursor = this.div.style.cursor;
4160     this.div.style.cursor = this.parent.div.style.cursor = window.getComputedStyle(event.target).cursor;
4161     const pointerUpCallback = () => {
4162       ac.abort();
4163       this.parent.togglePointerEvents(true);
4164       this.#altText?.toggle(true);
4165       this._isDraggable = savedDraggable;
4166       this.parent.div.style.cursor = savedParentCursor;
4167       this.div.style.cursor = savedCursor;
4168       this.#addResizeToUndoStack();
4169     };
4170     window.addEventListener("pointerup", pointerUpCallback, {
4171       signal
4172     });
4173     window.addEventListener("blur", pointerUpCallback, {
4174       signal
4175     });
4176   }
4177   #resize(x, y, width, height) {
4178     this.width = width;
4179     this.height = height;
4180     this.x = x;
4181     this.y = y;
4182     const [parentWidth, parentHeight] = this.parentDimensions;
4183     this.setDims(parentWidth * width, parentHeight * height);
4184     this.fixAndSetPosition();
4185     this._onResized();
4186   }
4187   _onResized() {}
4188   #addResizeToUndoStack() {
4189     if (!this.#savedDimensions) {
4190       return;
4191     }
4192     const {
4193       savedX,
4194       savedY,
4195       savedWidth,
4196       savedHeight
4197     } = this.#savedDimensions;
4198     this.#savedDimensions = null;
4199     const newX = this.x;
4200     const newY = this.y;
4201     const newWidth = this.width;
4202     const newHeight = this.height;
4203     if (newX === savedX && newY === savedY && newWidth === savedWidth && newHeight === savedHeight) {
4204       return;
4205     }
4206     this.addCommands({
4207       cmd: this.#resize.bind(this, newX, newY, newWidth, newHeight),
4208       undo: this.#resize.bind(this, savedX, savedY, savedWidth, savedHeight),
4209       mustExec: true
4210     });
4211   }
4212   static _round(x) {
4213     return Math.round(x * 10000) / 10000;
4214   }
4215   #resizerPointermove(name, event) {
4216     const [parentWidth, parentHeight] = this.parentDimensions;
4217     const savedX = this.x;
4218     const savedY = this.y;
4219     const savedWidth = this.width;
4220     const savedHeight = this.height;
4221     const minWidth = AnnotationEditor.MIN_SIZE / parentWidth;
4222     const minHeight = AnnotationEditor.MIN_SIZE / parentHeight;
4223     const rotationMatrix = this.#getRotationMatrix(this.rotation);
4224     const transf = (x, y) => [rotationMatrix[0] * x + rotationMatrix[2] * y, rotationMatrix[1] * x + rotationMatrix[3] * y];
4225     const invRotationMatrix = this.#getRotationMatrix(360 - this.rotation);
4226     const invTransf = (x, y) => [invRotationMatrix[0] * x + invRotationMatrix[2] * y, invRotationMatrix[1] * x + invRotationMatrix[3] * y];
4227     let getPoint;
4228     let getOpposite;
4229     let isDiagonal = false;
4230     let isHorizontal = false;
4231     switch (name) {
4232       case "topLeft":
4233         isDiagonal = true;
4234         getPoint = (w, h) => [0, 0];
4235         getOpposite = (w, h) => [w, h];
4236         break;
4237       case "topMiddle":
4238         getPoint = (w, h) => [w / 2, 0];
4239         getOpposite = (w, h) => [w / 2, h];
4240         break;
4241       case "topRight":
4242         isDiagonal = true;
4243         getPoint = (w, h) => [w, 0];
4244         getOpposite = (w, h) => [0, h];
4245         break;
4246       case "middleRight":
4247         isHorizontal = true;
4248         getPoint = (w, h) => [w, h / 2];
4249         getOpposite = (w, h) => [0, h / 2];
4250         break;
4251       case "bottomRight":
4252         isDiagonal = true;
4253         getPoint = (w, h) => [w, h];
4254         getOpposite = (w, h) => [0, 0];
4255         break;
4256       case "bottomMiddle":
4257         getPoint = (w, h) => [w / 2, h];
4258         getOpposite = (w, h) => [w / 2, 0];
4259         break;
4260       case "bottomLeft":
4261         isDiagonal = true;
4262         getPoint = (w, h) => [0, h];
4263         getOpposite = (w, h) => [w, 0];
4264         break;
4265       case "middleLeft":
4266         isHorizontal = true;
4267         getPoint = (w, h) => [0, h / 2];
4268         getOpposite = (w, h) => [w, h / 2];
4269         break;
4270     }
4271     const point = getPoint(savedWidth, savedHeight);
4272     const oppositePoint = getOpposite(savedWidth, savedHeight);
4273     let transfOppositePoint = transf(...oppositePoint);
4274     const oppositeX = AnnotationEditor._round(savedX + transfOppositePoint[0]);
4275     const oppositeY = AnnotationEditor._round(savedY + transfOppositePoint[1]);
4276     let ratioX = 1;
4277     let ratioY = 1;
4278     let deltaX, deltaY;
4279     if (!event.fromKeyboard) {
4280       const {
4281         screenX,
4282         screenY
4283       } = event;
4284       const [lastScreenX, lastScreenY] = this.#lastPointerCoords;
4285       [deltaX, deltaY] = this.screenToPageTranslation(screenX - lastScreenX, screenY - lastScreenY);
4286       this.#lastPointerCoords[0] = screenX;
4287       this.#lastPointerCoords[1] = screenY;
4288     } else {
4289       ({
4290         deltaX,
4291         deltaY
4292       } = event);
4293     }
4294     [deltaX, deltaY] = invTransf(deltaX / parentWidth, deltaY / parentHeight);
4295     if (isDiagonal) {
4296       const oldDiag = Math.hypot(savedWidth, savedHeight);
4297       ratioX = ratioY = Math.max(Math.min(Math.hypot(oppositePoint[0] - point[0] - deltaX, oppositePoint[1] - point[1] - deltaY) / oldDiag, 1 / savedWidth, 1 / savedHeight), minWidth / savedWidth, minHeight / savedHeight);
4298     } else if (isHorizontal) {
4299       ratioX = Math.max(minWidth, Math.min(1, Math.abs(oppositePoint[0] - point[0] - deltaX))) / savedWidth;
4300     } else {
4301       ratioY = Math.max(minHeight, Math.min(1, Math.abs(oppositePoint[1] - point[1] - deltaY))) / savedHeight;
4302     }
4303     const newWidth = AnnotationEditor._round(savedWidth * ratioX);
4304     const newHeight = AnnotationEditor._round(savedHeight * ratioY);
4305     transfOppositePoint = transf(...getOpposite(newWidth, newHeight));
4306     const newX = oppositeX - transfOppositePoint[0];
4307     const newY = oppositeY - transfOppositePoint[1];
4308     this.#initialRect ||= [this.x, this.y, this.width, this.height];
4309     this.width = newWidth;
4310     this.height = newHeight;
4311     this.x = newX;
4312     this.y = newY;
4313     this.setDims(parentWidth * newWidth, parentHeight * newHeight);
4314     this.fixAndSetPosition();
4315     this._onResizing();
4316   }
4317   _onResizing() {}
4318   altTextFinish() {
4319     this.#altText?.finish();
4320   }
4321   async addEditToolbar() {
4322     if (this._editToolbar || this.#isInEditMode) {
4323       return this._editToolbar;
4324     }
4325     this._editToolbar = new EditorToolbar(this);
4326     this.div.append(this._editToolbar.render());
4327     if (this.#altText) {
4328       await this._editToolbar.addAltText(this.#altText);
4329     }
4330     return this._editToolbar;
4331   }
4332   removeEditToolbar() {
4333     if (!this._editToolbar) {
4334       return;
4335     }
4336     this._editToolbar.remove();
4337     this._editToolbar = null;
4338     this.#altText?.destroy();
4339   }
4340   addContainer(container) {
4341     const editToolbarDiv = this._editToolbar?.div;
4342     if (editToolbarDiv) {
4343       editToolbarDiv.before(container);
4344     } else {
4345       this.div.append(container);
4346     }
4347   }
4348   getClientDimensions() {
4349     return this.div.getBoundingClientRect();
4350   }
4351   async addAltTextButton() {
4352     if (this.#altText) {
4353       return;
4354     }
4355     AltText.initialize(AnnotationEditor._l10n);
4356     this.#altText = new AltText(this);
4357     if (this.#accessibilityData) {
4358       this.#altText.data = this.#accessibilityData;
4359       this.#accessibilityData = null;
4360     }
4361     await this.addEditToolbar();
4362   }
4363   get altTextData() {
4364     return this.#altText?.data;
4365   }
4366   set altTextData(data) {
4367     if (!this.#altText) {
4368       return;
4369     }
4370     this.#altText.data = data;
4371   }
4372   get guessedAltText() {
4373     return this.#altText?.guessedText;
4374   }
4375   async setGuessedAltText(text) {
4376     await this.#altText?.setGuessedText(text);
4377   }
4378   serializeAltText(isForCopying) {
4379     return this.#altText?.serialize(isForCopying);
4380   }
4381   hasAltText() {
4382     return !!this.#altText && !this.#altText.isEmpty();
4383   }
4384   hasAltTextData() {
4385     return this.#altText?.hasData() ?? false;
4386   }
4387   render() {
4388     this.div = document.createElement("div");
4389     this.div.setAttribute("data-editor-rotation", (360 - this.rotation) % 360);
4390     this.div.className = this.name;
4391     this.div.setAttribute("id", this.id);
4392     this.div.tabIndex = this.#disabled ? -1 : 0;
4393     if (!this._isVisible) {
4394       this.div.classList.add("hidden");
4395     }
4396     this.setInForeground();
4397     this.#addFocusListeners();
4398     const [parentWidth, parentHeight] = this.parentDimensions;
4399     if (this.parentRotation % 180 !== 0) {
4400       this.div.style.maxWidth = `${(100 * parentHeight / parentWidth).toFixed(2)}%`;
4401       this.div.style.maxHeight = `${(100 * parentWidth / parentHeight).toFixed(2)}%`;
4402     }
4403     const [tx, ty] = this.getInitialTranslation();
4404     this.translate(tx, ty);
4405     bindEvents(this, this.div, ["pointerdown"]);
4406     if (this.isResizable && this._uiManager._supportsPinchToZoom) {
4407       this.#touchManager ||= new TouchManager({
4408         container: this.div,
4409         isPinchingDisabled: () => !this.isSelected,
4410         onPinchStart: this.#touchPinchStartCallback.bind(this),
4411         onPinching: this.#touchPinchCallback.bind(this),
4412         onPinchEnd: this.#touchPinchEndCallback.bind(this),
4413         signal: this._uiManager._signal
4414       });
4415     }
4416     this._uiManager._editorUndoBar?.hide();
4417     return this.div;
4418   }
4419   #touchPinchStartCallback() {
4420     this.#savedDimensions = {
4421       savedX: this.x,
4422       savedY: this.y,
4423       savedWidth: this.width,
4424       savedHeight: this.height
4425     };
4426     this.#altText?.toggle(false);
4427     this.parent.togglePointerEvents(false);
4428   }
4429   #touchPinchCallback(_origin, prevDistance, distance) {
4430     const slowDownFactor = 0.7;
4431     let factor = slowDownFactor * (distance / prevDistance) + 1 - slowDownFactor;
4432     if (factor === 1) {
4433       return;
4434     }
4435     const rotationMatrix = this.#getRotationMatrix(this.rotation);
4436     const transf = (x, y) => [rotationMatrix[0] * x + rotationMatrix[2] * y, rotationMatrix[1] * x + rotationMatrix[3] * y];
4437     const [parentWidth, parentHeight] = this.parentDimensions;
4438     const savedX = this.x;
4439     const savedY = this.y;
4440     const savedWidth = this.width;
4441     const savedHeight = this.height;
4442     const minWidth = AnnotationEditor.MIN_SIZE / parentWidth;
4443     const minHeight = AnnotationEditor.MIN_SIZE / parentHeight;
4444     factor = Math.max(Math.min(factor, 1 / savedWidth, 1 / savedHeight), minWidth / savedWidth, minHeight / savedHeight);
4445     const newWidth = AnnotationEditor._round(savedWidth * factor);
4446     const newHeight = AnnotationEditor._round(savedHeight * factor);
4447     if (newWidth === savedWidth && newHeight === savedHeight) {
4448       return;
4449     }
4450     this.#initialRect ||= [savedX, savedY, savedWidth, savedHeight];
4451     const transfCenterPoint = transf(savedWidth / 2, savedHeight / 2);
4452     const centerX = AnnotationEditor._round(savedX + transfCenterPoint[0]);
4453     const centerY = AnnotationEditor._round(savedY + transfCenterPoint[1]);
4454     const newTransfCenterPoint = transf(newWidth / 2, newHeight / 2);
4455     this.x = centerX - newTransfCenterPoint[0];
4456     this.y = centerY - newTransfCenterPoint[1];
4457     this.width = newWidth;
4458     this.height = newHeight;
4459     this.setDims(parentWidth * newWidth, parentHeight * newHeight);
4460     this.fixAndSetPosition();
4461     this._onResizing();
4462   }
4463   #touchPinchEndCallback() {
4464     this.#altText?.toggle(true);
4465     this.parent.togglePointerEvents(true);
4466     this.#addResizeToUndoStack();
4467   }
4468   pointerdown(event) {
4469     const {
4470       isMac
4471     } = util_FeatureTest.platform;
4472     if (event.button !== 0 || event.ctrlKey && isMac) {
4473       event.preventDefault();
4474       return;
4475     }
4476     this.#hasBeenClicked = true;
4477     if (this._isDraggable) {
4478       this.#setUpDragSession(event);
4479       return;
4480     }
4481     this.#selectOnPointerEvent(event);
4482   }
4483   get isSelected() {
4484     return this._uiManager.isSelected(this);
4485   }
4486   #selectOnPointerEvent(event) {
4487     const {
4488       isMac
4489     } = util_FeatureTest.platform;
4490     if (event.ctrlKey && !isMac || event.shiftKey || event.metaKey && isMac) {
4491       this.parent.toggleSelected(this);
4492     } else {
4493       this.parent.setSelected(this);
4494     }
4495   }
4496   #setUpDragSession(event) {
4497     const {
4498       isSelected
4499     } = this;
4500     this._uiManager.setUpDragSession();
4501     let hasDraggingStarted = false;
4502     const ac = new AbortController();
4503     const signal = this._uiManager.combinedSignal(ac);
4504     const opts = {
4505       capture: true,
4506       passive: false,
4507       signal
4508     };
4509     const cancelDrag = e => {
4510       ac.abort();
4511       this.#dragPointerId = null;
4512       this.#hasBeenClicked = false;
4513       if (!this._uiManager.endDragSession()) {
4514         this.#selectOnPointerEvent(e);
4515       }
4516       if (hasDraggingStarted) {
4517         this._onStopDragging();
4518       }
4519     };
4520     if (isSelected) {
4521       this.#prevDragX = event.clientX;
4522       this.#prevDragY = event.clientY;
4523       this.#dragPointerId = event.pointerId;
4524       this.#dragPointerType = event.pointerType;
4525       window.addEventListener("pointermove", e => {
4526         if (!hasDraggingStarted) {
4527           hasDraggingStarted = true;
4528           this._onStartDragging();
4529         }
4530         const {
4531           clientX: x,
4532           clientY: y,
4533           pointerId
4534         } = e;
4535         if (pointerId !== this.#dragPointerId) {
4536           stopEvent(e);
4537           return;
4538         }
4539         const [tx, ty] = this.screenToPageTranslation(x - this.#prevDragX, y - this.#prevDragY);
4540         this.#prevDragX = x;
4541         this.#prevDragY = y;
4542         this._uiManager.dragSelectedEditors(tx, ty);
4543       }, opts);
4544       window.addEventListener("touchmove", stopEvent, opts);
4545       window.addEventListener("pointerdown", e => {
4546         if (e.pointerType === this.#dragPointerType) {
4547           if (this.#touchManager || e.isPrimary) {
4548             cancelDrag(e);
4549           }
4550         }
4551         stopEvent(e);
4552       }, opts);
4553     }
4554     const pointerUpCallback = e => {
4555       if (!this.#dragPointerId || this.#dragPointerId === e.pointerId) {
4556         cancelDrag(e);
4557         return;
4558       }
4559       stopEvent(e);
4560     };
4561     window.addEventListener("pointerup", pointerUpCallback, {
4562       signal
4563     });
4564     window.addEventListener("blur", pointerUpCallback, {
4565       signal
4566     });
4567   }
4568   _onStartDragging() {}
4569   _onStopDragging() {}
4570   moveInDOM() {
4571     if (this.#moveInDOMTimeout) {
4572       clearTimeout(this.#moveInDOMTimeout);
4573     }
4574     this.#moveInDOMTimeout = setTimeout(() => {
4575       this.#moveInDOMTimeout = null;
4576       this.parent?.moveEditorInDOM(this);
4577     }, 0);
4578   }
4579   _setParentAndPosition(parent, x, y) {
4580     parent.changeParent(this);
4581     this.x = x;
4582     this.y = y;
4583     this.fixAndSetPosition();
4584     this._onTranslated();
4585   }
4586   getRect(tx, ty, rotation = this.rotation) {
4587     const scale = this.parentScale;
4588     const [pageWidth, pageHeight] = this.pageDimensions;
4589     const [pageX, pageY] = this.pageTranslation;
4590     const shiftX = tx / scale;
4591     const shiftY = ty / scale;
4592     const x = this.x * pageWidth;
4593     const y = this.y * pageHeight;
4594     const width = this.width * pageWidth;
4595     const height = this.height * pageHeight;
4596     switch (rotation) {
4597       case 0:
4598         return [x + shiftX + pageX, pageHeight - y - shiftY - height + pageY, x + shiftX + width + pageX, pageHeight - y - shiftY + pageY];
4599       case 90:
4600         return [x + shiftY + pageX, pageHeight - y + shiftX + pageY, x + shiftY + height + pageX, pageHeight - y + shiftX + width + pageY];
4601       case 180:
4602         return [x - shiftX - width + pageX, pageHeight - y + shiftY + pageY, x - shiftX + pageX, pageHeight - y + shiftY + height + pageY];
4603       case 270:
4604         return [x - shiftY - height + pageX, pageHeight - y - shiftX - width + pageY, x - shiftY + pageX, pageHeight - y - shiftX + pageY];
4605       default:
4606         throw new Error("Invalid rotation");
4607     }
4608   }
4609   getRectInCurrentCoords(rect, pageHeight) {
4610     const [x1, y1, x2, y2] = rect;
4611     const width = x2 - x1;
4612     const height = y2 - y1;
4613     switch (this.rotation) {
4614       case 0:
4615         return [x1, pageHeight - y2, width, height];
4616       case 90:
4617         return [x1, pageHeight - y1, height, width];
4618       case 180:
4619         return [x2, pageHeight - y1, width, height];
4620       case 270:
4621         return [x2, pageHeight - y2, height, width];
4622       default:
4623         throw new Error("Invalid rotation");
4624     }
4625   }
4626   onceAdded(focus) {}
4627   isEmpty() {
4628     return false;
4629   }
4630   enableEditMode() {
4631     this.#isInEditMode = true;
4632   }
4633   disableEditMode() {
4634     this.#isInEditMode = false;
4635   }
4636   isInEditMode() {
4637     return this.#isInEditMode;
4638   }
4639   shouldGetKeyboardEvents() {
4640     return this.#isResizerEnabledForKeyboard;
4641   }
4642   needsToBeRebuilt() {
4643     return this.div && !this.isAttachedToDOM;
4644   }
4645   get isOnScreen() {
4646     const {
4647       top,
4648       left,
4649       bottom,
4650       right
4651     } = this.getClientDimensions();
4652     const {
4653       innerHeight,
4654       innerWidth
4655     } = window;
4656     return left < innerWidth && right > 0 && top < innerHeight && bottom > 0;
4657   }
4658   #addFocusListeners() {
4659     if (this.#focusAC || !this.div) {
4660       return;
4661     }
4662     this.#focusAC = new AbortController();
4663     const signal = this._uiManager.combinedSignal(this.#focusAC);
4664     this.div.addEventListener("focusin", this.focusin.bind(this), {
4665       signal
4666     });
4667     this.div.addEventListener("focusout", this.focusout.bind(this), {
4668       signal
4669     });
4670   }
4671   rebuild() {
4672     this.#addFocusListeners();
4673   }
4674   rotate(_angle) {}
4675   resize() {}
4676   serializeDeleted() {
4677     return {
4678       id: this.annotationElementId,
4679       deleted: true,
4680       pageIndex: this.pageIndex,
4681       popupRef: this._initialData?.popupRef || ""
4682     };
4683   }
4684   serialize(isForCopying = false, context = null) {
4685     unreachable("An editor must be serializable");
4686   }
4687   static async deserialize(data, parent, uiManager) {
4688     const editor = new this.prototype.constructor({
4689       parent,
4690       id: parent.getNextId(),
4691       uiManager
4692     });
4693     editor.rotation = data.rotation;
4694     editor.#accessibilityData = data.accessibilityData;
4695     const [pageWidth, pageHeight] = editor.pageDimensions;
4696     const [x, y, width, height] = editor.getRectInCurrentCoords(data.rect, pageHeight);
4697     editor.x = x / pageWidth;
4698     editor.y = y / pageHeight;
4699     editor.width = width / pageWidth;
4700     editor.height = height / pageHeight;
4701     return editor;
4702   }
4703   get hasBeenModified() {
4704     return !!this.annotationElementId && (this.deleted || this.serialize() !== null);
4705   }
4706   remove() {
4707     this.#focusAC?.abort();
4708     this.#focusAC = null;
4709     if (!this.isEmpty()) {
4710       this.commit();
4711     }
4712     if (this.parent) {
4713       this.parent.remove(this);
4714     } else {
4715       this._uiManager.removeEditor(this);
4716     }
4717     if (this.#moveInDOMTimeout) {
4718       clearTimeout(this.#moveInDOMTimeout);
4719       this.#moveInDOMTimeout = null;
4720     }
4721     this.#stopResizing();
4722     this.removeEditToolbar();
4723     if (this.#telemetryTimeouts) {
4724       for (const timeout of this.#telemetryTimeouts.values()) {
4725         clearTimeout(timeout);
4726       }
4727       this.#telemetryTimeouts = null;
4728     }
4729     this.parent = null;
4730     this.#touchManager?.destroy();
4731     this.#touchManager = null;
4732   }
4733   get isResizable() {
4734     return false;
4735   }
4736   makeResizable() {
4737     if (this.isResizable) {
4738       this.#createResizers();
4739       this.#resizersDiv.classList.remove("hidden");
4740       bindEvents(this, this.div, ["keydown"]);
4741     }
4742   }
4743   get toolbarPosition() {
4744     return null;
4745   }
4746   keydown(event) {
4747     if (!this.isResizable || event.target !== this.div || event.key !== "Enter") {
4748       return;
4749     }
4750     this._uiManager.setSelected(this);
4751     this.#savedDimensions = {
4752       savedX: this.x,
4753       savedY: this.y,
4754       savedWidth: this.width,
4755       savedHeight: this.height
4756     };
4757     const children = this.#resizersDiv.children;
4758     if (!this.#allResizerDivs) {
4759       this.#allResizerDivs = Array.from(children);
4760       const boundResizerKeydown = this.#resizerKeydown.bind(this);
4761       const boundResizerBlur = this.#resizerBlur.bind(this);
4762       const signal = this._uiManager._signal;
4763       for (const div of this.#allResizerDivs) {
4764         const name = div.getAttribute("data-resizer-name");
4765         div.setAttribute("role", "spinbutton");
4766         div.addEventListener("keydown", boundResizerKeydown, {
4767           signal
4768         });
4769         div.addEventListener("blur", boundResizerBlur, {
4770           signal
4771         });
4772         div.addEventListener("focus", this.#resizerFocus.bind(this, name), {
4773           signal
4774         });
4775         div.setAttribute("data-l10n-id", AnnotationEditor._l10nResizer[name]);
4776       }
4777     }
4778     const first = this.#allResizerDivs[0];
4779     let firstPosition = 0;
4780     for (const div of children) {
4781       if (div === first) {
4782         break;
4783       }
4784       firstPosition++;
4785     }
4786     const nextFirstPosition = (360 - this.rotation + this.parentRotation) % 360 / 90 * (this.#allResizerDivs.length / 4);
4787     if (nextFirstPosition !== firstPosition) {
4788       if (nextFirstPosition < firstPosition) {
4789         for (let i = 0; i < firstPosition - nextFirstPosition; i++) {
4790           this.#resizersDiv.append(this.#resizersDiv.firstChild);
4791         }
4792       } else if (nextFirstPosition > firstPosition) {
4793         for (let i = 0; i < nextFirstPosition - firstPosition; i++) {
4794           this.#resizersDiv.firstChild.before(this.#resizersDiv.lastChild);
4795         }
4796       }
4797       let i = 0;
4798       for (const child of children) {
4799         const div = this.#allResizerDivs[i++];
4800         const name = div.getAttribute("data-resizer-name");
4801         child.setAttribute("data-l10n-id", AnnotationEditor._l10nResizer[name]);
4802       }
4803     }
4804     this.#setResizerTabIndex(0);
4805     this.#isResizerEnabledForKeyboard = true;
4806     this.#resizersDiv.firstChild.focus({
4807       focusVisible: true
4808     });
4809     event.preventDefault();
4810     event.stopImmediatePropagation();
4811   }
4812   #resizerKeydown(event) {
4813     AnnotationEditor._resizerKeyboardManager.exec(this, event);
4814   }
4815   #resizerBlur(event) {
4816     if (this.#isResizerEnabledForKeyboard && event.relatedTarget?.parentNode !== this.#resizersDiv) {
4817       this.#stopResizing();
4818     }
4819   }
4820   #resizerFocus(name) {
4821     this.#focusedResizerName = this.#isResizerEnabledForKeyboard ? name : "";
4822   }
4823   #setResizerTabIndex(value) {
4824     if (!this.#allResizerDivs) {
4825       return;
4826     }
4827     for (const div of this.#allResizerDivs) {
4828       div.tabIndex = value;
4829     }
4830   }
4831   _resizeWithKeyboard(x, y) {
4832     if (!this.#isResizerEnabledForKeyboard) {
4833       return;
4834     }
4835     this.#resizerPointermove(this.#focusedResizerName, {
4836       deltaX: x,
4837       deltaY: y,
4838       fromKeyboard: true
4839     });
4840   }
4841   #stopResizing() {
4842     this.#isResizerEnabledForKeyboard = false;
4843     this.#setResizerTabIndex(-1);
4844     this.#addResizeToUndoStack();
4845   }
4846   _stopResizingWithKeyboard() {
4847     this.#stopResizing();
4848     this.div.focus();
4849   }
4850   select() {
4851     this.makeResizable();
4852     this.div?.classList.add("selectedEditor");
4853     if (!this._editToolbar) {
4854       this.addEditToolbar().then(() => {
4855         if (this.div?.classList.contains("selectedEditor")) {
4856           this._editToolbar?.show();
4857         }
4858       });
4859       return;
4860     }
4861     this._editToolbar?.show();
4862     this.#altText?.toggleAltTextBadge(false);
4863   }
4864   unselect() {
4865     this.#resizersDiv?.classList.add("hidden");
4866     this.div?.classList.remove("selectedEditor");
4867     if (this.div?.contains(document.activeElement)) {
4868       this._uiManager.currentLayer.div.focus({
4869         preventScroll: true
4870       });
4871     }
4872     this._editToolbar?.hide();
4873     this.#altText?.toggleAltTextBadge(true);
4874   }
4875   updateParams(type, value) {}
4876   disableEditing() {}
4877   enableEditing() {}
4878   enterInEditMode() {}
4879   getImageForAltText() {
4880     return null;
4881   }
4882   get contentDiv() {
4883     return this.div;
4884   }
4885   get isEditing() {
4886     return this.#isEditing;
4887   }
4888   set isEditing(value) {
4889     this.#isEditing = value;
4890     if (!this.parent) {
4891       return;
4892     }
4893     if (value) {
4894       this.parent.setSelected(this);
4895       this.parent.setActiveEditor(this);
4896     } else {
4897       this.parent.setActiveEditor(null);
4898     }
4899   }
4900   setAspectRatio(width, height) {
4901     this.#keepAspectRatio = true;
4902     const aspectRatio = width / height;
4903     const {
4904       style
4905     } = this.div;
4906     style.aspectRatio = aspectRatio;
4907     style.height = "auto";
4908   }
4909   static get MIN_SIZE() {
4910     return 16;
4911   }
4912   static canCreateNewEmptyEditor() {
4913     return true;
4914   }
4915   get telemetryInitialData() {
4916     return {
4917       action: "added"
4918     };
4919   }
4920   get telemetryFinalData() {
4921     return null;
4922   }
4923   _reportTelemetry(data, mustWait = false) {
4924     if (mustWait) {
4925       this.#telemetryTimeouts ||= new Map();
4926       const {
4927         action
4928       } = data;
4929       let timeout = this.#telemetryTimeouts.get(action);
4930       if (timeout) {
4931         clearTimeout(timeout);
4932       }
4933       timeout = setTimeout(() => {
4934         this._reportTelemetry(data);
4935         this.#telemetryTimeouts.delete(action);
4936         if (this.#telemetryTimeouts.size === 0) {
4937           this.#telemetryTimeouts = null;
4938         }
4939       }, AnnotationEditor._telemetryTimeout);
4940       this.#telemetryTimeouts.set(action, timeout);
4941       return;
4942     }
4943     data.type ||= this.editorType;
4944     this._uiManager._eventBus.dispatch("reporttelemetry", {
4945       source: this,
4946       details: {
4947         type: "editing",
4948         data
4949       }
4950     });
4951   }
4952   show(visible = this._isVisible) {
4953     this.div.classList.toggle("hidden", !visible);
4954     this._isVisible = visible;
4955   }
4956   enable() {
4957     if (this.div) {
4958       this.div.tabIndex = 0;
4959     }
4960     this.#disabled = false;
4961   }
4962   disable() {
4963     if (this.div) {
4964       this.div.tabIndex = -1;
4965     }
4966     this.#disabled = true;
4967   }
4968   renderAnnotationElement(annotation) {
4969     let content = annotation.container.querySelector(".annotationContent");
4970     if (!content) {
4971       content = document.createElement("div");
4972       content.classList.add("annotationContent", this.editorType);
4973       annotation.container.prepend(content);
4974     } else if (content.nodeName === "CANVAS") {
4975       const canvas = content;
4976       content = document.createElement("div");
4977       content.classList.add("annotationContent", this.editorType);
4978       canvas.before(content);
4979     }
4980     return content;
4981   }
4982   resetAnnotationElement(annotation) {
4983     const {
4984       firstChild
4985     } = annotation.container;
4986     if (firstChild?.nodeName === "DIV" && firstChild.classList.contains("annotationContent")) {
4987       firstChild.remove();
4988     }
4989   }
4991 class FakeEditor extends AnnotationEditor {
4992   constructor(params) {
4993     super(params);
4994     this.annotationElementId = params.annotationElementId;
4995     this.deleted = true;
4996   }
4997   serialize() {
4998     return this.serializeDeleted();
4999   }
5002 ;// ./src/shared/murmurhash3.js
5003 const SEED = 0xc3d2e1f0;
5004 const MASK_HIGH = 0xffff0000;
5005 const MASK_LOW = 0xffff;
5006 class MurmurHash3_64 {
5007   constructor(seed) {
5008     this.h1 = seed ? seed & 0xffffffff : SEED;
5009     this.h2 = seed ? seed & 0xffffffff : SEED;
5010   }
5011   update(input) {
5012     let data, length;
5013     if (typeof input === "string") {
5014       data = new Uint8Array(input.length * 2);
5015       length = 0;
5016       for (let i = 0, ii = input.length; i < ii; i++) {
5017         const code = input.charCodeAt(i);
5018         if (code <= 0xff) {
5019           data[length++] = code;
5020         } else {
5021           data[length++] = code >>> 8;
5022           data[length++] = code & 0xff;
5023         }
5024       }
5025     } else if (ArrayBuffer.isView(input)) {
5026       data = input.slice();
5027       length = data.byteLength;
5028     } else {
5029       throw new Error("Invalid data format, must be a string or TypedArray.");
5030     }
5031     const blockCounts = length >> 2;
5032     const tailLength = length - blockCounts * 4;
5033     const dataUint32 = new Uint32Array(data.buffer, 0, blockCounts);
5034     let k1 = 0,
5035       k2 = 0;
5036     let h1 = this.h1,
5037       h2 = this.h2;
5038     const C1 = 0xcc9e2d51,
5039       C2 = 0x1b873593;
5040     const C1_LOW = C1 & MASK_LOW,
5041       C2_LOW = C2 & MASK_LOW;
5042     for (let i = 0; i < blockCounts; i++) {
5043       if (i & 1) {
5044         k1 = dataUint32[i];
5045         k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW;
5046         k1 = k1 << 15 | k1 >>> 17;
5047         k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW;
5048         h1 ^= k1;
5049         h1 = h1 << 13 | h1 >>> 19;
5050         h1 = h1 * 5 + 0xe6546b64;
5051       } else {
5052         k2 = dataUint32[i];
5053         k2 = k2 * C1 & MASK_HIGH | k2 * C1_LOW & MASK_LOW;
5054         k2 = k2 << 15 | k2 >>> 17;
5055         k2 = k2 * C2 & MASK_HIGH | k2 * C2_LOW & MASK_LOW;
5056         h2 ^= k2;
5057         h2 = h2 << 13 | h2 >>> 19;
5058         h2 = h2 * 5 + 0xe6546b64;
5059       }
5060     }
5061     k1 = 0;
5062     switch (tailLength) {
5063       case 3:
5064         k1 ^= data[blockCounts * 4 + 2] << 16;
5065       case 2:
5066         k1 ^= data[blockCounts * 4 + 1] << 8;
5067       case 1:
5068         k1 ^= data[blockCounts * 4];
5069         k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW;
5070         k1 = k1 << 15 | k1 >>> 17;
5071         k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW;
5072         if (blockCounts & 1) {
5073           h1 ^= k1;
5074         } else {
5075           h2 ^= k1;
5076         }
5077     }
5078     this.h1 = h1;
5079     this.h2 = h2;
5080   }
5081   hexdigest() {
5082     let h1 = this.h1,
5083       h2 = this.h2;
5084     h1 ^= h2 >>> 1;
5085     h1 = h1 * 0xed558ccd & MASK_HIGH | h1 * 0x8ccd & MASK_LOW;
5086     h2 = h2 * 0xff51afd7 & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16;
5087     h1 ^= h2 >>> 1;
5088     h1 = h1 * 0x1a85ec53 & MASK_HIGH | h1 * 0xec53 & MASK_LOW;
5089     h2 = h2 * 0xc4ceb9fe & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16;
5090     h1 ^= h2 >>> 1;
5091     return (h1 >>> 0).toString(16).padStart(8, "0") + (h2 >>> 0).toString(16).padStart(8, "0");
5092   }
5095 ;// ./src/display/annotation_storage.js
5099 const SerializableEmpty = Object.freeze({
5100   map: null,
5101   hash: "",
5102   transfer: undefined
5104 class AnnotationStorage {
5105   #modified = false;
5106   #modifiedIds = null;
5107   #storage = new Map();
5108   constructor() {
5109     this.onSetModified = null;
5110     this.onResetModified = null;
5111     this.onAnnotationEditor = null;
5112   }
5113   getValue(key, defaultValue) {
5114     const value = this.#storage.get(key);
5115     if (value === undefined) {
5116       return defaultValue;
5117     }
5118     return Object.assign(defaultValue, value);
5119   }
5120   getRawValue(key) {
5121     return this.#storage.get(key);
5122   }
5123   remove(key) {
5124     this.#storage.delete(key);
5125     if (this.#storage.size === 0) {
5126       this.resetModified();
5127     }
5128     if (typeof this.onAnnotationEditor === "function") {
5129       for (const value of this.#storage.values()) {
5130         if (value instanceof AnnotationEditor) {
5131           return;
5132         }
5133       }
5134       this.onAnnotationEditor(null);
5135     }
5136   }
5137   setValue(key, value) {
5138     const obj = this.#storage.get(key);
5139     let modified = false;
5140     if (obj !== undefined) {
5141       for (const [entry, val] of Object.entries(value)) {
5142         if (obj[entry] !== val) {
5143           modified = true;
5144           obj[entry] = val;
5145         }
5146       }
5147     } else {
5148       modified = true;
5149       this.#storage.set(key, value);
5150     }
5151     if (modified) {
5152       this.#setModified();
5153     }
5154     if (value instanceof AnnotationEditor && typeof this.onAnnotationEditor === "function") {
5155       this.onAnnotationEditor(value.constructor._type);
5156     }
5157   }
5158   has(key) {
5159     return this.#storage.has(key);
5160   }
5161   getAll() {
5162     return this.#storage.size > 0 ? objectFromMap(this.#storage) : null;
5163   }
5164   setAll(obj) {
5165     for (const [key, val] of Object.entries(obj)) {
5166       this.setValue(key, val);
5167     }
5168   }
5169   get size() {
5170     return this.#storage.size;
5171   }
5172   #setModified() {
5173     if (!this.#modified) {
5174       this.#modified = true;
5175       if (typeof this.onSetModified === "function") {
5176         this.onSetModified();
5177       }
5178     }
5179   }
5180   resetModified() {
5181     if (this.#modified) {
5182       this.#modified = false;
5183       if (typeof this.onResetModified === "function") {
5184         this.onResetModified();
5185       }
5186     }
5187   }
5188   get print() {
5189     return new PrintAnnotationStorage(this);
5190   }
5191   get serializable() {
5192     if (this.#storage.size === 0) {
5193       return SerializableEmpty;
5194     }
5195     const map = new Map(),
5196       hash = new MurmurHash3_64(),
5197       transfer = [];
5198     const context = Object.create(null);
5199     let hasBitmap = false;
5200     for (const [key, val] of this.#storage) {
5201       const serialized = val instanceof AnnotationEditor ? val.serialize(false, context) : val;
5202       if (serialized) {
5203         map.set(key, serialized);
5204         hash.update(`${key}:${JSON.stringify(serialized)}`);
5205         hasBitmap ||= !!serialized.bitmap;
5206       }
5207     }
5208     if (hasBitmap) {
5209       for (const value of map.values()) {
5210         if (value.bitmap) {
5211           transfer.push(value.bitmap);
5212         }
5213       }
5214     }
5215     return map.size > 0 ? {
5216       map,
5217       hash: hash.hexdigest(),
5218       transfer
5219     } : SerializableEmpty;
5220   }
5221   get editorStats() {
5222     let stats = null;
5223     const typeToEditor = new Map();
5224     for (const value of this.#storage.values()) {
5225       if (!(value instanceof AnnotationEditor)) {
5226         continue;
5227       }
5228       const editorStats = value.telemetryFinalData;
5229       if (!editorStats) {
5230         continue;
5231       }
5232       const {
5233         type
5234       } = editorStats;
5235       if (!typeToEditor.has(type)) {
5236         typeToEditor.set(type, Object.getPrototypeOf(value).constructor);
5237       }
5238       stats ||= Object.create(null);
5239       const map = stats[type] ||= new Map();
5240       for (const [key, val] of Object.entries(editorStats)) {
5241         if (key === "type") {
5242           continue;
5243         }
5244         let counters = map.get(key);
5245         if (!counters) {
5246           counters = new Map();
5247           map.set(key, counters);
5248         }
5249         const count = counters.get(val) ?? 0;
5250         counters.set(val, count + 1);
5251       }
5252     }
5253     for (const [type, editor] of typeToEditor) {
5254       stats[type] = editor.computeTelemetryFinalData(stats[type]);
5255     }
5256     return stats;
5257   }
5258   resetModifiedIds() {
5259     this.#modifiedIds = null;
5260   }
5261   get modifiedIds() {
5262     if (this.#modifiedIds) {
5263       return this.#modifiedIds;
5264     }
5265     const ids = [];
5266     for (const value of this.#storage.values()) {
5267       if (!(value instanceof AnnotationEditor) || !value.annotationElementId || !value.serialize()) {
5268         continue;
5269       }
5270       ids.push(value.annotationElementId);
5271     }
5272     return this.#modifiedIds = {
5273       ids: new Set(ids),
5274       hash: ids.join(",")
5275     };
5276   }
5278 class PrintAnnotationStorage extends AnnotationStorage {
5279   #serializable;
5280   constructor(parent) {
5281     super();
5282     const {
5283       map,
5284       hash,
5285       transfer
5286     } = parent.serializable;
5287     const clone = structuredClone(map, transfer ? {
5288       transfer
5289     } : null);
5290     this.#serializable = {
5291       map: clone,
5292       hash,
5293       transfer
5294     };
5295   }
5296   get print() {
5297     unreachable("Should not call PrintAnnotationStorage.print");
5298   }
5299   get serializable() {
5300     return this.#serializable;
5301   }
5302   get modifiedIds() {
5303     return shadow(this, "modifiedIds", {
5304       ids: new Set(),
5305       hash: ""
5306     });
5307   }
5310 ;// ./src/display/font_loader.js
5312 class FontLoader {
5313   #systemFonts = new Set();
5314   constructor({
5315     ownerDocument = globalThis.document,
5316     styleElement = null
5317   }) {
5318     this._document = ownerDocument;
5319     this.nativeFontFaces = new Set();
5320     this.styleElement = null;
5321   }
5322   addNativeFontFace(nativeFontFace) {
5323     this.nativeFontFaces.add(nativeFontFace);
5324     this._document.fonts.add(nativeFontFace);
5325   }
5326   removeNativeFontFace(nativeFontFace) {
5327     this.nativeFontFaces.delete(nativeFontFace);
5328     this._document.fonts.delete(nativeFontFace);
5329   }
5330   insertRule(rule) {
5331     if (!this.styleElement) {
5332       this.styleElement = this._document.createElement("style");
5333       this._document.documentElement.getElementsByTagName("head")[0].append(this.styleElement);
5334     }
5335     const styleSheet = this.styleElement.sheet;
5336     styleSheet.insertRule(rule, styleSheet.cssRules.length);
5337   }
5338   clear() {
5339     for (const nativeFontFace of this.nativeFontFaces) {
5340       this._document.fonts.delete(nativeFontFace);
5341     }
5342     this.nativeFontFaces.clear();
5343     this.#systemFonts.clear();
5344     if (this.styleElement) {
5345       this.styleElement.remove();
5346       this.styleElement = null;
5347     }
5348   }
5349   async loadSystemFont({
5350     systemFontInfo: info,
5351     _inspectFont
5352   }) {
5353     if (!info || this.#systemFonts.has(info.loadedName)) {
5354       return;
5355     }
5356     assert(!this.disableFontFace, "loadSystemFont shouldn't be called when `disableFontFace` is set.");
5357     if (this.isFontLoadingAPISupported) {
5358       const {
5359         loadedName,
5360         src,
5361         style
5362       } = info;
5363       const fontFace = new FontFace(loadedName, src, style);
5364       this.addNativeFontFace(fontFace);
5365       try {
5366         await fontFace.load();
5367         this.#systemFonts.add(loadedName);
5368         _inspectFont?.(info);
5369       } catch {
5370         warn(`Cannot load system font: ${info.baseFontName}, installing it could help to improve PDF rendering.`);
5371         this.removeNativeFontFace(fontFace);
5372       }
5373       return;
5374     }
5375     unreachable("Not implemented: loadSystemFont without the Font Loading API.");
5376   }
5377   async bind(font) {
5378     if (font.attached || font.missingFile && !font.systemFontInfo) {
5379       return;
5380     }
5381     font.attached = true;
5382     if (font.systemFontInfo) {
5383       await this.loadSystemFont(font);
5384       return;
5385     }
5386     if (this.isFontLoadingAPISupported) {
5387       const nativeFontFace = font.createNativeFontFace();
5388       if (nativeFontFace) {
5389         this.addNativeFontFace(nativeFontFace);
5390         try {
5391           await nativeFontFace.loaded;
5392         } catch (ex) {
5393           warn(`Failed to load font '${nativeFontFace.family}': '${ex}'.`);
5394           font.disableFontFace = true;
5395           throw ex;
5396         }
5397       }
5398       return;
5399     }
5400     const rule = font.createFontFaceRule();
5401     if (rule) {
5402       this.insertRule(rule);
5403       if (this.isSyncFontLoadingSupported) {
5404         return;
5405       }
5406       throw new Error("Not implemented: async font loading");
5407     }
5408   }
5409   get isFontLoadingAPISupported() {
5410     const hasFonts = !!this._document?.fonts;
5411     return shadow(this, "isFontLoadingAPISupported", hasFonts);
5412   }
5413   get isSyncFontLoadingSupported() {
5414     return shadow(this, "isSyncFontLoadingSupported", true);
5415   }
5416   _queueLoadingCallback(callback) {
5417     throw new Error("Not implemented: _queueLoadingCallback");
5418   }
5419   get _loadTestFont() {
5420     throw new Error("Not implemented: _loadTestFont");
5421   }
5422   _prepareFontLoadEvent(font, request) {
5423     throw new Error("Not implemented: _prepareFontLoadEvent");
5424   }
5426 class FontFaceObject {
5427   constructor(translatedData, {
5428     disableFontFace = false,
5429     fontExtraProperties = false,
5430     inspectFont = null
5431   }) {
5432     this.compiledGlyphs = Object.create(null);
5433     for (const i in translatedData) {
5434       this[i] = translatedData[i];
5435     }
5436     this.disableFontFace = disableFontFace === true;
5437     this.fontExtraProperties = fontExtraProperties === true;
5438     this._inspectFont = inspectFont;
5439   }
5440   createNativeFontFace() {
5441     if (!this.data || this.disableFontFace) {
5442       return null;
5443     }
5444     let nativeFontFace;
5445     if (!this.cssFontInfo) {
5446       nativeFontFace = new FontFace(this.loadedName, this.data, {});
5447     } else {
5448       const css = {
5449         weight: this.cssFontInfo.fontWeight
5450       };
5451       if (this.cssFontInfo.italicAngle) {
5452         css.style = `oblique ${this.cssFontInfo.italicAngle}deg`;
5453       }
5454       nativeFontFace = new FontFace(this.cssFontInfo.fontFamily, this.data, css);
5455     }
5456     this._inspectFont?.(this);
5457     return nativeFontFace;
5458   }
5459   createFontFaceRule() {
5460     if (!this.data || this.disableFontFace) {
5461       return null;
5462     }
5463     const url = `url(data:${this.mimetype};base64,${toBase64Util(this.data)});`;
5464     let rule;
5465     if (!this.cssFontInfo) {
5466       rule = `@font-face {font-family:"${this.loadedName}";src:${url}}`;
5467     } else {
5468       let css = `font-weight: ${this.cssFontInfo.fontWeight};`;
5469       if (this.cssFontInfo.italicAngle) {
5470         css += `font-style: oblique ${this.cssFontInfo.italicAngle}deg;`;
5471       }
5472       rule = `@font-face {font-family:"${this.cssFontInfo.fontFamily}";${css}src:${url}}`;
5473     }
5474     this._inspectFont?.(this, url);
5475     return rule;
5476   }
5477   getPathGenerator(objs, character) {
5478     if (this.compiledGlyphs[character] !== undefined) {
5479       return this.compiledGlyphs[character];
5480     }
5481     const objId = this.loadedName + "_path_" + character;
5482     let cmds;
5483     try {
5484       cmds = objs.get(objId);
5485     } catch (ex) {
5486       warn(`getPathGenerator - ignoring character: "${ex}".`);
5487     }
5488     const path = new Path2D(cmds || "");
5489     if (!this.fontExtraProperties) {
5490       objs.delete(objId);
5491     }
5492     return this.compiledGlyphs[character] = path;
5493   }
5496 ;// ./src/shared/message_handler.js
5498 const CallbackKind = {
5499   DATA: 1,
5500   ERROR: 2
5502 const StreamKind = {
5503   CANCEL: 1,
5504   CANCEL_COMPLETE: 2,
5505   CLOSE: 3,
5506   ENQUEUE: 4,
5507   ERROR: 5,
5508   PULL: 6,
5509   PULL_COMPLETE: 7,
5510   START_COMPLETE: 8
5512 function onFn() {}
5513 function wrapReason(ex) {
5514   if (ex instanceof AbortException || ex instanceof InvalidPDFException || ex instanceof PasswordException || ex instanceof ResponseException || ex instanceof UnknownErrorException) {
5515     return ex;
5516   }
5517   if (!(ex instanceof Error || typeof ex === "object" && ex !== null)) {
5518     unreachable('wrapReason: Expected "reason" to be a (possibly cloned) Error.');
5519   }
5520   switch (ex.name) {
5521     case "AbortException":
5522       return new AbortException(ex.message);
5523     case "InvalidPDFException":
5524       return new InvalidPDFException(ex.message);
5525     case "PasswordException":
5526       return new PasswordException(ex.message, ex.code);
5527     case "ResponseException":
5528       return new ResponseException(ex.message, ex.status, ex.missing);
5529     case "UnknownErrorException":
5530       return new UnknownErrorException(ex.message, ex.details);
5531   }
5532   return new UnknownErrorException(ex.message, ex.toString());
5534 class MessageHandler {
5535   #messageAC = new AbortController();
5536   constructor(sourceName, targetName, comObj) {
5537     this.sourceName = sourceName;
5538     this.targetName = targetName;
5539     this.comObj = comObj;
5540     this.callbackId = 1;
5541     this.streamId = 1;
5542     this.streamSinks = Object.create(null);
5543     this.streamControllers = Object.create(null);
5544     this.callbackCapabilities = Object.create(null);
5545     this.actionHandler = Object.create(null);
5546     comObj.addEventListener("message", this.#onMessage.bind(this), {
5547       signal: this.#messageAC.signal
5548     });
5549   }
5550   #onMessage({
5551     data
5552   }) {
5553     if (data.targetName !== this.sourceName) {
5554       return;
5555     }
5556     if (data.stream) {
5557       this.#processStreamMessage(data);
5558       return;
5559     }
5560     if (data.callback) {
5561       const callbackId = data.callbackId;
5562       const capability = this.callbackCapabilities[callbackId];
5563       if (!capability) {
5564         throw new Error(`Cannot resolve callback ${callbackId}`);
5565       }
5566       delete this.callbackCapabilities[callbackId];
5567       if (data.callback === CallbackKind.DATA) {
5568         capability.resolve(data.data);
5569       } else if (data.callback === CallbackKind.ERROR) {
5570         capability.reject(wrapReason(data.reason));
5571       } else {
5572         throw new Error("Unexpected callback case");
5573       }
5574       return;
5575     }
5576     const action = this.actionHandler[data.action];
5577     if (!action) {
5578       throw new Error(`Unknown action from worker: ${data.action}`);
5579     }
5580     if (data.callbackId) {
5581       const sourceName = this.sourceName,
5582         targetName = data.sourceName,
5583         comObj = this.comObj;
5584       Promise.try(action, data.data).then(function (result) {
5585         comObj.postMessage({
5586           sourceName,
5587           targetName,
5588           callback: CallbackKind.DATA,
5589           callbackId: data.callbackId,
5590           data: result
5591         });
5592       }, function (reason) {
5593         comObj.postMessage({
5594           sourceName,
5595           targetName,
5596           callback: CallbackKind.ERROR,
5597           callbackId: data.callbackId,
5598           reason: wrapReason(reason)
5599         });
5600       });
5601       return;
5602     }
5603     if (data.streamId) {
5604       this.#createStreamSink(data);
5605       return;
5606     }
5607     action(data.data);
5608   }
5609   on(actionName, handler) {
5610     const ah = this.actionHandler;
5611     if (ah[actionName]) {
5612       throw new Error(`There is already an actionName called "${actionName}"`);
5613     }
5614     ah[actionName] = handler;
5615   }
5616   send(actionName, data, transfers) {
5617     this.comObj.postMessage({
5618       sourceName: this.sourceName,
5619       targetName: this.targetName,
5620       action: actionName,
5621       data
5622     }, transfers);
5623   }
5624   sendWithPromise(actionName, data, transfers) {
5625     const callbackId = this.callbackId++;
5626     const capability = Promise.withResolvers();
5627     this.callbackCapabilities[callbackId] = capability;
5628     try {
5629       this.comObj.postMessage({
5630         sourceName: this.sourceName,
5631         targetName: this.targetName,
5632         action: actionName,
5633         callbackId,
5634         data
5635       }, transfers);
5636     } catch (ex) {
5637       capability.reject(ex);
5638     }
5639     return capability.promise;
5640   }
5641   sendWithStream(actionName, data, queueingStrategy, transfers) {
5642     const streamId = this.streamId++,
5643       sourceName = this.sourceName,
5644       targetName = this.targetName,
5645       comObj = this.comObj;
5646     return new ReadableStream({
5647       start: controller => {
5648         const startCapability = Promise.withResolvers();
5649         this.streamControllers[streamId] = {
5650           controller,
5651           startCall: startCapability,
5652           pullCall: null,
5653           cancelCall: null,
5654           isClosed: false
5655         };
5656         comObj.postMessage({
5657           sourceName,
5658           targetName,
5659           action: actionName,
5660           streamId,
5661           data,
5662           desiredSize: controller.desiredSize
5663         }, transfers);
5664         return startCapability.promise;
5665       },
5666       pull: controller => {
5667         const pullCapability = Promise.withResolvers();
5668         this.streamControllers[streamId].pullCall = pullCapability;
5669         comObj.postMessage({
5670           sourceName,
5671           targetName,
5672           stream: StreamKind.PULL,
5673           streamId,
5674           desiredSize: controller.desiredSize
5675         });
5676         return pullCapability.promise;
5677       },
5678       cancel: reason => {
5679         assert(reason instanceof Error, "cancel must have a valid reason");
5680         const cancelCapability = Promise.withResolvers();
5681         this.streamControllers[streamId].cancelCall = cancelCapability;
5682         this.streamControllers[streamId].isClosed = true;
5683         comObj.postMessage({
5684           sourceName,
5685           targetName,
5686           stream: StreamKind.CANCEL,
5687           streamId,
5688           reason: wrapReason(reason)
5689         });
5690         return cancelCapability.promise;
5691       }
5692     }, queueingStrategy);
5693   }
5694   #createStreamSink(data) {
5695     const streamId = data.streamId,
5696       sourceName = this.sourceName,
5697       targetName = data.sourceName,
5698       comObj = this.comObj;
5699     const self = this,
5700       action = this.actionHandler[data.action];
5701     const streamSink = {
5702       enqueue(chunk, size = 1, transfers) {
5703         if (this.isCancelled) {
5704           return;
5705         }
5706         const lastDesiredSize = this.desiredSize;
5707         this.desiredSize -= size;
5708         if (lastDesiredSize > 0 && this.desiredSize <= 0) {
5709           this.sinkCapability = Promise.withResolvers();
5710           this.ready = this.sinkCapability.promise;
5711         }
5712         comObj.postMessage({
5713           sourceName,
5714           targetName,
5715           stream: StreamKind.ENQUEUE,
5716           streamId,
5717           chunk
5718         }, transfers);
5719       },
5720       close() {
5721         if (this.isCancelled) {
5722           return;
5723         }
5724         this.isCancelled = true;
5725         comObj.postMessage({
5726           sourceName,
5727           targetName,
5728           stream: StreamKind.CLOSE,
5729           streamId
5730         });
5731         delete self.streamSinks[streamId];
5732       },
5733       error(reason) {
5734         assert(reason instanceof Error, "error must have a valid reason");
5735         if (this.isCancelled) {
5736           return;
5737         }
5738         this.isCancelled = true;
5739         comObj.postMessage({
5740           sourceName,
5741           targetName,
5742           stream: StreamKind.ERROR,
5743           streamId,
5744           reason: wrapReason(reason)
5745         });
5746       },
5747       sinkCapability: Promise.withResolvers(),
5748       onPull: null,
5749       onCancel: null,
5750       isCancelled: false,
5751       desiredSize: data.desiredSize,
5752       ready: null
5753     };
5754     streamSink.sinkCapability.resolve();
5755     streamSink.ready = streamSink.sinkCapability.promise;
5756     this.streamSinks[streamId] = streamSink;
5757     Promise.try(action, data.data, streamSink).then(function () {
5758       comObj.postMessage({
5759         sourceName,
5760         targetName,
5761         stream: StreamKind.START_COMPLETE,
5762         streamId,
5763         success: true
5764       });
5765     }, function (reason) {
5766       comObj.postMessage({
5767         sourceName,
5768         targetName,
5769         stream: StreamKind.START_COMPLETE,
5770         streamId,
5771         reason: wrapReason(reason)
5772       });
5773     });
5774   }
5775   #processStreamMessage(data) {
5776     const streamId = data.streamId,
5777       sourceName = this.sourceName,
5778       targetName = data.sourceName,
5779       comObj = this.comObj;
5780     const streamController = this.streamControllers[streamId],
5781       streamSink = this.streamSinks[streamId];
5782     switch (data.stream) {
5783       case StreamKind.START_COMPLETE:
5784         if (data.success) {
5785           streamController.startCall.resolve();
5786         } else {
5787           streamController.startCall.reject(wrapReason(data.reason));
5788         }
5789         break;
5790       case StreamKind.PULL_COMPLETE:
5791         if (data.success) {
5792           streamController.pullCall.resolve();
5793         } else {
5794           streamController.pullCall.reject(wrapReason(data.reason));
5795         }
5796         break;
5797       case StreamKind.PULL:
5798         if (!streamSink) {
5799           comObj.postMessage({
5800             sourceName,
5801             targetName,
5802             stream: StreamKind.PULL_COMPLETE,
5803             streamId,
5804             success: true
5805           });
5806           break;
5807         }
5808         if (streamSink.desiredSize <= 0 && data.desiredSize > 0) {
5809           streamSink.sinkCapability.resolve();
5810         }
5811         streamSink.desiredSize = data.desiredSize;
5812         Promise.try(streamSink.onPull || onFn).then(function () {
5813           comObj.postMessage({
5814             sourceName,
5815             targetName,
5816             stream: StreamKind.PULL_COMPLETE,
5817             streamId,
5818             success: true
5819           });
5820         }, function (reason) {
5821           comObj.postMessage({
5822             sourceName,
5823             targetName,
5824             stream: StreamKind.PULL_COMPLETE,
5825             streamId,
5826             reason: wrapReason(reason)
5827           });
5828         });
5829         break;
5830       case StreamKind.ENQUEUE:
5831         assert(streamController, "enqueue should have stream controller");
5832         if (streamController.isClosed) {
5833           break;
5834         }
5835         streamController.controller.enqueue(data.chunk);
5836         break;
5837       case StreamKind.CLOSE:
5838         assert(streamController, "close should have stream controller");
5839         if (streamController.isClosed) {
5840           break;
5841         }
5842         streamController.isClosed = true;
5843         streamController.controller.close();
5844         this.#deleteStreamController(streamController, streamId);
5845         break;
5846       case StreamKind.ERROR:
5847         assert(streamController, "error should have stream controller");
5848         streamController.controller.error(wrapReason(data.reason));
5849         this.#deleteStreamController(streamController, streamId);
5850         break;
5851       case StreamKind.CANCEL_COMPLETE:
5852         if (data.success) {
5853           streamController.cancelCall.resolve();
5854         } else {
5855           streamController.cancelCall.reject(wrapReason(data.reason));
5856         }
5857         this.#deleteStreamController(streamController, streamId);
5858         break;
5859       case StreamKind.CANCEL:
5860         if (!streamSink) {
5861           break;
5862         }
5863         const dataReason = wrapReason(data.reason);
5864         Promise.try(streamSink.onCancel || onFn, dataReason).then(function () {
5865           comObj.postMessage({
5866             sourceName,
5867             targetName,
5868             stream: StreamKind.CANCEL_COMPLETE,
5869             streamId,
5870             success: true
5871           });
5872         }, function (reason) {
5873           comObj.postMessage({
5874             sourceName,
5875             targetName,
5876             stream: StreamKind.CANCEL_COMPLETE,
5877             streamId,
5878             reason: wrapReason(reason)
5879           });
5880         });
5881         streamSink.sinkCapability.reject(dataReason);
5882         streamSink.isCancelled = true;
5883         delete this.streamSinks[streamId];
5884         break;
5885       default:
5886         throw new Error("Unexpected stream case");
5887     }
5888   }
5889   async #deleteStreamController(streamController, streamId) {
5890     await Promise.allSettled([streamController.startCall?.promise, streamController.pullCall?.promise, streamController.cancelCall?.promise]);
5891     delete this.streamControllers[streamId];
5892   }
5893   destroy() {
5894     this.#messageAC?.abort();
5895     this.#messageAC = null;
5896   }
5899 ;// ./src/display/pattern_helper.js
5902 const PathType = {
5903   FILL: "Fill",
5904   STROKE: "Stroke",
5905   SHADING: "Shading"
5907 function applyBoundingBox(ctx, bbox) {
5908   if (!bbox) {
5909     return;
5910   }
5911   const width = bbox[2] - bbox[0];
5912   const height = bbox[3] - bbox[1];
5913   const region = new Path2D();
5914   region.rect(bbox[0], bbox[1], width, height);
5915   ctx.clip(region);
5917 class BaseShadingPattern {
5918   getPattern() {
5919     unreachable("Abstract method `getPattern` called.");
5920   }
5922 class RadialAxialShadingPattern extends BaseShadingPattern {
5923   constructor(IR) {
5924     super();
5925     this._type = IR[1];
5926     this._bbox = IR[2];
5927     this._colorStops = IR[3];
5928     this._p0 = IR[4];
5929     this._p1 = IR[5];
5930     this._r0 = IR[6];
5931     this._r1 = IR[7];
5932     this.matrix = null;
5933   }
5934   _createGradient(ctx) {
5935     let grad;
5936     if (this._type === "axial") {
5937       grad = ctx.createLinearGradient(this._p0[0], this._p0[1], this._p1[0], this._p1[1]);
5938     } else if (this._type === "radial") {
5939       grad = ctx.createRadialGradient(this._p0[0], this._p0[1], this._r0, this._p1[0], this._p1[1], this._r1);
5940     }
5941     for (const colorStop of this._colorStops) {
5942       grad.addColorStop(colorStop[0], colorStop[1]);
5943     }
5944     return grad;
5945   }
5946   getPattern(ctx, owner, inverse, pathType) {
5947     let pattern;
5948     if (pathType === PathType.STROKE || pathType === PathType.FILL) {
5949       const ownerBBox = owner.current.getClippedPathBoundingBox(pathType, getCurrentTransform(ctx)) || [0, 0, 0, 0];
5950       const width = Math.ceil(ownerBBox[2] - ownerBBox[0]) || 1;
5951       const height = Math.ceil(ownerBBox[3] - ownerBBox[1]) || 1;
5952       const tmpCanvas = owner.cachedCanvases.getCanvas("pattern", width, height);
5953       const tmpCtx = tmpCanvas.context;
5954       tmpCtx.clearRect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height);
5955       tmpCtx.beginPath();
5956       tmpCtx.rect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height);
5957       tmpCtx.translate(-ownerBBox[0], -ownerBBox[1]);
5958       inverse = Util.transform(inverse, [1, 0, 0, 1, ownerBBox[0], ownerBBox[1]]);
5959       tmpCtx.transform(...owner.baseTransform);
5960       if (this.matrix) {
5961         tmpCtx.transform(...this.matrix);
5962       }
5963       applyBoundingBox(tmpCtx, this._bbox);
5964       tmpCtx.fillStyle = this._createGradient(tmpCtx);
5965       tmpCtx.fill();
5966       pattern = ctx.createPattern(tmpCanvas.canvas, "no-repeat");
5967       const domMatrix = new DOMMatrix(inverse);
5968       pattern.setTransform(domMatrix);
5969     } else {
5970       applyBoundingBox(ctx, this._bbox);
5971       pattern = this._createGradient(ctx);
5972     }
5973     return pattern;
5974   }
5976 function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) {
5977   const coords = context.coords,
5978     colors = context.colors;
5979   const bytes = data.data,
5980     rowSize = data.width * 4;
5981   let tmp;
5982   if (coords[p1 + 1] > coords[p2 + 1]) {
5983     tmp = p1;
5984     p1 = p2;
5985     p2 = tmp;
5986     tmp = c1;
5987     c1 = c2;
5988     c2 = tmp;
5989   }
5990   if (coords[p2 + 1] > coords[p3 + 1]) {
5991     tmp = p2;
5992     p2 = p3;
5993     p3 = tmp;
5994     tmp = c2;
5995     c2 = c3;
5996     c3 = tmp;
5997   }
5998   if (coords[p1 + 1] > coords[p2 + 1]) {
5999     tmp = p1;
6000     p1 = p2;
6001     p2 = tmp;
6002     tmp = c1;
6003     c1 = c2;
6004     c2 = tmp;
6005   }
6006   const x1 = (coords[p1] + context.offsetX) * context.scaleX;
6007   const y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY;
6008   const x2 = (coords[p2] + context.offsetX) * context.scaleX;
6009   const y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY;
6010   const x3 = (coords[p3] + context.offsetX) * context.scaleX;
6011   const y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY;
6012   if (y1 >= y3) {
6013     return;
6014   }
6015   const c1r = colors[c1],
6016     c1g = colors[c1 + 1],
6017     c1b = colors[c1 + 2];
6018   const c2r = colors[c2],
6019     c2g = colors[c2 + 1],
6020     c2b = colors[c2 + 2];
6021   const c3r = colors[c3],
6022     c3g = colors[c3 + 1],
6023     c3b = colors[c3 + 2];
6024   const minY = Math.round(y1),
6025     maxY = Math.round(y3);
6026   let xa, car, cag, cab;
6027   let xb, cbr, cbg, cbb;
6028   for (let y = minY; y <= maxY; y++) {
6029     if (y < y2) {
6030       const k = y < y1 ? 0 : (y1 - y) / (y1 - y2);
6031       xa = x1 - (x1 - x2) * k;
6032       car = c1r - (c1r - c2r) * k;
6033       cag = c1g - (c1g - c2g) * k;
6034       cab = c1b - (c1b - c2b) * k;
6035     } else {
6036       let k;
6037       if (y > y3) {
6038         k = 1;
6039       } else if (y2 === y3) {
6040         k = 0;
6041       } else {
6042         k = (y2 - y) / (y2 - y3);
6043       }
6044       xa = x2 - (x2 - x3) * k;
6045       car = c2r - (c2r - c3r) * k;
6046       cag = c2g - (c2g - c3g) * k;
6047       cab = c2b - (c2b - c3b) * k;
6048     }
6049     let k;
6050     if (y < y1) {
6051       k = 0;
6052     } else if (y > y3) {
6053       k = 1;
6054     } else {
6055       k = (y1 - y) / (y1 - y3);
6056     }
6057     xb = x1 - (x1 - x3) * k;
6058     cbr = c1r - (c1r - c3r) * k;
6059     cbg = c1g - (c1g - c3g) * k;
6060     cbb = c1b - (c1b - c3b) * k;
6061     const x1_ = Math.round(Math.min(xa, xb));
6062     const x2_ = Math.round(Math.max(xa, xb));
6063     let j = rowSize * y + x1_ * 4;
6064     for (let x = x1_; x <= x2_; x++) {
6065       k = (xa - x) / (xa - xb);
6066       if (k < 0) {
6067         k = 0;
6068       } else if (k > 1) {
6069         k = 1;
6070       }
6071       bytes[j++] = car - (car - cbr) * k | 0;
6072       bytes[j++] = cag - (cag - cbg) * k | 0;
6073       bytes[j++] = cab - (cab - cbb) * k | 0;
6074       bytes[j++] = 255;
6075     }
6076   }
6078 function drawFigure(data, figure, context) {
6079   const ps = figure.coords;
6080   const cs = figure.colors;
6081   let i, ii;
6082   switch (figure.type) {
6083     case "lattice":
6084       const verticesPerRow = figure.verticesPerRow;
6085       const rows = Math.floor(ps.length / verticesPerRow) - 1;
6086       const cols = verticesPerRow - 1;
6087       for (i = 0; i < rows; i++) {
6088         let q = i * verticesPerRow;
6089         for (let j = 0; j < cols; j++, q++) {
6090           drawTriangle(data, context, ps[q], ps[q + 1], ps[q + verticesPerRow], cs[q], cs[q + 1], cs[q + verticesPerRow]);
6091           drawTriangle(data, context, ps[q + verticesPerRow + 1], ps[q + 1], ps[q + verticesPerRow], cs[q + verticesPerRow + 1], cs[q + 1], cs[q + verticesPerRow]);
6092         }
6093       }
6094       break;
6095     case "triangles":
6096       for (i = 0, ii = ps.length; i < ii; i += 3) {
6097         drawTriangle(data, context, ps[i], ps[i + 1], ps[i + 2], cs[i], cs[i + 1], cs[i + 2]);
6098       }
6099       break;
6100     default:
6101       throw new Error("illegal figure");
6102   }
6104 class MeshShadingPattern extends BaseShadingPattern {
6105   constructor(IR) {
6106     super();
6107     this._coords = IR[2];
6108     this._colors = IR[3];
6109     this._figures = IR[4];
6110     this._bounds = IR[5];
6111     this._bbox = IR[6];
6112     this._background = IR[7];
6113     this.matrix = null;
6114   }
6115   _createMeshCanvas(combinedScale, backgroundColor, cachedCanvases) {
6116     const EXPECTED_SCALE = 1.1;
6117     const MAX_PATTERN_SIZE = 3000;
6118     const BORDER_SIZE = 2;
6119     const offsetX = Math.floor(this._bounds[0]);
6120     const offsetY = Math.floor(this._bounds[1]);
6121     const boundsWidth = Math.ceil(this._bounds[2]) - offsetX;
6122     const boundsHeight = Math.ceil(this._bounds[3]) - offsetY;
6123     const width = Math.min(Math.ceil(Math.abs(boundsWidth * combinedScale[0] * EXPECTED_SCALE)), MAX_PATTERN_SIZE);
6124     const height = Math.min(Math.ceil(Math.abs(boundsHeight * combinedScale[1] * EXPECTED_SCALE)), MAX_PATTERN_SIZE);
6125     const scaleX = boundsWidth / width;
6126     const scaleY = boundsHeight / height;
6127     const context = {
6128       coords: this._coords,
6129       colors: this._colors,
6130       offsetX: -offsetX,
6131       offsetY: -offsetY,
6132       scaleX: 1 / scaleX,
6133       scaleY: 1 / scaleY
6134     };
6135     const paddedWidth = width + BORDER_SIZE * 2;
6136     const paddedHeight = height + BORDER_SIZE * 2;
6137     const tmpCanvas = cachedCanvases.getCanvas("mesh", paddedWidth, paddedHeight);
6138     const tmpCtx = tmpCanvas.context;
6139     const data = tmpCtx.createImageData(width, height);
6140     if (backgroundColor) {
6141       const bytes = data.data;
6142       for (let i = 0, ii = bytes.length; i < ii; i += 4) {
6143         bytes[i] = backgroundColor[0];
6144         bytes[i + 1] = backgroundColor[1];
6145         bytes[i + 2] = backgroundColor[2];
6146         bytes[i + 3] = 255;
6147       }
6148     }
6149     for (const figure of this._figures) {
6150       drawFigure(data, figure, context);
6151     }
6152     tmpCtx.putImageData(data, BORDER_SIZE, BORDER_SIZE);
6153     const canvas = tmpCanvas.canvas;
6154     return {
6155       canvas,
6156       offsetX: offsetX - BORDER_SIZE * scaleX,
6157       offsetY: offsetY - BORDER_SIZE * scaleY,
6158       scaleX,
6159       scaleY
6160     };
6161   }
6162   getPattern(ctx, owner, inverse, pathType) {
6163     applyBoundingBox(ctx, this._bbox);
6164     let scale;
6165     if (pathType === PathType.SHADING) {
6166       scale = Util.singularValueDecompose2dScale(getCurrentTransform(ctx));
6167     } else {
6168       scale = Util.singularValueDecompose2dScale(owner.baseTransform);
6169       if (this.matrix) {
6170         const matrixScale = Util.singularValueDecompose2dScale(this.matrix);
6171         scale = [scale[0] * matrixScale[0], scale[1] * matrixScale[1]];
6172       }
6173     }
6174     const temporaryPatternCanvas = this._createMeshCanvas(scale, pathType === PathType.SHADING ? null : this._background, owner.cachedCanvases);
6175     if (pathType !== PathType.SHADING) {
6176       ctx.setTransform(...owner.baseTransform);
6177       if (this.matrix) {
6178         ctx.transform(...this.matrix);
6179       }
6180     }
6181     ctx.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY);
6182     ctx.scale(temporaryPatternCanvas.scaleX, temporaryPatternCanvas.scaleY);
6183     return ctx.createPattern(temporaryPatternCanvas.canvas, "no-repeat");
6184   }
6186 class DummyShadingPattern extends BaseShadingPattern {
6187   getPattern() {
6188     return "hotpink";
6189   }
6191 function getShadingPattern(IR) {
6192   switch (IR[0]) {
6193     case "RadialAxial":
6194       return new RadialAxialShadingPattern(IR);
6195     case "Mesh":
6196       return new MeshShadingPattern(IR);
6197     case "Dummy":
6198       return new DummyShadingPattern();
6199   }
6200   throw new Error(`Unknown IR type: ${IR[0]}`);
6202 const PaintType = {
6203   COLORED: 1,
6204   UNCOLORED: 2
6206 class TilingPattern {
6207   static MAX_PATTERN_SIZE = 3000;
6208   constructor(IR, color, ctx, canvasGraphicsFactory, baseTransform) {
6209     this.operatorList = IR[2];
6210     this.matrix = IR[3];
6211     this.bbox = IR[4];
6212     this.xstep = IR[5];
6213     this.ystep = IR[6];
6214     this.paintType = IR[7];
6215     this.tilingType = IR[8];
6216     this.color = color;
6217     this.ctx = ctx;
6218     this.canvasGraphicsFactory = canvasGraphicsFactory;
6219     this.baseTransform = baseTransform;
6220   }
6221   createPatternCanvas(owner) {
6222     const {
6223       bbox,
6224       operatorList,
6225       paintType,
6226       tilingType,
6227       color,
6228       canvasGraphicsFactory
6229     } = this;
6230     let {
6231       xstep,
6232       ystep
6233     } = this;
6234     xstep = Math.abs(xstep);
6235     ystep = Math.abs(ystep);
6236     info("TilingType: " + tilingType);
6237     const x0 = bbox[0],
6238       y0 = bbox[1],
6239       x1 = bbox[2],
6240       y1 = bbox[3];
6241     const width = x1 - x0;
6242     const height = y1 - y0;
6243     const matrixScale = Util.singularValueDecompose2dScale(this.matrix);
6244     const curMatrixScale = Util.singularValueDecompose2dScale(this.baseTransform);
6245     const combinedScaleX = matrixScale[0] * curMatrixScale[0];
6246     const combinedScaleY = matrixScale[1] * curMatrixScale[1];
6247     let canvasWidth = width,
6248       canvasHeight = height,
6249       redrawHorizontally = false,
6250       redrawVertically = false;
6251     const xScaledStep = Math.ceil(xstep * combinedScaleX);
6252     const yScaledStep = Math.ceil(ystep * combinedScaleY);
6253     const xScaledWidth = Math.ceil(width * combinedScaleX);
6254     const yScaledHeight = Math.ceil(height * combinedScaleY);
6255     if (xScaledStep >= xScaledWidth) {
6256       canvasWidth = xstep;
6257     } else {
6258       redrawHorizontally = true;
6259     }
6260     if (yScaledStep >= yScaledHeight) {
6261       canvasHeight = ystep;
6262     } else {
6263       redrawVertically = true;
6264     }
6265     const dimx = this.getSizeAndScale(canvasWidth, this.ctx.canvas.width, combinedScaleX);
6266     const dimy = this.getSizeAndScale(canvasHeight, this.ctx.canvas.height, combinedScaleY);
6267     const tmpCanvas = owner.cachedCanvases.getCanvas("pattern", dimx.size, dimy.size);
6268     const tmpCtx = tmpCanvas.context;
6269     const graphics = canvasGraphicsFactory.createCanvasGraphics(tmpCtx);
6270     graphics.groupLevel = owner.groupLevel;
6271     this.setFillAndStrokeStyleToContext(graphics, paintType, color);
6272     tmpCtx.translate(-dimx.scale * x0, -dimy.scale * y0);
6273     graphics.transform(dimx.scale, 0, 0, dimy.scale, 0, 0);
6274     tmpCtx.save();
6275     this.clipBbox(graphics, x0, y0, x1, y1);
6276     graphics.baseTransform = getCurrentTransform(graphics.ctx);
6277     graphics.executeOperatorList(operatorList);
6278     graphics.endDrawing();
6279     tmpCtx.restore();
6280     if (redrawHorizontally || redrawVertically) {
6281       const image = tmpCanvas.canvas;
6282       if (redrawHorizontally) {
6283         canvasWidth = xstep;
6284       }
6285       if (redrawVertically) {
6286         canvasHeight = ystep;
6287       }
6288       const dimx2 = this.getSizeAndScale(canvasWidth, this.ctx.canvas.width, combinedScaleX);
6289       const dimy2 = this.getSizeAndScale(canvasHeight, this.ctx.canvas.height, combinedScaleY);
6290       const xSize = dimx2.size;
6291       const ySize = dimy2.size;
6292       const tmpCanvas2 = owner.cachedCanvases.getCanvas("pattern-workaround", xSize, ySize);
6293       const tmpCtx2 = tmpCanvas2.context;
6294       const ii = redrawHorizontally ? Math.floor(width / xstep) : 0;
6295       const jj = redrawVertically ? Math.floor(height / ystep) : 0;
6296       for (let i = 0; i <= ii; i++) {
6297         for (let j = 0; j <= jj; j++) {
6298           tmpCtx2.drawImage(image, xSize * i, ySize * j, xSize, ySize, 0, 0, xSize, ySize);
6299         }
6300       }
6301       return {
6302         canvas: tmpCanvas2.canvas,
6303         scaleX: dimx2.scale,
6304         scaleY: dimy2.scale,
6305         offsetX: x0,
6306         offsetY: y0
6307       };
6308     }
6309     return {
6310       canvas: tmpCanvas.canvas,
6311       scaleX: dimx.scale,
6312       scaleY: dimy.scale,
6313       offsetX: x0,
6314       offsetY: y0
6315     };
6316   }
6317   getSizeAndScale(step, realOutputSize, scale) {
6318     const maxSize = Math.max(TilingPattern.MAX_PATTERN_SIZE, realOutputSize);
6319     let size = Math.ceil(step * scale);
6320     if (size >= maxSize) {
6321       size = maxSize;
6322     } else {
6323       scale = size / step;
6324     }
6325     return {
6326       scale,
6327       size
6328     };
6329   }
6330   clipBbox(graphics, x0, y0, x1, y1) {
6331     const bboxWidth = x1 - x0;
6332     const bboxHeight = y1 - y0;
6333     graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight);
6334     graphics.current.updateRectMinMax(getCurrentTransform(graphics.ctx), [x0, y0, x1, y1]);
6335     graphics.clip();
6336     graphics.endPath();
6337   }
6338   setFillAndStrokeStyleToContext(graphics, paintType, color) {
6339     const context = graphics.ctx,
6340       current = graphics.current;
6341     switch (paintType) {
6342       case PaintType.COLORED:
6343         const ctx = this.ctx;
6344         context.fillStyle = ctx.fillStyle;
6345         context.strokeStyle = ctx.strokeStyle;
6346         current.fillColor = ctx.fillStyle;
6347         current.strokeColor = ctx.strokeStyle;
6348         break;
6349       case PaintType.UNCOLORED:
6350         const cssColor = Util.makeHexColor(color[0], color[1], color[2]);
6351         context.fillStyle = cssColor;
6352         context.strokeStyle = cssColor;
6353         current.fillColor = cssColor;
6354         current.strokeColor = cssColor;
6355         break;
6356       default:
6357         throw new FormatError(`Unsupported paint type: ${paintType}`);
6358     }
6359   }
6360   getPattern(ctx, owner, inverse, pathType) {
6361     let matrix = inverse;
6362     if (pathType !== PathType.SHADING) {
6363       matrix = Util.transform(matrix, owner.baseTransform);
6364       if (this.matrix) {
6365         matrix = Util.transform(matrix, this.matrix);
6366       }
6367     }
6368     const temporaryPatternCanvas = this.createPatternCanvas(owner);
6369     let domMatrix = new DOMMatrix(matrix);
6370     domMatrix = domMatrix.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY);
6371     domMatrix = domMatrix.scale(1 / temporaryPatternCanvas.scaleX, 1 / temporaryPatternCanvas.scaleY);
6372     const pattern = ctx.createPattern(temporaryPatternCanvas.canvas, "repeat");
6373     pattern.setTransform(domMatrix);
6374     return pattern;
6375   }
6378 ;// ./src/shared/image_utils.js
6380 function convertToRGBA(params) {
6381   switch (params.kind) {
6382     case ImageKind.GRAYSCALE_1BPP:
6383       return convertBlackAndWhiteToRGBA(params);
6384     case ImageKind.RGB_24BPP:
6385       return convertRGBToRGBA(params);
6386   }
6387   return null;
6389 function convertBlackAndWhiteToRGBA({
6390   src,
6391   srcPos = 0,
6392   dest,
6393   width,
6394   height,
6395   nonBlackColor = 0xffffffff,
6396   inverseDecode = false
6397 }) {
6398   const black = util_FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff;
6399   const [zeroMapping, oneMapping] = inverseDecode ? [nonBlackColor, black] : [black, nonBlackColor];
6400   const widthInSource = width >> 3;
6401   const widthRemainder = width & 7;
6402   const srcLength = src.length;
6403   dest = new Uint32Array(dest.buffer);
6404   let destPos = 0;
6405   for (let i = 0; i < height; i++) {
6406     for (const max = srcPos + widthInSource; srcPos < max; srcPos++) {
6407       const elem = srcPos < srcLength ? src[srcPos] : 255;
6408       dest[destPos++] = elem & 0b10000000 ? oneMapping : zeroMapping;
6409       dest[destPos++] = elem & 0b1000000 ? oneMapping : zeroMapping;
6410       dest[destPos++] = elem & 0b100000 ? oneMapping : zeroMapping;
6411       dest[destPos++] = elem & 0b10000 ? oneMapping : zeroMapping;
6412       dest[destPos++] = elem & 0b1000 ? oneMapping : zeroMapping;
6413       dest[destPos++] = elem & 0b100 ? oneMapping : zeroMapping;
6414       dest[destPos++] = elem & 0b10 ? oneMapping : zeroMapping;
6415       dest[destPos++] = elem & 0b1 ? oneMapping : zeroMapping;
6416     }
6417     if (widthRemainder === 0) {
6418       continue;
6419     }
6420     const elem = srcPos < srcLength ? src[srcPos++] : 255;
6421     for (let j = 0; j < widthRemainder; j++) {
6422       dest[destPos++] = elem & 1 << 7 - j ? oneMapping : zeroMapping;
6423     }
6424   }
6425   return {
6426     srcPos,
6427     destPos
6428   };
6430 function convertRGBToRGBA({
6431   src,
6432   srcPos = 0,
6433   dest,
6434   destPos = 0,
6435   width,
6436   height
6437 }) {
6438   let i = 0;
6439   const len = width * height * 3;
6440   const len32 = len >> 2;
6441   const src32 = new Uint32Array(src.buffer, srcPos, len32);
6442   if (FeatureTest.isLittleEndian) {
6443     for (; i < len32 - 2; i += 3, destPos += 4) {
6444       const s1 = src32[i];
6445       const s2 = src32[i + 1];
6446       const s3 = src32[i + 2];
6447       dest[destPos] = s1 | 0xff000000;
6448       dest[destPos + 1] = s1 >>> 24 | s2 << 8 | 0xff000000;
6449       dest[destPos + 2] = s2 >>> 16 | s3 << 16 | 0xff000000;
6450       dest[destPos + 3] = s3 >>> 8 | 0xff000000;
6451     }
6452     for (let j = i * 4, jj = srcPos + len; j < jj; j += 3) {
6453       dest[destPos++] = src[j] | src[j + 1] << 8 | src[j + 2] << 16 | 0xff000000;
6454     }
6455   } else {
6456     for (; i < len32 - 2; i += 3, destPos += 4) {
6457       const s1 = src32[i];
6458       const s2 = src32[i + 1];
6459       const s3 = src32[i + 2];
6460       dest[destPos] = s1 | 0xff;
6461       dest[destPos + 1] = s1 << 24 | s2 >>> 8 | 0xff;
6462       dest[destPos + 2] = s2 << 16 | s3 >>> 16 | 0xff;
6463       dest[destPos + 3] = s3 << 8 | 0xff;
6464     }
6465     for (let j = i * 4, jj = srcPos + len; j < jj; j += 3) {
6466       dest[destPos++] = src[j] << 24 | src[j + 1] << 16 | src[j + 2] << 8 | 0xff;
6467     }
6468   }
6469   return {
6470     srcPos: srcPos + len,
6471     destPos
6472   };
6474 function grayToRGBA(src, dest) {
6475   if (FeatureTest.isLittleEndian) {
6476     for (let i = 0, ii = src.length; i < ii; i++) {
6477       dest[i] = src[i] * 0x10101 | 0xff000000;
6478     }
6479   } else {
6480     for (let i = 0, ii = src.length; i < ii; i++) {
6481       dest[i] = src[i] * 0x1010100 | 0x000000ff;
6482     }
6483   }
6486 ;// ./src/display/canvas.js
6491 const MIN_FONT_SIZE = 16;
6492 const MAX_FONT_SIZE = 100;
6493 const EXECUTION_TIME = 15;
6494 const EXECUTION_STEPS = 10;
6495 const MAX_SIZE_TO_COMPILE = 1000;
6496 const FULL_CHUNK_HEIGHT = 16;
6497 function mirrorContextOperations(ctx, destCtx) {
6498   if (ctx._removeMirroring) {
6499     throw new Error("Context is already forwarding operations.");
6500   }
6501   ctx.__originalSave = ctx.save;
6502   ctx.__originalRestore = ctx.restore;
6503   ctx.__originalRotate = ctx.rotate;
6504   ctx.__originalScale = ctx.scale;
6505   ctx.__originalTranslate = ctx.translate;
6506   ctx.__originalTransform = ctx.transform;
6507   ctx.__originalSetTransform = ctx.setTransform;
6508   ctx.__originalResetTransform = ctx.resetTransform;
6509   ctx.__originalClip = ctx.clip;
6510   ctx.__originalMoveTo = ctx.moveTo;
6511   ctx.__originalLineTo = ctx.lineTo;
6512   ctx.__originalBezierCurveTo = ctx.bezierCurveTo;
6513   ctx.__originalRect = ctx.rect;
6514   ctx.__originalClosePath = ctx.closePath;
6515   ctx.__originalBeginPath = ctx.beginPath;
6516   ctx._removeMirroring = () => {
6517     ctx.save = ctx.__originalSave;
6518     ctx.restore = ctx.__originalRestore;
6519     ctx.rotate = ctx.__originalRotate;
6520     ctx.scale = ctx.__originalScale;
6521     ctx.translate = ctx.__originalTranslate;
6522     ctx.transform = ctx.__originalTransform;
6523     ctx.setTransform = ctx.__originalSetTransform;
6524     ctx.resetTransform = ctx.__originalResetTransform;
6525     ctx.clip = ctx.__originalClip;
6526     ctx.moveTo = ctx.__originalMoveTo;
6527     ctx.lineTo = ctx.__originalLineTo;
6528     ctx.bezierCurveTo = ctx.__originalBezierCurveTo;
6529     ctx.rect = ctx.__originalRect;
6530     ctx.closePath = ctx.__originalClosePath;
6531     ctx.beginPath = ctx.__originalBeginPath;
6532     delete ctx._removeMirroring;
6533   };
6534   ctx.save = function ctxSave() {
6535     destCtx.save();
6536     this.__originalSave();
6537   };
6538   ctx.restore = function ctxRestore() {
6539     destCtx.restore();
6540     this.__originalRestore();
6541   };
6542   ctx.translate = function ctxTranslate(x, y) {
6543     destCtx.translate(x, y);
6544     this.__originalTranslate(x, y);
6545   };
6546   ctx.scale = function ctxScale(x, y) {
6547     destCtx.scale(x, y);
6548     this.__originalScale(x, y);
6549   };
6550   ctx.transform = function ctxTransform(a, b, c, d, e, f) {
6551     destCtx.transform(a, b, c, d, e, f);
6552     this.__originalTransform(a, b, c, d, e, f);
6553   };
6554   ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) {
6555     destCtx.setTransform(a, b, c, d, e, f);
6556     this.__originalSetTransform(a, b, c, d, e, f);
6557   };
6558   ctx.resetTransform = function ctxResetTransform() {
6559     destCtx.resetTransform();
6560     this.__originalResetTransform();
6561   };
6562   ctx.rotate = function ctxRotate(angle) {
6563     destCtx.rotate(angle);
6564     this.__originalRotate(angle);
6565   };
6566   ctx.clip = function ctxRotate(rule) {
6567     destCtx.clip(rule);
6568     this.__originalClip(rule);
6569   };
6570   ctx.moveTo = function (x, y) {
6571     destCtx.moveTo(x, y);
6572     this.__originalMoveTo(x, y);
6573   };
6574   ctx.lineTo = function (x, y) {
6575     destCtx.lineTo(x, y);
6576     this.__originalLineTo(x, y);
6577   };
6578   ctx.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) {
6579     destCtx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
6580     this.__originalBezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
6581   };
6582   ctx.rect = function (x, y, width, height) {
6583     destCtx.rect(x, y, width, height);
6584     this.__originalRect(x, y, width, height);
6585   };
6586   ctx.closePath = function () {
6587     destCtx.closePath();
6588     this.__originalClosePath();
6589   };
6590   ctx.beginPath = function () {
6591     destCtx.beginPath();
6592     this.__originalBeginPath();
6593   };
6595 class CachedCanvases {
6596   constructor(canvasFactory) {
6597     this.canvasFactory = canvasFactory;
6598     this.cache = Object.create(null);
6599   }
6600   getCanvas(id, width, height) {
6601     let canvasEntry;
6602     if (this.cache[id] !== undefined) {
6603       canvasEntry = this.cache[id];
6604       this.canvasFactory.reset(canvasEntry, width, height);
6605     } else {
6606       canvasEntry = this.canvasFactory.create(width, height);
6607       this.cache[id] = canvasEntry;
6608     }
6609     return canvasEntry;
6610   }
6611   delete(id) {
6612     delete this.cache[id];
6613   }
6614   clear() {
6615     for (const id in this.cache) {
6616       const canvasEntry = this.cache[id];
6617       this.canvasFactory.destroy(canvasEntry);
6618       delete this.cache[id];
6619     }
6620   }
6622 function drawImageAtIntegerCoords(ctx, srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH) {
6623   const [a, b, c, d, tx, ty] = getCurrentTransform(ctx);
6624   if (b === 0 && c === 0) {
6625     const tlX = destX * a + tx;
6626     const rTlX = Math.round(tlX);
6627     const tlY = destY * d + ty;
6628     const rTlY = Math.round(tlY);
6629     const brX = (destX + destW) * a + tx;
6630     const rWidth = Math.abs(Math.round(brX) - rTlX) || 1;
6631     const brY = (destY + destH) * d + ty;
6632     const rHeight = Math.abs(Math.round(brY) - rTlY) || 1;
6633     ctx.setTransform(Math.sign(a), 0, 0, Math.sign(d), rTlX, rTlY);
6634     ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rWidth, rHeight);
6635     ctx.setTransform(a, b, c, d, tx, ty);
6636     return [rWidth, rHeight];
6637   }
6638   if (a === 0 && d === 0) {
6639     const tlX = destY * c + tx;
6640     const rTlX = Math.round(tlX);
6641     const tlY = destX * b + ty;
6642     const rTlY = Math.round(tlY);
6643     const brX = (destY + destH) * c + tx;
6644     const rWidth = Math.abs(Math.round(brX) - rTlX) || 1;
6645     const brY = (destX + destW) * b + ty;
6646     const rHeight = Math.abs(Math.round(brY) - rTlY) || 1;
6647     ctx.setTransform(0, Math.sign(b), Math.sign(c), 0, rTlX, rTlY);
6648     ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rHeight, rWidth);
6649     ctx.setTransform(a, b, c, d, tx, ty);
6650     return [rHeight, rWidth];
6651   }
6652   ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH);
6653   const scaleX = Math.hypot(a, b);
6654   const scaleY = Math.hypot(c, d);
6655   return [scaleX * destW, scaleY * destH];
6657 function compileType3Glyph(imgData) {
6658   const {
6659     width,
6660     height
6661   } = imgData;
6662   if (width > MAX_SIZE_TO_COMPILE || height > MAX_SIZE_TO_COMPILE) {
6663     return null;
6664   }
6665   const POINT_TO_PROCESS_LIMIT = 1000;
6666   const POINT_TYPES = new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]);
6667   const width1 = width + 1;
6668   let points = new Uint8Array(width1 * (height + 1));
6669   let i, j, j0;
6670   const lineSize = width + 7 & ~7;
6671   let data = new Uint8Array(lineSize * height),
6672     pos = 0;
6673   for (const elem of imgData.data) {
6674     let mask = 128;
6675     while (mask > 0) {
6676       data[pos++] = elem & mask ? 0 : 255;
6677       mask >>= 1;
6678     }
6679   }
6680   let count = 0;
6681   pos = 0;
6682   if (data[pos] !== 0) {
6683     points[0] = 1;
6684     ++count;
6685   }
6686   for (j = 1; j < width; j++) {
6687     if (data[pos] !== data[pos + 1]) {
6688       points[j] = data[pos] ? 2 : 1;
6689       ++count;
6690     }
6691     pos++;
6692   }
6693   if (data[pos] !== 0) {
6694     points[j] = 2;
6695     ++count;
6696   }
6697   for (i = 1; i < height; i++) {
6698     pos = i * lineSize;
6699     j0 = i * width1;
6700     if (data[pos - lineSize] !== data[pos]) {
6701       points[j0] = data[pos] ? 1 : 8;
6702       ++count;
6703     }
6704     let sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0);
6705     for (j = 1; j < width; j++) {
6706       sum = (sum >> 2) + (data[pos + 1] ? 4 : 0) + (data[pos - lineSize + 1] ? 8 : 0);
6707       if (POINT_TYPES[sum]) {
6708         points[j0 + j] = POINT_TYPES[sum];
6709         ++count;
6710       }
6711       pos++;
6712     }
6713     if (data[pos - lineSize] !== data[pos]) {
6714       points[j0 + j] = data[pos] ? 2 : 4;
6715       ++count;
6716     }
6717     if (count > POINT_TO_PROCESS_LIMIT) {
6718       return null;
6719     }
6720   }
6721   pos = lineSize * (height - 1);
6722   j0 = i * width1;
6723   if (data[pos] !== 0) {
6724     points[j0] = 8;
6725     ++count;
6726   }
6727   for (j = 1; j < width; j++) {
6728     if (data[pos] !== data[pos + 1]) {
6729       points[j0 + j] = data[pos] ? 4 : 8;
6730       ++count;
6731     }
6732     pos++;
6733   }
6734   if (data[pos] !== 0) {
6735     points[j0 + j] = 4;
6736     ++count;
6737   }
6738   if (count > POINT_TO_PROCESS_LIMIT) {
6739     return null;
6740   }
6741   const steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]);
6742   const path = new Path2D();
6743   for (i = 0; count && i <= height; i++) {
6744     let p = i * width1;
6745     const end = p + width;
6746     while (p < end && !points[p]) {
6747       p++;
6748     }
6749     if (p === end) {
6750       continue;
6751     }
6752     path.moveTo(p % width1, i);
6753     const p0 = p;
6754     let type = points[p];
6755     do {
6756       const step = steps[type];
6757       do {
6758         p += step;
6759       } while (!points[p]);
6760       const pp = points[p];
6761       if (pp !== 5 && pp !== 10) {
6762         type = pp;
6763         points[p] = 0;
6764       } else {
6765         type = pp & 0x33 * type >> 4;
6766         points[p] &= type >> 2 | type << 2;
6767       }
6768       path.lineTo(p % width1, p / width1 | 0);
6769       if (!points[p]) {
6770         --count;
6771       }
6772     } while (p0 !== p);
6773     --i;
6774   }
6775   data = null;
6776   points = null;
6777   const drawOutline = function (c) {
6778     c.save();
6779     c.scale(1 / width, -1 / height);
6780     c.translate(0, -height);
6781     c.fill(path);
6782     c.beginPath();
6783     c.restore();
6784   };
6785   return drawOutline;
6787 class CanvasExtraState {
6788   constructor(width, height) {
6789     this.alphaIsShape = false;
6790     this.fontSize = 0;
6791     this.fontSizeScale = 1;
6792     this.textMatrix = IDENTITY_MATRIX;
6793     this.textMatrixScale = 1;
6794     this.fontMatrix = FONT_IDENTITY_MATRIX;
6795     this.leading = 0;
6796     this.x = 0;
6797     this.y = 0;
6798     this.lineX = 0;
6799     this.lineY = 0;
6800     this.charSpacing = 0;
6801     this.wordSpacing = 0;
6802     this.textHScale = 1;
6803     this.textRenderingMode = TextRenderingMode.FILL;
6804     this.textRise = 0;
6805     this.fillColor = "#000000";
6806     this.strokeColor = "#000000";
6807     this.patternFill = false;
6808     this.patternStroke = false;
6809     this.fillAlpha = 1;
6810     this.strokeAlpha = 1;
6811     this.lineWidth = 1;
6812     this.activeSMask = null;
6813     this.transferMaps = "none";
6814     this.startNewPathAndClipBox([0, 0, width, height]);
6815   }
6816   clone() {
6817     const clone = Object.create(this);
6818     clone.clipBox = this.clipBox.slice();
6819     return clone;
6820   }
6821   setCurrentPoint(x, y) {
6822     this.x = x;
6823     this.y = y;
6824   }
6825   updatePathMinMax(transform, x, y) {
6826     [x, y] = Util.applyTransform([x, y], transform);
6827     this.minX = Math.min(this.minX, x);
6828     this.minY = Math.min(this.minY, y);
6829     this.maxX = Math.max(this.maxX, x);
6830     this.maxY = Math.max(this.maxY, y);
6831   }
6832   updateRectMinMax(transform, rect) {
6833     const p1 = Util.applyTransform(rect, transform);
6834     const p2 = Util.applyTransform(rect.slice(2), transform);
6835     const p3 = Util.applyTransform([rect[0], rect[3]], transform);
6836     const p4 = Util.applyTransform([rect[2], rect[1]], transform);
6837     this.minX = Math.min(this.minX, p1[0], p2[0], p3[0], p4[0]);
6838     this.minY = Math.min(this.minY, p1[1], p2[1], p3[1], p4[1]);
6839     this.maxX = Math.max(this.maxX, p1[0], p2[0], p3[0], p4[0]);
6840     this.maxY = Math.max(this.maxY, p1[1], p2[1], p3[1], p4[1]);
6841   }
6842   updateScalingPathMinMax(transform, minMax) {
6843     Util.scaleMinMax(transform, minMax);
6844     this.minX = Math.min(this.minX, minMax[0]);
6845     this.minY = Math.min(this.minY, minMax[1]);
6846     this.maxX = Math.max(this.maxX, minMax[2]);
6847     this.maxY = Math.max(this.maxY, minMax[3]);
6848   }
6849   updateCurvePathMinMax(transform, x0, y0, x1, y1, x2, y2, x3, y3, minMax) {
6850     const box = Util.bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3, minMax);
6851     if (minMax) {
6852       return;
6853     }
6854     this.updateRectMinMax(transform, box);
6855   }
6856   getPathBoundingBox(pathType = PathType.FILL, transform = null) {
6857     const box = [this.minX, this.minY, this.maxX, this.maxY];
6858     if (pathType === PathType.STROKE) {
6859       if (!transform) {
6860         unreachable("Stroke bounding box must include transform.");
6861       }
6862       const scale = Util.singularValueDecompose2dScale(transform);
6863       const xStrokePad = scale[0] * this.lineWidth / 2;
6864       const yStrokePad = scale[1] * this.lineWidth / 2;
6865       box[0] -= xStrokePad;
6866       box[1] -= yStrokePad;
6867       box[2] += xStrokePad;
6868       box[3] += yStrokePad;
6869     }
6870     return box;
6871   }
6872   updateClipFromPath() {
6873     const intersect = Util.intersect(this.clipBox, this.getPathBoundingBox());
6874     this.startNewPathAndClipBox(intersect || [0, 0, 0, 0]);
6875   }
6876   isEmptyClip() {
6877     return this.minX === Infinity;
6878   }
6879   startNewPathAndClipBox(box) {
6880     this.clipBox = box;
6881     this.minX = Infinity;
6882     this.minY = Infinity;
6883     this.maxX = 0;
6884     this.maxY = 0;
6885   }
6886   getClippedPathBoundingBox(pathType = PathType.FILL, transform = null) {
6887     return Util.intersect(this.clipBox, this.getPathBoundingBox(pathType, transform));
6888   }
6890 function putBinaryImageData(ctx, imgData) {
6891   if (imgData instanceof ImageData) {
6892     ctx.putImageData(imgData, 0, 0);
6893     return;
6894   }
6895   const height = imgData.height,
6896     width = imgData.width;
6897   const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
6898   const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
6899   const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
6900   const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
6901   let srcPos = 0,
6902     destPos;
6903   const src = imgData.data;
6904   const dest = chunkImgData.data;
6905   let i, j, thisChunkHeight, elemsInThisChunk;
6906   if (imgData.kind === util_ImageKind.GRAYSCALE_1BPP) {
6907     const srcLength = src.byteLength;
6908     const dest32 = new Uint32Array(dest.buffer, 0, dest.byteLength >> 2);
6909     const dest32DataLength = dest32.length;
6910     const fullSrcDiff = width + 7 >> 3;
6911     const white = 0xffffffff;
6912     const black = util_FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff;
6913     for (i = 0; i < totalChunks; i++) {
6914       thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight;
6915       destPos = 0;
6916       for (j = 0; j < thisChunkHeight; j++) {
6917         const srcDiff = srcLength - srcPos;
6918         let k = 0;
6919         const kEnd = srcDiff > fullSrcDiff ? width : srcDiff * 8 - 7;
6920         const kEndUnrolled = kEnd & ~7;
6921         let mask = 0;
6922         let srcByte = 0;
6923         for (; k < kEndUnrolled; k += 8) {
6924           srcByte = src[srcPos++];
6925           dest32[destPos++] = srcByte & 128 ? white : black;
6926           dest32[destPos++] = srcByte & 64 ? white : black;
6927           dest32[destPos++] = srcByte & 32 ? white : black;
6928           dest32[destPos++] = srcByte & 16 ? white : black;
6929           dest32[destPos++] = srcByte & 8 ? white : black;
6930           dest32[destPos++] = srcByte & 4 ? white : black;
6931           dest32[destPos++] = srcByte & 2 ? white : black;
6932           dest32[destPos++] = srcByte & 1 ? white : black;
6933         }
6934         for (; k < kEnd; k++) {
6935           if (mask === 0) {
6936             srcByte = src[srcPos++];
6937             mask = 128;
6938           }
6939           dest32[destPos++] = srcByte & mask ? white : black;
6940           mask >>= 1;
6941         }
6942       }
6943       while (destPos < dest32DataLength) {
6944         dest32[destPos++] = 0;
6945       }
6946       ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
6947     }
6948   } else if (imgData.kind === util_ImageKind.RGBA_32BPP) {
6949     j = 0;
6950     elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4;
6951     for (i = 0; i < fullChunks; i++) {
6952       dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
6953       srcPos += elemsInThisChunk;
6954       ctx.putImageData(chunkImgData, 0, j);
6955       j += FULL_CHUNK_HEIGHT;
6956     }
6957     if (i < totalChunks) {
6958       elemsInThisChunk = width * partialChunkHeight * 4;
6959       dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
6960       ctx.putImageData(chunkImgData, 0, j);
6961     }
6962   } else if (imgData.kind === util_ImageKind.RGB_24BPP) {
6963     thisChunkHeight = FULL_CHUNK_HEIGHT;
6964     elemsInThisChunk = width * thisChunkHeight;
6965     for (i = 0; i < totalChunks; i++) {
6966       if (i >= fullChunks) {
6967         thisChunkHeight = partialChunkHeight;
6968         elemsInThisChunk = width * thisChunkHeight;
6969       }
6970       destPos = 0;
6971       for (j = elemsInThisChunk; j--;) {
6972         dest[destPos++] = src[srcPos++];
6973         dest[destPos++] = src[srcPos++];
6974         dest[destPos++] = src[srcPos++];
6975         dest[destPos++] = 255;
6976       }
6977       ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
6978     }
6979   } else {
6980     throw new Error(`bad image kind: ${imgData.kind}`);
6981   }
6983 function putBinaryImageMask(ctx, imgData) {
6984   if (imgData.bitmap) {
6985     ctx.drawImage(imgData.bitmap, 0, 0);
6986     return;
6987   }
6988   const height = imgData.height,
6989     width = imgData.width;
6990   const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
6991   const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
6992   const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
6993   const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
6994   let srcPos = 0;
6995   const src = imgData.data;
6996   const dest = chunkImgData.data;
6997   for (let i = 0; i < totalChunks; i++) {
6998     const thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight;
6999     ({
7000       srcPos
7001     } = convertBlackAndWhiteToRGBA({
7002       src,
7003       srcPos,
7004       dest,
7005       width,
7006       height: thisChunkHeight,
7007       nonBlackColor: 0
7008     }));
7009     ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
7010   }
7012 function copyCtxState(sourceCtx, destCtx) {
7013   const properties = ["strokeStyle", "fillStyle", "fillRule", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "globalCompositeOperation", "font", "filter"];
7014   for (const property of properties) {
7015     if (sourceCtx[property] !== undefined) {
7016       destCtx[property] = sourceCtx[property];
7017     }
7018   }
7019   if (sourceCtx.setLineDash !== undefined) {
7020     destCtx.setLineDash(sourceCtx.getLineDash());
7021     destCtx.lineDashOffset = sourceCtx.lineDashOffset;
7022   }
7024 function resetCtxToDefault(ctx) {
7025   ctx.strokeStyle = ctx.fillStyle = "#000000";
7026   ctx.fillRule = "nonzero";
7027   ctx.globalAlpha = 1;
7028   ctx.lineWidth = 1;
7029   ctx.lineCap = "butt";
7030   ctx.lineJoin = "miter";
7031   ctx.miterLimit = 10;
7032   ctx.globalCompositeOperation = "source-over";
7033   ctx.font = "10px sans-serif";
7034   if (ctx.setLineDash !== undefined) {
7035     ctx.setLineDash([]);
7036     ctx.lineDashOffset = 0;
7037   }
7038   const {
7039     filter
7040   } = ctx;
7041   if (filter !== "none" && filter !== "") {
7042     ctx.filter = "none";
7043   }
7045 function getImageSmoothingEnabled(transform, interpolate) {
7046   if (interpolate) {
7047     return true;
7048   }
7049   const scale = Util.singularValueDecompose2dScale(transform);
7050   scale[0] = Math.fround(scale[0]);
7051   scale[1] = Math.fround(scale[1]);
7052   const actualScale = Math.fround((globalThis.devicePixelRatio || 1) * PixelsPerInch.PDF_TO_CSS_UNITS);
7053   return scale[0] <= actualScale && scale[1] <= actualScale;
7055 const LINE_CAP_STYLES = ["butt", "round", "square"];
7056 const LINE_JOIN_STYLES = ["miter", "round", "bevel"];
7057 const NORMAL_CLIP = {};
7058 const EO_CLIP = {};
7059 class CanvasGraphics {
7060   constructor(canvasCtx, commonObjs, objs, canvasFactory, filterFactory, {
7061     optionalContentConfig,
7062     markedContentStack = null
7063   }, annotationCanvasMap, pageColors) {
7064     this.ctx = canvasCtx;
7065     this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height);
7066     this.stateStack = [];
7067     this.pendingClip = null;
7068     this.pendingEOFill = false;
7069     this.res = null;
7070     this.xobjs = null;
7071     this.commonObjs = commonObjs;
7072     this.objs = objs;
7073     this.canvasFactory = canvasFactory;
7074     this.filterFactory = filterFactory;
7075     this.groupStack = [];
7076     this.processingType3 = null;
7077     this.baseTransform = null;
7078     this.baseTransformStack = [];
7079     this.groupLevel = 0;
7080     this.smaskStack = [];
7081     this.smaskCounter = 0;
7082     this.tempSMask = null;
7083     this.suspendedCtx = null;
7084     this.contentVisible = true;
7085     this.markedContentStack = markedContentStack || [];
7086     this.optionalContentConfig = optionalContentConfig;
7087     this.cachedCanvases = new CachedCanvases(this.canvasFactory);
7088     this.cachedPatterns = new Map();
7089     this.annotationCanvasMap = annotationCanvasMap;
7090     this.viewportScale = 1;
7091     this.outputScaleX = 1;
7092     this.outputScaleY = 1;
7093     this.pageColors = pageColors;
7094     this._cachedScaleForStroking = [-1, 0];
7095     this._cachedGetSinglePixelWidth = null;
7096     this._cachedBitmapsMap = new Map();
7097   }
7098   getObject(data, fallback = null) {
7099     if (typeof data === "string") {
7100       return data.startsWith("g_") ? this.commonObjs.get(data) : this.objs.get(data);
7101     }
7102     return fallback;
7103   }
7104   beginDrawing({
7105     transform,
7106     viewport,
7107     transparency = false,
7108     background = null
7109   }) {
7110     const width = this.ctx.canvas.width;
7111     const height = this.ctx.canvas.height;
7112     const savedFillStyle = this.ctx.fillStyle;
7113     this.ctx.fillStyle = background || "#ffffff";
7114     this.ctx.fillRect(0, 0, width, height);
7115     this.ctx.fillStyle = savedFillStyle;
7116     if (transparency) {
7117       const transparentCanvas = this.cachedCanvases.getCanvas("transparent", width, height);
7118       this.compositeCtx = this.ctx;
7119       this.transparentCanvas = transparentCanvas.canvas;
7120       this.ctx = transparentCanvas.context;
7121       this.ctx.save();
7122       this.ctx.transform(...getCurrentTransform(this.compositeCtx));
7123     }
7124     this.ctx.save();
7125     resetCtxToDefault(this.ctx);
7126     if (transform) {
7127       this.ctx.transform(...transform);
7128       this.outputScaleX = transform[0];
7129       this.outputScaleY = transform[0];
7130     }
7131     this.ctx.transform(...viewport.transform);
7132     this.viewportScale = viewport.scale;
7133     this.baseTransform = getCurrentTransform(this.ctx);
7134   }
7135   executeOperatorList(operatorList, executionStartIdx, continueCallback, stepper) {
7136     const argsArray = operatorList.argsArray;
7137     const fnArray = operatorList.fnArray;
7138     let i = executionStartIdx || 0;
7139     const argsArrayLen = argsArray.length;
7140     if (argsArrayLen === i) {
7141       return i;
7142     }
7143     const chunkOperations = argsArrayLen - i > EXECUTION_STEPS && typeof continueCallback === "function";
7144     const endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;
7145     let steps = 0;
7146     const commonObjs = this.commonObjs;
7147     const objs = this.objs;
7148     let fnId;
7149     while (true) {
7150       if (stepper !== undefined && i === stepper.nextBreakPoint) {
7151         stepper.breakIt(i, continueCallback);
7152         return i;
7153       }
7154       fnId = fnArray[i];
7155       if (fnId !== OPS.dependency) {
7156         this[fnId].apply(this, argsArray[i]);
7157       } else {
7158         for (const depObjId of argsArray[i]) {
7159           const objsPool = depObjId.startsWith("g_") ? commonObjs : objs;
7160           if (!objsPool.has(depObjId)) {
7161             objsPool.get(depObjId, continueCallback);
7162             return i;
7163           }
7164         }
7165       }
7166       i++;
7167       if (i === argsArrayLen) {
7168         return i;
7169       }
7170       if (chunkOperations && ++steps > EXECUTION_STEPS) {
7171         if (Date.now() > endTime) {
7172           continueCallback();
7173           return i;
7174         }
7175         steps = 0;
7176       }
7177     }
7178   }
7179   #restoreInitialState() {
7180     while (this.stateStack.length || this.inSMaskMode) {
7181       this.restore();
7182     }
7183     this.current.activeSMask = null;
7184     this.ctx.restore();
7185     if (this.transparentCanvas) {
7186       this.ctx = this.compositeCtx;
7187       this.ctx.save();
7188       this.ctx.setTransform(1, 0, 0, 1, 0, 0);
7189       this.ctx.drawImage(this.transparentCanvas, 0, 0);
7190       this.ctx.restore();
7191       this.transparentCanvas = null;
7192     }
7193   }
7194   endDrawing() {
7195     this.#restoreInitialState();
7196     this.cachedCanvases.clear();
7197     this.cachedPatterns.clear();
7198     for (const cache of this._cachedBitmapsMap.values()) {
7199       for (const canvas of cache.values()) {
7200         if (typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement) {
7201           canvas.width = canvas.height = 0;
7202         }
7203       }
7204       cache.clear();
7205     }
7206     this._cachedBitmapsMap.clear();
7207     this.#drawFilter();
7208   }
7209   #drawFilter() {
7210     if (this.pageColors) {
7211       const hcmFilterId = this.filterFactory.addHCMFilter(this.pageColors.foreground, this.pageColors.background);
7212       if (hcmFilterId !== "none") {
7213         const savedFilter = this.ctx.filter;
7214         this.ctx.filter = hcmFilterId;
7215         this.ctx.drawImage(this.ctx.canvas, 0, 0);
7216         this.ctx.filter = savedFilter;
7217       }
7218     }
7219   }
7220   _scaleImage(img, inverseTransform) {
7221     const width = img.width ?? img.displayWidth;
7222     const height = img.height ?? img.displayHeight;
7223     let widthScale = Math.max(Math.hypot(inverseTransform[0], inverseTransform[1]), 1);
7224     let heightScale = Math.max(Math.hypot(inverseTransform[2], inverseTransform[3]), 1);
7225     let paintWidth = width,
7226       paintHeight = height;
7227     let tmpCanvasId = "prescale1";
7228     let tmpCanvas, tmpCtx;
7229     while (widthScale > 2 && paintWidth > 1 || heightScale > 2 && paintHeight > 1) {
7230       let newWidth = paintWidth,
7231         newHeight = paintHeight;
7232       if (widthScale > 2 && paintWidth > 1) {
7233         newWidth = paintWidth >= 16384 ? Math.floor(paintWidth / 2) - 1 || 1 : Math.ceil(paintWidth / 2);
7234         widthScale /= paintWidth / newWidth;
7235       }
7236       if (heightScale > 2 && paintHeight > 1) {
7237         newHeight = paintHeight >= 16384 ? Math.floor(paintHeight / 2) - 1 || 1 : Math.ceil(paintHeight) / 2;
7238         heightScale /= paintHeight / newHeight;
7239       }
7240       tmpCanvas = this.cachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight);
7241       tmpCtx = tmpCanvas.context;
7242       tmpCtx.clearRect(0, 0, newWidth, newHeight);
7243       tmpCtx.drawImage(img, 0, 0, paintWidth, paintHeight, 0, 0, newWidth, newHeight);
7244       img = tmpCanvas.canvas;
7245       paintWidth = newWidth;
7246       paintHeight = newHeight;
7247       tmpCanvasId = tmpCanvasId === "prescale1" ? "prescale2" : "prescale1";
7248     }
7249     return {
7250       img,
7251       paintWidth,
7252       paintHeight
7253     };
7254   }
7255   _createMaskCanvas(img) {
7256     const ctx = this.ctx;
7257     const {
7258       width,
7259       height
7260     } = img;
7261     const fillColor = this.current.fillColor;
7262     const isPatternFill = this.current.patternFill;
7263     const currentTransform = getCurrentTransform(ctx);
7264     let cache, cacheKey, scaled, maskCanvas;
7265     if ((img.bitmap || img.data) && img.count > 1) {
7266       const mainKey = img.bitmap || img.data.buffer;
7267       cacheKey = JSON.stringify(isPatternFill ? currentTransform : [currentTransform.slice(0, 4), fillColor]);
7268       cache = this._cachedBitmapsMap.get(mainKey);
7269       if (!cache) {
7270         cache = new Map();
7271         this._cachedBitmapsMap.set(mainKey, cache);
7272       }
7273       const cachedImage = cache.get(cacheKey);
7274       if (cachedImage && !isPatternFill) {
7275         const offsetX = Math.round(Math.min(currentTransform[0], currentTransform[2]) + currentTransform[4]);
7276         const offsetY = Math.round(Math.min(currentTransform[1], currentTransform[3]) + currentTransform[5]);
7277         return {
7278           canvas: cachedImage,
7279           offsetX,
7280           offsetY
7281         };
7282       }
7283       scaled = cachedImage;
7284     }
7285     if (!scaled) {
7286       maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
7287       putBinaryImageMask(maskCanvas.context, img);
7288     }
7289     let maskToCanvas = Util.transform(currentTransform, [1 / width, 0, 0, -1 / height, 0, 0]);
7290     maskToCanvas = Util.transform(maskToCanvas, [1, 0, 0, 1, 0, -height]);
7291     const [minX, minY, maxX, maxY] = Util.getAxialAlignedBoundingBox([0, 0, width, height], maskToCanvas);
7292     const drawnWidth = Math.round(maxX - minX) || 1;
7293     const drawnHeight = Math.round(maxY - minY) || 1;
7294     const fillCanvas = this.cachedCanvases.getCanvas("fillCanvas", drawnWidth, drawnHeight);
7295     const fillCtx = fillCanvas.context;
7296     const offsetX = minX;
7297     const offsetY = minY;
7298     fillCtx.translate(-offsetX, -offsetY);
7299     fillCtx.transform(...maskToCanvas);
7300     if (!scaled) {
7301       scaled = this._scaleImage(maskCanvas.canvas, getCurrentTransformInverse(fillCtx));
7302       scaled = scaled.img;
7303       if (cache && isPatternFill) {
7304         cache.set(cacheKey, scaled);
7305       }
7306     }
7307     fillCtx.imageSmoothingEnabled = getImageSmoothingEnabled(getCurrentTransform(fillCtx), img.interpolate);
7308     drawImageAtIntegerCoords(fillCtx, scaled, 0, 0, scaled.width, scaled.height, 0, 0, width, height);
7309     fillCtx.globalCompositeOperation = "source-in";
7310     const inverse = Util.transform(getCurrentTransformInverse(fillCtx), [1, 0, 0, 1, -offsetX, -offsetY]);
7311     fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx, this, inverse, PathType.FILL) : fillColor;
7312     fillCtx.fillRect(0, 0, width, height);
7313     if (cache && !isPatternFill) {
7314       this.cachedCanvases.delete("fillCanvas");
7315       cache.set(cacheKey, fillCanvas.canvas);
7316     }
7317     return {
7318       canvas: fillCanvas.canvas,
7319       offsetX: Math.round(offsetX),
7320       offsetY: Math.round(offsetY)
7321     };
7322   }
7323   setLineWidth(width) {
7324     if (width !== this.current.lineWidth) {
7325       this._cachedScaleForStroking[0] = -1;
7326     }
7327     this.current.lineWidth = width;
7328     this.ctx.lineWidth = width;
7329   }
7330   setLineCap(style) {
7331     this.ctx.lineCap = LINE_CAP_STYLES[style];
7332   }
7333   setLineJoin(style) {
7334     this.ctx.lineJoin = LINE_JOIN_STYLES[style];
7335   }
7336   setMiterLimit(limit) {
7337     this.ctx.miterLimit = limit;
7338   }
7339   setDash(dashArray, dashPhase) {
7340     const ctx = this.ctx;
7341     if (ctx.setLineDash !== undefined) {
7342       ctx.setLineDash(dashArray);
7343       ctx.lineDashOffset = dashPhase;
7344     }
7345   }
7346   setRenderingIntent(intent) {}
7347   setFlatness(flatness) {}
7348   setGState(states) {
7349     for (const [key, value] of states) {
7350       switch (key) {
7351         case "LW":
7352           this.setLineWidth(value);
7353           break;
7354         case "LC":
7355           this.setLineCap(value);
7356           break;
7357         case "LJ":
7358           this.setLineJoin(value);
7359           break;
7360         case "ML":
7361           this.setMiterLimit(value);
7362           break;
7363         case "D":
7364           this.setDash(value[0], value[1]);
7365           break;
7366         case "RI":
7367           this.setRenderingIntent(value);
7368           break;
7369         case "FL":
7370           this.setFlatness(value);
7371           break;
7372         case "Font":
7373           this.setFont(value[0], value[1]);
7374           break;
7375         case "CA":
7376           this.current.strokeAlpha = value;
7377           break;
7378         case "ca":
7379           this.current.fillAlpha = value;
7380           this.ctx.globalAlpha = value;
7381           break;
7382         case "BM":
7383           this.ctx.globalCompositeOperation = value;
7384           break;
7385         case "SMask":
7386           this.current.activeSMask = value ? this.tempSMask : null;
7387           this.tempSMask = null;
7388           this.checkSMaskState();
7389           break;
7390         case "TR":
7391           this.ctx.filter = this.current.transferMaps = this.filterFactory.addFilter(value);
7392           break;
7393       }
7394     }
7395   }
7396   get inSMaskMode() {
7397     return !!this.suspendedCtx;
7398   }
7399   checkSMaskState() {
7400     const inSMaskMode = this.inSMaskMode;
7401     if (this.current.activeSMask && !inSMaskMode) {
7402       this.beginSMaskMode();
7403     } else if (!this.current.activeSMask && inSMaskMode) {
7404       this.endSMaskMode();
7405     }
7406   }
7407   beginSMaskMode() {
7408     if (this.inSMaskMode) {
7409       throw new Error("beginSMaskMode called while already in smask mode");
7410     }
7411     const drawnWidth = this.ctx.canvas.width;
7412     const drawnHeight = this.ctx.canvas.height;
7413     const cacheId = "smaskGroupAt" + this.groupLevel;
7414     const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight);
7415     this.suspendedCtx = this.ctx;
7416     this.ctx = scratchCanvas.context;
7417     const ctx = this.ctx;
7418     ctx.setTransform(...getCurrentTransform(this.suspendedCtx));
7419     copyCtxState(this.suspendedCtx, ctx);
7420     mirrorContextOperations(ctx, this.suspendedCtx);
7421     this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
7422   }
7423   endSMaskMode() {
7424     if (!this.inSMaskMode) {
7425       throw new Error("endSMaskMode called while not in smask mode");
7426     }
7427     this.ctx._removeMirroring();
7428     copyCtxState(this.ctx, this.suspendedCtx);
7429     this.ctx = this.suspendedCtx;
7430     this.suspendedCtx = null;
7431   }
7432   compose(dirtyBox) {
7433     if (!this.current.activeSMask) {
7434       return;
7435     }
7436     if (!dirtyBox) {
7437       dirtyBox = [0, 0, this.ctx.canvas.width, this.ctx.canvas.height];
7438     } else {
7439       dirtyBox[0] = Math.floor(dirtyBox[0]);
7440       dirtyBox[1] = Math.floor(dirtyBox[1]);
7441       dirtyBox[2] = Math.ceil(dirtyBox[2]);
7442       dirtyBox[3] = Math.ceil(dirtyBox[3]);
7443     }
7444     const smask = this.current.activeSMask;
7445     const suspendedCtx = this.suspendedCtx;
7446     this.composeSMask(suspendedCtx, smask, this.ctx, dirtyBox);
7447     this.ctx.save();
7448     this.ctx.setTransform(1, 0, 0, 1, 0, 0);
7449     this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
7450     this.ctx.restore();
7451   }
7452   composeSMask(ctx, smask, layerCtx, layerBox) {
7453     const layerOffsetX = layerBox[0];
7454     const layerOffsetY = layerBox[1];
7455     const layerWidth = layerBox[2] - layerOffsetX;
7456     const layerHeight = layerBox[3] - layerOffsetY;
7457     if (layerWidth === 0 || layerHeight === 0) {
7458       return;
7459     }
7460     this.genericComposeSMask(smask.context, layerCtx, layerWidth, layerHeight, smask.subtype, smask.backdrop, smask.transferMap, layerOffsetX, layerOffsetY, smask.offsetX, smask.offsetY);
7461     ctx.save();
7462     ctx.globalAlpha = 1;
7463     ctx.globalCompositeOperation = "source-over";
7464     ctx.setTransform(1, 0, 0, 1, 0, 0);
7465     ctx.drawImage(layerCtx.canvas, 0, 0);
7466     ctx.restore();
7467   }
7468   genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop, transferMap, layerOffsetX, layerOffsetY, maskOffsetX, maskOffsetY) {
7469     let maskCanvas = maskCtx.canvas;
7470     let maskX = layerOffsetX - maskOffsetX;
7471     let maskY = layerOffsetY - maskOffsetY;
7472     if (backdrop) {
7473       const backdropRGB = Util.makeHexColor(...backdrop);
7474       if (maskX < 0 || maskY < 0 || maskX + width > maskCanvas.width || maskY + height > maskCanvas.height) {
7475         const canvas = this.cachedCanvases.getCanvas("maskExtension", width, height);
7476         const ctx = canvas.context;
7477         ctx.drawImage(maskCanvas, -maskX, -maskY);
7478         ctx.globalCompositeOperation = "destination-atop";
7479         ctx.fillStyle = backdropRGB;
7480         ctx.fillRect(0, 0, width, height);
7481         ctx.globalCompositeOperation = "source-over";
7482         maskCanvas = canvas.canvas;
7483         maskX = maskY = 0;
7484       } else {
7485         maskCtx.save();
7486         maskCtx.globalAlpha = 1;
7487         maskCtx.setTransform(1, 0, 0, 1, 0, 0);
7488         const clip = new Path2D();
7489         clip.rect(maskX, maskY, width, height);
7490         maskCtx.clip(clip);
7491         maskCtx.globalCompositeOperation = "destination-atop";
7492         maskCtx.fillStyle = backdropRGB;
7493         maskCtx.fillRect(maskX, maskY, width, height);
7494         maskCtx.restore();
7495       }
7496     }
7497     layerCtx.save();
7498     layerCtx.globalAlpha = 1;
7499     layerCtx.setTransform(1, 0, 0, 1, 0, 0);
7500     if (subtype === "Alpha" && transferMap) {
7501       layerCtx.filter = this.filterFactory.addAlphaFilter(transferMap);
7502     } else if (subtype === "Luminosity") {
7503       layerCtx.filter = this.filterFactory.addLuminosityFilter(transferMap);
7504     }
7505     const clip = new Path2D();
7506     clip.rect(layerOffsetX, layerOffsetY, width, height);
7507     layerCtx.clip(clip);
7508     layerCtx.globalCompositeOperation = "destination-in";
7509     layerCtx.drawImage(maskCanvas, maskX, maskY, width, height, layerOffsetX, layerOffsetY, width, height);
7510     layerCtx.restore();
7511   }
7512   save() {
7513     if (this.inSMaskMode) {
7514       copyCtxState(this.ctx, this.suspendedCtx);
7515       this.suspendedCtx.save();
7516     } else {
7517       this.ctx.save();
7518     }
7519     const old = this.current;
7520     this.stateStack.push(old);
7521     this.current = old.clone();
7522   }
7523   restore() {
7524     if (this.stateStack.length === 0 && this.inSMaskMode) {
7525       this.endSMaskMode();
7526     }
7527     if (this.stateStack.length !== 0) {
7528       this.current = this.stateStack.pop();
7529       if (this.inSMaskMode) {
7530         this.suspendedCtx.restore();
7531         copyCtxState(this.suspendedCtx, this.ctx);
7532       } else {
7533         this.ctx.restore();
7534       }
7535       this.checkSMaskState();
7536       this.pendingClip = null;
7537       this._cachedScaleForStroking[0] = -1;
7538       this._cachedGetSinglePixelWidth = null;
7539     }
7540   }
7541   transform(a, b, c, d, e, f) {
7542     this.ctx.transform(a, b, c, d, e, f);
7543     this._cachedScaleForStroking[0] = -1;
7544     this._cachedGetSinglePixelWidth = null;
7545   }
7546   constructPath(ops, args, minMax) {
7547     const ctx = this.ctx;
7548     const current = this.current;
7549     let x = current.x,
7550       y = current.y;
7551     let startX, startY;
7552     const currentTransform = getCurrentTransform(ctx);
7553     const isScalingMatrix = currentTransform[0] === 0 && currentTransform[3] === 0 || currentTransform[1] === 0 && currentTransform[2] === 0;
7554     const minMaxForBezier = isScalingMatrix ? minMax.slice(0) : null;
7555     for (let i = 0, j = 0, ii = ops.length; i < ii; i++) {
7556       switch (ops[i] | 0) {
7557         case OPS.rectangle:
7558           x = args[j++];
7559           y = args[j++];
7560           const width = args[j++];
7561           const height = args[j++];
7562           const xw = x + width;
7563           const yh = y + height;
7564           ctx.moveTo(x, y);
7565           if (width === 0 || height === 0) {
7566             ctx.lineTo(xw, yh);
7567           } else {
7568             ctx.lineTo(xw, y);
7569             ctx.lineTo(xw, yh);
7570             ctx.lineTo(x, yh);
7571           }
7572           if (!isScalingMatrix) {
7573             current.updateRectMinMax(currentTransform, [x, y, xw, yh]);
7574           }
7575           ctx.closePath();
7576           break;
7577         case OPS.moveTo:
7578           x = args[j++];
7579           y = args[j++];
7580           ctx.moveTo(x, y);
7581           if (!isScalingMatrix) {
7582             current.updatePathMinMax(currentTransform, x, y);
7583           }
7584           break;
7585         case OPS.lineTo:
7586           x = args[j++];
7587           y = args[j++];
7588           ctx.lineTo(x, y);
7589           if (!isScalingMatrix) {
7590             current.updatePathMinMax(currentTransform, x, y);
7591           }
7592           break;
7593         case OPS.curveTo:
7594           startX = x;
7595           startY = y;
7596           x = args[j + 4];
7597           y = args[j + 5];
7598           ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y);
7599           current.updateCurvePathMinMax(currentTransform, startX, startY, args[j], args[j + 1], args[j + 2], args[j + 3], x, y, minMaxForBezier);
7600           j += 6;
7601           break;
7602         case OPS.curveTo2:
7603           startX = x;
7604           startY = y;
7605           ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]);
7606           current.updateCurvePathMinMax(currentTransform, startX, startY, x, y, args[j], args[j + 1], args[j + 2], args[j + 3], minMaxForBezier);
7607           x = args[j + 2];
7608           y = args[j + 3];
7609           j += 4;
7610           break;
7611         case OPS.curveTo3:
7612           startX = x;
7613           startY = y;
7614           x = args[j + 2];
7615           y = args[j + 3];
7616           ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
7617           current.updateCurvePathMinMax(currentTransform, startX, startY, args[j], args[j + 1], x, y, x, y, minMaxForBezier);
7618           j += 4;
7619           break;
7620         case OPS.closePath:
7621           ctx.closePath();
7622           break;
7623       }
7624     }
7625     if (isScalingMatrix) {
7626       current.updateScalingPathMinMax(currentTransform, minMaxForBezier);
7627     }
7628     current.setCurrentPoint(x, y);
7629   }
7630   closePath() {
7631     this.ctx.closePath();
7632   }
7633   stroke(consumePath = true) {
7634     const ctx = this.ctx;
7635     const strokeColor = this.current.strokeColor;
7636     ctx.globalAlpha = this.current.strokeAlpha;
7637     if (this.contentVisible) {
7638       if (typeof strokeColor === "object" && strokeColor?.getPattern) {
7639         ctx.save();
7640         ctx.strokeStyle = strokeColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.STROKE);
7641         this.rescaleAndStroke(false);
7642         ctx.restore();
7643       } else {
7644         this.rescaleAndStroke(true);
7645       }
7646     }
7647     if (consumePath) {
7648       this.consumePath(this.current.getClippedPathBoundingBox());
7649     }
7650     ctx.globalAlpha = this.current.fillAlpha;
7651   }
7652   closeStroke() {
7653     this.closePath();
7654     this.stroke();
7655   }
7656   fill(consumePath = true) {
7657     const ctx = this.ctx;
7658     const fillColor = this.current.fillColor;
7659     const isPatternFill = this.current.patternFill;
7660     let needRestore = false;
7661     if (isPatternFill) {
7662       ctx.save();
7663       ctx.fillStyle = fillColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.FILL);
7664       needRestore = true;
7665     }
7666     const intersect = this.current.getClippedPathBoundingBox();
7667     if (this.contentVisible && intersect !== null) {
7668       if (this.pendingEOFill) {
7669         ctx.fill("evenodd");
7670         this.pendingEOFill = false;
7671       } else {
7672         ctx.fill();
7673       }
7674     }
7675     if (needRestore) {
7676       ctx.restore();
7677     }
7678     if (consumePath) {
7679       this.consumePath(intersect);
7680     }
7681   }
7682   eoFill() {
7683     this.pendingEOFill = true;
7684     this.fill();
7685   }
7686   fillStroke() {
7687     this.fill(false);
7688     this.stroke(false);
7689     this.consumePath();
7690   }
7691   eoFillStroke() {
7692     this.pendingEOFill = true;
7693     this.fillStroke();
7694   }
7695   closeFillStroke() {
7696     this.closePath();
7697     this.fillStroke();
7698   }
7699   closeEOFillStroke() {
7700     this.pendingEOFill = true;
7701     this.closePath();
7702     this.fillStroke();
7703   }
7704   endPath() {
7705     this.consumePath();
7706   }
7707   clip() {
7708     this.pendingClip = NORMAL_CLIP;
7709   }
7710   eoClip() {
7711     this.pendingClip = EO_CLIP;
7712   }
7713   beginText() {
7714     this.current.textMatrix = IDENTITY_MATRIX;
7715     this.current.textMatrixScale = 1;
7716     this.current.x = this.current.lineX = 0;
7717     this.current.y = this.current.lineY = 0;
7718   }
7719   endText() {
7720     const paths = this.pendingTextPaths;
7721     const ctx = this.ctx;
7722     if (paths === undefined) {
7723       ctx.beginPath();
7724       return;
7725     }
7726     const newPath = new Path2D();
7727     const invTransf = ctx.getTransform().invertSelf();
7728     for (const {
7729       transform,
7730       x,
7731       y,
7732       fontSize,
7733       path
7734     } of paths) {
7735       newPath.addPath(path, new DOMMatrix(transform).preMultiplySelf(invTransf).translate(x, y).scale(fontSize, -fontSize));
7736     }
7737     ctx.clip(newPath);
7738     ctx.beginPath();
7739     delete this.pendingTextPaths;
7740   }
7741   setCharSpacing(spacing) {
7742     this.current.charSpacing = spacing;
7743   }
7744   setWordSpacing(spacing) {
7745     this.current.wordSpacing = spacing;
7746   }
7747   setHScale(scale) {
7748     this.current.textHScale = scale / 100;
7749   }
7750   setLeading(leading) {
7751     this.current.leading = -leading;
7752   }
7753   setFont(fontRefName, size) {
7754     const fontObj = this.commonObjs.get(fontRefName);
7755     const current = this.current;
7756     if (!fontObj) {
7757       throw new Error(`Can't find font for ${fontRefName}`);
7758     }
7759     current.fontMatrix = fontObj.fontMatrix || FONT_IDENTITY_MATRIX;
7760     if (current.fontMatrix[0] === 0 || current.fontMatrix[3] === 0) {
7761       warn("Invalid font matrix for font " + fontRefName);
7762     }
7763     if (size < 0) {
7764       size = -size;
7765       current.fontDirection = -1;
7766     } else {
7767       current.fontDirection = 1;
7768     }
7769     this.current.font = fontObj;
7770     this.current.fontSize = size;
7771     if (fontObj.isType3Font) {
7772       return;
7773     }
7774     const name = fontObj.loadedName || "sans-serif";
7775     const typeface = fontObj.systemFontInfo?.css || `"${name}", ${fontObj.fallbackName}`;
7776     let bold = "normal";
7777     if (fontObj.black) {
7778       bold = "900";
7779     } else if (fontObj.bold) {
7780       bold = "bold";
7781     }
7782     const italic = fontObj.italic ? "italic" : "normal";
7783     let browserFontSize = size;
7784     if (size < MIN_FONT_SIZE) {
7785       browserFontSize = MIN_FONT_SIZE;
7786     } else if (size > MAX_FONT_SIZE) {
7787       browserFontSize = MAX_FONT_SIZE;
7788     }
7789     this.current.fontSizeScale = size / browserFontSize;
7790     this.ctx.font = `${italic} ${bold} ${browserFontSize}px ${typeface}`;
7791   }
7792   setTextRenderingMode(mode) {
7793     this.current.textRenderingMode = mode;
7794   }
7795   setTextRise(rise) {
7796     this.current.textRise = rise;
7797   }
7798   moveText(x, y) {
7799     this.current.x = this.current.lineX += x;
7800     this.current.y = this.current.lineY += y;
7801   }
7802   setLeadingMoveText(x, y) {
7803     this.setLeading(-y);
7804     this.moveText(x, y);
7805   }
7806   setTextMatrix(a, b, c, d, e, f) {
7807     this.current.textMatrix = [a, b, c, d, e, f];
7808     this.current.textMatrixScale = Math.hypot(a, b);
7809     this.current.x = this.current.lineX = 0;
7810     this.current.y = this.current.lineY = 0;
7811   }
7812   nextLine() {
7813     this.moveText(0, this.current.leading);
7814   }
7815   #getScaledPath(path, currentTransform, transform) {
7816     const newPath = new Path2D();
7817     newPath.addPath(path, new DOMMatrix(transform).invertSelf().multiplySelf(currentTransform));
7818     return newPath;
7819   }
7820   paintChar(character, x, y, patternFillTransform, patternStrokeTransform) {
7821     const ctx = this.ctx;
7822     const current = this.current;
7823     const font = current.font;
7824     const textRenderingMode = current.textRenderingMode;
7825     const fontSize = current.fontSize / current.fontSizeScale;
7826     const fillStrokeMode = textRenderingMode & TextRenderingMode.FILL_STROKE_MASK;
7827     const isAddToPathSet = !!(textRenderingMode & TextRenderingMode.ADD_TO_PATH_FLAG);
7828     const patternFill = current.patternFill && !font.missingFile;
7829     const patternStroke = current.patternStroke && !font.missingFile;
7830     let path;
7831     if (font.disableFontFace || isAddToPathSet || patternFill || patternStroke) {
7832       path = font.getPathGenerator(this.commonObjs, character);
7833     }
7834     if (font.disableFontFace || patternFill || patternStroke) {
7835       ctx.save();
7836       ctx.translate(x, y);
7837       ctx.scale(fontSize, -fontSize);
7838       let currentTransform;
7839       if (fillStrokeMode === TextRenderingMode.FILL || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
7840         if (patternFillTransform) {
7841           currentTransform = ctx.getTransform();
7842           ctx.setTransform(...patternFillTransform);
7843           ctx.fill(this.#getScaledPath(path, currentTransform, patternFillTransform));
7844         } else {
7845           ctx.fill(path);
7846         }
7847       }
7848       if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
7849         if (patternStrokeTransform) {
7850           currentTransform ||= ctx.getTransform();
7851           ctx.setTransform(...patternStrokeTransform);
7852           const {
7853             a,
7854             b,
7855             c,
7856             d
7857           } = currentTransform;
7858           const invPatternTransform = Util.inverseTransform(patternStrokeTransform);
7859           const transf = Util.transform([a, b, c, d, 0, 0], invPatternTransform);
7860           const [sx, sy] = Util.singularValueDecompose2dScale(transf);
7861           ctx.lineWidth *= Math.max(sx, sy) / fontSize;
7862           ctx.stroke(this.#getScaledPath(path, currentTransform, patternStrokeTransform));
7863         } else {
7864           ctx.lineWidth /= fontSize;
7865           ctx.stroke(path);
7866         }
7867       }
7868       ctx.restore();
7869     } else {
7870       if (fillStrokeMode === TextRenderingMode.FILL || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
7871         ctx.fillText(character, x, y);
7872       }
7873       if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
7874         ctx.strokeText(character, x, y);
7875       }
7876     }
7877     if (isAddToPathSet) {
7878       const paths = this.pendingTextPaths ||= [];
7879       paths.push({
7880         transform: getCurrentTransform(ctx),
7881         x,
7882         y,
7883         fontSize,
7884         path
7885       });
7886     }
7887   }
7888   get isFontSubpixelAAEnabled() {
7889     const {
7890       context: ctx
7891     } = this.cachedCanvases.getCanvas("isFontSubpixelAAEnabled", 10, 10);
7892     ctx.scale(1.5, 1);
7893     ctx.fillText("I", 0, 10);
7894     const data = ctx.getImageData(0, 0, 10, 10).data;
7895     let enabled = false;
7896     for (let i = 3; i < data.length; i += 4) {
7897       if (data[i] > 0 && data[i] < 255) {
7898         enabled = true;
7899         break;
7900       }
7901     }
7902     return shadow(this, "isFontSubpixelAAEnabled", enabled);
7903   }
7904   showText(glyphs) {
7905     const current = this.current;
7906     const font = current.font;
7907     if (font.isType3Font) {
7908       return this.showType3Text(glyphs);
7909     }
7910     const fontSize = current.fontSize;
7911     if (fontSize === 0) {
7912       return undefined;
7913     }
7914     const ctx = this.ctx;
7915     const fontSizeScale = current.fontSizeScale;
7916     const charSpacing = current.charSpacing;
7917     const wordSpacing = current.wordSpacing;
7918     const fontDirection = current.fontDirection;
7919     const textHScale = current.textHScale * fontDirection;
7920     const glyphsLength = glyphs.length;
7921     const vertical = font.vertical;
7922     const spacingDir = vertical ? 1 : -1;
7923     const defaultVMetrics = font.defaultVMetrics;
7924     const widthAdvanceScale = fontSize * current.fontMatrix[0];
7925     const simpleFillText = current.textRenderingMode === TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill;
7926     ctx.save();
7927     ctx.transform(...current.textMatrix);
7928     ctx.translate(current.x, current.y + current.textRise);
7929     if (fontDirection > 0) {
7930       ctx.scale(textHScale, -1);
7931     } else {
7932       ctx.scale(textHScale, 1);
7933     }
7934     let patternFillTransform, patternStrokeTransform;
7935     if (current.patternFill) {
7936       ctx.save();
7937       const pattern = current.fillColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.FILL);
7938       patternFillTransform = getCurrentTransform(ctx);
7939       ctx.restore();
7940       ctx.fillStyle = pattern;
7941     }
7942     if (current.patternStroke) {
7943       ctx.save();
7944       const pattern = current.strokeColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.STROKE);
7945       patternStrokeTransform = getCurrentTransform(ctx);
7946       ctx.restore();
7947       ctx.strokeStyle = pattern;
7948     }
7949     let lineWidth = current.lineWidth;
7950     const scale = current.textMatrixScale;
7951     if (scale === 0 || lineWidth === 0) {
7952       const fillStrokeMode = current.textRenderingMode & TextRenderingMode.FILL_STROKE_MASK;
7953       if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
7954         lineWidth = this.getSinglePixelWidth();
7955       }
7956     } else {
7957       lineWidth /= scale;
7958     }
7959     if (fontSizeScale !== 1.0) {
7960       ctx.scale(fontSizeScale, fontSizeScale);
7961       lineWidth /= fontSizeScale;
7962     }
7963     ctx.lineWidth = lineWidth;
7964     if (font.isInvalidPDFjsFont) {
7965       const chars = [];
7966       let width = 0;
7967       for (const glyph of glyphs) {
7968         chars.push(glyph.unicode);
7969         width += glyph.width;
7970       }
7971       ctx.fillText(chars.join(""), 0, 0);
7972       current.x += width * widthAdvanceScale * textHScale;
7973       ctx.restore();
7974       this.compose();
7975       return undefined;
7976     }
7977     let x = 0,
7978       i;
7979     for (i = 0; i < glyphsLength; ++i) {
7980       const glyph = glyphs[i];
7981       if (typeof glyph === "number") {
7982         x += spacingDir * glyph * fontSize / 1000;
7983         continue;
7984       }
7985       let restoreNeeded = false;
7986       const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
7987       const character = glyph.fontChar;
7988       const accent = glyph.accent;
7989       let scaledX, scaledY;
7990       let width = glyph.width;
7991       if (vertical) {
7992         const vmetric = glyph.vmetric || defaultVMetrics;
7993         const vx = -(glyph.vmetric ? vmetric[1] : width * 0.5) * widthAdvanceScale;
7994         const vy = vmetric[2] * widthAdvanceScale;
7995         width = vmetric ? -vmetric[0] : width;
7996         scaledX = vx / fontSizeScale;
7997         scaledY = (x + vy) / fontSizeScale;
7998       } else {
7999         scaledX = x / fontSizeScale;
8000         scaledY = 0;
8001       }
8002       if (font.remeasure && width > 0) {
8003         const measuredWidth = ctx.measureText(character).width * 1000 / fontSize * fontSizeScale;
8004         if (width < measuredWidth && this.isFontSubpixelAAEnabled) {
8005           const characterScaleX = width / measuredWidth;
8006           restoreNeeded = true;
8007           ctx.save();
8008           ctx.scale(characterScaleX, 1);
8009           scaledX /= characterScaleX;
8010         } else if (width !== measuredWidth) {
8011           scaledX += (width - measuredWidth) / 2000 * fontSize / fontSizeScale;
8012         }
8013       }
8014       if (this.contentVisible && (glyph.isInFont || font.missingFile)) {
8015         if (simpleFillText && !accent) {
8016           ctx.fillText(character, scaledX, scaledY);
8017         } else {
8018           this.paintChar(character, scaledX, scaledY, patternFillTransform, patternStrokeTransform);
8019           if (accent) {
8020             const scaledAccentX = scaledX + fontSize * accent.offset.x / fontSizeScale;
8021             const scaledAccentY = scaledY - fontSize * accent.offset.y / fontSizeScale;
8022             this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY, patternFillTransform, patternStrokeTransform);
8023           }
8024         }
8025       }
8026       const charWidth = vertical ? width * widthAdvanceScale - spacing * fontDirection : width * widthAdvanceScale + spacing * fontDirection;
8027       x += charWidth;
8028       if (restoreNeeded) {
8029         ctx.restore();
8030       }
8031     }
8032     if (vertical) {
8033       current.y -= x;
8034     } else {
8035       current.x += x * textHScale;
8036     }
8037     ctx.restore();
8038     this.compose();
8039     return undefined;
8040   }
8041   showType3Text(glyphs) {
8042     const ctx = this.ctx;
8043     const current = this.current;
8044     const font = current.font;
8045     const fontSize = current.fontSize;
8046     const fontDirection = current.fontDirection;
8047     const spacingDir = font.vertical ? 1 : -1;
8048     const charSpacing = current.charSpacing;
8049     const wordSpacing = current.wordSpacing;
8050     const textHScale = current.textHScale * fontDirection;
8051     const fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
8052     const glyphsLength = glyphs.length;
8053     const isTextInvisible = current.textRenderingMode === TextRenderingMode.INVISIBLE;
8054     let i, glyph, width, spacingLength;
8055     if (isTextInvisible || fontSize === 0) {
8056       return;
8057     }
8058     this._cachedScaleForStroking[0] = -1;
8059     this._cachedGetSinglePixelWidth = null;
8060     ctx.save();
8061     ctx.transform(...current.textMatrix);
8062     ctx.translate(current.x, current.y);
8063     ctx.scale(textHScale, fontDirection);
8064     for (i = 0; i < glyphsLength; ++i) {
8065       glyph = glyphs[i];
8066       if (typeof glyph === "number") {
8067         spacingLength = spacingDir * glyph * fontSize / 1000;
8068         this.ctx.translate(spacingLength, 0);
8069         current.x += spacingLength * textHScale;
8070         continue;
8071       }
8072       const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
8073       const operatorList = font.charProcOperatorList[glyph.operatorListId];
8074       if (!operatorList) {
8075         warn(`Type3 character "${glyph.operatorListId}" is not available.`);
8076         continue;
8077       }
8078       if (this.contentVisible) {
8079         this.processingType3 = glyph;
8080         this.save();
8081         ctx.scale(fontSize, fontSize);
8082         ctx.transform(...fontMatrix);
8083         this.executeOperatorList(operatorList);
8084         this.restore();
8085       }
8086       const transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
8087       width = transformed[0] * fontSize + spacing;
8088       ctx.translate(width, 0);
8089       current.x += width * textHScale;
8090     }
8091     ctx.restore();
8092     this.processingType3 = null;
8093   }
8094   setCharWidth(xWidth, yWidth) {}
8095   setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) {
8096     this.ctx.rect(llx, lly, urx - llx, ury - lly);
8097     this.ctx.clip();
8098     this.endPath();
8099   }
8100   getColorN_Pattern(IR) {
8101     let pattern;
8102     if (IR[0] === "TilingPattern") {
8103       const color = IR[1];
8104       const baseTransform = this.baseTransform || getCurrentTransform(this.ctx);
8105       const canvasGraphicsFactory = {
8106         createCanvasGraphics: ctx => new CanvasGraphics(ctx, this.commonObjs, this.objs, this.canvasFactory, this.filterFactory, {
8107           optionalContentConfig: this.optionalContentConfig,
8108           markedContentStack: this.markedContentStack
8109         })
8110       };
8111       pattern = new TilingPattern(IR, color, this.ctx, canvasGraphicsFactory, baseTransform);
8112     } else {
8113       pattern = this._getPattern(IR[1], IR[2]);
8114     }
8115     return pattern;
8116   }
8117   setStrokeColorN() {
8118     this.current.strokeColor = this.getColorN_Pattern(arguments);
8119     this.current.patternStroke = true;
8120   }
8121   setFillColorN() {
8122     this.current.fillColor = this.getColorN_Pattern(arguments);
8123     this.current.patternFill = true;
8124   }
8125   setStrokeRGBColor(r, g, b) {
8126     this.ctx.strokeStyle = this.current.strokeColor = Util.makeHexColor(r, g, b);
8127     this.current.patternStroke = false;
8128   }
8129   setStrokeTransparent() {
8130     this.ctx.strokeStyle = this.current.strokeColor = "transparent";
8131     this.current.patternStroke = false;
8132   }
8133   setFillRGBColor(r, g, b) {
8134     this.ctx.fillStyle = this.current.fillColor = Util.makeHexColor(r, g, b);
8135     this.current.patternFill = false;
8136   }
8137   setFillTransparent() {
8138     this.ctx.fillStyle = this.current.fillColor = "transparent";
8139     this.current.patternFill = false;
8140   }
8141   _getPattern(objId, matrix = null) {
8142     let pattern;
8143     if (this.cachedPatterns.has(objId)) {
8144       pattern = this.cachedPatterns.get(objId);
8145     } else {
8146       pattern = getShadingPattern(this.getObject(objId));
8147       this.cachedPatterns.set(objId, pattern);
8148     }
8149     if (matrix) {
8150       pattern.matrix = matrix;
8151     }
8152     return pattern;
8153   }
8154   shadingFill(objId) {
8155     if (!this.contentVisible) {
8156       return;
8157     }
8158     const ctx = this.ctx;
8159     this.save();
8160     const pattern = this._getPattern(objId);
8161     ctx.fillStyle = pattern.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.SHADING);
8162     const inv = getCurrentTransformInverse(ctx);
8163     if (inv) {
8164       const {
8165         width,
8166         height
8167       } = ctx.canvas;
8168       const [x0, y0, x1, y1] = Util.getAxialAlignedBoundingBox([0, 0, width, height], inv);
8169       this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
8170     } else {
8171       this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
8172     }
8173     this.compose(this.current.getClippedPathBoundingBox());
8174     this.restore();
8175   }
8176   beginInlineImage() {
8177     unreachable("Should not call beginInlineImage");
8178   }
8179   beginImageData() {
8180     unreachable("Should not call beginImageData");
8181   }
8182   paintFormXObjectBegin(matrix, bbox) {
8183     if (!this.contentVisible) {
8184       return;
8185     }
8186     this.save();
8187     this.baseTransformStack.push(this.baseTransform);
8188     if (matrix) {
8189       this.transform(...matrix);
8190     }
8191     this.baseTransform = getCurrentTransform(this.ctx);
8192     if (bbox) {
8193       const width = bbox[2] - bbox[0];
8194       const height = bbox[3] - bbox[1];
8195       this.ctx.rect(bbox[0], bbox[1], width, height);
8196       this.current.updateRectMinMax(getCurrentTransform(this.ctx), bbox);
8197       this.clip();
8198       this.endPath();
8199     }
8200   }
8201   paintFormXObjectEnd() {
8202     if (!this.contentVisible) {
8203       return;
8204     }
8205     this.restore();
8206     this.baseTransform = this.baseTransformStack.pop();
8207   }
8208   beginGroup(group) {
8209     if (!this.contentVisible) {
8210       return;
8211     }
8212     this.save();
8213     if (this.inSMaskMode) {
8214       this.endSMaskMode();
8215       this.current.activeSMask = null;
8216     }
8217     const currentCtx = this.ctx;
8218     if (!group.isolated) {
8219       info("TODO: Support non-isolated groups.");
8220     }
8221     if (group.knockout) {
8222       warn("Knockout groups not supported.");
8223     }
8224     const currentTransform = getCurrentTransform(currentCtx);
8225     if (group.matrix) {
8226       currentCtx.transform(...group.matrix);
8227     }
8228     if (!group.bbox) {
8229       throw new Error("Bounding box is required.");
8230     }
8231     let bounds = Util.getAxialAlignedBoundingBox(group.bbox, getCurrentTransform(currentCtx));
8232     const canvasBounds = [0, 0, currentCtx.canvas.width, currentCtx.canvas.height];
8233     bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
8234     const offsetX = Math.floor(bounds[0]);
8235     const offsetY = Math.floor(bounds[1]);
8236     const drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
8237     const drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
8238     this.current.startNewPathAndClipBox([0, 0, drawnWidth, drawnHeight]);
8239     let cacheId = "groupAt" + this.groupLevel;
8240     if (group.smask) {
8241       cacheId += "_smask_" + this.smaskCounter++ % 2;
8242     }
8243     const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight);
8244     const groupCtx = scratchCanvas.context;
8245     groupCtx.translate(-offsetX, -offsetY);
8246     groupCtx.transform(...currentTransform);
8247     if (group.smask) {
8248       this.smaskStack.push({
8249         canvas: scratchCanvas.canvas,
8250         context: groupCtx,
8251         offsetX,
8252         offsetY,
8253         subtype: group.smask.subtype,
8254         backdrop: group.smask.backdrop,
8255         transferMap: group.smask.transferMap || null,
8256         startTransformInverse: null
8257       });
8258     } else {
8259       currentCtx.setTransform(1, 0, 0, 1, 0, 0);
8260       currentCtx.translate(offsetX, offsetY);
8261       currentCtx.save();
8262     }
8263     copyCtxState(currentCtx, groupCtx);
8264     this.ctx = groupCtx;
8265     this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
8266     this.groupStack.push(currentCtx);
8267     this.groupLevel++;
8268   }
8269   endGroup(group) {
8270     if (!this.contentVisible) {
8271       return;
8272     }
8273     this.groupLevel--;
8274     const groupCtx = this.ctx;
8275     const ctx = this.groupStack.pop();
8276     this.ctx = ctx;
8277     this.ctx.imageSmoothingEnabled = false;
8278     if (group.smask) {
8279       this.tempSMask = this.smaskStack.pop();
8280       this.restore();
8281     } else {
8282       this.ctx.restore();
8283       const currentMtx = getCurrentTransform(this.ctx);
8284       this.restore();
8285       this.ctx.save();
8286       this.ctx.setTransform(...currentMtx);
8287       const dirtyBox = Util.getAxialAlignedBoundingBox([0, 0, groupCtx.canvas.width, groupCtx.canvas.height], currentMtx);
8288       this.ctx.drawImage(groupCtx.canvas, 0, 0);
8289       this.ctx.restore();
8290       this.compose(dirtyBox);
8291     }
8292   }
8293   beginAnnotation(id, rect, transform, matrix, hasOwnCanvas) {
8294     this.#restoreInitialState();
8295     resetCtxToDefault(this.ctx);
8296     this.ctx.save();
8297     this.save();
8298     if (this.baseTransform) {
8299       this.ctx.setTransform(...this.baseTransform);
8300     }
8301     if (rect) {
8302       const width = rect[2] - rect[0];
8303       const height = rect[3] - rect[1];
8304       if (hasOwnCanvas && this.annotationCanvasMap) {
8305         transform = transform.slice();
8306         transform[4] -= rect[0];
8307         transform[5] -= rect[1];
8308         rect = rect.slice();
8309         rect[0] = rect[1] = 0;
8310         rect[2] = width;
8311         rect[3] = height;
8312         const [scaleX, scaleY] = Util.singularValueDecompose2dScale(getCurrentTransform(this.ctx));
8313         const {
8314           viewportScale
8315         } = this;
8316         const canvasWidth = Math.ceil(width * this.outputScaleX * viewportScale);
8317         const canvasHeight = Math.ceil(height * this.outputScaleY * viewportScale);
8318         this.annotationCanvas = this.canvasFactory.create(canvasWidth, canvasHeight);
8319         const {
8320           canvas,
8321           context
8322         } = this.annotationCanvas;
8323         this.annotationCanvasMap.set(id, canvas);
8324         this.annotationCanvas.savedCtx = this.ctx;
8325         this.ctx = context;
8326         this.ctx.save();
8327         this.ctx.setTransform(scaleX, 0, 0, -scaleY, 0, height * scaleY);
8328         resetCtxToDefault(this.ctx);
8329       } else {
8330         resetCtxToDefault(this.ctx);
8331         this.endPath();
8332         this.ctx.rect(rect[0], rect[1], width, height);
8333         this.ctx.clip();
8334         this.ctx.beginPath();
8335       }
8336     }
8337     this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height);
8338     this.transform(...transform);
8339     this.transform(...matrix);
8340   }
8341   endAnnotation() {
8342     if (this.annotationCanvas) {
8343       this.ctx.restore();
8344       this.#drawFilter();
8345       this.ctx = this.annotationCanvas.savedCtx;
8346       delete this.annotationCanvas.savedCtx;
8347       delete this.annotationCanvas;
8348     }
8349   }
8350   paintImageMaskXObject(img) {
8351     if (!this.contentVisible) {
8352       return;
8353     }
8354     const count = img.count;
8355     img = this.getObject(img.data, img);
8356     img.count = count;
8357     const ctx = this.ctx;
8358     const glyph = this.processingType3;
8359     if (glyph) {
8360       if (glyph.compiled === undefined) {
8361         glyph.compiled = compileType3Glyph(img);
8362       }
8363       if (glyph.compiled) {
8364         glyph.compiled(ctx);
8365         return;
8366       }
8367     }
8368     const mask = this._createMaskCanvas(img);
8369     const maskCanvas = mask.canvas;
8370     ctx.save();
8371     ctx.setTransform(1, 0, 0, 1, 0, 0);
8372     ctx.drawImage(maskCanvas, mask.offsetX, mask.offsetY);
8373     ctx.restore();
8374     this.compose();
8375   }
8376   paintImageMaskXObjectRepeat(img, scaleX, skewX = 0, skewY = 0, scaleY, positions) {
8377     if (!this.contentVisible) {
8378       return;
8379     }
8380     img = this.getObject(img.data, img);
8381     const ctx = this.ctx;
8382     ctx.save();
8383     const currentTransform = getCurrentTransform(ctx);
8384     ctx.transform(scaleX, skewX, skewY, scaleY, 0, 0);
8385     const mask = this._createMaskCanvas(img);
8386     ctx.setTransform(1, 0, 0, 1, mask.offsetX - currentTransform[4], mask.offsetY - currentTransform[5]);
8387     for (let i = 0, ii = positions.length; i < ii; i += 2) {
8388       const trans = Util.transform(currentTransform, [scaleX, skewX, skewY, scaleY, positions[i], positions[i + 1]]);
8389       const [x, y] = Util.applyTransform([0, 0], trans);
8390       ctx.drawImage(mask.canvas, x, y);
8391     }
8392     ctx.restore();
8393     this.compose();
8394   }
8395   paintImageMaskXObjectGroup(images) {
8396     if (!this.contentVisible) {
8397       return;
8398     }
8399     const ctx = this.ctx;
8400     const fillColor = this.current.fillColor;
8401     const isPatternFill = this.current.patternFill;
8402     for (const image of images) {
8403       const {
8404         data,
8405         width,
8406         height,
8407         transform
8408       } = image;
8409       const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
8410       const maskCtx = maskCanvas.context;
8411       maskCtx.save();
8412       const img = this.getObject(data, image);
8413       putBinaryImageMask(maskCtx, img);
8414       maskCtx.globalCompositeOperation = "source-in";
8415       maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, getCurrentTransformInverse(ctx), PathType.FILL) : fillColor;
8416       maskCtx.fillRect(0, 0, width, height);
8417       maskCtx.restore();
8418       ctx.save();
8419       ctx.transform(...transform);
8420       ctx.scale(1, -1);
8421       drawImageAtIntegerCoords(ctx, maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
8422       ctx.restore();
8423     }
8424     this.compose();
8425   }
8426   paintImageXObject(objId) {
8427     if (!this.contentVisible) {
8428       return;
8429     }
8430     const imgData = this.getObject(objId);
8431     if (!imgData) {
8432       warn("Dependent image isn't ready yet");
8433       return;
8434     }
8435     this.paintInlineImageXObject(imgData);
8436   }
8437   paintImageXObjectRepeat(objId, scaleX, scaleY, positions) {
8438     if (!this.contentVisible) {
8439       return;
8440     }
8441     const imgData = this.getObject(objId);
8442     if (!imgData) {
8443       warn("Dependent image isn't ready yet");
8444       return;
8445     }
8446     const width = imgData.width;
8447     const height = imgData.height;
8448     const map = [];
8449     for (let i = 0, ii = positions.length; i < ii; i += 2) {
8450       map.push({
8451         transform: [scaleX, 0, 0, scaleY, positions[i], positions[i + 1]],
8452         x: 0,
8453         y: 0,
8454         w: width,
8455         h: height
8456       });
8457     }
8458     this.paintInlineImageXObjectGroup(imgData, map);
8459   }
8460   applyTransferMapsToCanvas(ctx) {
8461     if (this.current.transferMaps !== "none") {
8462       ctx.filter = this.current.transferMaps;
8463       ctx.drawImage(ctx.canvas, 0, 0);
8464       ctx.filter = "none";
8465     }
8466     return ctx.canvas;
8467   }
8468   applyTransferMapsToBitmap(imgData) {
8469     if (this.current.transferMaps === "none") {
8470       return imgData.bitmap;
8471     }
8472     const {
8473       bitmap,
8474       width,
8475       height
8476     } = imgData;
8477     const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height);
8478     const tmpCtx = tmpCanvas.context;
8479     tmpCtx.filter = this.current.transferMaps;
8480     tmpCtx.drawImage(bitmap, 0, 0);
8481     tmpCtx.filter = "none";
8482     return tmpCanvas.canvas;
8483   }
8484   paintInlineImageXObject(imgData) {
8485     if (!this.contentVisible) {
8486       return;
8487     }
8488     const width = imgData.width;
8489     const height = imgData.height;
8490     const ctx = this.ctx;
8491     this.save();
8492     const {
8493       filter
8494     } = ctx;
8495     if (filter !== "none" && filter !== "") {
8496       ctx.filter = "none";
8497     }
8498     ctx.scale(1 / width, -1 / height);
8499     let imgToPaint;
8500     if (imgData.bitmap) {
8501       imgToPaint = this.applyTransferMapsToBitmap(imgData);
8502     } else if (typeof HTMLElement === "function" && imgData instanceof HTMLElement || !imgData.data) {
8503       imgToPaint = imgData;
8504     } else {
8505       const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height);
8506       const tmpCtx = tmpCanvas.context;
8507       putBinaryImageData(tmpCtx, imgData);
8508       imgToPaint = this.applyTransferMapsToCanvas(tmpCtx);
8509     }
8510     const scaled = this._scaleImage(imgToPaint, getCurrentTransformInverse(ctx));
8511     ctx.imageSmoothingEnabled = getImageSmoothingEnabled(getCurrentTransform(ctx), imgData.interpolate);
8512     drawImageAtIntegerCoords(ctx, scaled.img, 0, 0, scaled.paintWidth, scaled.paintHeight, 0, -height, width, height);
8513     this.compose();
8514     this.restore();
8515   }
8516   paintInlineImageXObjectGroup(imgData, map) {
8517     if (!this.contentVisible) {
8518       return;
8519     }
8520     const ctx = this.ctx;
8521     let imgToPaint;
8522     if (imgData.bitmap) {
8523       imgToPaint = imgData.bitmap;
8524     } else {
8525       const w = imgData.width;
8526       const h = imgData.height;
8527       const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", w, h);
8528       const tmpCtx = tmpCanvas.context;
8529       putBinaryImageData(tmpCtx, imgData);
8530       imgToPaint = this.applyTransferMapsToCanvas(tmpCtx);
8531     }
8532     for (const entry of map) {
8533       ctx.save();
8534       ctx.transform(...entry.transform);
8535       ctx.scale(1, -1);
8536       drawImageAtIntegerCoords(ctx, imgToPaint, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1);
8537       ctx.restore();
8538     }
8539     this.compose();
8540   }
8541   paintSolidColorImageMask() {
8542     if (!this.contentVisible) {
8543       return;
8544     }
8545     this.ctx.fillRect(0, 0, 1, 1);
8546     this.compose();
8547   }
8548   markPoint(tag) {}
8549   markPointProps(tag, properties) {}
8550   beginMarkedContent(tag) {
8551     this.markedContentStack.push({
8552       visible: true
8553     });
8554   }
8555   beginMarkedContentProps(tag, properties) {
8556     if (tag === "OC") {
8557       this.markedContentStack.push({
8558         visible: this.optionalContentConfig.isVisible(properties)
8559       });
8560     } else {
8561       this.markedContentStack.push({
8562         visible: true
8563       });
8564     }
8565     this.contentVisible = this.isContentVisible();
8566   }
8567   endMarkedContent() {
8568     this.markedContentStack.pop();
8569     this.contentVisible = this.isContentVisible();
8570   }
8571   beginCompat() {}
8572   endCompat() {}
8573   consumePath(clipBox) {
8574     const isEmpty = this.current.isEmptyClip();
8575     if (this.pendingClip) {
8576       this.current.updateClipFromPath();
8577     }
8578     if (!this.pendingClip) {
8579       this.compose(clipBox);
8580     }
8581     const ctx = this.ctx;
8582     if (this.pendingClip) {
8583       if (!isEmpty) {
8584         if (this.pendingClip === EO_CLIP) {
8585           ctx.clip("evenodd");
8586         } else {
8587           ctx.clip();
8588         }
8589       }
8590       this.pendingClip = null;
8591     }
8592     this.current.startNewPathAndClipBox(this.current.clipBox);
8593     ctx.beginPath();
8594   }
8595   getSinglePixelWidth() {
8596     if (!this._cachedGetSinglePixelWidth) {
8597       const m = getCurrentTransform(this.ctx);
8598       if (m[1] === 0 && m[2] === 0) {
8599         this._cachedGetSinglePixelWidth = 1 / Math.min(Math.abs(m[0]), Math.abs(m[3]));
8600       } else {
8601         const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]);
8602         const normX = Math.hypot(m[0], m[2]);
8603         const normY = Math.hypot(m[1], m[3]);
8604         this._cachedGetSinglePixelWidth = Math.max(normX, normY) / absDet;
8605       }
8606     }
8607     return this._cachedGetSinglePixelWidth;
8608   }
8609   getScaleForStroking() {
8610     if (this._cachedScaleForStroking[0] === -1) {
8611       const {
8612         lineWidth
8613       } = this.current;
8614       const {
8615         a,
8616         b,
8617         c,
8618         d
8619       } = this.ctx.getTransform();
8620       let scaleX, scaleY;
8621       if (b === 0 && c === 0) {
8622         const normX = Math.abs(a);
8623         const normY = Math.abs(d);
8624         if (normX === normY) {
8625           if (lineWidth === 0) {
8626             scaleX = scaleY = 1 / normX;
8627           } else {
8628             const scaledLineWidth = normX * lineWidth;
8629             scaleX = scaleY = scaledLineWidth < 1 ? 1 / scaledLineWidth : 1;
8630           }
8631         } else if (lineWidth === 0) {
8632           scaleX = 1 / normX;
8633           scaleY = 1 / normY;
8634         } else {
8635           const scaledXLineWidth = normX * lineWidth;
8636           const scaledYLineWidth = normY * lineWidth;
8637           scaleX = scaledXLineWidth < 1 ? 1 / scaledXLineWidth : 1;
8638           scaleY = scaledYLineWidth < 1 ? 1 / scaledYLineWidth : 1;
8639         }
8640       } else {
8641         const absDet = Math.abs(a * d - b * c);
8642         const normX = Math.hypot(a, b);
8643         const normY = Math.hypot(c, d);
8644         if (lineWidth === 0) {
8645           scaleX = normY / absDet;
8646           scaleY = normX / absDet;
8647         } else {
8648           const baseArea = lineWidth * absDet;
8649           scaleX = normY > baseArea ? normY / baseArea : 1;
8650           scaleY = normX > baseArea ? normX / baseArea : 1;
8651         }
8652       }
8653       this._cachedScaleForStroking[0] = scaleX;
8654       this._cachedScaleForStroking[1] = scaleY;
8655     }
8656     return this._cachedScaleForStroking;
8657   }
8658   rescaleAndStroke(saveRestore) {
8659     const {
8660       ctx
8661     } = this;
8662     const {
8663       lineWidth
8664     } = this.current;
8665     const [scaleX, scaleY] = this.getScaleForStroking();
8666     ctx.lineWidth = lineWidth || 1;
8667     if (scaleX === 1 && scaleY === 1) {
8668       ctx.stroke();
8669       return;
8670     }
8671     const dashes = ctx.getLineDash();
8672     if (saveRestore) {
8673       ctx.save();
8674     }
8675     ctx.scale(scaleX, scaleY);
8676     if (dashes.length > 0) {
8677       const scale = Math.max(scaleX, scaleY);
8678       ctx.setLineDash(dashes.map(x => x / scale));
8679       ctx.lineDashOffset /= scale;
8680     }
8681     ctx.stroke();
8682     if (saveRestore) {
8683       ctx.restore();
8684     }
8685   }
8686   isContentVisible() {
8687     for (let i = this.markedContentStack.length - 1; i >= 0; i--) {
8688       if (!this.markedContentStack[i].visible) {
8689         return false;
8690       }
8691     }
8692     return true;
8693   }
8695 for (const op in OPS) {
8696   if (CanvasGraphics.prototype[op] !== undefined) {
8697     CanvasGraphics.prototype[OPS[op]] = CanvasGraphics.prototype[op];
8698   }
8701 ;// ./src/display/canvas_factory.js
8703 class BaseCanvasFactory {
8704   #enableHWA = false;
8705   constructor({
8706     enableHWA = false
8707   }) {
8708     this.#enableHWA = enableHWA;
8709   }
8710   create(width, height) {
8711     if (width <= 0 || height <= 0) {
8712       throw new Error("Invalid canvas size");
8713     }
8714     const canvas = this._createCanvas(width, height);
8715     return {
8716       canvas,
8717       context: canvas.getContext("2d", {
8718         willReadFrequently: !this.#enableHWA
8719       })
8720     };
8721   }
8722   reset(canvasAndContext, width, height) {
8723     if (!canvasAndContext.canvas) {
8724       throw new Error("Canvas is not specified");
8725     }
8726     if (width <= 0 || height <= 0) {
8727       throw new Error("Invalid canvas size");
8728     }
8729     canvasAndContext.canvas.width = width;
8730     canvasAndContext.canvas.height = height;
8731   }
8732   destroy(canvasAndContext) {
8733     if (!canvasAndContext.canvas) {
8734       throw new Error("Canvas is not specified");
8735     }
8736     canvasAndContext.canvas.width = 0;
8737     canvasAndContext.canvas.height = 0;
8738     canvasAndContext.canvas = null;
8739     canvasAndContext.context = null;
8740   }
8741   _createCanvas(width, height) {
8742     unreachable("Abstract method `_createCanvas` called.");
8743   }
8745 class DOMCanvasFactory extends BaseCanvasFactory {
8746   constructor({
8747     ownerDocument = globalThis.document,
8748     enableHWA = false
8749   }) {
8750     super({
8751       enableHWA
8752     });
8753     this._document = ownerDocument;
8754   }
8755   _createCanvas(width, height) {
8756     const canvas = this._document.createElement("canvas");
8757     canvas.width = width;
8758     canvas.height = height;
8759     return canvas;
8760   }
8763 ;// ./src/display/stubs.js
8764 const DOMCMapReaderFactory = null;
8765 const DOMWasmFactory = null;
8766 const DOMStandardFontDataFactory = null;
8767 const NodeCanvasFactory = null;
8768 const NodeCMapReaderFactory = null;
8769 const NodeFilterFactory = null;
8770 const NodeWasmFactory = null;
8771 const NodeStandardFontDataFactory = null;
8772 const PDFFetchStream = null;
8773 const PDFNetworkStream = null;
8774 const PDFNodeStream = null;
8776 ;// ./src/display/filter_factory.js
8779 class BaseFilterFactory {
8780   addFilter(maps) {
8781     return "none";
8782   }
8783   addHCMFilter(fgColor, bgColor) {
8784     return "none";
8785   }
8786   addAlphaFilter(map) {
8787     return "none";
8788   }
8789   addLuminosityFilter(map) {
8790     return "none";
8791   }
8792   addHighlightHCMFilter(filterName, fgColor, bgColor, newFgColor, newBgColor) {
8793     return "none";
8794   }
8795   destroy(keepHCM = false) {}
8797 class DOMFilterFactory extends BaseFilterFactory {
8798   #baseUrl;
8799   #_cache;
8800   #_defs;
8801   #docId;
8802   #document;
8803   #_hcmCache;
8804   #id = 0;
8805   constructor({
8806     docId,
8807     ownerDocument = globalThis.document
8808   }) {
8809     super();
8810     this.#docId = docId;
8811     this.#document = ownerDocument;
8812   }
8813   get #cache() {
8814     return this.#_cache ||= new Map();
8815   }
8816   get #hcmCache() {
8817     return this.#_hcmCache ||= new Map();
8818   }
8819   get #defs() {
8820     if (!this.#_defs) {
8821       const div = this.#document.createElement("div");
8822       const {
8823         style
8824       } = div;
8825       style.visibility = "hidden";
8826       style.contain = "strict";
8827       style.width = style.height = 0;
8828       style.position = "absolute";
8829       style.top = style.left = 0;
8830       style.zIndex = -1;
8831       const svg = this.#document.createElementNS(SVG_NS, "svg");
8832       svg.setAttribute("width", 0);
8833       svg.setAttribute("height", 0);
8834       this.#_defs = this.#document.createElementNS(SVG_NS, "defs");
8835       div.append(svg);
8836       svg.append(this.#_defs);
8837       this.#document.body.append(div);
8838     }
8839     return this.#_defs;
8840   }
8841   #createTables(maps) {
8842     if (maps.length === 1) {
8843       const mapR = maps[0];
8844       const buffer = new Array(256);
8845       for (let i = 0; i < 256; i++) {
8846         buffer[i] = mapR[i] / 255;
8847       }
8848       const table = buffer.join(",");
8849       return [table, table, table];
8850     }
8851     const [mapR, mapG, mapB] = maps;
8852     const bufferR = new Array(256);
8853     const bufferG = new Array(256);
8854     const bufferB = new Array(256);
8855     for (let i = 0; i < 256; i++) {
8856       bufferR[i] = mapR[i] / 255;
8857       bufferG[i] = mapG[i] / 255;
8858       bufferB[i] = mapB[i] / 255;
8859     }
8860     return [bufferR.join(","), bufferG.join(","), bufferB.join(",")];
8861   }
8862   #createUrl(id) {
8863     if (this.#baseUrl === undefined) {
8864       this.#baseUrl = "";
8865       const url = this.#document.URL;
8866       if (url !== this.#document.baseURI) {
8867         if (isDataScheme(url)) {
8868           warn('#createUrl: ignore "data:"-URL for performance reasons.');
8869         } else {
8870           this.#baseUrl = url.split("#", 1)[0];
8871         }
8872       }
8873     }
8874     return `url(${this.#baseUrl}#${id})`;
8875   }
8876   addFilter(maps) {
8877     if (!maps) {
8878       return "none";
8879     }
8880     let value = this.#cache.get(maps);
8881     if (value) {
8882       return value;
8883     }
8884     const [tableR, tableG, tableB] = this.#createTables(maps);
8885     const key = maps.length === 1 ? tableR : `${tableR}${tableG}${tableB}`;
8886     value = this.#cache.get(key);
8887     if (value) {
8888       this.#cache.set(maps, value);
8889       return value;
8890     }
8891     const id = `g_${this.#docId}_transfer_map_${this.#id++}`;
8892     const url = this.#createUrl(id);
8893     this.#cache.set(maps, url);
8894     this.#cache.set(key, url);
8895     const filter = this.#createFilter(id);
8896     this.#addTransferMapConversion(tableR, tableG, tableB, filter);
8897     return url;
8898   }
8899   addHCMFilter(fgColor, bgColor) {
8900     const key = `${fgColor}-${bgColor}`;
8901     const filterName = "base";
8902     let info = this.#hcmCache.get(filterName);
8903     if (info?.key === key) {
8904       return info.url;
8905     }
8906     if (info) {
8907       info.filter?.remove();
8908       info.key = key;
8909       info.url = "none";
8910       info.filter = null;
8911     } else {
8912       info = {
8913         key,
8914         url: "none",
8915         filter: null
8916       };
8917       this.#hcmCache.set(filterName, info);
8918     }
8919     if (!fgColor || !bgColor) {
8920       return info.url;
8921     }
8922     const fgRGB = this.#getRGB(fgColor);
8923     fgColor = Util.makeHexColor(...fgRGB);
8924     const bgRGB = this.#getRGB(bgColor);
8925     bgColor = Util.makeHexColor(...bgRGB);
8926     this.#defs.style.color = "";
8927     if (fgColor === "#000000" && bgColor === "#ffffff" || fgColor === bgColor) {
8928       return info.url;
8929     }
8930     const map = new Array(256);
8931     for (let i = 0; i <= 255; i++) {
8932       const x = i / 255;
8933       map[i] = x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
8934     }
8935     const table = map.join(",");
8936     const id = `g_${this.#docId}_hcm_filter`;
8937     const filter = info.filter = this.#createFilter(id);
8938     this.#addTransferMapConversion(table, table, table, filter);
8939     this.#addGrayConversion(filter);
8940     const getSteps = (c, n) => {
8941       const start = fgRGB[c] / 255;
8942       const end = bgRGB[c] / 255;
8943       const arr = new Array(n + 1);
8944       for (let i = 0; i <= n; i++) {
8945         arr[i] = start + i / n * (end - start);
8946       }
8947       return arr.join(",");
8948     };
8949     this.#addTransferMapConversion(getSteps(0, 5), getSteps(1, 5), getSteps(2, 5), filter);
8950     info.url = this.#createUrl(id);
8951     return info.url;
8952   }
8953   addAlphaFilter(map) {
8954     let value = this.#cache.get(map);
8955     if (value) {
8956       return value;
8957     }
8958     const [tableA] = this.#createTables([map]);
8959     const key = `alpha_${tableA}`;
8960     value = this.#cache.get(key);
8961     if (value) {
8962       this.#cache.set(map, value);
8963       return value;
8964     }
8965     const id = `g_${this.#docId}_alpha_map_${this.#id++}`;
8966     const url = this.#createUrl(id);
8967     this.#cache.set(map, url);
8968     this.#cache.set(key, url);
8969     const filter = this.#createFilter(id);
8970     this.#addTransferMapAlphaConversion(tableA, filter);
8971     return url;
8972   }
8973   addLuminosityFilter(map) {
8974     let value = this.#cache.get(map || "luminosity");
8975     if (value) {
8976       return value;
8977     }
8978     let tableA, key;
8979     if (map) {
8980       [tableA] = this.#createTables([map]);
8981       key = `luminosity_${tableA}`;
8982     } else {
8983       key = "luminosity";
8984     }
8985     value = this.#cache.get(key);
8986     if (value) {
8987       this.#cache.set(map, value);
8988       return value;
8989     }
8990     const id = `g_${this.#docId}_luminosity_map_${this.#id++}`;
8991     const url = this.#createUrl(id);
8992     this.#cache.set(map, url);
8993     this.#cache.set(key, url);
8994     const filter = this.#createFilter(id);
8995     this.#addLuminosityConversion(filter);
8996     if (map) {
8997       this.#addTransferMapAlphaConversion(tableA, filter);
8998     }
8999     return url;
9000   }
9001   addHighlightHCMFilter(filterName, fgColor, bgColor, newFgColor, newBgColor) {
9002     const key = `${fgColor}-${bgColor}-${newFgColor}-${newBgColor}`;
9003     let info = this.#hcmCache.get(filterName);
9004     if (info?.key === key) {
9005       return info.url;
9006     }
9007     if (info) {
9008       info.filter?.remove();
9009       info.key = key;
9010       info.url = "none";
9011       info.filter = null;
9012     } else {
9013       info = {
9014         key,
9015         url: "none",
9016         filter: null
9017       };
9018       this.#hcmCache.set(filterName, info);
9019     }
9020     if (!fgColor || !bgColor) {
9021       return info.url;
9022     }
9023     const [fgRGB, bgRGB] = [fgColor, bgColor].map(this.#getRGB.bind(this));
9024     let fgGray = Math.round(0.2126 * fgRGB[0] + 0.7152 * fgRGB[1] + 0.0722 * fgRGB[2]);
9025     let bgGray = Math.round(0.2126 * bgRGB[0] + 0.7152 * bgRGB[1] + 0.0722 * bgRGB[2]);
9026     let [newFgRGB, newBgRGB] = [newFgColor, newBgColor].map(this.#getRGB.bind(this));
9027     if (bgGray < fgGray) {
9028       [fgGray, bgGray, newFgRGB, newBgRGB] = [bgGray, fgGray, newBgRGB, newFgRGB];
9029     }
9030     this.#defs.style.color = "";
9031     const getSteps = (fg, bg, n) => {
9032       const arr = new Array(256);
9033       const step = (bgGray - fgGray) / n;
9034       const newStart = fg / 255;
9035       const newStep = (bg - fg) / (255 * n);
9036       let prev = 0;
9037       for (let i = 0; i <= n; i++) {
9038         const k = Math.round(fgGray + i * step);
9039         const value = newStart + i * newStep;
9040         for (let j = prev; j <= k; j++) {
9041           arr[j] = value;
9042         }
9043         prev = k + 1;
9044       }
9045       for (let i = prev; i < 256; i++) {
9046         arr[i] = arr[prev - 1];
9047       }
9048       return arr.join(",");
9049     };
9050     const id = `g_${this.#docId}_hcm_${filterName}_filter`;
9051     const filter = info.filter = this.#createFilter(id);
9052     this.#addGrayConversion(filter);
9053     this.#addTransferMapConversion(getSteps(newFgRGB[0], newBgRGB[0], 5), getSteps(newFgRGB[1], newBgRGB[1], 5), getSteps(newFgRGB[2], newBgRGB[2], 5), filter);
9054     info.url = this.#createUrl(id);
9055     return info.url;
9056   }
9057   destroy(keepHCM = false) {
9058     if (keepHCM && this.#_hcmCache?.size) {
9059       return;
9060     }
9061     this.#_defs?.parentNode.parentNode.remove();
9062     this.#_defs = null;
9063     this.#_cache?.clear();
9064     this.#_cache = null;
9065     this.#_hcmCache?.clear();
9066     this.#_hcmCache = null;
9067     this.#id = 0;
9068   }
9069   #addLuminosityConversion(filter) {
9070     const feColorMatrix = this.#document.createElementNS(SVG_NS, "feColorMatrix");
9071     feColorMatrix.setAttribute("type", "matrix");
9072     feColorMatrix.setAttribute("values", "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.3 0.59 0.11 0 0");
9073     filter.append(feColorMatrix);
9074   }
9075   #addGrayConversion(filter) {
9076     const feColorMatrix = this.#document.createElementNS(SVG_NS, "feColorMatrix");
9077     feColorMatrix.setAttribute("type", "matrix");
9078     feColorMatrix.setAttribute("values", "0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0 0 0 1 0");
9079     filter.append(feColorMatrix);
9080   }
9081   #createFilter(id) {
9082     const filter = this.#document.createElementNS(SVG_NS, "filter");
9083     filter.setAttribute("color-interpolation-filters", "sRGB");
9084     filter.setAttribute("id", id);
9085     this.#defs.append(filter);
9086     return filter;
9087   }
9088   #appendFeFunc(feComponentTransfer, func, table) {
9089     const feFunc = this.#document.createElementNS(SVG_NS, func);
9090     feFunc.setAttribute("type", "discrete");
9091     feFunc.setAttribute("tableValues", table);
9092     feComponentTransfer.append(feFunc);
9093   }
9094   #addTransferMapConversion(rTable, gTable, bTable, filter) {
9095     const feComponentTransfer = this.#document.createElementNS(SVG_NS, "feComponentTransfer");
9096     filter.append(feComponentTransfer);
9097     this.#appendFeFunc(feComponentTransfer, "feFuncR", rTable);
9098     this.#appendFeFunc(feComponentTransfer, "feFuncG", gTable);
9099     this.#appendFeFunc(feComponentTransfer, "feFuncB", bTable);
9100   }
9101   #addTransferMapAlphaConversion(aTable, filter) {
9102     const feComponentTransfer = this.#document.createElementNS(SVG_NS, "feComponentTransfer");
9103     filter.append(feComponentTransfer);
9104     this.#appendFeFunc(feComponentTransfer, "feFuncA", aTable);
9105   }
9106   #getRGB(color) {
9107     this.#defs.style.color = color;
9108     return getRGB(getComputedStyle(this.#defs).getPropertyValue("color"));
9109   }
9112 ;// ./src/display/worker_options.js
9113 class GlobalWorkerOptions {
9114   static #port = null;
9115   static #src = "";
9116   static get workerPort() {
9117     return this.#port;
9118   }
9119   static set workerPort(val) {
9120     if (!(typeof Worker !== "undefined" && val instanceof Worker) && val !== null) {
9121       throw new Error("Invalid `workerPort` type.");
9122     }
9123     this.#port = val;
9124   }
9125   static get workerSrc() {
9126     return this.#src;
9127   }
9128   static set workerSrc(val) {
9129     if (typeof val !== "string") {
9130       throw new Error("Invalid `workerSrc` type.");
9131     }
9132     this.#src = val;
9133   }
9136 ;// ./src/display/metadata.js
9138 class Metadata {
9139   #metadataMap;
9140   #data;
9141   constructor({
9142     parsedData,
9143     rawData
9144   }) {
9145     this.#metadataMap = parsedData;
9146     this.#data = rawData;
9147   }
9148   getRaw() {
9149     return this.#data;
9150   }
9151   get(name) {
9152     return this.#metadataMap.get(name) ?? null;
9153   }
9154   getAll() {
9155     return objectFromMap(this.#metadataMap);
9156   }
9157   has(name) {
9158     return this.#metadataMap.has(name);
9159   }
9162 ;// ./src/display/optional_content_config.js
9165 const INTERNAL = Symbol("INTERNAL");
9166 class OptionalContentGroup {
9167   #isDisplay = false;
9168   #isPrint = false;
9169   #userSet = false;
9170   #visible = true;
9171   constructor(renderingIntent, {
9172     name,
9173     intent,
9174     usage,
9175     rbGroups
9176   }) {
9177     this.#isDisplay = !!(renderingIntent & RenderingIntentFlag.DISPLAY);
9178     this.#isPrint = !!(renderingIntent & RenderingIntentFlag.PRINT);
9179     this.name = name;
9180     this.intent = intent;
9181     this.usage = usage;
9182     this.rbGroups = rbGroups;
9183   }
9184   get visible() {
9185     if (this.#userSet) {
9186       return this.#visible;
9187     }
9188     if (!this.#visible) {
9189       return false;
9190     }
9191     const {
9192       print,
9193       view
9194     } = this.usage;
9195     if (this.#isDisplay) {
9196       return view?.viewState !== "OFF";
9197     } else if (this.#isPrint) {
9198       return print?.printState !== "OFF";
9199     }
9200     return true;
9201   }
9202   _setVisible(internal, visible, userSet = false) {
9203     if (internal !== INTERNAL) {
9204       unreachable("Internal method `_setVisible` called.");
9205     }
9206     this.#userSet = userSet;
9207     this.#visible = visible;
9208   }
9210 class OptionalContentConfig {
9211   #cachedGetHash = null;
9212   #groups = new Map();
9213   #initialHash = null;
9214   #order = null;
9215   constructor(data, renderingIntent = RenderingIntentFlag.DISPLAY) {
9216     this.renderingIntent = renderingIntent;
9217     this.name = null;
9218     this.creator = null;
9219     if (data === null) {
9220       return;
9221     }
9222     this.name = data.name;
9223     this.creator = data.creator;
9224     this.#order = data.order;
9225     for (const group of data.groups) {
9226       this.#groups.set(group.id, new OptionalContentGroup(renderingIntent, group));
9227     }
9228     if (data.baseState === "OFF") {
9229       for (const group of this.#groups.values()) {
9230         group._setVisible(INTERNAL, false);
9231       }
9232     }
9233     for (const on of data.on) {
9234       this.#groups.get(on)._setVisible(INTERNAL, true);
9235     }
9236     for (const off of data.off) {
9237       this.#groups.get(off)._setVisible(INTERNAL, false);
9238     }
9239     this.#initialHash = this.getHash();
9240   }
9241   #evaluateVisibilityExpression(array) {
9242     const length = array.length;
9243     if (length < 2) {
9244       return true;
9245     }
9246     const operator = array[0];
9247     for (let i = 1; i < length; i++) {
9248       const element = array[i];
9249       let state;
9250       if (Array.isArray(element)) {
9251         state = this.#evaluateVisibilityExpression(element);
9252       } else if (this.#groups.has(element)) {
9253         state = this.#groups.get(element).visible;
9254       } else {
9255         warn(`Optional content group not found: ${element}`);
9256         return true;
9257       }
9258       switch (operator) {
9259         case "And":
9260           if (!state) {
9261             return false;
9262           }
9263           break;
9264         case "Or":
9265           if (state) {
9266             return true;
9267           }
9268           break;
9269         case "Not":
9270           return !state;
9271         default:
9272           return true;
9273       }
9274     }
9275     return operator === "And";
9276   }
9277   isVisible(group) {
9278     if (this.#groups.size === 0) {
9279       return true;
9280     }
9281     if (!group) {
9282       info("Optional content group not defined.");
9283       return true;
9284     }
9285     if (group.type === "OCG") {
9286       if (!this.#groups.has(group.id)) {
9287         warn(`Optional content group not found: ${group.id}`);
9288         return true;
9289       }
9290       return this.#groups.get(group.id).visible;
9291     } else if (group.type === "OCMD") {
9292       if (group.expression) {
9293         return this.#evaluateVisibilityExpression(group.expression);
9294       }
9295       if (!group.policy || group.policy === "AnyOn") {
9296         for (const id of group.ids) {
9297           if (!this.#groups.has(id)) {
9298             warn(`Optional content group not found: ${id}`);
9299             return true;
9300           }
9301           if (this.#groups.get(id).visible) {
9302             return true;
9303           }
9304         }
9305         return false;
9306       } else if (group.policy === "AllOn") {
9307         for (const id of group.ids) {
9308           if (!this.#groups.has(id)) {
9309             warn(`Optional content group not found: ${id}`);
9310             return true;
9311           }
9312           if (!this.#groups.get(id).visible) {
9313             return false;
9314           }
9315         }
9316         return true;
9317       } else if (group.policy === "AnyOff") {
9318         for (const id of group.ids) {
9319           if (!this.#groups.has(id)) {
9320             warn(`Optional content group not found: ${id}`);
9321             return true;
9322           }
9323           if (!this.#groups.get(id).visible) {
9324             return true;
9325           }
9326         }
9327         return false;
9328       } else if (group.policy === "AllOff") {
9329         for (const id of group.ids) {
9330           if (!this.#groups.has(id)) {
9331             warn(`Optional content group not found: ${id}`);
9332             return true;
9333           }
9334           if (this.#groups.get(id).visible) {
9335             return false;
9336           }
9337         }
9338         return true;
9339       }
9340       warn(`Unknown optional content policy ${group.policy}.`);
9341       return true;
9342     }
9343     warn(`Unknown group type ${group.type}.`);
9344     return true;
9345   }
9346   setVisibility(id, visible = true, preserveRB = true) {
9347     const group = this.#groups.get(id);
9348     if (!group) {
9349       warn(`Optional content group not found: ${id}`);
9350       return;
9351     }
9352     if (preserveRB && visible && group.rbGroups.length) {
9353       for (const rbGroup of group.rbGroups) {
9354         for (const otherId of rbGroup) {
9355           if (otherId !== id) {
9356             this.#groups.get(otherId)?._setVisible(INTERNAL, false, true);
9357           }
9358         }
9359       }
9360     }
9361     group._setVisible(INTERNAL, !!visible, true);
9362     this.#cachedGetHash = null;
9363   }
9364   setOCGState({
9365     state,
9366     preserveRB
9367   }) {
9368     let operator;
9369     for (const elem of state) {
9370       switch (elem) {
9371         case "ON":
9372         case "OFF":
9373         case "Toggle":
9374           operator = elem;
9375           continue;
9376       }
9377       const group = this.#groups.get(elem);
9378       if (!group) {
9379         continue;
9380       }
9381       switch (operator) {
9382         case "ON":
9383           this.setVisibility(elem, true, preserveRB);
9384           break;
9385         case "OFF":
9386           this.setVisibility(elem, false, preserveRB);
9387           break;
9388         case "Toggle":
9389           this.setVisibility(elem, !group.visible, preserveRB);
9390           break;
9391       }
9392     }
9393     this.#cachedGetHash = null;
9394   }
9395   get hasInitialVisibility() {
9396     return this.#initialHash === null || this.getHash() === this.#initialHash;
9397   }
9398   getOrder() {
9399     if (!this.#groups.size) {
9400       return null;
9401     }
9402     if (this.#order) {
9403       return this.#order.slice();
9404     }
9405     return [...this.#groups.keys()];
9406   }
9407   getGroups() {
9408     return this.#groups.size > 0 ? objectFromMap(this.#groups) : null;
9409   }
9410   getGroup(id) {
9411     return this.#groups.get(id) || null;
9412   }
9413   getHash() {
9414     if (this.#cachedGetHash !== null) {
9415       return this.#cachedGetHash;
9416     }
9417     const hash = new MurmurHash3_64();
9418     for (const [id, group] of this.#groups) {
9419       hash.update(`${id}:${group.visible}`);
9420     }
9421     return this.#cachedGetHash = hash.hexdigest();
9422   }
9425 ;// ./src/display/transport_stream.js
9428 class PDFDataTransportStream {
9429   constructor(pdfDataRangeTransport, {
9430     disableRange = false,
9431     disableStream = false
9432   }) {
9433     assert(pdfDataRangeTransport, 'PDFDataTransportStream - missing required "pdfDataRangeTransport" argument.');
9434     const {
9435       length,
9436       initialData,
9437       progressiveDone,
9438       contentDispositionFilename
9439     } = pdfDataRangeTransport;
9440     this._queuedChunks = [];
9441     this._progressiveDone = progressiveDone;
9442     this._contentDispositionFilename = contentDispositionFilename;
9443     if (initialData?.length > 0) {
9444       const buffer = initialData instanceof Uint8Array && initialData.byteLength === initialData.buffer.byteLength ? initialData.buffer : new Uint8Array(initialData).buffer;
9445       this._queuedChunks.push(buffer);
9446     }
9447     this._pdfDataRangeTransport = pdfDataRangeTransport;
9448     this._isStreamingSupported = !disableStream;
9449     this._isRangeSupported = !disableRange;
9450     this._contentLength = length;
9451     this._fullRequestReader = null;
9452     this._rangeReaders = [];
9453     pdfDataRangeTransport.addRangeListener((begin, chunk) => {
9454       this._onReceiveData({
9455         begin,
9456         chunk
9457       });
9458     });
9459     pdfDataRangeTransport.addProgressListener((loaded, total) => {
9460       this._onProgress({
9461         loaded,
9462         total
9463       });
9464     });
9465     pdfDataRangeTransport.addProgressiveReadListener(chunk => {
9466       this._onReceiveData({
9467         chunk
9468       });
9469     });
9470     pdfDataRangeTransport.addProgressiveDoneListener(() => {
9471       this._onProgressiveDone();
9472     });
9473     pdfDataRangeTransport.transportReady();
9474   }
9475   _onReceiveData({
9476     begin,
9477     chunk
9478   }) {
9479     const buffer = chunk instanceof Uint8Array && chunk.byteLength === chunk.buffer.byteLength ? chunk.buffer : new Uint8Array(chunk).buffer;
9480     if (begin === undefined) {
9481       if (this._fullRequestReader) {
9482         this._fullRequestReader._enqueue(buffer);
9483       } else {
9484         this._queuedChunks.push(buffer);
9485       }
9486     } else {
9487       const found = this._rangeReaders.some(function (rangeReader) {
9488         if (rangeReader._begin !== begin) {
9489           return false;
9490         }
9491         rangeReader._enqueue(buffer);
9492         return true;
9493       });
9494       assert(found, "_onReceiveData - no `PDFDataTransportStreamRangeReader` instance found.");
9495     }
9496   }
9497   get _progressiveDataLength() {
9498     return this._fullRequestReader?._loaded ?? 0;
9499   }
9500   _onProgress(evt) {
9501     if (evt.total === undefined) {
9502       this._rangeReaders[0]?.onProgress?.({
9503         loaded: evt.loaded
9504       });
9505     } else {
9506       this._fullRequestReader?.onProgress?.({
9507         loaded: evt.loaded,
9508         total: evt.total
9509       });
9510     }
9511   }
9512   _onProgressiveDone() {
9513     this._fullRequestReader?.progressiveDone();
9514     this._progressiveDone = true;
9515   }
9516   _removeRangeReader(reader) {
9517     const i = this._rangeReaders.indexOf(reader);
9518     if (i >= 0) {
9519       this._rangeReaders.splice(i, 1);
9520     }
9521   }
9522   getFullReader() {
9523     assert(!this._fullRequestReader, "PDFDataTransportStream.getFullReader can only be called once.");
9524     const queuedChunks = this._queuedChunks;
9525     this._queuedChunks = null;
9526     return new PDFDataTransportStreamReader(this, queuedChunks, this._progressiveDone, this._contentDispositionFilename);
9527   }
9528   getRangeReader(begin, end) {
9529     if (end <= this._progressiveDataLength) {
9530       return null;
9531     }
9532     const reader = new PDFDataTransportStreamRangeReader(this, begin, end);
9533     this._pdfDataRangeTransport.requestDataRange(begin, end);
9534     this._rangeReaders.push(reader);
9535     return reader;
9536   }
9537   cancelAllRequests(reason) {
9538     this._fullRequestReader?.cancel(reason);
9539     for (const reader of this._rangeReaders.slice(0)) {
9540       reader.cancel(reason);
9541     }
9542     this._pdfDataRangeTransport.abort();
9543   }
9545 class PDFDataTransportStreamReader {
9546   constructor(stream, queuedChunks, progressiveDone = false, contentDispositionFilename = null) {
9547     this._stream = stream;
9548     this._done = progressiveDone || false;
9549     this._filename = isPdfFile(contentDispositionFilename) ? contentDispositionFilename : null;
9550     this._queuedChunks = queuedChunks || [];
9551     this._loaded = 0;
9552     for (const chunk of this._queuedChunks) {
9553       this._loaded += chunk.byteLength;
9554     }
9555     this._requests = [];
9556     this._headersReady = Promise.resolve();
9557     stream._fullRequestReader = this;
9558     this.onProgress = null;
9559   }
9560   _enqueue(chunk) {
9561     if (this._done) {
9562       return;
9563     }
9564     if (this._requests.length > 0) {
9565       const requestCapability = this._requests.shift();
9566       requestCapability.resolve({
9567         value: chunk,
9568         done: false
9569       });
9570     } else {
9571       this._queuedChunks.push(chunk);
9572     }
9573     this._loaded += chunk.byteLength;
9574   }
9575   get headersReady() {
9576     return this._headersReady;
9577   }
9578   get filename() {
9579     return this._filename;
9580   }
9581   get isRangeSupported() {
9582     return this._stream._isRangeSupported;
9583   }
9584   get isStreamingSupported() {
9585     return this._stream._isStreamingSupported;
9586   }
9587   get contentLength() {
9588     return this._stream._contentLength;
9589   }
9590   async read() {
9591     if (this._queuedChunks.length > 0) {
9592       const chunk = this._queuedChunks.shift();
9593       return {
9594         value: chunk,
9595         done: false
9596       };
9597     }
9598     if (this._done) {
9599       return {
9600         value: undefined,
9601         done: true
9602       };
9603     }
9604     const requestCapability = Promise.withResolvers();
9605     this._requests.push(requestCapability);
9606     return requestCapability.promise;
9607   }
9608   cancel(reason) {
9609     this._done = true;
9610     for (const requestCapability of this._requests) {
9611       requestCapability.resolve({
9612         value: undefined,
9613         done: true
9614       });
9615     }
9616     this._requests.length = 0;
9617   }
9618   progressiveDone() {
9619     if (this._done) {
9620       return;
9621     }
9622     this._done = true;
9623   }
9625 class PDFDataTransportStreamRangeReader {
9626   constructor(stream, begin, end) {
9627     this._stream = stream;
9628     this._begin = begin;
9629     this._end = end;
9630     this._queuedChunk = null;
9631     this._requests = [];
9632     this._done = false;
9633     this.onProgress = null;
9634   }
9635   _enqueue(chunk) {
9636     if (this._done) {
9637       return;
9638     }
9639     if (this._requests.length === 0) {
9640       this._queuedChunk = chunk;
9641     } else {
9642       const requestsCapability = this._requests.shift();
9643       requestsCapability.resolve({
9644         value: chunk,
9645         done: false
9646       });
9647       for (const requestCapability of this._requests) {
9648         requestCapability.resolve({
9649           value: undefined,
9650           done: true
9651         });
9652       }
9653       this._requests.length = 0;
9654     }
9655     this._done = true;
9656     this._stream._removeRangeReader(this);
9657   }
9658   get isStreamingSupported() {
9659     return false;
9660   }
9661   async read() {
9662     if (this._queuedChunk) {
9663       const chunk = this._queuedChunk;
9664       this._queuedChunk = null;
9665       return {
9666         value: chunk,
9667         done: false
9668       };
9669     }
9670     if (this._done) {
9671       return {
9672         value: undefined,
9673         done: true
9674       };
9675     }
9676     const requestCapability = Promise.withResolvers();
9677     this._requests.push(requestCapability);
9678     return requestCapability.promise;
9679   }
9680   cancel(reason) {
9681     this._done = true;
9682     for (const requestCapability of this._requests) {
9683       requestCapability.resolve({
9684         value: undefined,
9685         done: true
9686       });
9687     }
9688     this._requests.length = 0;
9689     this._stream._removeRangeReader(this);
9690   }
9693 ;// ./src/display/text_layer.js
9696 const MAX_TEXT_DIVS_TO_RENDER = 100000;
9697 const DEFAULT_FONT_SIZE = 30;
9698 const DEFAULT_FONT_ASCENT = 0.8;
9699 class TextLayer {
9700   #capability = Promise.withResolvers();
9701   #container = null;
9702   #disableProcessItems = false;
9703   #fontInspectorEnabled = !!globalThis.FontInspector?.enabled;
9704   #lang = null;
9705   #layoutTextParams = null;
9706   #pageHeight = 0;
9707   #pageWidth = 0;
9708   #reader = null;
9709   #rootContainer = null;
9710   #rotation = 0;
9711   #scale = 0;
9712   #styleCache = Object.create(null);
9713   #textContentItemsStr = [];
9714   #textContentSource = null;
9715   #textDivs = [];
9716   #textDivProperties = new WeakMap();
9717   #transform = null;
9718   static #ascentCache = new Map();
9719   static #canvasContexts = new Map();
9720   static #canvasCtxFonts = new WeakMap();
9721   static #minFontSize = null;
9722   static #pendingTextLayers = new Set();
9723   constructor({
9724     textContentSource,
9725     container,
9726     viewport
9727   }) {
9728     if (textContentSource instanceof ReadableStream) {
9729       this.#textContentSource = textContentSource;
9730     } else {
9731       throw new Error('No "textContentSource" parameter specified.');
9732     }
9733     this.#container = this.#rootContainer = container;
9734     this.#scale = viewport.scale * (globalThis.devicePixelRatio || 1);
9735     this.#rotation = viewport.rotation;
9736     this.#layoutTextParams = {
9737       div: null,
9738       properties: null,
9739       ctx: null
9740     };
9741     const {
9742       pageWidth,
9743       pageHeight,
9744       pageX,
9745       pageY
9746     } = viewport.rawDims;
9747     this.#transform = [1, 0, 0, -1, -pageX, pageY + pageHeight];
9748     this.#pageWidth = pageWidth;
9749     this.#pageHeight = pageHeight;
9750     TextLayer.#ensureMinFontSizeComputed();
9751     setLayerDimensions(container, viewport);
9752     this.#capability.promise.finally(() => {
9753       TextLayer.#pendingTextLayers.delete(this);
9754       this.#layoutTextParams = null;
9755       this.#styleCache = null;
9756     }).catch(() => {});
9757   }
9758   static get fontFamilyMap() {
9759     const {
9760       isWindows,
9761       isFirefox
9762     } = util_FeatureTest.platform;
9763     return shadow(this, "fontFamilyMap", new Map([["sans-serif", `${isWindows && isFirefox ? "Calibri, " : ""}sans-serif`], ["monospace", `${isWindows && isFirefox ? "Lucida Console, " : ""}monospace`]]));
9764   }
9765   render() {
9766     const pump = () => {
9767       this.#reader.read().then(({
9768         value,
9769         done
9770       }) => {
9771         if (done) {
9772           this.#capability.resolve();
9773           return;
9774         }
9775         this.#lang ??= value.lang;
9776         Object.assign(this.#styleCache, value.styles);
9777         this.#processItems(value.items);
9778         pump();
9779       }, this.#capability.reject);
9780     };
9781     this.#reader = this.#textContentSource.getReader();
9782     TextLayer.#pendingTextLayers.add(this);
9783     pump();
9784     return this.#capability.promise;
9785   }
9786   update({
9787     viewport,
9788     onBefore = null
9789   }) {
9790     const scale = viewport.scale * (globalThis.devicePixelRatio || 1);
9791     const rotation = viewport.rotation;
9792     if (rotation !== this.#rotation) {
9793       onBefore?.();
9794       this.#rotation = rotation;
9795       setLayerDimensions(this.#rootContainer, {
9796         rotation
9797       });
9798     }
9799     if (scale !== this.#scale) {
9800       onBefore?.();
9801       this.#scale = scale;
9802       const params = {
9803         div: null,
9804         properties: null,
9805         ctx: TextLayer.#getCtx(this.#lang)
9806       };
9807       for (const div of this.#textDivs) {
9808         params.properties = this.#textDivProperties.get(div);
9809         params.div = div;
9810         this.#layout(params);
9811       }
9812     }
9813   }
9814   cancel() {
9815     const abortEx = new AbortException("TextLayer task cancelled.");
9816     this.#reader?.cancel(abortEx).catch(() => {});
9817     this.#reader = null;
9818     this.#capability.reject(abortEx);
9819   }
9820   get textDivs() {
9821     return this.#textDivs;
9822   }
9823   get textContentItemsStr() {
9824     return this.#textContentItemsStr;
9825   }
9826   #processItems(items) {
9827     if (this.#disableProcessItems) {
9828       return;
9829     }
9830     this.#layoutTextParams.ctx ??= TextLayer.#getCtx(this.#lang);
9831     const textDivs = this.#textDivs,
9832       textContentItemsStr = this.#textContentItemsStr;
9833     for (const item of items) {
9834       if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER) {
9835         warn("Ignoring additional textDivs for performance reasons.");
9836         this.#disableProcessItems = true;
9837         return;
9838       }
9839       if (item.str === undefined) {
9840         if (item.type === "beginMarkedContentProps" || item.type === "beginMarkedContent") {
9841           const parent = this.#container;
9842           this.#container = document.createElement("span");
9843           this.#container.classList.add("markedContent");
9844           if (item.id !== null) {
9845             this.#container.setAttribute("id", `${item.id}`);
9846           }
9847           parent.append(this.#container);
9848         } else if (item.type === "endMarkedContent") {
9849           this.#container = this.#container.parentNode;
9850         }
9851         continue;
9852       }
9853       textContentItemsStr.push(item.str);
9854       this.#appendText(item);
9855     }
9856   }
9857   #appendText(geom) {
9858     const textDiv = document.createElement("span");
9859     const textDivProperties = {
9860       angle: 0,
9861       canvasWidth: 0,
9862       hasText: geom.str !== "",
9863       hasEOL: geom.hasEOL,
9864       fontSize: 0
9865     };
9866     this.#textDivs.push(textDiv);
9867     const tx = Util.transform(this.#transform, geom.transform);
9868     let angle = Math.atan2(tx[1], tx[0]);
9869     const style = this.#styleCache[geom.fontName];
9870     if (style.vertical) {
9871       angle += Math.PI / 2;
9872     }
9873     let fontFamily = this.#fontInspectorEnabled && style.fontSubstitution || style.fontFamily;
9874     fontFamily = TextLayer.fontFamilyMap.get(fontFamily) || fontFamily;
9875     const fontHeight = Math.hypot(tx[2], tx[3]);
9876     const fontAscent = fontHeight * TextLayer.#getAscent(fontFamily, this.#lang);
9877     let left, top;
9878     if (angle === 0) {
9879       left = tx[4];
9880       top = tx[5] - fontAscent;
9881     } else {
9882       left = tx[4] + fontAscent * Math.sin(angle);
9883       top = tx[5] - fontAscent * Math.cos(angle);
9884     }
9885     const scaleFactorStr = "calc(var(--scale-factor)*";
9886     const divStyle = textDiv.style;
9887     if (this.#container === this.#rootContainer) {
9888       divStyle.left = `${(100 * left / this.#pageWidth).toFixed(2)}%`;
9889       divStyle.top = `${(100 * top / this.#pageHeight).toFixed(2)}%`;
9890     } else {
9891       divStyle.left = `${scaleFactorStr}${left.toFixed(2)}px)`;
9892       divStyle.top = `${scaleFactorStr}${top.toFixed(2)}px)`;
9893     }
9894     divStyle.fontSize = `${scaleFactorStr}${(TextLayer.#minFontSize * fontHeight).toFixed(2)}px)`;
9895     divStyle.fontFamily = fontFamily;
9896     textDivProperties.fontSize = fontHeight;
9897     textDiv.setAttribute("role", "presentation");
9898     textDiv.textContent = geom.str;
9899     textDiv.dir = geom.dir;
9900     if (this.#fontInspectorEnabled) {
9901       textDiv.dataset.fontName = style.fontSubstitutionLoadedName || geom.fontName;
9902     }
9903     if (angle !== 0) {
9904       textDivProperties.angle = angle * (180 / Math.PI);
9905     }
9906     let shouldScaleText = false;
9907     if (geom.str.length > 1) {
9908       shouldScaleText = true;
9909     } else if (geom.str !== " " && geom.transform[0] !== geom.transform[3]) {
9910       const absScaleX = Math.abs(geom.transform[0]),
9911         absScaleY = Math.abs(geom.transform[3]);
9912       if (absScaleX !== absScaleY && Math.max(absScaleX, absScaleY) / Math.min(absScaleX, absScaleY) > 1.5) {
9913         shouldScaleText = true;
9914       }
9915     }
9916     if (shouldScaleText) {
9917       textDivProperties.canvasWidth = style.vertical ? geom.height : geom.width;
9918     }
9919     this.#textDivProperties.set(textDiv, textDivProperties);
9920     this.#layoutTextParams.div = textDiv;
9921     this.#layoutTextParams.properties = textDivProperties;
9922     this.#layout(this.#layoutTextParams);
9923     if (textDivProperties.hasText) {
9924       this.#container.append(textDiv);
9925     }
9926     if (textDivProperties.hasEOL) {
9927       const br = document.createElement("br");
9928       br.setAttribute("role", "presentation");
9929       this.#container.append(br);
9930     }
9931   }
9932   #layout(params) {
9933     const {
9934       div,
9935       properties,
9936       ctx
9937     } = params;
9938     const {
9939       style
9940     } = div;
9941     let transform = "";
9942     if (TextLayer.#minFontSize > 1) {
9943       transform = `scale(${1 / TextLayer.#minFontSize})`;
9944     }
9945     if (properties.canvasWidth !== 0 && properties.hasText) {
9946       const {
9947         fontFamily
9948       } = style;
9949       const {
9950         canvasWidth,
9951         fontSize
9952       } = properties;
9953       TextLayer.#ensureCtxFont(ctx, fontSize * this.#scale, fontFamily);
9954       const {
9955         width
9956       } = ctx.measureText(div.textContent);
9957       if (width > 0) {
9958         transform = `scaleX(${canvasWidth * this.#scale / width}) ${transform}`;
9959       }
9960     }
9961     if (properties.angle !== 0) {
9962       transform = `rotate(${properties.angle}deg) ${transform}`;
9963     }
9964     if (transform.length > 0) {
9965       style.transform = transform;
9966     }
9967   }
9968   static cleanup() {
9969     if (this.#pendingTextLayers.size > 0) {
9970       return;
9971     }
9972     this.#ascentCache.clear();
9973     for (const {
9974       canvas
9975     } of this.#canvasContexts.values()) {
9976       canvas.remove();
9977     }
9978     this.#canvasContexts.clear();
9979   }
9980   static #getCtx(lang = null) {
9981     let ctx = this.#canvasContexts.get(lang ||= "");
9982     if (!ctx) {
9983       const canvas = document.createElement("canvas");
9984       canvas.className = "hiddenCanvasElement";
9985       canvas.lang = lang;
9986       document.body.append(canvas);
9987       ctx = canvas.getContext("2d", {
9988         alpha: false,
9989         willReadFrequently: true
9990       });
9991       this.#canvasContexts.set(lang, ctx);
9992       this.#canvasCtxFonts.set(ctx, {
9993         size: 0,
9994         family: ""
9995       });
9996     }
9997     return ctx;
9998   }
9999   static #ensureCtxFont(ctx, size, family) {
10000     const cached = this.#canvasCtxFonts.get(ctx);
10001     if (size === cached.size && family === cached.family) {
10002       return;
10003     }
10004     ctx.font = `${size}px ${family}`;
10005     cached.size = size;
10006     cached.family = family;
10007   }
10008   static #ensureMinFontSizeComputed() {
10009     if (this.#minFontSize !== null) {
10010       return;
10011     }
10012     const div = document.createElement("div");
10013     div.style.opacity = 0;
10014     div.style.lineHeight = 1;
10015     div.style.fontSize = "1px";
10016     div.style.position = "absolute";
10017     div.textContent = "X";
10018     document.body.append(div);
10019     this.#minFontSize = div.getBoundingClientRect().height;
10020     div.remove();
10021   }
10022   static #getAscent(fontFamily, lang) {
10023     const cachedAscent = this.#ascentCache.get(fontFamily);
10024     if (cachedAscent) {
10025       return cachedAscent;
10026     }
10027     const ctx = this.#getCtx(lang);
10028     ctx.canvas.width = ctx.canvas.height = DEFAULT_FONT_SIZE;
10029     this.#ensureCtxFont(ctx, DEFAULT_FONT_SIZE, fontFamily);
10030     const metrics = ctx.measureText("");
10031     let ascent = metrics.fontBoundingBoxAscent;
10032     let descent = Math.abs(metrics.fontBoundingBoxDescent);
10033     if (ascent) {
10034       const ratio = ascent / (ascent + descent);
10035       this.#ascentCache.set(fontFamily, ratio);
10036       ctx.canvas.width = ctx.canvas.height = 0;
10037       return ratio;
10038     }
10039     ctx.strokeStyle = "red";
10040     ctx.clearRect(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE);
10041     ctx.strokeText("g", 0, 0);
10042     let pixels = ctx.getImageData(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE).data;
10043     descent = 0;
10044     for (let i = pixels.length - 1 - 3; i >= 0; i -= 4) {
10045       if (pixels[i] > 0) {
10046         descent = Math.ceil(i / 4 / DEFAULT_FONT_SIZE);
10047         break;
10048       }
10049     }
10050     ctx.clearRect(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE);
10051     ctx.strokeText("A", 0, DEFAULT_FONT_SIZE);
10052     pixels = ctx.getImageData(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE).data;
10053     ascent = 0;
10054     for (let i = 0, ii = pixels.length; i < ii; i += 4) {
10055       if (pixels[i] > 0) {
10056         ascent = DEFAULT_FONT_SIZE - Math.floor(i / 4 / DEFAULT_FONT_SIZE);
10057         break;
10058       }
10059     }
10060     ctx.canvas.width = ctx.canvas.height = 0;
10061     const ratio = ascent ? ascent / (ascent + descent) : DEFAULT_FONT_ASCENT;
10062     this.#ascentCache.set(fontFamily, ratio);
10063     return ratio;
10064   }
10067 ;// ./src/display/xfa_text.js
10068 class XfaText {
10069   static textContent(xfa) {
10070     const items = [];
10071     const output = {
10072       items,
10073       styles: Object.create(null)
10074     };
10075     function walk(node) {
10076       if (!node) {
10077         return;
10078       }
10079       let str = null;
10080       const name = node.name;
10081       if (name === "#text") {
10082         str = node.value;
10083       } else if (!XfaText.shouldBuildText(name)) {
10084         return;
10085       } else if (node?.attributes?.textContent) {
10086         str = node.attributes.textContent;
10087       } else if (node.value) {
10088         str = node.value;
10089       }
10090       if (str !== null) {
10091         items.push({
10092           str
10093         });
10094       }
10095       if (!node.children) {
10096         return;
10097       }
10098       for (const child of node.children) {
10099         walk(child);
10100       }
10101     }
10102     walk(xfa);
10103     return output;
10104   }
10105   static shouldBuildText(name) {
10106     return !(name === "textarea" || name === "input" || name === "option" || name === "select");
10107   }
10110 ;// ./src/display/api.js
10132 const DEFAULT_RANGE_CHUNK_SIZE = 65536;
10133 const RENDERING_CANCELLED_TIMEOUT = 100;
10134 function getDocument(src = {}) {
10135   const task = new PDFDocumentLoadingTask();
10136   const {
10137     docId
10138   } = task;
10139   const url = src.url ? getUrlProp(src.url) : null;
10140   const data = src.data ? getDataProp(src.data) : null;
10141   const httpHeaders = src.httpHeaders || null;
10142   const withCredentials = src.withCredentials === true;
10143   const password = src.password ?? null;
10144   const rangeTransport = src.range instanceof PDFDataRangeTransport ? src.range : null;
10145   const rangeChunkSize = Number.isInteger(src.rangeChunkSize) && src.rangeChunkSize > 0 ? src.rangeChunkSize : DEFAULT_RANGE_CHUNK_SIZE;
10146   let worker = src.worker instanceof PDFWorker ? src.worker : null;
10147   const verbosity = src.verbosity;
10148   const docBaseUrl = typeof src.docBaseUrl === "string" && !isDataScheme(src.docBaseUrl) ? src.docBaseUrl : null;
10149   const cMapUrl = getFactoryUrlProp(src.cMapUrl);
10150   const cMapPacked = src.cMapPacked !== false;
10151   const CMapReaderFactory = src.CMapReaderFactory || DOMCMapReaderFactory;
10152   const standardFontDataUrl = getFactoryUrlProp(src.standardFontDataUrl);
10153   const StandardFontDataFactory = src.StandardFontDataFactory || DOMStandardFontDataFactory;
10154   const wasmUrl = getFactoryUrlProp(src.wasmUrl);
10155   const WasmFactory = src.WasmFactory || DOMWasmFactory;
10156   const ignoreErrors = src.stopAtErrors !== true;
10157   const maxImageSize = Number.isInteger(src.maxImageSize) && src.maxImageSize > -1 ? src.maxImageSize : -1;
10158   const isEvalSupported = src.isEvalSupported !== false;
10159   const isOffscreenCanvasSupported = typeof src.isOffscreenCanvasSupported === "boolean" ? src.isOffscreenCanvasSupported : !isNodeJS;
10160   const isImageDecoderSupported = typeof src.isImageDecoderSupported === "boolean" ? src.isImageDecoderSupported : true;
10161   const canvasMaxAreaInBytes = Number.isInteger(src.canvasMaxAreaInBytes) ? src.canvasMaxAreaInBytes : -1;
10162   const disableFontFace = typeof src.disableFontFace === "boolean" ? src.disableFontFace : isNodeJS;
10163   const fontExtraProperties = src.fontExtraProperties === true;
10164   const enableXfa = src.enableXfa === true;
10165   const ownerDocument = src.ownerDocument || globalThis.document;
10166   const disableRange = src.disableRange === true;
10167   const disableStream = src.disableStream === true;
10168   const disableAutoFetch = src.disableAutoFetch === true;
10169   const pdfBug = src.pdfBug === true;
10170   const CanvasFactory = src.CanvasFactory || DOMCanvasFactory;
10171   const FilterFactory = src.FilterFactory || DOMFilterFactory;
10172   const enableHWA = src.enableHWA === true;
10173   const length = rangeTransport ? rangeTransport.length : src.length ?? NaN;
10174   const useSystemFonts = typeof src.useSystemFonts === "boolean" ? src.useSystemFonts : !isNodeJS && !disableFontFace;
10175   const useWorkerFetch = typeof src.useWorkerFetch === "boolean" ? src.useWorkerFetch : true;
10176   const styleElement = null;
10177   setVerbosityLevel(verbosity);
10178   const transportFactory = {
10179     canvasFactory: new CanvasFactory({
10180       ownerDocument,
10181       enableHWA
10182     }),
10183     filterFactory: new FilterFactory({
10184       docId,
10185       ownerDocument
10186     }),
10187     cMapReaderFactory: null,
10188     standardFontDataFactory: null,
10189     wasmFactory: null
10190   };
10191   if (!worker) {
10192     const workerParams = {
10193       verbosity,
10194       port: GlobalWorkerOptions.workerPort
10195     };
10196     worker = workerParams.port ? PDFWorker.fromPort(workerParams) : new PDFWorker(workerParams);
10197     task._worker = worker;
10198   }
10199   const docParams = {
10200     docId,
10201     apiVersion: "5.0.98",
10202     data,
10203     password,
10204     disableAutoFetch,
10205     rangeChunkSize,
10206     length,
10207     docBaseUrl,
10208     enableXfa,
10209     evaluatorOptions: {
10210       maxImageSize,
10211       disableFontFace,
10212       ignoreErrors,
10213       isEvalSupported,
10214       isOffscreenCanvasSupported,
10215       isImageDecoderSupported,
10216       canvasMaxAreaInBytes,
10217       fontExtraProperties,
10218       useSystemFonts,
10219       cMapUrl: useWorkerFetch ? cMapUrl : null,
10220       standardFontDataUrl: useWorkerFetch ? standardFontDataUrl : null,
10221       wasmUrl: useWorkerFetch ? wasmUrl : null
10222     }
10223   };
10224   const transportParams = {
10225     disableFontFace,
10226     fontExtraProperties,
10227     ownerDocument,
10228     pdfBug,
10229     styleElement,
10230     loadingParams: {
10231       disableAutoFetch,
10232       enableXfa
10233     }
10234   };
10235   worker.promise.then(function () {
10236     if (task.destroyed) {
10237       throw new Error("Loading aborted");
10238     }
10239     if (worker.destroyed) {
10240       throw new Error("Worker was destroyed");
10241     }
10242     const workerIdPromise = worker.messageHandler.sendWithPromise("GetDocRequest", docParams, data ? [data.buffer] : null);
10243     let networkStream;
10244     if (rangeTransport) {
10245       networkStream = new PDFDataTransportStream(rangeTransport, {
10246         disableRange,
10247         disableStream
10248       });
10249     } else if (!data) {
10250       throw new Error("Not implemented: NetworkStream");
10251     }
10252     return workerIdPromise.then(workerId => {
10253       if (task.destroyed) {
10254         throw new Error("Loading aborted");
10255       }
10256       if (worker.destroyed) {
10257         throw new Error("Worker was destroyed");
10258       }
10259       const messageHandler = new MessageHandler(docId, workerId, worker.port);
10260       const transport = new WorkerTransport(messageHandler, task, networkStream, transportParams, transportFactory);
10261       task._transport = transport;
10262       messageHandler.send("Ready", null);
10263     });
10264   }).catch(task._capability.reject);
10265   return task;
10267 function getUrlProp(val) {
10268   return null;
10270 function getDataProp(val) {
10271   if (val instanceof Uint8Array && val.byteLength === val.buffer.byteLength) {
10272     return val;
10273   }
10274   if (typeof val === "string") {
10275     return stringToBytes(val);
10276   }
10277   if (val instanceof ArrayBuffer || ArrayBuffer.isView(val) || typeof val === "object" && !isNaN(val?.length)) {
10278     return new Uint8Array(val);
10279   }
10280   throw new Error("Invalid PDF binary data: either TypedArray, " + "string, or array-like object is expected in the data property.");
10282 function getFactoryUrlProp(val) {
10283   if (typeof val !== "string") {
10284     return null;
10285   }
10286   if (val.endsWith("/")) {
10287     return val;
10288   }
10289   throw new Error(`Invalid factory url: "${val}" must include trailing slash.`);
10291 function isRefProxy(ref) {
10292   return typeof ref === "object" && Number.isInteger(ref?.num) && ref.num >= 0 && Number.isInteger(ref?.gen) && ref.gen >= 0;
10294 class PDFDocumentLoadingTask {
10295   static #docId = 0;
10296   constructor() {
10297     this._capability = Promise.withResolvers();
10298     this._transport = null;
10299     this._worker = null;
10300     this.docId = `d${PDFDocumentLoadingTask.#docId++}`;
10301     this.destroyed = false;
10302     this.onPassword = null;
10303     this.onProgress = null;
10304   }
10305   get promise() {
10306     return this._capability.promise;
10307   }
10308   async destroy() {
10309     this.destroyed = true;
10310     await this._transport?.destroy();
10311     this._transport = null;
10312     this._worker?.destroy();
10313     this._worker = null;
10314   }
10316 class PDFDataRangeTransport {
10317   constructor(length, initialData, progressiveDone = false, contentDispositionFilename = null) {
10318     this.length = length;
10319     this.initialData = initialData;
10320     this.progressiveDone = progressiveDone;
10321     this.contentDispositionFilename = contentDispositionFilename;
10322     this._rangeListeners = [];
10323     this._progressListeners = [];
10324     this._progressiveReadListeners = [];
10325     this._progressiveDoneListeners = [];
10326     this._readyCapability = Promise.withResolvers();
10327   }
10328   addRangeListener(listener) {
10329     this._rangeListeners.push(listener);
10330   }
10331   addProgressListener(listener) {
10332     this._progressListeners.push(listener);
10333   }
10334   addProgressiveReadListener(listener) {
10335     this._progressiveReadListeners.push(listener);
10336   }
10337   addProgressiveDoneListener(listener) {
10338     this._progressiveDoneListeners.push(listener);
10339   }
10340   onDataRange(begin, chunk) {
10341     for (const listener of this._rangeListeners) {
10342       listener(begin, chunk);
10343     }
10344   }
10345   onDataProgress(loaded, total) {
10346     this._readyCapability.promise.then(() => {
10347       for (const listener of this._progressListeners) {
10348         listener(loaded, total);
10349       }
10350     });
10351   }
10352   onDataProgressiveRead(chunk) {
10353     this._readyCapability.promise.then(() => {
10354       for (const listener of this._progressiveReadListeners) {
10355         listener(chunk);
10356       }
10357     });
10358   }
10359   onDataProgressiveDone() {
10360     this._readyCapability.promise.then(() => {
10361       for (const listener of this._progressiveDoneListeners) {
10362         listener();
10363       }
10364     });
10365   }
10366   transportReady() {
10367     this._readyCapability.resolve();
10368   }
10369   requestDataRange(begin, end) {
10370     unreachable("Abstract method PDFDataRangeTransport.requestDataRange");
10371   }
10372   abort() {}
10374 class PDFDocumentProxy {
10375   constructor(pdfInfo, transport) {
10376     this._pdfInfo = pdfInfo;
10377     this._transport = transport;
10378   }
10379   get annotationStorage() {
10380     return this._transport.annotationStorage;
10381   }
10382   get canvasFactory() {
10383     return this._transport.canvasFactory;
10384   }
10385   get filterFactory() {
10386     return this._transport.filterFactory;
10387   }
10388   get numPages() {
10389     return this._pdfInfo.numPages;
10390   }
10391   get fingerprints() {
10392     return this._pdfInfo.fingerprints;
10393   }
10394   get isPureXfa() {
10395     return shadow(this, "isPureXfa", !!this._transport._htmlForXfa);
10396   }
10397   get allXfaHtml() {
10398     return this._transport._htmlForXfa;
10399   }
10400   getPage(pageNumber) {
10401     return this._transport.getPage(pageNumber);
10402   }
10403   getPageIndex(ref) {
10404     return this._transport.getPageIndex(ref);
10405   }
10406   getDestinations() {
10407     return this._transport.getDestinations();
10408   }
10409   getDestination(id) {
10410     return this._transport.getDestination(id);
10411   }
10412   getPageLabels() {
10413     return this._transport.getPageLabels();
10414   }
10415   getPageLayout() {
10416     return this._transport.getPageLayout();
10417   }
10418   getPageMode() {
10419     return this._transport.getPageMode();
10420   }
10421   getViewerPreferences() {
10422     return this._transport.getViewerPreferences();
10423   }
10424   getOpenAction() {
10425     return this._transport.getOpenAction();
10426   }
10427   getAttachments() {
10428     return this._transport.getAttachments();
10429   }
10430   getJSActions() {
10431     return this._transport.getDocJSActions();
10432   }
10433   getOutline() {
10434     return this._transport.getOutline();
10435   }
10436   getOptionalContentConfig({
10437     intent = "display"
10438   } = {}) {
10439     const {
10440       renderingIntent
10441     } = this._transport.getRenderingIntent(intent);
10442     return this._transport.getOptionalContentConfig(renderingIntent);
10443   }
10444   getPermissions() {
10445     return this._transport.getPermissions();
10446   }
10447   getMetadata() {
10448     return this._transport.getMetadata();
10449   }
10450   getMarkInfo() {
10451     return this._transport.getMarkInfo();
10452   }
10453   getData() {
10454     return this._transport.getData();
10455   }
10456   saveDocument() {
10457     return this._transport.saveDocument();
10458   }
10459   getDownloadInfo() {
10460     return this._transport.downloadInfoCapability.promise;
10461   }
10462   cleanup(keepLoadedFonts = false) {
10463     return this._transport.startCleanup(keepLoadedFonts || this.isPureXfa);
10464   }
10465   destroy() {
10466     return this.loadingTask.destroy();
10467   }
10468   cachedPageNumber(ref) {
10469     return this._transport.cachedPageNumber(ref);
10470   }
10471   get loadingParams() {
10472     return this._transport.loadingParams;
10473   }
10474   get loadingTask() {
10475     return this._transport.loadingTask;
10476   }
10477   getFieldObjects() {
10478     return this._transport.getFieldObjects();
10479   }
10480   hasJSActions() {
10481     return this._transport.hasJSActions();
10482   }
10483   getCalculationOrderIds() {
10484     return this._transport.getCalculationOrderIds();
10485   }
10487 class PDFPageProxy {
10488   #pendingCleanup = false;
10489   constructor(pageIndex, pageInfo, transport, pdfBug = false) {
10490     this._pageIndex = pageIndex;
10491     this._pageInfo = pageInfo;
10492     this._transport = transport;
10493     this._stats = pdfBug ? new StatTimer() : null;
10494     this._pdfBug = pdfBug;
10495     this.commonObjs = transport.commonObjs;
10496     this.objs = new PDFObjects();
10497     this._intentStates = new Map();
10498     this.destroyed = false;
10499   }
10500   get pageNumber() {
10501     return this._pageIndex + 1;
10502   }
10503   get rotate() {
10504     return this._pageInfo.rotate;
10505   }
10506   get ref() {
10507     return this._pageInfo.ref;
10508   }
10509   get userUnit() {
10510     return this._pageInfo.userUnit;
10511   }
10512   get view() {
10513     return this._pageInfo.view;
10514   }
10515   getViewport({
10516     scale,
10517     rotation = this.rotate,
10518     offsetX = 0,
10519     offsetY = 0,
10520     dontFlip = false
10521   } = {}) {
10522     return new PageViewport({
10523       viewBox: this.view,
10524       userUnit: this.userUnit,
10525       scale,
10526       rotation,
10527       offsetX,
10528       offsetY,
10529       dontFlip
10530     });
10531   }
10532   getAnnotations({
10533     intent = "display"
10534   } = {}) {
10535     const {
10536       renderingIntent
10537     } = this._transport.getRenderingIntent(intent);
10538     return this._transport.getAnnotations(this._pageIndex, renderingIntent);
10539   }
10540   getJSActions() {
10541     return this._transport.getPageJSActions(this._pageIndex);
10542   }
10543   get filterFactory() {
10544     return this._transport.filterFactory;
10545   }
10546   get isPureXfa() {
10547     return shadow(this, "isPureXfa", !!this._transport._htmlForXfa);
10548   }
10549   async getXfa() {
10550     return this._transport._htmlForXfa?.children[this._pageIndex] || null;
10551   }
10552   render({
10553     canvasContext,
10554     viewport,
10555     intent = "display",
10556     annotationMode = AnnotationMode.ENABLE,
10557     transform = null,
10558     background = null,
10559     optionalContentConfigPromise = null,
10560     annotationCanvasMap = null,
10561     pageColors = null,
10562     printAnnotationStorage = null,
10563     isEditing = false
10564   }) {
10565     this._stats?.time("Overall");
10566     const intentArgs = this._transport.getRenderingIntent(intent, annotationMode, printAnnotationStorage, isEditing);
10567     const {
10568       renderingIntent,
10569       cacheKey
10570     } = intentArgs;
10571     this.#pendingCleanup = false;
10572     optionalContentConfigPromise ||= this._transport.getOptionalContentConfig(renderingIntent);
10573     let intentState = this._intentStates.get(cacheKey);
10574     if (!intentState) {
10575       intentState = Object.create(null);
10576       this._intentStates.set(cacheKey, intentState);
10577     }
10578     if (intentState.streamReaderCancelTimeout) {
10579       clearTimeout(intentState.streamReaderCancelTimeout);
10580       intentState.streamReaderCancelTimeout = null;
10581     }
10582     const intentPrint = !!(renderingIntent & RenderingIntentFlag.PRINT);
10583     if (!intentState.displayReadyCapability) {
10584       intentState.displayReadyCapability = Promise.withResolvers();
10585       intentState.operatorList = {
10586         fnArray: [],
10587         argsArray: [],
10588         lastChunk: false,
10589         separateAnnots: null
10590       };
10591       this._stats?.time("Page Request");
10592       this._pumpOperatorList(intentArgs);
10593     }
10594     const complete = error => {
10595       intentState.renderTasks.delete(internalRenderTask);
10596       if (intentPrint) {
10597         this.#pendingCleanup = true;
10598       }
10599       this.#tryCleanup();
10600       if (error) {
10601         internalRenderTask.capability.reject(error);
10602         this._abortOperatorList({
10603           intentState,
10604           reason: error instanceof Error ? error : new Error(error)
10605         });
10606       } else {
10607         internalRenderTask.capability.resolve();
10608       }
10609       if (this._stats) {
10610         this._stats.timeEnd("Rendering");
10611         this._stats.timeEnd("Overall");
10612         if (globalThis.Stats?.enabled) {
10613           globalThis.Stats.add(this.pageNumber, this._stats);
10614         }
10615       }
10616     };
10617     const internalRenderTask = new InternalRenderTask({
10618       callback: complete,
10619       params: {
10620         canvasContext,
10621         viewport,
10622         transform,
10623         background
10624       },
10625       objs: this.objs,
10626       commonObjs: this.commonObjs,
10627       annotationCanvasMap,
10628       operatorList: intentState.operatorList,
10629       pageIndex: this._pageIndex,
10630       canvasFactory: this._transport.canvasFactory,
10631       filterFactory: this._transport.filterFactory,
10632       useRequestAnimationFrame: !intentPrint,
10633       pdfBug: this._pdfBug,
10634       pageColors
10635     });
10636     (intentState.renderTasks ||= new Set()).add(internalRenderTask);
10637     const renderTask = internalRenderTask.task;
10638     Promise.all([intentState.displayReadyCapability.promise, optionalContentConfigPromise]).then(([transparency, optionalContentConfig]) => {
10639       if (this.destroyed) {
10640         complete();
10641         return;
10642       }
10643       this._stats?.time("Rendering");
10644       if (!(optionalContentConfig.renderingIntent & renderingIntent)) {
10645         throw new Error("Must use the same `intent`-argument when calling the `PDFPageProxy.render` " + "and `PDFDocumentProxy.getOptionalContentConfig` methods.");
10646       }
10647       internalRenderTask.initializeGraphics({
10648         transparency,
10649         optionalContentConfig
10650       });
10651       internalRenderTask.operatorListChanged();
10652     }).catch(complete);
10653     return renderTask;
10654   }
10655   getOperatorList({
10656     intent = "display",
10657     annotationMode = AnnotationMode.ENABLE,
10658     printAnnotationStorage = null,
10659     isEditing = false
10660   } = {}) {
10661     throw new Error("Not implemented: getOperatorList");
10662   }
10663   streamTextContent({
10664     includeMarkedContent = false,
10665     disableNormalization = false
10666   } = {}) {
10667     const TEXT_CONTENT_CHUNK_SIZE = 100;
10668     return this._transport.messageHandler.sendWithStream("GetTextContent", {
10669       pageIndex: this._pageIndex,
10670       includeMarkedContent: includeMarkedContent === true,
10671       disableNormalization: disableNormalization === true
10672     }, {
10673       highWaterMark: TEXT_CONTENT_CHUNK_SIZE,
10674       size(textContent) {
10675         return textContent.items.length;
10676       }
10677     });
10678   }
10679   getTextContent(params = {}) {
10680     if (this._transport._htmlForXfa) {
10681       return this.getXfa().then(xfa => XfaText.textContent(xfa));
10682     }
10683     const readableStream = this.streamTextContent(params);
10684     return new Promise(function (resolve, reject) {
10685       function pump() {
10686         reader.read().then(function ({
10687           value,
10688           done
10689         }) {
10690           if (done) {
10691             resolve(textContent);
10692             return;
10693           }
10694           textContent.lang ??= value.lang;
10695           Object.assign(textContent.styles, value.styles);
10696           textContent.items.push(...value.items);
10697           pump();
10698         }, reject);
10699       }
10700       const reader = readableStream.getReader();
10701       const textContent = {
10702         items: [],
10703         styles: Object.create(null),
10704         lang: null
10705       };
10706       pump();
10707     });
10708   }
10709   getStructTree() {
10710     return this._transport.getStructTree(this._pageIndex);
10711   }
10712   _destroy() {
10713     this.destroyed = true;
10714     const waitOn = [];
10715     for (const intentState of this._intentStates.values()) {
10716       this._abortOperatorList({
10717         intentState,
10718         reason: new Error("Page was destroyed."),
10719         force: true
10720       });
10721       if (intentState.opListReadCapability) {
10722         continue;
10723       }
10724       for (const internalRenderTask of intentState.renderTasks) {
10725         waitOn.push(internalRenderTask.completed);
10726         internalRenderTask.cancel();
10727       }
10728     }
10729     this.objs.clear();
10730     this.#pendingCleanup = false;
10731     return Promise.all(waitOn);
10732   }
10733   cleanup(resetStats = false) {
10734     this.#pendingCleanup = true;
10735     const success = this.#tryCleanup();
10736     if (resetStats && success) {
10737       this._stats &&= new StatTimer();
10738     }
10739     return success;
10740   }
10741   #tryCleanup() {
10742     if (!this.#pendingCleanup || this.destroyed) {
10743       return false;
10744     }
10745     for (const {
10746       renderTasks,
10747       operatorList
10748     } of this._intentStates.values()) {
10749       if (renderTasks.size > 0 || !operatorList.lastChunk) {
10750         return false;
10751       }
10752     }
10753     this._intentStates.clear();
10754     this.objs.clear();
10755     this.#pendingCleanup = false;
10756     return true;
10757   }
10758   _startRenderPage(transparency, cacheKey) {
10759     const intentState = this._intentStates.get(cacheKey);
10760     if (!intentState) {
10761       return;
10762     }
10763     this._stats?.timeEnd("Page Request");
10764     intentState.displayReadyCapability?.resolve(transparency);
10765   }
10766   _renderPageChunk(operatorListChunk, intentState) {
10767     for (let i = 0, ii = operatorListChunk.length; i < ii; i++) {
10768       intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
10769       intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]);
10770     }
10771     intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
10772     intentState.operatorList.separateAnnots = operatorListChunk.separateAnnots;
10773     for (const internalRenderTask of intentState.renderTasks) {
10774       internalRenderTask.operatorListChanged();
10775     }
10776     if (operatorListChunk.lastChunk) {
10777       this.#tryCleanup();
10778     }
10779   }
10780   _pumpOperatorList({
10781     renderingIntent,
10782     cacheKey,
10783     annotationStorageSerializable,
10784     modifiedIds
10785   }) {
10786     const {
10787       map,
10788       transfer
10789     } = annotationStorageSerializable;
10790     const readableStream = this._transport.messageHandler.sendWithStream("GetOperatorList", {
10791       pageIndex: this._pageIndex,
10792       intent: renderingIntent,
10793       cacheKey,
10794       annotationStorage: map,
10795       modifiedIds
10796     }, transfer);
10797     const reader = readableStream.getReader();
10798     const intentState = this._intentStates.get(cacheKey);
10799     intentState.streamReader = reader;
10800     const pump = () => {
10801       reader.read().then(({
10802         value,
10803         done
10804       }) => {
10805         if (done) {
10806           intentState.streamReader = null;
10807           return;
10808         }
10809         if (this._transport.destroyed) {
10810           return;
10811         }
10812         this._renderPageChunk(value, intentState);
10813         pump();
10814       }, reason => {
10815         intentState.streamReader = null;
10816         if (this._transport.destroyed) {
10817           return;
10818         }
10819         if (intentState.operatorList) {
10820           intentState.operatorList.lastChunk = true;
10821           for (const internalRenderTask of intentState.renderTasks) {
10822             internalRenderTask.operatorListChanged();
10823           }
10824           this.#tryCleanup();
10825         }
10826         if (intentState.displayReadyCapability) {
10827           intentState.displayReadyCapability.reject(reason);
10828         } else if (intentState.opListReadCapability) {
10829           intentState.opListReadCapability.reject(reason);
10830         } else {
10831           throw reason;
10832         }
10833       });
10834     };
10835     pump();
10836   }
10837   _abortOperatorList({
10838     intentState,
10839     reason,
10840     force = false
10841   }) {
10842     if (!intentState.streamReader) {
10843       return;
10844     }
10845     if (intentState.streamReaderCancelTimeout) {
10846       clearTimeout(intentState.streamReaderCancelTimeout);
10847       intentState.streamReaderCancelTimeout = null;
10848     }
10849     if (!force) {
10850       if (intentState.renderTasks.size > 0) {
10851         return;
10852       }
10853       if (reason instanceof RenderingCancelledException) {
10854         let delay = RENDERING_CANCELLED_TIMEOUT;
10855         if (reason.extraDelay > 0 && reason.extraDelay < 1000) {
10856           delay += reason.extraDelay;
10857         }
10858         intentState.streamReaderCancelTimeout = setTimeout(() => {
10859           intentState.streamReaderCancelTimeout = null;
10860           this._abortOperatorList({
10861             intentState,
10862             reason,
10863             force: true
10864           });
10865         }, delay);
10866         return;
10867       }
10868     }
10869     intentState.streamReader.cancel(new AbortException(reason.message)).catch(() => {});
10870     intentState.streamReader = null;
10871     if (this._transport.destroyed) {
10872       return;
10873     }
10874     for (const [curCacheKey, curIntentState] of this._intentStates) {
10875       if (curIntentState === intentState) {
10876         this._intentStates.delete(curCacheKey);
10877         break;
10878       }
10879     }
10880     this.cleanup();
10881   }
10882   get stats() {
10883     return this._stats;
10884   }
10886 class LoopbackPort {
10887   #listeners = new Map();
10888   #deferred = Promise.resolve();
10889   postMessage(obj, transfer) {
10890     const event = {
10891       data: structuredClone(obj, transfer ? {
10892         transfer
10893       } : null)
10894     };
10895     this.#deferred.then(() => {
10896       for (const [listener] of this.#listeners) {
10897         listener.call(this, event);
10898       }
10899     });
10900   }
10901   addEventListener(name, listener, options = null) {
10902     let rmAbort = null;
10903     if (options?.signal instanceof AbortSignal) {
10904       const {
10905         signal
10906       } = options;
10907       if (signal.aborted) {
10908         warn("LoopbackPort - cannot use an `aborted` signal.");
10909         return;
10910       }
10911       const onAbort = () => this.removeEventListener(name, listener);
10912       rmAbort = () => signal.removeEventListener("abort", onAbort);
10913       signal.addEventListener("abort", onAbort);
10914     }
10915     this.#listeners.set(listener, rmAbort);
10916   }
10917   removeEventListener(name, listener) {
10918     const rmAbort = this.#listeners.get(listener);
10919     rmAbort?.();
10920     this.#listeners.delete(listener);
10921   }
10922   terminate() {
10923     for (const [, rmAbort] of this.#listeners) {
10924       rmAbort?.();
10925     }
10926     this.#listeners.clear();
10927   }
10929 class PDFWorker {
10930   static #fakeWorkerId = 0;
10931   static #isWorkerDisabled = false;
10932   static #workerPorts;
10933   constructor({
10934     name = null,
10935     port = null,
10936     verbosity = getVerbosityLevel()
10937   } = {}) {
10938     this.name = name;
10939     this.destroyed = false;
10940     this.verbosity = verbosity;
10941     this._readyCapability = Promise.withResolvers();
10942     this._port = null;
10943     this._webWorker = null;
10944     this._messageHandler = null;
10945     this._initialize();
10946   }
10947   get promise() {
10948     return this._readyCapability.promise;
10949   }
10950   #resolve() {
10951     this._readyCapability.resolve();
10952     this._messageHandler.send("configure", {
10953       verbosity: this.verbosity
10954     });
10955   }
10956   get port() {
10957     return this._port;
10958   }
10959   get messageHandler() {
10960     return this._messageHandler;
10961   }
10962   _initializeFromPort(port) {
10963     throw new Error("Not implemented: _initializeFromPort");
10964   }
10965   _initialize() {
10966     if (PDFWorker.#isWorkerDisabled || PDFWorker.#mainThreadWorkerMessageHandler) {
10967       this._setupFakeWorker();
10968       return;
10969     }
10970     let {
10971       workerSrc
10972     } = PDFWorker;
10973     try {
10974       const worker = new Worker(workerSrc, {
10975         type: "module"
10976       });
10977       const messageHandler = new MessageHandler("main", "worker", worker);
10978       const terminateEarly = () => {
10979         ac.abort();
10980         messageHandler.destroy();
10981         worker.terminate();
10982         if (this.destroyed) {
10983           this._readyCapability.reject(new Error("Worker was destroyed"));
10984         } else {
10985           this._setupFakeWorker();
10986         }
10987       };
10988       const ac = new AbortController();
10989       worker.addEventListener("error", () => {
10990         if (!this._webWorker) {
10991           terminateEarly();
10992         }
10993       }, {
10994         signal: ac.signal
10995       });
10996       messageHandler.on("test", data => {
10997         ac.abort();
10998         if (this.destroyed || !data) {
10999           terminateEarly();
11000           return;
11001         }
11002         this._messageHandler = messageHandler;
11003         this._port = worker;
11004         this._webWorker = worker;
11005         this.#resolve();
11006       });
11007       messageHandler.on("ready", data => {
11008         ac.abort();
11009         if (this.destroyed) {
11010           terminateEarly();
11011           return;
11012         }
11013         try {
11014           sendTest();
11015         } catch {
11016           this._setupFakeWorker();
11017         }
11018       });
11019       const sendTest = () => {
11020         const testObj = new Uint8Array();
11021         messageHandler.send("test", testObj, [testObj.buffer]);
11022       };
11023       sendTest();
11024       return;
11025     } catch {
11026       info("The worker has been disabled.");
11027     }
11028     this._setupFakeWorker();
11029   }
11030   _setupFakeWorker() {
11031     if (!PDFWorker.#isWorkerDisabled) {
11032       warn("Setting up fake worker.");
11033       PDFWorker.#isWorkerDisabled = true;
11034     }
11035     PDFWorker._setupFakeWorkerGlobal.then(WorkerMessageHandler => {
11036       if (this.destroyed) {
11037         this._readyCapability.reject(new Error("Worker was destroyed"));
11038         return;
11039       }
11040       const port = new LoopbackPort();
11041       this._port = port;
11042       const id = `fake${PDFWorker.#fakeWorkerId++}`;
11043       const workerHandler = new MessageHandler(id + "_worker", id, port);
11044       WorkerMessageHandler.setup(workerHandler, port);
11045       this._messageHandler = new MessageHandler(id, id + "_worker", port);
11046       this.#resolve();
11047     }).catch(reason => {
11048       this._readyCapability.reject(new Error(`Setting up fake worker failed: "${reason.message}".`));
11049     });
11050   }
11051   destroy() {
11052     this.destroyed = true;
11053     this._webWorker?.terminate();
11054     this._webWorker = null;
11055     PDFWorker.#workerPorts?.delete(this._port);
11056     this._port = null;
11057     this._messageHandler?.destroy();
11058     this._messageHandler = null;
11059   }
11060   static fromPort(params) {
11061     throw new Error("Not implemented: fromPort");
11062   }
11063   static get workerSrc() {
11064     if (GlobalWorkerOptions.workerSrc) {
11065       return GlobalWorkerOptions.workerSrc;
11066     }
11067     throw new Error('No "GlobalWorkerOptions.workerSrc" specified.');
11068   }
11069   static get #mainThreadWorkerMessageHandler() {
11070     try {
11071       return globalThis.pdfjsWorker?.WorkerMessageHandler || null;
11072     } catch {
11073       return null;
11074     }
11075   }
11076   static get _setupFakeWorkerGlobal() {
11077     const loader = async () => {
11078       if (this.#mainThreadWorkerMessageHandler) {
11079         return this.#mainThreadWorkerMessageHandler;
11080       }
11081       const worker = await import(/*webpackIgnore: true*/this.workerSrc);
11082       return worker.WorkerMessageHandler;
11083     };
11084     return shadow(this, "_setupFakeWorkerGlobal", loader());
11085   }
11087 class WorkerTransport {
11088   #methodPromises = new Map();
11089   #pageCache = new Map();
11090   #pagePromises = new Map();
11091   #pageRefCache = new Map();
11092   #passwordCapability = null;
11093   constructor(messageHandler, loadingTask, networkStream, params, factory) {
11094     this.messageHandler = messageHandler;
11095     this.loadingTask = loadingTask;
11096     this.commonObjs = new PDFObjects();
11097     this.fontLoader = new FontLoader({
11098       ownerDocument: params.ownerDocument,
11099       styleElement: params.styleElement
11100     });
11101     this.loadingParams = params.loadingParams;
11102     this._params = params;
11103     this.canvasFactory = factory.canvasFactory;
11104     this.filterFactory = factory.filterFactory;
11105     this.cMapReaderFactory = factory.cMapReaderFactory;
11106     this.standardFontDataFactory = factory.standardFontDataFactory;
11107     this.wasmFactory = factory.wasmFactory;
11108     this.destroyed = false;
11109     this.destroyCapability = null;
11110     this._networkStream = networkStream;
11111     this._fullReader = null;
11112     this._lastProgress = null;
11113     this.downloadInfoCapability = Promise.withResolvers();
11114     this.setupMessageHandler();
11115   }
11116   #cacheSimpleMethod(name, data = null) {
11117     const cachedPromise = this.#methodPromises.get(name);
11118     if (cachedPromise) {
11119       return cachedPromise;
11120     }
11121     const promise = this.messageHandler.sendWithPromise(name, data);
11122     this.#methodPromises.set(name, promise);
11123     return promise;
11124   }
11125   get annotationStorage() {
11126     return shadow(this, "annotationStorage", new AnnotationStorage());
11127   }
11128   getRenderingIntent(intent, annotationMode = AnnotationMode.ENABLE, printAnnotationStorage = null, isEditing = false, isOpList = false) {
11129     let renderingIntent = RenderingIntentFlag.DISPLAY;
11130     let annotationStorageSerializable = SerializableEmpty;
11131     switch (intent) {
11132       case "any":
11133         renderingIntent = RenderingIntentFlag.ANY;
11134         break;
11135       case "display":
11136         break;
11137       case "print":
11138         renderingIntent = RenderingIntentFlag.PRINT;
11139         break;
11140       default:
11141         warn(`getRenderingIntent - invalid intent: ${intent}`);
11142     }
11143     const annotationStorage = renderingIntent & RenderingIntentFlag.PRINT && printAnnotationStorage instanceof PrintAnnotationStorage ? printAnnotationStorage : this.annotationStorage;
11144     switch (annotationMode) {
11145       case AnnotationMode.DISABLE:
11146         renderingIntent += RenderingIntentFlag.ANNOTATIONS_DISABLE;
11147         break;
11148       case AnnotationMode.ENABLE:
11149         break;
11150       case AnnotationMode.ENABLE_FORMS:
11151         renderingIntent += RenderingIntentFlag.ANNOTATIONS_FORMS;
11152         break;
11153       case AnnotationMode.ENABLE_STORAGE:
11154         renderingIntent += RenderingIntentFlag.ANNOTATIONS_STORAGE;
11155         annotationStorageSerializable = annotationStorage.serializable;
11156         break;
11157       default:
11158         warn(`getRenderingIntent - invalid annotationMode: ${annotationMode}`);
11159     }
11160     if (isEditing) {
11161       renderingIntent += RenderingIntentFlag.IS_EDITING;
11162     }
11163     if (isOpList) {
11164       renderingIntent += RenderingIntentFlag.OPLIST;
11165     }
11166     const {
11167       ids: modifiedIds,
11168       hash: modifiedIdsHash
11169     } = annotationStorage.modifiedIds;
11170     const cacheKeyBuf = [renderingIntent, annotationStorageSerializable.hash, modifiedIdsHash];
11171     return {
11172       renderingIntent,
11173       cacheKey: cacheKeyBuf.join("_"),
11174       annotationStorageSerializable,
11175       modifiedIds
11176     };
11177   }
11178   destroy() {
11179     if (this.destroyCapability) {
11180       return this.destroyCapability.promise;
11181     }
11182     this.destroyed = true;
11183     this.destroyCapability = Promise.withResolvers();
11184     this.#passwordCapability?.reject(new Error("Worker was destroyed during onPassword callback"));
11185     const waitOn = [];
11186     for (const page of this.#pageCache.values()) {
11187       waitOn.push(page._destroy());
11188     }
11189     this.#pageCache.clear();
11190     this.#pagePromises.clear();
11191     this.#pageRefCache.clear();
11192     if (this.hasOwnProperty("annotationStorage")) {
11193       this.annotationStorage.resetModified();
11194     }
11195     const terminated = this.messageHandler.sendWithPromise("Terminate", null);
11196     waitOn.push(terminated);
11197     Promise.all(waitOn).then(() => {
11198       this.commonObjs.clear();
11199       this.fontLoader.clear();
11200       this.#methodPromises.clear();
11201       this.filterFactory.destroy();
11202       TextLayer.cleanup();
11203       this._networkStream?.cancelAllRequests(new AbortException("Worker was terminated."));
11204       this.messageHandler?.destroy();
11205       this.messageHandler = null;
11206       this.destroyCapability.resolve();
11207     }, this.destroyCapability.reject);
11208     return this.destroyCapability.promise;
11209   }
11210   setupMessageHandler() {
11211     const {
11212       messageHandler,
11213       loadingTask
11214     } = this;
11215     messageHandler.on("GetReader", (data, sink) => {
11216       assert(this._networkStream, "GetReader - no `IPDFStream` instance available.");
11217       this._fullReader = this._networkStream.getFullReader();
11218       this._fullReader.onProgress = evt => {
11219         this._lastProgress = {
11220           loaded: evt.loaded,
11221           total: evt.total
11222         };
11223       };
11224       sink.onPull = () => {
11225         this._fullReader.read().then(function ({
11226           value,
11227           done
11228         }) {
11229           if (done) {
11230             sink.close();
11231             return;
11232           }
11233           assert(value instanceof ArrayBuffer, "GetReader - expected an ArrayBuffer.");
11234           sink.enqueue(new Uint8Array(value), 1, [value]);
11235         }).catch(reason => {
11236           sink.error(reason);
11237         });
11238       };
11239       sink.onCancel = reason => {
11240         this._fullReader.cancel(reason);
11241         sink.ready.catch(readyReason => {
11242           if (this.destroyed) {
11243             return;
11244           }
11245           throw readyReason;
11246         });
11247       };
11248     });
11249     messageHandler.on("ReaderHeadersReady", async data => {
11250       await this._fullReader.headersReady;
11251       const {
11252         isStreamingSupported,
11253         isRangeSupported,
11254         contentLength
11255       } = this._fullReader;
11256       if (!isStreamingSupported || !isRangeSupported) {
11257         if (this._lastProgress) {
11258           loadingTask.onProgress?.(this._lastProgress);
11259         }
11260         this._fullReader.onProgress = evt => {
11261           loadingTask.onProgress?.({
11262             loaded: evt.loaded,
11263             total: evt.total
11264           });
11265         };
11266       }
11267       return {
11268         isStreamingSupported,
11269         isRangeSupported,
11270         contentLength
11271       };
11272     });
11273     messageHandler.on("GetRangeReader", (data, sink) => {
11274       assert(this._networkStream, "GetRangeReader - no `IPDFStream` instance available.");
11275       const rangeReader = this._networkStream.getRangeReader(data.begin, data.end);
11276       if (!rangeReader) {
11277         sink.close();
11278         return;
11279       }
11280       sink.onPull = () => {
11281         rangeReader.read().then(function ({
11282           value,
11283           done
11284         }) {
11285           if (done) {
11286             sink.close();
11287             return;
11288           }
11289           assert(value instanceof ArrayBuffer, "GetRangeReader - expected an ArrayBuffer.");
11290           sink.enqueue(new Uint8Array(value), 1, [value]);
11291         }).catch(reason => {
11292           sink.error(reason);
11293         });
11294       };
11295       sink.onCancel = reason => {
11296         rangeReader.cancel(reason);
11297         sink.ready.catch(readyReason => {
11298           if (this.destroyed) {
11299             return;
11300           }
11301           throw readyReason;
11302         });
11303       };
11304     });
11305     messageHandler.on("GetDoc", ({
11306       pdfInfo
11307     }) => {
11308       this._numPages = pdfInfo.numPages;
11309       this._htmlForXfa = pdfInfo.htmlForXfa;
11310       delete pdfInfo.htmlForXfa;
11311       loadingTask._capability.resolve(new PDFDocumentProxy(pdfInfo, this));
11312     });
11313     messageHandler.on("DocException", ex => {
11314       loadingTask._capability.reject(wrapReason(ex));
11315     });
11316     messageHandler.on("PasswordRequest", ex => {
11317       this.#passwordCapability = Promise.withResolvers();
11318       try {
11319         if (!loadingTask.onPassword) {
11320           throw wrapReason(ex);
11321         }
11322         const updatePassword = password => {
11323           if (password instanceof Error) {
11324             this.#passwordCapability.reject(password);
11325           } else {
11326             this.#passwordCapability.resolve({
11327               password
11328             });
11329           }
11330         };
11331         loadingTask.onPassword(updatePassword, ex.code);
11332       } catch (err) {
11333         this.#passwordCapability.reject(err);
11334       }
11335       return this.#passwordCapability.promise;
11336     });
11337     messageHandler.on("DataLoaded", data => {
11338       loadingTask.onProgress?.({
11339         loaded: data.length,
11340         total: data.length
11341       });
11342       this.downloadInfoCapability.resolve(data);
11343     });
11344     messageHandler.on("StartRenderPage", data => {
11345       if (this.destroyed) {
11346         return;
11347       }
11348       const page = this.#pageCache.get(data.pageIndex);
11349       page._startRenderPage(data.transparency, data.cacheKey);
11350     });
11351     messageHandler.on("commonobj", ([id, type, exportedData]) => {
11352       if (this.destroyed) {
11353         return null;
11354       }
11355       if (this.commonObjs.has(id)) {
11356         return null;
11357       }
11358       switch (type) {
11359         case "Font":
11360           const {
11361             disableFontFace,
11362             fontExtraProperties,
11363             pdfBug
11364           } = this._params;
11365           if ("error" in exportedData) {
11366             const exportedError = exportedData.error;
11367             warn(`Error during font loading: ${exportedError}`);
11368             this.commonObjs.resolve(id, exportedError);
11369             break;
11370           }
11371           const inspectFont = pdfBug && globalThis.FontInspector?.enabled ? (font, url) => globalThis.FontInspector.fontAdded(font, url) : null;
11372           const font = new FontFaceObject(exportedData, {
11373             disableFontFace,
11374             fontExtraProperties,
11375             inspectFont
11376           });
11377           this.fontLoader.bind(font).catch(() => messageHandler.sendWithPromise("FontFallback", {
11378             id
11379           })).finally(() => {
11380             if (!fontExtraProperties && font.data) {
11381               font.data = null;
11382             }
11383             this.commonObjs.resolve(id, font);
11384           });
11385           break;
11386         case "CopyLocalImage":
11387           const {
11388             imageRef
11389           } = exportedData;
11390           assert(imageRef, "The imageRef must be defined.");
11391           for (const pageProxy of this.#pageCache.values()) {
11392             for (const [, data] of pageProxy.objs) {
11393               if (data?.ref !== imageRef) {
11394                 continue;
11395               }
11396               if (!data.dataLen) {
11397                 return null;
11398               }
11399               this.commonObjs.resolve(id, structuredClone(data));
11400               return data.dataLen;
11401             }
11402           }
11403           break;
11404         case "FontPath":
11405         case "Image":
11406         case "Pattern":
11407           this.commonObjs.resolve(id, exportedData);
11408           break;
11409         default:
11410           throw new Error(`Got unknown common object type ${type}`);
11411       }
11412       return null;
11413     });
11414     messageHandler.on("obj", ([id, pageIndex, type, imageData]) => {
11415       if (this.destroyed) {
11416         return;
11417       }
11418       const pageProxy = this.#pageCache.get(pageIndex);
11419       if (pageProxy.objs.has(id)) {
11420         return;
11421       }
11422       if (pageProxy._intentStates.size === 0) {
11423         imageData?.bitmap?.close();
11424         return;
11425       }
11426       switch (type) {
11427         case "Image":
11428         case "Pattern":
11429           pageProxy.objs.resolve(id, imageData);
11430           break;
11431         default:
11432           throw new Error(`Got unknown object type ${type}`);
11433       }
11434     });
11435     messageHandler.on("DocProgress", data => {
11436       if (this.destroyed) {
11437         return;
11438       }
11439       loadingTask.onProgress?.({
11440         loaded: data.loaded,
11441         total: data.total
11442       });
11443     });
11444     messageHandler.on("FetchBuiltInCMap", async data => {
11445       throw new Error("Not implemented: FetchBuiltInCMap");
11446     });
11447     messageHandler.on("FetchStandardFontData", async data => {
11448       throw new Error("Not implemented: FetchStandardFontData");
11449     });
11450     messageHandler.on("FetchWasm", async data => {
11451       throw new Error("Not implemented: FetchWasm");
11452     });
11453   }
11454   getData() {
11455     return this.messageHandler.sendWithPromise("GetData", null);
11456   }
11457   saveDocument() {
11458     if (this.annotationStorage.size <= 0) {
11459       warn("saveDocument called while `annotationStorage` is empty, " + "please use the getData-method instead.");
11460     }
11461     const {
11462       map,
11463       transfer
11464     } = this.annotationStorage.serializable;
11465     return this.messageHandler.sendWithPromise("SaveDocument", {
11466       isPureXfa: !!this._htmlForXfa,
11467       numPages: this._numPages,
11468       annotationStorage: map,
11469       filename: this._fullReader?.filename ?? null
11470     }, transfer).finally(() => {
11471       this.annotationStorage.resetModified();
11472     });
11473   }
11474   getPage(pageNumber) {
11475     if (!Number.isInteger(pageNumber) || pageNumber <= 0 || pageNumber > this._numPages) {
11476       return Promise.reject(new Error("Invalid page request."));
11477     }
11478     const pageIndex = pageNumber - 1,
11479       cachedPromise = this.#pagePromises.get(pageIndex);
11480     if (cachedPromise) {
11481       return cachedPromise;
11482     }
11483     const promise = this.messageHandler.sendWithPromise("GetPage", {
11484       pageIndex
11485     }).then(pageInfo => {
11486       if (this.destroyed) {
11487         throw new Error("Transport destroyed");
11488       }
11489       if (pageInfo.refStr) {
11490         this.#pageRefCache.set(pageInfo.refStr, pageNumber);
11491       }
11492       const page = new PDFPageProxy(pageIndex, pageInfo, this, this._params.pdfBug);
11493       this.#pageCache.set(pageIndex, page);
11494       return page;
11495     });
11496     this.#pagePromises.set(pageIndex, promise);
11497     return promise;
11498   }
11499   getPageIndex(ref) {
11500     if (!isRefProxy(ref)) {
11501       return Promise.reject(new Error("Invalid pageIndex request."));
11502     }
11503     return this.messageHandler.sendWithPromise("GetPageIndex", {
11504       num: ref.num,
11505       gen: ref.gen
11506     });
11507   }
11508   getAnnotations(pageIndex, intent) {
11509     return this.messageHandler.sendWithPromise("GetAnnotations", {
11510       pageIndex,
11511       intent
11512     });
11513   }
11514   getFieldObjects() {
11515     return this.#cacheSimpleMethod("GetFieldObjects");
11516   }
11517   hasJSActions() {
11518     return this.#cacheSimpleMethod("HasJSActions");
11519   }
11520   getCalculationOrderIds() {
11521     return this.messageHandler.sendWithPromise("GetCalculationOrderIds", null);
11522   }
11523   getDestinations() {
11524     return this.messageHandler.sendWithPromise("GetDestinations", null);
11525   }
11526   getDestination(id) {
11527     if (typeof id !== "string") {
11528       return Promise.reject(new Error("Invalid destination request."));
11529     }
11530     return this.messageHandler.sendWithPromise("GetDestination", {
11531       id
11532     });
11533   }
11534   getPageLabels() {
11535     return this.messageHandler.sendWithPromise("GetPageLabels", null);
11536   }
11537   getPageLayout() {
11538     return this.messageHandler.sendWithPromise("GetPageLayout", null);
11539   }
11540   getPageMode() {
11541     return this.messageHandler.sendWithPromise("GetPageMode", null);
11542   }
11543   getViewerPreferences() {
11544     return this.messageHandler.sendWithPromise("GetViewerPreferences", null);
11545   }
11546   getOpenAction() {
11547     return this.messageHandler.sendWithPromise("GetOpenAction", null);
11548   }
11549   getAttachments() {
11550     return this.messageHandler.sendWithPromise("GetAttachments", null);
11551   }
11552   getDocJSActions() {
11553     return this.#cacheSimpleMethod("GetDocJSActions");
11554   }
11555   getPageJSActions(pageIndex) {
11556     return this.messageHandler.sendWithPromise("GetPageJSActions", {
11557       pageIndex
11558     });
11559   }
11560   getStructTree(pageIndex) {
11561     return this.messageHandler.sendWithPromise("GetStructTree", {
11562       pageIndex
11563     });
11564   }
11565   getOutline() {
11566     return this.messageHandler.sendWithPromise("GetOutline", null);
11567   }
11568   getOptionalContentConfig(renderingIntent) {
11569     return this.#cacheSimpleMethod("GetOptionalContentConfig").then(data => new OptionalContentConfig(data, renderingIntent));
11570   }
11571   getPermissions() {
11572     return this.messageHandler.sendWithPromise("GetPermissions", null);
11573   }
11574   getMetadata() {
11575     const name = "GetMetadata",
11576       cachedPromise = this.#methodPromises.get(name);
11577     if (cachedPromise) {
11578       return cachedPromise;
11579     }
11580     const promise = this.messageHandler.sendWithPromise(name, null).then(results => ({
11581       info: results[0],
11582       metadata: results[1] ? new Metadata(results[1]) : null,
11583       contentDispositionFilename: this._fullReader?.filename ?? null,
11584       contentLength: this._fullReader?.contentLength ?? null
11585     }));
11586     this.#methodPromises.set(name, promise);
11587     return promise;
11588   }
11589   getMarkInfo() {
11590     return this.messageHandler.sendWithPromise("GetMarkInfo", null);
11591   }
11592   async startCleanup(keepLoadedFonts = false) {
11593     if (this.destroyed) {
11594       return;
11595     }
11596     await this.messageHandler.sendWithPromise("Cleanup", null);
11597     for (const page of this.#pageCache.values()) {
11598       const cleanupSuccessful = page.cleanup();
11599       if (!cleanupSuccessful) {
11600         throw new Error(`startCleanup: Page ${page.pageNumber} is currently rendering.`);
11601       }
11602     }
11603     this.commonObjs.clear();
11604     if (!keepLoadedFonts) {
11605       this.fontLoader.clear();
11606     }
11607     this.#methodPromises.clear();
11608     this.filterFactory.destroy(true);
11609     TextLayer.cleanup();
11610   }
11611   cachedPageNumber(ref) {
11612     if (!isRefProxy(ref)) {
11613       return null;
11614     }
11615     const refStr = ref.gen === 0 ? `${ref.num}R` : `${ref.num}R${ref.gen}`;
11616     return this.#pageRefCache.get(refStr) ?? null;
11617   }
11619 const INITIAL_DATA = Symbol("INITIAL_DATA");
11620 class PDFObjects {
11621   #objs = Object.create(null);
11622   #ensureObj(objId) {
11623     return this.#objs[objId] ||= {
11624       ...Promise.withResolvers(),
11625       data: INITIAL_DATA
11626     };
11627   }
11628   get(objId, callback = null) {
11629     if (callback) {
11630       const obj = this.#ensureObj(objId);
11631       obj.promise.then(() => callback(obj.data));
11632       return null;
11633     }
11634     const obj = this.#objs[objId];
11635     if (!obj || obj.data === INITIAL_DATA) {
11636       throw new Error(`Requesting object that isn't resolved yet ${objId}.`);
11637     }
11638     return obj.data;
11639   }
11640   has(objId) {
11641     const obj = this.#objs[objId];
11642     return !!obj && obj.data !== INITIAL_DATA;
11643   }
11644   delete(objId) {
11645     const obj = this.#objs[objId];
11646     if (!obj || obj.data === INITIAL_DATA) {
11647       return false;
11648     }
11649     delete this.#objs[objId];
11650     return true;
11651   }
11652   resolve(objId, data = null) {
11653     const obj = this.#ensureObj(objId);
11654     obj.data = data;
11655     obj.resolve();
11656   }
11657   clear() {
11658     for (const objId in this.#objs) {
11659       const {
11660         data
11661       } = this.#objs[objId];
11662       data?.bitmap?.close();
11663     }
11664     this.#objs = Object.create(null);
11665   }
11666   *[Symbol.iterator]() {
11667     for (const objId in this.#objs) {
11668       const {
11669         data
11670       } = this.#objs[objId];
11671       if (data === INITIAL_DATA) {
11672         continue;
11673       }
11674       yield [objId, data];
11675     }
11676   }
11678 class RenderTask {
11679   #internalRenderTask = null;
11680   constructor(internalRenderTask) {
11681     this.#internalRenderTask = internalRenderTask;
11682     this.onContinue = null;
11683   }
11684   get promise() {
11685     return this.#internalRenderTask.capability.promise;
11686   }
11687   cancel(extraDelay = 0) {
11688     this.#internalRenderTask.cancel(null, extraDelay);
11689   }
11690   get separateAnnots() {
11691     const {
11692       separateAnnots
11693     } = this.#internalRenderTask.operatorList;
11694     if (!separateAnnots) {
11695       return false;
11696     }
11697     const {
11698       annotationCanvasMap
11699     } = this.#internalRenderTask;
11700     return separateAnnots.form || separateAnnots.canvas && annotationCanvasMap?.size > 0;
11701   }
11703 class InternalRenderTask {
11704   #rAF = null;
11705   static #canvasInUse = new WeakSet();
11706   constructor({
11707     callback,
11708     params,
11709     objs,
11710     commonObjs,
11711     annotationCanvasMap,
11712     operatorList,
11713     pageIndex,
11714     canvasFactory,
11715     filterFactory,
11716     useRequestAnimationFrame = false,
11717     pdfBug = false,
11718     pageColors = null
11719   }) {
11720     this.callback = callback;
11721     this.params = params;
11722     this.objs = objs;
11723     this.commonObjs = commonObjs;
11724     this.annotationCanvasMap = annotationCanvasMap;
11725     this.operatorListIdx = null;
11726     this.operatorList = operatorList;
11727     this._pageIndex = pageIndex;
11728     this.canvasFactory = canvasFactory;
11729     this.filterFactory = filterFactory;
11730     this._pdfBug = pdfBug;
11731     this.pageColors = pageColors;
11732     this.running = false;
11733     this.graphicsReadyCallback = null;
11734     this.graphicsReady = false;
11735     this._useRequestAnimationFrame = useRequestAnimationFrame === true && typeof window !== "undefined";
11736     this.cancelled = false;
11737     this.capability = Promise.withResolvers();
11738     this.task = new RenderTask(this);
11739     this._cancelBound = this.cancel.bind(this);
11740     this._continueBound = this._continue.bind(this);
11741     this._scheduleNextBound = this._scheduleNext.bind(this);
11742     this._nextBound = this._next.bind(this);
11743     this._canvas = params.canvasContext.canvas;
11744   }
11745   get completed() {
11746     return this.capability.promise.catch(function () {});
11747   }
11748   initializeGraphics({
11749     transparency = false,
11750     optionalContentConfig
11751   }) {
11752     if (this.cancelled) {
11753       return;
11754     }
11755     if (this._canvas) {
11756       if (InternalRenderTask.#canvasInUse.has(this._canvas)) {
11757         throw new Error("Cannot use the same canvas during multiple render() operations. " + "Use different canvas or ensure previous operations were " + "cancelled or completed.");
11758       }
11759       InternalRenderTask.#canvasInUse.add(this._canvas);
11760     }
11761     if (this._pdfBug && globalThis.StepperManager?.enabled) {
11762       this.stepper = globalThis.StepperManager.create(this._pageIndex);
11763       this.stepper.init(this.operatorList);
11764       this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
11765     }
11766     const {
11767       canvasContext,
11768       viewport,
11769       transform,
11770       background
11771     } = this.params;
11772     this.gfx = new CanvasGraphics(canvasContext, this.commonObjs, this.objs, this.canvasFactory, this.filterFactory, {
11773       optionalContentConfig
11774     }, this.annotationCanvasMap, this.pageColors);
11775     this.gfx.beginDrawing({
11776       transform,
11777       viewport,
11778       transparency,
11779       background
11780     });
11781     this.operatorListIdx = 0;
11782     this.graphicsReady = true;
11783     this.graphicsReadyCallback?.();
11784   }
11785   cancel(error = null, extraDelay = 0) {
11786     this.running = false;
11787     this.cancelled = true;
11788     this.gfx?.endDrawing();
11789     if (this.#rAF) {
11790       window.cancelAnimationFrame(this.#rAF);
11791       this.#rAF = null;
11792     }
11793     InternalRenderTask.#canvasInUse.delete(this._canvas);
11794     this.callback(error || new RenderingCancelledException(`Rendering cancelled, page ${this._pageIndex + 1}`, extraDelay));
11795   }
11796   operatorListChanged() {
11797     if (!this.graphicsReady) {
11798       this.graphicsReadyCallback ||= this._continueBound;
11799       return;
11800     }
11801     this.stepper?.updateOperatorList(this.operatorList);
11802     if (this.running) {
11803       return;
11804     }
11805     this._continue();
11806   }
11807   _continue() {
11808     this.running = true;
11809     if (this.cancelled) {
11810       return;
11811     }
11812     if (this.task.onContinue) {
11813       this.task.onContinue(this._scheduleNextBound);
11814     } else {
11815       this._scheduleNext();
11816     }
11817   }
11818   _scheduleNext() {
11819     if (this._useRequestAnimationFrame) {
11820       this.#rAF = window.requestAnimationFrame(() => {
11821         this.#rAF = null;
11822         this._nextBound().catch(this._cancelBound);
11823       });
11824     } else {
11825       Promise.resolve().then(this._nextBound).catch(this._cancelBound);
11826     }
11827   }
11828   async _next() {
11829     if (this.cancelled) {
11830       return;
11831     }
11832     this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList, this.operatorListIdx, this._continueBound, this.stepper);
11833     if (this.operatorListIdx === this.operatorList.argsArray.length) {
11834       this.running = false;
11835       if (this.operatorList.lastChunk) {
11836         this.gfx.endDrawing();
11837         InternalRenderTask.#canvasInUse.delete(this._canvas);
11838         this.callback();
11839       }
11840     }
11841   }
11843 const version = "5.0.98";
11844 const build = "16155fd80";
11846 ;// ./src/shared/scripting_utils.js
11847 function makeColorComp(n) {
11848   return Math.floor(Math.max(0, Math.min(1, n)) * 255).toString(16).padStart(2, "0");
11850 function scaleAndClamp(x) {
11851   return Math.max(0, Math.min(255, 255 * x));
11853 class ColorConverters {
11854   static CMYK_G([c, y, m, k]) {
11855     return ["G", 1 - Math.min(1, 0.3 * c + 0.59 * m + 0.11 * y + k)];
11856   }
11857   static G_CMYK([g]) {
11858     return ["CMYK", 0, 0, 0, 1 - g];
11859   }
11860   static G_RGB([g]) {
11861     return ["RGB", g, g, g];
11862   }
11863   static G_rgb([g]) {
11864     g = scaleAndClamp(g);
11865     return [g, g, g];
11866   }
11867   static G_HTML([g]) {
11868     const G = makeColorComp(g);
11869     return `#${G}${G}${G}`;
11870   }
11871   static RGB_G([r, g, b]) {
11872     return ["G", 0.3 * r + 0.59 * g + 0.11 * b];
11873   }
11874   static RGB_rgb(color) {
11875     return color.map(scaleAndClamp);
11876   }
11877   static RGB_HTML(color) {
11878     return `#${color.map(makeColorComp).join("")}`;
11879   }
11880   static T_HTML() {
11881     return "#00000000";
11882   }
11883   static T_rgb() {
11884     return [null];
11885   }
11886   static CMYK_RGB([c, y, m, k]) {
11887     return ["RGB", 1 - Math.min(1, c + k), 1 - Math.min(1, m + k), 1 - Math.min(1, y + k)];
11888   }
11889   static CMYK_rgb([c, y, m, k]) {
11890     return [scaleAndClamp(1 - Math.min(1, c + k)), scaleAndClamp(1 - Math.min(1, m + k)), scaleAndClamp(1 - Math.min(1, y + k))];
11891   }
11892   static CMYK_HTML(components) {
11893     const rgb = this.CMYK_RGB(components).slice(1);
11894     return this.RGB_HTML(rgb);
11895   }
11896   static RGB_CMYK([r, g, b]) {
11897     const c = 1 - r;
11898     const m = 1 - g;
11899     const y = 1 - b;
11900     const k = Math.min(c, m, y);
11901     return ["CMYK", c, m, y, k];
11902   }
11905 ;// ./src/display/svg_factory.js
11908 class BaseSVGFactory {
11909   create(width, height, skipDimensions = false) {
11910     if (width <= 0 || height <= 0) {
11911       throw new Error("Invalid SVG dimensions");
11912     }
11913     const svg = this._createSVG("svg:svg");
11914     svg.setAttribute("version", "1.1");
11915     if (!skipDimensions) {
11916       svg.setAttribute("width", `${width}px`);
11917       svg.setAttribute("height", `${height}px`);
11918     }
11919     svg.setAttribute("preserveAspectRatio", "none");
11920     svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
11921     return svg;
11922   }
11923   createElement(type) {
11924     if (typeof type !== "string") {
11925       throw new Error("Invalid SVG element type");
11926     }
11927     return this._createSVG(type);
11928   }
11929   _createSVG(type) {
11930     unreachable("Abstract method `_createSVG` called.");
11931   }
11933 class DOMSVGFactory extends BaseSVGFactory {
11934   _createSVG(type) {
11935     return document.createElementNS(SVG_NS, type);
11936   }
11939 ;// ./src/display/xfa_layer.js
11941 class XfaLayer {
11942   static setupStorage(html, id, element, storage, intent) {
11943     const storedData = storage.getValue(id, {
11944       value: null
11945     });
11946     switch (element.name) {
11947       case "textarea":
11948         if (storedData.value !== null) {
11949           html.textContent = storedData.value;
11950         }
11951         if (intent === "print") {
11952           break;
11953         }
11954         html.addEventListener("input", event => {
11955           storage.setValue(id, {
11956             value: event.target.value
11957           });
11958         });
11959         break;
11960       case "input":
11961         if (element.attributes.type === "radio" || element.attributes.type === "checkbox") {
11962           if (storedData.value === element.attributes.xfaOn) {
11963             html.setAttribute("checked", true);
11964           } else if (storedData.value === element.attributes.xfaOff) {
11965             html.removeAttribute("checked");
11966           }
11967           if (intent === "print") {
11968             break;
11969           }
11970           html.addEventListener("change", event => {
11971             storage.setValue(id, {
11972               value: event.target.checked ? event.target.getAttribute("xfaOn") : event.target.getAttribute("xfaOff")
11973             });
11974           });
11975         } else {
11976           if (storedData.value !== null) {
11977             html.setAttribute("value", storedData.value);
11978           }
11979           if (intent === "print") {
11980             break;
11981           }
11982           html.addEventListener("input", event => {
11983             storage.setValue(id, {
11984               value: event.target.value
11985             });
11986           });
11987         }
11988         break;
11989       case "select":
11990         if (storedData.value !== null) {
11991           html.setAttribute("value", storedData.value);
11992           for (const option of element.children) {
11993             if (option.attributes.value === storedData.value) {
11994               option.attributes.selected = true;
11995             } else if (option.attributes.hasOwnProperty("selected")) {
11996               delete option.attributes.selected;
11997             }
11998           }
11999         }
12000         html.addEventListener("input", event => {
12001           const options = event.target.options;
12002           const value = options.selectedIndex === -1 ? "" : options[options.selectedIndex].value;
12003           storage.setValue(id, {
12004             value
12005           });
12006         });
12007         break;
12008     }
12009   }
12010   static setAttributes({
12011     html,
12012     element,
12013     storage = null,
12014     intent,
12015     linkService
12016   }) {
12017     const {
12018       attributes
12019     } = element;
12020     const isHTMLAnchorElement = html instanceof HTMLAnchorElement;
12021     if (attributes.type === "radio") {
12022       attributes.name = `${attributes.name}-${intent}`;
12023     }
12024     for (const [key, value] of Object.entries(attributes)) {
12025       if (value === null || value === undefined) {
12026         continue;
12027       }
12028       switch (key) {
12029         case "class":
12030           if (value.length) {
12031             html.setAttribute(key, value.join(" "));
12032           }
12033           break;
12034         case "dataId":
12035           break;
12036         case "id":
12037           html.setAttribute("data-element-id", value);
12038           break;
12039         case "style":
12040           Object.assign(html.style, value);
12041           break;
12042         case "textContent":
12043           html.textContent = value;
12044           break;
12045         default:
12046           if (!isHTMLAnchorElement || key !== "href" && key !== "newWindow") {
12047             html.setAttribute(key, value);
12048           }
12049       }
12050     }
12051     if (isHTMLAnchorElement) {
12052       linkService.addLinkAttributes(html, attributes.href, attributes.newWindow);
12053     }
12054     if (storage && attributes.dataId) {
12055       this.setupStorage(html, attributes.dataId, element, storage);
12056     }
12057   }
12058   static render(parameters) {
12059     const storage = parameters.annotationStorage;
12060     const linkService = parameters.linkService;
12061     const root = parameters.xfaHtml;
12062     const intent = parameters.intent || "display";
12063     const rootHtml = document.createElement(root.name);
12064     if (root.attributes) {
12065       this.setAttributes({
12066         html: rootHtml,
12067         element: root,
12068         intent,
12069         linkService
12070       });
12071     }
12072     const isNotForRichText = intent !== "richText";
12073     const rootDiv = parameters.div;
12074     rootDiv.append(rootHtml);
12075     if (parameters.viewport) {
12076       const transform = `matrix(${parameters.viewport.transform.join(",")})`;
12077       rootDiv.style.transform = transform;
12078     }
12079     if (isNotForRichText) {
12080       rootDiv.setAttribute("class", "xfaLayer xfaFont");
12081     }
12082     const textDivs = [];
12083     if (root.children.length === 0) {
12084       if (root.value) {
12085         const node = document.createTextNode(root.value);
12086         rootHtml.append(node);
12087         if (isNotForRichText && XfaText.shouldBuildText(root.name)) {
12088           textDivs.push(node);
12089         }
12090       }
12091       return {
12092         textDivs
12093       };
12094     }
12095     const stack = [[root, -1, rootHtml]];
12096     while (stack.length > 0) {
12097       const [parent, i, html] = stack.at(-1);
12098       if (i + 1 === parent.children.length) {
12099         stack.pop();
12100         continue;
12101       }
12102       const child = parent.children[++stack.at(-1)[1]];
12103       if (child === null) {
12104         continue;
12105       }
12106       const {
12107         name
12108       } = child;
12109       if (name === "#text") {
12110         const node = document.createTextNode(child.value);
12111         textDivs.push(node);
12112         html.append(node);
12113         continue;
12114       }
12115       const childHtml = child?.attributes?.xmlns ? document.createElementNS(child.attributes.xmlns, name) : document.createElement(name);
12116       html.append(childHtml);
12117       if (child.attributes) {
12118         this.setAttributes({
12119           html: childHtml,
12120           element: child,
12121           storage,
12122           intent,
12123           linkService
12124         });
12125       }
12126       if (child.children?.length > 0) {
12127         stack.push([child, -1, childHtml]);
12128       } else if (child.value) {
12129         const node = document.createTextNode(child.value);
12130         if (isNotForRichText && XfaText.shouldBuildText(name)) {
12131           textDivs.push(node);
12132         }
12133         childHtml.append(node);
12134       }
12135     }
12136     for (const el of rootDiv.querySelectorAll(".xfaNonInteractive input, .xfaNonInteractive textarea")) {
12137       el.setAttribute("readOnly", true);
12138     }
12139     return {
12140       textDivs
12141     };
12142   }
12143   static update(parameters) {
12144     const transform = `matrix(${parameters.viewport.transform.join(",")})`;
12145     parameters.div.style.transform = transform;
12146     parameters.div.hidden = false;
12147   }
12150 ;// ./src/display/annotation_layer.js
12157 const DEFAULT_TAB_INDEX = 1000;
12158 const annotation_layer_DEFAULT_FONT_SIZE = 9;
12159 const GetElementsByNameSet = new WeakSet();
12160 class AnnotationElementFactory {
12161   static create(parameters) {
12162     const subtype = parameters.data.annotationType;
12163     switch (subtype) {
12164       case AnnotationType.LINK:
12165         return new LinkAnnotationElement(parameters);
12166       case AnnotationType.TEXT:
12167         return new TextAnnotationElement(parameters);
12168       case AnnotationType.WIDGET:
12169         const fieldType = parameters.data.fieldType;
12170         switch (fieldType) {
12171           case "Tx":
12172             return new TextWidgetAnnotationElement(parameters);
12173           case "Btn":
12174             if (parameters.data.radioButton) {
12175               return new RadioButtonWidgetAnnotationElement(parameters);
12176             } else if (parameters.data.checkBox) {
12177               return new CheckboxWidgetAnnotationElement(parameters);
12178             }
12179             return new PushButtonWidgetAnnotationElement(parameters);
12180           case "Ch":
12181             return new ChoiceWidgetAnnotationElement(parameters);
12182           case "Sig":
12183             return new SignatureWidgetAnnotationElement(parameters);
12184         }
12185         return new WidgetAnnotationElement(parameters);
12186       case AnnotationType.POPUP:
12187         return new PopupAnnotationElement(parameters);
12188       case AnnotationType.FREETEXT:
12189         return new FreeTextAnnotationElement(parameters);
12190       case AnnotationType.LINE:
12191         return new LineAnnotationElement(parameters);
12192       case AnnotationType.SQUARE:
12193         return new SquareAnnotationElement(parameters);
12194       case AnnotationType.CIRCLE:
12195         return new CircleAnnotationElement(parameters);
12196       case AnnotationType.POLYLINE:
12197         return new PolylineAnnotationElement(parameters);
12198       case AnnotationType.CARET:
12199         return new CaretAnnotationElement(parameters);
12200       case AnnotationType.INK:
12201         return new InkAnnotationElement(parameters);
12202       case AnnotationType.POLYGON:
12203         return new PolygonAnnotationElement(parameters);
12204       case AnnotationType.HIGHLIGHT:
12205         return new HighlightAnnotationElement(parameters);
12206       case AnnotationType.UNDERLINE:
12207         return new UnderlineAnnotationElement(parameters);
12208       case AnnotationType.SQUIGGLY:
12209         return new SquigglyAnnotationElement(parameters);
12210       case AnnotationType.STRIKEOUT:
12211         return new StrikeOutAnnotationElement(parameters);
12212       case AnnotationType.STAMP:
12213         return new StampAnnotationElement(parameters);
12214       case AnnotationType.FILEATTACHMENT:
12215         return new FileAttachmentAnnotationElement(parameters);
12216       default:
12217         return new AnnotationElement(parameters);
12218     }
12219   }
12221 class AnnotationElement {
12222   #updates = null;
12223   #hasBorder = false;
12224   #popupElement = null;
12225   constructor(parameters, {
12226     isRenderable = false,
12227     ignoreBorder = false,
12228     createQuadrilaterals = false
12229   } = {}) {
12230     this.isRenderable = isRenderable;
12231     this.data = parameters.data;
12232     this.layer = parameters.layer;
12233     this.linkService = parameters.linkService;
12234     this.downloadManager = parameters.downloadManager;
12235     this.imageResourcesPath = parameters.imageResourcesPath;
12236     this.renderForms = parameters.renderForms;
12237     this.svgFactory = parameters.svgFactory;
12238     this.annotationStorage = parameters.annotationStorage;
12239     this.enableScripting = parameters.enableScripting;
12240     this.hasJSActions = parameters.hasJSActions;
12241     this._fieldObjects = parameters.fieldObjects;
12242     this.parent = parameters.parent;
12243     if (isRenderable) {
12244       this.container = this._createContainer(ignoreBorder);
12245     }
12246     if (createQuadrilaterals) {
12247       this._createQuadrilaterals();
12248     }
12249   }
12250   static _hasPopupData({
12251     titleObj,
12252     contentsObj,
12253     richText
12254   }) {
12255     return !!(titleObj?.str || contentsObj?.str || richText?.str);
12256   }
12257   get _isEditable() {
12258     return this.data.isEditable;
12259   }
12260   get hasPopupData() {
12261     return AnnotationElement._hasPopupData(this.data);
12262   }
12263   updateEdited(params) {
12264     if (!this.container) {
12265       return;
12266     }
12267     this.#updates ||= {
12268       rect: this.data.rect.slice(0)
12269     };
12270     const {
12271       rect
12272     } = params;
12273     if (rect) {
12274       this.#setRectEdited(rect);
12275     }
12276     this.#popupElement?.popup.updateEdited(params);
12277   }
12278   resetEdited() {
12279     if (!this.#updates) {
12280       return;
12281     }
12282     this.#setRectEdited(this.#updates.rect);
12283     this.#popupElement?.popup.resetEdited();
12284     this.#updates = null;
12285   }
12286   #setRectEdited(rect) {
12287     const {
12288       container: {
12289         style
12290       },
12291       data: {
12292         rect: currentRect,
12293         rotation
12294       },
12295       parent: {
12296         viewport: {
12297           rawDims: {
12298             pageWidth,
12299             pageHeight,
12300             pageX,
12301             pageY
12302           }
12303         }
12304       }
12305     } = this;
12306     currentRect?.splice(0, 4, ...rect);
12307     style.left = `${100 * (rect[0] - pageX) / pageWidth}%`;
12308     style.top = `${100 * (pageHeight - rect[3] + pageY) / pageHeight}%`;
12309     if (rotation === 0) {
12310       style.width = `${100 * (rect[2] - rect[0]) / pageWidth}%`;
12311       style.height = `${100 * (rect[3] - rect[1]) / pageHeight}%`;
12312     } else {
12313       this.setRotation(rotation);
12314     }
12315   }
12316   _createContainer(ignoreBorder) {
12317     const {
12318       data,
12319       parent: {
12320         page,
12321         viewport
12322       }
12323     } = this;
12324     const container = document.createElement("section");
12325     container.setAttribute("data-annotation-id", data.id);
12326     if (!(this instanceof WidgetAnnotationElement)) {
12327       container.tabIndex = DEFAULT_TAB_INDEX;
12328     }
12329     const {
12330       style
12331     } = container;
12332     style.zIndex = this.parent.zIndex++;
12333     if (data.alternativeText) {
12334       container.title = data.alternativeText;
12335     }
12336     if (data.noRotate) {
12337       container.classList.add("norotate");
12338     }
12339     if (!data.rect || this instanceof PopupAnnotationElement) {
12340       const {
12341         rotation
12342       } = data;
12343       if (!data.hasOwnCanvas && rotation !== 0) {
12344         this.setRotation(rotation, container);
12345       }
12346       return container;
12347     }
12348     const {
12349       width,
12350       height
12351     } = this;
12352     if (!ignoreBorder && data.borderStyle.width > 0) {
12353       style.borderWidth = `${data.borderStyle.width}px`;
12354       const horizontalRadius = data.borderStyle.horizontalCornerRadius;
12355       const verticalRadius = data.borderStyle.verticalCornerRadius;
12356       if (horizontalRadius > 0 || verticalRadius > 0) {
12357         const radius = `calc(${horizontalRadius}px * var(--scale-factor)) / calc(${verticalRadius}px * var(--scale-factor))`;
12358         style.borderRadius = radius;
12359       } else if (this instanceof RadioButtonWidgetAnnotationElement) {
12360         const radius = `calc(${width}px * var(--scale-factor)) / calc(${height}px * var(--scale-factor))`;
12361         style.borderRadius = radius;
12362       }
12363       switch (data.borderStyle.style) {
12364         case AnnotationBorderStyleType.SOLID:
12365           style.borderStyle = "solid";
12366           break;
12367         case AnnotationBorderStyleType.DASHED:
12368           style.borderStyle = "dashed";
12369           break;
12370         case AnnotationBorderStyleType.BEVELED:
12371           warn("Unimplemented border style: beveled");
12372           break;
12373         case AnnotationBorderStyleType.INSET:
12374           warn("Unimplemented border style: inset");
12375           break;
12376         case AnnotationBorderStyleType.UNDERLINE:
12377           style.borderBottomStyle = "solid";
12378           break;
12379         default:
12380           break;
12381       }
12382       const borderColor = data.borderColor || null;
12383       if (borderColor) {
12384         this.#hasBorder = true;
12385         style.borderColor = Util.makeHexColor(borderColor[0] | 0, borderColor[1] | 0, borderColor[2] | 0);
12386       } else {
12387         style.borderWidth = 0;
12388       }
12389     }
12390     const rect = Util.normalizeRect([data.rect[0], page.view[3] - data.rect[1] + page.view[1], data.rect[2], page.view[3] - data.rect[3] + page.view[1]]);
12391     const {
12392       pageWidth,
12393       pageHeight,
12394       pageX,
12395       pageY
12396     } = viewport.rawDims;
12397     style.left = `${100 * (rect[0] - pageX) / pageWidth}%`;
12398     style.top = `${100 * (rect[1] - pageY) / pageHeight}%`;
12399     const {
12400       rotation
12401     } = data;
12402     if (data.hasOwnCanvas || rotation === 0) {
12403       style.width = `${100 * width / pageWidth}%`;
12404       style.height = `${100 * height / pageHeight}%`;
12405     } else {
12406       this.setRotation(rotation, container);
12407     }
12408     return container;
12409   }
12410   setRotation(angle, container = this.container) {
12411     if (!this.data.rect) {
12412       return;
12413     }
12414     const {
12415       pageWidth,
12416       pageHeight
12417     } = this.parent.viewport.rawDims;
12418     let {
12419       width,
12420       height
12421     } = this;
12422     if (angle % 180 !== 0) {
12423       [width, height] = [height, width];
12424     }
12425     container.style.width = `${100 * width / pageWidth}%`;
12426     container.style.height = `${100 * height / pageHeight}%`;
12427     container.setAttribute("data-main-rotation", (360 - angle) % 360);
12428   }
12429   get _commonActions() {
12430     const setColor = (jsName, styleName, event) => {
12431       const color = event.detail[jsName];
12432       const colorType = color[0];
12433       const colorArray = color.slice(1);
12434       event.target.style[styleName] = ColorConverters[`${colorType}_HTML`](colorArray);
12435       this.annotationStorage.setValue(this.data.id, {
12436         [styleName]: ColorConverters[`${colorType}_rgb`](colorArray)
12437       });
12438     };
12439     return shadow(this, "_commonActions", {
12440       display: event => {
12441         const {
12442           display
12443         } = event.detail;
12444         const hidden = display % 2 === 1;
12445         this.container.style.visibility = hidden ? "hidden" : "visible";
12446         this.annotationStorage.setValue(this.data.id, {
12447           noView: hidden,
12448           noPrint: display === 1 || display === 2
12449         });
12450       },
12451       print: event => {
12452         this.annotationStorage.setValue(this.data.id, {
12453           noPrint: !event.detail.print
12454         });
12455       },
12456       hidden: event => {
12457         const {
12458           hidden
12459         } = event.detail;
12460         this.container.style.visibility = hidden ? "hidden" : "visible";
12461         this.annotationStorage.setValue(this.data.id, {
12462           noPrint: hidden,
12463           noView: hidden
12464         });
12465       },
12466       focus: event => {
12467         setTimeout(() => event.target.focus({
12468           preventScroll: false
12469         }), 0);
12470       },
12471       userName: event => {
12472         event.target.title = event.detail.userName;
12473       },
12474       readonly: event => {
12475         event.target.disabled = event.detail.readonly;
12476       },
12477       required: event => {
12478         this._setRequired(event.target, event.detail.required);
12479       },
12480       bgColor: event => {
12481         setColor("bgColor", "backgroundColor", event);
12482       },
12483       fillColor: event => {
12484         setColor("fillColor", "backgroundColor", event);
12485       },
12486       fgColor: event => {
12487         setColor("fgColor", "color", event);
12488       },
12489       textColor: event => {
12490         setColor("textColor", "color", event);
12491       },
12492       borderColor: event => {
12493         setColor("borderColor", "borderColor", event);
12494       },
12495       strokeColor: event => {
12496         setColor("strokeColor", "borderColor", event);
12497       },
12498       rotation: event => {
12499         const angle = event.detail.rotation;
12500         this.setRotation(angle);
12501         this.annotationStorage.setValue(this.data.id, {
12502           rotation: angle
12503         });
12504       }
12505     });
12506   }
12507   _dispatchEventFromSandbox(actions, jsEvent) {
12508     const commonActions = this._commonActions;
12509     for (const name of Object.keys(jsEvent.detail)) {
12510       const action = actions[name] || commonActions[name];
12511       action?.(jsEvent);
12512     }
12513   }
12514   _setDefaultPropertiesFromJS(element) {
12515     if (!this.enableScripting) {
12516       return;
12517     }
12518     const storedData = this.annotationStorage.getRawValue(this.data.id);
12519     if (!storedData) {
12520       return;
12521     }
12522     const commonActions = this._commonActions;
12523     for (const [actionName, detail] of Object.entries(storedData)) {
12524       const action = commonActions[actionName];
12525       if (action) {
12526         const eventProxy = {
12527           detail: {
12528             [actionName]: detail
12529           },
12530           target: element
12531         };
12532         action(eventProxy);
12533         delete storedData[actionName];
12534       }
12535     }
12536   }
12537   _createQuadrilaterals() {
12538     if (!this.container) {
12539       return;
12540     }
12541     const {
12542       quadPoints
12543     } = this.data;
12544     if (!quadPoints) {
12545       return;
12546     }
12547     const [rectBlX, rectBlY, rectTrX, rectTrY] = this.data.rect.map(x => Math.fround(x));
12548     if (quadPoints.length === 8) {
12549       const [trX, trY, blX, blY] = quadPoints.subarray(2, 6);
12550       if (rectTrX === trX && rectTrY === trY && rectBlX === blX && rectBlY === blY) {
12551         return;
12552       }
12553     }
12554     const {
12555       style
12556     } = this.container;
12557     let svgBuffer;
12558     if (this.#hasBorder) {
12559       const {
12560         borderColor,
12561         borderWidth
12562       } = style;
12563       style.borderWidth = 0;
12564       svgBuffer = ["url('data:image/svg+xml;utf8,", `<svg xmlns="http://www.w3.org/2000/svg"`, ` preserveAspectRatio="none" viewBox="0 0 1 1">`, `<g fill="transparent" stroke="${borderColor}" stroke-width="${borderWidth}">`];
12565       this.container.classList.add("hasBorder");
12566     }
12567     const width = rectTrX - rectBlX;
12568     const height = rectTrY - rectBlY;
12569     const {
12570       svgFactory
12571     } = this;
12572     const svg = svgFactory.createElement("svg");
12573     svg.classList.add("quadrilateralsContainer");
12574     svg.setAttribute("width", 0);
12575     svg.setAttribute("height", 0);
12576     const defs = svgFactory.createElement("defs");
12577     svg.append(defs);
12578     const clipPath = svgFactory.createElement("clipPath");
12579     const id = `clippath_${this.data.id}`;
12580     clipPath.setAttribute("id", id);
12581     clipPath.setAttribute("clipPathUnits", "objectBoundingBox");
12582     defs.append(clipPath);
12583     for (let i = 2, ii = quadPoints.length; i < ii; i += 8) {
12584       const trX = quadPoints[i];
12585       const trY = quadPoints[i + 1];
12586       const blX = quadPoints[i + 2];
12587       const blY = quadPoints[i + 3];
12588       const rect = svgFactory.createElement("rect");
12589       const x = (blX - rectBlX) / width;
12590       const y = (rectTrY - trY) / height;
12591       const rectWidth = (trX - blX) / width;
12592       const rectHeight = (trY - blY) / height;
12593       rect.setAttribute("x", x);
12594       rect.setAttribute("y", y);
12595       rect.setAttribute("width", rectWidth);
12596       rect.setAttribute("height", rectHeight);
12597       clipPath.append(rect);
12598       svgBuffer?.push(`<rect vector-effect="non-scaling-stroke" x="${x}" y="${y}" width="${rectWidth}" height="${rectHeight}"/>`);
12599     }
12600     if (this.#hasBorder) {
12601       svgBuffer.push(`</g></svg>')`);
12602       style.backgroundImage = svgBuffer.join("");
12603     }
12604     this.container.append(svg);
12605     this.container.style.clipPath = `url(#${id})`;
12606   }
12607   _createPopup() {
12608     const {
12609       data
12610     } = this;
12611     const popup = this.#popupElement = new PopupAnnotationElement({
12612       data: {
12613         color: data.color,
12614         titleObj: data.titleObj,
12615         modificationDate: data.modificationDate,
12616         contentsObj: data.contentsObj,
12617         richText: data.richText,
12618         parentRect: data.rect,
12619         borderStyle: 0,
12620         id: `popup_${data.id}`,
12621         rotation: data.rotation
12622       },
12623       parent: this.parent,
12624       elements: [this]
12625     });
12626     this.parent.div.append(popup.render());
12627   }
12628   render() {
12629     unreachable("Abstract method `AnnotationElement.render` called");
12630   }
12631   _getElementsByName(name, skipId = null) {
12632     const fields = [];
12633     if (this._fieldObjects) {
12634       const fieldObj = this._fieldObjects[name];
12635       if (fieldObj) {
12636         for (const {
12637           page,
12638           id,
12639           exportValues
12640         } of fieldObj) {
12641           if (page === -1) {
12642             continue;
12643           }
12644           if (id === skipId) {
12645             continue;
12646           }
12647           const exportValue = typeof exportValues === "string" ? exportValues : null;
12648           const domElement = document.querySelector(`[data-element-id="${id}"]`);
12649           if (domElement && !GetElementsByNameSet.has(domElement)) {
12650             warn(`_getElementsByName - element not allowed: ${id}`);
12651             continue;
12652           }
12653           fields.push({
12654             id,
12655             exportValue,
12656             domElement
12657           });
12658         }
12659       }
12660       return fields;
12661     }
12662     for (const domElement of document.getElementsByName(name)) {
12663       const {
12664         exportValue
12665       } = domElement;
12666       const id = domElement.getAttribute("data-element-id");
12667       if (id === skipId) {
12668         continue;
12669       }
12670       if (!GetElementsByNameSet.has(domElement)) {
12671         continue;
12672       }
12673       fields.push({
12674         id,
12675         exportValue,
12676         domElement
12677       });
12678     }
12679     return fields;
12680   }
12681   show() {
12682     if (this.container) {
12683       this.container.hidden = false;
12684     }
12685     this.popup?.maybeShow();
12686   }
12687   hide() {
12688     if (this.container) {
12689       this.container.hidden = true;
12690     }
12691     this.popup?.forceHide();
12692   }
12693   getElementsToTriggerPopup() {
12694     return this.container;
12695   }
12696   addHighlightArea() {
12697     const triggers = this.getElementsToTriggerPopup();
12698     if (Array.isArray(triggers)) {
12699       for (const element of triggers) {
12700         element.classList.add("highlightArea");
12701       }
12702     } else {
12703       triggers.classList.add("highlightArea");
12704     }
12705   }
12706   _editOnDoubleClick() {
12707     if (!this._isEditable) {
12708       return;
12709     }
12710     const {
12711       annotationEditorType: mode,
12712       data: {
12713         id: editId
12714       }
12715     } = this;
12716     this.container.addEventListener("dblclick", () => {
12717       this.linkService.eventBus?.dispatch("switchannotationeditormode", {
12718         source: this,
12719         mode,
12720         editId
12721       });
12722     });
12723   }
12724   get width() {
12725     return this.data.rect[2] - this.data.rect[0];
12726   }
12727   get height() {
12728     return this.data.rect[3] - this.data.rect[1];
12729   }
12731 class LinkAnnotationElement extends AnnotationElement {
12732   constructor(parameters, options = null) {
12733     super(parameters, {
12734       isRenderable: true,
12735       ignoreBorder: !!options?.ignoreBorder,
12736       createQuadrilaterals: true
12737     });
12738     this.isTooltipOnly = parameters.data.isTooltipOnly;
12739   }
12740   render() {
12741     const {
12742       data,
12743       linkService
12744     } = this;
12745     const link = document.createElement("a");
12746     link.setAttribute("data-element-id", data.id);
12747     let isBound = false;
12748     if (data.url) {
12749       linkService.addLinkAttributes(link, data.url, data.newWindow);
12750       isBound = true;
12751     } else if (data.action) {
12752       this._bindNamedAction(link, data.action);
12753       isBound = true;
12754     } else if (data.attachment) {
12755       this.#bindAttachment(link, data.attachment, data.attachmentDest);
12756       isBound = true;
12757     } else if (data.setOCGState) {
12758       this.#bindSetOCGState(link, data.setOCGState);
12759       isBound = true;
12760     } else if (data.dest) {
12761       this._bindLink(link, data.dest);
12762       isBound = true;
12763     } else {
12764       if (data.actions && (data.actions.Action || data.actions["Mouse Up"] || data.actions["Mouse Down"]) && this.enableScripting && this.hasJSActions) {
12765         this._bindJSAction(link, data);
12766         isBound = true;
12767       }
12768       if (data.resetForm) {
12769         this._bindResetFormAction(link, data.resetForm);
12770         isBound = true;
12771       } else if (this.isTooltipOnly && !isBound) {
12772         this._bindLink(link, "");
12773         isBound = true;
12774       }
12775     }
12776     this.container.classList.add("linkAnnotation");
12777     if (isBound) {
12778       this.container.append(link);
12779     }
12780     return this.container;
12781   }
12782   #setInternalLink() {
12783     this.container.setAttribute("data-internal-link", "");
12784   }
12785   _bindLink(link, destination) {
12786     link.href = this.linkService.getDestinationHash(destination);
12787     link.onclick = () => {
12788       if (destination) {
12789         this.linkService.goToDestination(destination);
12790       }
12791       return false;
12792     };
12793     if (destination || destination === "") {
12794       this.#setInternalLink();
12795     }
12796   }
12797   _bindNamedAction(link, action) {
12798     link.href = this.linkService.getAnchorUrl("");
12799     link.onclick = () => {
12800       this.linkService.executeNamedAction(action);
12801       return false;
12802     };
12803     this.#setInternalLink();
12804   }
12805   #bindAttachment(link, attachment, dest = null) {
12806     link.href = this.linkService.getAnchorUrl("");
12807     if (attachment.description) {
12808       link.title = attachment.description;
12809     }
12810     link.onclick = () => {
12811       this.downloadManager?.openOrDownloadData(attachment.content, attachment.filename, dest);
12812       return false;
12813     };
12814     this.#setInternalLink();
12815   }
12816   #bindSetOCGState(link, action) {
12817     link.href = this.linkService.getAnchorUrl("");
12818     link.onclick = () => {
12819       this.linkService.executeSetOCGState(action);
12820       return false;
12821     };
12822     this.#setInternalLink();
12823   }
12824   _bindJSAction(link, data) {
12825     link.href = this.linkService.getAnchorUrl("");
12826     const map = new Map([["Action", "onclick"], ["Mouse Up", "onmouseup"], ["Mouse Down", "onmousedown"]]);
12827     for (const name of Object.keys(data.actions)) {
12828       const jsName = map.get(name);
12829       if (!jsName) {
12830         continue;
12831       }
12832       link[jsName] = () => {
12833         this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
12834           source: this,
12835           detail: {
12836             id: data.id,
12837             name
12838           }
12839         });
12840         return false;
12841       };
12842     }
12843     if (!link.onclick) {
12844       link.onclick = () => false;
12845     }
12846     this.#setInternalLink();
12847   }
12848   _bindResetFormAction(link, resetForm) {
12849     const otherClickAction = link.onclick;
12850     if (!otherClickAction) {
12851       link.href = this.linkService.getAnchorUrl("");
12852     }
12853     this.#setInternalLink();
12854     if (!this._fieldObjects) {
12855       warn(`_bindResetFormAction - "resetForm" action not supported, ` + "ensure that the `fieldObjects` parameter is provided.");
12856       if (!otherClickAction) {
12857         link.onclick = () => false;
12858       }
12859       return;
12860     }
12861     link.onclick = () => {
12862       otherClickAction?.();
12863       const {
12864         fields: resetFormFields,
12865         refs: resetFormRefs,
12866         include
12867       } = resetForm;
12868       const allFields = [];
12869       if (resetFormFields.length !== 0 || resetFormRefs.length !== 0) {
12870         const fieldIds = new Set(resetFormRefs);
12871         for (const fieldName of resetFormFields) {
12872           const fields = this._fieldObjects[fieldName] || [];
12873           for (const {
12874             id
12875           } of fields) {
12876             fieldIds.add(id);
12877           }
12878         }
12879         for (const fields of Object.values(this._fieldObjects)) {
12880           for (const field of fields) {
12881             if (fieldIds.has(field.id) === include) {
12882               allFields.push(field);
12883             }
12884           }
12885         }
12886       } else {
12887         for (const fields of Object.values(this._fieldObjects)) {
12888           allFields.push(...fields);
12889         }
12890       }
12891       const storage = this.annotationStorage;
12892       const allIds = [];
12893       for (const field of allFields) {
12894         const {
12895           id
12896         } = field;
12897         allIds.push(id);
12898         switch (field.type) {
12899           case "text":
12900             {
12901               const value = field.defaultValue || "";
12902               storage.setValue(id, {
12903                 value
12904               });
12905               break;
12906             }
12907           case "checkbox":
12908           case "radiobutton":
12909             {
12910               const value = field.defaultValue === field.exportValues;
12911               storage.setValue(id, {
12912                 value
12913               });
12914               break;
12915             }
12916           case "combobox":
12917           case "listbox":
12918             {
12919               const value = field.defaultValue || "";
12920               storage.setValue(id, {
12921                 value
12922               });
12923               break;
12924             }
12925           default:
12926             continue;
12927         }
12928         const domElement = document.querySelector(`[data-element-id="${id}"]`);
12929         if (!domElement) {
12930           continue;
12931         } else if (!GetElementsByNameSet.has(domElement)) {
12932           warn(`_bindResetFormAction - element not allowed: ${id}`);
12933           continue;
12934         }
12935         domElement.dispatchEvent(new Event("resetform"));
12936       }
12937       if (this.enableScripting) {
12938         this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
12939           source: this,
12940           detail: {
12941             id: "app",
12942             ids: allIds,
12943             name: "ResetForm"
12944           }
12945         });
12946       }
12947       return false;
12948     };
12949   }
12951 class TextAnnotationElement extends AnnotationElement {
12952   constructor(parameters) {
12953     super(parameters, {
12954       isRenderable: true
12955     });
12956   }
12957   render() {
12958     this.container.classList.add("textAnnotation");
12959     const image = document.createElement("img");
12960     image.src = this.imageResourcesPath + "annotation-" + this.data.name.toLowerCase() + ".svg";
12961     image.setAttribute("data-l10n-id", "pdfjs-text-annotation-type");
12962     image.setAttribute("data-l10n-args", JSON.stringify({
12963       type: this.data.name
12964     }));
12965     if (!this.data.popupRef && this.hasPopupData) {
12966       this._createPopup();
12967     }
12968     this.container.append(image);
12969     return this.container;
12970   }
12972 class WidgetAnnotationElement extends AnnotationElement {
12973   render() {
12974     return this.container;
12975   }
12976   showElementAndHideCanvas(element) {
12977     if (this.data.hasOwnCanvas) {
12978       if (element.previousSibling?.nodeName === "CANVAS") {
12979         element.previousSibling.hidden = true;
12980       }
12981       element.hidden = false;
12982     }
12983   }
12984   _getKeyModifier(event) {
12985     return util_FeatureTest.platform.isMac ? event.metaKey : event.ctrlKey;
12986   }
12987   _setEventListener(element, elementData, baseName, eventName, valueGetter) {
12988     if (baseName.includes("mouse")) {
12989       element.addEventListener(baseName, event => {
12990         this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
12991           source: this,
12992           detail: {
12993             id: this.data.id,
12994             name: eventName,
12995             value: valueGetter(event),
12996             shift: event.shiftKey,
12997             modifier: this._getKeyModifier(event)
12998           }
12999         });
13000       });
13001     } else {
13002       element.addEventListener(baseName, event => {
13003         if (baseName === "blur") {
13004           if (!elementData.focused || !event.relatedTarget) {
13005             return;
13006           }
13007           elementData.focused = false;
13008         } else if (baseName === "focus") {
13009           if (elementData.focused) {
13010             return;
13011           }
13012           elementData.focused = true;
13013         }
13014         if (!valueGetter) {
13015           return;
13016         }
13017         this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
13018           source: this,
13019           detail: {
13020             id: this.data.id,
13021             name: eventName,
13022             value: valueGetter(event)
13023           }
13024         });
13025       });
13026     }
13027   }
13028   _setEventListeners(element, elementData, names, getter) {
13029     for (const [baseName, eventName] of names) {
13030       if (eventName === "Action" || this.data.actions?.[eventName]) {
13031         if (eventName === "Focus" || eventName === "Blur") {
13032           elementData ||= {
13033             focused: false
13034           };
13035         }
13036         this._setEventListener(element, elementData, baseName, eventName, getter);
13037         if (eventName === "Focus" && !this.data.actions?.Blur) {
13038           this._setEventListener(element, elementData, "blur", "Blur", null);
13039         } else if (eventName === "Blur" && !this.data.actions?.Focus) {
13040           this._setEventListener(element, elementData, "focus", "Focus", null);
13041         }
13042       }
13043     }
13044   }
13045   _setBackgroundColor(element) {
13046     const color = this.data.backgroundColor || null;
13047     element.style.backgroundColor = color === null ? "transparent" : Util.makeHexColor(color[0], color[1], color[2]);
13048   }
13049   _setTextStyle(element) {
13050     const TEXT_ALIGNMENT = ["left", "center", "right"];
13051     const {
13052       fontColor
13053     } = this.data.defaultAppearanceData;
13054     const fontSize = this.data.defaultAppearanceData.fontSize || annotation_layer_DEFAULT_FONT_SIZE;
13055     const style = element.style;
13056     let computedFontSize;
13057     const BORDER_SIZE = 2;
13058     const roundToOneDecimal = x => Math.round(10 * x) / 10;
13059     if (this.data.multiLine) {
13060       const height = Math.abs(this.data.rect[3] - this.data.rect[1] - BORDER_SIZE);
13061       const numberOfLines = Math.round(height / (LINE_FACTOR * fontSize)) || 1;
13062       const lineHeight = height / numberOfLines;
13063       computedFontSize = Math.min(fontSize, roundToOneDecimal(lineHeight / LINE_FACTOR));
13064     } else {
13065       const height = Math.abs(this.data.rect[3] - this.data.rect[1] - BORDER_SIZE);
13066       computedFontSize = Math.min(fontSize, roundToOneDecimal(height / LINE_FACTOR));
13067     }
13068     style.fontSize = `calc(${computedFontSize}px * var(--scale-factor))`;
13069     style.color = Util.makeHexColor(fontColor[0], fontColor[1], fontColor[2]);
13070     if (this.data.textAlignment !== null) {
13071       style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment];
13072     }
13073   }
13074   _setRequired(element, isRequired) {
13075     if (isRequired) {
13076       element.setAttribute("required", true);
13077     } else {
13078       element.removeAttribute("required");
13079     }
13080     element.setAttribute("aria-required", isRequired);
13081   }
13083 class TextWidgetAnnotationElement extends WidgetAnnotationElement {
13084   constructor(parameters) {
13085     const isRenderable = parameters.renderForms || parameters.data.hasOwnCanvas || !parameters.data.hasAppearance && !!parameters.data.fieldValue;
13086     super(parameters, {
13087       isRenderable
13088     });
13089   }
13090   setPropertyOnSiblings(base, key, value, keyInStorage) {
13091     const storage = this.annotationStorage;
13092     for (const element of this._getElementsByName(base.name, base.id)) {
13093       if (element.domElement) {
13094         element.domElement[key] = value;
13095       }
13096       storage.setValue(element.id, {
13097         [keyInStorage]: value
13098       });
13099     }
13100   }
13101   render() {
13102     const storage = this.annotationStorage;
13103     const id = this.data.id;
13104     this.container.classList.add("textWidgetAnnotation");
13105     let element = null;
13106     if (this.renderForms) {
13107       const storedData = storage.getValue(id, {
13108         value: this.data.fieldValue
13109       });
13110       let textContent = storedData.value || "";
13111       const maxLen = storage.getValue(id, {
13112         charLimit: this.data.maxLen
13113       }).charLimit;
13114       if (maxLen && textContent.length > maxLen) {
13115         textContent = textContent.slice(0, maxLen);
13116       }
13117       let fieldFormattedValues = storedData.formattedValue || this.data.textContent?.join("\n") || null;
13118       if (fieldFormattedValues && this.data.comb) {
13119         fieldFormattedValues = fieldFormattedValues.replaceAll(/\s+/g, "");
13120       }
13121       const elementData = {
13122         userValue: textContent,
13123         formattedValue: fieldFormattedValues,
13124         lastCommittedValue: null,
13125         commitKey: 1,
13126         focused: false
13127       };
13128       if (this.data.multiLine) {
13129         element = document.createElement("textarea");
13130         element.textContent = fieldFormattedValues ?? textContent;
13131         if (this.data.doNotScroll) {
13132           element.style.overflowY = "hidden";
13133         }
13134       } else {
13135         element = document.createElement("input");
13136         element.type = this.data.password ? "password" : "text";
13137         element.setAttribute("value", fieldFormattedValues ?? textContent);
13138         if (this.data.doNotScroll) {
13139           element.style.overflowX = "hidden";
13140         }
13141       }
13142       if (this.data.hasOwnCanvas) {
13143         element.hidden = true;
13144       }
13145       GetElementsByNameSet.add(element);
13146       element.setAttribute("data-element-id", id);
13147       element.disabled = this.data.readOnly;
13148       element.name = this.data.fieldName;
13149       element.tabIndex = DEFAULT_TAB_INDEX;
13150       this._setRequired(element, this.data.required);
13151       if (maxLen) {
13152         element.maxLength = maxLen;
13153       }
13154       element.addEventListener("input", event => {
13155         storage.setValue(id, {
13156           value: event.target.value
13157         });
13158         this.setPropertyOnSiblings(element, "value", event.target.value, "value");
13159         elementData.formattedValue = null;
13160       });
13161       element.addEventListener("resetform", event => {
13162         const defaultValue = this.data.defaultFieldValue ?? "";
13163         element.value = elementData.userValue = defaultValue;
13164         elementData.formattedValue = null;
13165       });
13166       let blurListener = event => {
13167         const {
13168           formattedValue
13169         } = elementData;
13170         if (formattedValue !== null && formattedValue !== undefined) {
13171           event.target.value = formattedValue;
13172         }
13173         event.target.scrollLeft = 0;
13174       };
13175       if (this.enableScripting && this.hasJSActions) {
13176         element.addEventListener("focus", event => {
13177           if (elementData.focused) {
13178             return;
13179           }
13180           const {
13181             target
13182           } = event;
13183           if (elementData.userValue) {
13184             target.value = elementData.userValue;
13185           }
13186           elementData.lastCommittedValue = target.value;
13187           elementData.commitKey = 1;
13188           if (!this.data.actions?.Focus) {
13189             elementData.focused = true;
13190           }
13191         });
13192         element.addEventListener("updatefromsandbox", jsEvent => {
13193           this.showElementAndHideCanvas(jsEvent.target);
13194           const actions = {
13195             value(event) {
13196               elementData.userValue = event.detail.value ?? "";
13197               storage.setValue(id, {
13198                 value: elementData.userValue.toString()
13199               });
13200               event.target.value = elementData.userValue;
13201             },
13202             formattedValue(event) {
13203               const {
13204                 formattedValue
13205               } = event.detail;
13206               elementData.formattedValue = formattedValue;
13207               if (formattedValue !== null && formattedValue !== undefined && event.target !== document.activeElement) {
13208                 event.target.value = formattedValue;
13209               }
13210               storage.setValue(id, {
13211                 formattedValue
13212               });
13213             },
13214             selRange(event) {
13215               event.target.setSelectionRange(...event.detail.selRange);
13216             },
13217             charLimit: event => {
13218               const {
13219                 charLimit
13220               } = event.detail;
13221               const {
13222                 target
13223               } = event;
13224               if (charLimit === 0) {
13225                 target.removeAttribute("maxLength");
13226                 return;
13227               }
13228               target.setAttribute("maxLength", charLimit);
13229               let value = elementData.userValue;
13230               if (!value || value.length <= charLimit) {
13231                 return;
13232               }
13233               value = value.slice(0, charLimit);
13234               target.value = elementData.userValue = value;
13235               storage.setValue(id, {
13236                 value
13237               });
13238               this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
13239                 source: this,
13240                 detail: {
13241                   id,
13242                   name: "Keystroke",
13243                   value,
13244                   willCommit: true,
13245                   commitKey: 1,
13246                   selStart: target.selectionStart,
13247                   selEnd: target.selectionEnd
13248                 }
13249               });
13250             }
13251           };
13252           this._dispatchEventFromSandbox(actions, jsEvent);
13253         });
13254         element.addEventListener("keydown", event => {
13255           elementData.commitKey = 1;
13256           let commitKey = -1;
13257           if (event.key === "Escape") {
13258             commitKey = 0;
13259           } else if (event.key === "Enter" && !this.data.multiLine) {
13260             commitKey = 2;
13261           } else if (event.key === "Tab") {
13262             elementData.commitKey = 3;
13263           }
13264           if (commitKey === -1) {
13265             return;
13266           }
13267           const {
13268             value
13269           } = event.target;
13270           if (elementData.lastCommittedValue === value) {
13271             return;
13272           }
13273           elementData.lastCommittedValue = value;
13274           elementData.userValue = value;
13275           this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
13276             source: this,
13277             detail: {
13278               id,
13279               name: "Keystroke",
13280               value,
13281               willCommit: true,
13282               commitKey,
13283               selStart: event.target.selectionStart,
13284               selEnd: event.target.selectionEnd
13285             }
13286           });
13287         });
13288         const _blurListener = blurListener;
13289         blurListener = null;
13290         element.addEventListener("blur", event => {
13291           if (!elementData.focused || !event.relatedTarget) {
13292             return;
13293           }
13294           if (!this.data.actions?.Blur) {
13295             elementData.focused = false;
13296           }
13297           const {
13298             value
13299           } = event.target;
13300           elementData.userValue = value;
13301           if (elementData.lastCommittedValue !== value) {
13302             this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
13303               source: this,
13304               detail: {
13305                 id,
13306                 name: "Keystroke",
13307                 value,
13308                 willCommit: true,
13309                 commitKey: elementData.commitKey,
13310                 selStart: event.target.selectionStart,
13311                 selEnd: event.target.selectionEnd
13312               }
13313             });
13314           }
13315           _blurListener(event);
13316         });
13317         if (this.data.actions?.Keystroke) {
13318           element.addEventListener("beforeinput", event => {
13319             elementData.lastCommittedValue = null;
13320             const {
13321               data,
13322               target
13323             } = event;
13324             const {
13325               value,
13326               selectionStart,
13327               selectionEnd
13328             } = target;
13329             let selStart = selectionStart,
13330               selEnd = selectionEnd;
13331             switch (event.inputType) {
13332               case "deleteWordBackward":
13333                 {
13334                   const match = value.substring(0, selectionStart).match(/\w*[^\w]*$/);
13335                   if (match) {
13336                     selStart -= match[0].length;
13337                   }
13338                   break;
13339                 }
13340               case "deleteWordForward":
13341                 {
13342                   const match = value.substring(selectionStart).match(/^[^\w]*\w*/);
13343                   if (match) {
13344                     selEnd += match[0].length;
13345                   }
13346                   break;
13347                 }
13348               case "deleteContentBackward":
13349                 if (selectionStart === selectionEnd) {
13350                   selStart -= 1;
13351                 }
13352                 break;
13353               case "deleteContentForward":
13354                 if (selectionStart === selectionEnd) {
13355                   selEnd += 1;
13356                 }
13357                 break;
13358             }
13359             event.preventDefault();
13360             this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
13361               source: this,
13362               detail: {
13363                 id,
13364                 name: "Keystroke",
13365                 value,
13366                 change: data || "",
13367                 willCommit: false,
13368                 selStart,
13369                 selEnd
13370               }
13371             });
13372           });
13373         }
13374         this._setEventListeners(element, elementData, [["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.value);
13375       }
13376       if (blurListener) {
13377         element.addEventListener("blur", blurListener);
13378       }
13379       if (this.data.comb) {
13380         const fieldWidth = this.data.rect[2] - this.data.rect[0];
13381         const combWidth = fieldWidth / maxLen;
13382         element.classList.add("comb");
13383         element.style.letterSpacing = `calc(${combWidth}px * var(--scale-factor) - 1ch)`;
13384       }
13385     } else {
13386       element = document.createElement("div");
13387       element.textContent = this.data.fieldValue;
13388       element.style.verticalAlign = "middle";
13389       element.style.display = "table-cell";
13390       if (this.data.hasOwnCanvas) {
13391         element.hidden = true;
13392       }
13393     }
13394     this._setTextStyle(element);
13395     this._setBackgroundColor(element);
13396     this._setDefaultPropertiesFromJS(element);
13397     this.container.append(element);
13398     return this.container;
13399   }
13401 class SignatureWidgetAnnotationElement extends WidgetAnnotationElement {
13402   constructor(parameters) {
13403     super(parameters, {
13404       isRenderable: !!parameters.data.hasOwnCanvas
13405     });
13406   }
13408 class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
13409   constructor(parameters) {
13410     super(parameters, {
13411       isRenderable: parameters.renderForms
13412     });
13413   }
13414   render() {
13415     const storage = this.annotationStorage;
13416     const data = this.data;
13417     const id = data.id;
13418     let value = storage.getValue(id, {
13419       value: data.exportValue === data.fieldValue
13420     }).value;
13421     if (typeof value === "string") {
13422       value = value !== "Off";
13423       storage.setValue(id, {
13424         value
13425       });
13426     }
13427     this.container.classList.add("buttonWidgetAnnotation", "checkBox");
13428     const element = document.createElement("input");
13429     GetElementsByNameSet.add(element);
13430     element.setAttribute("data-element-id", id);
13431     element.disabled = data.readOnly;
13432     this._setRequired(element, this.data.required);
13433     element.type = "checkbox";
13434     element.name = data.fieldName;
13435     if (value) {
13436       element.setAttribute("checked", true);
13437     }
13438     element.setAttribute("exportValue", data.exportValue);
13439     element.tabIndex = DEFAULT_TAB_INDEX;
13440     element.addEventListener("change", event => {
13441       const {
13442         name,
13443         checked
13444       } = event.target;
13445       for (const checkbox of this._getElementsByName(name, id)) {
13446         const curChecked = checked && checkbox.exportValue === data.exportValue;
13447         if (checkbox.domElement) {
13448           checkbox.domElement.checked = curChecked;
13449         }
13450         storage.setValue(checkbox.id, {
13451           value: curChecked
13452         });
13453       }
13454       storage.setValue(id, {
13455         value: checked
13456       });
13457     });
13458     element.addEventListener("resetform", event => {
13459       const defaultValue = data.defaultFieldValue || "Off";
13460       event.target.checked = defaultValue === data.exportValue;
13461     });
13462     if (this.enableScripting && this.hasJSActions) {
13463       element.addEventListener("updatefromsandbox", jsEvent => {
13464         const actions = {
13465           value(event) {
13466             event.target.checked = event.detail.value !== "Off";
13467             storage.setValue(id, {
13468               value: event.target.checked
13469             });
13470           }
13471         };
13472         this._dispatchEventFromSandbox(actions, jsEvent);
13473       });
13474       this._setEventListeners(element, null, [["change", "Validate"], ["change", "Action"], ["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.checked);
13475     }
13476     this._setBackgroundColor(element);
13477     this._setDefaultPropertiesFromJS(element);
13478     this.container.append(element);
13479     return this.container;
13480   }
13482 class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
13483   constructor(parameters) {
13484     super(parameters, {
13485       isRenderable: parameters.renderForms
13486     });
13487   }
13488   render() {
13489     this.container.classList.add("buttonWidgetAnnotation", "radioButton");
13490     const storage = this.annotationStorage;
13491     const data = this.data;
13492     const id = data.id;
13493     let value = storage.getValue(id, {
13494       value: data.fieldValue === data.buttonValue
13495     }).value;
13496     if (typeof value === "string") {
13497       value = value !== data.buttonValue;
13498       storage.setValue(id, {
13499         value
13500       });
13501     }
13502     if (value) {
13503       for (const radio of this._getElementsByName(data.fieldName, id)) {
13504         storage.setValue(radio.id, {
13505           value: false
13506         });
13507       }
13508     }
13509     const element = document.createElement("input");
13510     GetElementsByNameSet.add(element);
13511     element.setAttribute("data-element-id", id);
13512     element.disabled = data.readOnly;
13513     this._setRequired(element, this.data.required);
13514     element.type = "radio";
13515     element.name = data.fieldName;
13516     if (value) {
13517       element.setAttribute("checked", true);
13518     }
13519     element.tabIndex = DEFAULT_TAB_INDEX;
13520     element.addEventListener("change", event => {
13521       const {
13522         name,
13523         checked
13524       } = event.target;
13525       for (const radio of this._getElementsByName(name, id)) {
13526         storage.setValue(radio.id, {
13527           value: false
13528         });
13529       }
13530       storage.setValue(id, {
13531         value: checked
13532       });
13533     });
13534     element.addEventListener("resetform", event => {
13535       const defaultValue = data.defaultFieldValue;
13536       event.target.checked = defaultValue !== null && defaultValue !== undefined && defaultValue === data.buttonValue;
13537     });
13538     if (this.enableScripting && this.hasJSActions) {
13539       const pdfButtonValue = data.buttonValue;
13540       element.addEventListener("updatefromsandbox", jsEvent => {
13541         const actions = {
13542           value: event => {
13543             const checked = pdfButtonValue === event.detail.value;
13544             for (const radio of this._getElementsByName(event.target.name)) {
13545               const curChecked = checked && radio.id === id;
13546               if (radio.domElement) {
13547                 radio.domElement.checked = curChecked;
13548               }
13549               storage.setValue(radio.id, {
13550                 value: curChecked
13551               });
13552             }
13553           }
13554         };
13555         this._dispatchEventFromSandbox(actions, jsEvent);
13556       });
13557       this._setEventListeners(element, null, [["change", "Validate"], ["change", "Action"], ["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.checked);
13558     }
13559     this._setBackgroundColor(element);
13560     this._setDefaultPropertiesFromJS(element);
13561     this.container.append(element);
13562     return this.container;
13563   }
13565 class PushButtonWidgetAnnotationElement extends LinkAnnotationElement {
13566   constructor(parameters) {
13567     super(parameters, {
13568       ignoreBorder: parameters.data.hasAppearance
13569     });
13570   }
13571   render() {
13572     const container = super.render();
13573     container.classList.add("buttonWidgetAnnotation", "pushButton");
13574     const linkElement = container.lastChild;
13575     if (this.enableScripting && this.hasJSActions && linkElement) {
13576       this._setDefaultPropertiesFromJS(linkElement);
13577       linkElement.addEventListener("updatefromsandbox", jsEvent => {
13578         this._dispatchEventFromSandbox({}, jsEvent);
13579       });
13580     }
13581     return container;
13582   }
13584 class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
13585   constructor(parameters) {
13586     super(parameters, {
13587       isRenderable: parameters.renderForms
13588     });
13589   }
13590   render() {
13591     this.container.classList.add("choiceWidgetAnnotation");
13592     const storage = this.annotationStorage;
13593     const id = this.data.id;
13594     const storedData = storage.getValue(id, {
13595       value: this.data.fieldValue
13596     });
13597     const selectElement = document.createElement("select");
13598     GetElementsByNameSet.add(selectElement);
13599     selectElement.setAttribute("data-element-id", id);
13600     selectElement.disabled = this.data.readOnly;
13601     this._setRequired(selectElement, this.data.required);
13602     selectElement.name = this.data.fieldName;
13603     selectElement.tabIndex = DEFAULT_TAB_INDEX;
13604     let addAnEmptyEntry = this.data.combo && this.data.options.length > 0;
13605     if (!this.data.combo) {
13606       selectElement.size = this.data.options.length;
13607       if (this.data.multiSelect) {
13608         selectElement.multiple = true;
13609       }
13610     }
13611     selectElement.addEventListener("resetform", event => {
13612       const defaultValue = this.data.defaultFieldValue;
13613       for (const option of selectElement.options) {
13614         option.selected = option.value === defaultValue;
13615       }
13616     });
13617     for (const option of this.data.options) {
13618       const optionElement = document.createElement("option");
13619       optionElement.textContent = option.displayValue;
13620       optionElement.value = option.exportValue;
13621       if (storedData.value.includes(option.exportValue)) {
13622         optionElement.setAttribute("selected", true);
13623         addAnEmptyEntry = false;
13624       }
13625       selectElement.append(optionElement);
13626     }
13627     let removeEmptyEntry = null;
13628     if (addAnEmptyEntry) {
13629       const noneOptionElement = document.createElement("option");
13630       noneOptionElement.value = " ";
13631       noneOptionElement.setAttribute("hidden", true);
13632       noneOptionElement.setAttribute("selected", true);
13633       selectElement.prepend(noneOptionElement);
13634       removeEmptyEntry = () => {
13635         noneOptionElement.remove();
13636         selectElement.removeEventListener("input", removeEmptyEntry);
13637         removeEmptyEntry = null;
13638       };
13639       selectElement.addEventListener("input", removeEmptyEntry);
13640     }
13641     const getValue = isExport => {
13642       const name = isExport ? "value" : "textContent";
13643       const {
13644         options,
13645         multiple
13646       } = selectElement;
13647       if (!multiple) {
13648         return options.selectedIndex === -1 ? null : options[options.selectedIndex][name];
13649       }
13650       return Array.prototype.filter.call(options, option => option.selected).map(option => option[name]);
13651     };
13652     let selectedValues = getValue(false);
13653     const getItems = event => {
13654       const options = event.target.options;
13655       return Array.prototype.map.call(options, option => ({
13656         displayValue: option.textContent,
13657         exportValue: option.value
13658       }));
13659     };
13660     if (this.enableScripting && this.hasJSActions) {
13661       selectElement.addEventListener("updatefromsandbox", jsEvent => {
13662         const actions = {
13663           value(event) {
13664             removeEmptyEntry?.();
13665             const value = event.detail.value;
13666             const values = new Set(Array.isArray(value) ? value : [value]);
13667             for (const option of selectElement.options) {
13668               option.selected = values.has(option.value);
13669             }
13670             storage.setValue(id, {
13671               value: getValue(true)
13672             });
13673             selectedValues = getValue(false);
13674           },
13675           multipleSelection(event) {
13676             selectElement.multiple = true;
13677           },
13678           remove(event) {
13679             const options = selectElement.options;
13680             const index = event.detail.remove;
13681             options[index].selected = false;
13682             selectElement.remove(index);
13683             if (options.length > 0) {
13684               const i = Array.prototype.findIndex.call(options, option => option.selected);
13685               if (i === -1) {
13686                 options[0].selected = true;
13687               }
13688             }
13689             storage.setValue(id, {
13690               value: getValue(true),
13691               items: getItems(event)
13692             });
13693             selectedValues = getValue(false);
13694           },
13695           clear(event) {
13696             while (selectElement.length !== 0) {
13697               selectElement.remove(0);
13698             }
13699             storage.setValue(id, {
13700               value: null,
13701               items: []
13702             });
13703             selectedValues = getValue(false);
13704           },
13705           insert(event) {
13706             const {
13707               index,
13708               displayValue,
13709               exportValue
13710             } = event.detail.insert;
13711             const selectChild = selectElement.children[index];
13712             const optionElement = document.createElement("option");
13713             optionElement.textContent = displayValue;
13714             optionElement.value = exportValue;
13715             if (selectChild) {
13716               selectChild.before(optionElement);
13717             } else {
13718               selectElement.append(optionElement);
13719             }
13720             storage.setValue(id, {
13721               value: getValue(true),
13722               items: getItems(event)
13723             });
13724             selectedValues = getValue(false);
13725           },
13726           items(event) {
13727             const {
13728               items
13729             } = event.detail;
13730             while (selectElement.length !== 0) {
13731               selectElement.remove(0);
13732             }
13733             for (const item of items) {
13734               const {
13735                 displayValue,
13736                 exportValue
13737               } = item;
13738               const optionElement = document.createElement("option");
13739               optionElement.textContent = displayValue;
13740               optionElement.value = exportValue;
13741               selectElement.append(optionElement);
13742             }
13743             if (selectElement.options.length > 0) {
13744               selectElement.options[0].selected = true;
13745             }
13746             storage.setValue(id, {
13747               value: getValue(true),
13748               items: getItems(event)
13749             });
13750             selectedValues = getValue(false);
13751           },
13752           indices(event) {
13753             const indices = new Set(event.detail.indices);
13754             for (const option of event.target.options) {
13755               option.selected = indices.has(option.index);
13756             }
13757             storage.setValue(id, {
13758               value: getValue(true)
13759             });
13760             selectedValues = getValue(false);
13761           },
13762           editable(event) {
13763             event.target.disabled = !event.detail.editable;
13764           }
13765         };
13766         this._dispatchEventFromSandbox(actions, jsEvent);
13767       });
13768       selectElement.addEventListener("input", event => {
13769         const exportValue = getValue(true);
13770         const change = getValue(false);
13771         storage.setValue(id, {
13772           value: exportValue
13773         });
13774         event.preventDefault();
13775         this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
13776           source: this,
13777           detail: {
13778             id,
13779             name: "Keystroke",
13780             value: selectedValues,
13781             change,
13782             changeEx: exportValue,
13783             willCommit: false,
13784             commitKey: 1,
13785             keyDown: false
13786           }
13787         });
13788       });
13789       this._setEventListeners(selectElement, null, [["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"], ["input", "Action"], ["input", "Validate"]], event => event.target.value);
13790     } else {
13791       selectElement.addEventListener("input", function (event) {
13792         storage.setValue(id, {
13793           value: getValue(true)
13794         });
13795       });
13796     }
13797     if (this.data.combo) {
13798       this._setTextStyle(selectElement);
13799     } else {}
13800     this._setBackgroundColor(selectElement);
13801     this._setDefaultPropertiesFromJS(selectElement);
13802     this.container.append(selectElement);
13803     return this.container;
13804   }
13806 class PopupAnnotationElement extends AnnotationElement {
13807   constructor(parameters) {
13808     const {
13809       data,
13810       elements
13811     } = parameters;
13812     super(parameters, {
13813       isRenderable: AnnotationElement._hasPopupData(data)
13814     });
13815     this.elements = elements;
13816     this.popup = null;
13817   }
13818   render() {
13819     this.container.classList.add("popupAnnotation");
13820     const popup = this.popup = new PopupElement({
13821       container: this.container,
13822       color: this.data.color,
13823       titleObj: this.data.titleObj,
13824       modificationDate: this.data.modificationDate,
13825       contentsObj: this.data.contentsObj,
13826       richText: this.data.richText,
13827       rect: this.data.rect,
13828       parentRect: this.data.parentRect || null,
13829       parent: this.parent,
13830       elements: this.elements,
13831       open: this.data.open
13832     });
13833     const elementIds = [];
13834     for (const element of this.elements) {
13835       element.popup = popup;
13836       element.container.ariaHasPopup = "dialog";
13837       elementIds.push(element.data.id);
13838       element.addHighlightArea();
13839     }
13840     this.container.setAttribute("aria-controls", elementIds.map(id => `${AnnotationPrefix}${id}`).join(","));
13841     return this.container;
13842   }
13844 class PopupElement {
13845   #boundKeyDown = this.#keyDown.bind(this);
13846   #boundHide = this.#hide.bind(this);
13847   #boundShow = this.#show.bind(this);
13848   #boundToggle = this.#toggle.bind(this);
13849   #color = null;
13850   #container = null;
13851   #contentsObj = null;
13852   #dateObj = null;
13853   #elements = null;
13854   #parent = null;
13855   #parentRect = null;
13856   #pinned = false;
13857   #popup = null;
13858   #position = null;
13859   #rect = null;
13860   #richText = null;
13861   #titleObj = null;
13862   #updates = null;
13863   #wasVisible = false;
13864   constructor({
13865     container,
13866     color,
13867     elements,
13868     titleObj,
13869     modificationDate,
13870     contentsObj,
13871     richText,
13872     parent,
13873     rect,
13874     parentRect,
13875     open
13876   }) {
13877     this.#container = container;
13878     this.#titleObj = titleObj;
13879     this.#contentsObj = contentsObj;
13880     this.#richText = richText;
13881     this.#parent = parent;
13882     this.#color = color;
13883     this.#rect = rect;
13884     this.#parentRect = parentRect;
13885     this.#elements = elements;
13886     this.#dateObj = PDFDateString.toDateObject(modificationDate);
13887     this.trigger = elements.flatMap(e => e.getElementsToTriggerPopup());
13888     for (const element of this.trigger) {
13889       element.addEventListener("click", this.#boundToggle);
13890       element.addEventListener("mouseenter", this.#boundShow);
13891       element.addEventListener("mouseleave", this.#boundHide);
13892       element.classList.add("popupTriggerArea");
13893     }
13894     for (const element of elements) {
13895       element.container?.addEventListener("keydown", this.#boundKeyDown);
13896     }
13897     this.#container.hidden = true;
13898     if (open) {
13899       this.#toggle();
13900     }
13901   }
13902   render() {
13903     if (this.#popup) {
13904       return;
13905     }
13906     const popup = this.#popup = document.createElement("div");
13907     popup.className = "popup";
13908     if (this.#color) {
13909       const baseColor = popup.style.outlineColor = Util.makeHexColor(...this.#color);
13910       popup.style.backgroundColor = `color-mix(in srgb, ${baseColor} 30%, white)`;
13911     }
13912     const header = document.createElement("span");
13913     header.className = "header";
13914     const title = document.createElement("h1");
13915     header.append(title);
13916     ({
13917       dir: title.dir,
13918       str: title.textContent
13919     } = this.#titleObj);
13920     popup.append(header);
13921     if (this.#dateObj) {
13922       const modificationDate = document.createElement("span");
13923       modificationDate.classList.add("popupDate");
13924       modificationDate.setAttribute("data-l10n-id", "pdfjs-annotation-date-time-string");
13925       modificationDate.setAttribute("data-l10n-args", JSON.stringify({
13926         dateObj: this.#dateObj.valueOf()
13927       }));
13928       header.append(modificationDate);
13929     }
13930     const html = this.#html;
13931     if (html) {
13932       XfaLayer.render({
13933         xfaHtml: html,
13934         intent: "richText",
13935         div: popup
13936       });
13937       popup.lastChild.classList.add("richText", "popupContent");
13938     } else {
13939       const contents = this._formatContents(this.#contentsObj);
13940       popup.append(contents);
13941     }
13942     this.#container.append(popup);
13943   }
13944   get #html() {
13945     const richText = this.#richText;
13946     const contentsObj = this.#contentsObj;
13947     if (richText?.str && (!contentsObj?.str || contentsObj.str === richText.str)) {
13948       return this.#richText.html || null;
13949     }
13950     return null;
13951   }
13952   get #fontSize() {
13953     return this.#html?.attributes?.style?.fontSize || 0;
13954   }
13955   get #fontColor() {
13956     return this.#html?.attributes?.style?.color || null;
13957   }
13958   #makePopupContent(text) {
13959     const popupLines = [];
13960     const popupContent = {
13961       str: text,
13962       html: {
13963         name: "div",
13964         attributes: {
13965           dir: "auto"
13966         },
13967         children: [{
13968           name: "p",
13969           children: popupLines
13970         }]
13971       }
13972     };
13973     const lineAttributes = {
13974       style: {
13975         color: this.#fontColor,
13976         fontSize: this.#fontSize ? `calc(${this.#fontSize}px * var(--scale-factor))` : ""
13977       }
13978     };
13979     for (const line of text.split("\n")) {
13980       popupLines.push({
13981         name: "span",
13982         value: line,
13983         attributes: lineAttributes
13984       });
13985     }
13986     return popupContent;
13987   }
13988   _formatContents({
13989     str,
13990     dir
13991   }) {
13992     const p = document.createElement("p");
13993     p.classList.add("popupContent");
13994     p.dir = dir;
13995     const lines = str.split(/(?:\r\n?|\n)/);
13996     for (let i = 0, ii = lines.length; i < ii; ++i) {
13997       const line = lines[i];
13998       p.append(document.createTextNode(line));
13999       if (i < ii - 1) {
14000         p.append(document.createElement("br"));
14001       }
14002     }
14003     return p;
14004   }
14005   #keyDown(event) {
14006     if (event.altKey || event.shiftKey || event.ctrlKey || event.metaKey) {
14007       return;
14008     }
14009     if (event.key === "Enter" || event.key === "Escape" && this.#pinned) {
14010       this.#toggle();
14011     }
14012   }
14013   updateEdited({
14014     rect,
14015     popupContent
14016   }) {
14017     this.#updates ||= {
14018       contentsObj: this.#contentsObj,
14019       richText: this.#richText
14020     };
14021     if (rect) {
14022       this.#position = null;
14023     }
14024     if (popupContent) {
14025       this.#richText = this.#makePopupContent(popupContent);
14026       this.#contentsObj = null;
14027     }
14028     this.#popup?.remove();
14029     this.#popup = null;
14030   }
14031   resetEdited() {
14032     if (!this.#updates) {
14033       return;
14034     }
14035     ({
14036       contentsObj: this.#contentsObj,
14037       richText: this.#richText
14038     } = this.#updates);
14039     this.#updates = null;
14040     this.#popup?.remove();
14041     this.#popup = null;
14042     this.#position = null;
14043   }
14044   #setPosition() {
14045     if (this.#position !== null) {
14046       return;
14047     }
14048     const {
14049       page: {
14050         view
14051       },
14052       viewport: {
14053         rawDims: {
14054           pageWidth,
14055           pageHeight,
14056           pageX,
14057           pageY
14058         }
14059       }
14060     } = this.#parent;
14061     let useParentRect = !!this.#parentRect;
14062     let rect = useParentRect ? this.#parentRect : this.#rect;
14063     for (const element of this.#elements) {
14064       if (!rect || Util.intersect(element.data.rect, rect) !== null) {
14065         rect = element.data.rect;
14066         useParentRect = true;
14067         break;
14068       }
14069     }
14070     const normalizedRect = Util.normalizeRect([rect[0], view[3] - rect[1] + view[1], rect[2], view[3] - rect[3] + view[1]]);
14071     const HORIZONTAL_SPACE_AFTER_ANNOTATION = 5;
14072     const parentWidth = useParentRect ? rect[2] - rect[0] + HORIZONTAL_SPACE_AFTER_ANNOTATION : 0;
14073     const popupLeft = normalizedRect[0] + parentWidth;
14074     const popupTop = normalizedRect[1];
14075     this.#position = [100 * (popupLeft - pageX) / pageWidth, 100 * (popupTop - pageY) / pageHeight];
14076     const {
14077       style
14078     } = this.#container;
14079     style.left = `${this.#position[0]}%`;
14080     style.top = `${this.#position[1]}%`;
14081   }
14082   #toggle() {
14083     this.#pinned = !this.#pinned;
14084     if (this.#pinned) {
14085       this.#show();
14086       this.#container.addEventListener("click", this.#boundToggle);
14087       this.#container.addEventListener("keydown", this.#boundKeyDown);
14088     } else {
14089       this.#hide();
14090       this.#container.removeEventListener("click", this.#boundToggle);
14091       this.#container.removeEventListener("keydown", this.#boundKeyDown);
14092     }
14093   }
14094   #show() {
14095     if (!this.#popup) {
14096       this.render();
14097     }
14098     if (!this.isVisible) {
14099       this.#setPosition();
14100       this.#container.hidden = false;
14101       this.#container.style.zIndex = parseInt(this.#container.style.zIndex) + 1000;
14102     } else if (this.#pinned) {
14103       this.#container.classList.add("focused");
14104     }
14105   }
14106   #hide() {
14107     this.#container.classList.remove("focused");
14108     if (this.#pinned || !this.isVisible) {
14109       return;
14110     }
14111     this.#container.hidden = true;
14112     this.#container.style.zIndex = parseInt(this.#container.style.zIndex) - 1000;
14113   }
14114   forceHide() {
14115     this.#wasVisible = this.isVisible;
14116     if (!this.#wasVisible) {
14117       return;
14118     }
14119     this.#container.hidden = true;
14120   }
14121   maybeShow() {
14122     if (!this.#wasVisible) {
14123       return;
14124     }
14125     if (!this.#popup) {
14126       this.#show();
14127     }
14128     this.#wasVisible = false;
14129     this.#container.hidden = false;
14130   }
14131   get isVisible() {
14132     return this.#container.hidden === false;
14133   }
14135 class FreeTextAnnotationElement extends AnnotationElement {
14136   constructor(parameters) {
14137     super(parameters, {
14138       isRenderable: true,
14139       ignoreBorder: true
14140     });
14141     this.textContent = parameters.data.textContent;
14142     this.textPosition = parameters.data.textPosition;
14143     this.annotationEditorType = AnnotationEditorType.FREETEXT;
14144   }
14145   render() {
14146     this.container.classList.add("freeTextAnnotation");
14147     if (this.textContent) {
14148       const content = document.createElement("div");
14149       content.classList.add("annotationTextContent");
14150       content.setAttribute("role", "comment");
14151       for (const line of this.textContent) {
14152         const lineSpan = document.createElement("span");
14153         lineSpan.textContent = line;
14154         content.append(lineSpan);
14155       }
14156       this.container.append(content);
14157     }
14158     if (!this.data.popupRef && this.hasPopupData) {
14159       this._createPopup();
14160     }
14161     this._editOnDoubleClick();
14162     return this.container;
14163   }
14165 class LineAnnotationElement extends AnnotationElement {
14166   #line = null;
14167   constructor(parameters) {
14168     super(parameters, {
14169       isRenderable: true,
14170       ignoreBorder: true
14171     });
14172   }
14173   render() {
14174     this.container.classList.add("lineAnnotation");
14175     const {
14176       data,
14177       width,
14178       height
14179     } = this;
14180     const svg = this.svgFactory.create(width, height, true);
14181     const line = this.#line = this.svgFactory.createElement("svg:line");
14182     line.setAttribute("x1", data.rect[2] - data.lineCoordinates[0]);
14183     line.setAttribute("y1", data.rect[3] - data.lineCoordinates[1]);
14184     line.setAttribute("x2", data.rect[2] - data.lineCoordinates[2]);
14185     line.setAttribute("y2", data.rect[3] - data.lineCoordinates[3]);
14186     line.setAttribute("stroke-width", data.borderStyle.width || 1);
14187     line.setAttribute("stroke", "transparent");
14188     line.setAttribute("fill", "transparent");
14189     svg.append(line);
14190     this.container.append(svg);
14191     if (!data.popupRef && this.hasPopupData) {
14192       this._createPopup();
14193     }
14194     return this.container;
14195   }
14196   getElementsToTriggerPopup() {
14197     return this.#line;
14198   }
14199   addHighlightArea() {
14200     this.container.classList.add("highlightArea");
14201   }
14203 class SquareAnnotationElement extends AnnotationElement {
14204   #square = null;
14205   constructor(parameters) {
14206     super(parameters, {
14207       isRenderable: true,
14208       ignoreBorder: true
14209     });
14210   }
14211   render() {
14212     this.container.classList.add("squareAnnotation");
14213     const {
14214       data,
14215       width,
14216       height
14217     } = this;
14218     const svg = this.svgFactory.create(width, height, true);
14219     const borderWidth = data.borderStyle.width;
14220     const square = this.#square = this.svgFactory.createElement("svg:rect");
14221     square.setAttribute("x", borderWidth / 2);
14222     square.setAttribute("y", borderWidth / 2);
14223     square.setAttribute("width", width - borderWidth);
14224     square.setAttribute("height", height - borderWidth);
14225     square.setAttribute("stroke-width", borderWidth || 1);
14226     square.setAttribute("stroke", "transparent");
14227     square.setAttribute("fill", "transparent");
14228     svg.append(square);
14229     this.container.append(svg);
14230     if (!data.popupRef && this.hasPopupData) {
14231       this._createPopup();
14232     }
14233     return this.container;
14234   }
14235   getElementsToTriggerPopup() {
14236     return this.#square;
14237   }
14238   addHighlightArea() {
14239     this.container.classList.add("highlightArea");
14240   }
14242 class CircleAnnotationElement extends AnnotationElement {
14243   #circle = null;
14244   constructor(parameters) {
14245     super(parameters, {
14246       isRenderable: true,
14247       ignoreBorder: true
14248     });
14249   }
14250   render() {
14251     this.container.classList.add("circleAnnotation");
14252     const {
14253       data,
14254       width,
14255       height
14256     } = this;
14257     const svg = this.svgFactory.create(width, height, true);
14258     const borderWidth = data.borderStyle.width;
14259     const circle = this.#circle = this.svgFactory.createElement("svg:ellipse");
14260     circle.setAttribute("cx", width / 2);
14261     circle.setAttribute("cy", height / 2);
14262     circle.setAttribute("rx", width / 2 - borderWidth / 2);
14263     circle.setAttribute("ry", height / 2 - borderWidth / 2);
14264     circle.setAttribute("stroke-width", borderWidth || 1);
14265     circle.setAttribute("stroke", "transparent");
14266     circle.setAttribute("fill", "transparent");
14267     svg.append(circle);
14268     this.container.append(svg);
14269     if (!data.popupRef && this.hasPopupData) {
14270       this._createPopup();
14271     }
14272     return this.container;
14273   }
14274   getElementsToTriggerPopup() {
14275     return this.#circle;
14276   }
14277   addHighlightArea() {
14278     this.container.classList.add("highlightArea");
14279   }
14281 class PolylineAnnotationElement extends AnnotationElement {
14282   #polyline = null;
14283   constructor(parameters) {
14284     super(parameters, {
14285       isRenderable: true,
14286       ignoreBorder: true
14287     });
14288     this.containerClassName = "polylineAnnotation";
14289     this.svgElementName = "svg:polyline";
14290   }
14291   render() {
14292     this.container.classList.add(this.containerClassName);
14293     const {
14294       data: {
14295         rect,
14296         vertices,
14297         borderStyle,
14298         popupRef
14299       },
14300       width,
14301       height
14302     } = this;
14303     if (!vertices) {
14304       return this.container;
14305     }
14306     const svg = this.svgFactory.create(width, height, true);
14307     let points = [];
14308     for (let i = 0, ii = vertices.length; i < ii; i += 2) {
14309       const x = vertices[i] - rect[0];
14310       const y = rect[3] - vertices[i + 1];
14311       points.push(`${x},${y}`);
14312     }
14313     points = points.join(" ");
14314     const polyline = this.#polyline = this.svgFactory.createElement(this.svgElementName);
14315     polyline.setAttribute("points", points);
14316     polyline.setAttribute("stroke-width", borderStyle.width || 1);
14317     polyline.setAttribute("stroke", "transparent");
14318     polyline.setAttribute("fill", "transparent");
14319     svg.append(polyline);
14320     this.container.append(svg);
14321     if (!popupRef && this.hasPopupData) {
14322       this._createPopup();
14323     }
14324     return this.container;
14325   }
14326   getElementsToTriggerPopup() {
14327     return this.#polyline;
14328   }
14329   addHighlightArea() {
14330     this.container.classList.add("highlightArea");
14331   }
14333 class PolygonAnnotationElement extends PolylineAnnotationElement {
14334   constructor(parameters) {
14335     super(parameters);
14336     this.containerClassName = "polygonAnnotation";
14337     this.svgElementName = "svg:polygon";
14338   }
14340 class CaretAnnotationElement extends AnnotationElement {
14341   constructor(parameters) {
14342     super(parameters, {
14343       isRenderable: true,
14344       ignoreBorder: true
14345     });
14346   }
14347   render() {
14348     this.container.classList.add("caretAnnotation");
14349     if (!this.data.popupRef && this.hasPopupData) {
14350       this._createPopup();
14351     }
14352     return this.container;
14353   }
14355 class InkAnnotationElement extends AnnotationElement {
14356   #polylinesGroupElement = null;
14357   #polylines = [];
14358   constructor(parameters) {
14359     super(parameters, {
14360       isRenderable: true,
14361       ignoreBorder: true
14362     });
14363     this.containerClassName = "inkAnnotation";
14364     this.svgElementName = "svg:polyline";
14365     this.annotationEditorType = this.data.it === "InkHighlight" ? AnnotationEditorType.HIGHLIGHT : AnnotationEditorType.INK;
14366   }
14367   #getTransform(rotation, rect) {
14368     switch (rotation) {
14369       case 90:
14370         return {
14371           transform: `rotate(90) translate(${-rect[0]},${rect[1]}) scale(1,-1)`,
14372           width: rect[3] - rect[1],
14373           height: rect[2] - rect[0]
14374         };
14375       case 180:
14376         return {
14377           transform: `rotate(180) translate(${-rect[2]},${rect[1]}) scale(1,-1)`,
14378           width: rect[2] - rect[0],
14379           height: rect[3] - rect[1]
14380         };
14381       case 270:
14382         return {
14383           transform: `rotate(270) translate(${-rect[2]},${rect[3]}) scale(1,-1)`,
14384           width: rect[3] - rect[1],
14385           height: rect[2] - rect[0]
14386         };
14387       default:
14388         return {
14389           transform: `translate(${-rect[0]},${rect[3]}) scale(1,-1)`,
14390           width: rect[2] - rect[0],
14391           height: rect[3] - rect[1]
14392         };
14393     }
14394   }
14395   render() {
14396     this.container.classList.add(this.containerClassName);
14397     const {
14398       data: {
14399         rect,
14400         rotation,
14401         inkLists,
14402         borderStyle,
14403         popupRef
14404       }
14405     } = this;
14406     const {
14407       transform,
14408       width,
14409       height
14410     } = this.#getTransform(rotation, rect);
14411     const svg = this.svgFactory.create(width, height, true);
14412     const g = this.#polylinesGroupElement = this.svgFactory.createElement("svg:g");
14413     svg.append(g);
14414     g.setAttribute("stroke-width", borderStyle.width || 1);
14415     g.setAttribute("stroke-linecap", "round");
14416     g.setAttribute("stroke-linejoin", "round");
14417     g.setAttribute("stroke-miterlimit", 10);
14418     g.setAttribute("stroke", "transparent");
14419     g.setAttribute("fill", "transparent");
14420     g.setAttribute("transform", transform);
14421     for (let i = 0, ii = inkLists.length; i < ii; i++) {
14422       const polyline = this.svgFactory.createElement(this.svgElementName);
14423       this.#polylines.push(polyline);
14424       polyline.setAttribute("points", inkLists[i].join(","));
14425       g.append(polyline);
14426     }
14427     if (!popupRef && this.hasPopupData) {
14428       this._createPopup();
14429     }
14430     this.container.append(svg);
14431     this._editOnDoubleClick();
14432     return this.container;
14433   }
14434   updateEdited(params) {
14435     super.updateEdited(params);
14436     const {
14437       thickness,
14438       points,
14439       rect
14440     } = params;
14441     const g = this.#polylinesGroupElement;
14442     if (thickness >= 0) {
14443       g.setAttribute("stroke-width", thickness || 1);
14444     }
14445     if (points) {
14446       for (let i = 0, ii = this.#polylines.length; i < ii; i++) {
14447         this.#polylines[i].setAttribute("points", points[i].join(","));
14448       }
14449     }
14450     if (rect) {
14451       const {
14452         transform,
14453         width,
14454         height
14455       } = this.#getTransform(this.data.rotation, rect);
14456       const root = g.parentElement;
14457       root.setAttribute("viewBox", `0 0 ${width} ${height}`);
14458       g.setAttribute("transform", transform);
14459     }
14460   }
14461   getElementsToTriggerPopup() {
14462     return this.#polylines;
14463   }
14464   addHighlightArea() {
14465     this.container.classList.add("highlightArea");
14466   }
14468 class HighlightAnnotationElement extends AnnotationElement {
14469   constructor(parameters) {
14470     super(parameters, {
14471       isRenderable: true,
14472       ignoreBorder: true,
14473       createQuadrilaterals: true
14474     });
14475     this.annotationEditorType = AnnotationEditorType.HIGHLIGHT;
14476   }
14477   render() {
14478     if (!this.data.popupRef && this.hasPopupData) {
14479       this._createPopup();
14480     }
14481     this.container.classList.add("highlightAnnotation");
14482     this._editOnDoubleClick();
14483     return this.container;
14484   }
14486 class UnderlineAnnotationElement extends AnnotationElement {
14487   constructor(parameters) {
14488     super(parameters, {
14489       isRenderable: true,
14490       ignoreBorder: true,
14491       createQuadrilaterals: true
14492     });
14493   }
14494   render() {
14495     if (!this.data.popupRef && this.hasPopupData) {
14496       this._createPopup();
14497     }
14498     this.container.classList.add("underlineAnnotation");
14499     return this.container;
14500   }
14502 class SquigglyAnnotationElement extends AnnotationElement {
14503   constructor(parameters) {
14504     super(parameters, {
14505       isRenderable: true,
14506       ignoreBorder: true,
14507       createQuadrilaterals: true
14508     });
14509   }
14510   render() {
14511     if (!this.data.popupRef && this.hasPopupData) {
14512       this._createPopup();
14513     }
14514     this.container.classList.add("squigglyAnnotation");
14515     return this.container;
14516   }
14518 class StrikeOutAnnotationElement extends AnnotationElement {
14519   constructor(parameters) {
14520     super(parameters, {
14521       isRenderable: true,
14522       ignoreBorder: true,
14523       createQuadrilaterals: true
14524     });
14525   }
14526   render() {
14527     if (!this.data.popupRef && this.hasPopupData) {
14528       this._createPopup();
14529     }
14530     this.container.classList.add("strikeoutAnnotation");
14531     return this.container;
14532   }
14534 class StampAnnotationElement extends AnnotationElement {
14535   constructor(parameters) {
14536     super(parameters, {
14537       isRenderable: true,
14538       ignoreBorder: true
14539     });
14540     this.annotationEditorType = AnnotationEditorType.STAMP;
14541   }
14542   render() {
14543     this.container.classList.add("stampAnnotation");
14544     this.container.setAttribute("role", "img");
14545     if (!this.data.popupRef && this.hasPopupData) {
14546       this._createPopup();
14547     }
14548     this._editOnDoubleClick();
14549     return this.container;
14550   }
14552 class FileAttachmentAnnotationElement extends AnnotationElement {
14553   #trigger = null;
14554   constructor(parameters) {
14555     super(parameters, {
14556       isRenderable: true
14557     });
14558     const {
14559       file
14560     } = this.data;
14561     this.filename = file.filename;
14562     this.content = file.content;
14563     this.linkService.eventBus?.dispatch("fileattachmentannotation", {
14564       source: this,
14565       ...file
14566     });
14567   }
14568   render() {
14569     this.container.classList.add("fileAttachmentAnnotation");
14570     const {
14571       container,
14572       data
14573     } = this;
14574     let trigger;
14575     if (data.hasAppearance || data.fillAlpha === 0) {
14576       trigger = document.createElement("div");
14577     } else {
14578       trigger = document.createElement("img");
14579       trigger.src = `${this.imageResourcesPath}annotation-${/paperclip/i.test(data.name) ? "paperclip" : "pushpin"}.svg`;
14580       if (data.fillAlpha && data.fillAlpha < 1) {
14581         trigger.style = `filter: opacity(${Math.round(data.fillAlpha * 100)}%);`;
14582       }
14583     }
14584     trigger.addEventListener("dblclick", this.#download.bind(this));
14585     this.#trigger = trigger;
14586     const {
14587       isMac
14588     } = util_FeatureTest.platform;
14589     container.addEventListener("keydown", evt => {
14590       if (evt.key === "Enter" && (isMac ? evt.metaKey : evt.ctrlKey)) {
14591         this.#download();
14592       }
14593     });
14594     if (!data.popupRef && this.hasPopupData) {
14595       this._createPopup();
14596     } else {
14597       trigger.classList.add("popupTriggerArea");
14598     }
14599     container.append(trigger);
14600     return container;
14601   }
14602   getElementsToTriggerPopup() {
14603     return this.#trigger;
14604   }
14605   addHighlightArea() {
14606     this.container.classList.add("highlightArea");
14607   }
14608   #download() {
14609     this.downloadManager?.openOrDownloadData(this.content, this.filename);
14610   }
14612 class AnnotationLayer {
14613   #accessibilityManager = null;
14614   #annotationCanvasMap = null;
14615   #editableAnnotations = new Map();
14616   #structTreeLayer = null;
14617   constructor({
14618     div,
14619     accessibilityManager,
14620     annotationCanvasMap,
14621     annotationEditorUIManager,
14622     page,
14623     viewport,
14624     structTreeLayer
14625   }) {
14626     this.div = div;
14627     this.#accessibilityManager = accessibilityManager;
14628     this.#annotationCanvasMap = annotationCanvasMap;
14629     this.#structTreeLayer = structTreeLayer || null;
14630     this.page = page;
14631     this.viewport = viewport;
14632     this.zIndex = 0;
14633     this._annotationEditorUIManager = annotationEditorUIManager;
14634   }
14635   hasEditableAnnotations() {
14636     return this.#editableAnnotations.size > 0;
14637   }
14638   async #appendElement(element, id) {
14639     const contentElement = element.firstChild || element;
14640     const annotationId = contentElement.id = `${AnnotationPrefix}${id}`;
14641     const ariaAttributes = await this.#structTreeLayer?.getAriaAttributes(annotationId);
14642     if (ariaAttributes) {
14643       for (const [key, value] of ariaAttributes) {
14644         contentElement.setAttribute(key, value);
14645       }
14646     }
14647     this.div.append(element);
14648     this.#accessibilityManager?.moveElementInDOM(this.div, element, contentElement, false);
14649   }
14650   async render(params) {
14651     const {
14652       annotations
14653     } = params;
14654     const layer = this.div;
14655     setLayerDimensions(layer, this.viewport);
14656     const popupToElements = new Map();
14657     const elementParams = {
14658       data: null,
14659       layer,
14660       linkService: params.linkService,
14661       downloadManager: params.downloadManager,
14662       imageResourcesPath: params.imageResourcesPath || "",
14663       renderForms: params.renderForms !== false,
14664       svgFactory: new DOMSVGFactory(),
14665       annotationStorage: params.annotationStorage || new AnnotationStorage(),
14666       enableScripting: params.enableScripting === true,
14667       hasJSActions: params.hasJSActions,
14668       fieldObjects: params.fieldObjects,
14669       parent: this,
14670       elements: null
14671     };
14672     for (const data of annotations) {
14673       if (data.noHTML) {
14674         continue;
14675       }
14676       const isPopupAnnotation = data.annotationType === AnnotationType.POPUP;
14677       if (!isPopupAnnotation) {
14678         if (data.rect[2] === data.rect[0] || data.rect[3] === data.rect[1]) {
14679           continue;
14680         }
14681       } else {
14682         const elements = popupToElements.get(data.id);
14683         if (!elements) {
14684           continue;
14685         }
14686         elementParams.elements = elements;
14687       }
14688       elementParams.data = data;
14689       const element = AnnotationElementFactory.create(elementParams);
14690       if (!element.isRenderable) {
14691         continue;
14692       }
14693       if (!isPopupAnnotation && data.popupRef) {
14694         const elements = popupToElements.get(data.popupRef);
14695         if (!elements) {
14696           popupToElements.set(data.popupRef, [element]);
14697         } else {
14698           elements.push(element);
14699         }
14700       }
14701       const rendered = element.render();
14702       if (data.hidden) {
14703         rendered.style.visibility = "hidden";
14704       }
14705       await this.#appendElement(rendered, data.id);
14706       if (element._isEditable) {
14707         this.#editableAnnotations.set(element.data.id, element);
14708         this._annotationEditorUIManager?.renderAnnotationElement(element);
14709       }
14710     }
14711     this.#setAnnotationCanvasMap();
14712   }
14713   async addLinkAnnotations(annotations, linkService) {
14714     const elementParams = {
14715       data: null,
14716       layer: this.div,
14717       linkService,
14718       svgFactory: new DOMSVGFactory(),
14719       parent: this
14720     };
14721     for (const data of annotations) {
14722       elementParams.data = data;
14723       const element = AnnotationElementFactory.create(elementParams);
14724       if (!element.isRenderable) {
14725         continue;
14726       }
14727       const rendered = element.render();
14728       await this.#appendElement(rendered, data.id);
14729     }
14730   }
14731   update({
14732     viewport
14733   }) {
14734     const layer = this.div;
14735     this.viewport = viewport;
14736     setLayerDimensions(layer, {
14737       rotation: viewport.rotation
14738     });
14739     this.#setAnnotationCanvasMap();
14740     layer.hidden = false;
14741   }
14742   #setAnnotationCanvasMap() {
14743     if (!this.#annotationCanvasMap) {
14744       return;
14745     }
14746     const layer = this.div;
14747     for (const [id, canvas] of this.#annotationCanvasMap) {
14748       const element = layer.querySelector(`[data-annotation-id="${id}"]`);
14749       if (!element) {
14750         continue;
14751       }
14752       canvas.className = "annotationContent";
14753       const {
14754         firstChild
14755       } = element;
14756       if (!firstChild) {
14757         element.append(canvas);
14758       } else if (firstChild.nodeName === "CANVAS") {
14759         firstChild.replaceWith(canvas);
14760       } else if (!firstChild.classList.contains("annotationContent")) {
14761         firstChild.before(canvas);
14762       } else {
14763         firstChild.after(canvas);
14764       }
14765       const editableAnnotation = this.#editableAnnotations.get(id);
14766       if (!editableAnnotation) {
14767         continue;
14768       }
14769       if (editableAnnotation._hasNoCanvas) {
14770         this._annotationEditorUIManager?.setMissingCanvas(id, element.id, canvas);
14771         editableAnnotation._hasNoCanvas = false;
14772       } else {
14773         editableAnnotation.canvas = canvas;
14774       }
14775     }
14776     this.#annotationCanvasMap.clear();
14777   }
14778   getEditableAnnotations() {
14779     return Array.from(this.#editableAnnotations.values());
14780   }
14781   getEditableAnnotation(id) {
14782     return this.#editableAnnotations.get(id);
14783   }
14786 ;// ./src/display/editor/freetext.js
14791 const EOL_PATTERN = /\r\n?|\n/g;
14792 class FreeTextEditor extends AnnotationEditor {
14793   #color;
14794   #content = "";
14795   #editorDivId = `${this.id}-editor`;
14796   #editModeAC = null;
14797   #fontSize;
14798   static _freeTextDefaultContent = "";
14799   static _internalPadding = 0;
14800   static _defaultColor = null;
14801   static _defaultFontSize = 10;
14802   static get _keyboardManager() {
14803     const proto = FreeTextEditor.prototype;
14804     const arrowChecker = self => self.isEmpty();
14805     const small = AnnotationEditorUIManager.TRANSLATE_SMALL;
14806     const big = AnnotationEditorUIManager.TRANSLATE_BIG;
14807     return shadow(this, "_keyboardManager", new KeyboardManager([[["ctrl+s", "mac+meta+s", "ctrl+p", "mac+meta+p"], proto.commitOrRemove, {
14808       bubbles: true
14809     }], [["ctrl+Enter", "mac+meta+Enter", "Escape", "mac+Escape"], proto.commitOrRemove], [["ArrowLeft", "mac+ArrowLeft"], proto._translateEmpty, {
14810       args: [-small, 0],
14811       checker: arrowChecker
14812     }], [["ctrl+ArrowLeft", "mac+shift+ArrowLeft"], proto._translateEmpty, {
14813       args: [-big, 0],
14814       checker: arrowChecker
14815     }], [["ArrowRight", "mac+ArrowRight"], proto._translateEmpty, {
14816       args: [small, 0],
14817       checker: arrowChecker
14818     }], [["ctrl+ArrowRight", "mac+shift+ArrowRight"], proto._translateEmpty, {
14819       args: [big, 0],
14820       checker: arrowChecker
14821     }], [["ArrowUp", "mac+ArrowUp"], proto._translateEmpty, {
14822       args: [0, -small],
14823       checker: arrowChecker
14824     }], [["ctrl+ArrowUp", "mac+shift+ArrowUp"], proto._translateEmpty, {
14825       args: [0, -big],
14826       checker: arrowChecker
14827     }], [["ArrowDown", "mac+ArrowDown"], proto._translateEmpty, {
14828       args: [0, small],
14829       checker: arrowChecker
14830     }], [["ctrl+ArrowDown", "mac+shift+ArrowDown"], proto._translateEmpty, {
14831       args: [0, big],
14832       checker: arrowChecker
14833     }]]));
14834   }
14835   static _type = "freetext";
14836   static _editorType = AnnotationEditorType.FREETEXT;
14837   constructor(params) {
14838     super({
14839       ...params,
14840       name: "freeTextEditor"
14841     });
14842     this.#color = params.color || FreeTextEditor._defaultColor || AnnotationEditor._defaultLineColor;
14843     this.#fontSize = params.fontSize || FreeTextEditor._defaultFontSize;
14844   }
14845   static initialize(l10n, uiManager) {
14846     AnnotationEditor.initialize(l10n, uiManager);
14847     const style = getComputedStyle(document.documentElement);
14848     this._internalPadding = parseFloat(style.getPropertyValue("--freetext-padding"));
14849   }
14850   static updateDefaultParams(type, value) {
14851     switch (type) {
14852       case AnnotationEditorParamsType.FREETEXT_SIZE:
14853         FreeTextEditor._defaultFontSize = value;
14854         break;
14855       case AnnotationEditorParamsType.FREETEXT_COLOR:
14856         FreeTextEditor._defaultColor = value;
14857         break;
14858     }
14859   }
14860   updateParams(type, value) {
14861     switch (type) {
14862       case AnnotationEditorParamsType.FREETEXT_SIZE:
14863         this.#updateFontSize(value);
14864         break;
14865       case AnnotationEditorParamsType.FREETEXT_COLOR:
14866         this.#updateColor(value);
14867         break;
14868     }
14869   }
14870   static get defaultPropertiesToUpdate() {
14871     return [[AnnotationEditorParamsType.FREETEXT_SIZE, FreeTextEditor._defaultFontSize], [AnnotationEditorParamsType.FREETEXT_COLOR, FreeTextEditor._defaultColor || AnnotationEditor._defaultLineColor]];
14872   }
14873   get propertiesToUpdate() {
14874     return [[AnnotationEditorParamsType.FREETEXT_SIZE, this.#fontSize], [AnnotationEditorParamsType.FREETEXT_COLOR, this.#color]];
14875   }
14876   #updateFontSize(fontSize) {
14877     const setFontsize = size => {
14878       this.editorDiv.style.fontSize = `calc(${size}px * var(--scale-factor))`;
14879       this.translate(0, -(size - this.#fontSize) * this.parentScale);
14880       this.#fontSize = size;
14881       this.#setEditorDimensions();
14882     };
14883     const savedFontsize = this.#fontSize;
14884     this.addCommands({
14885       cmd: setFontsize.bind(this, fontSize),
14886       undo: setFontsize.bind(this, savedFontsize),
14887       post: this._uiManager.updateUI.bind(this._uiManager, this),
14888       mustExec: true,
14889       type: AnnotationEditorParamsType.FREETEXT_SIZE,
14890       overwriteIfSameType: true,
14891       keepUndo: true
14892     });
14893   }
14894   #updateColor(color) {
14895     const setColor = col => {
14896       this.#color = this.editorDiv.style.color = col;
14897     };
14898     const savedColor = this.#color;
14899     this.addCommands({
14900       cmd: setColor.bind(this, color),
14901       undo: setColor.bind(this, savedColor),
14902       post: this._uiManager.updateUI.bind(this._uiManager, this),
14903       mustExec: true,
14904       type: AnnotationEditorParamsType.FREETEXT_COLOR,
14905       overwriteIfSameType: true,
14906       keepUndo: true
14907     });
14908   }
14909   _translateEmpty(x, y) {
14910     this._uiManager.translateSelectedEditors(x, y, true);
14911   }
14912   getInitialTranslation() {
14913     const scale = this.parentScale;
14914     return [-FreeTextEditor._internalPadding * scale, -(FreeTextEditor._internalPadding + this.#fontSize) * scale];
14915   }
14916   rebuild() {
14917     if (!this.parent) {
14918       return;
14919     }
14920     super.rebuild();
14921     if (this.div === null) {
14922       return;
14923     }
14924     if (!this.isAttachedToDOM) {
14925       this.parent.add(this);
14926     }
14927   }
14928   enableEditMode() {
14929     if (this.isInEditMode()) {
14930       return;
14931     }
14932     this.parent.setEditingState(false);
14933     this.parent.updateToolbar(AnnotationEditorType.FREETEXT);
14934     super.enableEditMode();
14935     this.overlayDiv.classList.remove("enabled");
14936     this.editorDiv.contentEditable = true;
14937     this._isDraggable = false;
14938     this.div.removeAttribute("aria-activedescendant");
14939     this.#editModeAC = new AbortController();
14940     const signal = this._uiManager.combinedSignal(this.#editModeAC);
14941     this.editorDiv.addEventListener("keydown", this.editorDivKeydown.bind(this), {
14942       signal
14943     });
14944     this.editorDiv.addEventListener("focus", this.editorDivFocus.bind(this), {
14945       signal
14946     });
14947     this.editorDiv.addEventListener("blur", this.editorDivBlur.bind(this), {
14948       signal
14949     });
14950     this.editorDiv.addEventListener("input", this.editorDivInput.bind(this), {
14951       signal
14952     });
14953     this.editorDiv.addEventListener("paste", this.editorDivPaste.bind(this), {
14954       signal
14955     });
14956   }
14957   disableEditMode() {
14958     if (!this.isInEditMode()) {
14959       return;
14960     }
14961     this.parent.setEditingState(true);
14962     super.disableEditMode();
14963     this.overlayDiv.classList.add("enabled");
14964     this.editorDiv.contentEditable = false;
14965     this.div.setAttribute("aria-activedescendant", this.#editorDivId);
14966     this._isDraggable = true;
14967     this.#editModeAC?.abort();
14968     this.#editModeAC = null;
14969     this.div.focus({
14970       preventScroll: true
14971     });
14972     this.isEditing = false;
14973     this.parent.div.classList.add("freetextEditing");
14974   }
14975   focusin(event) {
14976     if (!this._focusEventsAllowed) {
14977       return;
14978     }
14979     super.focusin(event);
14980     if (event.target !== this.editorDiv) {
14981       this.editorDiv.focus();
14982     }
14983   }
14984   onceAdded(focus) {
14985     if (this.width) {
14986       return;
14987     }
14988     this.enableEditMode();
14989     if (focus) {
14990       this.editorDiv.focus();
14991     }
14992     if (this._initialOptions?.isCentered) {
14993       this.center();
14994     }
14995     this._initialOptions = null;
14996   }
14997   isEmpty() {
14998     return !this.editorDiv || this.editorDiv.innerText.trim() === "";
14999   }
15000   remove() {
15001     this.isEditing = false;
15002     if (this.parent) {
15003       this.parent.setEditingState(true);
15004       this.parent.div.classList.add("freetextEditing");
15005     }
15006     super.remove();
15007   }
15008   #extractText() {
15009     const buffer = [];
15010     this.editorDiv.normalize();
15011     let prevChild = null;
15012     for (const child of this.editorDiv.childNodes) {
15013       if (prevChild?.nodeType === Node.TEXT_NODE && child.nodeName === "BR") {
15014         continue;
15015       }
15016       buffer.push(FreeTextEditor.#getNodeContent(child));
15017       prevChild = child;
15018     }
15019     return buffer.join("\n");
15020   }
15021   #setEditorDimensions() {
15022     const [parentWidth, parentHeight] = this.parentDimensions;
15023     let rect;
15024     if (this.isAttachedToDOM) {
15025       rect = this.div.getBoundingClientRect();
15026     } else {
15027       const {
15028         currentLayer,
15029         div
15030       } = this;
15031       const savedDisplay = div.style.display;
15032       const savedVisibility = div.classList.contains("hidden");
15033       div.classList.remove("hidden");
15034       div.style.display = "hidden";
15035       currentLayer.div.append(this.div);
15036       rect = div.getBoundingClientRect();
15037       div.remove();
15038       div.style.display = savedDisplay;
15039       div.classList.toggle("hidden", savedVisibility);
15040     }
15041     if (this.rotation % 180 === this.parentRotation % 180) {
15042       this.width = rect.width / parentWidth;
15043       this.height = rect.height / parentHeight;
15044     } else {
15045       this.width = rect.height / parentWidth;
15046       this.height = rect.width / parentHeight;
15047     }
15048     this.fixAndSetPosition();
15049   }
15050   commit() {
15051     if (!this.isInEditMode()) {
15052       return;
15053     }
15054     super.commit();
15055     this.disableEditMode();
15056     const savedText = this.#content;
15057     const newText = this.#content = this.#extractText().trimEnd();
15058     if (savedText === newText) {
15059       return;
15060     }
15061     const setText = text => {
15062       this.#content = text;
15063       if (!text) {
15064         this.remove();
15065         return;
15066       }
15067       this.#setContent();
15068       this._uiManager.rebuild(this);
15069       this.#setEditorDimensions();
15070     };
15071     this.addCommands({
15072       cmd: () => {
15073         setText(newText);
15074       },
15075       undo: () => {
15076         setText(savedText);
15077       },
15078       mustExec: false
15079     });
15080     this.#setEditorDimensions();
15081   }
15082   shouldGetKeyboardEvents() {
15083     return this.isInEditMode();
15084   }
15085   enterInEditMode() {
15086     this.enableEditMode();
15087     this.editorDiv.focus();
15088   }
15089   dblclick(event) {
15090     this.enterInEditMode();
15091   }
15092   keydown(event) {
15093     if (event.target === this.div && event.key === "Enter") {
15094       this.enterInEditMode();
15095       event.preventDefault();
15096     }
15097   }
15098   editorDivKeydown(event) {
15099     FreeTextEditor._keyboardManager.exec(this, event);
15100   }
15101   editorDivFocus(event) {
15102     this.isEditing = true;
15103   }
15104   editorDivBlur(event) {
15105     this.isEditing = false;
15106   }
15107   editorDivInput(event) {
15108     this.parent.div.classList.toggle("freetextEditing", this.isEmpty());
15109   }
15110   disableEditing() {
15111     this.editorDiv.setAttribute("role", "comment");
15112     this.editorDiv.removeAttribute("aria-multiline");
15113   }
15114   enableEditing() {
15115     this.editorDiv.setAttribute("role", "textbox");
15116     this.editorDiv.setAttribute("aria-multiline", true);
15117   }
15118   render() {
15119     if (this.div) {
15120       return this.div;
15121     }
15122     let baseX, baseY;
15123     if (this.width) {
15124       baseX = this.x;
15125       baseY = this.y;
15126     }
15127     super.render();
15128     this.editorDiv = document.createElement("div");
15129     this.editorDiv.className = "internal";
15130     this.editorDiv.setAttribute("id", this.#editorDivId);
15131     this.editorDiv.setAttribute("data-l10n-id", "pdfjs-free-text2");
15132     this.editorDiv.setAttribute("data-l10n-attrs", "default-content");
15133     this.enableEditing();
15134     this.editorDiv.contentEditable = true;
15135     const {
15136       style
15137     } = this.editorDiv;
15138     style.fontSize = `calc(${this.#fontSize}px * var(--scale-factor))`;
15139     style.color = this.#color;
15140     this.div.append(this.editorDiv);
15141     this.overlayDiv = document.createElement("div");
15142     this.overlayDiv.classList.add("overlay", "enabled");
15143     this.div.append(this.overlayDiv);
15144     bindEvents(this, this.div, ["dblclick", "keydown"]);
15145     if (this.width) {
15146       const [parentWidth, parentHeight] = this.parentDimensions;
15147       if (this.annotationElementId) {
15148         const {
15149           position
15150         } = this._initialData;
15151         let [tx, ty] = this.getInitialTranslation();
15152         [tx, ty] = this.pageTranslationToScreen(tx, ty);
15153         const [pageWidth, pageHeight] = this.pageDimensions;
15154         const [pageX, pageY] = this.pageTranslation;
15155         let posX, posY;
15156         switch (this.rotation) {
15157           case 0:
15158             posX = baseX + (position[0] - pageX) / pageWidth;
15159             posY = baseY + this.height - (position[1] - pageY) / pageHeight;
15160             break;
15161           case 90:
15162             posX = baseX + (position[0] - pageX) / pageWidth;
15163             posY = baseY - (position[1] - pageY) / pageHeight;
15164             [tx, ty] = [ty, -tx];
15165             break;
15166           case 180:
15167             posX = baseX - this.width + (position[0] - pageX) / pageWidth;
15168             posY = baseY - (position[1] - pageY) / pageHeight;
15169             [tx, ty] = [-tx, -ty];
15170             break;
15171           case 270:
15172             posX = baseX + (position[0] - pageX - this.height * pageHeight) / pageWidth;
15173             posY = baseY + (position[1] - pageY - this.width * pageWidth) / pageHeight;
15174             [tx, ty] = [-ty, tx];
15175             break;
15176         }
15177         this.setAt(posX * parentWidth, posY * parentHeight, tx, ty);
15178       } else {
15179         this.setAt(baseX * parentWidth, baseY * parentHeight, this.width * parentWidth, this.height * parentHeight);
15180       }
15181       this.#setContent();
15182       this._isDraggable = true;
15183       this.editorDiv.contentEditable = false;
15184     } else {
15185       this._isDraggable = false;
15186       this.editorDiv.contentEditable = true;
15187     }
15188     return this.div;
15189   }
15190   static #getNodeContent(node) {
15191     return (node.nodeType === Node.TEXT_NODE ? node.nodeValue : node.innerText).replaceAll(EOL_PATTERN, "");
15192   }
15193   editorDivPaste(event) {
15194     const clipboardData = event.clipboardData || window.clipboardData;
15195     const {
15196       types
15197     } = clipboardData;
15198     if (types.length === 1 && types[0] === "text/plain") {
15199       return;
15200     }
15201     event.preventDefault();
15202     const paste = FreeTextEditor.#deserializeContent(clipboardData.getData("text") || "").replaceAll(EOL_PATTERN, "\n");
15203     if (!paste) {
15204       return;
15205     }
15206     const selection = window.getSelection();
15207     if (!selection.rangeCount) {
15208       return;
15209     }
15210     this.editorDiv.normalize();
15211     selection.deleteFromDocument();
15212     const range = selection.getRangeAt(0);
15213     if (!paste.includes("\n")) {
15214       range.insertNode(document.createTextNode(paste));
15215       this.editorDiv.normalize();
15216       selection.collapseToStart();
15217       return;
15218     }
15219     const {
15220       startContainer,
15221       startOffset
15222     } = range;
15223     const bufferBefore = [];
15224     const bufferAfter = [];
15225     if (startContainer.nodeType === Node.TEXT_NODE) {
15226       const parent = startContainer.parentElement;
15227       bufferAfter.push(startContainer.nodeValue.slice(startOffset).replaceAll(EOL_PATTERN, ""));
15228       if (parent !== this.editorDiv) {
15229         let buffer = bufferBefore;
15230         for (const child of this.editorDiv.childNodes) {
15231           if (child === parent) {
15232             buffer = bufferAfter;
15233             continue;
15234           }
15235           buffer.push(FreeTextEditor.#getNodeContent(child));
15236         }
15237       }
15238       bufferBefore.push(startContainer.nodeValue.slice(0, startOffset).replaceAll(EOL_PATTERN, ""));
15239     } else if (startContainer === this.editorDiv) {
15240       let buffer = bufferBefore;
15241       let i = 0;
15242       for (const child of this.editorDiv.childNodes) {
15243         if (i++ === startOffset) {
15244           buffer = bufferAfter;
15245         }
15246         buffer.push(FreeTextEditor.#getNodeContent(child));
15247       }
15248     }
15249     this.#content = `${bufferBefore.join("\n")}${paste}${bufferAfter.join("\n")}`;
15250     this.#setContent();
15251     const newRange = new Range();
15252     let beforeLength = bufferBefore.reduce((acc, line) => acc + line.length, 0);
15253     for (const {
15254       firstChild
15255     } of this.editorDiv.childNodes) {
15256       if (firstChild.nodeType === Node.TEXT_NODE) {
15257         const length = firstChild.nodeValue.length;
15258         if (beforeLength <= length) {
15259           newRange.setStart(firstChild, beforeLength);
15260           newRange.setEnd(firstChild, beforeLength);
15261           break;
15262         }
15263         beforeLength -= length;
15264       }
15265     }
15266     selection.removeAllRanges();
15267     selection.addRange(newRange);
15268   }
15269   #setContent() {
15270     this.editorDiv.replaceChildren();
15271     if (!this.#content) {
15272       return;
15273     }
15274     for (const line of this.#content.split("\n")) {
15275       const div = document.createElement("div");
15276       div.append(line ? document.createTextNode(line) : document.createElement("br"));
15277       this.editorDiv.append(div);
15278     }
15279   }
15280   #serializeContent() {
15281     return this.#content.replaceAll("\xa0", " ");
15282   }
15283   static #deserializeContent(content) {
15284     return content.replaceAll(" ", "\xa0");
15285   }
15286   get contentDiv() {
15287     return this.editorDiv;
15288   }
15289   static async deserialize(data, parent, uiManager) {
15290     let initialData = null;
15291     if (data instanceof FreeTextAnnotationElement) {
15292       const {
15293         data: {
15294           defaultAppearanceData: {
15295             fontSize,
15296             fontColor
15297           },
15298           rect,
15299           rotation,
15300           id,
15301           popupRef
15302         },
15303         textContent,
15304         textPosition,
15305         parent: {
15306           page: {
15307             pageNumber
15308           }
15309         }
15310       } = data;
15311       if (!textContent || textContent.length === 0) {
15312         return null;
15313       }
15314       initialData = data = {
15315         annotationType: AnnotationEditorType.FREETEXT,
15316         color: Array.from(fontColor),
15317         fontSize,
15318         value: textContent.join("\n"),
15319         position: textPosition,
15320         pageIndex: pageNumber - 1,
15321         rect: rect.slice(0),
15322         rotation,
15323         id,
15324         deleted: false,
15325         popupRef
15326       };
15327     }
15328     const editor = await super.deserialize(data, parent, uiManager);
15329     editor.#fontSize = data.fontSize;
15330     editor.#color = Util.makeHexColor(...data.color);
15331     editor.#content = FreeTextEditor.#deserializeContent(data.value);
15332     editor.annotationElementId = data.id || null;
15333     editor._initialData = initialData;
15334     return editor;
15335   }
15336   serialize(isForCopying = false) {
15337     if (this.isEmpty()) {
15338       return null;
15339     }
15340     if (this.deleted) {
15341       return this.serializeDeleted();
15342     }
15343     const padding = FreeTextEditor._internalPadding * this.parentScale;
15344     const rect = this.getRect(padding, padding);
15345     const color = AnnotationEditor._colorManager.convert(this.isAttachedToDOM ? getComputedStyle(this.editorDiv).color : this.#color);
15346     const serialized = {
15347       annotationType: AnnotationEditorType.FREETEXT,
15348       color,
15349       fontSize: this.#fontSize,
15350       value: this.#serializeContent(),
15351       pageIndex: this.pageIndex,
15352       rect,
15353       rotation: this.rotation,
15354       structTreeParentId: this._structTreeParentId
15355     };
15356     if (isForCopying) {
15357       return serialized;
15358     }
15359     if (this.annotationElementId && !this.#hasElementChanged(serialized)) {
15360       return null;
15361     }
15362     serialized.id = this.annotationElementId;
15363     return serialized;
15364   }
15365   #hasElementChanged(serialized) {
15366     const {
15367       value,
15368       fontSize,
15369       color,
15370       pageIndex
15371     } = this._initialData;
15372     return this._hasBeenMoved || serialized.value !== value || serialized.fontSize !== fontSize || serialized.color.some((c, i) => c !== color[i]) || serialized.pageIndex !== pageIndex;
15373   }
15374   renderAnnotationElement(annotation) {
15375     const content = super.renderAnnotationElement(annotation);
15376     if (this.deleted) {
15377       return content;
15378     }
15379     const {
15380       style
15381     } = content;
15382     style.fontSize = `calc(${this.#fontSize}px * var(--scale-factor))`;
15383     style.color = this.#color;
15384     content.replaceChildren();
15385     for (const line of this.#content.split("\n")) {
15386       const div = document.createElement("div");
15387       div.append(line ? document.createTextNode(line) : document.createElement("br"));
15388       content.append(div);
15389     }
15390     const padding = FreeTextEditor._internalPadding * this.parentScale;
15391     annotation.updateEdited({
15392       rect: this.getRect(padding, padding),
15393       popupContent: this.#content
15394     });
15395     return content;
15396   }
15397   resetAnnotationElement(annotation) {
15398     super.resetAnnotationElement(annotation);
15399     annotation.resetEdited();
15400   }
15403 ;// ./src/display/editor/drawers/outline.js
15405 class Outline {
15406   static PRECISION = 1e-4;
15407   toSVGPath() {
15408     unreachable("Abstract method `toSVGPath` must be implemented.");
15409   }
15410   get box() {
15411     unreachable("Abstract getter `box` must be implemented.");
15412   }
15413   serialize(_bbox, _rotation) {
15414     unreachable("Abstract method `serialize` must be implemented.");
15415   }
15416   static _rescale(src, tx, ty, sx, sy, dest) {
15417     dest ||= new Float32Array(src.length);
15418     for (let i = 0, ii = src.length; i < ii; i += 2) {
15419       dest[i] = tx + src[i] * sx;
15420       dest[i + 1] = ty + src[i + 1] * sy;
15421     }
15422     return dest;
15423   }
15424   static _rescaleAndSwap(src, tx, ty, sx, sy, dest) {
15425     dest ||= new Float32Array(src.length);
15426     for (let i = 0, ii = src.length; i < ii; i += 2) {
15427       dest[i] = tx + src[i + 1] * sx;
15428       dest[i + 1] = ty + src[i] * sy;
15429     }
15430     return dest;
15431   }
15432   static _translate(src, tx, ty, dest) {
15433     dest ||= new Float32Array(src.length);
15434     for (let i = 0, ii = src.length; i < ii; i += 2) {
15435       dest[i] = tx + src[i];
15436       dest[i + 1] = ty + src[i + 1];
15437     }
15438     return dest;
15439   }
15440   static svgRound(x) {
15441     return Math.round(x * 10000);
15442   }
15443   static _normalizePoint(x, y, parentWidth, parentHeight, rotation) {
15444     switch (rotation) {
15445       case 90:
15446         return [1 - y / parentWidth, x / parentHeight];
15447       case 180:
15448         return [1 - x / parentWidth, 1 - y / parentHeight];
15449       case 270:
15450         return [y / parentWidth, 1 - x / parentHeight];
15451       default:
15452         return [x / parentWidth, y / parentHeight];
15453     }
15454   }
15455   static _normalizePagePoint(x, y, rotation) {
15456     switch (rotation) {
15457       case 90:
15458         return [1 - y, x];
15459       case 180:
15460         return [1 - x, 1 - y];
15461       case 270:
15462         return [y, 1 - x];
15463       default:
15464         return [x, y];
15465     }
15466   }
15467   static createBezierPoints(x1, y1, x2, y2, x3, y3) {
15468     return [(x1 + 5 * x2) / 6, (y1 + 5 * y2) / 6, (5 * x2 + x3) / 6, (5 * y2 + y3) / 6, (x2 + x3) / 2, (y2 + y3) / 2];
15469   }
15472 ;// ./src/display/editor/drawers/freedraw.js
15475 class FreeDrawOutliner {
15476   #box;
15477   #bottom = [];
15478   #innerMargin;
15479   #isLTR;
15480   #top = [];
15481   #last = new Float32Array(18);
15482   #lastX;
15483   #lastY;
15484   #min;
15485   #min_dist;
15486   #scaleFactor;
15487   #thickness;
15488   #points = [];
15489   static #MIN_DIST = 8;
15490   static #MIN_DIFF = 2;
15491   static #MIN = FreeDrawOutliner.#MIN_DIST + FreeDrawOutliner.#MIN_DIFF;
15492   constructor({
15493     x,
15494     y
15495   }, box, scaleFactor, thickness, isLTR, innerMargin = 0) {
15496     this.#box = box;
15497     this.#thickness = thickness * scaleFactor;
15498     this.#isLTR = isLTR;
15499     this.#last.set([NaN, NaN, NaN, NaN, x, y], 6);
15500     this.#innerMargin = innerMargin;
15501     this.#min_dist = FreeDrawOutliner.#MIN_DIST * scaleFactor;
15502     this.#min = FreeDrawOutliner.#MIN * scaleFactor;
15503     this.#scaleFactor = scaleFactor;
15504     this.#points.push(x, y);
15505   }
15506   isEmpty() {
15507     return isNaN(this.#last[8]);
15508   }
15509   #getLastCoords() {
15510     const lastTop = this.#last.subarray(4, 6);
15511     const lastBottom = this.#last.subarray(16, 18);
15512     const [x, y, width, height] = this.#box;
15513     return [(this.#lastX + (lastTop[0] - lastBottom[0]) / 2 - x) / width, (this.#lastY + (lastTop[1] - lastBottom[1]) / 2 - y) / height, (this.#lastX + (lastBottom[0] - lastTop[0]) / 2 - x) / width, (this.#lastY + (lastBottom[1] - lastTop[1]) / 2 - y) / height];
15514   }
15515   add({
15516     x,
15517     y
15518   }) {
15519     this.#lastX = x;
15520     this.#lastY = y;
15521     const [layerX, layerY, layerWidth, layerHeight] = this.#box;
15522     let [x1, y1, x2, y2] = this.#last.subarray(8, 12);
15523     const diffX = x - x2;
15524     const diffY = y - y2;
15525     const d = Math.hypot(diffX, diffY);
15526     if (d < this.#min) {
15527       return false;
15528     }
15529     const diffD = d - this.#min_dist;
15530     const K = diffD / d;
15531     const shiftX = K * diffX;
15532     const shiftY = K * diffY;
15533     let x0 = x1;
15534     let y0 = y1;
15535     x1 = x2;
15536     y1 = y2;
15537     x2 += shiftX;
15538     y2 += shiftY;
15539     this.#points?.push(x, y);
15540     const nX = -shiftY / diffD;
15541     const nY = shiftX / diffD;
15542     const thX = nX * this.#thickness;
15543     const thY = nY * this.#thickness;
15544     this.#last.set(this.#last.subarray(2, 8), 0);
15545     this.#last.set([x2 + thX, y2 + thY], 4);
15546     this.#last.set(this.#last.subarray(14, 18), 12);
15547     this.#last.set([x2 - thX, y2 - thY], 16);
15548     if (isNaN(this.#last[6])) {
15549       if (this.#top.length === 0) {
15550         this.#last.set([x1 + thX, y1 + thY], 2);
15551         this.#top.push(NaN, NaN, NaN, NaN, (x1 + thX - layerX) / layerWidth, (y1 + thY - layerY) / layerHeight);
15552         this.#last.set([x1 - thX, y1 - thY], 14);
15553         this.#bottom.push(NaN, NaN, NaN, NaN, (x1 - thX - layerX) / layerWidth, (y1 - thY - layerY) / layerHeight);
15554       }
15555       this.#last.set([x0, y0, x1, y1, x2, y2], 6);
15556       return !this.isEmpty();
15557     }
15558     this.#last.set([x0, y0, x1, y1, x2, y2], 6);
15559     const angle = Math.abs(Math.atan2(y0 - y1, x0 - x1) - Math.atan2(shiftY, shiftX));
15560     if (angle < Math.PI / 2) {
15561       [x1, y1, x2, y2] = this.#last.subarray(2, 6);
15562       this.#top.push(NaN, NaN, NaN, NaN, ((x1 + x2) / 2 - layerX) / layerWidth, ((y1 + y2) / 2 - layerY) / layerHeight);
15563       [x1, y1, x0, y0] = this.#last.subarray(14, 18);
15564       this.#bottom.push(NaN, NaN, NaN, NaN, ((x0 + x1) / 2 - layerX) / layerWidth, ((y0 + y1) / 2 - layerY) / layerHeight);
15565       return true;
15566     }
15567     [x0, y0, x1, y1, x2, y2] = this.#last.subarray(0, 6);
15568     this.#top.push(((x0 + 5 * x1) / 6 - layerX) / layerWidth, ((y0 + 5 * y1) / 6 - layerY) / layerHeight, ((5 * x1 + x2) / 6 - layerX) / layerWidth, ((5 * y1 + y2) / 6 - layerY) / layerHeight, ((x1 + x2) / 2 - layerX) / layerWidth, ((y1 + y2) / 2 - layerY) / layerHeight);
15569     [x2, y2, x1, y1, x0, y0] = this.#last.subarray(12, 18);
15570     this.#bottom.push(((x0 + 5 * x1) / 6 - layerX) / layerWidth, ((y0 + 5 * y1) / 6 - layerY) / layerHeight, ((5 * x1 + x2) / 6 - layerX) / layerWidth, ((5 * y1 + y2) / 6 - layerY) / layerHeight, ((x1 + x2) / 2 - layerX) / layerWidth, ((y1 + y2) / 2 - layerY) / layerHeight);
15571     return true;
15572   }
15573   toSVGPath() {
15574     if (this.isEmpty()) {
15575       return "";
15576     }
15577     const top = this.#top;
15578     const bottom = this.#bottom;
15579     if (isNaN(this.#last[6]) && !this.isEmpty()) {
15580       return this.#toSVGPathTwoPoints();
15581     }
15582     const buffer = [];
15583     buffer.push(`M${top[4]} ${top[5]}`);
15584     for (let i = 6; i < top.length; i += 6) {
15585       if (isNaN(top[i])) {
15586         buffer.push(`L${top[i + 4]} ${top[i + 5]}`);
15587       } else {
15588         buffer.push(`C${top[i]} ${top[i + 1]} ${top[i + 2]} ${top[i + 3]} ${top[i + 4]} ${top[i + 5]}`);
15589       }
15590     }
15591     this.#toSVGPathEnd(buffer);
15592     for (let i = bottom.length - 6; i >= 6; i -= 6) {
15593       if (isNaN(bottom[i])) {
15594         buffer.push(`L${bottom[i + 4]} ${bottom[i + 5]}`);
15595       } else {
15596         buffer.push(`C${bottom[i]} ${bottom[i + 1]} ${bottom[i + 2]} ${bottom[i + 3]} ${bottom[i + 4]} ${bottom[i + 5]}`);
15597       }
15598     }
15599     this.#toSVGPathStart(buffer);
15600     return buffer.join(" ");
15601   }
15602   #toSVGPathTwoPoints() {
15603     const [x, y, width, height] = this.#box;
15604     const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
15605     return `M${(this.#last[2] - x) / width} ${(this.#last[3] - y) / height} L${(this.#last[4] - x) / width} ${(this.#last[5] - y) / height} L${lastTopX} ${lastTopY} L${lastBottomX} ${lastBottomY} L${(this.#last[16] - x) / width} ${(this.#last[17] - y) / height} L${(this.#last[14] - x) / width} ${(this.#last[15] - y) / height} Z`;
15606   }
15607   #toSVGPathStart(buffer) {
15608     const bottom = this.#bottom;
15609     buffer.push(`L${bottom[4]} ${bottom[5]} Z`);
15610   }
15611   #toSVGPathEnd(buffer) {
15612     const [x, y, width, height] = this.#box;
15613     const lastTop = this.#last.subarray(4, 6);
15614     const lastBottom = this.#last.subarray(16, 18);
15615     const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
15616     buffer.push(`L${(lastTop[0] - x) / width} ${(lastTop[1] - y) / height} L${lastTopX} ${lastTopY} L${lastBottomX} ${lastBottomY} L${(lastBottom[0] - x) / width} ${(lastBottom[1] - y) / height}`);
15617   }
15618   newFreeDrawOutline(outline, points, box, scaleFactor, innerMargin, isLTR) {
15619     return new FreeDrawOutline(outline, points, box, scaleFactor, innerMargin, isLTR);
15620   }
15621   getOutlines() {
15622     const top = this.#top;
15623     const bottom = this.#bottom;
15624     const last = this.#last;
15625     const [layerX, layerY, layerWidth, layerHeight] = this.#box;
15626     const points = new Float32Array((this.#points?.length ?? 0) + 2);
15627     for (let i = 0, ii = points.length - 2; i < ii; i += 2) {
15628       points[i] = (this.#points[i] - layerX) / layerWidth;
15629       points[i + 1] = (this.#points[i + 1] - layerY) / layerHeight;
15630     }
15631     points[points.length - 2] = (this.#lastX - layerX) / layerWidth;
15632     points[points.length - 1] = (this.#lastY - layerY) / layerHeight;
15633     if (isNaN(last[6]) && !this.isEmpty()) {
15634       return this.#getOutlineTwoPoints(points);
15635     }
15636     const outline = new Float32Array(this.#top.length + 24 + this.#bottom.length);
15637     let N = top.length;
15638     for (let i = 0; i < N; i += 2) {
15639       if (isNaN(top[i])) {
15640         outline[i] = outline[i + 1] = NaN;
15641         continue;
15642       }
15643       outline[i] = top[i];
15644       outline[i + 1] = top[i + 1];
15645     }
15646     N = this.#getOutlineEnd(outline, N);
15647     for (let i = bottom.length - 6; i >= 6; i -= 6) {
15648       for (let j = 0; j < 6; j += 2) {
15649         if (isNaN(bottom[i + j])) {
15650           outline[N] = outline[N + 1] = NaN;
15651           N += 2;
15652           continue;
15653         }
15654         outline[N] = bottom[i + j];
15655         outline[N + 1] = bottom[i + j + 1];
15656         N += 2;
15657       }
15658     }
15659     this.#getOutlineStart(outline, N);
15660     return this.newFreeDrawOutline(outline, points, this.#box, this.#scaleFactor, this.#innerMargin, this.#isLTR);
15661   }
15662   #getOutlineTwoPoints(points) {
15663     const last = this.#last;
15664     const [layerX, layerY, layerWidth, layerHeight] = this.#box;
15665     const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
15666     const outline = new Float32Array(36);
15667     outline.set([NaN, NaN, NaN, NaN, (last[2] - layerX) / layerWidth, (last[3] - layerY) / layerHeight, NaN, NaN, NaN, NaN, (last[4] - layerX) / layerWidth, (last[5] - layerY) / layerHeight, NaN, NaN, NaN, NaN, lastTopX, lastTopY, NaN, NaN, NaN, NaN, lastBottomX, lastBottomY, NaN, NaN, NaN, NaN, (last[16] - layerX) / layerWidth, (last[17] - layerY) / layerHeight, NaN, NaN, NaN, NaN, (last[14] - layerX) / layerWidth, (last[15] - layerY) / layerHeight], 0);
15668     return this.newFreeDrawOutline(outline, points, this.#box, this.#scaleFactor, this.#innerMargin, this.#isLTR);
15669   }
15670   #getOutlineStart(outline, pos) {
15671     const bottom = this.#bottom;
15672     outline.set([NaN, NaN, NaN, NaN, bottom[4], bottom[5]], pos);
15673     return pos += 6;
15674   }
15675   #getOutlineEnd(outline, pos) {
15676     const lastTop = this.#last.subarray(4, 6);
15677     const lastBottom = this.#last.subarray(16, 18);
15678     const [layerX, layerY, layerWidth, layerHeight] = this.#box;
15679     const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
15680     outline.set([NaN, NaN, NaN, NaN, (lastTop[0] - layerX) / layerWidth, (lastTop[1] - layerY) / layerHeight, NaN, NaN, NaN, NaN, lastTopX, lastTopY, NaN, NaN, NaN, NaN, lastBottomX, lastBottomY, NaN, NaN, NaN, NaN, (lastBottom[0] - layerX) / layerWidth, (lastBottom[1] - layerY) / layerHeight], pos);
15681     return pos += 24;
15682   }
15684 class FreeDrawOutline extends Outline {
15685   #box;
15686   #bbox = new Float32Array(4);
15687   #innerMargin;
15688   #isLTR;
15689   #points;
15690   #scaleFactor;
15691   #outline;
15692   constructor(outline, points, box, scaleFactor, innerMargin, isLTR) {
15693     super();
15694     this.#outline = outline;
15695     this.#points = points;
15696     this.#box = box;
15697     this.#scaleFactor = scaleFactor;
15698     this.#innerMargin = innerMargin;
15699     this.#isLTR = isLTR;
15700     this.lastPoint = [NaN, NaN];
15701     this.#computeMinMax(isLTR);
15702     const [x, y, width, height] = this.#bbox;
15703     for (let i = 0, ii = outline.length; i < ii; i += 2) {
15704       outline[i] = (outline[i] - x) / width;
15705       outline[i + 1] = (outline[i + 1] - y) / height;
15706     }
15707     for (let i = 0, ii = points.length; i < ii; i += 2) {
15708       points[i] = (points[i] - x) / width;
15709       points[i + 1] = (points[i + 1] - y) / height;
15710     }
15711   }
15712   toSVGPath() {
15713     const buffer = [`M${this.#outline[4]} ${this.#outline[5]}`];
15714     for (let i = 6, ii = this.#outline.length; i < ii; i += 6) {
15715       if (isNaN(this.#outline[i])) {
15716         buffer.push(`L${this.#outline[i + 4]} ${this.#outline[i + 5]}`);
15717         continue;
15718       }
15719       buffer.push(`C${this.#outline[i]} ${this.#outline[i + 1]} ${this.#outline[i + 2]} ${this.#outline[i + 3]} ${this.#outline[i + 4]} ${this.#outline[i + 5]}`);
15720     }
15721     buffer.push("Z");
15722     return buffer.join(" ");
15723   }
15724   serialize([blX, blY, trX, trY], rotation) {
15725     const width = trX - blX;
15726     const height = trY - blY;
15727     let outline;
15728     let points;
15729     switch (rotation) {
15730       case 0:
15731         outline = Outline._rescale(this.#outline, blX, trY, width, -height);
15732         points = Outline._rescale(this.#points, blX, trY, width, -height);
15733         break;
15734       case 90:
15735         outline = Outline._rescaleAndSwap(this.#outline, blX, blY, width, height);
15736         points = Outline._rescaleAndSwap(this.#points, blX, blY, width, height);
15737         break;
15738       case 180:
15739         outline = Outline._rescale(this.#outline, trX, blY, -width, height);
15740         points = Outline._rescale(this.#points, trX, blY, -width, height);
15741         break;
15742       case 270:
15743         outline = Outline._rescaleAndSwap(this.#outline, trX, trY, -width, -height);
15744         points = Outline._rescaleAndSwap(this.#points, trX, trY, -width, -height);
15745         break;
15746     }
15747     return {
15748       outline: Array.from(outline),
15749       points: [Array.from(points)]
15750     };
15751   }
15752   #computeMinMax(isLTR) {
15753     const outline = this.#outline;
15754     let lastX = outline[4];
15755     let lastY = outline[5];
15756     let minX = lastX;
15757     let minY = lastY;
15758     let maxX = lastX;
15759     let maxY = lastY;
15760     let lastPointX = lastX;
15761     let lastPointY = lastY;
15762     const ltrCallback = isLTR ? Math.max : Math.min;
15763     for (let i = 6, ii = outline.length; i < ii; i += 6) {
15764       if (isNaN(outline[i])) {
15765         minX = Math.min(minX, outline[i + 4]);
15766         minY = Math.min(minY, outline[i + 5]);
15767         maxX = Math.max(maxX, outline[i + 4]);
15768         maxY = Math.max(maxY, outline[i + 5]);
15769         if (lastPointY < outline[i + 5]) {
15770           lastPointX = outline[i + 4];
15771           lastPointY = outline[i + 5];
15772         } else if (lastPointY === outline[i + 5]) {
15773           lastPointX = ltrCallback(lastPointX, outline[i + 4]);
15774         }
15775       } else {
15776         const bbox = Util.bezierBoundingBox(lastX, lastY, ...outline.slice(i, i + 6));
15777         minX = Math.min(minX, bbox[0]);
15778         minY = Math.min(minY, bbox[1]);
15779         maxX = Math.max(maxX, bbox[2]);
15780         maxY = Math.max(maxY, bbox[3]);
15781         if (lastPointY < bbox[3]) {
15782           lastPointX = bbox[2];
15783           lastPointY = bbox[3];
15784         } else if (lastPointY === bbox[3]) {
15785           lastPointX = ltrCallback(lastPointX, bbox[2]);
15786         }
15787       }
15788       lastX = outline[i + 4];
15789       lastY = outline[i + 5];
15790     }
15791     const bbox = this.#bbox;
15792     bbox[0] = minX - this.#innerMargin;
15793     bbox[1] = minY - this.#innerMargin;
15794     bbox[2] = maxX - minX + 2 * this.#innerMargin;
15795     bbox[3] = maxY - minY + 2 * this.#innerMargin;
15796     this.lastPoint = [lastPointX, lastPointY];
15797   }
15798   get box() {
15799     return this.#bbox;
15800   }
15801   newOutliner(point, box, scaleFactor, thickness, isLTR, innerMargin = 0) {
15802     return new FreeDrawOutliner(point, box, scaleFactor, thickness, isLTR, innerMargin);
15803   }
15804   getNewOutline(thickness, innerMargin) {
15805     const [x, y, width, height] = this.#bbox;
15806     const [layerX, layerY, layerWidth, layerHeight] = this.#box;
15807     const sx = width * layerWidth;
15808     const sy = height * layerHeight;
15809     const tx = x * layerWidth + layerX;
15810     const ty = y * layerHeight + layerY;
15811     const outliner = this.newOutliner({
15812       x: this.#points[0] * sx + tx,
15813       y: this.#points[1] * sy + ty
15814     }, this.#box, this.#scaleFactor, thickness, this.#isLTR, innerMargin ?? this.#innerMargin);
15815     for (let i = 2; i < this.#points.length; i += 2) {
15816       outliner.add({
15817         x: this.#points[i] * sx + tx,
15818         y: this.#points[i + 1] * sy + ty
15819       });
15820     }
15821     return outliner.getOutlines();
15822   }
15825 ;// ./src/display/editor/drawers/highlight.js
15828 class HighlightOutliner {
15829   #box;
15830   #lastPoint;
15831   #verticalEdges = [];
15832   #intervals = [];
15833   constructor(boxes, borderWidth = 0, innerMargin = 0, isLTR = true) {
15834     let minX = Infinity;
15835     let maxX = -Infinity;
15836     let minY = Infinity;
15837     let maxY = -Infinity;
15838     const NUMBER_OF_DIGITS = 4;
15839     const EPSILON = 10 ** -NUMBER_OF_DIGITS;
15840     for (const {
15841       x,
15842       y,
15843       width,
15844       height
15845     } of boxes) {
15846       const x1 = Math.floor((x - borderWidth) / EPSILON) * EPSILON;
15847       const x2 = Math.ceil((x + width + borderWidth) / EPSILON) * EPSILON;
15848       const y1 = Math.floor((y - borderWidth) / EPSILON) * EPSILON;
15849       const y2 = Math.ceil((y + height + borderWidth) / EPSILON) * EPSILON;
15850       const left = [x1, y1, y2, true];
15851       const right = [x2, y1, y2, false];
15852       this.#verticalEdges.push(left, right);
15853       minX = Math.min(minX, x1);
15854       maxX = Math.max(maxX, x2);
15855       minY = Math.min(minY, y1);
15856       maxY = Math.max(maxY, y2);
15857     }
15858     const bboxWidth = maxX - minX + 2 * innerMargin;
15859     const bboxHeight = maxY - minY + 2 * innerMargin;
15860     const shiftedMinX = minX - innerMargin;
15861     const shiftedMinY = minY - innerMargin;
15862     const lastEdge = this.#verticalEdges.at(isLTR ? -1 : -2);
15863     const lastPoint = [lastEdge[0], lastEdge[2]];
15864     for (const edge of this.#verticalEdges) {
15865       const [x, y1, y2] = edge;
15866       edge[0] = (x - shiftedMinX) / bboxWidth;
15867       edge[1] = (y1 - shiftedMinY) / bboxHeight;
15868       edge[2] = (y2 - shiftedMinY) / bboxHeight;
15869     }
15870     this.#box = new Float32Array([shiftedMinX, shiftedMinY, bboxWidth, bboxHeight]);
15871     this.#lastPoint = lastPoint;
15872   }
15873   getOutlines() {
15874     this.#verticalEdges.sort((a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2]);
15875     const outlineVerticalEdges = [];
15876     for (const edge of this.#verticalEdges) {
15877       if (edge[3]) {
15878         outlineVerticalEdges.push(...this.#breakEdge(edge));
15879         this.#insert(edge);
15880       } else {
15881         this.#remove(edge);
15882         outlineVerticalEdges.push(...this.#breakEdge(edge));
15883       }
15884     }
15885     return this.#getOutlines(outlineVerticalEdges);
15886   }
15887   #getOutlines(outlineVerticalEdges) {
15888     const edges = [];
15889     const allEdges = new Set();
15890     for (const edge of outlineVerticalEdges) {
15891       const [x, y1, y2] = edge;
15892       edges.push([x, y1, edge], [x, y2, edge]);
15893     }
15894     edges.sort((a, b) => a[1] - b[1] || a[0] - b[0]);
15895     for (let i = 0, ii = edges.length; i < ii; i += 2) {
15896       const edge1 = edges[i][2];
15897       const edge2 = edges[i + 1][2];
15898       edge1.push(edge2);
15899       edge2.push(edge1);
15900       allEdges.add(edge1);
15901       allEdges.add(edge2);
15902     }
15903     const outlines = [];
15904     let outline;
15905     while (allEdges.size > 0) {
15906       const edge = allEdges.values().next().value;
15907       let [x, y1, y2, edge1, edge2] = edge;
15908       allEdges.delete(edge);
15909       let lastPointX = x;
15910       let lastPointY = y1;
15911       outline = [x, y2];
15912       outlines.push(outline);
15913       while (true) {
15914         let e;
15915         if (allEdges.has(edge1)) {
15916           e = edge1;
15917         } else if (allEdges.has(edge2)) {
15918           e = edge2;
15919         } else {
15920           break;
15921         }
15922         allEdges.delete(e);
15923         [x, y1, y2, edge1, edge2] = e;
15924         if (lastPointX !== x) {
15925           outline.push(lastPointX, lastPointY, x, lastPointY === y1 ? y1 : y2);
15926           lastPointX = x;
15927         }
15928         lastPointY = lastPointY === y1 ? y2 : y1;
15929       }
15930       outline.push(lastPointX, lastPointY);
15931     }
15932     return new HighlightOutline(outlines, this.#box, this.#lastPoint);
15933   }
15934   #binarySearch(y) {
15935     const array = this.#intervals;
15936     let start = 0;
15937     let end = array.length - 1;
15938     while (start <= end) {
15939       const middle = start + end >> 1;
15940       const y1 = array[middle][0];
15941       if (y1 === y) {
15942         return middle;
15943       }
15944       if (y1 < y) {
15945         start = middle + 1;
15946       } else {
15947         end = middle - 1;
15948       }
15949     }
15950     return end + 1;
15951   }
15952   #insert([, y1, y2]) {
15953     const index = this.#binarySearch(y1);
15954     this.#intervals.splice(index, 0, [y1, y2]);
15955   }
15956   #remove([, y1, y2]) {
15957     const index = this.#binarySearch(y1);
15958     for (let i = index; i < this.#intervals.length; i++) {
15959       const [start, end] = this.#intervals[i];
15960       if (start !== y1) {
15961         break;
15962       }
15963       if (start === y1 && end === y2) {
15964         this.#intervals.splice(i, 1);
15965         return;
15966       }
15967     }
15968     for (let i = index - 1; i >= 0; i--) {
15969       const [start, end] = this.#intervals[i];
15970       if (start !== y1) {
15971         break;
15972       }
15973       if (start === y1 && end === y2) {
15974         this.#intervals.splice(i, 1);
15975         return;
15976       }
15977     }
15978   }
15979   #breakEdge(edge) {
15980     const [x, y1, y2] = edge;
15981     const results = [[x, y1, y2]];
15982     const index = this.#binarySearch(y2);
15983     for (let i = 0; i < index; i++) {
15984       const [start, end] = this.#intervals[i];
15985       for (let j = 0, jj = results.length; j < jj; j++) {
15986         const [, y3, y4] = results[j];
15987         if (end <= y3 || y4 <= start) {
15988           continue;
15989         }
15990         if (y3 >= start) {
15991           if (y4 > end) {
15992             results[j][1] = end;
15993           } else {
15994             if (jj === 1) {
15995               return [];
15996             }
15997             results.splice(j, 1);
15998             j--;
15999             jj--;
16000           }
16001           continue;
16002         }
16003         results[j][2] = start;
16004         if (y4 > end) {
16005           results.push([x, end, y4]);
16006         }
16007       }
16008     }
16009     return results;
16010   }
16012 class HighlightOutline extends Outline {
16013   #box;
16014   #outlines;
16015   constructor(outlines, box, lastPoint) {
16016     super();
16017     this.#outlines = outlines;
16018     this.#box = box;
16019     this.lastPoint = lastPoint;
16020   }
16021   toSVGPath() {
16022     const buffer = [];
16023     for (const polygon of this.#outlines) {
16024       let [prevX, prevY] = polygon;
16025       buffer.push(`M${prevX} ${prevY}`);
16026       for (let i = 2; i < polygon.length; i += 2) {
16027         const x = polygon[i];
16028         const y = polygon[i + 1];
16029         if (x === prevX) {
16030           buffer.push(`V${y}`);
16031           prevY = y;
16032         } else if (y === prevY) {
16033           buffer.push(`H${x}`);
16034           prevX = x;
16035         }
16036       }
16037       buffer.push("Z");
16038     }
16039     return buffer.join(" ");
16040   }
16041   serialize([blX, blY, trX, trY], _rotation) {
16042     const outlines = [];
16043     const width = trX - blX;
16044     const height = trY - blY;
16045     for (const outline of this.#outlines) {
16046       const points = new Array(outline.length);
16047       for (let i = 0; i < outline.length; i += 2) {
16048         points[i] = blX + outline[i] * width;
16049         points[i + 1] = trY - outline[i + 1] * height;
16050       }
16051       outlines.push(points);
16052     }
16053     return outlines;
16054   }
16055   get box() {
16056     return this.#box;
16057   }
16058   get classNamesForOutlining() {
16059     return ["highlightOutline"];
16060   }
16062 class FreeHighlightOutliner extends FreeDrawOutliner {
16063   newFreeDrawOutline(outline, points, box, scaleFactor, innerMargin, isLTR) {
16064     return new FreeHighlightOutline(outline, points, box, scaleFactor, innerMargin, isLTR);
16065   }
16067 class FreeHighlightOutline extends FreeDrawOutline {
16068   newOutliner(point, box, scaleFactor, thickness, isLTR, innerMargin = 0) {
16069     return new FreeHighlightOutliner(point, box, scaleFactor, thickness, isLTR, innerMargin);
16070   }
16073 ;// ./src/display/editor/color_picker.js
16077 class ColorPicker {
16078   #button = null;
16079   #buttonSwatch = null;
16080   #defaultColor;
16081   #dropdown = null;
16082   #dropdownWasFromKeyboard = false;
16083   #isMainColorPicker = false;
16084   #editor = null;
16085   #eventBus;
16086   #openDropdownAC = null;
16087   #uiManager = null;
16088   #type;
16089   static #l10nColor = null;
16090   static get _keyboardManager() {
16091     return shadow(this, "_keyboardManager", new KeyboardManager([[["Escape", "mac+Escape"], ColorPicker.prototype._hideDropdownFromKeyboard], [[" ", "mac+ "], ColorPicker.prototype._colorSelectFromKeyboard], [["ArrowDown", "ArrowRight", "mac+ArrowDown", "mac+ArrowRight"], ColorPicker.prototype._moveToNext], [["ArrowUp", "ArrowLeft", "mac+ArrowUp", "mac+ArrowLeft"], ColorPicker.prototype._moveToPrevious], [["Home", "mac+Home"], ColorPicker.prototype._moveToBeginning], [["End", "mac+End"], ColorPicker.prototype._moveToEnd]]));
16092   }
16093   constructor({
16094     editor = null,
16095     uiManager = null
16096   }) {
16097     if (editor) {
16098       this.#isMainColorPicker = false;
16099       this.#type = AnnotationEditorParamsType.HIGHLIGHT_COLOR;
16100       this.#editor = editor;
16101     } else {
16102       this.#isMainColorPicker = true;
16103       this.#type = AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR;
16104     }
16105     this.#uiManager = editor?._uiManager || uiManager;
16106     this.#eventBus = this.#uiManager._eventBus;
16107     this.#defaultColor = editor?.color || this.#uiManager?.highlightColors.values().next().value || "#FFFF98";
16108     ColorPicker.#l10nColor ||= Object.freeze({
16109       blue: "pdfjs-editor-colorpicker-blue",
16110       green: "pdfjs-editor-colorpicker-green",
16111       pink: "pdfjs-editor-colorpicker-pink",
16112       red: "pdfjs-editor-colorpicker-red",
16113       yellow: "pdfjs-editor-colorpicker-yellow"
16114     });
16115   }
16116   renderButton() {
16117     const button = this.#button = document.createElement("button");
16118     button.className = "colorPicker";
16119     button.tabIndex = "0";
16120     button.setAttribute("data-l10n-id", "pdfjs-editor-colorpicker-button");
16121     button.setAttribute("aria-haspopup", true);
16122     const signal = this.#uiManager._signal;
16123     button.addEventListener("click", this.#openDropdown.bind(this), {
16124       signal
16125     });
16126     button.addEventListener("keydown", this.#keyDown.bind(this), {
16127       signal
16128     });
16129     const swatch = this.#buttonSwatch = document.createElement("span");
16130     swatch.className = "swatch";
16131     swatch.setAttribute("aria-hidden", true);
16132     swatch.style.backgroundColor = this.#defaultColor;
16133     button.append(swatch);
16134     return button;
16135   }
16136   renderMainDropdown() {
16137     const dropdown = this.#dropdown = this.#getDropdownRoot();
16138     dropdown.setAttribute("aria-orientation", "horizontal");
16139     dropdown.setAttribute("aria-labelledby", "highlightColorPickerLabel");
16140     return dropdown;
16141   }
16142   #getDropdownRoot() {
16143     const div = document.createElement("div");
16144     const signal = this.#uiManager._signal;
16145     div.addEventListener("contextmenu", noContextMenu, {
16146       signal
16147     });
16148     div.className = "dropdown";
16149     div.role = "listbox";
16150     div.setAttribute("aria-multiselectable", false);
16151     div.setAttribute("aria-orientation", "vertical");
16152     div.setAttribute("data-l10n-id", "pdfjs-editor-colorpicker-dropdown");
16153     for (const [name, color] of this.#uiManager.highlightColors) {
16154       const button = document.createElement("button");
16155       button.tabIndex = "0";
16156       button.role = "option";
16157       button.setAttribute("data-color", color);
16158       button.title = name;
16159       button.setAttribute("data-l10n-id", ColorPicker.#l10nColor[name]);
16160       const swatch = document.createElement("span");
16161       button.append(swatch);
16162       swatch.className = "swatch";
16163       swatch.style.backgroundColor = color;
16164       button.setAttribute("aria-selected", color === this.#defaultColor);
16165       button.addEventListener("click", this.#colorSelect.bind(this, color), {
16166         signal
16167       });
16168       div.append(button);
16169     }
16170     div.addEventListener("keydown", this.#keyDown.bind(this), {
16171       signal
16172     });
16173     return div;
16174   }
16175   #colorSelect(color, event) {
16176     event.stopPropagation();
16177     this.#eventBus.dispatch("switchannotationeditorparams", {
16178       source: this,
16179       type: this.#type,
16180       value: color
16181     });
16182   }
16183   _colorSelectFromKeyboard(event) {
16184     if (event.target === this.#button) {
16185       this.#openDropdown(event);
16186       return;
16187     }
16188     const color = event.target.getAttribute("data-color");
16189     if (!color) {
16190       return;
16191     }
16192     this.#colorSelect(color, event);
16193   }
16194   _moveToNext(event) {
16195     if (!this.#isDropdownVisible) {
16196       this.#openDropdown(event);
16197       return;
16198     }
16199     if (event.target === this.#button) {
16200       this.#dropdown.firstChild?.focus();
16201       return;
16202     }
16203     event.target.nextSibling?.focus();
16204   }
16205   _moveToPrevious(event) {
16206     if (event.target === this.#dropdown?.firstChild || event.target === this.#button) {
16207       if (this.#isDropdownVisible) {
16208         this._hideDropdownFromKeyboard();
16209       }
16210       return;
16211     }
16212     if (!this.#isDropdownVisible) {
16213       this.#openDropdown(event);
16214     }
16215     event.target.previousSibling?.focus();
16216   }
16217   _moveToBeginning(event) {
16218     if (!this.#isDropdownVisible) {
16219       this.#openDropdown(event);
16220       return;
16221     }
16222     this.#dropdown.firstChild?.focus();
16223   }
16224   _moveToEnd(event) {
16225     if (!this.#isDropdownVisible) {
16226       this.#openDropdown(event);
16227       return;
16228     }
16229     this.#dropdown.lastChild?.focus();
16230   }
16231   #keyDown(event) {
16232     ColorPicker._keyboardManager.exec(this, event);
16233   }
16234   #openDropdown(event) {
16235     if (this.#isDropdownVisible) {
16236       this.hideDropdown();
16237       return;
16238     }
16239     this.#dropdownWasFromKeyboard = event.detail === 0;
16240     if (!this.#openDropdownAC) {
16241       this.#openDropdownAC = new AbortController();
16242       window.addEventListener("pointerdown", this.#pointerDown.bind(this), {
16243         signal: this.#uiManager.combinedSignal(this.#openDropdownAC)
16244       });
16245     }
16246     if (this.#dropdown) {
16247       this.#dropdown.classList.remove("hidden");
16248       return;
16249     }
16250     const root = this.#dropdown = this.#getDropdownRoot();
16251     this.#button.append(root);
16252   }
16253   #pointerDown(event) {
16254     if (this.#dropdown?.contains(event.target)) {
16255       return;
16256     }
16257     this.hideDropdown();
16258   }
16259   hideDropdown() {
16260     this.#dropdown?.classList.add("hidden");
16261     this.#openDropdownAC?.abort();
16262     this.#openDropdownAC = null;
16263   }
16264   get #isDropdownVisible() {
16265     return this.#dropdown && !this.#dropdown.classList.contains("hidden");
16266   }
16267   _hideDropdownFromKeyboard() {
16268     if (this.#isMainColorPicker) {
16269       return;
16270     }
16271     if (!this.#isDropdownVisible) {
16272       this.#editor?.unselect();
16273       return;
16274     }
16275     this.hideDropdown();
16276     this.#button.focus({
16277       preventScroll: true,
16278       focusVisible: this.#dropdownWasFromKeyboard
16279     });
16280   }
16281   updateColor(color) {
16282     if (this.#buttonSwatch) {
16283       this.#buttonSwatch.style.backgroundColor = color;
16284     }
16285     if (!this.#dropdown) {
16286       return;
16287     }
16288     const i = this.#uiManager.highlightColors.values();
16289     for (const child of this.#dropdown.children) {
16290       child.setAttribute("aria-selected", i.next().value === color);
16291     }
16292   }
16293   destroy() {
16294     this.#button?.remove();
16295     this.#button = null;
16296     this.#buttonSwatch = null;
16297     this.#dropdown?.remove();
16298     this.#dropdown = null;
16299   }
16302 ;// ./src/display/editor/highlight.js
16310 class HighlightEditor extends AnnotationEditor {
16311   #anchorNode = null;
16312   #anchorOffset = 0;
16313   #boxes;
16314   #clipPathId = null;
16315   #colorPicker = null;
16316   #focusOutlines = null;
16317   #focusNode = null;
16318   #focusOffset = 0;
16319   #highlightDiv = null;
16320   #highlightOutlines = null;
16321   #id = null;
16322   #isFreeHighlight = false;
16323   #lastPoint = null;
16324   #opacity;
16325   #outlineId = null;
16326   #text = "";
16327   #thickness;
16328   #methodOfCreation = "";
16329   static _defaultColor = null;
16330   static _defaultOpacity = 1;
16331   static _defaultThickness = 12;
16332   static _type = "highlight";
16333   static _editorType = AnnotationEditorType.HIGHLIGHT;
16334   static _freeHighlightId = -1;
16335   static _freeHighlight = null;
16336   static _freeHighlightClipId = "";
16337   static get _keyboardManager() {
16338     const proto = HighlightEditor.prototype;
16339     return shadow(this, "_keyboardManager", new KeyboardManager([[["ArrowLeft", "mac+ArrowLeft"], proto._moveCaret, {
16340       args: [0]
16341     }], [["ArrowRight", "mac+ArrowRight"], proto._moveCaret, {
16342       args: [1]
16343     }], [["ArrowUp", "mac+ArrowUp"], proto._moveCaret, {
16344       args: [2]
16345     }], [["ArrowDown", "mac+ArrowDown"], proto._moveCaret, {
16346       args: [3]
16347     }]]));
16348   }
16349   constructor(params) {
16350     super({
16351       ...params,
16352       name: "highlightEditor"
16353     });
16354     this.color = params.color || HighlightEditor._defaultColor;
16355     this.#thickness = params.thickness || HighlightEditor._defaultThickness;
16356     this.#opacity = params.opacity || HighlightEditor._defaultOpacity;
16357     this.#boxes = params.boxes || null;
16358     this.#methodOfCreation = params.methodOfCreation || "";
16359     this.#text = params.text || "";
16360     this._isDraggable = false;
16361     if (params.highlightId > -1) {
16362       this.#isFreeHighlight = true;
16363       this.#createFreeOutlines(params);
16364       this.#addToDrawLayer();
16365     } else if (this.#boxes) {
16366       this.#anchorNode = params.anchorNode;
16367       this.#anchorOffset = params.anchorOffset;
16368       this.#focusNode = params.focusNode;
16369       this.#focusOffset = params.focusOffset;
16370       this.#createOutlines();
16371       this.#addToDrawLayer();
16372       this.rotate(this.rotation);
16373     }
16374   }
16375   get telemetryInitialData() {
16376     return {
16377       action: "added",
16378       type: this.#isFreeHighlight ? "free_highlight" : "highlight",
16379       color: this._uiManager.highlightColorNames.get(this.color),
16380       thickness: this.#thickness,
16381       methodOfCreation: this.#methodOfCreation
16382     };
16383   }
16384   get telemetryFinalData() {
16385     return {
16386       type: "highlight",
16387       color: this._uiManager.highlightColorNames.get(this.color)
16388     };
16389   }
16390   static computeTelemetryFinalData(data) {
16391     return {
16392       numberOfColors: data.get("color").size
16393     };
16394   }
16395   #createOutlines() {
16396     const outliner = new HighlightOutliner(this.#boxes, 0.001);
16397     this.#highlightOutlines = outliner.getOutlines();
16398     [this.x, this.y, this.width, this.height] = this.#highlightOutlines.box;
16399     const outlinerForOutline = new HighlightOutliner(this.#boxes, 0.0025, 0.001, this._uiManager.direction === "ltr");
16400     this.#focusOutlines = outlinerForOutline.getOutlines();
16401     const {
16402       lastPoint
16403     } = this.#focusOutlines;
16404     this.#lastPoint = [(lastPoint[0] - this.x) / this.width, (lastPoint[1] - this.y) / this.height];
16405   }
16406   #createFreeOutlines({
16407     highlightOutlines,
16408     highlightId,
16409     clipPathId
16410   }) {
16411     this.#highlightOutlines = highlightOutlines;
16412     const extraThickness = 1.5;
16413     this.#focusOutlines = highlightOutlines.getNewOutline(this.#thickness / 2 + extraThickness, 0.0025);
16414     if (highlightId >= 0) {
16415       this.#id = highlightId;
16416       this.#clipPathId = clipPathId;
16417       this.parent.drawLayer.finalizeDraw(highlightId, {
16418         bbox: highlightOutlines.box,
16419         path: {
16420           d: highlightOutlines.toSVGPath()
16421         }
16422       });
16423       this.#outlineId = this.parent.drawLayer.drawOutline({
16424         rootClass: {
16425           highlightOutline: true,
16426           free: true
16427         },
16428         bbox: this.#focusOutlines.box,
16429         path: {
16430           d: this.#focusOutlines.toSVGPath()
16431         }
16432       }, true);
16433     } else if (this.parent) {
16434       const angle = this.parent.viewport.rotation;
16435       this.parent.drawLayer.updateProperties(this.#id, {
16436         bbox: HighlightEditor.#rotateBbox(this.#highlightOutlines.box, (angle - this.rotation + 360) % 360),
16437         path: {
16438           d: highlightOutlines.toSVGPath()
16439         }
16440       });
16441       this.parent.drawLayer.updateProperties(this.#outlineId, {
16442         bbox: HighlightEditor.#rotateBbox(this.#focusOutlines.box, angle),
16443         path: {
16444           d: this.#focusOutlines.toSVGPath()
16445         }
16446       });
16447     }
16448     const [x, y, width, height] = highlightOutlines.box;
16449     switch (this.rotation) {
16450       case 0:
16451         this.x = x;
16452         this.y = y;
16453         this.width = width;
16454         this.height = height;
16455         break;
16456       case 90:
16457         {
16458           const [pageWidth, pageHeight] = this.parentDimensions;
16459           this.x = y;
16460           this.y = 1 - x;
16461           this.width = width * pageHeight / pageWidth;
16462           this.height = height * pageWidth / pageHeight;
16463           break;
16464         }
16465       case 180:
16466         this.x = 1 - x;
16467         this.y = 1 - y;
16468         this.width = width;
16469         this.height = height;
16470         break;
16471       case 270:
16472         {
16473           const [pageWidth, pageHeight] = this.parentDimensions;
16474           this.x = 1 - y;
16475           this.y = x;
16476           this.width = width * pageHeight / pageWidth;
16477           this.height = height * pageWidth / pageHeight;
16478           break;
16479         }
16480     }
16481     const {
16482       lastPoint
16483     } = this.#focusOutlines;
16484     this.#lastPoint = [(lastPoint[0] - x) / width, (lastPoint[1] - y) / height];
16485   }
16486   static initialize(l10n, uiManager) {
16487     AnnotationEditor.initialize(l10n, uiManager);
16488     HighlightEditor._defaultColor ||= uiManager.highlightColors?.values().next().value || "#fff066";
16489   }
16490   static updateDefaultParams(type, value) {
16491     switch (type) {
16492       case AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR:
16493         HighlightEditor._defaultColor = value;
16494         break;
16495       case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS:
16496         HighlightEditor._defaultThickness = value;
16497         break;
16498     }
16499   }
16500   translateInPage(x, y) {}
16501   get toolbarPosition() {
16502     return this.#lastPoint;
16503   }
16504   updateParams(type, value) {
16505     switch (type) {
16506       case AnnotationEditorParamsType.HIGHLIGHT_COLOR:
16507         this.#updateColor(value);
16508         break;
16509       case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS:
16510         this.#updateThickness(value);
16511         break;
16512     }
16513   }
16514   static get defaultPropertiesToUpdate() {
16515     return [[AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR, HighlightEditor._defaultColor], [AnnotationEditorParamsType.HIGHLIGHT_THICKNESS, HighlightEditor._defaultThickness]];
16516   }
16517   get propertiesToUpdate() {
16518     return [[AnnotationEditorParamsType.HIGHLIGHT_COLOR, this.color || HighlightEditor._defaultColor], [AnnotationEditorParamsType.HIGHLIGHT_THICKNESS, this.#thickness || HighlightEditor._defaultThickness], [AnnotationEditorParamsType.HIGHLIGHT_FREE, this.#isFreeHighlight]];
16519   }
16520   #updateColor(color) {
16521     const setColorAndOpacity = (col, opa) => {
16522       this.color = col;
16523       this.#opacity = opa;
16524       this.parent?.drawLayer.updateProperties(this.#id, {
16525         root: {
16526           fill: col,
16527           "fill-opacity": opa
16528         }
16529       });
16530       this.#colorPicker?.updateColor(col);
16531     };
16532     const savedColor = this.color;
16533     const savedOpacity = this.#opacity;
16534     this.addCommands({
16535       cmd: setColorAndOpacity.bind(this, color, HighlightEditor._defaultOpacity),
16536       undo: setColorAndOpacity.bind(this, savedColor, savedOpacity),
16537       post: this._uiManager.updateUI.bind(this._uiManager, this),
16538       mustExec: true,
16539       type: AnnotationEditorParamsType.HIGHLIGHT_COLOR,
16540       overwriteIfSameType: true,
16541       keepUndo: true
16542     });
16543     this._reportTelemetry({
16544       action: "color_changed",
16545       color: this._uiManager.highlightColorNames.get(color)
16546     }, true);
16547   }
16548   #updateThickness(thickness) {
16549     const savedThickness = this.#thickness;
16550     const setThickness = th => {
16551       this.#thickness = th;
16552       this.#changeThickness(th);
16553     };
16554     this.addCommands({
16555       cmd: setThickness.bind(this, thickness),
16556       undo: setThickness.bind(this, savedThickness),
16557       post: this._uiManager.updateUI.bind(this._uiManager, this),
16558       mustExec: true,
16559       type: AnnotationEditorParamsType.INK_THICKNESS,
16560       overwriteIfSameType: true,
16561       keepUndo: true
16562     });
16563     this._reportTelemetry({
16564       action: "thickness_changed",
16565       thickness
16566     }, true);
16567   }
16568   async addEditToolbar() {
16569     const toolbar = await super.addEditToolbar();
16570     if (!toolbar) {
16571       return null;
16572     }
16573     if (this._uiManager.highlightColors) {
16574       this.#colorPicker = new ColorPicker({
16575         editor: this
16576       });
16577       toolbar.addColorPicker(this.#colorPicker);
16578     }
16579     return toolbar;
16580   }
16581   disableEditing() {
16582     super.disableEditing();
16583     this.div.classList.toggle("disabled", true);
16584   }
16585   enableEditing() {
16586     super.enableEditing();
16587     this.div.classList.toggle("disabled", false);
16588   }
16589   fixAndSetPosition() {
16590     return super.fixAndSetPosition(this.#getRotation());
16591   }
16592   getBaseTranslation() {
16593     return [0, 0];
16594   }
16595   getRect(tx, ty) {
16596     return super.getRect(tx, ty, this.#getRotation());
16597   }
16598   onceAdded(focus) {
16599     if (!this.annotationElementId) {
16600       this.parent.addUndoableEditor(this);
16601     }
16602     if (focus) {
16603       this.div.focus();
16604     }
16605   }
16606   remove() {
16607     this.#cleanDrawLayer();
16608     this._reportTelemetry({
16609       action: "deleted"
16610     });
16611     super.remove();
16612   }
16613   rebuild() {
16614     if (!this.parent) {
16615       return;
16616     }
16617     super.rebuild();
16618     if (this.div === null) {
16619       return;
16620     }
16621     this.#addToDrawLayer();
16622     if (!this.isAttachedToDOM) {
16623       this.parent.add(this);
16624     }
16625   }
16626   setParent(parent) {
16627     let mustBeSelected = false;
16628     if (this.parent && !parent) {
16629       this.#cleanDrawLayer();
16630     } else if (parent) {
16631       this.#addToDrawLayer(parent);
16632       mustBeSelected = !this.parent && this.div?.classList.contains("selectedEditor");
16633     }
16634     super.setParent(parent);
16635     this.show(this._isVisible);
16636     if (mustBeSelected) {
16637       this.select();
16638     }
16639   }
16640   #changeThickness(thickness) {
16641     if (!this.#isFreeHighlight) {
16642       return;
16643     }
16644     this.#createFreeOutlines({
16645       highlightOutlines: this.#highlightOutlines.getNewOutline(thickness / 2)
16646     });
16647     this.fixAndSetPosition();
16648     const [parentWidth, parentHeight] = this.parentDimensions;
16649     this.setDims(this.width * parentWidth, this.height * parentHeight);
16650   }
16651   #cleanDrawLayer() {
16652     if (this.#id === null || !this.parent) {
16653       return;
16654     }
16655     this.parent.drawLayer.remove(this.#id);
16656     this.#id = null;
16657     this.parent.drawLayer.remove(this.#outlineId);
16658     this.#outlineId = null;
16659   }
16660   #addToDrawLayer(parent = this.parent) {
16661     if (this.#id !== null) {
16662       return;
16663     }
16664     ({
16665       id: this.#id,
16666       clipPathId: this.#clipPathId
16667     } = parent.drawLayer.draw({
16668       bbox: this.#highlightOutlines.box,
16669       root: {
16670         viewBox: "0 0 1 1",
16671         fill: this.color,
16672         "fill-opacity": this.#opacity
16673       },
16674       rootClass: {
16675         highlight: true,
16676         free: this.#isFreeHighlight
16677       },
16678       path: {
16679         d: this.#highlightOutlines.toSVGPath()
16680       }
16681     }, false, true));
16682     this.#outlineId = parent.drawLayer.drawOutline({
16683       rootClass: {
16684         highlightOutline: true,
16685         free: this.#isFreeHighlight
16686       },
16687       bbox: this.#focusOutlines.box,
16688       path: {
16689         d: this.#focusOutlines.toSVGPath()
16690       }
16691     }, this.#isFreeHighlight);
16692     if (this.#highlightDiv) {
16693       this.#highlightDiv.style.clipPath = this.#clipPathId;
16694     }
16695   }
16696   static #rotateBbox([x, y, width, height], angle) {
16697     switch (angle) {
16698       case 90:
16699         return [1 - y - height, x, height, width];
16700       case 180:
16701         return [1 - x - width, 1 - y - height, width, height];
16702       case 270:
16703         return [y, 1 - x - width, height, width];
16704     }
16705     return [x, y, width, height];
16706   }
16707   rotate(angle) {
16708     const {
16709       drawLayer
16710     } = this.parent;
16711     let box;
16712     if (this.#isFreeHighlight) {
16713       angle = (angle - this.rotation + 360) % 360;
16714       box = HighlightEditor.#rotateBbox(this.#highlightOutlines.box, angle);
16715     } else {
16716       box = HighlightEditor.#rotateBbox([this.x, this.y, this.width, this.height], angle);
16717     }
16718     drawLayer.updateProperties(this.#id, {
16719       bbox: box,
16720       root: {
16721         "data-main-rotation": angle
16722       }
16723     });
16724     drawLayer.updateProperties(this.#outlineId, {
16725       bbox: HighlightEditor.#rotateBbox(this.#focusOutlines.box, angle),
16726       root: {
16727         "data-main-rotation": angle
16728       }
16729     });
16730   }
16731   render() {
16732     if (this.div) {
16733       return this.div;
16734     }
16735     const div = super.render();
16736     if (this.#text) {
16737       div.setAttribute("aria-label", this.#text);
16738       div.setAttribute("role", "mark");
16739     }
16740     if (this.#isFreeHighlight) {
16741       div.classList.add("free");
16742     } else {
16743       this.div.addEventListener("keydown", this.#keydown.bind(this), {
16744         signal: this._uiManager._signal
16745       });
16746     }
16747     const highlightDiv = this.#highlightDiv = document.createElement("div");
16748     div.append(highlightDiv);
16749     highlightDiv.setAttribute("aria-hidden", "true");
16750     highlightDiv.className = "internal";
16751     highlightDiv.style.clipPath = this.#clipPathId;
16752     const [parentWidth, parentHeight] = this.parentDimensions;
16753     this.setDims(this.width * parentWidth, this.height * parentHeight);
16754     bindEvents(this, this.#highlightDiv, ["pointerover", "pointerleave"]);
16755     this.enableEditing();
16756     return div;
16757   }
16758   pointerover() {
16759     if (!this.isSelected) {
16760       this.parent?.drawLayer.updateProperties(this.#outlineId, {
16761         rootClass: {
16762           hovered: true
16763         }
16764       });
16765     }
16766   }
16767   pointerleave() {
16768     if (!this.isSelected) {
16769       this.parent?.drawLayer.updateProperties(this.#outlineId, {
16770         rootClass: {
16771           hovered: false
16772         }
16773       });
16774     }
16775   }
16776   #keydown(event) {
16777     HighlightEditor._keyboardManager.exec(this, event);
16778   }
16779   _moveCaret(direction) {
16780     this.parent.unselect(this);
16781     switch (direction) {
16782       case 0:
16783       case 2:
16784         this.#setCaret(true);
16785         break;
16786       case 1:
16787       case 3:
16788         this.#setCaret(false);
16789         break;
16790     }
16791   }
16792   #setCaret(start) {
16793     if (!this.#anchorNode) {
16794       return;
16795     }
16796     const selection = window.getSelection();
16797     if (start) {
16798       selection.setPosition(this.#anchorNode, this.#anchorOffset);
16799     } else {
16800       selection.setPosition(this.#focusNode, this.#focusOffset);
16801     }
16802   }
16803   select() {
16804     super.select();
16805     if (!this.#outlineId) {
16806       return;
16807     }
16808     this.parent?.drawLayer.updateProperties(this.#outlineId, {
16809       rootClass: {
16810         hovered: false,
16811         selected: true
16812       }
16813     });
16814   }
16815   unselect() {
16816     super.unselect();
16817     if (!this.#outlineId) {
16818       return;
16819     }
16820     this.parent?.drawLayer.updateProperties(this.#outlineId, {
16821       rootClass: {
16822         selected: false
16823       }
16824     });
16825     if (!this.#isFreeHighlight) {
16826       this.#setCaret(false);
16827     }
16828   }
16829   get _mustFixPosition() {
16830     return !this.#isFreeHighlight;
16831   }
16832   show(visible = this._isVisible) {
16833     super.show(visible);
16834     if (this.parent) {
16835       this.parent.drawLayer.updateProperties(this.#id, {
16836         rootClass: {
16837           hidden: !visible
16838         }
16839       });
16840       this.parent.drawLayer.updateProperties(this.#outlineId, {
16841         rootClass: {
16842           hidden: !visible
16843         }
16844       });
16845     }
16846   }
16847   #getRotation() {
16848     return this.#isFreeHighlight ? this.rotation : 0;
16849   }
16850   #serializeBoxes() {
16851     if (this.#isFreeHighlight) {
16852       return null;
16853     }
16854     const [pageWidth, pageHeight] = this.pageDimensions;
16855     const [pageX, pageY] = this.pageTranslation;
16856     const boxes = this.#boxes;
16857     const quadPoints = new Float32Array(boxes.length * 8);
16858     let i = 0;
16859     for (const {
16860       x,
16861       y,
16862       width,
16863       height
16864     } of boxes) {
16865       const sx = x * pageWidth + pageX;
16866       const sy = (1 - y) * pageHeight + pageY;
16867       quadPoints[i] = quadPoints[i + 4] = sx;
16868       quadPoints[i + 1] = quadPoints[i + 3] = sy;
16869       quadPoints[i + 2] = quadPoints[i + 6] = sx + width * pageWidth;
16870       quadPoints[i + 5] = quadPoints[i + 7] = sy - height * pageHeight;
16871       i += 8;
16872     }
16873     return quadPoints;
16874   }
16875   #serializeOutlines(rect) {
16876     return this.#highlightOutlines.serialize(rect, this.#getRotation());
16877   }
16878   static startHighlighting(parent, isLTR, {
16879     target: textLayer,
16880     x,
16881     y
16882   }) {
16883     const {
16884       x: layerX,
16885       y: layerY,
16886       width: parentWidth,
16887       height: parentHeight
16888     } = textLayer.getBoundingClientRect();
16889     const ac = new AbortController();
16890     const signal = parent.combinedSignal(ac);
16891     const pointerUpCallback = e => {
16892       ac.abort();
16893       this.#endHighlight(parent, e);
16894     };
16895     window.addEventListener("blur", pointerUpCallback, {
16896       signal
16897     });
16898     window.addEventListener("pointerup", pointerUpCallback, {
16899       signal
16900     });
16901     window.addEventListener("pointerdown", stopEvent, {
16902       capture: true,
16903       passive: false,
16904       signal
16905     });
16906     window.addEventListener("contextmenu", noContextMenu, {
16907       signal
16908     });
16909     textLayer.addEventListener("pointermove", this.#highlightMove.bind(this, parent), {
16910       signal
16911     });
16912     this._freeHighlight = new FreeHighlightOutliner({
16913       x,
16914       y
16915     }, [layerX, layerY, parentWidth, parentHeight], parent.scale, this._defaultThickness / 2, isLTR, 0.001);
16916     ({
16917       id: this._freeHighlightId,
16918       clipPathId: this._freeHighlightClipId
16919     } = parent.drawLayer.draw({
16920       bbox: [0, 0, 1, 1],
16921       root: {
16922         viewBox: "0 0 1 1",
16923         fill: this._defaultColor,
16924         "fill-opacity": this._defaultOpacity
16925       },
16926       rootClass: {
16927         highlight: true,
16928         free: true
16929       },
16930       path: {
16931         d: this._freeHighlight.toSVGPath()
16932       }
16933     }, true, true));
16934   }
16935   static #highlightMove(parent, event) {
16936     if (this._freeHighlight.add(event)) {
16937       parent.drawLayer.updateProperties(this._freeHighlightId, {
16938         path: {
16939           d: this._freeHighlight.toSVGPath()
16940         }
16941       });
16942     }
16943   }
16944   static #endHighlight(parent, event) {
16945     if (!this._freeHighlight.isEmpty()) {
16946       parent.createAndAddNewEditor(event, false, {
16947         highlightId: this._freeHighlightId,
16948         highlightOutlines: this._freeHighlight.getOutlines(),
16949         clipPathId: this._freeHighlightClipId,
16950         methodOfCreation: "main_toolbar"
16951       });
16952     } else {
16953       parent.drawLayer.remove(this._freeHighlightId);
16954     }
16955     this._freeHighlightId = -1;
16956     this._freeHighlight = null;
16957     this._freeHighlightClipId = "";
16958   }
16959   static async deserialize(data, parent, uiManager) {
16960     let initialData = null;
16961     if (data instanceof HighlightAnnotationElement) {
16962       const {
16963         data: {
16964           quadPoints,
16965           rect,
16966           rotation,
16967           id,
16968           color,
16969           opacity,
16970           popupRef
16971         },
16972         parent: {
16973           page: {
16974             pageNumber
16975           }
16976         }
16977       } = data;
16978       initialData = data = {
16979         annotationType: AnnotationEditorType.HIGHLIGHT,
16980         color: Array.from(color),
16981         opacity,
16982         quadPoints,
16983         boxes: null,
16984         pageIndex: pageNumber - 1,
16985         rect: rect.slice(0),
16986         rotation,
16987         id,
16988         deleted: false,
16989         popupRef
16990       };
16991     } else if (data instanceof InkAnnotationElement) {
16992       const {
16993         data: {
16994           inkLists,
16995           rect,
16996           rotation,
16997           id,
16998           color,
16999           borderStyle: {
17000             rawWidth: thickness
17001           },
17002           popupRef
17003         },
17004         parent: {
17005           page: {
17006             pageNumber
17007           }
17008         }
17009       } = data;
17010       initialData = data = {
17011         annotationType: AnnotationEditorType.HIGHLIGHT,
17012         color: Array.from(color),
17013         thickness,
17014         inkLists,
17015         boxes: null,
17016         pageIndex: pageNumber - 1,
17017         rect: rect.slice(0),
17018         rotation,
17019         id,
17020         deleted: false,
17021         popupRef
17022       };
17023     }
17024     const {
17025       color,
17026       quadPoints,
17027       inkLists,
17028       opacity
17029     } = data;
17030     const editor = await super.deserialize(data, parent, uiManager);
17031     editor.color = Util.makeHexColor(...color);
17032     editor.#opacity = opacity || 1;
17033     if (inkLists) {
17034       editor.#thickness = data.thickness;
17035     }
17036     editor.annotationElementId = data.id || null;
17037     editor._initialData = initialData;
17038     const [pageWidth, pageHeight] = editor.pageDimensions;
17039     const [pageX, pageY] = editor.pageTranslation;
17040     if (quadPoints) {
17041       const boxes = editor.#boxes = [];
17042       for (let i = 0; i < quadPoints.length; i += 8) {
17043         boxes.push({
17044           x: (quadPoints[i] - pageX) / pageWidth,
17045           y: 1 - (quadPoints[i + 1] - pageY) / pageHeight,
17046           width: (quadPoints[i + 2] - quadPoints[i]) / pageWidth,
17047           height: (quadPoints[i + 1] - quadPoints[i + 5]) / pageHeight
17048         });
17049       }
17050       editor.#createOutlines();
17051       editor.#addToDrawLayer();
17052       editor.rotate(editor.rotation);
17053     } else if (inkLists) {
17054       editor.#isFreeHighlight = true;
17055       const points = inkLists[0];
17056       const point = {
17057         x: points[0] - pageX,
17058         y: pageHeight - (points[1] - pageY)
17059       };
17060       const outliner = new FreeHighlightOutliner(point, [0, 0, pageWidth, pageHeight], 1, editor.#thickness / 2, true, 0.001);
17061       for (let i = 0, ii = points.length; i < ii; i += 2) {
17062         point.x = points[i] - pageX;
17063         point.y = pageHeight - (points[i + 1] - pageY);
17064         outliner.add(point);
17065       }
17066       const {
17067         id,
17068         clipPathId
17069       } = parent.drawLayer.draw({
17070         bbox: [0, 0, 1, 1],
17071         root: {
17072           viewBox: "0 0 1 1",
17073           fill: editor.color,
17074           "fill-opacity": editor._defaultOpacity
17075         },
17076         rootClass: {
17077           highlight: true,
17078           free: true
17079         },
17080         path: {
17081           d: outliner.toSVGPath()
17082         }
17083       }, true, true);
17084       editor.#createFreeOutlines({
17085         highlightOutlines: outliner.getOutlines(),
17086         highlightId: id,
17087         clipPathId
17088       });
17089       editor.#addToDrawLayer();
17090     }
17091     return editor;
17092   }
17093   serialize(isForCopying = false) {
17094     if (this.isEmpty() || isForCopying) {
17095       return null;
17096     }
17097     if (this.deleted) {
17098       return this.serializeDeleted();
17099     }
17100     const rect = this.getRect(0, 0);
17101     const color = AnnotationEditor._colorManager.convert(this.color);
17102     const serialized = {
17103       annotationType: AnnotationEditorType.HIGHLIGHT,
17104       color,
17105       opacity: this.#opacity,
17106       thickness: this.#thickness,
17107       quadPoints: this.#serializeBoxes(),
17108       outlines: this.#serializeOutlines(rect),
17109       pageIndex: this.pageIndex,
17110       rect,
17111       rotation: this.#getRotation(),
17112       structTreeParentId: this._structTreeParentId
17113     };
17114     if (this.annotationElementId && !this.#hasElementChanged(serialized)) {
17115       return null;
17116     }
17117     serialized.id = this.annotationElementId;
17118     return serialized;
17119   }
17120   #hasElementChanged(serialized) {
17121     const {
17122       color
17123     } = this._initialData;
17124     return serialized.color.some((c, i) => c !== color[i]);
17125   }
17126   renderAnnotationElement(annotation) {
17127     annotation.updateEdited({
17128       rect: this.getRect(0, 0)
17129     });
17130     return null;
17131   }
17132   static canCreateNewEmptyEditor() {
17133     return false;
17134   }
17137 ;// ./src/display/editor/draw.js
17141 class DrawingOptions {
17142   #svgProperties = Object.create(null);
17143   updateProperty(name, value) {
17144     this[name] = value;
17145     this.updateSVGProperty(name, value);
17146   }
17147   updateProperties(properties) {
17148     if (!properties) {
17149       return;
17150     }
17151     for (const [name, value] of Object.entries(properties)) {
17152       this.updateProperty(name, value);
17153     }
17154   }
17155   updateSVGProperty(name, value) {
17156     this.#svgProperties[name] = value;
17157   }
17158   toSVGProperties() {
17159     const root = this.#svgProperties;
17160     this.#svgProperties = Object.create(null);
17161     return {
17162       root
17163     };
17164   }
17165   reset() {
17166     this.#svgProperties = Object.create(null);
17167   }
17168   updateAll(options = this) {
17169     this.updateProperties(options);
17170   }
17171   clone() {
17172     unreachable("Not implemented");
17173   }
17175 class DrawingEditor extends AnnotationEditor {
17176   #drawOutlines = null;
17177   #mustBeCommitted;
17178   _drawId = null;
17179   static _currentDrawId = -1;
17180   static _currentParent = null;
17181   static #currentDraw = null;
17182   static #currentDrawingAC = null;
17183   static #currentDrawingOptions = null;
17184   static #currentPointerId = NaN;
17185   static #currentPointerType = null;
17186   static #currentPointerIds = null;
17187   static #currentMoveTimestamp = NaN;
17188   static _INNER_MARGIN = 3;
17189   constructor(params) {
17190     super(params);
17191     this.#mustBeCommitted = params.mustBeCommitted || false;
17192     this._addOutlines(params);
17193   }
17194   _addOutlines(params) {
17195     if (params.drawOutlines) {
17196       this.#createDrawOutlines(params);
17197       this.#addToDrawLayer();
17198     }
17199   }
17200   #createDrawOutlines({
17201     drawOutlines,
17202     drawId,
17203     drawingOptions
17204   }) {
17205     this.#drawOutlines = drawOutlines;
17206     this._drawingOptions ||= drawingOptions;
17207     if (drawId >= 0) {
17208       this._drawId = drawId;
17209       this.parent.drawLayer.finalizeDraw(drawId, drawOutlines.defaultProperties);
17210     } else {
17211       this._drawId = this.#createDrawing(drawOutlines, this.parent);
17212     }
17213     this.#updateBbox(drawOutlines.box);
17214   }
17215   #createDrawing(drawOutlines, parent) {
17216     const {
17217       id
17218     } = parent.drawLayer.draw(DrawingEditor._mergeSVGProperties(this._drawingOptions.toSVGProperties(), drawOutlines.defaultSVGProperties), false, false);
17219     return id;
17220   }
17221   static _mergeSVGProperties(p1, p2) {
17222     const p1Keys = new Set(Object.keys(p1));
17223     for (const [key, value] of Object.entries(p2)) {
17224       if (p1Keys.has(key)) {
17225         Object.assign(p1[key], value);
17226       } else {
17227         p1[key] = value;
17228       }
17229     }
17230     return p1;
17231   }
17232   static getDefaultDrawingOptions(_options) {
17233     unreachable("Not implemented");
17234   }
17235   static get typesMap() {
17236     unreachable("Not implemented");
17237   }
17238   static get isDrawer() {
17239     return true;
17240   }
17241   static get supportMultipleDrawings() {
17242     return false;
17243   }
17244   static updateDefaultParams(type, value) {
17245     const propertyName = this.typesMap.get(type);
17246     if (propertyName) {
17247       this._defaultDrawingOptions.updateProperty(propertyName, value);
17248     }
17249     if (this._currentParent) {
17250       DrawingEditor.#currentDraw.updateProperty(propertyName, value);
17251       this._currentParent.drawLayer.updateProperties(this._currentDrawId, this._defaultDrawingOptions.toSVGProperties());
17252     }
17253   }
17254   updateParams(type, value) {
17255     const propertyName = this.constructor.typesMap.get(type);
17256     if (propertyName) {
17257       this._updateProperty(type, propertyName, value);
17258     }
17259   }
17260   static get defaultPropertiesToUpdate() {
17261     const properties = [];
17262     const options = this._defaultDrawingOptions;
17263     for (const [type, name] of this.typesMap) {
17264       properties.push([type, options[name]]);
17265     }
17266     return properties;
17267   }
17268   get propertiesToUpdate() {
17269     const properties = [];
17270     const {
17271       _drawingOptions
17272     } = this;
17273     for (const [type, name] of this.constructor.typesMap) {
17274       properties.push([type, _drawingOptions[name]]);
17275     }
17276     return properties;
17277   }
17278   _updateProperty(type, name, value) {
17279     const options = this._drawingOptions;
17280     const savedValue = options[name];
17281     const setter = val => {
17282       options.updateProperty(name, val);
17283       const bbox = this.#drawOutlines.updateProperty(name, val);
17284       if (bbox) {
17285         this.#updateBbox(bbox);
17286       }
17287       this.parent?.drawLayer.updateProperties(this._drawId, options.toSVGProperties());
17288     };
17289     this.addCommands({
17290       cmd: setter.bind(this, value),
17291       undo: setter.bind(this, savedValue),
17292       post: this._uiManager.updateUI.bind(this._uiManager, this),
17293       mustExec: true,
17294       type,
17295       overwriteIfSameType: true,
17296       keepUndo: true
17297     });
17298   }
17299   _onResizing() {
17300     this.parent?.drawLayer.updateProperties(this._drawId, DrawingEditor._mergeSVGProperties(this.#drawOutlines.getPathResizingSVGProperties(this.#convertToDrawSpace()), {
17301       bbox: this.#rotateBox()
17302     }));
17303   }
17304   _onResized() {
17305     this.parent?.drawLayer.updateProperties(this._drawId, DrawingEditor._mergeSVGProperties(this.#drawOutlines.getPathResizedSVGProperties(this.#convertToDrawSpace()), {
17306       bbox: this.#rotateBox()
17307     }));
17308   }
17309   _onTranslating(x, y) {
17310     this.parent?.drawLayer.updateProperties(this._drawId, {
17311       bbox: this.#rotateBox(x, y)
17312     });
17313   }
17314   _onTranslated() {
17315     this.parent?.drawLayer.updateProperties(this._drawId, DrawingEditor._mergeSVGProperties(this.#drawOutlines.getPathTranslatedSVGProperties(this.#convertToDrawSpace(), this.parentDimensions), {
17316       bbox: this.#rotateBox()
17317     }));
17318   }
17319   _onStartDragging() {
17320     this.parent?.drawLayer.updateProperties(this._drawId, {
17321       rootClass: {
17322         moving: true
17323       }
17324     });
17325   }
17326   _onStopDragging() {
17327     this.parent?.drawLayer.updateProperties(this._drawId, {
17328       rootClass: {
17329         moving: false
17330       }
17331     });
17332   }
17333   commit() {
17334     super.commit();
17335     this.disableEditMode();
17336     this.disableEditing();
17337   }
17338   disableEditing() {
17339     super.disableEditing();
17340     this.div.classList.toggle("disabled", true);
17341   }
17342   enableEditing() {
17343     super.enableEditing();
17344     this.div.classList.toggle("disabled", false);
17345   }
17346   getBaseTranslation() {
17347     return [0, 0];
17348   }
17349   get isResizable() {
17350     return true;
17351   }
17352   onceAdded(focus) {
17353     if (!this.annotationElementId) {
17354       this.parent.addUndoableEditor(this);
17355     }
17356     this._isDraggable = true;
17357     if (this.#mustBeCommitted) {
17358       this.#mustBeCommitted = false;
17359       this.commit();
17360       this.parent.setSelected(this);
17361       if (focus && this.isOnScreen) {
17362         this.div.focus();
17363       }
17364     }
17365   }
17366   remove() {
17367     this.#cleanDrawLayer();
17368     super.remove();
17369   }
17370   rebuild() {
17371     if (!this.parent) {
17372       return;
17373     }
17374     super.rebuild();
17375     if (this.div === null) {
17376       return;
17377     }
17378     this.#addToDrawLayer();
17379     this.#updateBbox(this.#drawOutlines.box);
17380     if (!this.isAttachedToDOM) {
17381       this.parent.add(this);
17382     }
17383   }
17384   setParent(parent) {
17385     let mustBeSelected = false;
17386     if (this.parent && !parent) {
17387       this._uiManager.removeShouldRescale(this);
17388       this.#cleanDrawLayer();
17389     } else if (parent) {
17390       this._uiManager.addShouldRescale(this);
17391       this.#addToDrawLayer(parent);
17392       mustBeSelected = !this.parent && this.div?.classList.contains("selectedEditor");
17393     }
17394     super.setParent(parent);
17395     if (mustBeSelected) {
17396       this.select();
17397     }
17398   }
17399   #cleanDrawLayer() {
17400     if (this._drawId === null || !this.parent) {
17401       return;
17402     }
17403     this.parent.drawLayer.remove(this._drawId);
17404     this._drawId = null;
17405     this._drawingOptions.reset();
17406   }
17407   #addToDrawLayer(parent = this.parent) {
17408     if (this._drawId !== null && this.parent === parent) {
17409       return;
17410     }
17411     if (this._drawId !== null) {
17412       this.parent.drawLayer.updateParent(this._drawId, parent.drawLayer);
17413       return;
17414     }
17415     this._drawingOptions.updateAll();
17416     this._drawId = this.#createDrawing(this.#drawOutlines, parent);
17417   }
17418   #convertToParentSpace([x, y, width, height]) {
17419     const {
17420       parentDimensions: [pW, pH],
17421       rotation
17422     } = this;
17423     switch (rotation) {
17424       case 90:
17425         return [y, 1 - x, width * (pH / pW), height * (pW / pH)];
17426       case 180:
17427         return [1 - x, 1 - y, width, height];
17428       case 270:
17429         return [1 - y, x, width * (pH / pW), height * (pW / pH)];
17430       default:
17431         return [x, y, width, height];
17432     }
17433   }
17434   #convertToDrawSpace() {
17435     const {
17436       x,
17437       y,
17438       width,
17439       height,
17440       parentDimensions: [pW, pH],
17441       rotation
17442     } = this;
17443     switch (rotation) {
17444       case 90:
17445         return [1 - y, x, width * (pW / pH), height * (pH / pW)];
17446       case 180:
17447         return [1 - x, 1 - y, width, height];
17448       case 270:
17449         return [y, 1 - x, width * (pW / pH), height * (pH / pW)];
17450       default:
17451         return [x, y, width, height];
17452     }
17453   }
17454   #updateBbox(bbox) {
17455     [this.x, this.y, this.width, this.height] = this.#convertToParentSpace(bbox);
17456     if (this.div) {
17457       this.fixAndSetPosition();
17458       const [parentWidth, parentHeight] = this.parentDimensions;
17459       this.setDims(this.width * parentWidth, this.height * parentHeight);
17460     }
17461     this._onResized();
17462   }
17463   #rotateBox() {
17464     const {
17465       x,
17466       y,
17467       width,
17468       height,
17469       rotation,
17470       parentRotation,
17471       parentDimensions: [pW, pH]
17472     } = this;
17473     switch ((rotation * 4 + parentRotation) / 90) {
17474       case 1:
17475         return [1 - y - height, x, height, width];
17476       case 2:
17477         return [1 - x - width, 1 - y - height, width, height];
17478       case 3:
17479         return [y, 1 - x - width, height, width];
17480       case 4:
17481         return [x, y - width * (pW / pH), height * (pH / pW), width * (pW / pH)];
17482       case 5:
17483         return [1 - y, x, width * (pW / pH), height * (pH / pW)];
17484       case 6:
17485         return [1 - x - height * (pH / pW), 1 - y, height * (pH / pW), width * (pW / pH)];
17486       case 7:
17487         return [y - width * (pW / pH), 1 - x - height * (pH / pW), width * (pW / pH), height * (pH / pW)];
17488       case 8:
17489         return [x - width, y - height, width, height];
17490       case 9:
17491         return [1 - y, x - width, height, width];
17492       case 10:
17493         return [1 - x, 1 - y, width, height];
17494       case 11:
17495         return [y - height, 1 - x, height, width];
17496       case 12:
17497         return [x - height * (pH / pW), y, height * (pH / pW), width * (pW / pH)];
17498       case 13:
17499         return [1 - y - width * (pW / pH), x - height * (pH / pW), width * (pW / pH), height * (pH / pW)];
17500       case 14:
17501         return [1 - x, 1 - y - width * (pW / pH), height * (pH / pW), width * (pW / pH)];
17502       case 15:
17503         return [y, 1 - x, width * (pW / pH), height * (pH / pW)];
17504       default:
17505         return [x, y, width, height];
17506     }
17507   }
17508   rotate() {
17509     if (!this.parent) {
17510       return;
17511     }
17512     this.parent.drawLayer.updateProperties(this._drawId, DrawingEditor._mergeSVGProperties({
17513       bbox: this.#rotateBox()
17514     }, this.#drawOutlines.updateRotation((this.parentRotation - this.rotation + 360) % 360)));
17515   }
17516   onScaleChanging() {
17517     if (!this.parent) {
17518       return;
17519     }
17520     this.#updateBbox(this.#drawOutlines.updateParentDimensions(this.parentDimensions, this.parent.scale));
17521   }
17522   static onScaleChangingWhenDrawing() {}
17523   render() {
17524     if (this.div) {
17525       return this.div;
17526     }
17527     const div = super.render();
17528     div.classList.add("draw");
17529     const drawDiv = document.createElement("div");
17530     div.append(drawDiv);
17531     drawDiv.setAttribute("aria-hidden", "true");
17532     drawDiv.className = "internal";
17533     const [parentWidth, parentHeight] = this.parentDimensions;
17534     this.setDims(this.width * parentWidth, this.height * parentHeight);
17535     this._uiManager.addShouldRescale(this);
17536     this.disableEditing();
17537     return div;
17538   }
17539   static createDrawerInstance(_x, _y, _parentWidth, _parentHeight, _rotation) {
17540     unreachable("Not implemented");
17541   }
17542   static startDrawing(parent, uiManager, _isLTR, event) {
17543     const {
17544       target,
17545       offsetX: x,
17546       offsetY: y,
17547       pointerId,
17548       pointerType
17549     } = event;
17550     if (DrawingEditor.#currentPointerType && DrawingEditor.#currentPointerType !== pointerType) {
17551       return;
17552     }
17553     const {
17554       viewport: {
17555         rotation
17556       }
17557     } = parent;
17558     const {
17559       width: parentWidth,
17560       height: parentHeight
17561     } = target.getBoundingClientRect();
17562     const ac = DrawingEditor.#currentDrawingAC = new AbortController();
17563     const signal = parent.combinedSignal(ac);
17564     DrawingEditor.#currentPointerId ||= pointerId;
17565     DrawingEditor.#currentPointerType ??= pointerType;
17566     window.addEventListener("pointerup", e => {
17567       if (DrawingEditor.#currentPointerId === e.pointerId) {
17568         this._endDraw(e);
17569       } else {
17570         DrawingEditor.#currentPointerIds?.delete(e.pointerId);
17571       }
17572     }, {
17573       signal
17574     });
17575     window.addEventListener("pointercancel", e => {
17576       if (DrawingEditor.#currentPointerId === e.pointerId) {
17577         this._currentParent.endDrawingSession();
17578       } else {
17579         DrawingEditor.#currentPointerIds?.delete(e.pointerId);
17580       }
17581     }, {
17582       signal
17583     });
17584     window.addEventListener("pointerdown", e => {
17585       if (DrawingEditor.#currentPointerType !== e.pointerType) {
17586         return;
17587       }
17588       (DrawingEditor.#currentPointerIds ||= new Set()).add(e.pointerId);
17589       if (DrawingEditor.#currentDraw.isCancellable()) {
17590         DrawingEditor.#currentDraw.removeLastElement();
17591         if (DrawingEditor.#currentDraw.isEmpty()) {
17592           this._currentParent.endDrawingSession(true);
17593         } else {
17594           this._endDraw(null);
17595         }
17596       }
17597     }, {
17598       capture: true,
17599       passive: false,
17600       signal
17601     });
17602     window.addEventListener("contextmenu", noContextMenu, {
17603       signal
17604     });
17605     target.addEventListener("pointermove", this._drawMove.bind(this), {
17606       signal
17607     });
17608     target.addEventListener("touchmove", e => {
17609       if (e.timeStamp === DrawingEditor.#currentMoveTimestamp) {
17610         stopEvent(e);
17611       }
17612     }, {
17613       signal
17614     });
17615     parent.toggleDrawing();
17616     uiManager._editorUndoBar?.hide();
17617     if (DrawingEditor.#currentDraw) {
17618       parent.drawLayer.updateProperties(this._currentDrawId, DrawingEditor.#currentDraw.startNew(x, y, parentWidth, parentHeight, rotation));
17619       return;
17620     }
17621     uiManager.updateUIForDefaultProperties(this);
17622     DrawingEditor.#currentDraw = this.createDrawerInstance(x, y, parentWidth, parentHeight, rotation);
17623     DrawingEditor.#currentDrawingOptions = this.getDefaultDrawingOptions();
17624     this._currentParent = parent;
17625     ({
17626       id: this._currentDrawId
17627     } = parent.drawLayer.draw(this._mergeSVGProperties(DrawingEditor.#currentDrawingOptions.toSVGProperties(), DrawingEditor.#currentDraw.defaultSVGProperties), true, false));
17628   }
17629   static _drawMove(event) {
17630     DrawingEditor.#currentMoveTimestamp = -1;
17631     if (!DrawingEditor.#currentDraw) {
17632       return;
17633     }
17634     const {
17635       offsetX,
17636       offsetY,
17637       pointerId
17638     } = event;
17639     if (DrawingEditor.#currentPointerId !== pointerId) {
17640       return;
17641     }
17642     if (DrawingEditor.#currentPointerIds?.size >= 1) {
17643       this._endDraw(event);
17644       return;
17645     }
17646     this._currentParent.drawLayer.updateProperties(this._currentDrawId, DrawingEditor.#currentDraw.add(offsetX, offsetY));
17647     DrawingEditor.#currentMoveTimestamp = event.timeStamp;
17648     stopEvent(event);
17649   }
17650   static _cleanup(all) {
17651     if (all) {
17652       this._currentDrawId = -1;
17653       this._currentParent = null;
17654       DrawingEditor.#currentDraw = null;
17655       DrawingEditor.#currentDrawingOptions = null;
17656       DrawingEditor.#currentPointerType = null;
17657       DrawingEditor.#currentMoveTimestamp = NaN;
17658     }
17659     if (DrawingEditor.#currentDrawingAC) {
17660       DrawingEditor.#currentDrawingAC.abort();
17661       DrawingEditor.#currentDrawingAC = null;
17662       DrawingEditor.#currentPointerId = NaN;
17663       DrawingEditor.#currentPointerIds = null;
17664     }
17665   }
17666   static _endDraw(event) {
17667     const parent = this._currentParent;
17668     if (!parent) {
17669       return;
17670     }
17671     parent.toggleDrawing(true);
17672     this._cleanup(false);
17673     if (event?.target === parent.div) {
17674       parent.drawLayer.updateProperties(this._currentDrawId, DrawingEditor.#currentDraw.end(event.offsetX, event.offsetY));
17675     }
17676     if (this.supportMultipleDrawings) {
17677       const draw = DrawingEditor.#currentDraw;
17678       const drawId = this._currentDrawId;
17679       const lastElement = draw.getLastElement();
17680       parent.addCommands({
17681         cmd: () => {
17682           parent.drawLayer.updateProperties(drawId, draw.setLastElement(lastElement));
17683         },
17684         undo: () => {
17685           parent.drawLayer.updateProperties(drawId, draw.removeLastElement());
17686         },
17687         mustExec: false,
17688         type: AnnotationEditorParamsType.DRAW_STEP
17689       });
17690       return;
17691     }
17692     this.endDrawing(false);
17693   }
17694   static endDrawing(isAborted) {
17695     const parent = this._currentParent;
17696     if (!parent) {
17697       return null;
17698     }
17699     parent.toggleDrawing(true);
17700     parent.cleanUndoStack(AnnotationEditorParamsType.DRAW_STEP);
17701     if (!DrawingEditor.#currentDraw.isEmpty()) {
17702       const {
17703         pageDimensions: [pageWidth, pageHeight],
17704         scale
17705       } = parent;
17706       const editor = parent.createAndAddNewEditor({
17707         offsetX: 0,
17708         offsetY: 0
17709       }, false, {
17710         drawId: this._currentDrawId,
17711         drawOutlines: DrawingEditor.#currentDraw.getOutlines(pageWidth * scale, pageHeight * scale, scale, this._INNER_MARGIN),
17712         drawingOptions: DrawingEditor.#currentDrawingOptions,
17713         mustBeCommitted: !isAborted
17714       });
17715       this._cleanup(true);
17716       return editor;
17717     }
17718     parent.drawLayer.remove(this._currentDrawId);
17719     this._cleanup(true);
17720     return null;
17721   }
17722   createDrawingOptions(_data) {}
17723   static deserializeDraw(_pageX, _pageY, _pageWidth, _pageHeight, _innerWidth, _data) {
17724     unreachable("Not implemented");
17725   }
17726   static async deserialize(data, parent, uiManager) {
17727     const {
17728       rawDims: {
17729         pageWidth,
17730         pageHeight,
17731         pageX,
17732         pageY
17733       }
17734     } = parent.viewport;
17735     const drawOutlines = this.deserializeDraw(pageX, pageY, pageWidth, pageHeight, this._INNER_MARGIN, data);
17736     const editor = await super.deserialize(data, parent, uiManager);
17737     editor.createDrawingOptions(data);
17738     editor.#createDrawOutlines({
17739       drawOutlines
17740     });
17741     editor.#addToDrawLayer();
17742     editor.onScaleChanging();
17743     editor.rotate();
17744     return editor;
17745   }
17746   serializeDraw(isForCopying) {
17747     const [pageX, pageY] = this.pageTranslation;
17748     const [pageWidth, pageHeight] = this.pageDimensions;
17749     return this.#drawOutlines.serialize([pageX, pageY, pageWidth, pageHeight], isForCopying);
17750   }
17751   renderAnnotationElement(annotation) {
17752     annotation.updateEdited({
17753       rect: this.getRect(0, 0)
17754     });
17755     return null;
17756   }
17757   static canCreateNewEmptyEditor() {
17758     return false;
17759   }
17762 ;// ./src/display/editor/drawers/inkdraw.js
17765 class InkDrawOutliner {
17766   #last = new Float64Array(6);
17767   #line;
17768   #lines;
17769   #rotation;
17770   #thickness;
17771   #points;
17772   #lastSVGPath = "";
17773   #lastIndex = 0;
17774   #outlines = new InkDrawOutline();
17775   #parentWidth;
17776   #parentHeight;
17777   constructor(x, y, parentWidth, parentHeight, rotation, thickness) {
17778     this.#parentWidth = parentWidth;
17779     this.#parentHeight = parentHeight;
17780     this.#rotation = rotation;
17781     this.#thickness = thickness;
17782     [x, y] = this.#normalizePoint(x, y);
17783     const line = this.#line = [NaN, NaN, NaN, NaN, x, y];
17784     this.#points = [x, y];
17785     this.#lines = [{
17786       line,
17787       points: this.#points
17788     }];
17789     this.#last.set(line, 0);
17790   }
17791   updateProperty(name, value) {
17792     if (name === "stroke-width") {
17793       this.#thickness = value;
17794     }
17795   }
17796   #normalizePoint(x, y) {
17797     return Outline._normalizePoint(x, y, this.#parentWidth, this.#parentHeight, this.#rotation);
17798   }
17799   isEmpty() {
17800     return !this.#lines || this.#lines.length === 0;
17801   }
17802   isCancellable() {
17803     return this.#points.length <= 10;
17804   }
17805   add(x, y) {
17806     [x, y] = this.#normalizePoint(x, y);
17807     const [x1, y1, x2, y2] = this.#last.subarray(2, 6);
17808     const diffX = x - x2;
17809     const diffY = y - y2;
17810     const d = Math.hypot(this.#parentWidth * diffX, this.#parentHeight * diffY);
17811     if (d <= 2) {
17812       return null;
17813     }
17814     this.#points.push(x, y);
17815     if (isNaN(x1)) {
17816       this.#last.set([x2, y2, x, y], 2);
17817       this.#line.push(NaN, NaN, NaN, NaN, x, y);
17818       return {
17819         path: {
17820           d: this.toSVGPath()
17821         }
17822       };
17823     }
17824     if (isNaN(this.#last[0])) {
17825       this.#line.splice(6, 6);
17826     }
17827     this.#last.set([x1, y1, x2, y2, x, y], 0);
17828     this.#line.push(...Outline.createBezierPoints(x1, y1, x2, y2, x, y));
17829     return {
17830       path: {
17831         d: this.toSVGPath()
17832       }
17833     };
17834   }
17835   end(x, y) {
17836     const change = this.add(x, y);
17837     if (change) {
17838       return change;
17839     }
17840     if (this.#points.length === 2) {
17841       return {
17842         path: {
17843           d: this.toSVGPath()
17844         }
17845       };
17846     }
17847     return null;
17848   }
17849   startNew(x, y, parentWidth, parentHeight, rotation) {
17850     this.#parentWidth = parentWidth;
17851     this.#parentHeight = parentHeight;
17852     this.#rotation = rotation;
17853     [x, y] = this.#normalizePoint(x, y);
17854     const line = this.#line = [NaN, NaN, NaN, NaN, x, y];
17855     this.#points = [x, y];
17856     const last = this.#lines.at(-1);
17857     if (last) {
17858       last.line = new Float32Array(last.line);
17859       last.points = new Float32Array(last.points);
17860     }
17861     this.#lines.push({
17862       line,
17863       points: this.#points
17864     });
17865     this.#last.set(line, 0);
17866     this.#lastIndex = 0;
17867     this.toSVGPath();
17868     return null;
17869   }
17870   getLastElement() {
17871     return this.#lines.at(-1);
17872   }
17873   setLastElement(element) {
17874     if (!this.#lines) {
17875       return this.#outlines.setLastElement(element);
17876     }
17877     this.#lines.push(element);
17878     this.#line = element.line;
17879     this.#points = element.points;
17880     this.#lastIndex = 0;
17881     return {
17882       path: {
17883         d: this.toSVGPath()
17884       }
17885     };
17886   }
17887   removeLastElement() {
17888     if (!this.#lines) {
17889       return this.#outlines.removeLastElement();
17890     }
17891     this.#lines.pop();
17892     this.#lastSVGPath = "";
17893     for (let i = 0, ii = this.#lines.length; i < ii; i++) {
17894       const {
17895         line,
17896         points
17897       } = this.#lines[i];
17898       this.#line = line;
17899       this.#points = points;
17900       this.#lastIndex = 0;
17901       this.toSVGPath();
17902     }
17903     return {
17904       path: {
17905         d: this.#lastSVGPath
17906       }
17907     };
17908   }
17909   toSVGPath() {
17910     const firstX = Outline.svgRound(this.#line[4]);
17911     const firstY = Outline.svgRound(this.#line[5]);
17912     if (this.#points.length === 2) {
17913       this.#lastSVGPath = `${this.#lastSVGPath} M ${firstX} ${firstY} Z`;
17914       return this.#lastSVGPath;
17915     }
17916     if (this.#points.length <= 6) {
17917       const i = this.#lastSVGPath.lastIndexOf("M");
17918       this.#lastSVGPath = `${this.#lastSVGPath.slice(0, i)} M ${firstX} ${firstY}`;
17919       this.#lastIndex = 6;
17920     }
17921     if (this.#points.length === 4) {
17922       const secondX = Outline.svgRound(this.#line[10]);
17923       const secondY = Outline.svgRound(this.#line[11]);
17924       this.#lastSVGPath = `${this.#lastSVGPath} L ${secondX} ${secondY}`;
17925       this.#lastIndex = 12;
17926       return this.#lastSVGPath;
17927     }
17928     const buffer = [];
17929     if (this.#lastIndex === 0) {
17930       buffer.push(`M ${firstX} ${firstY}`);
17931       this.#lastIndex = 6;
17932     }
17933     for (let i = this.#lastIndex, ii = this.#line.length; i < ii; i += 6) {
17934       const [c1x, c1y, c2x, c2y, x, y] = this.#line.slice(i, i + 6).map(Outline.svgRound);
17935       buffer.push(`C${c1x} ${c1y} ${c2x} ${c2y} ${x} ${y}`);
17936     }
17937     this.#lastSVGPath += buffer.join(" ");
17938     this.#lastIndex = this.#line.length;
17939     return this.#lastSVGPath;
17940   }
17941   getOutlines(parentWidth, parentHeight, scale, innerMargin) {
17942     const last = this.#lines.at(-1);
17943     last.line = new Float32Array(last.line);
17944     last.points = new Float32Array(last.points);
17945     this.#outlines.build(this.#lines, parentWidth, parentHeight, scale, this.#rotation, this.#thickness, innerMargin);
17946     this.#last = null;
17947     this.#line = null;
17948     this.#lines = null;
17949     this.#lastSVGPath = null;
17950     return this.#outlines;
17951   }
17952   get defaultSVGProperties() {
17953     return {
17954       root: {
17955         viewBox: "0 0 10000 10000"
17956       },
17957       rootClass: {
17958         draw: true
17959       },
17960       bbox: [0, 0, 1, 1]
17961     };
17962   }
17964 class InkDrawOutline extends Outline {
17965   #bbox;
17966   #currentRotation = 0;
17967   #innerMargin;
17968   #lines;
17969   #parentWidth;
17970   #parentHeight;
17971   #parentScale;
17972   #rotation;
17973   #thickness;
17974   build(lines, parentWidth, parentHeight, parentScale, rotation, thickness, innerMargin) {
17975     this.#parentWidth = parentWidth;
17976     this.#parentHeight = parentHeight;
17977     this.#parentScale = parentScale;
17978     this.#rotation = rotation;
17979     this.#thickness = thickness;
17980     this.#innerMargin = innerMargin ?? 0;
17981     this.#lines = lines;
17982     this.#computeBbox();
17983   }
17984   get thickness() {
17985     return this.#thickness;
17986   }
17987   setLastElement(element) {
17988     this.#lines.push(element);
17989     return {
17990       path: {
17991         d: this.toSVGPath()
17992       }
17993     };
17994   }
17995   removeLastElement() {
17996     this.#lines.pop();
17997     return {
17998       path: {
17999         d: this.toSVGPath()
18000       }
18001     };
18002   }
18003   toSVGPath() {
18004     const buffer = [];
18005     for (const {
18006       line
18007     } of this.#lines) {
18008       buffer.push(`M${Outline.svgRound(line[4])} ${Outline.svgRound(line[5])}`);
18009       if (line.length === 6) {
18010         buffer.push("Z");
18011         continue;
18012       }
18013       if (line.length === 12 && isNaN(line[6])) {
18014         buffer.push(`L${Outline.svgRound(line[10])} ${Outline.svgRound(line[11])}`);
18015         continue;
18016       }
18017       for (let i = 6, ii = line.length; i < ii; i += 6) {
18018         const [c1x, c1y, c2x, c2y, x, y] = line.subarray(i, i + 6).map(Outline.svgRound);
18019         buffer.push(`C${c1x} ${c1y} ${c2x} ${c2y} ${x} ${y}`);
18020       }
18021     }
18022     return buffer.join("");
18023   }
18024   serialize([pageX, pageY, pageWidth, pageHeight], isForCopying) {
18025     const serializedLines = [];
18026     const serializedPoints = [];
18027     const [x, y, width, height] = this.#getBBoxWithNoMargin();
18028     let tx, ty, sx, sy, x1, y1, x2, y2, rescaleFn;
18029     switch (this.#rotation) {
18030       case 0:
18031         rescaleFn = Outline._rescale;
18032         tx = pageX;
18033         ty = pageY + pageHeight;
18034         sx = pageWidth;
18035         sy = -pageHeight;
18036         x1 = pageX + x * pageWidth;
18037         y1 = pageY + (1 - y - height) * pageHeight;
18038         x2 = pageX + (x + width) * pageWidth;
18039         y2 = pageY + (1 - y) * pageHeight;
18040         break;
18041       case 90:
18042         rescaleFn = Outline._rescaleAndSwap;
18043         tx = pageX;
18044         ty = pageY;
18045         sx = pageWidth;
18046         sy = pageHeight;
18047         x1 = pageX + y * pageWidth;
18048         y1 = pageY + x * pageHeight;
18049         x2 = pageX + (y + height) * pageWidth;
18050         y2 = pageY + (x + width) * pageHeight;
18051         break;
18052       case 180:
18053         rescaleFn = Outline._rescale;
18054         tx = pageX + pageWidth;
18055         ty = pageY;
18056         sx = -pageWidth;
18057         sy = pageHeight;
18058         x1 = pageX + (1 - x - width) * pageWidth;
18059         y1 = pageY + y * pageHeight;
18060         x2 = pageX + (1 - x) * pageWidth;
18061         y2 = pageY + (y + height) * pageHeight;
18062         break;
18063       case 270:
18064         rescaleFn = Outline._rescaleAndSwap;
18065         tx = pageX + pageWidth;
18066         ty = pageY + pageHeight;
18067         sx = -pageWidth;
18068         sy = -pageHeight;
18069         x1 = pageX + (1 - y - height) * pageWidth;
18070         y1 = pageY + (1 - x - width) * pageHeight;
18071         x2 = pageX + (1 - y) * pageWidth;
18072         y2 = pageY + (1 - x) * pageHeight;
18073         break;
18074     }
18075     for (const {
18076       line,
18077       points
18078     } of this.#lines) {
18079       serializedLines.push(rescaleFn(line, tx, ty, sx, sy, isForCopying ? new Array(line.length) : null));
18080       serializedPoints.push(rescaleFn(points, tx, ty, sx, sy, isForCopying ? new Array(points.length) : null));
18081     }
18082     return {
18083       lines: serializedLines,
18084       points: serializedPoints,
18085       rect: [x1, y1, x2, y2]
18086     };
18087   }
18088   static deserialize(pageX, pageY, pageWidth, pageHeight, innerMargin, {
18089     paths: {
18090       lines,
18091       points
18092     },
18093     rotation,
18094     thickness
18095   }) {
18096     const newLines = [];
18097     let tx, ty, sx, sy, rescaleFn;
18098     switch (rotation) {
18099       case 0:
18100         rescaleFn = Outline._rescale;
18101         tx = -pageX / pageWidth;
18102         ty = pageY / pageHeight + 1;
18103         sx = 1 / pageWidth;
18104         sy = -1 / pageHeight;
18105         break;
18106       case 90:
18107         rescaleFn = Outline._rescaleAndSwap;
18108         tx = -pageY / pageHeight;
18109         ty = -pageX / pageWidth;
18110         sx = 1 / pageHeight;
18111         sy = 1 / pageWidth;
18112         break;
18113       case 180:
18114         rescaleFn = Outline._rescale;
18115         tx = pageX / pageWidth + 1;
18116         ty = -pageY / pageHeight;
18117         sx = -1 / pageWidth;
18118         sy = 1 / pageHeight;
18119         break;
18120       case 270:
18121         rescaleFn = Outline._rescaleAndSwap;
18122         tx = pageY / pageHeight + 1;
18123         ty = pageX / pageWidth + 1;
18124         sx = -1 / pageHeight;
18125         sy = -1 / pageWidth;
18126         break;
18127     }
18128     if (!lines) {
18129       lines = [];
18130       for (const point of points) {
18131         const len = point.length;
18132         if (len === 2) {
18133           lines.push(new Float32Array([NaN, NaN, NaN, NaN, point[0], point[1]]));
18134           continue;
18135         }
18136         if (len === 4) {
18137           lines.push(new Float32Array([NaN, NaN, NaN, NaN, point[0], point[1], NaN, NaN, NaN, NaN, point[2], point[3]]));
18138           continue;
18139         }
18140         const line = new Float32Array(3 * (len - 2));
18141         lines.push(line);
18142         let [x1, y1, x2, y2] = point.subarray(0, 4);
18143         line.set([NaN, NaN, NaN, NaN, x1, y1], 0);
18144         for (let i = 4; i < len; i += 2) {
18145           const x = point[i];
18146           const y = point[i + 1];
18147           line.set(Outline.createBezierPoints(x1, y1, x2, y2, x, y), (i - 2) * 3);
18148           [x1, y1, x2, y2] = [x2, y2, x, y];
18149         }
18150       }
18151     }
18152     for (let i = 0, ii = lines.length; i < ii; i++) {
18153       newLines.push({
18154         line: rescaleFn(lines[i].map(x => x ?? NaN), tx, ty, sx, sy),
18155         points: rescaleFn(points[i].map(x => x ?? NaN), tx, ty, sx, sy)
18156       });
18157     }
18158     const outlines = new InkDrawOutline();
18159     outlines.build(newLines, pageWidth, pageHeight, 1, rotation, thickness, innerMargin);
18160     return outlines;
18161   }
18162   #getMarginComponents(thickness = this.#thickness) {
18163     const margin = this.#innerMargin + thickness / 2 * this.#parentScale;
18164     return this.#rotation % 180 === 0 ? [margin / this.#parentWidth, margin / this.#parentHeight] : [margin / this.#parentHeight, margin / this.#parentWidth];
18165   }
18166   #getBBoxWithNoMargin() {
18167     const [x, y, width, height] = this.#bbox;
18168     const [marginX, marginY] = this.#getMarginComponents(0);
18169     return [x + marginX, y + marginY, width - 2 * marginX, height - 2 * marginY];
18170   }
18171   #computeBbox() {
18172     const bbox = this.#bbox = new Float32Array([Infinity, Infinity, -Infinity, -Infinity]);
18173     for (const {
18174       line
18175     } of this.#lines) {
18176       if (line.length <= 12) {
18177         for (let i = 4, ii = line.length; i < ii; i += 6) {
18178           const [x, y] = line.subarray(i, i + 2);
18179           bbox[0] = Math.min(bbox[0], x);
18180           bbox[1] = Math.min(bbox[1], y);
18181           bbox[2] = Math.max(bbox[2], x);
18182           bbox[3] = Math.max(bbox[3], y);
18183         }
18184         continue;
18185       }
18186       let lastX = line[4],
18187         lastY = line[5];
18188       for (let i = 6, ii = line.length; i < ii; i += 6) {
18189         const [c1x, c1y, c2x, c2y, x, y] = line.subarray(i, i + 6);
18190         Util.bezierBoundingBox(lastX, lastY, c1x, c1y, c2x, c2y, x, y, bbox);
18191         lastX = x;
18192         lastY = y;
18193       }
18194     }
18195     const [marginX, marginY] = this.#getMarginComponents();
18196     bbox[0] = Math.min(1, Math.max(0, bbox[0] - marginX));
18197     bbox[1] = Math.min(1, Math.max(0, bbox[1] - marginY));
18198     bbox[2] = Math.min(1, Math.max(0, bbox[2] + marginX));
18199     bbox[3] = Math.min(1, Math.max(0, bbox[3] + marginY));
18200     bbox[2] -= bbox[0];
18201     bbox[3] -= bbox[1];
18202   }
18203   get box() {
18204     return this.#bbox;
18205   }
18206   updateProperty(name, value) {
18207     if (name === "stroke-width") {
18208       return this.#updateThickness(value);
18209     }
18210     return null;
18211   }
18212   #updateThickness(thickness) {
18213     const [oldMarginX, oldMarginY] = this.#getMarginComponents();
18214     this.#thickness = thickness;
18215     const [newMarginX, newMarginY] = this.#getMarginComponents();
18216     const [diffMarginX, diffMarginY] = [newMarginX - oldMarginX, newMarginY - oldMarginY];
18217     const bbox = this.#bbox;
18218     bbox[0] -= diffMarginX;
18219     bbox[1] -= diffMarginY;
18220     bbox[2] += 2 * diffMarginX;
18221     bbox[3] += 2 * diffMarginY;
18222     return bbox;
18223   }
18224   updateParentDimensions([width, height], scale) {
18225     const [oldMarginX, oldMarginY] = this.#getMarginComponents();
18226     this.#parentWidth = width;
18227     this.#parentHeight = height;
18228     this.#parentScale = scale;
18229     const [newMarginX, newMarginY] = this.#getMarginComponents();
18230     const diffMarginX = newMarginX - oldMarginX;
18231     const diffMarginY = newMarginY - oldMarginY;
18232     const bbox = this.#bbox;
18233     bbox[0] -= diffMarginX;
18234     bbox[1] -= diffMarginY;
18235     bbox[2] += 2 * diffMarginX;
18236     bbox[3] += 2 * diffMarginY;
18237     return bbox;
18238   }
18239   updateRotation(rotation) {
18240     this.#currentRotation = rotation;
18241     return {
18242       path: {
18243         transform: this.rotationTransform
18244       }
18245     };
18246   }
18247   get viewBox() {
18248     return this.#bbox.map(Outline.svgRound).join(" ");
18249   }
18250   get defaultProperties() {
18251     const [x, y] = this.#bbox;
18252     return {
18253       root: {
18254         viewBox: this.viewBox
18255       },
18256       path: {
18257         "transform-origin": `${Outline.svgRound(x)} ${Outline.svgRound(y)}`
18258       }
18259     };
18260   }
18261   get rotationTransform() {
18262     const [,, width, height] = this.#bbox;
18263     let a = 0,
18264       b = 0,
18265       c = 0,
18266       d = 0,
18267       e = 0,
18268       f = 0;
18269     switch (this.#currentRotation) {
18270       case 90:
18271         b = height / width;
18272         c = -width / height;
18273         e = width;
18274         break;
18275       case 180:
18276         a = -1;
18277         d = -1;
18278         e = width;
18279         f = height;
18280         break;
18281       case 270:
18282         b = -height / width;
18283         c = width / height;
18284         f = height;
18285         break;
18286       default:
18287         return "";
18288     }
18289     return `matrix(${a} ${b} ${c} ${d} ${Outline.svgRound(e)} ${Outline.svgRound(f)})`;
18290   }
18291   getPathResizingSVGProperties([newX, newY, newWidth, newHeight]) {
18292     const [marginX, marginY] = this.#getMarginComponents();
18293     const [x, y, width, height] = this.#bbox;
18294     if (Math.abs(width - marginX) <= Outline.PRECISION || Math.abs(height - marginY) <= Outline.PRECISION) {
18295       const tx = newX + newWidth / 2 - (x + width / 2);
18296       const ty = newY + newHeight / 2 - (y + height / 2);
18297       return {
18298         path: {
18299           "transform-origin": `${Outline.svgRound(newX)} ${Outline.svgRound(newY)}`,
18300           transform: `${this.rotationTransform} translate(${tx} ${ty})`
18301         }
18302       };
18303     }
18304     const s1x = (newWidth - 2 * marginX) / (width - 2 * marginX);
18305     const s1y = (newHeight - 2 * marginY) / (height - 2 * marginY);
18306     const s2x = width / newWidth;
18307     const s2y = height / newHeight;
18308     return {
18309       path: {
18310         "transform-origin": `${Outline.svgRound(x)} ${Outline.svgRound(y)}`,
18311         transform: `${this.rotationTransform} scale(${s2x} ${s2y}) ` + `translate(${Outline.svgRound(marginX)} ${Outline.svgRound(marginY)}) scale(${s1x} ${s1y}) ` + `translate(${Outline.svgRound(-marginX)} ${Outline.svgRound(-marginY)})`
18312       }
18313     };
18314   }
18315   getPathResizedSVGProperties([newX, newY, newWidth, newHeight]) {
18316     const [marginX, marginY] = this.#getMarginComponents();
18317     const bbox = this.#bbox;
18318     const [x, y, width, height] = bbox;
18319     bbox[0] = newX;
18320     bbox[1] = newY;
18321     bbox[2] = newWidth;
18322     bbox[3] = newHeight;
18323     if (Math.abs(width - marginX) <= Outline.PRECISION || Math.abs(height - marginY) <= Outline.PRECISION) {
18324       const tx = newX + newWidth / 2 - (x + width / 2);
18325       const ty = newY + newHeight / 2 - (y + height / 2);
18326       for (const {
18327         line,
18328         points
18329       } of this.#lines) {
18330         Outline._translate(line, tx, ty, line);
18331         Outline._translate(points, tx, ty, points);
18332       }
18333       return {
18334         root: {
18335           viewBox: this.viewBox
18336         },
18337         path: {
18338           "transform-origin": `${Outline.svgRound(newX)} ${Outline.svgRound(newY)}`,
18339           transform: this.rotationTransform || null,
18340           d: this.toSVGPath()
18341         }
18342       };
18343     }
18344     const s1x = (newWidth - 2 * marginX) / (width - 2 * marginX);
18345     const s1y = (newHeight - 2 * marginY) / (height - 2 * marginY);
18346     const tx = -s1x * (x + marginX) + newX + marginX;
18347     const ty = -s1y * (y + marginY) + newY + marginY;
18348     if (s1x !== 1 || s1y !== 1 || tx !== 0 || ty !== 0) {
18349       for (const {
18350         line,
18351         points
18352       } of this.#lines) {
18353         Outline._rescale(line, tx, ty, s1x, s1y, line);
18354         Outline._rescale(points, tx, ty, s1x, s1y, points);
18355       }
18356     }
18357     return {
18358       root: {
18359         viewBox: this.viewBox
18360       },
18361       path: {
18362         "transform-origin": `${Outline.svgRound(newX)} ${Outline.svgRound(newY)}`,
18363         transform: this.rotationTransform || null,
18364         d: this.toSVGPath()
18365       }
18366     };
18367   }
18368   getPathTranslatedSVGProperties([newX, newY], parentDimensions) {
18369     const [newParentWidth, newParentHeight] = parentDimensions;
18370     const bbox = this.#bbox;
18371     const tx = newX - bbox[0];
18372     const ty = newY - bbox[1];
18373     if (this.#parentWidth === newParentWidth && this.#parentHeight === newParentHeight) {
18374       for (const {
18375         line,
18376         points
18377       } of this.#lines) {
18378         Outline._translate(line, tx, ty, line);
18379         Outline._translate(points, tx, ty, points);
18380       }
18381     } else {
18382       const sx = this.#parentWidth / newParentWidth;
18383       const sy = this.#parentHeight / newParentHeight;
18384       this.#parentWidth = newParentWidth;
18385       this.#parentHeight = newParentHeight;
18386       for (const {
18387         line,
18388         points
18389       } of this.#lines) {
18390         Outline._rescale(line, tx, ty, sx, sy, line);
18391         Outline._rescale(points, tx, ty, sx, sy, points);
18392       }
18393       bbox[2] *= sx;
18394       bbox[3] *= sy;
18395     }
18396     bbox[0] = newX;
18397     bbox[1] = newY;
18398     return {
18399       root: {
18400         viewBox: this.viewBox
18401       },
18402       path: {
18403         d: this.toSVGPath(),
18404         "transform-origin": `${Outline.svgRound(newX)} ${Outline.svgRound(newY)}`
18405       }
18406     };
18407   }
18408   get defaultSVGProperties() {
18409     const bbox = this.#bbox;
18410     return {
18411       root: {
18412         viewBox: this.viewBox
18413       },
18414       rootClass: {
18415         draw: true
18416       },
18417       path: {
18418         d: this.toSVGPath(),
18419         "transform-origin": `${Outline.svgRound(bbox[0])} ${Outline.svgRound(bbox[1])}`,
18420         transform: this.rotationTransform || null
18421       },
18422       bbox
18423     };
18424   }
18427 ;// ./src/display/editor/ink.js
18433 class InkDrawingOptions extends DrawingOptions {
18434   constructor(viewerParameters) {
18435     super();
18436     this._viewParameters = viewerParameters;
18437     super.updateProperties({
18438       fill: "none",
18439       stroke: AnnotationEditor._defaultLineColor,
18440       "stroke-opacity": 1,
18441       "stroke-width": 1,
18442       "stroke-linecap": "round",
18443       "stroke-linejoin": "round",
18444       "stroke-miterlimit": 10
18445     });
18446   }
18447   updateSVGProperty(name, value) {
18448     if (name === "stroke-width") {
18449       value ??= this["stroke-width"];
18450       value *= this._viewParameters.realScale;
18451     }
18452     super.updateSVGProperty(name, value);
18453   }
18454   clone() {
18455     const clone = new InkDrawingOptions(this._viewParameters);
18456     clone.updateAll(this);
18457     return clone;
18458   }
18460 class InkEditor extends DrawingEditor {
18461   static _type = "ink";
18462   static _editorType = AnnotationEditorType.INK;
18463   static _defaultDrawingOptions = null;
18464   constructor(params) {
18465     super({
18466       ...params,
18467       name: "inkEditor"
18468     });
18469     this._willKeepAspectRatio = true;
18470   }
18471   static initialize(l10n, uiManager) {
18472     AnnotationEditor.initialize(l10n, uiManager);
18473     this._defaultDrawingOptions = new InkDrawingOptions(uiManager.viewParameters);
18474   }
18475   static getDefaultDrawingOptions(options) {
18476     const clone = this._defaultDrawingOptions.clone();
18477     clone.updateProperties(options);
18478     return clone;
18479   }
18480   static get supportMultipleDrawings() {
18481     return true;
18482   }
18483   static get typesMap() {
18484     return shadow(this, "typesMap", new Map([[AnnotationEditorParamsType.INK_THICKNESS, "stroke-width"], [AnnotationEditorParamsType.INK_COLOR, "stroke"], [AnnotationEditorParamsType.INK_OPACITY, "stroke-opacity"]]));
18485   }
18486   static createDrawerInstance(x, y, parentWidth, parentHeight, rotation) {
18487     return new InkDrawOutliner(x, y, parentWidth, parentHeight, rotation, this._defaultDrawingOptions["stroke-width"]);
18488   }
18489   static deserializeDraw(pageX, pageY, pageWidth, pageHeight, innerMargin, data) {
18490     return InkDrawOutline.deserialize(pageX, pageY, pageWidth, pageHeight, innerMargin, data);
18491   }
18492   static async deserialize(data, parent, uiManager) {
18493     let initialData = null;
18494     if (data instanceof InkAnnotationElement) {
18495       const {
18496         data: {
18497           inkLists,
18498           rect,
18499           rotation,
18500           id,
18501           color,
18502           opacity,
18503           borderStyle: {
18504             rawWidth: thickness
18505           },
18506           popupRef
18507         },
18508         parent: {
18509           page: {
18510             pageNumber
18511           }
18512         }
18513       } = data;
18514       initialData = data = {
18515         annotationType: AnnotationEditorType.INK,
18516         color: Array.from(color),
18517         thickness,
18518         opacity,
18519         paths: {
18520           points: inkLists
18521         },
18522         boxes: null,
18523         pageIndex: pageNumber - 1,
18524         rect: rect.slice(0),
18525         rotation,
18526         id,
18527         deleted: false,
18528         popupRef
18529       };
18530     }
18531     const editor = await super.deserialize(data, parent, uiManager);
18532     editor.annotationElementId = data.id || null;
18533     editor._initialData = initialData;
18534     return editor;
18535   }
18536   onScaleChanging() {
18537     if (!this.parent) {
18538       return;
18539     }
18540     super.onScaleChanging();
18541     const {
18542       _drawId,
18543       _drawingOptions,
18544       parent
18545     } = this;
18546     _drawingOptions.updateSVGProperty("stroke-width");
18547     parent.drawLayer.updateProperties(_drawId, _drawingOptions.toSVGProperties());
18548   }
18549   static onScaleChangingWhenDrawing() {
18550     const parent = this._currentParent;
18551     if (!parent) {
18552       return;
18553     }
18554     super.onScaleChangingWhenDrawing();
18555     this._defaultDrawingOptions.updateSVGProperty("stroke-width");
18556     parent.drawLayer.updateProperties(this._currentDrawId, this._defaultDrawingOptions.toSVGProperties());
18557   }
18558   createDrawingOptions({
18559     color,
18560     thickness,
18561     opacity
18562   }) {
18563     this._drawingOptions = InkEditor.getDefaultDrawingOptions({
18564       stroke: Util.makeHexColor(...color),
18565       "stroke-width": thickness,
18566       "stroke-opacity": opacity
18567     });
18568   }
18569   serialize(isForCopying = false) {
18570     if (this.isEmpty()) {
18571       return null;
18572     }
18573     if (this.deleted) {
18574       return this.serializeDeleted();
18575     }
18576     const {
18577       lines,
18578       points,
18579       rect
18580     } = this.serializeDraw(isForCopying);
18581     const {
18582       _drawingOptions: {
18583         stroke,
18584         "stroke-opacity": opacity,
18585         "stroke-width": thickness
18586       }
18587     } = this;
18588     const serialized = {
18589       annotationType: AnnotationEditorType.INK,
18590       color: AnnotationEditor._colorManager.convert(stroke),
18591       opacity,
18592       thickness,
18593       paths: {
18594         lines,
18595         points
18596       },
18597       pageIndex: this.pageIndex,
18598       rect,
18599       rotation: this.rotation,
18600       structTreeParentId: this._structTreeParentId
18601     };
18602     if (isForCopying) {
18603       return serialized;
18604     }
18605     if (this.annotationElementId && !this.#hasElementChanged(serialized)) {
18606       return null;
18607     }
18608     serialized.id = this.annotationElementId;
18609     return serialized;
18610   }
18611   #hasElementChanged(serialized) {
18612     const {
18613       color,
18614       thickness,
18615       opacity,
18616       pageIndex
18617     } = this._initialData;
18618     return this._hasBeenMoved || this._hasBeenResized || serialized.color.some((c, i) => c !== color[i]) || serialized.thickness !== thickness || serialized.opacity !== opacity || serialized.pageIndex !== pageIndex;
18619   }
18620   renderAnnotationElement(annotation) {
18621     const {
18622       points,
18623       rect
18624     } = this.serializeDraw(false);
18625     annotation.updateEdited({
18626       rect,
18627       thickness: this._drawingOptions["stroke-width"],
18628       points
18629     });
18630     return null;
18631   }
18634 ;// ./src/display/editor/drawers/contour.js
18636 class ContourDrawOutline extends InkDrawOutline {
18637   toSVGPath() {
18638     let path = super.toSVGPath();
18639     if (!path.endsWith("Z")) {
18640       path += "Z";
18641     }
18642     return path;
18643   }
18646 ;// ./src/display/editor/drawers/signaturedraw.js
18650 class SignatureExtractor {
18651   static #PARAMETERS = {
18652     maxDim: 512,
18653     sigmaSFactor: 0.02,
18654     sigmaR: 25,
18655     kernelSize: 16
18656   };
18657   static #neighborIndexToId(i0, j0, i, j) {
18658     i -= i0;
18659     j -= j0;
18660     if (i === 0) {
18661       return j > 0 ? 0 : 4;
18662     }
18663     if (i === 1) {
18664       return j + 6;
18665     }
18666     return 2 - j;
18667   }
18668   static #neighborIdToIndex = new Int32Array([0, 1, -1, 1, -1, 0, -1, -1, 0, -1, 1, -1, 1, 0, 1, 1]);
18669   static #clockwiseNonZero(buf, width, i0, j0, i, j, offset) {
18670     const id = this.#neighborIndexToId(i0, j0, i, j);
18671     for (let k = 0; k < 8; k++) {
18672       const kk = (-k + id - offset + 16) % 8;
18673       const shiftI = this.#neighborIdToIndex[2 * kk];
18674       const shiftJ = this.#neighborIdToIndex[2 * kk + 1];
18675       if (buf[(i0 + shiftI) * width + (j0 + shiftJ)] !== 0) {
18676         return kk;
18677       }
18678     }
18679     return -1;
18680   }
18681   static #counterClockwiseNonZero(buf, width, i0, j0, i, j, offset) {
18682     const id = this.#neighborIndexToId(i0, j0, i, j);
18683     for (let k = 0; k < 8; k++) {
18684       const kk = (k + id + offset + 16) % 8;
18685       const shiftI = this.#neighborIdToIndex[2 * kk];
18686       const shiftJ = this.#neighborIdToIndex[2 * kk + 1];
18687       if (buf[(i0 + shiftI) * width + (j0 + shiftJ)] !== 0) {
18688         return kk;
18689       }
18690     }
18691     return -1;
18692   }
18693   static #findContours(buf, width, height, threshold) {
18694     const N = buf.length;
18695     const types = new Int32Array(N);
18696     for (let i = 0; i < N; i++) {
18697       types[i] = buf[i] <= threshold ? 1 : 0;
18698     }
18699     for (let i = 1; i < height - 1; i++) {
18700       types[i * width] = types[i * width + width - 1] = 0;
18701     }
18702     for (let i = 0; i < width; i++) {
18703       types[i] = types[width * height - 1 - i] = 0;
18704     }
18705     let nbd = 1;
18706     let lnbd;
18707     const contours = [];
18708     for (let i = 1; i < height - 1; i++) {
18709       lnbd = 1;
18710       for (let j = 1; j < width - 1; j++) {
18711         const ij = i * width + j;
18712         const pix = types[ij];
18713         if (pix === 0) {
18714           continue;
18715         }
18716         let i2 = i;
18717         let j2 = j;
18718         if (pix === 1 && types[ij - 1] === 0) {
18719           nbd += 1;
18720           j2 -= 1;
18721         } else if (pix >= 1 && types[ij + 1] === 0) {
18722           nbd += 1;
18723           j2 += 1;
18724           if (pix > 1) {
18725             lnbd = pix;
18726           }
18727         } else {
18728           if (pix !== 1) {
18729             lnbd = Math.abs(pix);
18730           }
18731           continue;
18732         }
18733         const points = [j, i];
18734         const isHole = j2 === j + 1;
18735         const contour = {
18736           isHole,
18737           points,
18738           id: nbd,
18739           parent: 0
18740         };
18741         contours.push(contour);
18742         let contour0;
18743         for (const c of contours) {
18744           if (c.id === lnbd) {
18745             contour0 = c;
18746             break;
18747           }
18748         }
18749         if (!contour0) {
18750           contour.parent = isHole ? lnbd : 0;
18751         } else if (contour0.isHole) {
18752           contour.parent = isHole ? contour0.parent : lnbd;
18753         } else {
18754           contour.parent = isHole ? lnbd : contour0.parent;
18755         }
18756         const k = this.#clockwiseNonZero(types, width, i, j, i2, j2, 0);
18757         if (k === -1) {
18758           types[ij] = -nbd;
18759           if (types[ij] !== 1) {
18760             lnbd = Math.abs(types[ij]);
18761           }
18762           continue;
18763         }
18764         let shiftI = this.#neighborIdToIndex[2 * k];
18765         let shiftJ = this.#neighborIdToIndex[2 * k + 1];
18766         const i1 = i + shiftI;
18767         const j1 = j + shiftJ;
18768         i2 = i1;
18769         j2 = j1;
18770         let i3 = i;
18771         let j3 = j;
18772         while (true) {
18773           const kk = this.#counterClockwiseNonZero(types, width, i3, j3, i2, j2, 1);
18774           shiftI = this.#neighborIdToIndex[2 * kk];
18775           shiftJ = this.#neighborIdToIndex[2 * kk + 1];
18776           const i4 = i3 + shiftI;
18777           const j4 = j3 + shiftJ;
18778           points.push(j4, i4);
18779           const ij3 = i3 * width + j3;
18780           if (types[ij3 + 1] === 0) {
18781             types[ij3] = -nbd;
18782           } else if (types[ij3] === 1) {
18783             types[ij3] = nbd;
18784           }
18785           if (i4 === i && j4 === j && i3 === i1 && j3 === j1) {
18786             if (types[ij] !== 1) {
18787               lnbd = Math.abs(types[ij]);
18788             }
18789             break;
18790           } else {
18791             i2 = i3;
18792             j2 = j3;
18793             i3 = i4;
18794             j3 = j4;
18795           }
18796         }
18797       }
18798     }
18799     return contours;
18800   }
18801   static #douglasPeuckerHelper(points, start, end, output) {
18802     if (end - start <= 4) {
18803       for (let i = start; i < end - 2; i += 2) {
18804         output.push(points[i], points[i + 1]);
18805       }
18806       return;
18807     }
18808     const ax = points[start];
18809     const ay = points[start + 1];
18810     const abx = points[end - 4] - ax;
18811     const aby = points[end - 3] - ay;
18812     const dist = Math.hypot(abx, aby);
18813     const nabx = abx / dist;
18814     const naby = aby / dist;
18815     const aa = nabx * ay - naby * ax;
18816     const m = aby / abx;
18817     const invS = 1 / dist;
18818     const phi = Math.atan(m);
18819     const cosPhi = Math.cos(phi);
18820     const sinPhi = Math.sin(phi);
18821     const tmax = invS * (Math.abs(cosPhi) + Math.abs(sinPhi));
18822     const poly = invS * (1 - tmax + tmax ** 2);
18823     const partialPhi = Math.max(Math.atan(Math.abs(sinPhi + cosPhi) * poly), Math.atan(Math.abs(sinPhi - cosPhi) * poly));
18824     let dmax = 0;
18825     let index = start;
18826     for (let i = start + 2; i < end - 2; i += 2) {
18827       const d = Math.abs(aa - nabx * points[i + 1] + naby * points[i]);
18828       if (d > dmax) {
18829         index = i;
18830         dmax = d;
18831       }
18832     }
18833     if (dmax > (dist * partialPhi) ** 2) {
18834       this.#douglasPeuckerHelper(points, start, index + 2, output);
18835       this.#douglasPeuckerHelper(points, index, end, output);
18836     } else {
18837       output.push(ax, ay);
18838     }
18839   }
18840   static #douglasPeucker(points) {
18841     const output = [];
18842     const len = points.length;
18843     this.#douglasPeuckerHelper(points, 0, len, output);
18844     output.push(points[len - 2], points[len - 1]);
18845     return output.length <= 4 ? null : output;
18846   }
18847   static #bilateralFilter(buf, width, height, sigmaS, sigmaR, kernelSize) {
18848     const kernel = new Float32Array(kernelSize ** 2);
18849     const sigmaS2 = -2 * sigmaS ** 2;
18850     const halfSize = kernelSize >> 1;
18851     for (let i = 0; i < kernelSize; i++) {
18852       const x = (i - halfSize) ** 2;
18853       for (let j = 0; j < kernelSize; j++) {
18854         kernel[i * kernelSize + j] = Math.exp((x + (j - halfSize) ** 2) / sigmaS2);
18855       }
18856     }
18857     const rangeValues = new Float32Array(256);
18858     const sigmaR2 = -2 * sigmaR ** 2;
18859     for (let i = 0; i < 256; i++) {
18860       rangeValues[i] = Math.exp(i ** 2 / sigmaR2);
18861     }
18862     const N = buf.length;
18863     const out = new Uint8Array(N);
18864     const histogram = new Uint32Array(256);
18865     for (let i = 0; i < height; i++) {
18866       for (let j = 0; j < width; j++) {
18867         const ij = i * width + j;
18868         const center = buf[ij];
18869         let sum = 0;
18870         let norm = 0;
18871         for (let k = 0; k < kernelSize; k++) {
18872           const y = i + k - halfSize;
18873           if (y < 0 || y >= height) {
18874             continue;
18875           }
18876           for (let l = 0; l < kernelSize; l++) {
18877             const x = j + l - halfSize;
18878             if (x < 0 || x >= width) {
18879               continue;
18880             }
18881             const neighbour = buf[y * width + x];
18882             const w = kernel[k * kernelSize + l] * rangeValues[Math.abs(neighbour - center)];
18883             sum += neighbour * w;
18884             norm += w;
18885           }
18886         }
18887         const pix = out[ij] = Math.round(sum / norm);
18888         histogram[pix]++;
18889       }
18890     }
18891     return [out, histogram];
18892   }
18893   static #getHistogram(buf) {
18894     const histogram = new Uint32Array(256);
18895     for (const g of buf) {
18896       histogram[g]++;
18897     }
18898     return histogram;
18899   }
18900   static #toUint8(buf) {
18901     const N = buf.length;
18902     const out = new Uint8ClampedArray(N >> 2);
18903     let max = -Infinity;
18904     let min = Infinity;
18905     for (let i = 0, ii = out.length; i < ii; i++) {
18906       const A = buf[(i << 2) + 3];
18907       if (A === 0) {
18908         max = out[i] = 0xff;
18909         continue;
18910       }
18911       const pix = out[i] = buf[i << 2];
18912       if (pix > max) {
18913         max = pix;
18914       }
18915       if (pix < min) {
18916         min = pix;
18917       }
18918     }
18919     const ratio = 255 / (max - min);
18920     for (let i = 0; i < N; i++) {
18921       out[i] = (out[i] - min) * ratio;
18922     }
18923     return out;
18924   }
18925   static #guessThreshold(histogram) {
18926     let i;
18927     let M = -Infinity;
18928     let L = -Infinity;
18929     const min = histogram.findIndex(v => v !== 0);
18930     let pos = min;
18931     let spos = min;
18932     for (i = min; i < 256; i++) {
18933       const v = histogram[i];
18934       if (v > M) {
18935         if (i - pos > L) {
18936           L = i - pos;
18937           spos = i - 1;
18938         }
18939         M = v;
18940         pos = i;
18941       }
18942     }
18943     for (i = spos - 1; i >= 0; i--) {
18944       if (histogram[i] > histogram[i + 1]) {
18945         break;
18946       }
18947     }
18948     return i;
18949   }
18950   static #getGrayPixels(bitmap) {
18951     const originalBitmap = bitmap;
18952     const {
18953       width,
18954       height
18955     } = bitmap;
18956     const {
18957       maxDim
18958     } = this.#PARAMETERS;
18959     let newWidth = width;
18960     let newHeight = height;
18961     if (width > maxDim || height > maxDim) {
18962       let prevWidth = width;
18963       let prevHeight = height;
18964       let steps = Math.log2(Math.max(width, height) / maxDim);
18965       const isteps = Math.floor(steps);
18966       steps = steps === isteps ? isteps - 1 : isteps;
18967       for (let i = 0; i < steps; i++) {
18968         newWidth = prevWidth;
18969         newHeight = prevHeight;
18970         if (newWidth > maxDim) {
18971           newWidth = Math.ceil(newWidth / 2);
18972         }
18973         if (newHeight > maxDim) {
18974           newHeight = Math.ceil(newHeight / 2);
18975         }
18976         const offscreen = new OffscreenCanvas(newWidth, newHeight);
18977         const ctx = offscreen.getContext("2d");
18978         ctx.drawImage(bitmap, 0, 0, prevWidth, prevHeight, 0, 0, newWidth, newHeight);
18979         prevWidth = newWidth;
18980         prevHeight = newHeight;
18981         if (bitmap !== originalBitmap) {
18982           bitmap.close();
18983         }
18984         bitmap = offscreen.transferToImageBitmap();
18985       }
18986       const ratio = Math.min(maxDim / newWidth, maxDim / newHeight);
18987       newWidth = Math.round(newWidth * ratio);
18988       newHeight = Math.round(newHeight * ratio);
18989     }
18990     const offscreen = new OffscreenCanvas(newWidth, newHeight);
18991     const ctx = offscreen.getContext("2d", {
18992       willReadFrequently: true
18993     });
18994     ctx.filter = "grayscale(1)";
18995     ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, newWidth, newHeight);
18996     const grayImage = ctx.getImageData(0, 0, newWidth, newHeight).data;
18997     const uint8Buf = this.#toUint8(grayImage);
18998     return [uint8Buf, newWidth, newHeight];
18999   }
19000   static extractContoursFromText(text, {
19001     fontFamily,
19002     fontStyle,
19003     fontWeight
19004   }, pageWidth, pageHeight, rotation, innerMargin) {
19005     let canvas = new OffscreenCanvas(1, 1);
19006     let ctx = canvas.getContext("2d", {
19007       alpha: false
19008     });
19009     const fontSize = 200;
19010     const font = ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
19011     const {
19012       actualBoundingBoxLeft,
19013       actualBoundingBoxRight,
19014       actualBoundingBoxAscent,
19015       actualBoundingBoxDescent,
19016       fontBoundingBoxAscent,
19017       fontBoundingBoxDescent,
19018       width
19019     } = ctx.measureText(text);
19020     const SCALE = 1.5;
19021     const canvasWidth = Math.ceil(Math.max(Math.abs(actualBoundingBoxLeft) + Math.abs(actualBoundingBoxRight) || 0, width) * SCALE);
19022     const canvasHeight = Math.ceil(Math.max(Math.abs(actualBoundingBoxAscent) + Math.abs(actualBoundingBoxDescent) || fontSize, Math.abs(fontBoundingBoxAscent) + Math.abs(fontBoundingBoxDescent) || fontSize) * SCALE);
19023     canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
19024     ctx = canvas.getContext("2d", {
19025       alpha: true,
19026       willReadFrequently: true
19027     });
19028     ctx.font = font;
19029     ctx.filter = "grayscale(1)";
19030     ctx.fillStyle = "white";
19031     ctx.fillRect(0, 0, canvasWidth, canvasHeight);
19032     ctx.fillStyle = "black";
19033     ctx.fillText(text, canvasWidth * (SCALE - 1) / 2, canvasHeight * (3 - SCALE) / 2);
19034     const uint8Buf = this.#toUint8(ctx.getImageData(0, 0, canvasWidth, canvasHeight).data);
19035     const histogram = this.#getHistogram(uint8Buf);
19036     const threshold = this.#guessThreshold(histogram);
19037     const contourList = this.#findContours(uint8Buf, canvasWidth, canvasHeight, threshold);
19038     return this.processDrawnLines({
19039       lines: {
19040         curves: contourList,
19041         width: canvasWidth,
19042         height: canvasHeight
19043       },
19044       pageWidth,
19045       pageHeight,
19046       rotation,
19047       innerMargin,
19048       mustSmooth: true,
19049       areContours: true
19050     });
19051   }
19052   static process(bitmap, pageWidth, pageHeight, rotation, innerMargin) {
19053     const [uint8Buf, width, height] = this.#getGrayPixels(bitmap);
19054     const [buffer, histogram] = this.#bilateralFilter(uint8Buf, width, height, Math.hypot(width, height) * this.#PARAMETERS.sigmaSFactor, this.#PARAMETERS.sigmaR, this.#PARAMETERS.kernelSize);
19055     const threshold = this.#guessThreshold(histogram);
19056     const contourList = this.#findContours(buffer, width, height, threshold);
19057     return this.processDrawnLines({
19058       lines: {
19059         curves: contourList,
19060         width,
19061         height
19062       },
19063       pageWidth,
19064       pageHeight,
19065       rotation,
19066       innerMargin,
19067       mustSmooth: true,
19068       areContours: true
19069     });
19070   }
19071   static processDrawnLines({
19072     lines,
19073     pageWidth,
19074     pageHeight,
19075     rotation,
19076     innerMargin,
19077     mustSmooth,
19078     areContours
19079   }) {
19080     if (rotation % 180 !== 0) {
19081       [pageWidth, pageHeight] = [pageHeight, pageWidth];
19082     }
19083     const {
19084       curves,
19085       thickness,
19086       width,
19087       height
19088     } = lines;
19089     const linesAndPoints = [];
19090     const ratio = Math.min(pageWidth / width, pageHeight / height);
19091     const xScale = ratio / pageWidth;
19092     const yScale = ratio / pageHeight;
19093     for (const {
19094       points
19095     } of curves) {
19096       const reducedPoints = mustSmooth ? this.#douglasPeucker(points) : points;
19097       if (!reducedPoints) {
19098         continue;
19099       }
19100       const len = reducedPoints.length;
19101       const newPoints = new Float32Array(len);
19102       const line = new Float32Array(3 * (len === 2 ? 2 : len - 2));
19103       linesAndPoints.push({
19104         line,
19105         points: newPoints
19106       });
19107       if (len === 2) {
19108         newPoints[0] = reducedPoints[0] * xScale;
19109         newPoints[1] = reducedPoints[1] * yScale;
19110         line.set([NaN, NaN, NaN, NaN, newPoints[0], newPoints[1]], 0);
19111         continue;
19112       }
19113       let [x1, y1, x2, y2] = reducedPoints;
19114       x1 *= xScale;
19115       y1 *= yScale;
19116       x2 *= xScale;
19117       y2 *= yScale;
19118       newPoints.set([x1, y1, x2, y2], 0);
19119       line.set([NaN, NaN, NaN, NaN, x1, y1], 0);
19120       for (let i = 4; i < len; i += 2) {
19121         const x = newPoints[i] = reducedPoints[i] * xScale;
19122         const y = newPoints[i + 1] = reducedPoints[i + 1] * yScale;
19123         line.set(Outline.createBezierPoints(x1, y1, x2, y2, x, y), (i - 2) * 3);
19124         [x1, y1, x2, y2] = [x2, y2, x, y];
19125       }
19126     }
19127     if (linesAndPoints.length === 0) {
19128       return null;
19129     }
19130     const outline = areContours ? new ContourDrawOutline() : new InkDrawOutline();
19131     outline.build(linesAndPoints, pageWidth, pageHeight, 1, rotation, areContours ? 0 : thickness, innerMargin);
19132     return outline;
19133   }
19136 ;// ./src/display/editor/signature.js
19143 class SignatureOptions extends DrawingOptions {
19144   constructor() {
19145     super();
19146     super.updateProperties({
19147       fill: "black",
19148       "stroke-width": 0
19149     });
19150   }
19151   clone() {
19152     const clone = new SignatureOptions();
19153     clone.updateAll(this);
19154     return clone;
19155   }
19157 class DrawnSignatureOptions extends InkDrawingOptions {
19158   constructor(viewerParameters) {
19159     super(viewerParameters);
19160     super.updateProperties({
19161       stroke: "black",
19162       "stroke-width": 1
19163     });
19164   }
19165   clone() {
19166     const clone = new DrawnSignatureOptions(this._viewParameters);
19167     clone.updateAll(this);
19168     return clone;
19169   }
19171 class SignatureEditor extends DrawingEditor {
19172   #isExtracted = false;
19173   static _type = "signature";
19174   static _editorType = AnnotationEditorType.SIGNATURE;
19175   static _defaultDrawingOptions = null;
19176   constructor(params) {
19177     super({
19178       ...params,
19179       mustBeCommitted: true,
19180       name: "signatureEditor"
19181     });
19182     this._willKeepAspectRatio = true;
19183   }
19184   static initialize(l10n, uiManager) {
19185     AnnotationEditor.initialize(l10n, uiManager);
19186     this._defaultDrawingOptions = new SignatureOptions();
19187     this._defaultDrawnSignatureOptions = new DrawnSignatureOptions(uiManager.viewParameters);
19188   }
19189   static getDefaultDrawingOptions(options) {
19190     const clone = this._defaultDrawingOptions.clone();
19191     clone.updateProperties(options);
19192     return clone;
19193   }
19194   static get supportMultipleDrawings() {
19195     return false;
19196   }
19197   static get typesMap() {
19198     return shadow(this, "typesMap", new Map());
19199   }
19200   static get isDrawer() {
19201     return false;
19202   }
19203   get isResizable() {
19204     return true;
19205   }
19206   onScaleChanging() {
19207     if (this._drawId === null) {
19208       return;
19209     }
19210     super.onScaleChanging();
19211   }
19212   render() {
19213     if (this.div) {
19214       return this.div;
19215     }
19216     super.render();
19217     this.div.hidden = true;
19218     this.div.setAttribute("role", "figure");
19219     this._uiManager.getSignature(this);
19220     return this.div;
19221   }
19222   addSignature(outline, heightInPage) {
19223     const {
19224       x: savedX,
19225       y: savedY
19226     } = this;
19227     this.#isExtracted = outline instanceof ContourDrawOutline;
19228     let drawingOptions;
19229     if (this.#isExtracted) {
19230       drawingOptions = SignatureEditor.getDefaultDrawingOptions();
19231     } else {
19232       drawingOptions = SignatureEditor._defaultDrawnSignatureOptions.clone();
19233       drawingOptions.updateProperties({
19234         "stroke-width": outline.thickness
19235       });
19236     }
19237     this._addOutlines({
19238       drawOutlines: outline,
19239       drawingOptions
19240     });
19241     const [parentWidth, parentHeight] = this.parentDimensions;
19242     const [, pageHeight] = this.pageDimensions;
19243     let newHeight = heightInPage / pageHeight;
19244     newHeight = newHeight >= 1 ? 0.5 : newHeight;
19245     this.width *= newHeight / this.height;
19246     this.height = newHeight;
19247     this.setDims(parentWidth * this.width, parentHeight * this.height);
19248     this.x = savedX;
19249     this.y = savedY;
19250     this.center();
19251     this._onResized();
19252     this.onScaleChanging();
19253     this.rotate();
19254     this._uiManager.addToAnnotationStorage(this);
19255     this.div.hidden = false;
19256   }
19257   getFromImage(bitmap) {
19258     const {
19259       rawDims: {
19260         pageWidth,
19261         pageHeight
19262       },
19263       rotation
19264     } = this.parent.viewport;
19265     return SignatureExtractor.process(bitmap, pageWidth, pageHeight, rotation, SignatureEditor._INNER_MARGIN);
19266   }
19267   getFromText(text, fontInfo) {
19268     const {
19269       rawDims: {
19270         pageWidth,
19271         pageHeight
19272       },
19273       rotation
19274     } = this.parent.viewport;
19275     return SignatureExtractor.extractContoursFromText(text, fontInfo, pageWidth, pageHeight, rotation, SignatureEditor._INNER_MARGIN);
19276   }
19277   getDrawnSignature(curves) {
19278     const {
19279       rawDims: {
19280         pageWidth,
19281         pageHeight
19282       },
19283       rotation
19284     } = this.parent.viewport;
19285     return SignatureExtractor.processDrawnLines({
19286       lines: curves,
19287       pageWidth,
19288       pageHeight,
19289       rotation,
19290       innerMargin: SignatureEditor._INNER_MARGIN,
19291       mustSmooth: false,
19292       areContours: false
19293     });
19294   }
19297 ;// ./src/display/editor/stamp.js
19302 class StampEditor extends AnnotationEditor {
19303   #bitmap = null;
19304   #bitmapId = null;
19305   #bitmapPromise = null;
19306   #bitmapUrl = null;
19307   #bitmapFile = null;
19308   #bitmapFileName = "";
19309   #canvas = null;
19310   #missingCanvas = false;
19311   #resizeTimeoutId = null;
19312   #isSvg = false;
19313   #hasBeenAddedInUndoStack = false;
19314   static _type = "stamp";
19315   static _editorType = AnnotationEditorType.STAMP;
19316   constructor(params) {
19317     super({
19318       ...params,
19319       name: "stampEditor"
19320     });
19321     this.#bitmapUrl = params.bitmapUrl;
19322     this.#bitmapFile = params.bitmapFile;
19323   }
19324   static initialize(l10n, uiManager) {
19325     AnnotationEditor.initialize(l10n, uiManager);
19326   }
19327   static isHandlingMimeForPasting(mime) {
19328     return SupportedImageMimeTypes.includes(mime);
19329   }
19330   static paste(item, parent) {
19331     parent.pasteEditor(AnnotationEditorType.STAMP, {
19332       bitmapFile: item.getAsFile()
19333     });
19334   }
19335   altTextFinish() {
19336     if (this._uiManager.useNewAltTextFlow) {
19337       this.div.hidden = false;
19338     }
19339     super.altTextFinish();
19340   }
19341   get telemetryFinalData() {
19342     return {
19343       type: "stamp",
19344       hasAltText: !!this.altTextData?.altText
19345     };
19346   }
19347   static computeTelemetryFinalData(data) {
19348     const hasAltTextStats = data.get("hasAltText");
19349     return {
19350       hasAltText: hasAltTextStats.get(true) ?? 0,
19351       hasNoAltText: hasAltTextStats.get(false) ?? 0
19352     };
19353   }
19354   #getBitmapFetched(data, fromId = false) {
19355     if (!data) {
19356       this.remove();
19357       return;
19358     }
19359     this.#bitmap = data.bitmap;
19360     if (!fromId) {
19361       this.#bitmapId = data.id;
19362       this.#isSvg = data.isSvg;
19363     }
19364     if (data.file) {
19365       this.#bitmapFileName = data.file.name;
19366     }
19367     this.#createCanvas();
19368   }
19369   #getBitmapDone() {
19370     this.#bitmapPromise = null;
19371     this._uiManager.enableWaiting(false);
19372     if (!this.#canvas) {
19373       return;
19374     }
19375     if (this._uiManager.useNewAltTextWhenAddingImage && this._uiManager.useNewAltTextFlow && this.#bitmap) {
19376       this._editToolbar.hide();
19377       this._uiManager.editAltText(this, true);
19378       return;
19379     }
19380     if (!this._uiManager.useNewAltTextWhenAddingImage && this._uiManager.useNewAltTextFlow && this.#bitmap) {
19381       this._reportTelemetry({
19382         action: "pdfjs.image.image_added",
19383         data: {
19384           alt_text_modal: false,
19385           alt_text_type: "empty"
19386         }
19387       });
19388       try {
19389         this.mlGuessAltText();
19390       } catch {}
19391     }
19392     this.div.focus();
19393   }
19394   async mlGuessAltText(imageData = null, updateAltTextData = true) {
19395     if (this.hasAltTextData()) {
19396       return null;
19397     }
19398     const {
19399       mlManager
19400     } = this._uiManager;
19401     if (!mlManager) {
19402       throw new Error("No ML.");
19403     }
19404     if (!(await mlManager.isEnabledFor("altText"))) {
19405       throw new Error("ML isn't enabled for alt text.");
19406     }
19407     const {
19408       data,
19409       width,
19410       height
19411     } = imageData || this.copyCanvas(null, null, true).imageData;
19412     const response = await mlManager.guess({
19413       name: "altText",
19414       request: {
19415         data,
19416         width,
19417         height,
19418         channels: data.length / (width * height)
19419       }
19420     });
19421     if (!response) {
19422       throw new Error("No response from the AI service.");
19423     }
19424     if (response.error) {
19425       throw new Error("Error from the AI service.");
19426     }
19427     if (response.cancel) {
19428       return null;
19429     }
19430     if (!response.output) {
19431       throw new Error("No valid response from the AI service.");
19432     }
19433     const altText = response.output;
19434     await this.setGuessedAltText(altText);
19435     if (updateAltTextData && !this.hasAltTextData()) {
19436       this.altTextData = {
19437         alt: altText,
19438         decorative: false
19439       };
19440     }
19441     return altText;
19442   }
19443   #getBitmap() {
19444     if (this.#bitmapId) {
19445       this._uiManager.enableWaiting(true);
19446       this._uiManager.imageManager.getFromId(this.#bitmapId).then(data => this.#getBitmapFetched(data, true)).finally(() => this.#getBitmapDone());
19447       return;
19448     }
19449     if (this.#bitmapUrl) {
19450       const url = this.#bitmapUrl;
19451       this.#bitmapUrl = null;
19452       this._uiManager.enableWaiting(true);
19453       this.#bitmapPromise = this._uiManager.imageManager.getFromUrl(url).then(data => this.#getBitmapFetched(data)).finally(() => this.#getBitmapDone());
19454       return;
19455     }
19456     if (this.#bitmapFile) {
19457       const file = this.#bitmapFile;
19458       this.#bitmapFile = null;
19459       this._uiManager.enableWaiting(true);
19460       this.#bitmapPromise = this._uiManager.imageManager.getFromFile(file).then(data => this.#getBitmapFetched(data)).finally(() => this.#getBitmapDone());
19461       return;
19462     }
19463     const input = document.createElement("input");
19464     input.type = "file";
19465     input.accept = SupportedImageMimeTypes.join(",");
19466     const signal = this._uiManager._signal;
19467     this.#bitmapPromise = new Promise(resolve => {
19468       input.addEventListener("change", async () => {
19469         if (!input.files || input.files.length === 0) {
19470           this.remove();
19471         } else {
19472           this._uiManager.enableWaiting(true);
19473           const data = await this._uiManager.imageManager.getFromFile(input.files[0]);
19474           this._reportTelemetry({
19475             action: "pdfjs.image.image_selected",
19476             data: {
19477               alt_text_modal: this._uiManager.useNewAltTextFlow
19478             }
19479           });
19480           this.#getBitmapFetched(data);
19481         }
19482         resolve();
19483       }, {
19484         signal
19485       });
19486       input.addEventListener("cancel", () => {
19487         this.remove();
19488         resolve();
19489       }, {
19490         signal
19491       });
19492     }).finally(() => this.#getBitmapDone());
19493     input.click();
19494   }
19495   remove() {
19496     if (this.#bitmapId) {
19497       this.#bitmap = null;
19498       this._uiManager.imageManager.deleteId(this.#bitmapId);
19499       this.#canvas?.remove();
19500       this.#canvas = null;
19501       if (this.#resizeTimeoutId) {
19502         clearTimeout(this.#resizeTimeoutId);
19503         this.#resizeTimeoutId = null;
19504       }
19505     }
19506     super.remove();
19507   }
19508   rebuild() {
19509     if (!this.parent) {
19510       if (this.#bitmapId) {
19511         this.#getBitmap();
19512       }
19513       return;
19514     }
19515     super.rebuild();
19516     if (this.div === null) {
19517       return;
19518     }
19519     if (this.#bitmapId && this.#canvas === null) {
19520       this.#getBitmap();
19521     }
19522     if (!this.isAttachedToDOM) {
19523       this.parent.add(this);
19524     }
19525   }
19526   onceAdded(focus) {
19527     this._isDraggable = true;
19528     if (focus) {
19529       this.div.focus();
19530     }
19531   }
19532   isEmpty() {
19533     return !(this.#bitmapPromise || this.#bitmap || this.#bitmapUrl || this.#bitmapFile || this.#bitmapId || this.#missingCanvas);
19534   }
19535   get isResizable() {
19536     return true;
19537   }
19538   render() {
19539     if (this.div) {
19540       return this.div;
19541     }
19542     let baseX, baseY;
19543     if (this.width) {
19544       baseX = this.x;
19545       baseY = this.y;
19546     }
19547     super.render();
19548     this.div.hidden = true;
19549     this.div.setAttribute("role", "figure");
19550     this.addAltTextButton();
19551     if (!this.#missingCanvas) {
19552       if (this.#bitmap) {
19553         this.#createCanvas();
19554       } else {
19555         this.#getBitmap();
19556       }
19557     }
19558     if (this.width && !this.annotationElementId) {
19559       const [parentWidth, parentHeight] = this.parentDimensions;
19560       this.setAt(baseX * parentWidth, baseY * parentHeight, this.width * parentWidth, this.height * parentHeight);
19561     }
19562     this._uiManager.addShouldRescale(this);
19563     return this.div;
19564   }
19565   setCanvas(annotationElementId, canvas) {
19566     const {
19567       id: bitmapId,
19568       bitmap
19569     } = this._uiManager.imageManager.getFromCanvas(annotationElementId, canvas);
19570     canvas.remove();
19571     if (bitmapId && this._uiManager.imageManager.isValidId(bitmapId)) {
19572       this.#bitmapId = bitmapId;
19573       if (bitmap) {
19574         this.#bitmap = bitmap;
19575       }
19576       this.#missingCanvas = false;
19577       this.#createCanvas();
19578     }
19579   }
19580   _onResized() {
19581     this.onScaleChanging();
19582   }
19583   onScaleChanging() {
19584     if (!this.parent) {
19585       return;
19586     }
19587     if (this.#resizeTimeoutId !== null) {
19588       clearTimeout(this.#resizeTimeoutId);
19589     }
19590     const TIME_TO_WAIT = 200;
19591     this.#resizeTimeoutId = setTimeout(() => {
19592       this.#resizeTimeoutId = null;
19593       this.#drawBitmap();
19594     }, TIME_TO_WAIT);
19595   }
19596   #createCanvas() {
19597     const {
19598       div
19599     } = this;
19600     let {
19601       width,
19602       height
19603     } = this.#bitmap;
19604     const [pageWidth, pageHeight] = this.pageDimensions;
19605     const MAX_RATIO = 0.75;
19606     if (this.width) {
19607       width = this.width * pageWidth;
19608       height = this.height * pageHeight;
19609     } else if (width > MAX_RATIO * pageWidth || height > MAX_RATIO * pageHeight) {
19610       const factor = Math.min(MAX_RATIO * pageWidth / width, MAX_RATIO * pageHeight / height);
19611       width *= factor;
19612       height *= factor;
19613     }
19614     const [parentWidth, parentHeight] = this.parentDimensions;
19615     this.setDims(width * parentWidth / pageWidth, height * parentHeight / pageHeight);
19616     this._uiManager.enableWaiting(false);
19617     const canvas = this.#canvas = document.createElement("canvas");
19618     canvas.setAttribute("role", "img");
19619     this.addContainer(canvas);
19620     this.width = width / pageWidth;
19621     this.height = height / pageHeight;
19622     if (this._initialOptions?.isCentered) {
19623       this.center();
19624     } else {
19625       this.fixAndSetPosition();
19626     }
19627     this._initialOptions = null;
19628     if (!this._uiManager.useNewAltTextWhenAddingImage || !this._uiManager.useNewAltTextFlow || this.annotationElementId) {
19629       div.hidden = false;
19630     }
19631     this.#drawBitmap();
19632     if (!this.#hasBeenAddedInUndoStack) {
19633       this.parent.addUndoableEditor(this);
19634       this.#hasBeenAddedInUndoStack = true;
19635     }
19636     this._reportTelemetry({
19637       action: "inserted_image"
19638     });
19639     if (this.#bitmapFileName) {
19640       canvas.setAttribute("aria-label", this.#bitmapFileName);
19641     }
19642   }
19643   copyCanvas(maxDataDimension, maxPreviewDimension, createImageData = false) {
19644     if (!maxDataDimension) {
19645       maxDataDimension = 224;
19646     }
19647     const {
19648       width: bitmapWidth,
19649       height: bitmapHeight
19650     } = this.#bitmap;
19651     const outputScale = new OutputScale();
19652     let bitmap = this.#bitmap;
19653     let width = bitmapWidth,
19654       height = bitmapHeight;
19655     let canvas = null;
19656     if (maxPreviewDimension) {
19657       if (bitmapWidth > maxPreviewDimension || bitmapHeight > maxPreviewDimension) {
19658         const ratio = Math.min(maxPreviewDimension / bitmapWidth, maxPreviewDimension / bitmapHeight);
19659         width = Math.floor(bitmapWidth * ratio);
19660         height = Math.floor(bitmapHeight * ratio);
19661       }
19662       canvas = document.createElement("canvas");
19663       const scaledWidth = canvas.width = Math.ceil(width * outputScale.sx);
19664       const scaledHeight = canvas.height = Math.ceil(height * outputScale.sy);
19665       if (!this.#isSvg) {
19666         bitmap = this.#scaleBitmap(scaledWidth, scaledHeight);
19667       }
19668       const ctx = canvas.getContext("2d");
19669       ctx.filter = this._uiManager.hcmFilter;
19670       let white = "white",
19671         black = "#cfcfd8";
19672       if (this._uiManager.hcmFilter !== "none") {
19673         black = "black";
19674       } else if (window.matchMedia?.("(prefers-color-scheme: dark)").matches) {
19675         white = "#8f8f9d";
19676         black = "#42414d";
19677       }
19678       const boxDim = 15;
19679       const boxDimWidth = boxDim * outputScale.sx;
19680       const boxDimHeight = boxDim * outputScale.sy;
19681       const pattern = new OffscreenCanvas(boxDimWidth * 2, boxDimHeight * 2);
19682       const patternCtx = pattern.getContext("2d");
19683       patternCtx.fillStyle = white;
19684       patternCtx.fillRect(0, 0, boxDimWidth * 2, boxDimHeight * 2);
19685       patternCtx.fillStyle = black;
19686       patternCtx.fillRect(0, 0, boxDimWidth, boxDimHeight);
19687       patternCtx.fillRect(boxDimWidth, boxDimHeight, boxDimWidth, boxDimHeight);
19688       ctx.fillStyle = ctx.createPattern(pattern, "repeat");
19689       ctx.fillRect(0, 0, scaledWidth, scaledHeight);
19690       ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, scaledWidth, scaledHeight);
19691     }
19692     let imageData = null;
19693     if (createImageData) {
19694       let dataWidth, dataHeight;
19695       if (outputScale.symmetric && bitmap.width < maxDataDimension && bitmap.height < maxDataDimension) {
19696         dataWidth = bitmap.width;
19697         dataHeight = bitmap.height;
19698       } else {
19699         bitmap = this.#bitmap;
19700         if (bitmapWidth > maxDataDimension || bitmapHeight > maxDataDimension) {
19701           const ratio = Math.min(maxDataDimension / bitmapWidth, maxDataDimension / bitmapHeight);
19702           dataWidth = Math.floor(bitmapWidth * ratio);
19703           dataHeight = Math.floor(bitmapHeight * ratio);
19704           if (!this.#isSvg) {
19705             bitmap = this.#scaleBitmap(dataWidth, dataHeight);
19706           }
19707         }
19708       }
19709       const offscreen = new OffscreenCanvas(dataWidth, dataHeight);
19710       const offscreenCtx = offscreen.getContext("2d", {
19711         willReadFrequently: true
19712       });
19713       offscreenCtx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, dataWidth, dataHeight);
19714       imageData = {
19715         width: dataWidth,
19716         height: dataHeight,
19717         data: offscreenCtx.getImageData(0, 0, dataWidth, dataHeight).data
19718       };
19719     }
19720     return {
19721       canvas,
19722       width,
19723       height,
19724       imageData
19725     };
19726   }
19727   #scaleBitmap(width, height) {
19728     const {
19729       width: bitmapWidth,
19730       height: bitmapHeight
19731     } = this.#bitmap;
19732     let newWidth = bitmapWidth;
19733     let newHeight = bitmapHeight;
19734     let bitmap = this.#bitmap;
19735     while (newWidth > 2 * width || newHeight > 2 * height) {
19736       const prevWidth = newWidth;
19737       const prevHeight = newHeight;
19738       if (newWidth > 2 * width) {
19739         newWidth = newWidth >= 16384 ? Math.floor(newWidth / 2) - 1 : Math.ceil(newWidth / 2);
19740       }
19741       if (newHeight > 2 * height) {
19742         newHeight = newHeight >= 16384 ? Math.floor(newHeight / 2) - 1 : Math.ceil(newHeight / 2);
19743       }
19744       const offscreen = new OffscreenCanvas(newWidth, newHeight);
19745       const ctx = offscreen.getContext("2d");
19746       ctx.drawImage(bitmap, 0, 0, prevWidth, prevHeight, 0, 0, newWidth, newHeight);
19747       bitmap = offscreen.transferToImageBitmap();
19748     }
19749     return bitmap;
19750   }
19751   #drawBitmap() {
19752     const [parentWidth, parentHeight] = this.parentDimensions;
19753     const {
19754       width,
19755       height
19756     } = this;
19757     const outputScale = new OutputScale();
19758     const scaledWidth = Math.ceil(width * parentWidth * outputScale.sx);
19759     const scaledHeight = Math.ceil(height * parentHeight * outputScale.sy);
19760     const canvas = this.#canvas;
19761     if (!canvas || canvas.width === scaledWidth && canvas.height === scaledHeight) {
19762       return;
19763     }
19764     canvas.width = scaledWidth;
19765     canvas.height = scaledHeight;
19766     const bitmap = this.#isSvg ? this.#bitmap : this.#scaleBitmap(scaledWidth, scaledHeight);
19767     const ctx = canvas.getContext("2d");
19768     ctx.filter = this._uiManager.hcmFilter;
19769     ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, scaledWidth, scaledHeight);
19770   }
19771   getImageForAltText() {
19772     return this.#canvas;
19773   }
19774   #serializeBitmap(toUrl) {
19775     if (toUrl) {
19776       if (this.#isSvg) {
19777         const url = this._uiManager.imageManager.getSvgUrl(this.#bitmapId);
19778         if (url) {
19779           return url;
19780         }
19781       }
19782       const canvas = document.createElement("canvas");
19783       ({
19784         width: canvas.width,
19785         height: canvas.height
19786       } = this.#bitmap);
19787       const ctx = canvas.getContext("2d");
19788       ctx.drawImage(this.#bitmap, 0, 0);
19789       return canvas.toDataURL();
19790     }
19791     if (this.#isSvg) {
19792       const [pageWidth, pageHeight] = this.pageDimensions;
19793       const width = Math.round(this.width * pageWidth * PixelsPerInch.PDF_TO_CSS_UNITS);
19794       const height = Math.round(this.height * pageHeight * PixelsPerInch.PDF_TO_CSS_UNITS);
19795       const offscreen = new OffscreenCanvas(width, height);
19796       const ctx = offscreen.getContext("2d");
19797       ctx.drawImage(this.#bitmap, 0, 0, this.#bitmap.width, this.#bitmap.height, 0, 0, width, height);
19798       return offscreen.transferToImageBitmap();
19799     }
19800     return structuredClone(this.#bitmap);
19801   }
19802   static async deserialize(data, parent, uiManager) {
19803     let initialData = null;
19804     let missingCanvas = false;
19805     if (data instanceof StampAnnotationElement) {
19806       const {
19807         data: {
19808           rect,
19809           rotation,
19810           id,
19811           structParent,
19812           popupRef
19813         },
19814         container,
19815         parent: {
19816           page: {
19817             pageNumber
19818           }
19819         },
19820         canvas
19821       } = data;
19822       let bitmapId, bitmap;
19823       if (canvas) {
19824         delete data.canvas;
19825         ({
19826           id: bitmapId,
19827           bitmap
19828         } = uiManager.imageManager.getFromCanvas(container.id, canvas));
19829         canvas.remove();
19830       } else {
19831         missingCanvas = true;
19832         data._hasNoCanvas = true;
19833       }
19834       const altText = (await parent._structTree.getAriaAttributes(`${AnnotationPrefix}${id}`))?.get("aria-label") || "";
19835       initialData = data = {
19836         annotationType: AnnotationEditorType.STAMP,
19837         bitmapId,
19838         bitmap,
19839         pageIndex: pageNumber - 1,
19840         rect: rect.slice(0),
19841         rotation,
19842         id,
19843         deleted: false,
19844         accessibilityData: {
19845           decorative: false,
19846           altText
19847         },
19848         isSvg: false,
19849         structParent,
19850         popupRef
19851       };
19852     }
19853     const editor = await super.deserialize(data, parent, uiManager);
19854     const {
19855       rect,
19856       bitmap,
19857       bitmapUrl,
19858       bitmapId,
19859       isSvg,
19860       accessibilityData
19861     } = data;
19862     if (missingCanvas) {
19863       uiManager.addMissingCanvas(data.id, editor);
19864       editor.#missingCanvas = true;
19865     } else if (bitmapId && uiManager.imageManager.isValidId(bitmapId)) {
19866       editor.#bitmapId = bitmapId;
19867       if (bitmap) {
19868         editor.#bitmap = bitmap;
19869       }
19870     } else {
19871       editor.#bitmapUrl = bitmapUrl;
19872     }
19873     editor.#isSvg = isSvg;
19874     const [parentWidth, parentHeight] = editor.pageDimensions;
19875     editor.width = (rect[2] - rect[0]) / parentWidth;
19876     editor.height = (rect[3] - rect[1]) / parentHeight;
19877     editor.annotationElementId = data.id || null;
19878     if (accessibilityData) {
19879       editor.altTextData = accessibilityData;
19880     }
19881     editor._initialData = initialData;
19882     editor.#hasBeenAddedInUndoStack = !!initialData;
19883     return editor;
19884   }
19885   serialize(isForCopying = false, context = null) {
19886     if (this.isEmpty()) {
19887       return null;
19888     }
19889     if (this.deleted) {
19890       return this.serializeDeleted();
19891     }
19892     const serialized = {
19893       annotationType: AnnotationEditorType.STAMP,
19894       bitmapId: this.#bitmapId,
19895       pageIndex: this.pageIndex,
19896       rect: this.getRect(0, 0),
19897       rotation: this.rotation,
19898       isSvg: this.#isSvg,
19899       structTreeParentId: this._structTreeParentId
19900     };
19901     if (isForCopying) {
19902       serialized.bitmapUrl = this.#serializeBitmap(true);
19903       serialized.accessibilityData = this.serializeAltText(true);
19904       return serialized;
19905     }
19906     const {
19907       decorative,
19908       altText
19909     } = this.serializeAltText(false);
19910     if (!decorative && altText) {
19911       serialized.accessibilityData = {
19912         type: "Figure",
19913         alt: altText
19914       };
19915     }
19916     if (this.annotationElementId) {
19917       const changes = this.#hasElementChanged(serialized);
19918       if (changes.isSame) {
19919         return null;
19920       }
19921       if (changes.isSameAltText) {
19922         delete serialized.accessibilityData;
19923       } else {
19924         serialized.accessibilityData.structParent = this._initialData.structParent ?? -1;
19925       }
19926     }
19927     serialized.id = this.annotationElementId;
19928     if (context === null) {
19929       return serialized;
19930     }
19931     context.stamps ||= new Map();
19932     const area = this.#isSvg ? (serialized.rect[2] - serialized.rect[0]) * (serialized.rect[3] - serialized.rect[1]) : null;
19933     if (!context.stamps.has(this.#bitmapId)) {
19934       context.stamps.set(this.#bitmapId, {
19935         area,
19936         serialized
19937       });
19938       serialized.bitmap = this.#serializeBitmap(false);
19939     } else if (this.#isSvg) {
19940       const prevData = context.stamps.get(this.#bitmapId);
19941       if (area > prevData.area) {
19942         prevData.area = area;
19943         prevData.serialized.bitmap.close();
19944         prevData.serialized.bitmap = this.#serializeBitmap(false);
19945       }
19946     }
19947     return serialized;
19948   }
19949   #hasElementChanged(serialized) {
19950     const {
19951       pageIndex,
19952       accessibilityData: {
19953         altText
19954       }
19955     } = this._initialData;
19956     const isSamePageIndex = serialized.pageIndex === pageIndex;
19957     const isSameAltText = (serialized.accessibilityData?.alt || "") === altText;
19958     return {
19959       isSame: !this._hasBeenMoved && !this._hasBeenResized && isSamePageIndex && isSameAltText,
19960       isSameAltText
19961     };
19962   }
19963   renderAnnotationElement(annotation) {
19964     annotation.updateEdited({
19965       rect: this.getRect(0, 0)
19966     });
19967     return null;
19968   }
19971 ;// ./src/display/editor/annotation_editor_layer.js
19980 class AnnotationEditorLayer {
19981   #accessibilityManager;
19982   #allowClick = false;
19983   #annotationLayer = null;
19984   #clickAC = null;
19985   #editorFocusTimeoutId = null;
19986   #editors = new Map();
19987   #hadPointerDown = false;
19988   #isDisabling = false;
19989   #isEnabling = false;
19990   #drawingAC = null;
19991   #focusedElement = null;
19992   #textLayer = null;
19993   #textSelectionAC = null;
19994   #uiManager;
19995   static _initialized = false;
19996   static #editorTypes = new Map([FreeTextEditor, InkEditor, StampEditor, HighlightEditor, SignatureEditor].map(type => [type._editorType, type]));
19997   constructor({
19998     uiManager,
19999     pageIndex,
20000     div,
20001     structTreeLayer,
20002     accessibilityManager,
20003     annotationLayer,
20004     drawLayer,
20005     textLayer,
20006     viewport,
20007     l10n
20008   }) {
20009     const editorTypes = [...AnnotationEditorLayer.#editorTypes.values()];
20010     if (!AnnotationEditorLayer._initialized) {
20011       AnnotationEditorLayer._initialized = true;
20012       for (const editorType of editorTypes) {
20013         editorType.initialize(l10n, uiManager);
20014       }
20015     }
20016     uiManager.registerEditorTypes(editorTypes);
20017     this.#uiManager = uiManager;
20018     this.pageIndex = pageIndex;
20019     this.div = div;
20020     this.#accessibilityManager = accessibilityManager;
20021     this.#annotationLayer = annotationLayer;
20022     this.viewport = viewport;
20023     this.#textLayer = textLayer;
20024     this.drawLayer = drawLayer;
20025     this._structTree = structTreeLayer;
20026     this.#uiManager.addLayer(this);
20027   }
20028   get isEmpty() {
20029     return this.#editors.size === 0;
20030   }
20031   get isInvisible() {
20032     return this.isEmpty && this.#uiManager.getMode() === AnnotationEditorType.NONE;
20033   }
20034   updateToolbar(mode) {
20035     this.#uiManager.updateToolbar(mode);
20036   }
20037   updateMode(mode = this.#uiManager.getMode()) {
20038     this.#cleanup();
20039     switch (mode) {
20040       case AnnotationEditorType.NONE:
20041         this.disableTextSelection();
20042         this.togglePointerEvents(false);
20043         this.toggleAnnotationLayerPointerEvents(true);
20044         this.disableClick();
20045         return;
20046       case AnnotationEditorType.INK:
20047         this.disableTextSelection();
20048         this.togglePointerEvents(true);
20049         this.enableClick();
20050         break;
20051       case AnnotationEditorType.HIGHLIGHT:
20052         this.enableTextSelection();
20053         this.togglePointerEvents(false);
20054         this.disableClick();
20055         break;
20056       default:
20057         this.disableTextSelection();
20058         this.togglePointerEvents(true);
20059         this.enableClick();
20060     }
20061     this.toggleAnnotationLayerPointerEvents(false);
20062     const {
20063       classList
20064     } = this.div;
20065     for (const editorType of AnnotationEditorLayer.#editorTypes.values()) {
20066       classList.toggle(`${editorType._type}Editing`, mode === editorType._editorType);
20067     }
20068     this.div.hidden = false;
20069   }
20070   hasTextLayer(textLayer) {
20071     return textLayer === this.#textLayer?.div;
20072   }
20073   setEditingState(isEditing) {
20074     this.#uiManager.setEditingState(isEditing);
20075   }
20076   addCommands(params) {
20077     this.#uiManager.addCommands(params);
20078   }
20079   cleanUndoStack(type) {
20080     this.#uiManager.cleanUndoStack(type);
20081   }
20082   toggleDrawing(enabled = false) {
20083     this.div.classList.toggle("drawing", !enabled);
20084   }
20085   togglePointerEvents(enabled = false) {
20086     this.div.classList.toggle("disabled", !enabled);
20087   }
20088   toggleAnnotationLayerPointerEvents(enabled = false) {
20089     this.#annotationLayer?.div.classList.toggle("disabled", !enabled);
20090   }
20091   async enable() {
20092     this.#isEnabling = true;
20093     this.div.tabIndex = 0;
20094     this.togglePointerEvents(true);
20095     const annotationElementIds = new Set();
20096     for (const editor of this.#editors.values()) {
20097       editor.enableEditing();
20098       editor.show(true);
20099       if (editor.annotationElementId) {
20100         this.#uiManager.removeChangedExistingAnnotation(editor);
20101         annotationElementIds.add(editor.annotationElementId);
20102       }
20103     }
20104     if (!this.#annotationLayer) {
20105       this.#isEnabling = false;
20106       return;
20107     }
20108     const editables = this.#annotationLayer.getEditableAnnotations();
20109     for (const editable of editables) {
20110       editable.hide();
20111       if (this.#uiManager.isDeletedAnnotationElement(editable.data.id)) {
20112         continue;
20113       }
20114       if (annotationElementIds.has(editable.data.id)) {
20115         continue;
20116       }
20117       const editor = await this.deserialize(editable);
20118       if (!editor) {
20119         continue;
20120       }
20121       this.addOrRebuild(editor);
20122       editor.enableEditing();
20123     }
20124     this.#isEnabling = false;
20125   }
20126   disable() {
20127     this.#isDisabling = true;
20128     this.div.tabIndex = -1;
20129     this.togglePointerEvents(false);
20130     const changedAnnotations = new Map();
20131     const resetAnnotations = new Map();
20132     for (const editor of this.#editors.values()) {
20133       editor.disableEditing();
20134       if (!editor.annotationElementId) {
20135         continue;
20136       }
20137       if (editor.serialize() !== null) {
20138         changedAnnotations.set(editor.annotationElementId, editor);
20139         continue;
20140       } else {
20141         resetAnnotations.set(editor.annotationElementId, editor);
20142       }
20143       this.getEditableAnnotation(editor.annotationElementId)?.show();
20144       editor.remove();
20145     }
20146     if (this.#annotationLayer) {
20147       const editables = this.#annotationLayer.getEditableAnnotations();
20148       for (const editable of editables) {
20149         const {
20150           id
20151         } = editable.data;
20152         if (this.#uiManager.isDeletedAnnotationElement(id)) {
20153           continue;
20154         }
20155         let editor = resetAnnotations.get(id);
20156         if (editor) {
20157           editor.resetAnnotationElement(editable);
20158           editor.show(false);
20159           editable.show();
20160           continue;
20161         }
20162         editor = changedAnnotations.get(id);
20163         if (editor) {
20164           this.#uiManager.addChangedExistingAnnotation(editor);
20165           if (editor.renderAnnotationElement(editable)) {
20166             editor.show(false);
20167           }
20168         }
20169         editable.show();
20170       }
20171     }
20172     this.#cleanup();
20173     if (this.isEmpty) {
20174       this.div.hidden = true;
20175     }
20176     const {
20177       classList
20178     } = this.div;
20179     for (const editorType of AnnotationEditorLayer.#editorTypes.values()) {
20180       classList.remove(`${editorType._type}Editing`);
20181     }
20182     this.disableTextSelection();
20183     this.toggleAnnotationLayerPointerEvents(true);
20184     this.#isDisabling = false;
20185   }
20186   getEditableAnnotation(id) {
20187     return this.#annotationLayer?.getEditableAnnotation(id) || null;
20188   }
20189   setActiveEditor(editor) {
20190     const currentActive = this.#uiManager.getActive();
20191     if (currentActive === editor) {
20192       return;
20193     }
20194     this.#uiManager.setActiveEditor(editor);
20195   }
20196   enableTextSelection() {
20197     this.div.tabIndex = -1;
20198     if (this.#textLayer?.div && !this.#textSelectionAC) {
20199       this.#textSelectionAC = new AbortController();
20200       const signal = this.#uiManager.combinedSignal(this.#textSelectionAC);
20201       this.#textLayer.div.addEventListener("pointerdown", this.#textLayerPointerDown.bind(this), {
20202         signal
20203       });
20204       this.#textLayer.div.classList.add("highlighting");
20205     }
20206   }
20207   disableTextSelection() {
20208     this.div.tabIndex = 0;
20209     if (this.#textLayer?.div && this.#textSelectionAC) {
20210       this.#textSelectionAC.abort();
20211       this.#textSelectionAC = null;
20212       this.#textLayer.div.classList.remove("highlighting");
20213     }
20214   }
20215   #textLayerPointerDown(event) {
20216     this.#uiManager.unselectAll();
20217     const {
20218       target
20219     } = event;
20220     if (target === this.#textLayer.div || (target.getAttribute("role") === "img" || target.classList.contains("endOfContent")) && this.#textLayer.div.contains(target)) {
20221       const {
20222         isMac
20223       } = util_FeatureTest.platform;
20224       if (event.button !== 0 || event.ctrlKey && isMac) {
20225         return;
20226       }
20227       this.#uiManager.showAllEditors("highlight", true, true);
20228       this.#textLayer.div.classList.add("free");
20229       this.toggleDrawing();
20230       HighlightEditor.startHighlighting(this, this.#uiManager.direction === "ltr", {
20231         target: this.#textLayer.div,
20232         x: event.x,
20233         y: event.y
20234       });
20235       this.#textLayer.div.addEventListener("pointerup", () => {
20236         this.#textLayer.div.classList.remove("free");
20237         this.toggleDrawing(true);
20238       }, {
20239         once: true,
20240         signal: this.#uiManager._signal
20241       });
20242       event.preventDefault();
20243     }
20244   }
20245   enableClick() {
20246     if (this.#clickAC) {
20247       return;
20248     }
20249     this.#clickAC = new AbortController();
20250     const signal = this.#uiManager.combinedSignal(this.#clickAC);
20251     this.div.addEventListener("pointerdown", this.pointerdown.bind(this), {
20252       signal
20253     });
20254     const pointerup = this.pointerup.bind(this);
20255     this.div.addEventListener("pointerup", pointerup, {
20256       signal
20257     });
20258     this.div.addEventListener("pointercancel", pointerup, {
20259       signal
20260     });
20261   }
20262   disableClick() {
20263     this.#clickAC?.abort();
20264     this.#clickAC = null;
20265   }
20266   attach(editor) {
20267     this.#editors.set(editor.id, editor);
20268     const {
20269       annotationElementId
20270     } = editor;
20271     if (annotationElementId && this.#uiManager.isDeletedAnnotationElement(annotationElementId)) {
20272       this.#uiManager.removeDeletedAnnotationElement(editor);
20273     }
20274   }
20275   detach(editor) {
20276     this.#editors.delete(editor.id);
20277     this.#accessibilityManager?.removePointerInTextLayer(editor.contentDiv);
20278     if (!this.#isDisabling && editor.annotationElementId) {
20279       this.#uiManager.addDeletedAnnotationElement(editor);
20280     }
20281   }
20282   remove(editor) {
20283     this.detach(editor);
20284     this.#uiManager.removeEditor(editor);
20285     editor.div.remove();
20286     editor.isAttachedToDOM = false;
20287   }
20288   changeParent(editor) {
20289     if (editor.parent === this) {
20290       return;
20291     }
20292     if (editor.parent && editor.annotationElementId) {
20293       this.#uiManager.addDeletedAnnotationElement(editor.annotationElementId);
20294       AnnotationEditor.deleteAnnotationElement(editor);
20295       editor.annotationElementId = null;
20296     }
20297     this.attach(editor);
20298     editor.parent?.detach(editor);
20299     editor.setParent(this);
20300     if (editor.div && editor.isAttachedToDOM) {
20301       editor.div.remove();
20302       this.div.append(editor.div);
20303     }
20304   }
20305   add(editor) {
20306     if (editor.parent === this && editor.isAttachedToDOM) {
20307       return;
20308     }
20309     this.changeParent(editor);
20310     this.#uiManager.addEditor(editor);
20311     this.attach(editor);
20312     if (!editor.isAttachedToDOM) {
20313       const div = editor.render();
20314       this.div.append(div);
20315       editor.isAttachedToDOM = true;
20316     }
20317     editor.fixAndSetPosition();
20318     editor.onceAdded(!this.#isEnabling);
20319     this.#uiManager.addToAnnotationStorage(editor);
20320     editor._reportTelemetry(editor.telemetryInitialData);
20321   }
20322   moveEditorInDOM(editor) {
20323     if (!editor.isAttachedToDOM) {
20324       return;
20325     }
20326     const {
20327       activeElement
20328     } = document;
20329     if (editor.div.contains(activeElement) && !this.#editorFocusTimeoutId) {
20330       editor._focusEventsAllowed = false;
20331       this.#editorFocusTimeoutId = setTimeout(() => {
20332         this.#editorFocusTimeoutId = null;
20333         if (!editor.div.contains(document.activeElement)) {
20334           editor.div.addEventListener("focusin", () => {
20335             editor._focusEventsAllowed = true;
20336           }, {
20337             once: true,
20338             signal: this.#uiManager._signal
20339           });
20340           activeElement.focus();
20341         } else {
20342           editor._focusEventsAllowed = true;
20343         }
20344       }, 0);
20345     }
20346     editor._structTreeParentId = this.#accessibilityManager?.moveElementInDOM(this.div, editor.div, editor.contentDiv, true);
20347   }
20348   addOrRebuild(editor) {
20349     if (editor.needsToBeRebuilt()) {
20350       editor.parent ||= this;
20351       editor.rebuild();
20352       editor.show();
20353     } else {
20354       this.add(editor);
20355     }
20356   }
20357   addUndoableEditor(editor) {
20358     const cmd = () => editor._uiManager.rebuild(editor);
20359     const undo = () => {
20360       editor.remove();
20361     };
20362     this.addCommands({
20363       cmd,
20364       undo,
20365       mustExec: false
20366     });
20367   }
20368   getNextId() {
20369     return this.#uiManager.getId();
20370   }
20371   get #currentEditorType() {
20372     return AnnotationEditorLayer.#editorTypes.get(this.#uiManager.getMode());
20373   }
20374   combinedSignal(ac) {
20375     return this.#uiManager.combinedSignal(ac);
20376   }
20377   #createNewEditor(params) {
20378     const editorType = this.#currentEditorType;
20379     return editorType ? new editorType.prototype.constructor(params) : null;
20380   }
20381   canCreateNewEmptyEditor() {
20382     return this.#currentEditorType?.canCreateNewEmptyEditor();
20383   }
20384   pasteEditor(mode, params) {
20385     this.#uiManager.updateToolbar(mode);
20386     this.#uiManager.updateMode(mode);
20387     const {
20388       offsetX,
20389       offsetY
20390     } = this.#getCenterPoint();
20391     const id = this.getNextId();
20392     const editor = this.#createNewEditor({
20393       parent: this,
20394       id,
20395       x: offsetX,
20396       y: offsetY,
20397       uiManager: this.#uiManager,
20398       isCentered: true,
20399       ...params
20400     });
20401     if (editor) {
20402       this.add(editor);
20403     }
20404   }
20405   async deserialize(data) {
20406     return (await AnnotationEditorLayer.#editorTypes.get(data.annotationType ?? data.annotationEditorType)?.deserialize(data, this, this.#uiManager)) || null;
20407   }
20408   createAndAddNewEditor(event, isCentered, data = {}) {
20409     const id = this.getNextId();
20410     const editor = this.#createNewEditor({
20411       parent: this,
20412       id,
20413       x: event.offsetX,
20414       y: event.offsetY,
20415       uiManager: this.#uiManager,
20416       isCentered,
20417       ...data
20418     });
20419     if (editor) {
20420       this.add(editor);
20421     }
20422     return editor;
20423   }
20424   #getCenterPoint() {
20425     const {
20426       x,
20427       y,
20428       width,
20429       height
20430     } = this.div.getBoundingClientRect();
20431     const tlX = Math.max(0, x);
20432     const tlY = Math.max(0, y);
20433     const brX = Math.min(window.innerWidth, x + width);
20434     const brY = Math.min(window.innerHeight, y + height);
20435     const centerX = (tlX + brX) / 2 - x;
20436     const centerY = (tlY + brY) / 2 - y;
20437     const [offsetX, offsetY] = this.viewport.rotation % 180 === 0 ? [centerX, centerY] : [centerY, centerX];
20438     return {
20439       offsetX,
20440       offsetY
20441     };
20442   }
20443   addNewEditor() {
20444     this.createAndAddNewEditor(this.#getCenterPoint(), true);
20445   }
20446   setSelected(editor) {
20447     this.#uiManager.setSelected(editor);
20448   }
20449   toggleSelected(editor) {
20450     this.#uiManager.toggleSelected(editor);
20451   }
20452   unselect(editor) {
20453     this.#uiManager.unselect(editor);
20454   }
20455   pointerup(event) {
20456     const {
20457       isMac
20458     } = util_FeatureTest.platform;
20459     if (event.button !== 0 || event.ctrlKey && isMac) {
20460       return;
20461     }
20462     if (event.target !== this.div) {
20463       return;
20464     }
20465     if (!this.#hadPointerDown) {
20466       return;
20467     }
20468     this.#hadPointerDown = false;
20469     if (this.#currentEditorType?.isDrawer && this.#currentEditorType.supportMultipleDrawings) {
20470       return;
20471     }
20472     if (!this.#allowClick) {
20473       this.#allowClick = true;
20474       return;
20475     }
20476     const currentMode = this.#uiManager.getMode();
20477     if (currentMode === AnnotationEditorType.STAMP || currentMode === AnnotationEditorType.SIGNATURE) {
20478       this.#uiManager.unselectAll();
20479       return;
20480     }
20481     this.createAndAddNewEditor(event, false);
20482   }
20483   pointerdown(event) {
20484     if (this.#uiManager.getMode() === AnnotationEditorType.HIGHLIGHT) {
20485       this.enableTextSelection();
20486     }
20487     if (this.#hadPointerDown) {
20488       this.#hadPointerDown = false;
20489       return;
20490     }
20491     const {
20492       isMac
20493     } = util_FeatureTest.platform;
20494     if (event.button !== 0 || event.ctrlKey && isMac) {
20495       return;
20496     }
20497     if (event.target !== this.div) {
20498       return;
20499     }
20500     this.#hadPointerDown = true;
20501     if (this.#currentEditorType?.isDrawer) {
20502       this.startDrawingSession(event);
20503       return;
20504     }
20505     const editor = this.#uiManager.getActive();
20506     this.#allowClick = !editor || editor.isEmpty();
20507   }
20508   startDrawingSession(event) {
20509     this.div.focus({
20510       preventScroll: true
20511     });
20512     if (this.#drawingAC) {
20513       this.#currentEditorType.startDrawing(this, this.#uiManager, false, event);
20514       return;
20515     }
20516     this.#uiManager.setCurrentDrawingSession(this);
20517     this.#drawingAC = new AbortController();
20518     const signal = this.#uiManager.combinedSignal(this.#drawingAC);
20519     this.div.addEventListener("blur", ({
20520       relatedTarget
20521     }) => {
20522       if (relatedTarget && !this.div.contains(relatedTarget)) {
20523         this.#focusedElement = null;
20524         this.commitOrRemove();
20525       }
20526     }, {
20527       signal
20528     });
20529     this.#currentEditorType.startDrawing(this, this.#uiManager, false, event);
20530   }
20531   pause(on) {
20532     if (on) {
20533       const {
20534         activeElement
20535       } = document;
20536       if (this.div.contains(activeElement)) {
20537         this.#focusedElement = activeElement;
20538       }
20539       return;
20540     }
20541     if (this.#focusedElement) {
20542       setTimeout(() => {
20543         this.#focusedElement?.focus();
20544         this.#focusedElement = null;
20545       }, 0);
20546     }
20547   }
20548   endDrawingSession(isAborted = false) {
20549     if (!this.#drawingAC) {
20550       return null;
20551     }
20552     this.#uiManager.setCurrentDrawingSession(null);
20553     this.#drawingAC.abort();
20554     this.#drawingAC = null;
20555     this.#focusedElement = null;
20556     return this.#currentEditorType.endDrawing(isAborted);
20557   }
20558   findNewParent(editor, x, y) {
20559     const layer = this.#uiManager.findParent(x, y);
20560     if (layer === null || layer === this) {
20561       return false;
20562     }
20563     layer.changeParent(editor);
20564     return true;
20565   }
20566   commitOrRemove() {
20567     if (this.#drawingAC) {
20568       this.endDrawingSession();
20569       return true;
20570     }
20571     return false;
20572   }
20573   onScaleChanging() {
20574     if (!this.#drawingAC) {
20575       return;
20576     }
20577     this.#currentEditorType.onScaleChangingWhenDrawing(this);
20578   }
20579   destroy() {
20580     this.commitOrRemove();
20581     if (this.#uiManager.getActive()?.parent === this) {
20582       this.#uiManager.commitOrRemove();
20583       this.#uiManager.setActiveEditor(null);
20584     }
20585     if (this.#editorFocusTimeoutId) {
20586       clearTimeout(this.#editorFocusTimeoutId);
20587       this.#editorFocusTimeoutId = null;
20588     }
20589     for (const editor of this.#editors.values()) {
20590       this.#accessibilityManager?.removePointerInTextLayer(editor.contentDiv);
20591       editor.setParent(null);
20592       editor.isAttachedToDOM = false;
20593       editor.div.remove();
20594     }
20595     this.div = null;
20596     this.#editors.clear();
20597     this.#uiManager.removeLayer(this);
20598   }
20599   #cleanup() {
20600     for (const editor of this.#editors.values()) {
20601       if (editor.isEmpty()) {
20602         editor.remove();
20603       }
20604     }
20605   }
20606   render({
20607     viewport
20608   }) {
20609     this.viewport = viewport;
20610     setLayerDimensions(this.div, viewport);
20611     for (const editor of this.#uiManager.getEditors(this.pageIndex)) {
20612       this.add(editor);
20613       editor.rebuild();
20614     }
20615     this.updateMode();
20616   }
20617   update({
20618     viewport
20619   }) {
20620     this.#uiManager.commitOrRemove();
20621     this.#cleanup();
20622     const oldRotation = this.viewport.rotation;
20623     const rotation = viewport.rotation;
20624     this.viewport = viewport;
20625     setLayerDimensions(this.div, {
20626       rotation
20627     });
20628     if (oldRotation !== rotation) {
20629       for (const editor of this.#editors.values()) {
20630         editor.rotate(rotation);
20631       }
20632     }
20633   }
20634   get pageDimensions() {
20635     const {
20636       pageWidth,
20637       pageHeight
20638     } = this.viewport.rawDims;
20639     return [pageWidth, pageHeight];
20640   }
20641   get scale() {
20642     return this.#uiManager.viewParameters.realScale;
20643   }
20646 ;// ./src/display/draw_layer.js
20649 class DrawLayer {
20650   #parent = null;
20651   #mapping = new Map();
20652   #toUpdate = new Map();
20653   static #id = 0;
20654   constructor({
20655     pageIndex
20656   }) {
20657     this.pageIndex = pageIndex;
20658   }
20659   setParent(parent) {
20660     if (!this.#parent) {
20661       this.#parent = parent;
20662       return;
20663     }
20664     if (this.#parent !== parent) {
20665       if (this.#mapping.size > 0) {
20666         for (const root of this.#mapping.values()) {
20667           root.remove();
20668           parent.append(root);
20669         }
20670       }
20671       this.#parent = parent;
20672     }
20673   }
20674   static get _svgFactory() {
20675     return shadow(this, "_svgFactory", new DOMSVGFactory());
20676   }
20677   static #setBox(element, [x, y, width, height]) {
20678     const {
20679       style
20680     } = element;
20681     style.top = `${100 * y}%`;
20682     style.left = `${100 * x}%`;
20683     style.width = `${100 * width}%`;
20684     style.height = `${100 * height}%`;
20685   }
20686   #createSVG() {
20687     const svg = DrawLayer._svgFactory.create(1, 1, true);
20688     this.#parent.append(svg);
20689     svg.setAttribute("aria-hidden", true);
20690     return svg;
20691   }
20692   #createClipPath(defs, pathId) {
20693     const clipPath = DrawLayer._svgFactory.createElement("clipPath");
20694     defs.append(clipPath);
20695     const clipPathId = `clip_${pathId}`;
20696     clipPath.setAttribute("id", clipPathId);
20697     clipPath.setAttribute("clipPathUnits", "objectBoundingBox");
20698     const clipPathUse = DrawLayer._svgFactory.createElement("use");
20699     clipPath.append(clipPathUse);
20700     clipPathUse.setAttribute("href", `#${pathId}`);
20701     clipPathUse.classList.add("clip");
20702     return clipPathId;
20703   }
20704   #updateProperties(element, properties) {
20705     for (const [key, value] of Object.entries(properties)) {
20706       if (value === null) {
20707         element.removeAttribute(key);
20708       } else {
20709         element.setAttribute(key, value);
20710       }
20711     }
20712   }
20713   draw(properties, isPathUpdatable = false, hasClip = false) {
20714     const id = DrawLayer.#id++;
20715     const root = this.#createSVG();
20716     const defs = DrawLayer._svgFactory.createElement("defs");
20717     root.append(defs);
20718     const path = DrawLayer._svgFactory.createElement("path");
20719     defs.append(path);
20720     const pathId = `path_p${this.pageIndex}_${id}`;
20721     path.setAttribute("id", pathId);
20722     path.setAttribute("vector-effect", "non-scaling-stroke");
20723     if (isPathUpdatable) {
20724       this.#toUpdate.set(id, path);
20725     }
20726     const clipPathId = hasClip ? this.#createClipPath(defs, pathId) : null;
20727     const use = DrawLayer._svgFactory.createElement("use");
20728     root.append(use);
20729     use.setAttribute("href", `#${pathId}`);
20730     this.updateProperties(root, properties);
20731     this.#mapping.set(id, root);
20732     return {
20733       id,
20734       clipPathId: `url(#${clipPathId})`
20735     };
20736   }
20737   drawOutline(properties, mustRemoveSelfIntersections) {
20738     const id = DrawLayer.#id++;
20739     const root = this.#createSVG();
20740     const defs = DrawLayer._svgFactory.createElement("defs");
20741     root.append(defs);
20742     const path = DrawLayer._svgFactory.createElement("path");
20743     defs.append(path);
20744     const pathId = `path_p${this.pageIndex}_${id}`;
20745     path.setAttribute("id", pathId);
20746     path.setAttribute("vector-effect", "non-scaling-stroke");
20747     let maskId;
20748     if (mustRemoveSelfIntersections) {
20749       const mask = DrawLayer._svgFactory.createElement("mask");
20750       defs.append(mask);
20751       maskId = `mask_p${this.pageIndex}_${id}`;
20752       mask.setAttribute("id", maskId);
20753       mask.setAttribute("maskUnits", "objectBoundingBox");
20754       const rect = DrawLayer._svgFactory.createElement("rect");
20755       mask.append(rect);
20756       rect.setAttribute("width", "1");
20757       rect.setAttribute("height", "1");
20758       rect.setAttribute("fill", "white");
20759       const use = DrawLayer._svgFactory.createElement("use");
20760       mask.append(use);
20761       use.setAttribute("href", `#${pathId}`);
20762       use.setAttribute("stroke", "none");
20763       use.setAttribute("fill", "black");
20764       use.setAttribute("fill-rule", "nonzero");
20765       use.classList.add("mask");
20766     }
20767     const use1 = DrawLayer._svgFactory.createElement("use");
20768     root.append(use1);
20769     use1.setAttribute("href", `#${pathId}`);
20770     if (maskId) {
20771       use1.setAttribute("mask", `url(#${maskId})`);
20772     }
20773     const use2 = use1.cloneNode();
20774     root.append(use2);
20775     use1.classList.add("mainOutline");
20776     use2.classList.add("secondaryOutline");
20777     this.updateProperties(root, properties);
20778     this.#mapping.set(id, root);
20779     return id;
20780   }
20781   finalizeDraw(id, properties) {
20782     this.#toUpdate.delete(id);
20783     this.updateProperties(id, properties);
20784   }
20785   updateProperties(elementOrId, properties) {
20786     if (!properties) {
20787       return;
20788     }
20789     const {
20790       root,
20791       bbox,
20792       rootClass,
20793       path
20794     } = properties;
20795     const element = typeof elementOrId === "number" ? this.#mapping.get(elementOrId) : elementOrId;
20796     if (!element) {
20797       return;
20798     }
20799     if (root) {
20800       this.#updateProperties(element, root);
20801     }
20802     if (bbox) {
20803       DrawLayer.#setBox(element, bbox);
20804     }
20805     if (rootClass) {
20806       const {
20807         classList
20808       } = element;
20809       for (const [className, value] of Object.entries(rootClass)) {
20810         classList.toggle(className, value);
20811       }
20812     }
20813     if (path) {
20814       const defs = element.firstChild;
20815       const pathElement = defs.firstChild;
20816       this.#updateProperties(pathElement, path);
20817     }
20818   }
20819   updateParent(id, layer) {
20820     if (layer === this) {
20821       return;
20822     }
20823     const root = this.#mapping.get(id);
20824     if (!root) {
20825       return;
20826     }
20827     layer.#parent.append(root);
20828     this.#mapping.delete(id);
20829     layer.#mapping.set(id, root);
20830   }
20831   remove(id) {
20832     this.#toUpdate.delete(id);
20833     if (this.#parent === null) {
20834       return;
20835     }
20836     this.#mapping.get(id).remove();
20837     this.#mapping.delete(id);
20838   }
20839   destroy() {
20840     this.#parent = null;
20841     for (const root of this.#mapping.values()) {
20842       root.remove();
20843     }
20844     this.#mapping.clear();
20845     this.#toUpdate.clear();
20846   }
20849 ;// ./src/pdf.js
20864 const pdfjsVersion = "5.0.98";
20865 const pdfjsBuild = "16155fd80";
20867 var __webpack_exports__AbortException = __webpack_exports__.AbortException;
20868 var __webpack_exports__AnnotationBorderStyleType = __webpack_exports__.AnnotationBorderStyleType;
20869 var __webpack_exports__AnnotationEditorLayer = __webpack_exports__.AnnotationEditorLayer;
20870 var __webpack_exports__AnnotationEditorParamsType = __webpack_exports__.AnnotationEditorParamsType;
20871 var __webpack_exports__AnnotationEditorType = __webpack_exports__.AnnotationEditorType;
20872 var __webpack_exports__AnnotationEditorUIManager = __webpack_exports__.AnnotationEditorUIManager;
20873 var __webpack_exports__AnnotationLayer = __webpack_exports__.AnnotationLayer;
20874 var __webpack_exports__AnnotationMode = __webpack_exports__.AnnotationMode;
20875 var __webpack_exports__AnnotationType = __webpack_exports__.AnnotationType;
20876 var __webpack_exports__ColorPicker = __webpack_exports__.ColorPicker;
20877 var __webpack_exports__DOMSVGFactory = __webpack_exports__.DOMSVGFactory;
20878 var __webpack_exports__DrawLayer = __webpack_exports__.DrawLayer;
20879 var __webpack_exports__FeatureTest = __webpack_exports__.FeatureTest;
20880 var __webpack_exports__GlobalWorkerOptions = __webpack_exports__.GlobalWorkerOptions;
20881 var __webpack_exports__ImageKind = __webpack_exports__.ImageKind;
20882 var __webpack_exports__InvalidPDFException = __webpack_exports__.InvalidPDFException;
20883 var __webpack_exports__OPS = __webpack_exports__.OPS;
20884 var __webpack_exports__OutputScale = __webpack_exports__.OutputScale;
20885 var __webpack_exports__PDFDataRangeTransport = __webpack_exports__.PDFDataRangeTransport;
20886 var __webpack_exports__PDFDateString = __webpack_exports__.PDFDateString;
20887 var __webpack_exports__PDFWorker = __webpack_exports__.PDFWorker;
20888 var __webpack_exports__PasswordResponses = __webpack_exports__.PasswordResponses;
20889 var __webpack_exports__PermissionFlag = __webpack_exports__.PermissionFlag;
20890 var __webpack_exports__PixelsPerInch = __webpack_exports__.PixelsPerInch;
20891 var __webpack_exports__RenderingCancelledException = __webpack_exports__.RenderingCancelledException;
20892 var __webpack_exports__ResponseException = __webpack_exports__.ResponseException;
20893 var __webpack_exports__SupportedImageMimeTypes = __webpack_exports__.SupportedImageMimeTypes;
20894 var __webpack_exports__TextLayer = __webpack_exports__.TextLayer;
20895 var __webpack_exports__TouchManager = __webpack_exports__.TouchManager;
20896 var __webpack_exports__Util = __webpack_exports__.Util;
20897 var __webpack_exports__VerbosityLevel = __webpack_exports__.VerbosityLevel;
20898 var __webpack_exports__XfaLayer = __webpack_exports__.XfaLayer;
20899 var __webpack_exports__build = __webpack_exports__.build;
20900 var __webpack_exports__createValidAbsoluteUrl = __webpack_exports__.createValidAbsoluteUrl;
20901 var __webpack_exports__fetchData = __webpack_exports__.fetchData;
20902 var __webpack_exports__getDocument = __webpack_exports__.getDocument;
20903 var __webpack_exports__getFilenameFromUrl = __webpack_exports__.getFilenameFromUrl;
20904 var __webpack_exports__getPdfFilenameFromUrl = __webpack_exports__.getPdfFilenameFromUrl;
20905 var __webpack_exports__getXfaPageViewport = __webpack_exports__.getXfaPageViewport;
20906 var __webpack_exports__isDataScheme = __webpack_exports__.isDataScheme;
20907 var __webpack_exports__isPdfFile = __webpack_exports__.isPdfFile;
20908 var __webpack_exports__noContextMenu = __webpack_exports__.noContextMenu;
20909 var __webpack_exports__normalizeUnicode = __webpack_exports__.normalizeUnicode;
20910 var __webpack_exports__setLayerDimensions = __webpack_exports__.setLayerDimensions;
20911 var __webpack_exports__shadow = __webpack_exports__.shadow;
20912 var __webpack_exports__stopEvent = __webpack_exports__.stopEvent;
20913 var __webpack_exports__version = __webpack_exports__.version;
20914 export { __webpack_exports__AbortException as AbortException, __webpack_exports__AnnotationBorderStyleType as AnnotationBorderStyleType, __webpack_exports__AnnotationEditorLayer as AnnotationEditorLayer, __webpack_exports__AnnotationEditorParamsType as AnnotationEditorParamsType, __webpack_exports__AnnotationEditorType as AnnotationEditorType, __webpack_exports__AnnotationEditorUIManager as AnnotationEditorUIManager, __webpack_exports__AnnotationLayer as AnnotationLayer, __webpack_exports__AnnotationMode as AnnotationMode, __webpack_exports__AnnotationType as AnnotationType, __webpack_exports__ColorPicker as ColorPicker, __webpack_exports__DOMSVGFactory as DOMSVGFactory, __webpack_exports__DrawLayer as DrawLayer, __webpack_exports__FeatureTest as FeatureTest, __webpack_exports__GlobalWorkerOptions as GlobalWorkerOptions, __webpack_exports__ImageKind as ImageKind, __webpack_exports__InvalidPDFException as InvalidPDFException, __webpack_exports__OPS as OPS, __webpack_exports__OutputScale as OutputScale, __webpack_exports__PDFDataRangeTransport as PDFDataRangeTransport, __webpack_exports__PDFDateString as PDFDateString, __webpack_exports__PDFWorker as PDFWorker, __webpack_exports__PasswordResponses as PasswordResponses, __webpack_exports__PermissionFlag as PermissionFlag, __webpack_exports__PixelsPerInch as PixelsPerInch, __webpack_exports__RenderingCancelledException as RenderingCancelledException, __webpack_exports__ResponseException as ResponseException, __webpack_exports__SupportedImageMimeTypes as SupportedImageMimeTypes, __webpack_exports__TextLayer as TextLayer, __webpack_exports__TouchManager as TouchManager, __webpack_exports__Util as Util, __webpack_exports__VerbosityLevel as VerbosityLevel, __webpack_exports__XfaLayer as XfaLayer, __webpack_exports__build as build, __webpack_exports__createValidAbsoluteUrl as createValidAbsoluteUrl, __webpack_exports__fetchData as fetchData, __webpack_exports__getDocument as getDocument, __webpack_exports__getFilenameFromUrl as getFilenameFromUrl, __webpack_exports__getPdfFilenameFromUrl as getPdfFilenameFromUrl, __webpack_exports__getXfaPageViewport as getXfaPageViewport, __webpack_exports__isDataScheme as isDataScheme, __webpack_exports__isPdfFile as isPdfFile, __webpack_exports__noContextMenu as noContextMenu, __webpack_exports__normalizeUnicode as normalizeUnicode, __webpack_exports__setLayerDimensions as setLayerDimensions, __webpack_exports__shadow as shadow, __webpack_exports__stopEvent as stopEvent, __webpack_exports__version as version };