PageSourceSearch

https://odoo.pantalytics.com/web/static/lib/pdfjs/build/pdf.js

js pantalytics.com collected 2026-09-25 21:12:00 UTC 628,500 bytes, 20,522 lines download raw bytes

vendor: 5,331 bytes, lines 1-130
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 */
22
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/************************************************************************/
45var __webpack_exports__ = globalThis.pdfjsLib = {};
46
47// EXPORTS
48__webpack_require__.d(__webpack_exports__, {
49  AbortException: () => (/* reexport */ AbortException),
50  AnnotationEditorLayer: () => (/* reexport */ AnnotationEditorLayer),
51  AnnotationEditorParamsType: () => (/* reexport */ AnnotationEditorParamsType),
52  AnnotationEditorType: () => (/* reexport */ AnnotationEditorType),
53  AnnotationEditorUIManager: () => (/* reexport */ AnnotationEditorUIManager),
54  AnnotationLayer: () => (/* reexport */ AnnotationLayer),
55  AnnotationMode: () => (/* reexport */ AnnotationMode),
56  ColorPicker: () => (/* reexport */ ColorPicker),
57  DOMSVGFactory: () => (/* reexport */ DOMSVGFactory),
58  DrawLayer: () => (/* reexport */ DrawLayer),
59  FeatureTest: () => (/* reexport */ util_FeatureTest),
60  GlobalWorkerOptions: () => (/* reexport */ GlobalWorkerOptions),
61  ImageKind: () => (/* reexport */ util_ImageKind),
62  InvalidPDFException: () => (/* reexport */ InvalidPDFException),
63  MissingPDFException: () => (/* reexport */ MissingPDFException),
64  OPS: () => (/* reexport */ OPS),
65  OutputScale: () => (/* reexport */ OutputScale),
66  PDFDataRangeTransport: () => (/* reexport */ PDFDataRangeTransport),
67  PDFDateString: () => (/* reexport */ PDFDateString),
68  PDFWorker: () => (/* reexport */ PDFWorker),
69  PasswordResponses: () => (/* reexport */ PasswordResponses),
70  PermissionFlag: () => (/* reexport */ PermissionFlag),
71  PixelsPerInch: () => (/* reexport */ PixelsPerInch),
72  RenderingCancelledException: () => (/* reexport */ RenderingCancelledException),
73  TextLayer: () => (/* reexport */ TextLayer),
74  UnexpectedResponseException: () => (/* reexport */ UnexpectedResponseException),
75  Util: () => (/* reexport */ Util),
76  VerbosityLevel: () => (/* reexport */ VerbosityLevel),
77  XfaLayer: () => (/* reexport */ XfaLayer),
78  build: () => (/* reexport */ build),
79  createValidAbsoluteUrl: () => (/* reexport */ createValidAbsoluteUrl),
80  fetchData: () => (/* reexport */ fetchData),
81  getDocument: () => (/* reexport */ getDocument),
82  getFilenameFromUrl: () => (/* reexport */ getFilenameFromUrl),
83  getPdfFilenameFromUrl: () => (/* reexport */ getPdfFilenameFromUrl),
84  getXfaPageViewport: () => (/* reexport */ getXfaPageViewport),
85  isDataScheme: () => (/* reexport */ isDataScheme),
86  isPdfFile: () => (/* reexport */ isPdfFile),
87  noContextMenu: () => (/* reexport */ noContextMenu),
88  normalizeUnicode: () => (/* reexport */ normalizeUnicode),
89  setLayerDimensions: () => (/* reexport */ setLayerDimensions),
90  shadow: () => (/* reexport */ shadow),
91  version: () => (/* reexport */ version)
92});
93
94;// ./src/shared/util.js
95const isNodeJS = typeof process === "object" && process + "" === "[object process]" && !process.versions.nw && !(process.versions.electron && process.type && process.type !== "browser");
96const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
97const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
98const MAX_IMAGE_SIZE_TO_CACHE = 10e6;
99const LINE_FACTOR = 1.35;
100const LINE_DESCENT_FACTOR = 0.35;
101const BASELINE_FACTOR = LINE_DESCENT_FACTOR / LINE_FACTOR;
102const RenderingIntentFlag = {
103  ANY: 0x01,
104  DISPLAY: 0x02,
105  PRINT: 0x04,
106  SAVE: 0x08,
107  ANNOTATIONS_FORMS: 0x10,
108  ANNOTATIONS_STORAGE: 0x20,
109  ANNOTATIONS_DISABLE: 0x40,
110  IS_EDITING: 0x80,
111  OPLIST: 0x100
112};
113const AnnotationMode = {
114  DISABLE: 0,
115  ENABLE: 1,
116  ENABLE_FORMS: 2,
117  ENABLE_STORAGE: 3
118};
119const AnnotationEditorPrefix = "pdfjs_internal_editor_";
120const AnnotationEditorType = {
121  DISABLE: -1,
122  NONE: 0,
123  FREETEXT: 3,
124  HIGHLIGHT: 9,
125  STAMP: 13,
126  INK: 15
127};
128const AnnotationEditorParamsType = {
129  RESIZE: 1,
130  CREATE: 2,
131  FREETEXT_SIZE: 11,
132  FREETEXT_COLOR: 12,
133  FREETEXT_OPACITY: 13,
134  INK_COLOR: 21,
135  INK_THICKNESS: 22,
136  INK_OPACITY: 23,
137  HIGHLIGHT_COLOR: 31,
138  HIGHLIGHT_DEFAULT_COLOR: 32,
139  HIGHLIGHT_THICKNESS: 33,
140  HIGHLIGHT_FREE: 34,
141  HIGHLIGHT_SHOW_ALL: 35
142};
143const PermissionFlag = {
144  PRINT: 0x04,
145  MODIFY_CONTENTS: 0x08,
146  COPY: 0x10,
147  MODIFY_ANNOTATIONS: 0x20,
148  FILL_INTERACTIVE_FORMS: 0x100,
149  COPY_FOR_ACCESSIBILITY: 0x200,
150  ASSEMBLE: 0x400,
151  PRINT_HIGH_QUALITY: 0x800
152};
153const TextRenderingMode = {
154  FILL: 0,
155  STROKE: 1,
156  FILL_STROKE: 2,
157  INVISIBLE: 3,
158  FILL_ADD_TO_PATH: 4,
159  STROKE_ADD_TO_PATH: 5,
160  FILL_STROKE_ADD_TO_PATH: 6,
161  ADD_TO_PATH: 7,
162  FILL_STROKE_MASK: 3,
163  ADD_TO_PATH_FLAG: 4
164};
165const util_ImageKind = {
166  GRAYSCALE_1BPP: 1,
167  RGB_24BPP: 2,
168  RGBA_32BPP: 3
169};
170const AnnotationType = {
171  TEXT: 1,
172  LINK: 2,
173  FREETEXT: 3,
174  LINE: 4,
175  SQUARE: 5,
176  CIRCLE: 6,
177  POLYGON: 7,
178  POLYLINE: 8,
179  HIGHLIGHT: 9,
180  UNDERLINE: 10,
181  SQUIGGLY: 11,
182  STRIKEOUT: 12,
183  STAMP: 13,
184  CARET: 14,
185  INK: 15,
186  POPUP: 16,
187  FILEATTACHMENT: 17,
188  SOUND: 18,
189  MOVIE: 19,
190  WIDGET: 20,
191  SCREEN: 21,
192  PRINTERMARK: 22,
193  TRAPNET: 23,
194  WATERMARK: 24,
195  THREED: 25,
196  REDACT: 26
197};
198const AnnotationReplyType = {
199  GROUP: "Group",
200  REPLY: "R"
201};
202const AnnotationFlag = {
203  INVISIBLE: 0x01,
204  HIDDEN: 0x02,
205  PRINT: 0x04,
206  NOZOOM: 0x08,
207  NOROTATE: 0x10,
208  NOVIEW: 0x20,
209  READONLY: 0x40,
210  LOCKED: 0x80,
211  TOGGLENOVIEW: 0x100,
212  LOCKEDCONTENTS: 0x200
213};
214const AnnotationFieldFlag = {
215  READONLY: 0x0000001,
216  REQUIRED: 0x0000002,
217  NOEXPORT: 0x0000004,
218  MULTILINE: 0x0001000,
219  PASSWORD: 0x0002000,
220  NOTOGGLETOOFF: 0x0004000,
221  RADIO: 0x0008000,
222  PUSHBUTTON: 0x0010000,
223  COMBO: 0x0020000,
224  EDIT: 0x0040000,
225  SORT: 0x0080000,
226  FILESELECT: 0x0100000,
227  MULTISELECT: 0x0200000,
228  DONOTSPELLCHECK: 0x0400000,
229  DONOTSCROLL: 0x0800000,
230  COMB: 0x1000000,
231  RICHTEXT: 0x2000000,
232  RADIOSINUNISON: 0x2000000,
233  COMMITONSELCHANGE: 0x4000000
234};
235const AnnotationBorderStyleType = {
236  SOLID: 1,
237  DASHED: 2,
238  BEVELED: 3,
239  INSET: 4,
240  UNDERLINE: 5
241};
242const AnnotationActionEventType = {
243  E: "Mouse Enter",
244  X: "Mouse Exit",
245  D: "Mouse Down",
246  U: "Mouse Up",
247  Fo: "Focus",
248  Bl: "Blur",
249  PO: "PageOpen",
250  PC: "PageClose",
251  PV: "PageVisible",
252  PI: "PageInvisible",
253  K: "Keystroke",
254  F: "Format",
255  V: "Validate",
256  C: "Calculate"
257};
258const DocumentActionEventType = {
259  WC: "WillClose",
260  WS: "WillSave",
261  DS: "DidSave",
262  WP: "WillPrint",
263  DP: "DidPrint"
264};
265const PageActionEventType = {
266  O: "PageOpen",
267  C: "PageClose"
268};
269const VerbosityLevel = {
270  ERRORS: 0,
271  WARNINGS: 1,
272  INFOS: 5
273};
274const OPS = {
275  dependency: 1,
276  setLineWidth: 2,
277  setLineCap: 3,
278  setLineJoin: 4,
279  setMiterLimit: 5,
280  setDash: 6,
281  setRenderingIntent: 7,
282  setFlatness: 8,
283  setGState: 9,
284  save: 10,
285  restore: 11,
286  transform: 12,
287  moveTo: 13,
288  lineTo: 14,
289  curveTo: 15,
290  curveTo2: 16,
vendor: 5,342 bytes, lines 291-514
291  curveTo3: 17,
292  closePath: 18,
293  rectangle: 19,
294  stroke: 20,
295  closeStroke: 21,
296  fill: 22,
297  eoFill: 23,
298  fillStroke: 24,
299  eoFillStroke: 25,
300  closeFillStroke: 26,
301  closeEOFillStroke: 27,
302  endPath: 28,
303  clip: 29,
304  eoClip: 30,
305  beginText: 31,
306  endText: 32,
307  setCharSpacing: 33,
308  setWordSpacing: 34,
309  setHScale: 35,
310  setLeading: 36,
311  setFont: 37,
312  setTextRenderingMode: 38,
313  setTextRise: 39,
314  moveText: 40,
315  setLeadingMoveText: 41,
316  setTextMatrix: 42,
317  nextLine: 43,
318  showText: 44,
319  showSpacedText: 45,
320  nextLineShowText: 46,
321  nextLineSetSpacingShowText: 47,
322  setCharWidth: 48,
323  setCharWidthAndBounds: 49,
324  setStrokeColorSpace: 50,
325  setFillColorSpace: 51,
326  setStrokeColor: 52,
327  setStrokeColorN: 53,
328  setFillColor: 54,
329  setFillColorN: 55,
330  setStrokeGray: 56,
331  setFillGray: 57,
332  setStrokeRGBColor: 58,
333  setFillRGBColor: 59,
334  setStrokeCMYKColor: 60,
335  setFillCMYKColor: 61,
336  shadingFill: 62,
337  beginInlineImage: 63,
338  beginImageData: 64,
339  endInlineImage: 65,
340  paintXObject: 66,
341  markPoint: 67,
342  markPointProps: 68,
343  beginMarkedContent: 69,
344  beginMarkedContentProps: 70,
345  endMarkedContent: 71,
346  beginCompat: 72,
347  endCompat: 73,
348  paintFormXObjectBegin: 74,
349  paintFormXObjectEnd: 75,
350  beginGroup: 76,
351  endGroup: 77,
352  beginAnnotation: 80,
353  endAnnotation: 81,
354  paintImageMaskXObject: 83,
355  paintImageMaskXObjectGroup: 84,
356  paintImageXObject: 85,
357  paintInlineImageXObject: 86,
358  paintInlineImageXObjectGroup: 87,
359  paintImageXObjectRepeat: 88,
360  paintImageMaskXObjectRepeat: 89,
361  paintSolidColorImageMask: 90,
362  constructPath: 91,
363  setStrokeTransparent: 92,
364  setFillTransparent: 93
365};
366const PasswordResponses = {
367  NEED_PASSWORD: 1,
368  INCORRECT_PASSWORD: 2
369};
370let verbosity = VerbosityLevel.WARNINGS;
371function setVerbosityLevel(level) {
372  if (Number.isInteger(level)) {
373    verbosity = level;
374  }
375}
376function getVerbosityLevel() {
377  return verbosity;
378}
379function info(msg) {
380  if (verbosity >= VerbosityLevel.INFOS) {
381    console.log(`Info: ${msg}`);
382  }
383}
384function warn(msg) {
385  if (verbosity >= VerbosityLevel.WARNINGS) {
386    console.log(`Warning: ${msg}`);
387  }
388}
389function unreachable(msg) {
390  throw new Error(msg);
391}
392function assert(cond, msg) {
393  if (!cond) {
394    unreachable(msg);
395  }
396}
397function _isValidProtocol(url) {
398  switch (url?.protocol) {
399    case "http:":
400    case "https:":
401    case "ftp:":
402    case "mailto:":
403    case "tel:":
404      return true;
405    default:
406      return false;
407  }
408}
409function createValidAbsoluteUrl(url, baseUrl = null, options = null) {
410  if (!url) {
411    return null;
412  }
413  try {
414    if (options && typeof url === "string") {
415      if (options.addDefaultProtocol && url.startsWith("www.")) {
416        const dots = url.match(/\./g);
417        if (dots?.length >= 2) {
418          url = `http://${url}`;
419        }
420      }
421      if (options.tryConvertEncoding) {
422        try {
423          url = stringToUTF8String(url);
424        } catch {}
425      }
426    }
427    const absoluteUrl = baseUrl ? new URL(url, baseUrl) : new URL(url);
428    if (_isValidProtocol(absoluteUrl)) {
429      return absoluteUrl;
430    }
431  } catch {}
432  return null;
433}
434function shadow(obj, prop, value, nonSerializable = false) {
435  Object.defineProperty(obj, prop, {
436    value,
437    enumerable: !nonSerializable,
438    configurable: true,
439    writable: false
440  });
441  return value;
442}
443const BaseException = function BaseExceptionClosure() {
444  function BaseException(message, name) {
445    this.message = message;
446    this.name = name;
447  }
448  BaseException.prototype = new Error();
449  BaseException.constructor = BaseException;
450  return BaseException;
451}();
452class PasswordException extends BaseException {
453  constructor(msg, code) {
454    super(msg, "PasswordException");
455    this.code = code;
456  }
457}
458class UnknownErrorException extends BaseException {
459  constructor(msg, details) {
460    super(msg, "UnknownErrorException");
461    this.details = details;
462  }
463}
464class InvalidPDFException extends BaseException {
465  constructor(msg) {
466    super(msg, "InvalidPDFException");
467  }
468}
469class MissingPDFException extends BaseException {
470  constructor(msg) {
471    super(msg, "MissingPDFException");
472  }
473}
474class UnexpectedResponseException extends BaseException {
475  constructor(msg, status) {
476    super(msg, "UnexpectedResponseException");
477    this.status = status;
478  }
479}
480class FormatError extends BaseException {
481  constructor(msg) {
482    super(msg, "FormatError");
483  }
484}
485class AbortException extends BaseException {
486  constructor(msg) {
487    super(msg, "AbortException");
488  }
489}
490function bytesToString(bytes) {
491  if (typeof bytes !== "object" || bytes?.length === undefined) {
492    unreachable("Invalid argument for bytesToString");
493  }
494  const length = bytes.length;
495  const MAX_ARGUMENT_COUNT = 8192;
496  if (length < MAX_ARGUMENT_COUNT) {
497    return String.fromCharCode.apply(null, bytes);
498  }
499  const strBuf = [];
500  for (let i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
501    const chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
502    const chunk = bytes.subarray(i, chunkEnd);
503    strBuf.push(String.fromCharCode.apply(null, chunk));
504  }
505  return strBuf.join("");
506}
507function stringToBytes(str) {
508  if (typeof str !== "string") {
509    unreachable("Invalid argument for stringToBytes");
510  }
511  const length = str.length;
512  const bytes = new Uint8Array(length);
513  for (let i = 0; i < length; ++i) {
514    bytes[i] = str.charCodeAt(i) & 0xff;
515  }
516  return bytes;
517}
518function string32(value) {
519  return String.fromCharCode(value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff);
520}
521function objectSize(obj) {
522  return Object.keys(obj).length;
523}
524function objectFromMap(map) {
525  const obj = Object.create(null);
526  for (const [key, value] of map) {
527    obj[key] = value;
528  }
529  return obj;
530}
531function isLittleEndian() {
532  const buffer8 = new Uint8Array(4);
533  buffer8[0] = 1;
534  const view32 = new Uint32Array(buffer8.buffer, 0, 1);
535  return view32[0] === 1;
536}
537function isEvalSupported() {
538  // Odoo: don't support scripting
539  return false;
540}
541class util_FeatureTest {
542  static get isLittleEndian() {
543    return shadow(this, "isLittleEndian", isLittleEndian());
544  }
545  static get isEvalSupported() {
546    return shadow(this, "isEvalSupported", isEvalSupported());
547  }
548  static get isOffscreenCanvasSupported() {
549    return shadow(this, "isOffscreenCanvasSupported", typeof OffscreenCanvas !== "undefined");
550  }
551  static get platform() {
552    if (typeof navigator !== "undefined" && typeof navigator?.platform === "string") {
553      return shadow(this, "platform", {
554        isMac: navigator.platform.includes("Mac"),
555        isWindows: navigator.platform.includes("Win"),
556        isFirefox: typeof navigator?.userAgent === "string" && navigator.userAgent.includes("Firefox")
557      });
558    }
559    return shadow(this, "platform", {
560      isMac: false,
561      isWindows: false,
562      isFirefox: false
563    });
564  }
565  static get isCSSRoundSupported() {
566    return shadow(this, "isCSSRoundSupported", globalThis.CSS?.supports?.("width: round(1.5px, 1px)"));
567  }
568}
569const hexNumbers = Array.from(Array(256).keys(), n => n.toString(16).padStart(2, "0"));
570class Util {
571  static makeHexColor(r, g, b) {
572    return `#${hexNumbers[r]}${hexNumbers[g]}${hexNumbers[b]}`;
573  }
574  static scaleMinMax(transform, minMax) {
575    let temp;
576    if (transform[0]) {
577      if (transform[0] < 0) {
578        temp = minMax[0];
579        minMax[0] = minMax[2];
580        minMax[2] = temp;
581      }
582      minMax[0] *= transform[0];
583      minMax[2] *= transform[0];
584      if (transform[3] < 0) {
585        temp = minMax[1];
586        minMax[1] = minMax[3];
587        minMax[3] = temp;
588      }
589      minMax[1] *= transform[3];
590      minMax[3] *= transform[3];
591    } else {
592      temp = minMax[0];
593      minMax[0] = minMax[1];
594      minMax[1] = temp;
595      temp = minMax[2];
596      minMax[2] = minMax[3];
597      minMax[3] = temp;
598      if (transform[1] < 0) {
599        temp = minMax[1];
600        minMax[1] = minMax[3];
601        minMax[3] = temp;
602      }
603      minMax[1] *= transform[1];
604      minMax[3] *= transform[1];
605      if (transform[2] < 0) {
606        temp = minMax[0];
607        minMax[0] = minMax[2];
608        minMax[2] = temp;
609      }
610      minMax[0] *= transform[2];
611      minMax[2] *= transform[2];
612    }
613    minMax[0] += transform[4];
614    minMax[1] += transform[5];
615    minMax[2] += transform[4];
616    minMax[3] += transform[5];
617  }
618  static transform(m1, m2) {
619    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]];
620  }
621  static applyTransform(p, m) {
622    const xt = p[0] * m[0] + p[1] * m[2] + m[4];
623    const yt = p[0] * m[1] + p[1] * m[3] + m[5];
624    return [xt, yt];
625  }
626  static applyInverseTransform(p, m) {
627    const d = m[0] * m[3] - m[1] * m[2];
628    const xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
629    const yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
630    return [xt, yt];
631  }
632  static getAxialAlignedBoundingBox(r, m) {
633    const p1 = this.applyTransform(r, m);
634    const p2 = this.applyTransform(r.slice(2, 4), m);
635    const p3 = this.applyTransform([r[0], r[3]], m);
636    const p4 = this.applyTransform([r[2], r[1]], m);
637    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])];
638  }
639  static inverseTransform(m) {
640    const d = m[0] * m[3] - m[1] * m[2];
641    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];
642  }
643  static singularValueDecompose2dScale(m) {
644    const transpose = [m[0], m[2], m[1], m[3]];
645    const a = m[0] * transpose[0] + m[1] * transpose[2];
646    const b = m[0] * transpose[1] + m[1] * transpose[3];
647    const c = m[2] * transpose[0] + m[3] * transpose[2];
648    const d = m[2] * transpose[1] + m[3] * transpose[3];
649    const first = (a + d) / 2;
650    const second = Math.sqrt((a + d) ** 2 - 4 * (a * d - c * b)) / 2;
651    const sx = first + second || 1;
652    const sy = first - second || 1;
653    return [Math.sqrt(sx), Math.sqrt(sy)];
654  }
655  static normalizeRect(rect) {
656    const r = rect.slice(0);
657    if (rect[0] > rect[2]) {
658      r[0] = rect[2];
659      r[2] = rect[0];
660    }
661    if (rect[1] > rect[3]) {
662      r[1] = rect[3];
663      r[3] = rect[1];
664    }
665    return r;
666  }
667  static intersect(rect1, rect2) {
668    const xLow = Math.max(Math.min(rect1[0], rect1[2]), Math.min(rect2[0], rect2[2]));
669    const xHigh = Math.min(Math.max(rect1[0], rect1[2]), Math.max(rect2[0], rect2[2]));
670    if (xLow > xHigh) {
671      return null;
672    }
673    const yLow = Math.max(Math.min(rect1[1], rect1[3]), Math.min(rect2[1], rect2[3]));
674    const yHigh = Math.min(Math.max(rect1[1], rect1[3]), Math.max(rect2[1], rect2[3]));
675    if (yLow > yHigh) {
676      return null;
677    }
678    return [xLow, yLow, xHigh, yHigh];
679  }
680  static #getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, t, minMax) {
681    if (t <= 0 || t >= 1) {
682      return;
683    }
684    const mt = 1 - t;
685    const tt = t * t;
686    const ttt = tt * t;
687    const x = mt * (mt * (mt * x0 + 3 * t * x1) + 3 * tt * x2) + ttt * x3;
688    const y = mt * (mt * (mt * y0 + 3 * t * y1) + 3 * tt * y2) + ttt * y3;
689    minMax[0] = Math.min(minMax[0], x);
690    minMax[1] = Math.min(minMax[1], y);
691    minMax[2] = Math.max(minMax[2], x);
692    minMax[3] = Math.max(minMax[3], y);
693  }
694  static #getExtremum(x0, x1, x2, x3, y0, y1, y2, y3, a, b, c, minMax) {
695    if (Math.abs(a) < 1e-12) {
696      if (Math.abs(b) >= 1e-12) {
697        this.#getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, -c / b, minMax);
698      }
699      return;
700    }
701    const delta = b ** 2 - 4 * c * a;
702    if (delta < 0) {
703      return;
704    }
705    const sqrtDelta = Math.sqrt(delta);
706    const a2 = 2 * a;
707    this.#getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, (-b + sqrtDelta) / a2, minMax);
708    this.#getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, (-b - sqrtDelta) / a2, minMax);
709  }
710  static bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3, minMax) {
711    if (minMax) {
712      minMax[0] = Math.min(minMax[0], x0, x3);
713      minMax[1] = Math.min(minMax[1], y0, y3);
714      minMax[2] = Math.max(minMax[2], x0, x3);
715      minMax[3] = Math.max(minMax[3], y0, y3);
716    } else {
717      minMax = [Math.min(x0, x3), Math.min(y0, y3), Math.max(x0, x3), Math.max(y0, y3)];
718    }
719    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);
720    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);
721    return minMax;
722  }
723}
724const 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]));
725function stringToPDFString(str) {
726  if (str[0] >= "\xEF") {
727    let encoding;
728    if (str[0] === "\xFE" && str[1] === "\xFF") {
729      encoding = "utf-16be";
730      if (str.length % 2 === 1) {
731        str = str.slice(0, -1);
732      }
733    } else if (str[0] === "\xFF" && str[1] === "\xFE") {
734      encoding = "utf-16le";
735      if (str.length % 2 === 1) {
736        str = str.slice(0, -1);
737      }
738    } else if (str[0] === "\xEF" && str[1] === "\xBB" && str[2] === "\xBF") {
739      encoding = "utf-8";
740    }
741    if (encoding) {
742      try {
743        const decoder = new TextDecoder(encoding, {
744          fatal: true
745        });
746        const buffer = stringToBytes(str);
747        const decoded = decoder.decode(buffer);
748        if (!decoded.includes("\x1b")) {
749          return decoded;
750        }
751        return decoded.replaceAll(/\x1b[^\x1b]*(?:\x1b|$)/g, "");
752      } catch (ex) {
753        warn(`stringToPDFString: "${ex}".`);
754      }
755    }
756  }
757  const strBuf = [];
758  for (let i = 0, ii = str.length; i < ii; i++) {
759    const charCode = str.charCodeAt(i);
760    if (charCode === 0x1b) {
761      while (++i < ii && str.charCodeAt(i) !== 0x1b) {}
762      continue;
763    }
764    const code = PDFStringTranslateTable[charCode];
765    strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
766  }
767  return strBuf.join("");
768}
769function stringToUTF8String(str) {
770  return decodeURIComponent(escape(str));
771}
772function utf8StringToString(str) {
773  return unescape(encodeURIComponent(str));
774}
775function isArrayEqual(arr1, arr2) {
776  if (arr1.length !== arr2.length) {
777    return false;
778  }
779  for (let i = 0, ii = arr1.length; i < ii; i++) {
780    if (arr1[i] !== arr2[i]) {
781      return false;
782    }
783  }
784  return true;
785}
786function getModificationDate(date = new Date()) {
787  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")];
788  return buffer.join("");
789}
790let NormalizeRegex = null;
791let NormalizationMap = null;
792function normalizeUnicode(str) {
793  if (!NormalizeRegex) {
794    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;
795    NormalizationMap = new Map([["ſt", "ſt"]]);
796  }
797  return str.replaceAll(NormalizeRegex, (_, p1, p2) => p1 ? p1.normalize("NFKC") : NormalizationMap.get(p2));
798}
799function getUuid() {
800  if (typeof crypto !== "undefined" && typeof crypto?.randomUUID === "function") {
801    return crypto.randomUUID();
802  }
803  const buf = new Uint8Array(32);
804  if (typeof crypto !== "undefined" && typeof crypto?.getRandomValues === "function") {
805    crypto.getRandomValues(buf);
806  } else {
807    for (let i = 0; i < 32; i++) {
808      buf[i] = Math.floor(Math.random() * 255);
809    }
810  }
811  return bytesToString(buf);
812}
813const AnnotationPrefix = "pdfjs_internal_id_";
814const FontRenderOps = {
815  BEZIER_CURVE_TO: 0,
816  MOVE_TO: 1,
817  LINE_TO: 2,
818  QUADRATIC_CURVE_TO: 3,
819  RESTORE: 4,
820  SAVE: 5,
821  SCALE: 6,
822  TRANSFORM: 7,
823  TRANSLATE: 8
824};
825function toHexUtil(arr) {
826  if (Uint8Array.prototype.toHex) {
827    return arr.toHex();
828  }
829  return Array.from(arr, num => hexNumbers[num]).join("");
830}
831function toBase64Util(arr) {
832  if (Uint8Array.prototype.toBase64) {
833    return arr.toBase64();
834  }
835  return btoa(bytesToString(arr));
836}
837function fromBase64Util(str) {
838  if (Uint8Array.fromBase64) {
839    return Uint8Array.fromBase64(str);
840  }
841  return stringToBytes(atob(str));
842}
843
844;// ./src/display/display_utils.js
845
846const SVG_NS = "http://www.w3.org/2000/svg";
847class PixelsPerInch {
848  static CSS = 96.0;
849  static PDF = 72.0;
850  static PDF_TO_CSS_UNITS = this.CSS / this.PDF;
851}
852async function fetchData(url, type = "text") {
853  if (isValidFetchUrl(url, document.baseURI)) {
854    const response = await fetch(url);
855    if (!response.ok) {
856      throw new Error(response.statusText);
857    }
858    switch (type) {
859      case "arraybuffer":
860        return response.arrayBuffer();
861      case "blob":
862        return response.blob();
863      case "json":
864        return response.json();
865    }
866    return response.text();
867  }
868  return new Promise((resolve, reject) => {
869    const request = new XMLHttpRequest();
870    request.open("GET", url, true);
871    request.responseType = type;
872    request.onreadystatechange = () => {
873      if (request.readyState !== XMLHttpRequest.DONE) {
874        return;
875      }
876      if (request.status === 200 || request.status === 0) {
877        switch (type) {
878          case "arraybuffer":
879          case "blob":
880          case "json":
881            resolve(request.response);
882            return;
883        }
884        resolve(request.responseText);
885        return;
886      }
887      reject(new Error(request.statusText));
888    };
889    request.send(null);
890  });
891}
892class PageViewport {
893  constructor({
vendor: 4,278 bytes, lines 894-1036
894    viewBox,
895    scale,
896    rotation,
897    offsetX = 0,
898    offsetY = 0,
899    dontFlip = false
900  }) {
901    this.viewBox = viewBox;
902    this.scale = scale;
903    this.rotation = rotation;
904    this.offsetX = offsetX;
905    this.offsetY = offsetY;
906    const centerX = (viewBox[2] + viewBox[0]) / 2;
907    const centerY = (viewBox[3] + viewBox[1]) / 2;
908    let rotateA, rotateB, rotateC, rotateD;
909    rotation %= 360;
910    if (rotation < 0) {
911      rotation += 360;
912    }
913    switch (rotation) {
914      case 180:
915        rotateA = -1;
916        rotateB = 0;
917        rotateC = 0;
918        rotateD = 1;
919        break;
920      case 90:
921        rotateA = 0;
922        rotateB = 1;
923        rotateC = 1;
924        rotateD = 0;
925        break;
926      case 270:
927        rotateA = 0;
928        rotateB = -1;
929        rotateC = -1;
930        rotateD = 0;
931        break;
932      case 0:
933        rotateA = 1;
934        rotateB = 0;
935        rotateC = 0;
936        rotateD = -1;
937        break;
938      default:
939        throw new Error("PageViewport: Invalid rotation, must be a multiple of 90 degrees.");
940    }
941    if (dontFlip) {
942      rotateC = -rotateC;
943      rotateD = -rotateD;
944    }
945    let offsetCanvasX, offsetCanvasY;
946    let width, height;
947    if (rotateA === 0) {
948      offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
949      offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
950      width = (viewBox[3] - viewBox[1]) * scale;
951      height = (viewBox[2] - viewBox[0]) * scale;
952    } else {
953      offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
954      offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
955      width = (viewBox[2] - viewBox[0]) * scale;
956      height = (viewBox[3] - viewBox[1]) * scale;
957    }
958    this.transform = [rotateA * scale, rotateB * scale, rotateC * scale, rotateD * scale, offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY];
959    this.width = width;
960    this.height = height;
961  }
962  get rawDims() {
963    const {
964      viewBox
965    } = this;
966    return shadow(this, "rawDims", {
967      pageWidth: viewBox[2] - viewBox[0],
968      pageHeight: viewBox[3] - viewBox[1],
969      pageX: viewBox[0],
970      pageY: viewBox[1]
971    });
972  }
973  clone({
974    scale = this.scale,
975    rotation = this.rotation,
976    offsetX = this.offsetX,
977    offsetY = this.offsetY,
978    dontFlip = false
979  } = {}) {
980    return new PageViewport({
981      viewBox: this.viewBox.slice(),
982      scale,
983      rotation,
984      offsetX,
985      offsetY,
986      dontFlip
987    });
988  }
989  convertToViewportPoint(x, y) {
990    return Util.applyTransform([x, y], this.transform);
991  }
992  convertToViewportRectangle(rect) {
993    const topLeft = Util.applyTransform([rect[0], rect[1]], this.transform);
994    const bottomRight = Util.applyTransform([rect[2], rect[3]], this.transform);
995    return [topLeft[0], topLeft[1], bottomRight[0], bottomRight[1]];
996  }
997  convertToPdfPoint(x, y) {
998    return Util.applyInverseTransform([x, y], this.transform);
999  }
1000}
1001class RenderingCancelledException extends BaseException {
1002  constructor(msg, extraDelay = 0) {
1003    super(msg, "RenderingCancelledException");
1004    this.extraDelay = extraDelay;
1005  }
1006}
1007function isDataScheme(url) {
1008  const ii = url.length;
1009  let i = 0;
1010  while (i < ii && url[i].trim() === "") {
1011    i++;
1012  }
1013  return url.substring(i, i + 5).toLowerCase() === "data:";
1014}
1015function isPdfFile(filename) {
1016  return typeof filename === "string" && /\.pdf$/i.test(filename);
1017}
1018function getFilenameFromUrl(url) {
1019  [url] = url.split(/[#?]/, 1);
1020  return url.substring(url.lastIndexOf("/") + 1);
1021}
1022function getPdfFilenameFromUrl(url, defaultFilename = "document.pdf") {
1023  if (typeof url !== "string") {
1024    return defaultFilename;
1025  }
1026  if (isDataScheme(url)) {
1027    warn('getPdfFilenameFromUrl: ignore "data:"-URL for performance reasons.');
1028    return defaultFilename;
1029  }
1030  const reURI = /^(?:(?:[^:]+:)?\/\/[^/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
1031  const reFilename = /[^/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
1032  const splitURI = reURI.exec(url);
1033  let suggestedFilename = reFilename.exec(splitURI[1]) || reFilename.exec(splitURI[2]) || reFilename.exec(splitURI[3]);
1034  if (suggestedFilename) {
1035    suggestedFilename = suggestedFilename[0];
1036    if (suggestedFilename.includes("%")) {
1037      try {
1038        suggestedFilename = reFilename.exec(decodeURIComponent(suggestedFilename))[0];
1039      } catch {}
1040    }
1041  }
1042  return suggestedFilename || defaultFilename;
1043}
1044class StatTimer {
1045  started = Object.create(null);
1046  times = [];
1047  time(name) {
1048    if (name in this.started) {
1049      warn(`Timer is already running for ${name}`);
1050    }
1051    this.started[name] = Date.now();
1052  }
1053  timeEnd(name) {
1054    if (!(name in this.started)) {
1055      warn(`Timer has not been started for ${name}`);
1056    }
1057    this.times.push({
1058      name,
1059      start: this.started[name],
1060      end: Date.now()
1061    });
1062    delete this.started[name];
1063  }
1064  toString() {
1065    const outBuf = [];
1066    let longest = 0;
1067    for (const {
1068      name
1069    } of this.times) {
1070      longest = Math.max(name.length, longest);
1071    }
1072    for (const {
1073      name,
1074      start,
1075      end
1076    } of this.times) {
1077      outBuf.push(`${name.padEnd(longest)} ${end - start}ms\n`);
1078    }
1079    return outBuf.join("");
1080  }
1081}
1082function isValidFetchUrl(url, baseUrl) {
1083  try {
1084    const {
1085      protocol
1086    } = baseUrl ? new URL(url, baseUrl) : new URL(url);
1087    return protocol === "http:" || protocol === "https:";
1088  } catch {
1089    return false;
1090  }
1091}
1092function noContextMenu(e) {
1093  e.preventDefault();
1094}
1095function deprecated(details) {
1096  console.log("Deprecated API usage: " + details);
1097}
1098class PDFDateString {
1099  static #regex;
1100  static toDateObject(input) {
1101    if (!input || typeof input !== "string") {
1102      return null;
1103    }
1104    this.#regex ||= new RegExp("^D:" + "(\\d{4})" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "([Z|+|-])?" + "(\\d{2})?" + "'?" + "(\\d{2})?" + "'?");
1105    const matches = this.#regex.exec(input);
1106    if (!matches) {
1107      return null;
1108    }
1109    const year = parseInt(matches[1], 10);
1110    let month = parseInt(matches[2], 10);
vendor: 4,468 bytes, lines 1111-1263
1111    month = month >= 1 && month <= 12 ? month - 1 : 0;
1112    let day = parseInt(matches[3], 10);
1113    day = day >= 1 && day <= 31 ? day : 1;
1114    let hour = parseInt(matches[4], 10);
1115    hour = hour >= 0 && hour <= 23 ? hour : 0;
1116    let minute = parseInt(matches[5], 10);
1117    minute = minute >= 0 && minute <= 59 ? minute : 0;
1118    let second = parseInt(matches[6], 10);
1119    second = second >= 0 && second <= 59 ? second : 0;
1120    const universalTimeRelation = matches[7] || "Z";
1121    let offsetHour = parseInt(matches[8], 10);
1122    offsetHour = offsetHour >= 0 && offsetHour <= 23 ? offsetHour : 0;
1123    let offsetMinute = parseInt(matches[9], 10) || 0;
1124    offsetMinute = offsetMinute >= 0 && offsetMinute <= 59 ? offsetMinute : 0;
1125    if (universalTimeRelation === "-") {
1126      hour += offsetHour;
1127      minute += offsetMinute;
1128    } else if (universalTimeRelation === "+") {
1129      hour -= offsetHour;
1130      minute -= offsetMinute;
1131    }
1132    return new Date(Date.UTC(year, month, day, hour, minute, second));
1133  }
1134}
1135function getXfaPageViewport(xfaPage, {
1136  scale = 1,
1137  rotation = 0
1138}) {
1139  const {
1140    width,
1141    height
1142  } = xfaPage.attributes.style;
1143  const viewBox = [0, 0, parseInt(width), parseInt(height)];
1144  return new PageViewport({
1145    viewBox,
1146    scale,
1147    rotation
1148  });
1149}
1150function getRGB(color) {
1151  if (color.startsWith("#")) {
1152    const colorRGB = parseInt(color.slice(1), 16);
1153    return [(colorRGB & 0xff0000) >> 16, (colorRGB & 0x00ff00) >> 8, colorRGB & 0x0000ff];
1154  }
1155  if (color.startsWith("rgb(")) {
1156    return color.slice(4, -1).split(",").map(x => parseInt(x));
1157  }
1158  if (color.startsWith("rgba(")) {
1159    return color.slice(5, -1).split(",").map(x => parseInt(x)).slice(0, 3);
1160  }
1161  warn(`Not a valid color format: "${color}"`);
1162  return [0, 0, 0];
1163}
1164function getColorValues(colors) {
1165  const span = document.createElement("span");
1166  span.style.visibility = "hidden";
1167  document.body.append(span);
1168  for (const name of colors.keys()) {
1169    span.style.color = name;
1170    const computedColor = window.getComputedStyle(span).color;
1171    colors.set(name, getRGB(computedColor));
1172  }
1173  span.remove();
1174}
1175function getCurrentTransform(ctx) {
1176  const {
1177    a,
1178    b,
1179    c,
1180    d,
1181    e,
1182    f
1183  } = ctx.getTransform();
1184  return [a, b, c, d, e, f];
1185}
1186function getCurrentTransformInverse(ctx) {
1187  const {
1188    a,
1189    b,
1190    c,
1191    d,
1192    e,
1193    f
1194  } = ctx.getTransform().invertSelf();
1195  return [a, b, c, d, e, f];
1196}
1197function setLayerDimensions(div, viewport, mustFlip = false, mustRotate = true) {
1198  if (viewport instanceof PageViewport) {
1199    const {
1200      pageWidth,
1201      pageHeight
1202    } = viewport.rawDims;
1203    const {
1204      style
1205    } = div;
1206    const useRound = util_FeatureTest.isCSSRoundSupported;
1207    const w = `var(--scale-factor) * ${pageWidth}px`,
1208      h = `var(--scale-factor) * ${pageHeight}px`;
1209    const widthStr = useRound ? `round(down, ${w}, var(--scale-round-x, 1px))` : `calc(${w})`,
1210      heightStr = useRound ? `round(down, ${h}, var(--scale-round-y, 1px))` : `calc(${h})`;
1211    if (!mustFlip || viewport.rotation % 180 === 0) {
1212      style.width = widthStr;
1213      style.height = heightStr;
1214    } else {
1215      style.width = heightStr;
1216      style.height = widthStr;
1217    }
1218  }
1219  if (mustRotate) {
1220    div.setAttribute("data-main-rotation", viewport.rotation);
1221  }
1222}
1223class OutputScale {
1224  constructor() {
1225    const pixelRatio = window.devicePixelRatio || 1;
1226    this.sx = pixelRatio;
1227    this.sy = pixelRatio;
1228  }
1229  get scaled() {
1230    return this.sx !== 1 || this.sy !== 1;
1231  }
1232  get symmetric() {
1233    return this.sx === this.sy;
1234  }
1235}
1236
1237;// ./src/display/editor/toolbar.js
1238
1239class EditorToolbar {
1240  #toolbar = null;
1241  #colorPicker = null;
1242  #editor;
1243  #buttons = null;
1244  #altText = null;
1245  static #l10nRemove = null;
1246  constructor(editor) {
1247    this.#editor = editor;
1248    EditorToolbar.#l10nRemove ||= Object.freeze({
1249      freetext: "pdfjs-editor-remove-freetext-button",
1250      highlight: "pdfjs-editor-remove-highlight-button",
1251      ink: "pdfjs-editor-remove-ink-button",
1252      stamp: "pdfjs-editor-remove-stamp-button"
1253    });
1254  }
1255  render() {
1256    const editToolbar = this.#toolbar = document.createElement("div");
1257    editToolbar.classList.add("editToolbar", "hidden");
1258    editToolbar.setAttribute("role", "toolbar");
1259    const signal = this.#editor._uiManager._signal;
1260    editToolbar.addEventListener("contextmenu", noContextMenu, {
1261      signal
1262    });
1263    editToolbar.addEventListener("pointerdown", EditorToolbar.#pointerDown, {
vendor: 11,500 bytes, lines 1264-1701
1264      signal
1265    });
1266    const buttons = this.#buttons = document.createElement("div");
1267    buttons.className = "buttons";
1268    editToolbar.append(buttons);
1269    const position = this.#editor.toolbarPosition;
1270    if (position) {
1271      const {
1272        style
1273      } = editToolbar;
1274      const x = this.#editor._uiManager.direction === "ltr" ? 1 - position[0] : position[0];
1275      style.insetInlineEnd = `${100 * x}%`;
1276      style.top = `calc(${100 * position[1]}% + var(--editor-toolbar-vert-offset))`;
1277    }
1278    this.#addDeleteButton();
1279    return editToolbar;
1280  }
1281  get div() {
1282    return this.#toolbar;
1283  }
1284  static #pointerDown(e) {
1285    e.stopPropagation();
1286  }
1287  #focusIn(e) {
1288    this.#editor._focusEventsAllowed = false;
1289    e.preventDefault();
1290    e.stopPropagation();
1291  }
1292  #focusOut(e) {
1293    this.#editor._focusEventsAllowed = true;
1294    e.preventDefault();
1295    e.stopPropagation();
1296  }
1297  #addListenersToElement(element) {
1298    const signal = this.#editor._uiManager._signal;
1299    element.addEventListener("focusin", this.#focusIn.bind(this), {
1300      capture: true,
1301      signal
1302    });
1303    element.addEventListener("focusout", this.#focusOut.bind(this), {
1304      capture: true,
1305      signal
1306    });
1307    element.addEventListener("contextmenu", noContextMenu, {
1308      signal
1309    });
1310  }
1311  hide() {
1312    this.#toolbar.classList.add("hidden");
1313    this.#colorPicker?.hideDropdown();
1314  }
1315  show() {
1316    this.#toolbar.classList.remove("hidden");
1317    this.#altText?.shown();
1318  }
1319  #addDeleteButton() {
1320    const {
1321      editorType,
1322      _uiManager
1323    } = this.#editor;
1324    const button = document.createElement("button");
1325    button.className = "delete";
1326    button.tabIndex = 0;
1327    button.setAttribute("data-l10n-id", EditorToolbar.#l10nRemove[editorType]);
1328    this.#addListenersToElement(button);
1329    button.addEventListener("click", e => {
1330      _uiManager.delete();
1331    }, {
1332      signal: _uiManager._signal
1333    });
1334    this.#buttons.append(button);
1335  }
1336  get #divider() {
1337    const divider = document.createElement("div");
1338    divider.className = "divider";
1339    return divider;
1340  }
1341  async addAltText(altText) {
1342    const button = await altText.render();
1343    this.#addListenersToElement(button);
1344    this.#buttons.prepend(button, this.#divider);
1345    this.#altText = altText;
1346  }
1347  addColorPicker(colorPicker) {
1348    this.#colorPicker = colorPicker;
1349    const button = colorPicker.renderButton();
1350    this.#addListenersToElement(button);
1351    this.#buttons.prepend(button, this.#divider);
1352  }
1353  remove() {
1354    this.#toolbar.remove();
1355    this.#colorPicker?.destroy();
1356    this.#colorPicker = null;
1357  }
1358}
1359class HighlightToolbar {
1360  #buttons = null;
1361  #toolbar = null;
1362  #uiManager;
1363  constructor(uiManager) {
1364    this.#uiManager = uiManager;
1365  }
1366  #render() {
1367    const editToolbar = this.#toolbar = document.createElement("div");
1368    editToolbar.className = "editToolbar";
1369    editToolbar.setAttribute("role", "toolbar");
1370    editToolbar.addEventListener("contextmenu", noContextMenu, {
1371      signal: this.#uiManager._signal
1372    });
1373    const buttons = this.#buttons = document.createElement("div");
1374    buttons.className = "buttons";
1375    editToolbar.append(buttons);
1376    this.#addHighlightButton();
1377    return editToolbar;
1378  }
1379  #getLastPoint(boxes, isLTR) {
1380    let lastY = 0;
1381    let lastX = 0;
1382    for (const box of boxes) {
1383      const y = box.y + box.height;
1384      if (y < lastY) {
1385        continue;
1386      }
1387      const x = box.x + (isLTR ? box.width : 0);
1388      if (y > lastY) {
1389        lastX = x;
1390        lastY = y;
1391        continue;
1392      }
1393      if (isLTR) {
1394        if (x > lastX) {
1395          lastX = x;
1396        }
1397      } else if (x < lastX) {
1398        lastX = x;
1399      }
1400    }
1401    return [isLTR ? 1 - lastX : lastX, lastY];
1402  }
1403  show(parent, boxes, isLTR) {
1404    const [x, y] = this.#getLastPoint(boxes, isLTR);
1405    const {
1406      style
1407    } = this.#toolbar ||= this.#render();
1408    parent.append(this.#toolbar);
1409    style.insetInlineEnd = `${100 * x}%`;
1410    style.top = `calc(${100 * y}% + var(--editor-toolbar-vert-offset))`;
1411  }
1412  hide() {
1413    this.#toolbar.remove();
1414  }
1415  #addHighlightButton() {
1416    const button = document.createElement("button");
1417    button.className = "highlightButton";
1418    button.tabIndex = 0;
1419    button.setAttribute("data-l10n-id", `pdfjs-highlight-floating-button1`);
1420    const span = document.createElement("span");
1421    button.append(span);
1422    span.className = "visuallyHidden";
1423    span.setAttribute("data-l10n-id", "pdfjs-highlight-floating-button-label");
1424    const signal = this.#uiManager._signal;
1425    button.addEventListener("contextmenu", noContextMenu, {
1426      signal
1427    });
1428    button.addEventListener("click", () => {
1429      this.#uiManager.highlightSelection("floating_button");
1430    }, {
1431      signal
1432    });
1433    this.#buttons.append(button);
1434  }
1435}
1436
1437;// ./src/display/editor/tools.js
1438
1439
1440
1441function bindEvents(obj, element, names) {
1442  for (const name of names) {
1443    element.addEventListener(name, obj[name].bind(obj));
1444  }
1445}
1446function opacityToHex(opacity) {
1447  return Math.round(Math.min(255, Math.max(1, 255 * opacity))).toString(16).padStart(2, "0");
1448}
1449class IdManager {
1450  #id = 0;
1451  get id() {
1452    return `${AnnotationEditorPrefix}${this.#id++}`;
1453  }
1454}
1455class ImageManager {
1456  #baseId = getUuid();
1457  #id = 0;
1458  #cache = null;
1459  static get _isSVGFittingCanvas() {
1460    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>`;
1461    const canvas = new OffscreenCanvas(1, 3);
1462    const ctx = canvas.getContext("2d", {
1463      willReadFrequently: true
1464    });
1465    const image = new Image();
1466    image.src = svg;
1467    const promise = image.decode().then(() => {
1468      ctx.drawImage(image, 0, 0, 1, 1, 0, 0, 1, 3);
1469      return new Uint32Array(ctx.getImageData(0, 0, 1, 1).data.buffer)[0] === 0;
1470    });
1471    return shadow(this, "_isSVGFittingCanvas", promise);
1472  }
1473  async #get(key, rawData) {
1474    this.#cache ||= new Map();
1475    let data = this.#cache.get(key);
1476    if (data === null) {
1477      return null;
1478    }
1479    if (data?.bitmap) {
1480      data.refCounter += 1;
1481      return data;
1482    }
1483    try {
1484      data ||= {
1485        bitmap: null,
1486        id: `image_${this.#baseId}_${this.#id++}`,
1487        refCounter: 0,
1488        isSvg: false
1489      };
1490      let image;
1491      if (typeof rawData === "string") {
1492        data.url = rawData;
1493        image = await fetchData(rawData, "blob");
1494      } else if (rawData instanceof File) {
1495        image = data.file = rawData;
1496      } else if (rawData instanceof Blob) {
1497        image = rawData;
1498      }
1499      if (image.type === "image/svg+xml") {
1500        const mustRemoveAspectRatioPromise = ImageManager._isSVGFittingCanvas;
1501        const fileReader = new FileReader();
1502        const imageElement = new Image();
1503        const imagePromise = new Promise((resolve, reject) => {
1504          imageElement.onload = () => {
1505            data.bitmap = imageElement;
1506            data.isSvg = true;
1507            resolve();
1508          };
1509          fileReader.onload = async () => {
1510            const url = data.svgUrl = fileReader.result;
1511            imageElement.src = (await mustRemoveAspectRatioPromise) ? `${url}#svgView(preserveAspectRatio(none))` : url;
1512          };
1513          imageElement.onerror = fileReader.onerror = reject;
1514        });
1515        fileReader.readAsDataURL(image);
1516        await imagePromise;
1517      } else {
1518        data.bitmap = await createImageBitmap(image);
1519      }
1520      data.refCounter = 1;
1521    } catch (e) {
1522      console.error(e);
1523      data = null;
1524    }
1525    this.#cache.set(key, data);
1526    if (data) {
1527      this.#cache.set(data.id, data);
1528    }
1529    return data;
1530  }
1531  async getFromFile(file) {
1532    const {
1533      lastModified,
1534      name,
1535      size,
1536      type
1537    } = file;
1538    return this.#get(`${lastModified}_${name}_${size}_${type}`, file);
1539  }
1540  async getFromUrl(url) {
1541    return this.#get(url, url);
1542  }
1543  async getFromBlob(id, blobPromise) {
1544    const blob = await blobPromise;
1545    return this.#get(id, blob);
1546  }
1547  async getFromId(id) {
1548    this.#cache ||= new Map();
1549    const data = this.#cache.get(id);
1550    if (!data) {
1551      return null;
1552    }
1553    if (data.bitmap) {
1554      data.refCounter += 1;
1555      return data;
1556    }
1557    if (data.file) {
1558      return this.getFromFile(data.file);
1559    }
1560    if (data.blobPromise) {
1561      const {
1562        blobPromise
1563      } = data;
1564      delete data.blobPromise;
1565      return this.getFromBlob(data.id, blobPromise);
1566    }
1567    return this.getFromUrl(data.url);
1568  }
1569  getFromCanvas(id, canvas) {
1570    this.#cache ||= new Map();
1571    let data = this.#cache.get(id);
1572    if (data?.bitmap) {
1573      data.refCounter += 1;
1574      return data;
1575    }
1576    const offscreen = new OffscreenCanvas(canvas.width, canvas.height);
1577    const ctx = offscreen.getContext("2d");
1578    ctx.drawImage(canvas, 0, 0);
1579    data = {
1580      bitmap: offscreen.transferToImageBitmap(),
1581      id: `image_${this.#baseId}_${this.#id++}`,
1582      refCounter: 1,
1583      isSvg: false
1584    };
1585    this.#cache.set(id, data);
1586    this.#cache.set(data.id, data);
1587    return data;
1588  }
1589  getSvgUrl(id) {
1590    const data = this.#cache.get(id);
1591    if (!data?.isSvg) {
1592      return null;
1593    }
1594    return data.svgUrl;
1595  }
1596  deleteId(id) {
1597    this.#cache ||= new Map();
1598    const data = this.#cache.get(id);
1599    if (!data) {
1600      return;
1601    }
1602    data.refCounter -= 1;
1603    if (data.refCounter !== 0) {
1604      return;
1605    }
1606    const {
1607      bitmap
1608    } = data;
1609    if (!data.url && !data.file) {
1610      const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
1611      const ctx = canvas.getContext("bitmaprenderer");
1612      ctx.transferFromImageBitmap(bitmap);
1613      data.blobPromise = canvas.convertToBlob();
1614    }
1615    bitmap.close?.();
1616    data.bitmap = null;
1617  }
1618  isValidId(id) {
1619    return id.startsWith(`image_${this.#baseId}_`);
1620  }
1621}
1622class CommandManager {
1623  #commands = [];
1624  #locked = false;
1625  #maxSize;
1626  #position = -1;
1627  constructor(maxSize = 128) {
1628    this.#maxSize = maxSize;
1629  }
1630  add({
1631    cmd,
1632    undo,
1633    post,
1634    mustExec,
1635    type = NaN,
1636    overwriteIfSameType = false,
1637    keepUndo = false
1638  }) {
1639    if (mustExec) {
1640      cmd();
1641    }
1642    if (this.#locked) {
1643      return;
1644    }
1645    const save = {
1646      cmd,
1647      undo,
1648      post,
1649      type
1650    };
1651    if (this.#position === -1) {
1652      if (this.#commands.length > 0) {
1653        this.#commands.length = 0;
1654      }
1655      this.#position = 0;
1656      this.#commands.push(save);
1657      return;
1658    }
1659    if (overwriteIfSameType && this.#commands[this.#position].type === type) {
1660      if (keepUndo) {
1661        save.undo = this.#commands[this.#position].undo;
1662      }
1663      this.#commands[this.#position] = save;
1664      return;
1665    }
1666    const next = this.#position + 1;
1667    if (next === this.#maxSize) {
1668      this.#commands.splice(0, 1);
1669    } else {
1670      this.#position = next;
1671      if (next < this.#commands.length) {
1672        this.#commands.splice(next);
1673      }
1674    }
1675    this.#commands.push(save);
1676  }
1677  undo() {
1678    if (this.#position === -1) {
1679      return;
1680    }
1681    this.#locked = true;
1682    const {
1683      undo,
1684      post
1685    } = this.#commands[this.#position];
1686    undo();
1687    post?.();
1688    this.#locked = false;
1689    this.#position -= 1;
1690  }
1691  redo() {
1692    if (this.#position < this.#commands.length - 1) {
1693      this.#position += 1;
1694      this.#locked = true;
1695      const {
1696        cmd,
1697        post
1698      } = this.#commands[this.#position];
1699      cmd();
1700      post?.();
1701      this.#locked = false;
vendor: 7,958 bytes, lines 1702-1949
1702    }
1703  }
1704  hasSomethingToUndo() {
1705    return this.#position !== -1;
1706  }
1707  hasSomethingToRedo() {
1708    return this.#position < this.#commands.length - 1;
1709  }
1710  destroy() {
1711    this.#commands = null;
1712  }
1713}
1714class KeyboardManager {
1715  constructor(callbacks) {
1716    this.buffer = [];
1717    this.callbacks = new Map();
1718    this.allKeys = new Set();
1719    const {
1720      isMac
1721    } = util_FeatureTest.platform;
1722    for (const [keys, callback, options = {}] of callbacks) {
1723      for (const key of keys) {
1724        const isMacKey = key.startsWith("mac+");
1725        if (isMac && isMacKey) {
1726          this.callbacks.set(key.slice(4), {
1727            callback,
1728            options
1729          });
1730          this.allKeys.add(key.split("+").at(-1));
1731        } else if (!isMac && !isMacKey) {
1732          this.callbacks.set(key, {
1733            callback,
1734            options
1735          });
1736          this.allKeys.add(key.split("+").at(-1));
1737        }
1738      }
1739    }
1740  }
1741  #serialize(event) {
1742    if (event.altKey) {
1743      this.buffer.push("alt");
1744    }
1745    if (event.ctrlKey) {
1746      this.buffer.push("ctrl");
1747    }
1748    if (event.metaKey) {
1749      this.buffer.push("meta");
1750    }
1751    if (event.shiftKey) {
1752      this.buffer.push("shift");
1753    }
1754    this.buffer.push(event.key);
1755    const str = this.buffer.join("+");
1756    this.buffer.length = 0;
1757    return str;
1758  }
1759  exec(self, event) {
1760    if (!this.allKeys.has(event.key)) {
1761      return;
1762    }
1763    const info = this.callbacks.get(this.#serialize(event));
1764    if (!info) {
1765      return;
1766    }
1767    const {
1768      callback,
1769      options: {
1770        bubbles = false,
1771        args = [],
1772        checker = null
1773      }
1774    } = info;
1775    if (checker && !checker(self, event)) {
1776      return;
1777    }
1778    callback.bind(self, ...args, event)();
1779    if (!bubbles) {
1780      event.stopPropagation();
1781      event.preventDefault();
1782    }
1783  }
1784}
1785class ColorManager {
1786  static _colorsMapping = new Map([["CanvasText", [0, 0, 0]], ["Canvas", [255, 255, 255]]]);
1787  get _colors() {
1788    const colors = new Map([["CanvasText", null], ["Canvas", null]]);
1789    getColorValues(colors);
1790    return shadow(this, "_colors", colors);
1791  }
1792  convert(color) {
1793    const rgb = getRGB(color);
1794    if (!window.matchMedia("(forced-colors: active)").matches) {
1795      return rgb;
1796    }
1797    for (const [name, RGB] of this._colors) {
1798      if (RGB.every((x, i) => x === rgb[i])) {
1799        return ColorManager._colorsMapping.get(name);
1800      }
1801    }
1802    return rgb;
1803  }
1804  getHexCode(name) {
1805    const rgb = this._colors.get(name);
1806    if (!rgb) {
1807      return name;
1808    }
1809    return Util.makeHexColor(...rgb);
1810  }
1811}
1812class AnnotationEditorUIManager {
1813  #abortController = new AbortController();
1814  #activeEditor = null;
1815  #allEditors = new Map();
1816  #allLayers = new Map();
1817  #altTextManager = null;
1818  #annotationStorage = null;
1819  #changedExistingAnnotations = null;
1820  #commandManager = new CommandManager();
1821  #copyPasteAC = null;
1822  #currentPageIndex = 0;
1823  #deletedAnnotationsElementIds = new Set();
1824  #draggingEditors = null;
1825  #editorTypes = null;
1826  #editorsToRescale = new Set();
1827  #enableHighlightFloatingButton = false;
1828  #enableUpdatedAddImage = false;
1829  #enableNewAltTextWhenAddingImage = false;
1830  #filterFactory = null;
1831  #focusMainContainerTimeoutId = null;
1832  #focusManagerAC = null;
1833  #highlightColors = null;
1834  #highlightWhenShiftUp = false;
1835  #highlightToolbar = null;
1836  #idManager = new IdManager();
1837  #isEnabled = false;
1838  #isWaiting = false;
1839  #keyboardManagerAC = null;
1840  #lastActiveElement = null;
1841  #mainHighlightColorPicker = null;
1842  #mlManager = null;
1843  #mode = AnnotationEditorType.NONE;
1844  #selectedEditors = new Set();
1845  #selectedTextNode = null;
1846  #pageColors = null;
1847  #showAllStates = null;
1848  #previousStates = {
1849    isEditing: false,
1850    isEmpty: true,
1851    hasSomethingToUndo: false,
1852    hasSomethingToRedo: false,
1853    hasSelectedEditor: false,
1854    hasSelectedText: false
1855  };
1856  #translation = [0, 0];
1857  #translationTimeoutId = null;
1858  #container = null;
1859  #viewer = null;
1860  #updateModeCapability = null;
1861  static TRANSLATE_SMALL = 1;
1862  static TRANSLATE_BIG = 10;
1863  static get _keyboardManager() {
1864    const proto = AnnotationEditorUIManager.prototype;
1865    const arrowChecker = self => self.#container.contains(document.activeElement) && document.activeElement.tagName !== "BUTTON" && self.hasSomethingToControl();
1866    const textInputChecker = (_self, {
1867      target: el
1868    }) => {
1869      if (el instanceof HTMLInputElement) {
1870        const {
1871          type
1872        } = el;
1873        return type !== "text" && type !== "number";
1874      }
1875      return true;
1876    };
1877    const small = this.TRANSLATE_SMALL;
1878    const big = this.TRANSLATE_BIG;
1879    return shadow(this, "_keyboardManager", new KeyboardManager([[["ctrl+a", "mac+meta+a"], proto.selectAll, {
1880      checker: textInputChecker
1881    }], [["ctrl+z", "mac+meta+z"], proto.undo, {
1882      checker: textInputChecker
1883    }], [["ctrl+y", "ctrl+shift+z", "mac+meta+shift+z", "ctrl+shift+Z", "mac+meta+shift+Z"], proto.redo, {
1884      checker: textInputChecker
1885    }], [["Backspace", "alt+Backspace", "ctrl+Backspace", "shift+Backspace", "mac+Backspace", "mac+alt+Backspace", "mac+ctrl+Backspace", "Delete", "ctrl+Delete", "shift+Delete", "mac+Delete"], proto.delete, {
1886      checker: textInputChecker
1887    }], [["Enter", "mac+Enter"], proto.addNewEditorFromKeyboard, {
1888      checker: (self, {
1889        target: el
1890      }) => !(el instanceof HTMLButtonElement) && self.#container.contains(el) && !self.isEnterHandled
1891    }], [[" ", "mac+ "], proto.addNewEditorFromKeyboard, {
1892      checker: (self, {
1893        target: el
1894      }) => !(el instanceof HTMLButtonElement) && self.#container.contains(document.activeElement)
1895    }], [["Escape", "mac+Escape"], proto.unselectAll], [["ArrowLeft", "mac+ArrowLeft"], proto.translateSelectedEditors, {
1896      args: [-small, 0],
1897      checker: arrowChecker
1898    }], [["ctrl+ArrowLeft", "mac+shift+ArrowLeft"], proto.translateSelectedEditors, {
1899      args: [-big, 0],
1900      checker: arrowChecker
1901    }], [["ArrowRight", "mac+ArrowRight"], proto.translateSelectedEditors, {
1902      args: [small, 0],
1903      checker: arrowChecker
1904    }], [["ctrl+ArrowRight", "mac+shift+ArrowRight"], proto.translateSelectedEditors, {
1905      args: [big, 0],
1906      checker: arrowChecker
1907    }], [["ArrowUp", "mac+ArrowUp"], proto.translateSelectedEditors, {
1908      args: [0, -small],
1909      checker: arrowChecker
1910    }], [["ctrl+ArrowUp", "mac+shift+ArrowUp"], proto.translateSelectedEditors, {
1911      args: [0, -big],
1912      checker: arrowChecker
1913    }], [["ArrowDown", "mac+ArrowDown"], proto.translateSelectedEditors, {
1914      args: [0, small],
1915      checker: arrowChecker
1916    }], [["ctrl+ArrowDown", "mac+shift+ArrowDown"], proto.translateSelectedEditors, {
1917      args: [0, big],
1918      checker: arrowChecker
1919    }]]));
1920  }
1921  constructor(container, viewer, altTextManager, eventBus, pdfDocument, pageColors, highlightColors, enableHighlightFloatingButton, enableUpdatedAddImage, enableNewAltTextWhenAddingImage, mlManager) {
1922    const signal = this._signal = this.#abortController.signal;
1923    this.#container = container;
1924    this.#viewer = viewer;
1925    this.#altTextManager = altTextManager;
1926    this._eventBus = eventBus;
1927    eventBus._on("editingaction", this.onEditingAction.bind(this), {
1928      signal
1929    });
1930    eventBus._on("pagechanging", this.onPageChanging.bind(this), {
1931      signal
1932    });
1933    eventBus._on("scalechanging", this.onScaleChanging.bind(this), {
1934      signal
1935    });
1936    eventBus._on("rotationchanging", this.onRotationChanging.bind(this), {
1937      signal
1938    });
1939    eventBus._on("setpreference", this.onSetPreference.bind(this), {
1940      signal
1941    });
1942    eventBus._on("switchannotationeditorparams", evt => this.updateParams(evt.type, evt.value), {
1943      signal
1944    });
1945    this.#addSelectionListener();
1946    this.#addDragAndDropListeners();
1947    this.#addKeyboardManager();
1948    this.#annotationStorage = pdfDocument.annotationStorage;
1949    this.#filterFactory = pdfDocument.filterFactory;
vendor: 9,411 bytes, lines 1950-2269
1950    this.#pageColors = pageColors;
1951    this.#highlightColors = highlightColors || null;
1952    this.#enableHighlightFloatingButton = enableHighlightFloatingButton;
1953    this.#enableUpdatedAddImage = enableUpdatedAddImage;
1954    this.#enableNewAltTextWhenAddingImage = enableNewAltTextWhenAddingImage;
1955    this.#mlManager = mlManager || null;
1956    this.viewParameters = {
1957      realScale: PixelsPerInch.PDF_TO_CSS_UNITS,
1958      rotation: 0
1959    };
1960    this.isShiftKeyDown = false;
1961  }
1962  destroy() {
1963    this.#updateModeCapability?.resolve();
1964    this.#updateModeCapability = null;
1965    this.#abortController?.abort();
1966    this.#abortController = null;
1967    this._signal = null;
1968    for (const layer of this.#allLayers.values()) {
1969      layer.destroy();
1970    }
1971    this.#allLayers.clear();
1972    this.#allEditors.clear();
1973    this.#editorsToRescale.clear();
1974    this.#activeEditor = null;
1975    this.#selectedEditors.clear();
1976    this.#commandManager.destroy();
1977    this.#altTextManager?.destroy();
1978    this.#highlightToolbar?.hide();
1979    this.#highlightToolbar = null;
1980    if (this.#focusMainContainerTimeoutId) {
1981      clearTimeout(this.#focusMainContainerTimeoutId);
1982      this.#focusMainContainerTimeoutId = null;
1983    }
1984    if (this.#translationTimeoutId) {
1985      clearTimeout(this.#translationTimeoutId);
1986      this.#translationTimeoutId = null;
1987    }
1988  }
1989  combinedSignal(ac) {
1990    return AbortSignal.any([this._signal, ac.signal]);
1991  }
1992  get mlManager() {
1993    return this.#mlManager;
1994  }
1995  get useNewAltTextFlow() {
1996    return this.#enableUpdatedAddImage;
1997  }
1998  get useNewAltTextWhenAddingImage() {
1999    return this.#enableNewAltTextWhenAddingImage;
2000  }
2001  get hcmFilter() {
2002    return shadow(this, "hcmFilter", this.#pageColors ? this.#filterFactory.addHCMFilter(this.#pageColors.foreground, this.#pageColors.background) : "none");
2003  }
2004  get direction() {
2005    return shadow(this, "direction", getComputedStyle(this.#container).direction);
2006  }
2007  get highlightColors() {
2008    return shadow(this, "highlightColors", this.#highlightColors ? new Map(this.#highlightColors.split(",").map(pair => pair.split("=").map(x => x.trim()))) : null);
2009  }
2010  get highlightColorNames() {
2011    return shadow(this, "highlightColorNames", this.highlightColors ? new Map(Array.from(this.highlightColors, e => e.reverse())) : null);
2012  }
2013  setMainHighlightColorPicker(colorPicker) {
2014    this.#mainHighlightColorPicker = colorPicker;
2015  }
2016  editAltText(editor, firstTime = false) {
2017    this.#altTextManager?.editAltText(this, editor, firstTime);
2018  }
2019  switchToMode(mode, callback) {
2020    this._eventBus.on("annotationeditormodechanged", callback, {
2021      once: true,
2022      signal: this._signal
2023    });
2024    this._eventBus.dispatch("showannotationeditorui", {
2025      source: this,
2026      mode
2027    });
2028  }
2029  setPreference(name, value) {
2030    this._eventBus.dispatch("setpreference", {
2031      source: this,
2032      name,
2033      value
2034    });
2035  }
2036  onSetPreference({
2037    name,
2038    value
2039  }) {
2040    switch (name) {
2041      case "enableNewAltTextWhenAddingImage":
2042        this.#enableNewAltTextWhenAddingImage = value;
2043        break;
2044    }
2045  }
2046  onPageChanging({
2047    pageNumber
2048  }) {
2049    this.#currentPageIndex = pageNumber - 1;
2050  }
2051  focusMainContainer() {
2052    this.#container.focus();
2053  }
2054  findParent(x, y) {
2055    for (const layer of this.#allLayers.values()) {
2056      const {
2057        x: layerX,
2058        y: layerY,
2059        width,
2060        height
2061      } = layer.div.getBoundingClientRect();
2062      if (x >= layerX && x <= layerX + width && y >= layerY && y <= layerY + height) {
2063        return layer;
2064      }
2065    }
2066    return null;
2067  }
2068  disableUserSelect(value = false) {
2069    this.#viewer.classList.toggle("noUserSelect", value);
2070  }
2071  addShouldRescale(editor) {
2072    this.#editorsToRescale.add(editor);
2073  }
2074  removeShouldRescale(editor) {
2075    this.#editorsToRescale.delete(editor);
2076  }
2077  onScaleChanging({
2078    scale
2079  }) {
2080    this.commitOrRemove();
2081    this.viewParameters.realScale = scale * PixelsPerInch.PDF_TO_CSS_UNITS;
2082    for (const editor of this.#editorsToRescale) {
2083      editor.onScaleChanging();
2084    }
2085  }
2086  onRotationChanging({
2087    pagesRotation
2088  }) {
2089    this.commitOrRemove();
2090    this.viewParameters.rotation = pagesRotation;
2091  }
2092  #getAnchorElementForSelection({
2093    anchorNode
2094  }) {
2095    return anchorNode.nodeType === Node.TEXT_NODE ? anchorNode.parentElement : anchorNode;
2096  }
2097  #getLayerForTextLayer(textLayer) {
2098    const {
2099      currentLayer
2100    } = this;
2101    if (currentLayer.hasTextLayer(textLayer)) {
2102      return currentLayer;
2103    }
2104    for (const layer of this.#allLayers.values()) {
2105      if (layer.hasTextLayer(textLayer)) {
2106        return layer;
2107      }
2108    }
2109    return null;
2110  }
2111  highlightSelection(methodOfCreation = "") {
2112    const selection = document.getSelection();
2113    if (!selection || selection.isCollapsed) {
2114      return;
2115    }
2116    const {
2117      anchorNode,
2118      anchorOffset,
2119      focusNode,
2120      focusOffset
2121    } = selection;
2122    const text = selection.toString();
2123    const anchorElement = this.#getAnchorElementForSelection(selection);
2124    const textLayer = anchorElement.closest(".textLayer");
2125    const boxes = this.getSelectionBoxes(textLayer);
2126    if (!boxes) {
2127      return;
2128    }
2129    selection.empty();
2130    const layer = this.#getLayerForTextLayer(textLayer);
2131    const isNoneMode = this.#mode === AnnotationEditorType.NONE;
2132    const callback = () => {
2133      layer?.createAndAddNewEditor({
2134        x: 0,
2135        y: 0
2136      }, false, {
2137        methodOfCreation,
2138        boxes,
2139        anchorNode,
2140        anchorOffset,
2141        focusNode,
2142        focusOffset,
2143        text
2144      });
2145      if (isNoneMode) {
2146        this.showAllEditors("highlight", true, true);
2147      }
2148    };
2149    if (isNoneMode) {
2150      this.switchToMode(AnnotationEditorType.HIGHLIGHT, callback);
2151      return;
2152    }
2153    callback();
2154  }
2155  #displayHighlightToolbar() {
2156    const selection = document.getSelection();
2157    if (!selection || selection.isCollapsed) {
2158      return;
2159    }
2160    const anchorElement = this.#getAnchorElementForSelection(selection);
2161    const textLayer = anchorElement.closest(".textLayer");
2162    const boxes = this.getSelectionBoxes(textLayer);
2163    if (!boxes) {
2164      return;
2165    }
2166    this.#highlightToolbar ||= new HighlightToolbar(this);
2167    this.#highlightToolbar.show(textLayer, boxes, this.direction === "ltr");
2168  }
2169  addToAnnotationStorage(editor) {
2170    if (!editor.isEmpty() && this.#annotationStorage && !this.#annotationStorage.has(editor.id)) {
2171      this.#annotationStorage.setValue(editor.id, editor);
2172    }
2173  }
2174  #selectionChange() {
2175    const selection = document.getSelection();
2176    if (!selection || selection.isCollapsed) {
2177      if (this.#selectedTextNode) {
2178        this.#highlightToolbar?.hide();
2179        this.#selectedTextNode = null;
2180        this.#dispatchUpdateStates({
2181          hasSelectedText: false
2182        });
2183      }
2184      return;
2185    }
2186    const {
2187      anchorNode
2188    } = selection;
2189    if (anchorNode === this.#selectedTextNode) {
2190      return;
2191    }
2192    const anchorElement = this.#getAnchorElementForSelection(selection);
2193    const textLayer = anchorElement.closest(".textLayer");
2194    if (!textLayer) {
2195      if (this.#selectedTextNode) {
2196        this.#highlightToolbar?.hide();
2197        this.#selectedTextNode = null;
2198        this.#dispatchUpdateStates({
2199          hasSelectedText: false
2200        });
2201      }
2202      return;
2203    }
2204    this.#highlightToolbar?.hide();
2205    this.#selectedTextNode = anchorNode;
2206    this.#dispatchUpdateStates({
2207      hasSelectedText: true
2208    });
2209    if (this.#mode !== AnnotationEditorType.HIGHLIGHT && this.#mode !== AnnotationEditorType.NONE) {
2210      return;
2211    }
2212    if (this.#mode === AnnotationEditorType.HIGHLIGHT) {
2213      this.showAllEditors("highlight", true, true);
2214    }
2215    this.#highlightWhenShiftUp = this.isShiftKeyDown;
2216    if (!this.isShiftKeyDown) {
2217      const activeLayer = this.#mode === AnnotationEditorType.HIGHLIGHT ? this.#getLayerForTextLayer(textLayer) : null;
2218      activeLayer?.toggleDrawing();
2219      const ac = new AbortController();
2220      const signal = this.combinedSignal(ac);
2221      const pointerup = e => {
2222        if (e.type === "pointerup" && e.button !== 0) {
2223          return;
2224        }
2225        ac.abort();
2226        activeLayer?.toggleDrawing(true);
2227        if (e.type === "pointerup") {
2228          this.#onSelectEnd("main_toolbar");
2229        }
2230      };
2231      window.addEventListener("pointerup", pointerup, {
2232        signal
2233      });
2234      window.addEventListener("blur", pointerup, {
2235        signal
2236      });
2237    }
2238  }
2239  #onSelectEnd(methodOfCreation = "") {
2240    if (this.#mode === AnnotationEditorType.HIGHLIGHT) {
2241      this.highlightSelection(methodOfCreation);
2242    } else if (this.#enableHighlightFloatingButton) {
2243      this.#displayHighlightToolbar();
2244    }
2245  }
2246  #addSelectionListener() {
2247    document.addEventListener("selectionchange", this.#selectionChange.bind(this), {
2248      signal: this._signal
2249    });
2250  }
2251  #addFocusManager() {
2252    if (this.#focusManagerAC) {
2253      return;
2254    }
2255    this.#focusManagerAC = new AbortController();
2256    const signal = this.combinedSignal(this.#focusManagerAC);
2257    window.addEventListener("focus", this.focus.bind(this), {
2258      signal
2259    });
2260    window.addEventListener("blur", this.blur.bind(this), {
2261      signal
2262    });
2263  }
2264  #removeFocusManager() {
2265    this.#focusManagerAC?.abort();
2266    this.#focusManagerAC = null;
2267  }
2268  blur() {
2269    this.isShiftKeyDown = false;
vendor: 15,894 bytes, lines 2270-2853
2270    if (this.#highlightWhenShiftUp) {
2271      this.#highlightWhenShiftUp = false;
2272      this.#onSelectEnd("main_toolbar");
2273    }
2274    if (!this.hasSelection) {
2275      return;
2276    }
2277    const {
2278      activeElement
2279    } = document;
2280    for (const editor of this.#selectedEditors) {
2281      if (editor.div.contains(activeElement)) {
2282        this.#lastActiveElement = [editor, activeElement];
2283        editor._focusEventsAllowed = false;
2284        break;
2285      }
2286    }
2287  }
2288  focus() {
2289    if (!this.#lastActiveElement) {
2290      return;
2291    }
2292    const [lastEditor, lastActiveElement] = this.#lastActiveElement;
2293    this.#lastActiveElement = null;
2294    lastActiveElement.addEventListener("focusin", () => {
2295      lastEditor._focusEventsAllowed = true;
2296    }, {
2297      once: true,
2298      signal: this._signal
2299    });
2300    lastActiveElement.focus();
2301  }
2302  #addKeyboardManager() {
2303    if (this.#keyboardManagerAC) {
2304      return;
2305    }
2306    this.#keyboardManagerAC = new AbortController();
2307    const signal = this.combinedSignal(this.#keyboardManagerAC);
2308    window.addEventListener("keydown", this.keydown.bind(this), {
2309      signal
2310    });
2311    window.addEventListener("keyup", this.keyup.bind(this), {
2312      signal
2313    });
2314  }
2315  #removeKeyboardManager() {
2316    this.#keyboardManagerAC?.abort();
2317    this.#keyboardManagerAC = null;
2318  }
2319  #addCopyPasteListeners() {
2320    if (this.#copyPasteAC) {
2321      return;
2322    }
2323    this.#copyPasteAC = new AbortController();
2324    const signal = this.combinedSignal(this.#copyPasteAC);
2325    document.addEventListener("copy", this.copy.bind(this), {
2326      signal
2327    });
2328    document.addEventListener("cut", this.cut.bind(this), {
2329      signal
2330    });
2331    document.addEventListener("paste", this.paste.bind(this), {
2332      signal
2333    });
2334  }
2335  #removeCopyPasteListeners() {
2336    this.#copyPasteAC?.abort();
2337    this.#copyPasteAC = null;
2338  }
2339  #addDragAndDropListeners() {
2340    const signal = this._signal;
2341    document.addEventListener("dragover", this.dragOver.bind(this), {
2342      signal
2343    });
2344    document.addEventListener("drop", this.drop.bind(this), {
2345      signal
2346    });
2347  }
2348  addEditListeners() {
2349    this.#addKeyboardManager();
2350    this.#addCopyPasteListeners();
2351  }
2352  removeEditListeners() {
2353    this.#removeKeyboardManager();
2354    this.#removeCopyPasteListeners();
2355  }
2356  dragOver(event) {
2357    for (const {
2358      type
2359    } of event.dataTransfer.items) {
2360      for (const editorType of this.#editorTypes) {
2361        if (editorType.isHandlingMimeForPasting(type)) {
2362          event.dataTransfer.dropEffect = "copy";
2363          event.preventDefault();
2364          return;
2365        }
2366      }
2367    }
2368  }
2369  drop(event) {
2370    for (const item of event.dataTransfer.items) {
2371      for (const editorType of this.#editorTypes) {
2372        if (editorType.isHandlingMimeForPasting(item.type)) {
2373          editorType.paste(item, this.currentLayer);
2374          event.preventDefault();
2375          return;
2376        }
2377      }
2378    }
2379  }
2380  copy(event) {
2381    event.preventDefault();
2382    this.#activeEditor?.commitOrRemove();
2383    if (!this.hasSelection) {
2384      return;
2385    }
2386    const editors = [];
2387    for (const editor of this.#selectedEditors) {
2388      const serialized = editor.serialize(true);
2389      if (serialized) {
2390        editors.push(serialized);
2391      }
2392    }
2393    if (editors.length === 0) {
2394      return;
2395    }
2396    event.clipboardData.setData("application/pdfjs", JSON.stringify(editors));
2397  }
2398  cut(event) {
2399    this.copy(event);
2400    this.delete();
2401  }
2402  async paste(event) {
2403    event.preventDefault();
2404    const {
2405      clipboardData
2406    } = event;
2407    for (const item of clipboardData.items) {
2408      for (const editorType of this.#editorTypes) {
2409        if (editorType.isHandlingMimeForPasting(item.type)) {
2410          editorType.paste(item, this.currentLayer);
2411          return;
2412        }
2413      }
2414    }
2415    let data = clipboardData.getData("application/pdfjs");
2416    if (!data) {
2417      return;
2418    }
2419    try {
2420      data = JSON.parse(data);
2421    } catch (ex) {
2422      warn(`paste: "${ex.message}".`);
2423      return;
2424    }
2425    if (!Array.isArray(data)) {
2426      return;
2427    }
2428    this.unselectAll();
2429    const layer = this.currentLayer;
2430    try {
2431      const newEditors = [];
2432      for (const editor of data) {
2433        const deserializedEditor = await layer.deserialize(editor);
2434        if (!deserializedEditor) {
2435          return;
2436        }
2437        newEditors.push(deserializedEditor);
2438      }
2439      const cmd = () => {
2440        for (const editor of newEditors) {
2441          this.#addEditorToLayer(editor);
2442        }
2443        this.#selectEditors(newEditors);
2444      };
2445      const undo = () => {
2446        for (const editor of newEditors) {
2447          editor.remove();
2448        }
2449      };
2450      this.addCommands({
2451        cmd,
2452        undo,
2453        mustExec: true
2454      });
2455    } catch (ex) {
2456      warn(`paste: "${ex.message}".`);
2457    }
2458  }
2459  keydown(event) {
2460    if (!this.isShiftKeyDown && event.key === "Shift") {
2461      this.isShiftKeyDown = true;
2462    }
2463    if (this.#mode !== AnnotationEditorType.NONE && !this.isEditorHandlingKeyboard) {
2464      AnnotationEditorUIManager._keyboardManager.exec(this, event);
2465    }
2466  }
2467  keyup(event) {
2468    if (this.isShiftKeyDown && event.key === "Shift") {
2469      this.isShiftKeyDown = false;
2470      if (this.#highlightWhenShiftUp) {
2471        this.#highlightWhenShiftUp = false;
2472        this.#onSelectEnd("main_toolbar");
2473      }
2474    }
2475  }
2476  onEditingAction({
2477    name
2478  }) {
2479    switch (name) {
2480      case "undo":
2481      case "redo":
2482      case "delete":
2483      case "selectAll":
2484        this[name]();
2485        break;
2486      case "highlightSelection":
2487        this.highlightSelection("context_menu");
2488        break;
2489    }
2490  }
2491  #dispatchUpdateStates(details) {
2492    const hasChanged = Object.entries(details).some(([key, value]) => this.#previousStates[key] !== value);
2493    if (hasChanged) {
2494      this._eventBus.dispatch("annotationeditorstateschanged", {
2495        source: this,
2496        details: Object.assign(this.#previousStates, details)
2497      });
2498      if (this.#mode === AnnotationEditorType.HIGHLIGHT && details.hasSelectedEditor === false) {
2499        this.#dispatchUpdateUI([[AnnotationEditorParamsType.HIGHLIGHT_FREE, true]]);
2500      }
2501    }
2502  }
2503  #dispatchUpdateUI(details) {
2504    this._eventBus.dispatch("annotationeditorparamschanged", {
2505      source: this,
2506      details
2507    });
2508  }
2509  setEditingState(isEditing) {
2510    if (isEditing) {
2511      this.#addFocusManager();
2512      this.#addCopyPasteListeners();
2513      this.#dispatchUpdateStates({
2514        isEditing: this.#mode !== AnnotationEditorType.NONE,
2515        isEmpty: this.#isEmpty(),
2516        hasSomethingToUndo: this.#commandManager.hasSomethingToUndo(),
2517        hasSomethingToRedo: this.#commandManager.hasSomethingToRedo(),
2518        hasSelectedEditor: false
2519      });
2520    } else {
2521      this.#removeFocusManager();
2522      this.#removeCopyPasteListeners();
2523      this.#dispatchUpdateStates({
2524        isEditing: false
2525      });
2526      this.disableUserSelect(false);
2527    }
2528  }
2529  registerEditorTypes(types) {
2530    if (this.#editorTypes) {
2531      return;
2532    }
2533    this.#editorTypes = types;
2534    for (const editorType of this.#editorTypes) {
2535      this.#dispatchUpdateUI(editorType.defaultPropertiesToUpdate);
2536    }
2537  }
2538  getId() {
2539    return this.#idManager.id;
2540  }
2541  get currentLayer() {
2542    return this.#allLayers.get(this.#currentPageIndex);
2543  }
2544  getLayer(pageIndex) {
2545    return this.#allLayers.get(pageIndex);
2546  }
2547  get currentPageIndex() {
2548    return this.#currentPageIndex;
2549  }
2550  addLayer(layer) {
2551    this.#allLayers.set(layer.pageIndex, layer);
2552    if (this.#isEnabled) {
2553      layer.enable();
2554    } else {
2555      layer.disable();
2556    }
2557  }
2558  removeLayer(layer) {
2559    this.#allLayers.delete(layer.pageIndex);
2560  }
2561  async updateMode(mode, editId = null, isFromKeyboard = false) {
2562    if (this.#mode === mode) {
2563      return;
2564    }
2565    if (this.#updateModeCapability) {
2566      await this.#updateModeCapability.promise;
2567      if (!this.#updateModeCapability) {
2568        return;
2569      }
2570    }
2571    this.#updateModeCapability = Promise.withResolvers();
2572    this.#mode = mode;
2573    if (mode === AnnotationEditorType.NONE) {
2574      this.setEditingState(false);
2575      this.#disableAll();
2576      this.#updateModeCapability.resolve();
2577      return;
2578    }
2579    this.setEditingState(true);
2580    await this.#enableAll();
2581    this.unselectAll();
2582    for (const layer of this.#allLayers.values()) {
2583      layer.updateMode(mode);
2584    }
2585    if (!editId) {
2586      if (isFromKeyboard) {
2587        this.addNewEditorFromKeyboard();
2588      }
2589      this.#updateModeCapability.resolve();
2590      return;
2591    }
2592    for (const editor of this.#allEditors.values()) {
2593      if (editor.annotationElementId === editId) {
2594        this.setSelected(editor);
2595        editor.enterInEditMode();
2596      } else {
2597        editor.unselect();
2598      }
2599    }
2600    this.#updateModeCapability.resolve();
2601  }
2602  addNewEditorFromKeyboard() {
2603    if (this.currentLayer.canCreateNewEmptyEditor()) {
2604      this.currentLayer.addNewEditor();
2605    }
2606  }
2607  updateToolbar(mode) {
2608    if (mode === this.#mode) {
2609      return;
2610    }
2611    this._eventBus.dispatch("switchannotationeditormode", {
2612      source: this,
2613      mode
2614    });
2615  }
2616  updateParams(type, value) {
2617    if (!this.#editorTypes) {
2618      return;
2619    }
2620    switch (type) {
2621      case AnnotationEditorParamsType.CREATE:
2622        this.currentLayer.addNewEditor();
2623        return;
2624      case AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR:
2625        this.#mainHighlightColorPicker?.updateColor(value);
2626        break;
2627      case AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL:
2628        this._eventBus.dispatch("reporttelemetry", {
2629          source: this,
2630          details: {
2631            type: "editing",
2632            data: {
2633              type: "highlight",
2634              action: "toggle_visibility"
2635            }
2636          }
2637        });
2638        (this.#showAllStates ||= new Map()).set(type, value);
2639        this.showAllEditors("highlight", value);
2640        break;
2641    }
2642    for (const editor of this.#selectedEditors) {
2643      editor.updateParams(type, value);
2644    }
2645    for (const editorType of this.#editorTypes) {
2646      editorType.updateDefaultParams(type, value);
2647    }
2648  }
2649  showAllEditors(type, visible, updateButton = false) {
2650    for (const editor of this.#allEditors.values()) {
2651      if (editor.editorType === type) {
2652        editor.show(visible);
2653      }
2654    }
2655    const state = this.#showAllStates?.get(AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL) ?? true;
2656    if (state !== visible) {
2657      this.#dispatchUpdateUI([[AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL, visible]]);
2658    }
2659  }
2660  enableWaiting(mustWait = false) {
2661    if (this.#isWaiting === mustWait) {
2662      return;
2663    }
2664    this.#isWaiting = mustWait;
2665    for (const layer of this.#allLayers.values()) {
2666      if (mustWait) {
2667        layer.disableClick();
2668      } else {
2669        layer.enableClick();
2670      }
2671      layer.div.classList.toggle("waiting", mustWait);
2672    }
2673  }
2674  async #enableAll() {
2675    if (!this.#isEnabled) {
2676      this.#isEnabled = true;
2677      const promises = [];
2678      for (const layer of this.#allLayers.values()) {
2679        promises.push(layer.enable());
2680      }
2681      await Promise.all(promises);
2682      for (const editor of this.#allEditors.values()) {
2683        editor.enable();
2684      }
2685    }
2686  }
2687  #disableAll() {
2688    this.unselectAll();
2689    if (this.#isEnabled) {
2690      this.#isEnabled = false;
2691      for (const layer of this.#allLayers.values()) {
2692        layer.disable();
2693      }
2694      for (const editor of this.#allEditors.values()) {
2695        editor.disable();
2696      }
2697    }
2698  }
2699  getEditors(pageIndex) {
2700    const editors = [];
2701    for (const editor of this.#allEditors.values()) {
2702      if (editor.pageIndex === pageIndex) {
2703        editors.push(editor);
2704      }
2705    }
2706    return editors;
2707  }
2708  getEditor(id) {
2709    return this.#allEditors.get(id);
2710  }
2711  addEditor(editor) {
2712    this.#allEditors.set(editor.id, editor);
2713  }
2714  removeEditor(editor) {
2715    if (editor.div.contains(document.activeElement)) {
2716      if (this.#focusMainContainerTimeoutId) {
2717        clearTimeout(this.#focusMainContainerTimeoutId);
2718      }
2719      this.#focusMainContainerTimeoutId = setTimeout(() => {
2720        this.focusMainContainer();
2721        this.#focusMainContainerTimeoutId = null;
2722      }, 0);
2723    }
2724    this.#allEditors.delete(editor.id);
2725    this.unselect(editor);
2726    if (!editor.annotationElementId || !this.#deletedAnnotationsElementIds.has(editor.annotationElementId)) {
2727      this.#annotationStorage?.remove(editor.id);
2728    }
2729  }
2730  addDeletedAnnotationElement(editor) {
2731    this.#deletedAnnotationsElementIds.add(editor.annotationElementId);
2732    this.addChangedExistingAnnotation(editor);
2733    editor.deleted = true;
2734  }
2735  isDeletedAnnotationElement(annotationElementId) {
2736    return this.#deletedAnnotationsElementIds.has(annotationElementId);
2737  }
2738  removeDeletedAnnotationElement(editor) {
2739    this.#deletedAnnotationsElementIds.delete(editor.annotationElementId);
2740    this.removeChangedExistingAnnotation(editor);
2741    editor.deleted = false;
2742  }
2743  #addEditorToLayer(editor) {
2744    const layer = this.#allLayers.get(editor.pageIndex);
2745    if (layer) {
2746      layer.addOrRebuild(editor);
2747    } else {
2748      this.addEditor(editor);
2749      this.addToAnnotationStorage(editor);
2750    }
2751  }
2752  setActiveEditor(editor) {
2753    if (this.#activeEditor === editor) {
2754      return;
2755    }
2756    this.#activeEditor = editor;
2757    if (editor) {
2758      this.#dispatchUpdateUI(editor.propertiesToUpdate);
2759    }
2760  }
2761  get #lastSelectedEditor() {
2762    let ed = null;
2763    for (ed of this.#selectedEditors) {}
2764    return ed;
2765  }
2766  updateUI(editor) {
2767    if (this.#lastSelectedEditor === editor) {
2768      this.#dispatchUpdateUI(editor.propertiesToUpdate);
2769    }
2770  }
2771  toggleSelected(editor) {
2772    if (this.#selectedEditors.has(editor)) {
2773      this.#selectedEditors.delete(editor);
2774      editor.unselect();
2775      this.#dispatchUpdateStates({
2776        hasSelectedEditor: this.hasSelection
2777      });
2778      return;
2779    }
2780    this.#selectedEditors.add(editor);
2781    editor.select();
2782    this.#dispatchUpdateUI(editor.propertiesToUpdate);
2783    this.#dispatchUpdateStates({
2784      hasSelectedEditor: true
2785    });
2786  }
2787  setSelected(editor) {
2788    for (const ed of this.#selectedEditors) {
2789      if (ed !== editor) {
2790        ed.unselect();
2791      }
2792    }
2793    this.#selectedEditors.clear();
2794    this.#selectedEditors.add(editor);
2795    editor.select();
2796    this.#dispatchUpdateUI(editor.propertiesToUpdate);
2797    this.#dispatchUpdateStates({
2798      hasSelectedEditor: true
2799    });
2800  }
2801  isSelected(editor) {
2802    return this.#selectedEditors.has(editor);
2803  }
2804  get firstSelectedEditor() {
2805    return this.#selectedEditors.values().next().value;
2806  }
2807  unselect(editor) {
2808    editor.unselect();
2809    this.#selectedEditors.delete(editor);
2810    this.#dispatchUpdateStates({
2811      hasSelectedEditor: this.hasSelection
2812    });
2813  }
2814  get hasSelection() {
2815    return this.#selectedEditors.size !== 0;
2816  }
2817  get isEnterHandled() {
2818    return this.#selectedEditors.size === 1 && this.firstSelectedEditor.isEnterHandled;
2819  }
2820  undo() {
2821    this.#commandManager.undo();
2822    this.#dispatchUpdateStates({
2823      hasSomethingToUndo: this.#commandManager.hasSomethingToUndo(),
2824      hasSomethingToRedo: true,
2825      isEmpty: this.#isEmpty()
2826    });
2827  }
2828  redo() {
2829    this.#commandManager.redo();
2830    this.#dispatchUpdateStates({
2831      hasSomethingToUndo: true,
2832      hasSomethingToRedo: this.#commandManager.hasSomethingToRedo(),
2833      isEmpty: this.#isEmpty()
2834    });
2835  }
2836  addCommands(params) {
2837    this.#commandManager.add(params);
2838    this.#dispatchUpdateStates({
2839      hasSomethingToUndo: true,
2840      hasSomethingToRedo: false,
2841      isEmpty: this.#isEmpty()
2842    });
2843  }
2844  #isEmpty() {
2845    if (this.#allEditors.size === 0) {
2846      return true;
2847    }
2848    if (this.#allEditors.size === 1) {
2849      for (const editor of this.#allEditors.values()) {
2850        return editor.isEmpty();
2851      }
2852    }
2853    return false;
vendor: 16,438 bytes, lines 2854-3447
2854  }
2855  delete() {
2856    this.commitOrRemove();
2857    if (!this.hasSelection) {
2858      return;
2859    }
2860    const editors = [...this.#selectedEditors];
2861    const cmd = () => {
2862      for (const editor of editors) {
2863        editor.remove();
2864      }
2865    };
2866    const undo = () => {
2867      for (const editor of editors) {
2868        this.#addEditorToLayer(editor);
2869      }
2870    };
2871    this.addCommands({
2872      cmd,
2873      undo,
2874      mustExec: true
2875    });
2876  }
2877  commitOrRemove() {
2878    this.#activeEditor?.commitOrRemove();
2879  }
2880  hasSomethingToControl() {
2881    return this.#activeEditor || this.hasSelection;
2882  }
2883  #selectEditors(editors) {
2884    for (const editor of this.#selectedEditors) {
2885      editor.unselect();
2886    }
2887    this.#selectedEditors.clear();
2888    for (const editor of editors) {
2889      if (editor.isEmpty()) {
2890        continue;
2891      }
2892      this.#selectedEditors.add(editor);
2893      editor.select();
2894    }
2895    this.#dispatchUpdateStates({
2896      hasSelectedEditor: this.hasSelection
2897    });
2898  }
2899  selectAll() {
2900    for (const editor of this.#selectedEditors) {
2901      editor.commit();
2902    }
2903    this.#selectEditors(this.#allEditors.values());
2904  }
2905  unselectAll() {
2906    if (this.#activeEditor) {
2907      this.#activeEditor.commitOrRemove();
2908      if (this.#mode !== AnnotationEditorType.NONE) {
2909        return;
2910      }
2911    }
2912    if (!this.hasSelection) {
2913      return;
2914    }
2915    for (const editor of this.#selectedEditors) {
2916      editor.unselect();
2917    }
2918    this.#selectedEditors.clear();
2919    this.#dispatchUpdateStates({
2920      hasSelectedEditor: false
2921    });
2922  }
2923  translateSelectedEditors(x, y, noCommit = false) {
2924    if (!noCommit) {
2925      this.commitOrRemove();
2926    }
2927    if (!this.hasSelection) {
2928      return;
2929    }
2930    this.#translation[0] += x;
2931    this.#translation[1] += y;
2932    const [totalX, totalY] = this.#translation;
2933    const editors = [...this.#selectedEditors];
2934    const TIME_TO_WAIT = 1000;
2935    if (this.#translationTimeoutId) {
2936      clearTimeout(this.#translationTimeoutId);
2937    }
2938    this.#translationTimeoutId = setTimeout(() => {
2939      this.#translationTimeoutId = null;
2940      this.#translation[0] = this.#translation[1] = 0;
2941      this.addCommands({
2942        cmd: () => {
2943          for (const editor of editors) {
2944            if (this.#allEditors.has(editor.id)) {
2945              editor.translateInPage(totalX, totalY);
2946            }
2947          }
2948        },
2949        undo: () => {
2950          for (const editor of editors) {
2951            if (this.#allEditors.has(editor.id)) {
2952              editor.translateInPage(-totalX, -totalY);
2953            }
2954          }
2955        },
2956        mustExec: false
2957      });
2958    }, TIME_TO_WAIT);
2959    for (const editor of editors) {
2960      editor.translateInPage(x, y);
2961    }
2962  }
2963  setUpDragSession() {
2964    if (!this.hasSelection) {
2965      return;
2966    }
2967    this.disableUserSelect(true);
2968    this.#draggingEditors = new Map();
2969    for (const editor of this.#selectedEditors) {
2970      this.#draggingEditors.set(editor, {
2971        savedX: editor.x,
2972        savedY: editor.y,
2973        savedPageIndex: editor.pageIndex,
2974        newX: 0,
2975        newY: 0,
2976        newPageIndex: -1
2977      });
2978    }
2979  }
2980  endDragSession() {
2981    if (!this.#draggingEditors) {
2982      return false;
2983    }
2984    this.disableUserSelect(false);
2985    const map = this.#draggingEditors;
2986    this.#draggingEditors = null;
2987    let mustBeAddedInUndoStack = false;
2988    for (const [{
2989      x,
2990      y,
2991      pageIndex
2992    }, value] of map) {
2993      value.newX = x;
2994      value.newY = y;
2995      value.newPageIndex = pageIndex;
2996      mustBeAddedInUndoStack ||= x !== value.savedX || y !== value.savedY || pageIndex !== value.savedPageIndex;
2997    }
2998    if (!mustBeAddedInUndoStack) {
2999      return false;
3000    }
3001    const move = (editor, x, y, pageIndex) => {
3002      if (this.#allEditors.has(editor.id)) {
3003        const parent = this.#allLayers.get(pageIndex);
3004        if (parent) {
3005          editor._setParentAndPosition(parent, x, y);
3006        } else {
3007          editor.pageIndex = pageIndex;
3008          editor.x = x;
3009          editor.y = y;
3010        }
3011      }
3012    };
3013    this.addCommands({
3014      cmd: () => {
3015        for (const [editor, {
3016          newX,
3017          newY,
3018          newPageIndex
3019        }] of map) {
3020          move(editor, newX, newY, newPageIndex);
3021        }
3022      },
3023      undo: () => {
3024        for (const [editor, {
3025          savedX,
3026          savedY,
3027          savedPageIndex
3028        }] of map) {
3029          move(editor, savedX, savedY, savedPageIndex);
3030        }
3031      },
3032      mustExec: true
3033    });
3034    return true;
3035  }
3036  dragSelectedEditors(tx, ty) {
3037    if (!this.#draggingEditors) {
3038      return;
3039    }
3040    for (const editor of this.#draggingEditors.keys()) {
3041      editor.drag(tx, ty);
3042    }
3043  }
3044  rebuild(editor) {
3045    if (editor.parent === null) {
3046      const parent = this.getLayer(editor.pageIndex);
3047      if (parent) {
3048        parent.changeParent(editor);
3049        parent.addOrRebuild(editor);
3050      } else {
3051        this.addEditor(editor);
3052        this.addToAnnotationStorage(editor);
3053        editor.rebuild();
3054      }
3055    } else {
3056      editor.parent.addOrRebuild(editor);
3057    }
3058  }
3059  get isEditorHandlingKeyboard() {
3060    return this.getActive()?.shouldGetKeyboardEvents() || this.#selectedEditors.size === 1 && this.firstSelectedEditor.shouldGetKeyboardEvents();
3061  }
3062  isActive(editor) {
3063    return this.#activeEditor === editor;
3064  }
3065  getActive() {
3066    return this.#activeEditor;
3067  }
3068  getMode() {
3069    return this.#mode;
3070  }
3071  get imageManager() {
3072    return shadow(this, "imageManager", new ImageManager());
3073  }
3074  getSelectionBoxes(textLayer) {
3075    if (!textLayer) {
3076      return null;
3077    }
3078    const selection = document.getSelection();
3079    for (let i = 0, ii = selection.rangeCount; i < ii; i++) {
3080      if (!textLayer.contains(selection.getRangeAt(i).commonAncestorContainer)) {
3081        return null;
3082      }
3083    }
3084    const {
3085      x: layerX,
3086      y: layerY,
3087      width: parentWidth,
3088      height: parentHeight
3089    } = textLayer.getBoundingClientRect();
3090    let rotator;
3091    switch (textLayer.getAttribute("data-main-rotation")) {
3092      case "90":
3093        rotator = (x, y, w, h) => ({
3094          x: (y - layerY) / parentHeight,
3095          y: 1 - (x + w - layerX) / parentWidth,
3096          width: h / parentHeight,
3097          height: w / parentWidth
3098        });
3099        break;
3100      case "180":
3101        rotator = (x, y, w, h) => ({
3102          x: 1 - (x + w - layerX) / parentWidth,
3103          y: 1 - (y + h - layerY) / parentHeight,
3104          width: w / parentWidth,
3105          height: h / parentHeight
3106        });
3107        break;
3108      case "270":
3109        rotator = (x, y, w, h) => ({
3110          x: 1 - (y + h - layerY) / parentHeight,
3111          y: (x - layerX) / parentWidth,
3112          width: h / parentHeight,
3113          height: w / parentWidth
3114        });
3115        break;
3116      default:
3117        rotator = (x, y, w, h) => ({
3118          x: (x - layerX) / parentWidth,
3119          y: (y - layerY) / parentHeight,
3120          width: w / parentWidth,
3121          height: h / parentHeight
3122        });
3123        break;
3124    }
3125    const boxes = [];
3126    for (let i = 0, ii = selection.rangeCount; i < ii; i++) {
3127      const range = selection.getRangeAt(i);
3128      if (range.collapsed) {
3129        continue;
3130      }
3131      for (const {
3132        x,
3133        y,
3134        width,
3135        height
3136      } of range.getClientRects()) {
3137        if (width === 0 || height === 0) {
3138          continue;
3139        }
3140        boxes.push(rotator(x, y, width, height));
3141      }
3142    }
3143    return boxes.length === 0 ? null : boxes;
3144  }
3145  addChangedExistingAnnotation({
3146    annotationElementId,
3147    id
3148  }) {
3149    (this.#changedExistingAnnotations ||= new Map()).set(annotationElementId, id);
3150  }
3151  removeChangedExistingAnnotation({
3152    annotationElementId
3153  }) {
3154    this.#changedExistingAnnotations?.delete(annotationElementId);
3155  }
3156  renderAnnotationElement(annotation) {
3157    const editorId = this.#changedExistingAnnotations?.get(annotation.data.id);
3158    if (!editorId) {
3159      return;
3160    }
3161    const editor = this.#annotationStorage.getRawValue(editorId);
3162    if (!editor) {
3163      return;
3164    }
3165    if (this.#mode === AnnotationEditorType.NONE && !editor.hasBeenModified) {
3166      return;
3167    }
3168    editor.renderAnnotationElement(annotation);
3169  }
3170}
3171
3172;// ./src/display/editor/alt_text.js
3173
3174class AltText {
3175  #altText = null;
3176  #altTextDecorative = false;
3177  #altTextButton = null;
3178  #altTextButtonLabel = null;
3179  #altTextTooltip = null;
3180  #altTextTooltipTimeout = null;
3181  #altTextWasFromKeyBoard = false;
3182  #badge = null;
3183  #editor = null;
3184  #guessedText = null;
3185  #textWithDisclaimer = null;
3186  #useNewAltTextFlow = false;
3187  static #l10nNewButton = null;
3188  static _l10n = null;
3189  constructor(editor) {
3190    this.#editor = editor;
3191    this.#useNewAltTextFlow = editor._uiManager.useNewAltTextFlow;
3192    AltText.#l10nNewButton ||= Object.freeze({
3193      added: "pdfjs-editor-new-alt-text-added-button",
3194      "added-label": "pdfjs-editor-new-alt-text-added-button-label",
3195      missing: "pdfjs-editor-new-alt-text-missing-button",
3196      "missing-label": "pdfjs-editor-new-alt-text-missing-button-label",
3197      review: "pdfjs-editor-new-alt-text-to-review-button",
3198      "review-label": "pdfjs-editor-new-alt-text-to-review-button-label"
3199    });
3200  }
3201  static initialize(l10n) {
3202    AltText._l10n ??= l10n;
3203  }
3204  async render() {
3205    const altText = this.#altTextButton = document.createElement("button");
3206    altText.className = "altText";
3207    altText.tabIndex = "0";
3208    const label = this.#altTextButtonLabel = document.createElement("span");
3209    altText.append(label);
3210    if (this.#useNewAltTextFlow) {
3211      altText.classList.add("new");
3212      altText.setAttribute("data-l10n-id", AltText.#l10nNewButton.missing);
3213      label.setAttribute("data-l10n-id", AltText.#l10nNewButton["missing-label"]);
3214    } else {
3215      altText.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-button");
3216      label.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-button-label");
3217    }
3218    const signal = this.#editor._uiManager._signal;
3219    altText.addEventListener("contextmenu", noContextMenu, {
3220      signal
3221    });
3222    altText.addEventListener("pointerdown", event => event.stopPropagation(), {
3223      signal
3224    });
3225    const onClick = event => {
3226      event.preventDefault();
3227      this.#editor._uiManager.editAltText(this.#editor);
3228      if (this.#useNewAltTextFlow) {
3229        this.#editor._reportTelemetry({
3230          action: "pdfjs.image.alt_text.image_status_label_clicked",
3231          data: {
3232            label: this.#label
3233          }
3234        });
3235      }
3236    };
3237    altText.addEventListener("click", onClick, {
3238      capture: true,
3239      signal
3240    });
3241    altText.addEventListener("keydown", event => {
3242      if (event.target === altText && event.key === "Enter") {
3243        this.#altTextWasFromKeyBoard = true;
3244        onClick(event);
3245      }
3246    }, {
3247      signal
3248    });
3249    await this.#setState();
3250    return altText;
3251  }
3252  get #label() {
3253    return this.#altText && "added" || this.#altText === null && this.guessedText && "review" || "missing";
3254  }
3255  finish() {
3256    if (!this.#altTextButton) {
3257      return;
3258    }
3259    this.#altTextButton.focus({
3260      focusVisible: this.#altTextWasFromKeyBoard
3261    });
3262    this.#altTextWasFromKeyBoard = false;
3263  }
3264  isEmpty() {
3265    if (this.#useNewAltTextFlow) {
3266      return this.#altText === null;
3267    }
3268    return !this.#altText && !this.#altTextDecorative;
3269  }
3270  hasData() {
3271    if (this.#useNewAltTextFlow) {
3272      return this.#altText !== null || !!this.#guessedText;
3273    }
3274    return this.isEmpty();
3275  }
3276  get guessedText() {
3277    return this.#guessedText;
3278  }
3279  async setGuessedText(guessedText) {
3280    if (this.#altText !== null) {
3281      return;
3282    }
3283    this.#guessedText = guessedText;
3284    this.#textWithDisclaimer = await AltText._l10n.get("pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer", {
3285      generatedAltText: guessedText
3286    });
3287    this.#setState();
3288  }
3289  toggleAltTextBadge(visibility = false) {
3290    if (!this.#useNewAltTextFlow || this.#altText) {
3291      this.#badge?.remove();
3292      this.#badge = null;
3293      return;
3294    }
3295    if (!this.#badge) {
3296      const badge = this.#badge = document.createElement("div");
3297      badge.className = "noAltTextBadge";
3298      this.#editor.div.append(badge);
3299    }
3300    this.#badge.classList.toggle("hidden", !visibility);
3301  }
3302  serialize(isForCopying) {
3303    let altText = this.#altText;
3304    if (!isForCopying && this.#guessedText === altText) {
3305      altText = this.#textWithDisclaimer;
3306    }
3307    return {
3308      altText,
3309      decorative: this.#altTextDecorative,
3310      guessedText: this.#guessedText,
3311      textWithDisclaimer: this.#textWithDisclaimer
3312    };
3313  }
3314  get data() {
3315    return {
3316      altText: this.#altText,
3317      decorative: this.#altTextDecorative
3318    };
3319  }
3320  set data({
3321    altText,
3322    decorative,
3323    guessedText,
3324    textWithDisclaimer,
3325    cancel = false
3326  }) {
3327    if (guessedText) {
3328      this.#guessedText = guessedText;
3329      this.#textWithDisclaimer = textWithDisclaimer;
3330    }
3331    if (this.#altText === altText && this.#altTextDecorative === decorative) {
3332      return;
3333    }
3334    if (!cancel) {
3335      this.#altText = altText;
3336      this.#altTextDecorative = decorative;
3337    }
3338    this.#setState();
3339  }
3340  toggle(enabled = false) {
3341    if (!this.#altTextButton) {
3342      return;
3343    }
3344    if (!enabled && this.#altTextTooltipTimeout) {
3345      clearTimeout(this.#altTextTooltipTimeout);
3346      this.#altTextTooltipTimeout = null;
3347    }
3348    this.#altTextButton.disabled = !enabled;
3349  }
3350  shown() {
3351    this.#editor._reportTelemetry({
3352      action: "pdfjs.image.alt_text.image_status_label_displayed",
3353      data: {
3354        label: this.#label
3355      }
3356    });
3357  }
3358  destroy() {
3359    this.#altTextButton?.remove();
3360    this.#altTextButton = null;
3361    this.#altTextButtonLabel = null;
3362    this.#altTextTooltip = null;
3363    this.#badge?.remove();
3364    this.#badge = null;
3365  }
3366  async #setState() {
3367    const button = this.#altTextButton;
3368    if (!button) {
3369      return;
3370    }
3371    if (this.#useNewAltTextFlow) {
3372      button.classList.toggle("done", !!this.#altText);
3373      button.setAttribute("data-l10n-id", AltText.#l10nNewButton[this.#label]);
3374      this.#altTextButtonLabel?.setAttribute("data-l10n-id", AltText.#l10nNewButton[`${this.#label}-label`]);
3375      if (!this.#altText) {
3376        this.#altTextTooltip?.remove();
3377        return;
3378      }
3379    } else {
3380      if (!this.#altText && !this.#altTextDecorative) {
3381        button.classList.remove("done");
3382        this.#altTextTooltip?.remove();
3383        return;
3384      }
3385      button.classList.add("done");
3386      button.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-edit-button");
3387    }
3388    let tooltip = this.#altTextTooltip;
3389    if (!tooltip) {
3390      this.#altTextTooltip = tooltip = document.createElement("span");
3391      tooltip.className = "tooltip";
3392      tooltip.setAttribute("role", "tooltip");
3393      tooltip.id = `alt-text-tooltip-${this.#editor.id}`;
3394      const DELAY_TO_SHOW_TOOLTIP = 100;
3395      const signal = this.#editor._uiManager._signal;
3396      signal.addEventListener("abort", () => {
3397        clearTimeout(this.#altTextTooltipTimeout);
3398        this.#altTextTooltipTimeout = null;
3399      }, {
3400        once: true
3401      });
3402      button.addEventListener("mouseenter", () => {
3403        this.#altTextTooltipTimeout = setTimeout(() => {
3404          this.#altTextTooltipTimeout = null;
3405          this.#altTextTooltip.classList.add("show");
3406          this.#editor._reportTelemetry({
3407            action: "alt_text_tooltip"
3408          });
3409        }, DELAY_TO_SHOW_TOOLTIP);
3410      }, {
3411        signal
3412      });
3413      button.addEventListener("mouseleave", () => {
3414        if (this.#altTextTooltipTimeout) {
3415          clearTimeout(this.#altTextTooltipTimeout);
3416          this.#altTextTooltipTimeout = null;
3417        }
3418        this.#altTextTooltip?.classList.remove("show");
3419      }, {
3420        signal
3421      });
3422    }
3423    if (this.#altTextDecorative) {
3424      tooltip.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-decorative-tooltip");
3425    } else {
3426      tooltip.removeAttribute("data-l10n-id");
3427      tooltip.textContent = this.#altText;
3428    }
3429    if (!tooltip.parentNode) {
3430      button.append(tooltip);
3431    }
3432    const element = this.#editor.getImageForAltText();
3433    element?.setAttribute("aria-describedby", tooltip.id);
3434  }
3435}
3436
3437;// ./src/display/editor/editor.js
3438
3439
3440
3441
3442
3443class AnnotationEditor {
3444  #accessibilityData = null;
3445  #allResizerDivs = null;
3446  #altText = null;
3447  #disabled = false;
vendor: 4,328 bytes, lines 3448-3568
3448  #keepAspectRatio = false;
3449  #resizersDiv = null;
3450  #savedDimensions = null;
3451  #focusAC = null;
3452  #focusedResizerName = "";
3453  #hasBeenClicked = false;
3454  #initialPosition = null;
3455  #isEditing = false;
3456  #isInEditMode = false;
3457  #isResizerEnabledForKeyboard = false;
3458  #moveInDOMTimeout = null;
3459  #prevDragX = 0;
3460  #prevDragY = 0;
3461  #telemetryTimeouts = null;
3462  _editToolbar = null;
3463  _initialOptions = Object.create(null);
3464  _initialData = null;
3465  _isVisible = true;
3466  _uiManager = null;
3467  _focusEventsAllowed = true;
3468  static _l10n = null;
3469  static _l10nResizer = null;
3470  #isDraggable = false;
3471  #zIndex = AnnotationEditor._zIndex++;
3472  static _borderLineWidth = -1;
3473  static _colorManager = new ColorManager();
3474  static _zIndex = 1;
3475  static _telemetryTimeout = 1000;
3476  static get _resizerKeyboardManager() {
3477    const resize = AnnotationEditor.prototype._resizeWithKeyboard;
3478    const small = AnnotationEditorUIManager.TRANSLATE_SMALL;
3479    const big = AnnotationEditorUIManager.TRANSLATE_BIG;
3480    return shadow(this, "_resizerKeyboardManager", new KeyboardManager([[["ArrowLeft", "mac+ArrowLeft"], resize, {
3481      args: [-small, 0]
3482    }], [["ctrl+ArrowLeft", "mac+shift+ArrowLeft"], resize, {
3483      args: [-big, 0]
3484    }], [["ArrowRight", "mac+ArrowRight"], resize, {
3485      args: [small, 0]
3486    }], [["ctrl+ArrowRight", "mac+shift+ArrowRight"], resize, {
3487      args: [big, 0]
3488    }], [["ArrowUp", "mac+ArrowUp"], resize, {
3489      args: [0, -small]
3490    }], [["ctrl+ArrowUp", "mac+shift+ArrowUp"], resize, {
3491      args: [0, -big]
3492    }], [["ArrowDown", "mac+ArrowDown"], resize, {
3493      args: [0, small]
3494    }], [["ctrl+ArrowDown", "mac+shift+ArrowDown"], resize, {
3495      args: [0, big]
3496    }], [["Escape", "mac+Escape"], AnnotationEditor.prototype._stopResizingWithKeyboard]]));
3497  }
3498  constructor(parameters) {
3499    this.parent = parameters.parent;
3500    this.id = parameters.id;
3501    this.width = this.height = null;
3502    this.pageIndex = parameters.parent.pageIndex;
3503    this.name = parameters.name;
3504    this.div = null;
3505    this._uiManager = parameters.uiManager;
3506    this.annotationElementId = null;
3507    this._willKeepAspectRatio = false;
3508    this._initialOptions.isCentered = parameters.isCentered;
3509    this._structTreeParentId = null;
3510    const {
3511      rotation,
3512      rawDims: {
3513        pageWidth,
3514        pageHeight,
3515        pageX,
3516        pageY
3517      }
3518    } = this.parent.viewport;
3519    this.rotation = rotation;
3520    this.pageRotation = (360 + rotation - this._uiManager.viewParameters.rotation) % 360;
3521    this.pageDimensions = [pageWidth, pageHeight];
3522    this.pageTranslation = [pageX, pageY];
3523    const [width, height] = this.parentDimensions;
3524    this.x = parameters.x / width;
3525    this.y = parameters.y / height;
3526    this.isAttachedToDOM = false;
3527    this.deleted = false;
3528  }
3529  get editorType() {
3530    return Object.getPrototypeOf(this).constructor._type;
3531  }
3532  static get _defaultLineColor() {
3533    return shadow(this, "_defaultLineColor", this._colorManager.getHexCode("CanvasText"));
3534  }
3535  static deleteAnnotationElement(editor) {
3536    const fakeEditor = new FakeEditor({
3537      id: editor.parent.getNextId(),
3538      parent: editor.parent,
3539      uiManager: editor._uiManager
3540    });
3541    fakeEditor.annotationElementId = editor.annotationElementId;
3542    fakeEditor.deleted = true;
3543    fakeEditor._uiManager.addToAnnotationStorage(fakeEditor);
3544  }
3545  static initialize(l10n, _uiManager) {
3546    AnnotationEditor._l10n ??= l10n;
3547    AnnotationEditor._l10nResizer ||= Object.freeze({
3548      topLeft: "pdfjs-editor-resizer-top-left",
3549      topMiddle: "pdfjs-editor-resizer-top-middle",
3550      topRight: "pdfjs-editor-resizer-top-right",
3551      middleRight: "pdfjs-editor-resizer-middle-right",
3552      bottomRight: "pdfjs-editor-resizer-bottom-right",
3553      bottomMiddle: "pdfjs-editor-resizer-bottom-middle",
3554      bottomLeft: "pdfjs-editor-resizer-bottom-left",
3555      middleLeft: "pdfjs-editor-resizer-middle-left"
3556    });
3557    if (AnnotationEditor._borderLineWidth !== -1) {
3558      return;
3559    }
3560    const style = getComputedStyle(document.documentElement);
3561    AnnotationEditor._borderLineWidth = parseFloat(style.getPropertyValue("--outline-width")) || 0;
3562  }
3563  static updateDefaultParams(_type, _value) {}
3564  static get defaultPropertiesToUpdate() {
3565    return [];
3566  }
3567  static isHandlingMimeForPasting(mime) {
3568    return false;
vendor: 12,170 bytes, lines 3569-3980
3569  }
3570  static paste(item, parent) {
3571    unreachable("Not implemented");
3572  }
3573  get propertiesToUpdate() {
3574    return [];
3575  }
3576  get _isDraggable() {
3577    return this.#isDraggable;
3578  }
3579  set _isDraggable(value) {
3580    this.#isDraggable = value;
3581    this.div?.classList.toggle("draggable", value);
3582  }
3583  get isEnterHandled() {
3584    return true;
3585  }
3586  center() {
3587    const [pageWidth, pageHeight] = this.pageDimensions;
3588    switch (this.parentRotation) {
3589      case 90:
3590        this.x -= this.height * pageHeight / (pageWidth * 2);
3591        this.y += this.width * pageWidth / (pageHeight * 2);
3592        break;
3593      case 180:
3594        this.x += this.width / 2;
3595        this.y += this.height / 2;
3596        break;
3597      case 270:
3598        this.x += this.height * pageHeight / (pageWidth * 2);
3599        this.y -= this.width * pageWidth / (pageHeight * 2);
3600        break;
3601      default:
3602        this.x -= this.width / 2;
3603        this.y -= this.height / 2;
3604        break;
3605    }
3606    this.fixAndSetPosition();
3607  }
3608  addCommands(params) {
3609    this._uiManager.addCommands(params);
3610  }
3611  get currentLayer() {
3612    return this._uiManager.currentLayer;
3613  }
3614  setInBackground() {
3615    this.div.style.zIndex = 0;
3616  }
3617  setInForeground() {
3618    this.div.style.zIndex = this.#zIndex;
3619  }
3620  setParent(parent) {
3621    if (parent !== null) {
3622      this.pageIndex = parent.pageIndex;
3623      this.pageDimensions = parent.pageDimensions;
3624    } else {
3625      this.#stopResizing();
3626    }
3627    this.parent = parent;
3628  }
3629  focusin(event) {
3630    if (!this._focusEventsAllowed) {
3631      return;
3632    }
3633    if (!this.#hasBeenClicked) {
3634      this.parent.setSelected(this);
3635    } else {
3636      this.#hasBeenClicked = false;
3637    }
3638  }
3639  focusout(event) {
3640    if (!this._focusEventsAllowed) {
3641      return;
3642    }
3643    if (!this.isAttachedToDOM) {
3644      return;
3645    }
3646    const target = event.relatedTarget;
3647    if (target?.closest(`#${this.id}`)) {
3648      return;
3649    }
3650    event.preventDefault();
3651    if (!this.parent?.isMultipleSelection) {
3652      this.commitOrRemove();
3653    }
3654  }
3655  commitOrRemove() {
3656    if (this.isEmpty()) {
3657      this.remove();
3658    } else {
3659      this.commit();
3660    }
3661  }
3662  commit() {
3663    this.addToAnnotationStorage();
3664  }
3665  addToAnnotationStorage() {
3666    this._uiManager.addToAnnotationStorage(this);
3667  }
3668  setAt(x, y, tx, ty) {
3669    const [width, height] = this.parentDimensions;
3670    [tx, ty] = this.screenToPageTranslation(tx, ty);
3671    this.x = (x + tx) / width;
3672    this.y = (y + ty) / height;
3673    this.fixAndSetPosition();
3674  }
3675  #translate([width, height], x, y) {
3676    [x, y] = this.screenToPageTranslation(x, y);
3677    this.x += x / width;
3678    this.y += y / height;
3679    this.fixAndSetPosition();
3680  }
3681  translate(x, y) {
3682    this.#translate(this.parentDimensions, x, y);
3683  }
3684  translateInPage(x, y) {
3685    this.#initialPosition ||= [this.x, this.y];
3686    this.#translate(this.pageDimensions, x, y);
3687    this.div.scrollIntoView({
3688      block: "nearest"
3689    });
3690  }
3691  drag(tx, ty) {
3692    this.#initialPosition ||= [this.x, this.y];
3693    const [parentWidth, parentHeight] = this.parentDimensions;
3694    this.x += tx / parentWidth;
3695    this.y += ty / parentHeight;
3696    if (this.parent && (this.x < 0 || this.x > 1 || this.y < 0 || this.y > 1)) {
3697      const {
3698        x,
3699        y
3700      } = this.div.getBoundingClientRect();
3701      if (this.parent.findNewParent(this, x, y)) {
3702        this.x -= Math.floor(this.x);
3703        this.y -= Math.floor(this.y);
3704      }
3705    }
3706    let {
3707      x,
3708      y
3709    } = this;
3710    const [bx, by] = this.getBaseTranslation();
3711    x += bx;
3712    y += by;
3713    this.div.style.left = `${(100 * x).toFixed(2)}%`;
3714    this.div.style.top = `${(100 * y).toFixed(2)}%`;
3715    this.div.scrollIntoView({
3716      block: "nearest"
3717    });
3718  }
3719  get _hasBeenMoved() {
3720    return !!this.#initialPosition && (this.#initialPosition[0] !== this.x || this.#initialPosition[1] !== this.y);
3721  }
3722  getBaseTranslation() {
3723    const [parentWidth, parentHeight] = this.parentDimensions;
3724    const {
3725      _borderLineWidth
3726    } = AnnotationEditor;
3727    const x = _borderLineWidth / parentWidth;
3728    const y = _borderLineWidth / parentHeight;
3729    switch (this.rotation) {
3730      case 90:
3731        return [-x, y];
3732      case 180:
3733        return [x, y];
3734      case 270:
3735        return [x, -y];
3736      default:
3737        return [-x, -y];
3738    }
3739  }
3740  get _mustFixPosition() {
3741    return true;
3742  }
3743  fixAndSetPosition(rotation = this.rotation) {
3744    const [pageWidth, pageHeight] = this.pageDimensions;
3745    let {
3746      x,
3747      y,
3748      width,
3749      height
3750    } = this;
3751    width *= pageWidth;
3752    height *= pageHeight;
3753    x *= pageWidth;
3754    y *= pageHeight;
3755    if (this._mustFixPosition) {
3756      switch (rotation) {
3757        case 0:
3758          x = Math.max(0, Math.min(pageWidth - width, x));
3759          y = Math.max(0, Math.min(pageHeight - height, y));
3760          break;
3761        case 90:
3762          x = Math.max(0, Math.min(pageWidth - height, x));
3763          y = Math.min(pageHeight, Math.max(width, y));
3764          break;
3765        case 180:
3766          x = Math.min(pageWidth, Math.max(width, x));
3767          y = Math.min(pageHeight, Math.max(height, y));
3768          break;
3769        case 270:
3770          x = Math.min(pageWidth, Math.max(height, x));
3771          y = Math.max(0, Math.min(pageHeight - width, y));
3772          break;
3773      }
3774    }
3775    this.x = x /= pageWidth;
3776    this.y = y /= pageHeight;
3777    const [bx, by] = this.getBaseTranslation();
3778    x += bx;
3779    y += by;
3780    const {
3781      style
3782    } = this.div;
3783    style.left = `${(100 * x).toFixed(2)}%`;
3784    style.top = `${(100 * y).toFixed(2)}%`;
3785    this.moveInDOM();
3786  }
3787  static #rotatePoint(x, y, angle) {
3788    switch (angle) {
3789      case 90:
3790        return [y, -x];
3791      case 180:
3792        return [-x, -y];
3793      case 270:
3794        return [-y, x];
3795      default:
3796        return [x, y];
3797    }
3798  }
3799  screenToPageTranslation(x, y) {
3800    return AnnotationEditor.#rotatePoint(x, y, this.parentRotation);
3801  }
3802  pageTranslationToScreen(x, y) {
3803    return AnnotationEditor.#rotatePoint(x, y, 360 - this.parentRotation);
3804  }
3805  #getRotationMatrix(rotation) {
3806    switch (rotation) {
3807      case 90:
3808        {
3809          const [pageWidth, pageHeight] = this.pageDimensions;
3810          return [0, -pageWidth / pageHeight, pageHeight / pageWidth, 0];
3811        }
3812      case 180:
3813        return [-1, 0, 0, -1];
3814      case 270:
3815        {
3816          const [pageWidth, pageHeight] = this.pageDimensions;
3817          return [0, pageWidth / pageHeight, -pageHeight / pageWidth, 0];
3818        }
3819      default:
3820        return [1, 0, 0, 1];
3821    }
3822  }
3823  get parentScale() {
3824    return this._uiManager.viewParameters.realScale;
3825  }
3826  get parentRotation() {
3827    return (this._uiManager.viewParameters.rotation + this.pageRotation) % 360;
3828  }
3829  get parentDimensions() {
3830    const {
3831      parentScale,
3832      pageDimensions: [pageWidth, pageHeight]
3833    } = this;
3834    return [pageWidth * parentScale, pageHeight * parentScale];
3835  }
3836  setDims(width, height) {
3837    const [parentWidth, parentHeight] = this.parentDimensions;
3838    this.div.style.width = `${(100 * width / parentWidth).toFixed(2)}%`;
3839    if (!this.#keepAspectRatio) {
3840      this.div.style.height = `${(100 * height / parentHeight).toFixed(2)}%`;
3841    }
3842  }
3843  fixDims() {
3844    const {
3845      style
3846    } = this.div;
3847    const {
3848      height,
3849      width
3850    } = style;
3851    const widthPercent = width.endsWith("%");
3852    const heightPercent = !this.#keepAspectRatio && height.endsWith("%");
3853    if (widthPercent && heightPercent) {
3854      return;
3855    }
3856    const [parentWidth, parentHeight] = this.parentDimensions;
3857    if (!widthPercent) {
3858      style.width = `${(100 * parseFloat(width) / parentWidth).toFixed(2)}%`;
3859    }
3860    if (!this.#keepAspectRatio && !heightPercent) {
3861      style.height = `${(100 * parseFloat(height) / parentHeight).toFixed(2)}%`;
3862    }
3863  }
3864  getInitialTranslation() {
3865    return [0, 0];
3866  }
3867  #createResizers() {
3868    if (this.#resizersDiv) {
3869      return;
3870    }
3871    this.#resizersDiv = document.createElement("div");
3872    this.#resizersDiv.classList.add("resizers");
3873    const classes = this._willKeepAspectRatio ? ["topLeft", "topRight", "bottomRight", "bottomLeft"] : ["topLeft", "topMiddle", "topRight", "middleRight", "bottomRight", "bottomMiddle", "bottomLeft", "middleLeft"];
3874    const signal = this._uiManager._signal;
3875    for (const name of classes) {
3876      const div = document.createElement("div");
3877      this.#resizersDiv.append(div);
3878      div.classList.add("resizer", name);
3879      div.setAttribute("data-resizer-name", name);
3880      div.addEventListener("pointerdown", this.#resizerPointerdown.bind(this, name), {
3881        signal
3882      });
3883      div.addEventListener("contextmenu", noContextMenu, {
3884        signal
3885      });
3886      div.tabIndex = -1;
3887    }
3888    this.div.prepend(this.#resizersDiv);
3889  }
3890  #resizerPointerdown(name, event) {
3891    event.preventDefault();
3892    const {
3893      isMac
3894    } = util_FeatureTest.platform;
3895    if (event.button !== 0 || event.ctrlKey && isMac) {
3896      return;
3897    }
3898    this.#altText?.toggle(false);
3899    const savedDraggable = this._isDraggable;
3900    this._isDraggable = false;
3901    const ac = new AbortController();
3902    const signal = this._uiManager.combinedSignal(ac);
3903    this.parent.togglePointerEvents(false);
3904    window.addEventListener("pointermove", this.#resizerPointermove.bind(this, name), {
3905      passive: true,
3906      capture: true,
3907      signal
3908    });
3909    window.addEventListener("contextmenu", noContextMenu, {
3910      signal
3911    });
3912    const savedX = this.x;
3913    const savedY = this.y;
3914    const savedWidth = this.width;
3915    const savedHeight = this.height;
3916    const savedParentCursor = this.parent.div.style.cursor;
3917    const savedCursor = this.div.style.cursor;
3918    this.div.style.cursor = this.parent.div.style.cursor = window.getComputedStyle(event.target).cursor;
3919    const pointerUpCallback = () => {
3920      ac.abort();
3921      this.parent.togglePointerEvents(true);
3922      this.#altText?.toggle(true);
3923      this._isDraggable = savedDraggable;
3924      this.parent.div.style.cursor = savedParentCursor;
3925      this.div.style.cursor = savedCursor;
3926      this.#addResizeToUndoStack(savedX, savedY, savedWidth, savedHeight);
3927    };
3928    window.addEventListener("pointerup", pointerUpCallback, {
3929      signal
3930    });
3931    window.addEventListener("blur", pointerUpCallback, {
3932      signal
3933    });
3934  }
3935  #addResizeToUndoStack(savedX, savedY, savedWidth, savedHeight) {
3936    const newX = this.x;
3937    const newY = this.y;
3938    const newWidth = this.width;
3939    const newHeight = this.height;
3940    if (newX === savedX && newY === savedY && newWidth === savedWidth && newHeight === savedHeight) {
3941      return;
3942    }
3943    this.addCommands({
3944      cmd: () => {
3945        this.width = newWidth;
3946        this.height = newHeight;
3947        this.x = newX;
3948        this.y = newY;
3949        const [parentWidth, parentHeight] = this.parentDimensions;
3950        this.setDims(parentWidth * newWidth, parentHeight * newHeight);
3951        this.fixAndSetPosition();
3952      },
3953      undo: () => {
3954        this.width = savedWidth;
3955        this.height = savedHeight;
3956        this.x = savedX;
3957        this.y = savedY;
3958        const [parentWidth, parentHeight] = this.parentDimensions;
3959        this.setDims(parentWidth * savedWidth, parentHeight * savedHeight);
3960        this.fixAndSetPosition();
3961      },
3962      mustExec: true
3963    });
3964  }
3965  #resizerPointermove(name, event) {
3966    const [parentWidth, parentHeight] = this.parentDimensions;
3967    const savedX = this.x;
3968    const savedY = this.y;
3969    const savedWidth = this.width;
3970    const savedHeight = this.height;
3971    const minWidth = AnnotationEditor.MIN_SIZE / parentWidth;
3972    const minHeight = AnnotationEditor.MIN_SIZE / parentHeight;
3973    const round = x => Math.round(x * 10000) / 10000;
3974    const rotationMatrix = this.#getRotationMatrix(this.rotation);
3975    const transf = (x, y) => [rotationMatrix[0] * x + rotationMatrix[2] * y, rotationMatrix[1] * x + rotationMatrix[3] * y];
3976    const invRotationMatrix = this.#getRotationMatrix(360 - this.rotation);
3977    const invTransf = (x, y) => [invRotationMatrix[0] * x + invRotationMatrix[2] * y, invRotationMatrix[1] * x + invRotationMatrix[3] * y];
3978    let getPoint;
3979    let getOpposite;
3980    let isDiagonal = false;
3981    let isHorizontal = false;
3982    switch (name) {
3983      case "topLeft":
3984        isDiagonal = true;
3985        getPoint = (w, h) => [0, 0];
3986        getOpposite = (w, h) => [w, h];
3987        break;
3988      case "topMiddle":
3989        getPoint = (w, h) => [w / 2, 0];
3990        getOpposite = (w, h) => [w / 2, h];
3991        break;
3992      case "topRight":
3993        isDiagonal = true;
3994        getPoint = (w, h) => [w, 0];
3995        getOpposite = (w, h) => [0, h];
3996        break;
3997      case "middleRight":
3998        isHorizontal = true;
3999        getPoint = (w, h) => [w, h / 2];
4000        getOpposite = (w, h) => [0, h / 2];
4001        break;
4002      case "bottomRight":
4003        isDiagonal = true;
4004        getPoint = (w, h) => [w, h];
4005        getOpposite = (w, h) => [0, 0];
4006        break;
4007      case "bottomMiddle":
4008        getPoint = (w, h) => [w / 2, h];
4009        getOpposite = (w, h) => [w / 2, 0];
4010        break;
4011      case "bottomLeft":
4012        isDiagonal = true;
4013        getPoint = (w, h) => [0, h];
4014        getOpposite = (w, h) => [w, 0];
4015        break;
4016      case "middleLeft":
4017        isHorizontal = true;
4018        getPoint = (w, h) => [0, h / 2];
4019        getOpposite = (w, h) => [w, h / 2];
4020        break;
4021    }
4022    const point = getPoint(savedWidth, savedHeight);
4023    const oppositePoint = getOpposite(savedWidth, savedHeight);
4024    let transfOppositePoint = transf(...oppositePoint);
4025    const oppositeX = round(savedX + transfOppositePoint[0]);
4026    const oppositeY = round(savedY + transfOppositePoint[1]);
4027    let ratioX = 1;
4028    let ratioY = 1;
4029    let [deltaX, deltaY] = this.screenToPageTranslation(event.movementX, event.movementY);
4030    [deltaX, deltaY] = invTransf(deltaX / parentWidth, deltaY / parentHeight);
4031    if (isDiagonal) {
4032      const oldDiag = Math.hypot(savedWidth, savedHeight);
4033      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);
4034    } else if (isHorizontal) {
4035      ratioX = Math.max(minWidth, Math.min(1, Math.abs(oppositePoint[0] - point[0] - deltaX))) / savedWidth;
4036    } else {
4037      ratioY = Math.max(minHeight, Math.min(1, Math.abs(oppositePoint[1] - point[1] - deltaY))) / savedHeight;
4038    }
4039    const newWidth = round(savedWidth * ratioX);
4040    const newHeight = round(savedHeight * ratioY);
4041    transfOppositePoint = transf(...getOpposite(newWidth, newHeight));
4042    const newX = oppositeX - transfOppositePoint[0];
4043    const newY = oppositeY - transfOppositePoint[1];
4044    this.width = newWidth;
4045    this.height = newHeight;
4046    this.x = newX;
4047    this.y = newY;
4048    this.setDims(parentWidth * newWidth, parentHeight * newHeight);
4049    this.fixAndSetPosition();
4050  }
4051  altTextFinish() {
4052    this.#altText?.finish();
4053  }
4054  async addEditToolbar() {
4055    if (this._editToolbar || this.#isInEditMode) {
4056      return this._editToolbar;
4057    }
4058    this._editToolbar = new EditorToolbar(this);
4059    this.div.append(this._editToolbar.render());
4060    if (this.#altText) {
4061      await this._editToolbar.addAltText(this.#altText);
4062    }
4063    return this._editToolbar;
4064  }
4065  removeEditToolbar() {
4066    if (!this._editToolbar) {
4067      return;
4068    }
4069    this._editToolbar.remove();
4070    this._editToolbar = null;
4071    this.#altText?.destroy();
4072  }
4073  addContainer(container) {
4074    const editToolbarDiv = this._editToolbar?.div;
4075    if (editToolbarDiv) {
4076      editToolbarDiv.before(container);
4077    } else {
4078      this.div.append(container);
4079    }
4080  }
4081  getClientDimensions() {
4082    return this.div.getBoundingClientRect();
4083  }
4084  async addAltTextButton() {
4085    if (this.#altText) {
4086      return;
4087    }
4088    AltText.initialize(AnnotationEditor._l10n);
4089    this.#altText = new AltText(this);
4090    if (this.#accessibilityData) {
4091      this.#altText.data = this.#accessibilityData;
4092      this.#accessibilityData = null;
4093    }
4094    await this.addEditToolbar();
4095  }
4096  get altTextData() {
4097    return this.#altText?.data;
4098  }
4099  set altTextData(data) {
4100    if (!this.#altText) {
4101      return;
4102    }
4103    this.#altText.data = data;
4104  }
4105  get guessedAltText() {
4106    return this.#altText?.guessedText;
4107  }
4108  async setGuessedAltText(text) {
4109    await this.#altText?.setGuessedText(text);
4110  }
4111  serializeAltText(isForCopying) {
4112    return this.#altText?.serialize(isForCopying);
4113  }
4114  hasAltText() {
4115    return !!this.#altText && !this.#altText.isEmpty();
4116  }
4117  hasAltTextData() {
4118    return this.#altText?.hasData() ?? false;
4119  }
4120  render() {
4121    this.div = document.createElement("div");
4122    this.div.setAttribute("data-editor-rotation", (360 - this.rotation) % 360);
4123    this.div.className = this.name;
4124    this.div.setAttribute("id", this.id);
4125    this.div.tabIndex = this.#disabled ? -1 : 0;
4126    if (!this._isVisible) {
4127      this.div.classList.add("hidden");
4128    }
4129    this.setInForeground();
4130    this.#addFocusListeners();
4131    const [parentWidth, parentHeight] = this.parentDimensions;
4132    if (this.parentRotation % 180 !== 0) {
4133      this.div.style.maxWidth = `${(100 * parentHeight / parentWidth).toFixed(2)}%`;
4134      this.div.style.maxHeight = `${(100 * parentWidth / parentHeight).toFixed(2)}%`;
4135    }
4136    const [tx, ty] = this.getInitialTranslation();
4137    this.translate(tx, ty);
4138    bindEvents(this, this.div, ["pointerdown"]);
4139    return this.div;
4140  }
4141  pointerdown(event) {
4142    const {
4143      isMac
4144    } = util_FeatureTest.platform;
4145    if (event.button !== 0 || event.ctrlKey && isMac) {
4146      event.preventDefault();
4147      return;
4148    }
4149    this.#hasBeenClicked = true;
4150    if (this._isDraggable) {
4151      this.#setUpDragSession(event);
4152      return;
4153    }
4154    this.#selectOnPointerEvent(event);
4155  }
4156  get isSelected() {
4157    return this._uiManager.isSelected(this);
4158  }
4159  #selectOnPointerEvent(event) {
4160    const {
4161      isMac
4162    } = util_FeatureTest.platform;
4163    if (event.ctrlKey && !isMac || event.shiftKey || event.metaKey && isMac) {
4164      this.parent.toggleSelected(this);
4165    } else {
4166      this.parent.setSelected(this);
4167    }
4168  }
4169  #setUpDragSession(event) {
4170    const {
4171      isSelected
4172    } = this;
4173    this._uiManager.setUpDragSession();
4174    const ac = new AbortController();
4175    const signal = this._uiManager.combinedSignal(ac);
4176    if (isSelected) {
4177      this.div.classList.add("moving");
4178      this.#prevDragX = event.clientX;
4179      this.#prevDragY = event.clientY;
4180      const pointerMoveCallback = e => {
4181        const {
4182          clientX: x,
4183          clientY: y
4184        } = e;
4185        const [tx, ty] = this.screenToPageTranslation(x - this.#prevDragX, y - this.#prevDragY);
4186        this.#prevDragX = x;
vendor: 5,152 bytes, lines 4187-4360
4187        this.#prevDragY = y;
4188        this._uiManager.dragSelectedEditors(tx, ty);
4189      };
4190      window.addEventListener("pointermove", pointerMoveCallback, {
4191        passive: true,
4192        capture: true,
4193        signal
4194      });
4195    }
4196    const pointerUpCallback = () => {
4197      ac.abort();
4198      if (isSelected) {
4199        this.div.classList.remove("moving");
4200      }
4201      this.#hasBeenClicked = false;
4202      if (!this._uiManager.endDragSession()) {
4203        this.#selectOnPointerEvent(event);
4204      }
4205    };
4206    window.addEventListener("pointerup", pointerUpCallback, {
4207      signal
4208    });
4209    window.addEventListener("blur", pointerUpCallback, {
4210      signal
4211    });
4212  }
4213  moveInDOM() {
4214    if (this.#moveInDOMTimeout) {
4215      clearTimeout(this.#moveInDOMTimeout);
4216    }
4217    this.#moveInDOMTimeout = setTimeout(() => {
4218      this.#moveInDOMTimeout = null;
4219      this.parent?.moveEditorInDOM(this);
4220    }, 0);
4221  }
4222  _setParentAndPosition(parent, x, y) {
4223    parent.changeParent(this);
4224    this.x = x;
4225    this.y = y;
4226    this.fixAndSetPosition();
4227  }
4228  getRect(tx, ty, rotation = this.rotation) {
4229    const scale = this.parentScale;
4230    const [pageWidth, pageHeight] = this.pageDimensions;
4231    const [pageX, pageY] = this.pageTranslation;
4232    const shiftX = tx / scale;
4233    const shiftY = ty / scale;
4234    const x = this.x * pageWidth;
4235    const y = this.y * pageHeight;
4236    const width = this.width * pageWidth;
4237    const height = this.height * pageHeight;
4238    switch (rotation) {
4239      case 0:
4240        return [x + shiftX + pageX, pageHeight - y - shiftY - height + pageY, x + shiftX + width + pageX, pageHeight - y - shiftY + pageY];
4241      case 90:
4242        return [x + shiftY + pageX, pageHeight - y + shiftX + pageY, x + shiftY + height + pageX, pageHeight - y + shiftX + width + pageY];
4243      case 180:
4244        return [x - shiftX - width + pageX, pageHeight - y + shiftY + pageY, x - shiftX + pageX, pageHeight - y + shiftY + height + pageY];
4245      case 270:
4246        return [x - shiftY - height + pageX, pageHeight - y - shiftX - width + pageY, x - shiftY + pageX, pageHeight - y - shiftX + pageY];
4247      default:
4248        throw new Error("Invalid rotation");
4249    }
4250  }
4251  getRectInCurrentCoords(rect, pageHeight) {
4252    const [x1, y1, x2, y2] = rect;
4253    const width = x2 - x1;
4254    const height = y2 - y1;
4255    switch (this.rotation) {
4256      case 0:
4257        return [x1, pageHeight - y2, width, height];
4258      case 90:
4259        return [x1, pageHeight - y1, height, width];
4260      case 180:
4261        return [x2, pageHeight - y1, width, height];
4262      case 270:
4263        return [x2, pageHeight - y2, height, width];
4264      default:
4265        throw new Error("Invalid rotation");
4266    }
4267  }
4268  onceAdded() {}
4269  isEmpty() {
4270    return false;
4271  }
4272  enableEditMode() {
4273    this.#isInEditMode = true;
4274  }
4275  disableEditMode() {
4276    this.#isInEditMode = false;
4277  }
4278  isInEditMode() {
4279    return this.#isInEditMode;
4280  }
4281  shouldGetKeyboardEvents() {
4282    return this.#isResizerEnabledForKeyboard;
4283  }
4284  needsToBeRebuilt() {
4285    return this.div && !this.isAttachedToDOM;
4286  }
4287  #addFocusListeners() {
4288    if (this.#focusAC || !this.div) {
4289      return;
4290    }
4291    this.#focusAC = new AbortController();
4292    const signal = this._uiManager.combinedSignal(this.#focusAC);
4293    this.div.addEventListener("focusin", this.focusin.bind(this), {
4294      signal
4295    });
4296    this.div.addEventListener("focusout", this.focusout.bind(this), {
4297      signal
4298    });
4299  }
4300  rebuild() {
4301    this.#addFocusListeners();
4302  }
4303  rotate(_angle) {}
4304  serializeDeleted() {
4305    return {
4306      id: this.annotationElementId,
4307      deleted: true,
4308      pageIndex: this.pageIndex,
4309      popupRef: this._initialData?.popupRef || ""
4310    };
4311  }
4312  serialize(isForCopying = false, context = null) {
4313    unreachable("An editor must be serializable");
4314  }
4315  static async deserialize(data, parent, uiManager) {
4316    const editor = new this.prototype.constructor({
4317      parent,
4318      id: parent.getNextId(),
4319      uiManager
4320    });
4321    editor.rotation = data.rotation;
4322    editor.#accessibilityData = data.accessibilityData;
4323    const [pageWidth, pageHeight] = editor.pageDimensions;
4324    const [x, y, width, height] = editor.getRectInCurrentCoords(data.rect, pageHeight);
4325    editor.x = x / pageWidth;
4326    editor.y = y / pageHeight;
4327    editor.width = width / pageWidth;
4328    editor.height = height / pageHeight;
4329    return editor;
4330  }
4331  get hasBeenModified() {
4332    return !!this.annotationElementId && (this.deleted || this.serialize() !== null);
4333  }
4334  remove() {
4335    this.#focusAC?.abort();
4336    this.#focusAC = null;
4337    if (!this.isEmpty()) {
4338      this.commit();
4339    }
4340    if (this.parent) {
4341      this.parent.remove(this);
4342    } else {
4343      this._uiManager.removeEditor(this);
4344    }
4345    if (this.#moveInDOMTimeout) {
4346      clearTimeout(this.#moveInDOMTimeout);
4347      this.#moveInDOMTimeout = null;
4348    }
4349    this.#stopResizing();
4350    this.removeEditToolbar();
4351    if (this.#telemetryTimeouts) {
4352      for (const timeout of this.#telemetryTimeouts.values()) {
4353        clearTimeout(timeout);
4354      }
4355      this.#telemetryTimeouts = null;
4356    }
4357    this.parent = null;
4358  }
4359  get isResizable() {
4360    return false;
vendor: 10,691 bytes, lines 4361-4739
4361  }
4362  makeResizable() {
4363    if (this.isResizable) {
4364      this.#createResizers();
4365      this.#resizersDiv.classList.remove("hidden");
4366      bindEvents(this, this.div, ["keydown"]);
4367    }
4368  }
4369  get toolbarPosition() {
4370    return null;
4371  }
4372  keydown(event) {
4373    if (!this.isResizable || event.target !== this.div || event.key !== "Enter") {
4374      return;
4375    }
4376    this._uiManager.setSelected(this);
4377    this.#savedDimensions = {
4378      savedX: this.x,
4379      savedY: this.y,
4380      savedWidth: this.width,
4381      savedHeight: this.height
4382    };
4383    const children = this.#resizersDiv.children;
4384    if (!this.#allResizerDivs) {
4385      this.#allResizerDivs = Array.from(children);
4386      const boundResizerKeydown = this.#resizerKeydown.bind(this);
4387      const boundResizerBlur = this.#resizerBlur.bind(this);
4388      const signal = this._uiManager._signal;
4389      for (const div of this.#allResizerDivs) {
4390        const name = div.getAttribute("data-resizer-name");
4391        div.setAttribute("role", "spinbutton");
4392        div.addEventListener("keydown", boundResizerKeydown, {
4393          signal
4394        });
4395        div.addEventListener("blur", boundResizerBlur, {
4396          signal
4397        });
4398        div.addEventListener("focus", this.#resizerFocus.bind(this, name), {
4399          signal
4400        });
4401        div.setAttribute("data-l10n-id", AnnotationEditor._l10nResizer[name]);
4402      }
4403    }
4404    const first = this.#allResizerDivs[0];
4405    let firstPosition = 0;
4406    for (const div of children) {
4407      if (div === first) {
4408        break;
4409      }
4410      firstPosition++;
4411    }
4412    const nextFirstPosition = (360 - this.rotation + this.parentRotation) % 360 / 90 * (this.#allResizerDivs.length / 4);
4413    if (nextFirstPosition !== firstPosition) {
4414      if (nextFirstPosition < firstPosition) {
4415        for (let i = 0; i < firstPosition - nextFirstPosition; i++) {
4416          this.#resizersDiv.append(this.#resizersDiv.firstChild);
4417        }
4418      } else if (nextFirstPosition > firstPosition) {
4419        for (let i = 0; i < nextFirstPosition - firstPosition; i++) {
4420          this.#resizersDiv.firstChild.before(this.#resizersDiv.lastChild);
4421        }
4422      }
4423      let i = 0;
4424      for (const child of children) {
4425        const div = this.#allResizerDivs[i++];
4426        const name = div.getAttribute("data-resizer-name");
4427        child.setAttribute("data-l10n-id", AnnotationEditor._l10nResizer[name]);
4428      }
4429    }
4430    this.#setResizerTabIndex(0);
4431    this.#isResizerEnabledForKeyboard = true;
4432    this.#resizersDiv.firstChild.focus({
4433      focusVisible: true
4434    });
4435    event.preventDefault();
4436    event.stopImmediatePropagation();
4437  }
4438  #resizerKeydown(event) {
4439    AnnotationEditor._resizerKeyboardManager.exec(this, event);
4440  }
4441  #resizerBlur(event) {
4442    if (this.#isResizerEnabledForKeyboard && event.relatedTarget?.parentNode !== this.#resizersDiv) {
4443      this.#stopResizing();
4444    }
4445  }
4446  #resizerFocus(name) {
4447    this.#focusedResizerName = this.#isResizerEnabledForKeyboard ? name : "";
4448  }
4449  #setResizerTabIndex(value) {
4450    if (!this.#allResizerDivs) {
4451      return;
4452    }
4453    for (const div of this.#allResizerDivs) {
4454      div.tabIndex = value;
4455    }
4456  }
4457  _resizeWithKeyboard(x, y) {
4458    if (!this.#isResizerEnabledForKeyboard) {
4459      return;
4460    }
4461    this.#resizerPointermove(this.#focusedResizerName, {
4462      movementX: x,
4463      movementY: y
4464    });
4465  }
4466  #stopResizing() {
4467    this.#isResizerEnabledForKeyboard = false;
4468    this.#setResizerTabIndex(-1);
4469    if (this.#savedDimensions) {
4470      const {
4471        savedX,
4472        savedY,
4473        savedWidth,
4474        savedHeight
4475      } = this.#savedDimensions;
4476      this.#addResizeToUndoStack(savedX, savedY, savedWidth, savedHeight);
4477      this.#savedDimensions = null;
4478    }
4479  }
4480  _stopResizingWithKeyboard() {
4481    this.#stopResizing();
4482    this.div.focus();
4483  }
4484  select() {
4485    this.makeResizable();
4486    this.div?.classList.add("selectedEditor");
4487    if (!this._editToolbar) {
4488      this.addEditToolbar().then(() => {
4489        if (this.div?.classList.contains("selectedEditor")) {
4490          this._editToolbar?.show();
4491        }
4492      });
4493      return;
4494    }
4495    this._editToolbar?.show();
4496    this.#altText?.toggleAltTextBadge(false);
4497  }
4498  unselect() {
4499    this.#resizersDiv?.classList.add("hidden");
4500    this.div?.classList.remove("selectedEditor");
4501    if (this.div?.contains(document.activeElement)) {
4502      this._uiManager.currentLayer.div.focus({
4503        preventScroll: true
4504      });
4505    }
4506    this._editToolbar?.hide();
4507    this.#altText?.toggleAltTextBadge(true);
4508  }
4509  updateParams(type, value) {}
4510  disableEditing() {}
4511  enableEditing() {}
4512  enterInEditMode() {}
4513  getImageForAltText() {
4514    return null;
4515  }
4516  get contentDiv() {
4517    return this.div;
4518  }
4519  get isEditing() {
4520    return this.#isEditing;
4521  }
4522  set isEditing(value) {
4523    this.#isEditing = value;
4524    if (!this.parent) {
4525      return;
4526    }
4527    if (value) {
4528      this.parent.setSelected(this);
4529      this.parent.setActiveEditor(this);
4530    } else {
4531      this.parent.setActiveEditor(null);
4532    }
4533  }
4534  setAspectRatio(width, height) {
4535    this.#keepAspectRatio = true;
4536    const aspectRatio = width / height;
4537    const {
4538      style
4539    } = this.div;
4540    style.aspectRatio = aspectRatio;
4541    style.height = "auto";
4542  }
4543  static get MIN_SIZE() {
4544    return 16;
4545  }
4546  static canCreateNewEmptyEditor() {
4547    return true;
4548  }
4549  get telemetryInitialData() {
4550    return {
4551      action: "added"
4552    };
4553  }
4554  get telemetryFinalData() {
4555    return null;
4556  }
4557  _reportTelemetry(data, mustWait = false) {
4558    if (mustWait) {
4559      this.#telemetryTimeouts ||= new Map();
4560      const {
4561        action
4562      } = data;
4563      let timeout = this.#telemetryTimeouts.get(action);
4564      if (timeout) {
4565        clearTimeout(timeout);
4566      }
4567      timeout = setTimeout(() => {
4568        this._reportTelemetry(data);
4569        this.#telemetryTimeouts.delete(action);
4570        if (this.#telemetryTimeouts.size === 0) {
4571          this.#telemetryTimeouts = null;
4572        }
4573      }, AnnotationEditor._telemetryTimeout);
4574      this.#telemetryTimeouts.set(action, timeout);
4575      return;
4576    }
4577    data.type ||= this.editorType;
4578    this._uiManager._eventBus.dispatch("reporttelemetry", {
4579      source: this,
4580      details: {
4581        type: "editing",
4582        data
4583      }
4584    });
4585  }
4586  show(visible = this._isVisible) {
4587    this.div.classList.toggle("hidden", !visible);
4588    this._isVisible = visible;
4589  }
4590  enable() {
4591    if (this.div) {
4592      this.div.tabIndex = 0;
4593    }
4594    this.#disabled = false;
4595  }
4596  disable() {
4597    if (this.div) {
4598      this.div.tabIndex = -1;
4599    }
4600    this.#disabled = true;
4601  }
4602  renderAnnotationElement(annotation) {
4603    let content = annotation.container.querySelector(".annotationContent");
4604    if (!content) {
4605      content = document.createElement("div");
4606      content.classList.add("annotationContent", this.editorType);
4607      annotation.container.prepend(content);
4608    } else if (content.nodeName === "CANVAS") {
4609      const canvas = content;
4610      content = document.createElement("div");
4611      content.classList.add("annotationContent", this.editorType);
4612      canvas.before(content);
4613    }
4614    return content;
4615  }
4616  resetAnnotationElement(annotation) {
4617    const {
4618      firstChild
4619    } = annotation.container;
4620    if (firstChild?.nodeName === "DIV" && firstChild.classList.contains("annotationContent")) {
4621      firstChild.remove();
4622    }
4623  }
4624}
4625class FakeEditor extends AnnotationEditor {
4626  constructor(params) {
4627    super(params);
4628    this.annotationElementId = params.annotationElementId;
4629    this.deleted = true;
4630  }
4631  serialize() {
4632    return this.serializeDeleted();
4633  }
4634}
4635
4636;// ./src/shared/murmurhash3.js
4637const SEED = 0xc3d2e1f0;
4638const MASK_HIGH = 0xffff0000;
4639const MASK_LOW = 0xffff;
4640class MurmurHash3_64 {
4641  constructor(seed) {
4642    this.h1 = seed ? seed & 0xffffffff : SEED;
4643    this.h2 = seed ? seed & 0xffffffff : SEED;
4644  }
4645  update(input) {
4646    let data, length;
4647    if (typeof input === "string") {
4648      data = new Uint8Array(input.length * 2);
4649      length = 0;
4650      for (let i = 0, ii = input.length; i < ii; i++) {
4651        const code = input.charCodeAt(i);
4652        if (code <= 0xff) {
4653          data[length++] = code;
4654        } else {
4655          data[length++] = code >>> 8;
4656          data[length++] = code & 0xff;
4657        }
4658      }
4659    } else if (ArrayBuffer.isView(input)) {
4660      data = input.slice();
4661      length = data.byteLength;
4662    } else {
4663      throw new Error("Invalid data format, must be a string or TypedArray.");
4664    }
4665    const blockCounts = length >> 2;
4666    const tailLength = length - blockCounts * 4;
4667    const dataUint32 = new Uint32Array(data.buffer, 0, blockCounts);
4668    let k1 = 0,
4669      k2 = 0;
4670    let h1 = this.h1,
4671      h2 = this.h2;
4672    const C1 = 0xcc9e2d51,
4673      C2 = 0x1b873593;
4674    const C1_LOW = C1 & MASK_LOW,
4675      C2_LOW = C2 & MASK_LOW;
4676    for (let i = 0; i < blockCounts; i++) {
4677      if (i & 1) {
4678        k1 = dataUint32[i];
4679        k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW;
4680        k1 = k1 << 15 | k1 >>> 17;
4681        k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW;
4682        h1 ^= k1;
4683        h1 = h1 << 13 | h1 >>> 19;
4684        h1 = h1 * 5 + 0xe6546b64;
4685      } else {
4686        k2 = dataUint32[i];
4687        k2 = k2 * C1 & MASK_HIGH | k2 * C1_LOW & MASK_LOW;
4688        k2 = k2 << 15 | k2 >>> 17;
4689        k2 = k2 * C2 & MASK_HIGH | k2 * C2_LOW & MASK_LOW;
4690        h2 ^= k2;
4691        h2 = h2 << 13 | h2 >>> 19;
4692        h2 = h2 * 5 + 0xe6546b64;
4693      }
4694    }
4695    k1 = 0;
4696    switch (tailLength) {
4697      case 3:
4698        k1 ^= data[blockCounts * 4 + 2] << 16;
4699      case 2:
4700        k1 ^= data[blockCounts * 4 + 1] << 8;
4701      case 1:
4702        k1 ^= data[blockCounts * 4];
4703        k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW;
4704        k1 = k1 << 15 | k1 >>> 17;
4705        k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW;
4706        if (blockCounts & 1) {
4707          h1 ^= k1;
4708        } else {
4709          h2 ^= k1;
4710        }
4711    }
4712    this.h1 = h1;
4713    this.h2 = h2;
4714  }
4715  hexdigest() {
4716    let h1 = this.h1,
4717      h2 = this.h2;
4718    h1 ^= h2 >>> 1;
4719    h1 = h1 * 0xed558ccd & MASK_HIGH | h1 * 0x8ccd & MASK_LOW;
4720    h2 = h2 * 0xff51afd7 & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16;
4721    h1 ^= h2 >>> 1;
4722    h1 = h1 * 0x1a85ec53 & MASK_HIGH | h1 * 0xec53 & MASK_LOW;
4723    h2 = h2 * 0xc4ceb9fe & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16;
4724    h1 ^= h2 >>> 1;
4725    return (h1 >>> 0).toString(16).padStart(8, "0") + (h2 >>> 0).toString(16).padStart(8, "0");
4726  }
4727}
4728
4729;// ./src/display/annotation_storage.js
4730
4731
4732
4733const SerializableEmpty = Object.freeze({
4734  map: null,
4735  hash: "",
4736  transfer: undefined
4737});
4738class AnnotationStorage {
4739  #modified = false;
vendor: 6,371 bytes, lines 4740-4986
4740  #modifiedIds = null;
4741  #storage = new Map();
4742  constructor() {
4743    this.onSetModified = null;
4744    this.onResetModified = null;
4745    this.onAnnotationEditor = null;
4746  }
4747  getValue(key, defaultValue) {
4748    const value = this.#storage.get(key);
4749    if (value === undefined) {
4750      return defaultValue;
4751    }
4752    return Object.assign(defaultValue, value);
4753  }
4754  getRawValue(key) {
4755    return this.#storage.get(key);
4756  }
4757  remove(key) {
4758    this.#storage.delete(key);
4759    if (this.#storage.size === 0) {
4760      this.resetModified();
4761    }
4762    if (typeof this.onAnnotationEditor === "function") {
4763      for (const value of this.#storage.values()) {
4764        if (value instanceof AnnotationEditor) {
4765          return;
4766        }
4767      }
4768      this.onAnnotationEditor(null);
4769    }
4770  }
4771  setValue(key, value) {
4772    const obj = this.#storage.get(key);
4773    let modified = false;
4774    if (obj !== undefined) {
4775      for (const [entry, val] of Object.entries(value)) {
4776        if (obj[entry] !== val) {
4777          modified = true;
4778          obj[entry] = val;
4779        }
4780      }
4781    } else {
4782      modified = true;
4783      this.#storage.set(key, value);
4784    }
4785    if (modified) {
4786      this.#setModified();
4787    }
4788    if (value instanceof AnnotationEditor && typeof this.onAnnotationEditor === "function") {
4789      this.onAnnotationEditor(value.constructor._type);
4790    }
4791  }
4792  has(key) {
4793    return this.#storage.has(key);
4794  }
4795  getAll() {
4796    return this.#storage.size > 0 ? objectFromMap(this.#storage) : null;
4797  }
4798  setAll(obj) {
4799    for (const [key, val] of Object.entries(obj)) {
4800      this.setValue(key, val);
4801    }
4802  }
4803  get size() {
4804    return this.#storage.size;
4805  }
4806  #setModified() {
4807    if (!this.#modified) {
4808      this.#modified = true;
4809      if (typeof this.onSetModified === "function") {
4810        this.onSetModified();
4811      }
4812    }
4813  }
4814  resetModified() {
4815    if (this.#modified) {
4816      this.#modified = false;
4817      if (typeof this.onResetModified === "function") {
4818        this.onResetModified();
4819      }
4820    }
4821  }
4822  get print() {
4823    return new PrintAnnotationStorage(this);
4824  }
4825  get serializable() {
4826    if (this.#storage.size === 0) {
4827      return SerializableEmpty;
4828    }
4829    const map = new Map(),
4830      hash = new MurmurHash3_64(),
4831      transfer = [];
4832    const context = Object.create(null);
4833    let hasBitmap = false;
4834    for (const [key, val] of this.#storage) {
4835      const serialized = val instanceof AnnotationEditor ? val.serialize(false, context) : val;
4836      if (serialized) {
4837        map.set(key, serialized);
4838        hash.update(`${key}:${JSON.stringify(serialized)}`);
4839        hasBitmap ||= !!serialized.bitmap;
4840      }
4841    }
4842    if (hasBitmap) {
4843      for (const value of map.values()) {
4844        if (value.bitmap) {
4845          transfer.push(value.bitmap);
4846        }
4847      }
4848    }
4849    return map.size > 0 ? {
4850      map,
4851      hash: hash.hexdigest(),
4852      transfer
4853    } : SerializableEmpty;
4854  }
4855  get editorStats() {
4856    let stats = null;
4857    const typeToEditor = new Map();
4858    for (const value of this.#storage.values()) {
4859      if (!(value instanceof AnnotationEditor)) {
4860        continue;
4861      }
4862      const editorStats = value.telemetryFinalData;
4863      if (!editorStats) {
4864        continue;
4865      }
4866      const {
4867        type
4868      } = editorStats;
4869      if (!typeToEditor.has(type)) {
4870        typeToEditor.set(type, Object.getPrototypeOf(value).constructor);
4871      }
4872      stats ||= Object.create(null);
4873      const map = stats[type] ||= new Map();
4874      for (const [key, val] of Object.entries(editorStats)) {
4875        if (key === "type") {
4876          continue;
4877        }
4878        let counters = map.get(key);
4879        if (!counters) {
4880          counters = new Map();
4881          map.set(key, counters);
4882        }
4883        const count = counters.get(val) ?? 0;
4884        counters.set(val, count + 1);
4885      }
4886    }
4887    for (const [type, editor] of typeToEditor) {
4888      stats[type] = editor.computeTelemetryFinalData(stats[type]);
4889    }
4890    return stats;
4891  }
4892  resetModifiedIds() {
4893    this.#modifiedIds = null;
4894  }
4895  get modifiedIds() {
4896    if (this.#modifiedIds) {
4897      return this.#modifiedIds;
4898    }
4899    const ids = [];
4900    for (const value of this.#storage.values()) {
4901      if (!(value instanceof AnnotationEditor) || !value.annotationElementId || !value.serialize()) {
4902        continue;
4903      }
4904      ids.push(value.annotationElementId);
4905    }
4906    return this.#modifiedIds = {
4907      ids: new Set(ids),
4908      hash: ids.join(",")
4909    };
4910  }
4911}
4912class PrintAnnotationStorage extends AnnotationStorage {
4913  #serializable;
4914  constructor(parent) {
4915    super();
4916    const {
4917      map,
4918      hash,
4919      transfer
4920    } = parent.serializable;
4921    const clone = structuredClone(map, transfer ? {
4922      transfer
4923    } : null);
4924    this.#serializable = {
4925      map: clone,
4926      hash,
4927      transfer
4928    };
4929  }
4930  get print() {
4931    unreachable("Should not call PrintAnnotationStorage.print");
4932  }
4933  get serializable() {
4934    return this.#serializable;
4935  }
4936  get modifiedIds() {
4937    return shadow(this, "modifiedIds", {
4938      ids: new Set(),
4939      hash: ""
4940    });
4941  }
4942}
4943
4944;// ./src/display/font_loader.js
4945
4946class FontLoader {
4947  #systemFonts = new Set();
4948  constructor({
4949    ownerDocument = globalThis.document,
4950    styleElement = null
4951  }) {
4952    this._document = ownerDocument;
4953    this.nativeFontFaces = new Set();
4954    this.styleElement = null;
4955    this.loadingRequests = [];
4956    this.loadTestFontId = 0;
4957  }
4958  addNativeFontFace(nativeFontFace) {
4959    this.nativeFontFaces.add(nativeFontFace);
4960    this._document.fonts.add(nativeFontFace);
4961  }
4962  removeNativeFontFace(nativeFontFace) {
4963    this.nativeFontFaces.delete(nativeFontFace);
4964    this._document.fonts.delete(nativeFontFace);
4965  }
4966  insertRule(rule) {
4967    if (!this.styleElement) {
4968      this.styleElement = this._document.createElement("style");
4969      this._document.documentElement.getElementsByTagName("head")[0].append(this.styleElement);
4970    }
4971    const styleSheet = this.styleElement.sheet;
4972    styleSheet.insertRule(rule, styleSheet.cssRules.length);
4973  }
4974  clear() {
4975    for (const nativeFontFace of this.nativeFontFaces) {
4976      this._document.fonts.delete(nativeFontFace);
4977    }
4978    this.nativeFontFaces.clear();
4979    this.#systemFonts.clear();
4980    if (this.styleElement) {
4981      this.styleElement.remove();
4982      this.styleElement = null;
4983    }
4984  }
4985  async loadSystemFont({
4986    systemFontInfo: info,
vendor: 4,823 bytes, lines 4987-5087
4987    _inspectFont
4988  }) {
4989    if (!info || this.#systemFonts.has(info.loadedName)) {
4990      return;
4991    }
4992    assert(!this.disableFontFace, "loadSystemFont shouldn't be called when `disableFontFace` is set.");
4993    if (this.isFontLoadingAPISupported) {
4994      const {
4995        loadedName,
4996        src,
4997        style
4998      } = info;
4999      const fontFace = new FontFace(loadedName, src, style);
5000      this.addNativeFontFace(fontFace);
5001      try {
5002        await fontFace.load();
5003        this.#systemFonts.add(loadedName);
5004        _inspectFont?.(info);
5005      } catch {
5006        warn(`Cannot load system font: ${info.baseFontName}, installing it could help to improve PDF rendering.`);
5007        this.removeNativeFontFace(fontFace);
5008      }
5009      return;
5010    }
5011    unreachable("Not implemented: loadSystemFont without the Font Loading API.");
5012  }
5013  async bind(font) {
5014    if (font.attached || font.missingFile && !font.systemFontInfo) {
5015      return;
5016    }
5017    font.attached = true;
5018    if (font.systemFontInfo) {
5019      await this.loadSystemFont(font);
5020      return;
5021    }
5022    if (this.isFontLoadingAPISupported) {
5023      const nativeFontFace = font.createNativeFontFace();
5024      if (nativeFontFace) {
5025        this.addNativeFontFace(nativeFontFace);
5026        try {
5027          await nativeFontFace.loaded;
5028        } catch (ex) {
5029          warn(`Failed to load font '${nativeFontFace.family}': '${ex}'.`);
5030          font.disableFontFace = true;
5031          throw ex;
5032        }
5033      }
5034      return;
5035    }
5036    const rule = font.createFontFaceRule();
5037    if (rule) {
5038      this.insertRule(rule);
5039      if (this.isSyncFontLoadingSupported) {
5040        return;
5041      }
5042      await new Promise(resolve => {
5043        const request = this._queueLoadingCallback(resolve);
5044        this._prepareFontLoadEvent(font, request);
5045      });
5046    }
5047  }
5048  get isFontLoadingAPISupported() {
5049    const hasFonts = !!this._document?.fonts;
5050    return shadow(this, "isFontLoadingAPISupported", hasFonts);
5051  }
5052  get isSyncFontLoadingSupported() {
5053    let supported = false;
5054    if (isNodeJS) {
5055      supported = true;
5056    } else if (typeof navigator !== "undefined" && typeof navigator?.userAgent === "string" && /Mozilla\/5.0.*?rv:\d+.*? Gecko/.test(navigator.userAgent)) {
5057      supported = true;
5058    }
5059    return shadow(this, "isSyncFontLoadingSupported", supported);
5060  }
5061  _queueLoadingCallback(callback) {
5062    function completeRequest() {
5063      assert(!request.done, "completeRequest() cannot be called twice.");
5064      request.done = true;
5065      while (loadingRequests.length > 0 && loadingRequests[0].done) {
5066        const otherRequest = loadingRequests.shift();
5067        setTimeout(otherRequest.callback, 0);
5068      }
5069    }
5070    const {
5071      loadingRequests
5072    } = this;
5073    const request = {
5074      done: false,
5075      complete: completeRequest,
5076      callback
5077    };
5078    loadingRequests.push(request);
5079    return request;
5080  }
5081  get _loadTestFont() {
5082    const testFont = atob("T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQA" + "FQAABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAA" + "ALwAAAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgA" + "AAAGbmFtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1" + "AAsD6AAAAADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD" + "6AAAAAAD6AABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACM" + "AooCvAAAAeAAMQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4D" + "IP84AFoDIQAAAAAAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAA" + "AAEAAQAAAAEAAAAAAAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUA" + "AQAAAAEAAAAAAAYAAQAAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgAB" + "AAMAAQQJAAMAAgABAAMAAQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABY" + "AAAAAAAAAwAAAAMAAAAcAAEAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAA" + "AC7////TAAEAAAAAAAABBgAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAA" + "AAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgcA/gXBIwMAYuL+nz5tQXkD5j3CBLnEQAC" + "AQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYAAABAQAADwACAQEEE/t3" + "Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQAAAAAAAABAAAAAMmJbzEAAAAAzgTj" + "FQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAgABAAAAAAAAAAAD6AAAAAAAAA==");
5083    return shadow(this, "_loadTestFont", testFont);
5084  }
5085  _prepareFontLoadEvent(font, request) {
5086    function int32(data, offset) {
5087      return data.charCodeAt(offset) << 24 | data.charCodeAt(offset + 1) << 16 | data.charCodeAt(offset + 2) << 8 | data.charCodeAt(offset + 3) & 0xff;
5088    }
5089    function spliceString(s, offset, remove, insert) {
5090      const chunk1 = s.substring(0, offset);
5091      const chunk2 = s.substring(offset + remove);
5092      return chunk1 + insert + chunk2;
5093    }
5094    let i, ii;
5095    const canvas = this._document.createElement("canvas");
5096    canvas.width = 1;
5097    canvas.height = 1;
5098    const ctx = canvas.getContext("2d");
5099    let called = 0;
5100    function isFontReady(name, callback) {
5101      if (++called > 30) {
5102        warn("Load test font never loaded.");
5103        callback();
5104        return;
5105      }
5106      ctx.font = "30px " + name;
5107      ctx.fillText(".", 0, 20);
5108      const imageData = ctx.getImageData(0, 0, 1, 1);
5109      if (imageData.data[3] > 0) {
5110        callback();
5111        return;
5112      }
5113      setTimeout(isFontReady.bind(null, name, callback));
5114    }
5115    const loadTestFontId = `lt${Date.now()}${this.loadTestFontId++}`;
5116    let data = this._loadTestFont;
5117    const COMMENT_OFFSET = 976;
5118    data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length, loadTestFontId);
5119    const CFF_CHECKSUM_OFFSET = 16;
5120    const XXXX_VALUE = 0x58585858;
5121    let checksum = int32(data, CFF_CHECKSUM_OFFSET);
5122    for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) {
5123      checksum = checksum - XXXX_VALUE + int32(loadTestFontId, i) | 0;
5124    }
5125    if (i < loadTestFontId.length) {
5126      checksum = checksum - XXXX_VALUE + int32(loadTestFontId + "XXX", i) | 0;
5127    }
5128    data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum));
5129    const url = `url(data:font/opentype;base64,${btoa(data)});`;
5130    const rule = `@font-face {font-family:"${loadTestFontId}";src:${url}}`;
5131    this.insertRule(rule);
5132    const div = this._document.createElement("div");
5133    div.style.visibility = "hidden";
5134    div.style.width = div.style.height = "10px";
5135    div.style.position = "absolute";
5136    div.style.top = div.style.left = "0px";
5137    for (const name of [font.loadedName, loadTestFontId]) {
5138      const span = this._document.createElement("span");
5139      span.textContent = "Hi";
5140      span.style.fontFamily = name;
5141      div.append(span);
5142    }
5143    this._document.body.append(div);
5144    isFontReady(loadTestFontId, () => {
5145      div.remove();
5146      request.complete();
5147    });
5148  }
5149}
5150class FontFaceObject {
5151  constructor(translatedData, {
5152    disableFontFace = false,
5153    inspectFont = null
5154  }) {
5155    this.compiledGlyphs = Object.create(null);
5156    for (const i in translatedData) {
5157      this[i] = translatedData[i];
5158    }
5159    this.disableFontFace = disableFontFace === true;
5160    this._inspectFont = inspectFont;
5161  }
5162  createNativeFontFace() {
5163    if (!this.data || this.disableFontFace) {
5164      return null;
5165    }
5166    let nativeFontFace;
5167    if (!this.cssFontInfo) {
5168      nativeFontFace = new FontFace(this.loadedName, this.data, {});
5169    } else {
5170      const css = {
5171        weight: this.cssFontInfo.fontWeight
5172      };
5173      if (this.cssFontInfo.italicAngle) {
5174        css.style = `oblique ${this.cssFontInfo.italicAngle}deg`;
5175      }
5176      nativeFontFace = new FontFace(this.cssFontInfo.fontFamily, this.data, css);
5177    }
5178    this._inspectFont?.(this);
5179    return nativeFontFace;
5180  }
5181  createFontFaceRule() {
5182    if (!this.data || this.disableFontFace) {
5183      return null;
5184    }
5185    const url = `url(data:${this.mimetype};base64,${toBase64Util(this.data)});`;
5186    let rule;
5187    if (!this.cssFontInfo) {
5188      rule = `@font-face {font-family:"${this.loadedName}";src:${url}}`;
5189    } else {
5190      let css = `font-weight: ${this.cssFontInfo.fontWeight};`;
5191      if (this.cssFontInfo.italicAngle) {
5192        css += `font-style: oblique ${this.cssFontInfo.italicAngle}deg;`;
5193      }
5194      rule = `@font-face {font-family:"${this.cssFontInfo.fontFamily}";${css}src:${url}}`;
5195    }
5196    this._inspectFont?.(this, url);
5197    return rule;
5198  }
5199  getPathGenerator(objs, character) {
5200    if (this.compiledGlyphs[character] !== undefined) {
5201      return this.compiledGlyphs[character];
5202    }
5203    let cmds;
5204    try {
5205      cmds = objs.get(this.loadedName + "_path_" + character);
5206    } catch (ex) {
5207      warn(`getPathGenerator - ignoring character: "${ex}".`);
5208    }
5209    if (!Array.isArray(cmds) || cmds.length === 0) {
5210      return this.compiledGlyphs[character] = function (c, size) {};
5211    }
5212    const commands = [];
5213    for (let i = 0, ii = cmds.length; i < ii;) {
5214      switch (cmds[i++]) {
5215        case FontRenderOps.BEZIER_CURVE_TO:
5216          {
5217            const [a, b, c, d, e, f] = cmds.slice(i, i + 6);
5218            commands.push(ctx => ctx.bezierCurveTo(a, b, c, d, e, f));
5219            i += 6;
5220          }
5221          break;
5222        case FontRenderOps.MOVE_TO:
5223          {
5224            const [a, b] = cmds.slice(i, i + 2);
5225            commands.push(ctx => ctx.moveTo(a, b));
5226            i += 2;
5227          }
5228          break;
5229        case FontRenderOps.LINE_TO:
5230          {
5231            const [a, b] = cmds.slice(i, i + 2);
5232            commands.push(ctx => ctx.lineTo(a, b));
5233            i += 2;
5234          }
5235          break;
5236        case FontRenderOps.QUADRATIC_CURVE_TO:
5237          {
5238            const [a, b, c, d] = cmds.slice(i, i + 4);
5239            commands.push(ctx => ctx.quadraticCurveTo(a, b, c, d));
5240            i += 4;
5241          }
5242          break;
5243        case FontRenderOps.RESTORE:
5244          commands.push(ctx =>
5244 ctx.restore());
5245          break;
5246        case FontRenderOps.SAVE:
5247          commands.push(ctx => ctx.save());
5248          break;
5249        case FontRenderOps.SCALE:
5250          assert(commands.length === 2, "Scale command is only valid at the third position.");
5251          break;
5252        case FontRenderOps.TRANSFORM:
5253          {
5254            const [a, b, c, d, e, f] = cmds.slice(i, i + 6);
5255            commands.push(ctx => ctx.transform(a, b, c, d, e, f));
5256            i += 6;
5257          }
5258          break;
5259        case FontRenderOps.TRANSLATE:
5260          {
5261            const [a, b] = cmds.slice(i, i + 2);
5262            commands.push(ctx => ctx.translate(a, b));
5263            i += 2;
5264          }
5265          break;
5266      }
5267    }
5268    return this.compiledGlyphs[character] = function glyphDrawer(ctx, size) {
5269      commands[0](ctx);
5270      commands[1](ctx);
5271      ctx.scale(size, -size);
5272      for (let i = 2, ii = commands.length; i < ii; i++) {
5273        commands[i](ctx);
5274      }
5275    };
5276  }
5277}
5278
5279;// ./src/display/canvas_factory.js
5280
5281class BaseCanvasFactory {
5282  #enableHWA = false;
5283  constructor({
5284    enableHWA = false
5285  }) {
5286    this.#enableHWA = enableHWA;
5287  }
5288  create(width, height) {
5289    if (width <= 0 || height <= 0) {
5290      throw new Error("Invalid canvas size");
5291    }
5292    const canvas = this._createCanvas(width, height);
5293    return {
5294      canvas,
5295      context: canvas.getContext("2d", {
5296        willReadFrequently: !this.#enableHWA
5297      })
5298    };
5299  }
5300  reset(canvasAndContext, width, height) {
5301    if (!canvasAndContext.canvas) {
5302      throw new Error("Canvas is not specified");
5303    }
5304    if (width <= 0 || height <= 0) {
5305      throw new Error("Invalid canvas size");
5306    }
5307    canvasAndContext.canvas.width = width;
5308    canvasAndContext.canvas.height = height;
5309  }
5310  destroy(canvasAndContext) {
5311    if (!canvasAndContext.canvas) {
5312      throw new Error("Canvas is not specified");
5313    }
5314    canvasAndContext.canvas.width = 0;
5315    canvasAndContext.canvas.height = 0;
5316    canvasAndContext.canvas = null;
5317    canvasAndContext.context = null;
5318  }
5319  _createCanvas(width, height) {
5320    unreachable("Abstract method `_createCanvas` called.");
5321  }
5322}
5323class DOMCanvasFactory extends BaseCanvasFactory {
5324  constructor({
5325    ownerDocument = globalThis.document,
5326    enableHWA = false
5327  }) {
5328    super({
5329      enableHWA
5330    });
5331    this._document = ownerDocument;
5332  }
5333  _createCanvas(width, height) {
5334    const canvas = this._document.createElement("canvas");
5335    canvas.width = width;
5336    canvas.height = height;
5337    return canvas;
5338  }
5339}
5340
5341;// ./src/display/cmap_reader_factory.js
5342
5343
5344class BaseCMapReaderFactory {
5345  constructor({
5346    baseUrl = null,
5347    isCompressed = true
5348  }) {
5349    this.baseUrl = baseUrl;
5350    this.isCompressed = isCompressed;
5351  }
5352  async fetch({
5353    name
5354  }) {
5355    if (!this.baseUrl) {
5356      throw new Error("Ensure that the `cMapUrl` and `cMapPacked` API parameters are provided.");
5357    }
5358    if (!name) {
5359      throw new Error("CMap name must be specified.");
5360    }
5361    const url = this.baseUrl + name + (this.isCompressed ? ".bcmap" : "");
5362    return this._fetch(url).then(cMapData => ({
5363      cMapData,
5364      isCompressed: this.isCompressed
5365    })).catch(reason => {
5366      throw new Error(`Unable to load ${this.isCompressed ? "binary " : ""}CMap at: ${url}`);
5367    });
5368  }
5369  async _fetch(url) {
5370    unreachable("Abstract method `_fetch` called.");
5371  }
5372}
5373class DOMCMapReaderFactory extends BaseCMapReaderFactory {
5374  async _fetch(url) {
5375    const data = await fetchData(url, this.isCompressed ? "arraybuffer" : "text");
5376    return data instanceof ArrayBuffer ? new Uint8Array(data) : stringToBytes(data);
5377  }
5378}
5379
5380;// ./src/display/filter_factory.js
5381
5382
5383class BaseFilterFactory {
5384  addFilter(maps) {
5385    return "none";
5386  }
5387  addHCMFilter(fgColor, bgColor) {
5388    return "none";
5389  }
5390  addAlphaFilter(map) {
5391    return "none";
5392  }
5393  addLuminosityFilter(map) {
5394    return "none";
5395  }
5396  addHighlightHCMFilter(filterName, fgColor, bgColor, newFgColor, newBgColor) {
5397    return "none";
5398  }
5399  destroy(keepHCM = false) {}
5400}
5401class DOMFilterFactory extends BaseFilterFactory {
5402  #baseUrl;
5403  #_cache;
5404  #_defs;
5405  #docId;
5406  #document;
vendor: 9,357 bytes, lines 5407-5702
5407  #_hcmCache;
5408  #id = 0;
5409  constructor({
5410    docId,
5411    ownerDocument = globalThis.document
5412  }) {
5413    super();
5414    this.#docId = docId;
5415    this.#document = ownerDocument;
5416  }
5417  get #cache() {
5418    return this.#_cache ||= new Map();
5419  }
5420  get #hcmCache() {
5421    return this.#_hcmCache ||= new Map();
5422  }
5423  get #defs() {
5424    if (!this.#_defs) {
5425      const div = this.#document.createElement("div");
5426      const {
5427        style
5428      } = div;
5429      style.visibility = "hidden";
5430      style.contain = "strict";
5431      style.width = style.height = 0;
5432      style.position = "absolute";
5433      style.top = style.left = 0;
5434      style.zIndex = -1;
5435      const svg = this.#document.createElementNS(SVG_NS, "svg");
5436      svg.setAttribute("width", 0);
5437      svg.setAttribute("height", 0);
5438      this.#_defs = this.#document.createElementNS(SVG_NS, "defs");
5439      div.append(svg);
5440      svg.append(this.#_defs);
5441      this.#document.body.append(div);
5442    }
5443    return this.#_defs;
5444  }
5445  #createTables(maps) {
5446    if (maps.length === 1) {
5447      const mapR = maps[0];
5448      const buffer = new Array(256);
5449      for (let i = 0; i < 256; i++) {
5450        buffer[i] = mapR[i] / 255;
5451      }
5452      const table = buffer.join(",");
5453      return [table, table, table];
5454    }
5455    const [mapR, mapG, mapB] = maps;
5456    const bufferR = new Array(256);
5457    const bufferG = new Array(256);
5458    const bufferB = new Array(256);
5459    for (let i = 0; i < 256; i++) {
5460      bufferR[i] = mapR[i] / 255;
5461      bufferG[i] = mapG[i] / 255;
5462      bufferB[i] = mapB[i] / 255;
5463    }
5464    return [bufferR.join(","), bufferG.join(","), bufferB.join(",")];
5465  }
5466  #createUrl(id) {
5467    if (this.#baseUrl === undefined) {
5468      this.#baseUrl = "";
5469      const url = this.#document.URL;
5470      if (url !== this.#document.baseURI) {
5471        if (isDataScheme(url)) {
5472          warn('#createUrl: ignore "data:"-URL for performance reasons.');
5473        } else {
5474          this.#baseUrl = url.split("#", 1)[0];
5475        }
5476      }
5477    }
5478    return `url(${this.#baseUrl}#${id})`;
5479  }
5480  addFilter(maps) {
5481    if (!maps) {
5482      return "none";
5483    }
5484    let value = this.#cache.get(maps);
5485    if (value) {
5486      return value;
5487    }
5488    const [tableR, tableG, tableB] = this.#createTables(maps);
5489    const key = maps.length === 1 ? tableR : `${tableR}${tableG}${tableB}`;
5490    value = this.#cache.get(key);
5491    if (value) {
5492      this.#cache.set(maps, value);
5493      return value;
5494    }
5495    const id = `g_${this.#docId}_transfer_map_${this.#id++}`;
5496    const url = this.#createUrl(id);
5497    this.#cache.set(maps, url);
5498    this.#cache.set(key, url);
5499    const filter = this.#createFilter(id);
5500    this.#addTransferMapConversion(tableR, tableG, tableB, filter);
5501    return url;
5502  }
5503  addHCMFilter(fgColor, bgColor) {
5504    const key = `${fgColor}-${bgColor}`;
5505    const filterName = "base";
5506    let info = this.#hcmCache.get(filterName);
5507    if (info?.key === key) {
5508      return info.url;
5509    }
5510    if (info) {
5511      info.filter?.remove();
5512      info.key = key;
5513      info.url = "none";
5514      info.filter = null;
5515    } else {
5516      info = {
5517        key,
5518        url: "none",
5519        filter: null
5520      };
5521      this.#hcmCache.set(filterName, info);
5522    }
5523    if (!fgColor || !bgColor) {
5524      return info.url;
5525    }
5526    const fgRGB = this.#getRGB(fgColor);
5527    fgColor = Util.makeHexColor(...fgRGB);
5528    const bgRGB = this.#getRGB(bgColor);
5529    bgColor = Util.makeHexColor(...bgRGB);
5530    this.#defs.style.color = "";
5531    if (fgColor === "#000000" && bgColor === "#ffffff" || fgColor === bgColor) {
5532      return info.url;
5533    }
5534    const map = new Array(256);
5535    for (let i = 0; i <= 255; i++) {
5536      const x = i / 255;
5537      map[i] = x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
5538    }
5539    const table = map.join(",");
5540    const id = `g_${this.#docId}_hcm_filter`;
5541    const filter = info.filter = this.#createFilter(id);
5542    this.#addTransferMapConversion(table, table, table, filter);
5543    this.#addGrayConversion(filter);
5544    const getSteps = (c, n) => {
5545      const start = fgRGB[c] / 255;
5546      const end = bgRGB[c] / 255;
5547      const arr = new Array(n + 1);
5548      for (let i = 0; i <= n; i++) {
5549        arr[i] = start + i / n * (end - start);
5550      }
5551      return arr.join(",");
5552    };
5553    this.#addTransferMapConversion(getSteps(0, 5), getSteps(1, 5), getSteps(2, 5), filter);
5554    info.url = this.#createUrl(id);
5555    return info.url;
5556  }
5557  addAlphaFilter(map) {
5558    let value = this.#cache.get(map);
5559    if (value) {
5560      return value;
5561    }
5562    const [tableA] = this.#createTables([map]);
5563    const key = `alpha_${tableA}`;
5564    value = this.#cache.get(key);
5565    if (value) {
5566      this.#cache.set(map, value);
5567      return value;
5568    }
5569    const id = `g_${this.#docId}_alpha_map_${this.#id++}`;
5570    const url = this.#createUrl(id);
5571    this.#cache.set(map, url);
5572    this.#cache.set(key, url);
5573    const filter = this.#createFilter(id);
5574    this.#addTransferMapAlphaConversion(tableA, filter);
5575    return url;
5576  }
5577  addLuminosityFilter(map) {
5578    let value = this.#cache.get(map || "luminosity");
5579    if (value) {
5580      return value;
5581    }
5582    let tableA, key;
5583    if (map) {
5584      [tableA] = this.#createTables([map]);
5585      key = `luminosity_${tableA}`;
5586    } else {
5587      key = "luminosity";
5588    }
5589    value = this.#cache.get(key);
5590    if (value) {
5591      this.#cache.set(map, value);
5592      return value;
5593    }
5594    const id = `g_${this.#docId}_luminosity_map_${this.#id++}`;
5595    const url = this.#createUrl(id);
5596    this.#cache.set(map, url);
5597    this.#cache.set(key, url);
5598    const filter = this.#createFilter(id);
5599    this.#addLuminosityConversion(filter);
5600    if (map) {
5601      this.#addTransferMapAlphaConversion(tableA, filter);
5602    }
5603    return url;
5604  }
5605  addHighlightHCMFilter(filterName, fgColor, bgColor, newFgColor, newBgColor) {
5606    const key = `${fgColor}-${bgColor}-${newFgColor}-${newBgColor}`;
5607    let info = this.#hcmCache.get(filterName);
5608    if (info?.key === key) {
5609      return info.url;
5610    }
5611    if (info) {
5612      info.filter?.remove();
5613      info.key = key;
5614      info.url = "none";
5615      info.filter = null;
5616    } else {
5617      info = {
5618        key,
5619        url: "none",
5620        filter: null
5621      };
5622      this.#hcmCache.set(filterName, info);
5623    }
5624    if (!fgColor || !bgColor) {
5625      return info.url;
5626    }
5627    const [fgRGB, bgRGB] = [fgColor, bgColor].map(this.#getRGB.bind(this));
5628    let fgGray = Math.round(0.2126 * fgRGB[0] + 0.7152 * fgRGB[1] + 0.0722 * fgRGB[2]);
5629    let bgGray = Math.round(0.2126 * bgRGB[0] + 0.7152 * bgRGB[1] + 0.0722 * bgRGB[2]);
5630    let [newFgRGB, newBgRGB] = [newFgColor, newBgColor].map(this.#getRGB.bind(this));
5631    if (bgGray < fgGray) {
5632      [fgGray, bgGray, newFgRGB, newBgRGB] = [bgGray, fgGray, newBgRGB, newFgRGB];
5633    }
5634    this.#defs.style.color = "";
5635    const getSteps = (fg, bg, n) => {
5636      const arr = new Array(256);
5637      const step = (bgGray - fgGray) / n;
5638      const newStart = fg / 255;
5639      const newStep = (bg - fg) / (255 * n);
5640      let prev = 0;
5641      for (let i = 0; i <= n; i++) {
5642        const k = Math.round(fgGray + i * step);
5643        const value = newStart + i * newStep;
5644        for (let j = prev; j <= k; j++) {
5645          arr[j] = value;
5646        }
5647        prev = k + 1;
5648      }
5649      for (let i = prev; i < 256; i++) {
5650        arr[i] = arr[prev - 1];
5651      }
5652      return arr.join(",");
5653    };
5654    const id = `g_${this.#docId}_hcm_${filterName}_filter`;
5655    const filter = info.filter = this.#createFilter(id);
5656    this.#addGrayConversion(filter);
5657    this.#addTransferMapConversion(getSteps(newFgRGB[0], newBgRGB[0], 5), getSteps(newFgRGB[1], newBgRGB[1], 5), getSteps(newFgRGB[2], newBgRGB[2], 5), filter);
5658    info.url = this.#createUrl(id);
5659    return info.url;
5660  }
5661  destroy(keepHCM = false) {
5662    if (keepHCM && this.#hcmCache.size !== 0) {
5663      return;
5664    }
5665    if (this.#_defs) {
5666      this.#_defs.parentNode.parentNode.remove();
5667      this.#_defs = null;
5668    }
5669    if (this.#_cache) {
5670      this.#_cache.clear();
5671      this.#_cache = null;
5672    }
5673    this.#id = 0;
5674  }
5675  #addLuminosityConversion(filter) {
5676    const feColorMatrix = this.#document.createElementNS(SVG_NS, "feColorMatrix");
5677    feColorMatrix.setAttribute("type", "matrix");
5678    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");
5679    filter.append(feColorMatrix);
5680  }
5681  #addGrayConversion(filter) {
5682    const feColorMatrix = this.#document.createElementNS(SVG_NS, "feColorMatrix");
5683    feColorMatrix.setAttribute("type", "matrix");
5684    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");
5685    filter.append(feColorMatrix);
5686  }
5687  #createFilter(id) {
5688    const filter = this.#document.createElementNS(SVG_NS, "filter");
5689    filter.setAttribute("color-interpolation-filters", "sRGB");
5690    filter.setAttribute("id", id);
5691    this.#defs.append(filter);
5692    return filter;
5693  }
5694  #appendFeFunc(feComponentTransfer, func, table) {
5695    const feFunc = this.#document.createElementNS(SVG_NS, func);
5696    feFunc.setAttribute("type", "discrete");
5697    feFunc.setAttribute("tableValues", table);
5698    feComponentTransfer.append(feFunc);
5699  }
5700  #addTransferMapConversion(rTable, gTable, bTable, filter) {
5701    const feComponentTransfer = this.#document.createElementNS(SVG_NS, "feComponentTransfer");
5702    filter.append(feComponentTransfer);
5703    this.#appendFeFunc(feComponentTransfer, "feFuncR", rTable);
5704    this.#appendFeFunc(feComponentTransfer, "feFuncG", gTable);
5705    this.#appendFeFunc(feComponentTransfer, "feFuncB", bTable);
5706  }
5707  #addTransferMapAlphaConversion(aTable, filter) {
5708    const feComponentTransfer = this.#document.createElementNS(SVG_NS, "feComponentTransfer");
5709    filter.append(feComponentTransfer);
5710    this.#appendFeFunc(feComponentTransfer, "feFuncA", aTable);
5711  }
5712  #getRGB(color) {
5713    this.#defs.style.color = color;
5714    return getRGB(getComputedStyle(this.#defs).getPropertyValue("color"));
5715  }
5716}
5717
5718;// ./src/display/standard_fontdata_factory.js
5719
5720
5721class BaseStandardFontDataFactory {
5722  constructor({
5723    baseUrl = null
5724  }) {
5725    this.baseUrl = baseUrl;
5726  }
5727  async fetch({
5728    filename
5729  }) {
5730    if (!this.baseUrl) {
5731      throw new Error("Ensure that the `standardFontDataUrl` API parameter is provided.");
5732    }
5733    if (!filename) {
5734      throw new Error("Font filename must be specified.");
5735    }
5736    const url = `${this.baseUrl}${filename}`;
5737    return this._fetch(url).catch(reason => {
5738      throw new Error(`Unable to load font data at: ${url}`);
5739    });
5740  }
5741  async _fetch(url) {
5742    unreachable("Abstract method `_fetch` called.");
5743  }
5744}
5745class DOMStandardFontDataFactory extends BaseStandardFontDataFactory {
5746  async _fetch(url) {
5747    const data = await fetchData(url, "arraybuffer");
5748    return new Uint8Array(data);
5749  }
5750}
5751
5752;// ./src/display/node_utils.js
5753
5754
5755
5756
5757
5758if (isNodeJS) {
5759  var packageCapability = Promise.withResolvers();
5760  var packageMap = null;
5761  const loadPackages = async () => {
5762    const fs = await import(/*webpackIgnore: true*/"fs"),
5763      http = await import(/*webpackIgnore: true*/"http"),
5764      https = await import(/*webpackIgnore: true*/"https"),
5765      url = await import(/*webpackIgnore: true*/"url");
5766    let canvas, path2d;
5767    return new Map(Object.entries({
5768      fs,
5769      http,
5770      https,
5771      url,
5772      canvas,
5773      path2d
5774    }));
5775  };
5776  loadPackages().then(map => {
5777    packageMap = map;
5778    packageCapability.resolve();
5779  }, reason => {
5780    warn(`loadPackages: ${reason}`);
5781    packageMap = new Map();
5782    packageCapability.resolve();
5783  });
5784}
5785class NodePackages {
5786  static get promise() {
5787    return packageCapability.promise;
5788  }
5789  static get(name) {
5790    return packageMap?.get(name);
5791  }
5792}
5793async function node_utils_fetchData(url) {
5794  const fs = NodePackages.get("fs");
5795  const data = await fs.promises.readFile(url);
5796  return new Uint8Array(data);
5797}
5798class NodeFilterFactory extends BaseFilterFactory {}
5799class NodeCanvasFactory extends BaseCanvasFactory {
5800  _createCanvas(width, height) {
5801    const canvas = NodePackages.get("canvas");
5802    return canvas.createCanvas(width, height);
5803  }
5804}
5805class NodeCMapReaderFactory extends BaseCMapReaderFactory {
5806  async _fetch(url) {
5807    return node_utils_fetchData(url);
5808  }
5809}
5810class NodeStandardFontDataFactory extends BaseStandardFontDataFactory {
5811  async _fetch(url) {
5812    return node_utils_fetchData(url);
5813  }
5814}
5815
5816;// ./src/display/pattern_helper.js
5817
5818
5819const PathType = {
5820  FILL: "Fill",
5821  STROKE: "Stroke",
5822  SHADING: "Shading"
5823};
5824function applyBoundingBox(ctx, bbox) {
5825  if (!bbox) {
5826    return;
5827  }
5828  const width = bbox[2] - bbox[0];
5829  const height = bbox[3] - bbox[1];
5830  const region = new Path2D();
5831  region.rect(bbox[0], bbox[1], width, height);
5832  ctx.clip(region);
5833}
5834class BaseShadingPattern {
5835  getPattern() {
5836    unreachable("Abstract method `getPattern` called.");
5837  }
5838}
5839class RadialAxialShadingPattern extends BaseShadingPattern {
5840  constructor(IR) {
5841    super();
5842    this._type = IR[1];
5843    this._bbox = IR[2];
5844    this._colorStops = IR[3];
5845    this._p0 = IR[4];
5846    this._p1 = IR[5];
5847    this._r0 = IR[6];
5848    this._r1 = IR[7];
5849    this.matrix = null;
5850  }
5851  _createGradient(ctx) {
5852    let grad;
5853    if (this._type === "axial") {
5854      grad = ctx.createLinearGradient(this._p0[0], this._p0[1], this._p1[0], this._p1[1]);
5855    } else if (this._type === "radial") {
5856      grad = ctx.createRadialGradient(this._p0[0], this._p0[1], this._r0, this._p1[0], this._p1[1], this._r1);
5857    }
5858    for (const colorStop of this._colorStops) {
5859      grad.addColorStop(colorStop[0], colorStop[1]);
5860    }
5861    return grad;
5862  }
5863  getPattern(ctx, owner, inverse, pathType) {
5864    let pattern;
5865    if (pathType === PathType.STROKE || pathType === PathType.FILL) {
5866      const ownerBBox = owner.current.getClippedPathBoundingBox(pathType, getCurrentTransform(ctx)) || [0, 0, 0, 0];
5867      const width = Math.ceil(ownerBBox[2] - ownerBBox[0]) || 1;
vendor: 13,602 bytes, lines 5868-6280
5868      const height = Math.ceil(ownerBBox[3] - ownerBBox[1]) || 1;
5869      const tmpCanvas = owner.cachedCanvases.getCanvas("pattern", width, height);
5870      const tmpCtx = tmpCanvas.context;
5871      tmpCtx.clearRect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height);
5872      tmpCtx.beginPath();
5873      tmpCtx.rect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height);
5874      tmpCtx.translate(-ownerBBox[0], -ownerBBox[1]);
5875      inverse = Util.transform(inverse, [1, 0, 0, 1, ownerBBox[0], ownerBBox[1]]);
5876      tmpCtx.transform(...owner.baseTransform);
5877      if (this.matrix) {
5878        tmpCtx.transform(...this.matrix);
5879      }
5880      applyBoundingBox(tmpCtx, this._bbox);
5881      tmpCtx.fillStyle = this._createGradient(tmpCtx);
5882      tmpCtx.fill();
5883      pattern = ctx.createPattern(tmpCanvas.canvas, "no-repeat");
5884      const domMatrix = new DOMMatrix(inverse);
5885      pattern.setTransform(domMatrix);
5886    } else {
5887      applyBoundingBox(ctx, this._bbox);
5888      pattern = this._createGradient(ctx);
5889    }
5890    return pattern;
5891  }
5892}
5893function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) {
5894  const coords = context.coords,
5895    colors = context.colors;
5896  const bytes = data.data,
5897    rowSize = data.width * 4;
5898  let tmp;
5899  if (coords[p1 + 1] > coords[p2 + 1]) {
5900    tmp = p1;
5901    p1 = p2;
5902    p2 = tmp;
5903    tmp = c1;
5904    c1 = c2;
5905    c2 = tmp;
5906  }
5907  if (coords[p2 + 1] > coords[p3 + 1]) {
5908    tmp = p2;
5909    p2 = p3;
5910    p3 = tmp;
5911    tmp = c2;
5912    c2 = c3;
5913    c3 = tmp;
5914  }
5915  if (coords[p1 + 1] > coords[p2 + 1]) {
5916    tmp = p1;
5917    p1 = p2;
5918    p2 = tmp;
5919    tmp = c1;
5920    c1 = c2;
5921    c2 = tmp;
5922  }
5923  const x1 = (coords[p1] + context.offsetX) * context.scaleX;
5924  const y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY;
5925  const x2 = (coords[p2] + context.offsetX) * context.scaleX;
5926  const y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY;
5927  const x3 = (coords[p3] + context.offsetX) * context.scaleX;
5928  const y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY;
5929  if (y1 >= y3) {
5930    return;
5931  }
5932  const c1r = colors[c1],
5933    c1g = colors[c1 + 1],
5934    c1b = colors[c1 + 2];
5935  const c2r = colors[c2],
5936    c2g = colors[c2 + 1],
5937    c2b = colors[c2 + 2];
5938  const c3r = colors[c3],
5939    c3g = colors[c3 + 1],
5940    c3b = colors[c3 + 2];
5941  const minY = Math.round(y1),
5942    maxY = Math.round(y3);
5943  let xa, car, cag, cab;
5944  let xb, cbr, cbg, cbb;
5945  for (let y = minY; y <= maxY; y++) {
5946    if (y < y2) {
5947      const k = y < y1 ? 0 : (y1 - y) / (y1 - y2);
5948      xa = x1 - (x1 - x2) * k;
5949      car = c1r - (c1r - c2r) * k;
5950      cag = c1g - (c1g - c2g) * k;
5951      cab = c1b - (c1b - c2b) * k;
5952    } else {
5953      let k;
5954      if (y > y3) {
5955        k = 1;
5956      } else if (y2 === y3) {
5957        k = 0;
5958      } else {
5959        k = (y2 - y) / (y2 - y3);
5960      }
5961      xa = x2 - (x2 - x3) * k;
5962      car = c2r - (c2r - c3r) * k;
5963      cag = c2g - (c2g - c3g) * k;
5964      cab = c2b - (c2b - c3b) * k;
5965    }
5966    let k;
5967    if (y < y1) {
5968      k = 0;
5969    } else if (y > y3) {
5970      k = 1;
5971    } else {
5972      k = (y1 - y) / (y1 - y3);
5973    }
5974    xb = x1 - (x1 - x3) * k;
5975    cbr = c1r - (c1r - c3r) * k;
5976    cbg = c1g - (c1g - c3g) * k;
5977    cbb = c1b - (c1b - c3b) * k;
5978    const x1_ = Math.round(Math.min(xa, xb));
5979    const x2_ = Math.round(Math.max(xa, xb));
5980    let j = rowSize * y + x1_ * 4;
5981    for (let x = x1_; x <= x2_; x++) {
5982      k = (xa - x) / (xa - xb);
5983      if (k < 0) {
5984        k = 0;
5985      } else if (k > 1) {
5986        k = 1;
5987      }
5988      bytes[j++] = car - (car - cbr) * k | 0;
5989      bytes[j++] = cag - (cag - cbg) * k | 0;
5990      bytes[j++] = cab - (cab - cbb) * k | 0;
5991      bytes[j++] = 255;
5992    }
5993  }
5994}
5995function drawFigure(data, figure, context) {
5996  const ps = figure.coords;
5997  const cs = figure.colors;
5998  let i, ii;
5999  switch (figure.type) {
6000    case "lattice":
6001      const verticesPerRow = figure.verticesPerRow;
6002      const rows = Math.floor(ps.length / verticesPerRow) - 1;
6003      const cols = verticesPerRow - 1;
6004      for (i = 0; i < rows; i++) {
6005        let q = i * verticesPerRow;
6006        for (let j = 0; j < cols; j++, q++) {
6007          drawTriangle(data, context, ps[q], ps[q + 1], ps[q + verticesPerRow], cs[q], cs[q + 1], cs[q + verticesPerRow]);
6008          drawTriangle(data, context, ps[q + verticesPerRow + 1], ps[q + 1], ps[q + verticesPerRow], cs[q + verticesPerRow + 1], cs[q + 1], cs[q + verticesPerRow]);
6009        }
6010      }
6011      break;
6012    case "triangles":
6013      for (i = 0, ii = ps.length; i < ii; i += 3) {
6014        drawTriangle(data, context, ps[i], ps[i + 1], ps[i + 2], cs[i], cs[i + 1], cs[i + 2]);
6015      }
6016      break;
6017    default:
6018      throw new Error("illegal figure");
6019  }
6020}
6021class MeshShadingPattern extends BaseShadingPattern {
6022  constructor(IR) {
6023    super();
6024    this._coords = IR[2];
6025    this._colors = IR[3];
6026    this._figures = IR[4];
6027    this._bounds = IR[5];
6028    this._bbox = IR[7];
6029    this._background = IR[8];
6030    this.matrix = null;
6031  }
6032  _createMeshCanvas(combinedScale, backgroundColor, cachedCanvases) {
6033    const EXPECTED_SCALE = 1.1;
6034    const MAX_PATTERN_SIZE = 3000;
6035    const BORDER_SIZE = 2;
6036    const offsetX = Math.floor(this._bounds[0]);
6037    const offsetY = Math.floor(this._bounds[1]);
6038    const boundsWidth = Math.ceil(this._bounds[2]) - offsetX;
6039    const boundsHeight = Math.ceil(this._bounds[3]) - offsetY;
6040    const width = Math.min(Math.ceil(Math.abs(boundsWidth * combinedScale[0] * EXPECTED_SCALE)), MAX_PATTERN_SIZE);
6041    const height = Math.min(Math.ceil(Math.abs(boundsHeight * combinedScale[1] * EXPECTED_SCALE)), MAX_PATTERN_SIZE);
6042    const scaleX = boundsWidth / width;
6043    const scaleY = boundsHeight / height;
6044    const context = {
6045      coords: this._coords,
6046      colors: this._colors,
6047      offsetX: -offsetX,
6048      offsetY: -offsetY,
6049      scaleX: 1 / scaleX,
6050      scaleY: 1 / scaleY
6051    };
6052    const paddedWidth = width + BORDER_SIZE * 2;
6053    const paddedHeight = height + BORDER_SIZE * 2;
6054    const tmpCanvas = cachedCanvases.getCanvas("mesh", paddedWidth, paddedHeight);
6055    const tmpCtx = tmpCanvas.context;
6056    const data = tmpCtx.createImageData(width, height);
6057    if (backgroundColor) {
6058      const bytes = data.data;
6059      for (let i = 0, ii = bytes.length; i < ii; i += 4) {
6060        bytes[i] = backgroundColor[0];
6061        bytes[i + 1] = backgroundColor[1];
6062        bytes[i + 2] = backgroundColor[2];
6063        bytes[i + 3] = 255;
6064      }
6065    }
6066    for (const figure of this._figures) {
6067      drawFigure(data, figure, context);
6068    }
6069    tmpCtx.putImageData(data, BORDER_SIZE, BORDER_SIZE);
6070    const canvas = tmpCanvas.canvas;
6071    return {
6072      canvas,
6073      offsetX: offsetX - BORDER_SIZE * scaleX,
6074      offsetY: offsetY - BORDER_SIZE * scaleY,
6075      scaleX,
6076      scaleY
6077    };
6078  }
6079  getPattern(ctx, owner, inverse, pathType) {
6080    applyBoundingBox(ctx, this._bbox);
6081    let scale;
6082    if (pathType === PathType.SHADING) {
6083      scale = Util.singularValueDecompose2dScale(getCurrentTransform(ctx));
6084    } else {
6085      scale = Util.singularValueDecompose2dScale(owner.baseTransform);
6086      if (this.matrix) {
6087        const matrixScale = Util.singularValueDecompose2dScale(this.matrix);
6088        scale = [scale[0] * matrixScale[0], scale[1] * matrixScale[1]];
6089      }
6090    }
6091    const temporaryPatternCanvas = this._createMeshCanvas(scale, pathType === PathType.SHADING ? null : this._background, owner.cachedCanvases);
6092    if (pathType !== PathType.SHADING) {
6093      ctx.setTransform(...owner.baseTransform);
6094      if (this.matrix) {
6095        ctx.transform(...this.matrix);
6096      }
6097    }
6098    ctx.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY);
6099    ctx.scale(temporaryPatternCanvas.scaleX, temporaryPatternCanvas.scaleY);
6100    return ctx.createPattern(temporaryPatternCanvas.canvas, "no-repeat");
6101  }
6102}
6103class DummyShadingPattern extends BaseShadingPattern {
6104  getPattern() {
6105    return "hotpink";
6106  }
6107}
6108function getShadingPattern(IR) {
6109  switch (IR[0]) {
6110    case "RadialAxial":
6111      return new RadialAxialShadingPattern(IR);
6112    case "Mesh":
6113      return new MeshShadingPattern(IR);
6114    case "Dummy":
6115      return new DummyShadingPattern();
6116  }
6117  throw new Error(`Unknown IR type: ${IR[0]}`);
6118}
6119const PaintType = {
6120  COLORED: 1,
6121  UNCOLORED: 2
6122};
6123class TilingPattern {
6124  static MAX_PATTERN_SIZE = 3000;
6125  constructor(IR, color, ctx, canvasGraphicsFactory, baseTransform) {
6126    this.operatorList = IR[2];
6127    this.matrix = IR[3];
6128    this.bbox = IR[4];
6129    this.xstep = IR[5];
6130    this.ystep = IR[6];
6131    this.paintType = IR[7];
6132    this.tilingType = IR[8];
6133    this.color = color;
6134    this.ctx = ctx;
6135    this.canvasGraphicsFactory = canvasGraphicsFactory;
6136    this.baseTransform = baseTransform;
6137  }
6138  createPatternCanvas(owner) {
6139    const {
6140      bbox,
6141      operatorList,
6142      paintType,
6143      tilingType,
6144      color,
6145      canvasGraphicsFactory
6146    } = this;
6147    let {
6148      xstep,
6149      ystep
6150    } = this;
6151    xstep = Math.abs(xstep);
6152    ystep = Math.abs(ystep);
6153    info("TilingType: " + tilingType);
6154    const x0 = bbox[0],
6155      y0 = bbox[1],
6156      x1 = bbox[2],
6157      y1 = bbox[3];
6158    const width = x1 - x0;
6159    const height = y1 - y0;
6160    const matrixScale = Util.singularValueDecompose2dScale(this.matrix);
6161    const curMatrixScale = Util.singularValueDecompose2dScale(this.baseTransform);
6162    const combinedScaleX = matrixScale[0] * curMatrixScale[0];
6163    const combinedScaleY = matrixScale[1] * curMatrixScale[1];
6164    let canvasWidth = width,
6165      canvasHeight = height,
6166      redrawHorizontally = false,
6167      redrawVertically = false;
6168    const xScaledStep = Math.ceil(xstep * combinedScaleX);
6169    const yScaledStep = Math.ceil(ystep * combinedScaleY);
6170    const xScaledWidth = Math.ceil(width * combinedScaleX);
6171    const yScaledHeight = Math.ceil(height * combinedScaleY);
6172    if (xScaledStep >= xScaledWidth) {
6173      canvasWidth = xstep;
6174    } else {
6175      redrawHorizontally = true;
6176    }
6177    if (yScaledStep >= yScaledHeight) {
6178      canvasHeight = ystep;
6179    } else {
6180      redrawVertically = true;
6181    }
6182    const dimx = this.getSizeAndScale(canvasWidth, this.ctx.canvas.width, combinedScaleX);
6183    const dimy = this.getSizeAndScale(canvasHeight, this.ctx.canvas.height, combinedScaleY);
6184    const tmpCanvas = owner.cachedCanvases.getCanvas("pattern", dimx.size, dimy.size);
6185    const tmpCtx = tmpCanvas.context;
6186    const graphics = canvasGraphicsFactory.createCanvasGraphics(tmpCtx);
6187    graphics.groupLevel = owner.groupLevel;
6188    this.setFillAndStrokeStyleToContext(graphics, paintType, color);
6189    tmpCtx.translate(-dimx.scale * x0, -dimy.scale * y0);
6190    graphics.transform(dimx.scale, 0, 0, dimy.scale, 0, 0);
6191    tmpCtx.save();
6192    this.clipBbox(graphics, x0, y0, x1, y1);
6193    graphics.baseTransform = getCurrentTransform(graphics.ctx);
6194    graphics.executeOperatorList(operatorList);
6195    graphics.endDrawing();
6196    tmpCtx.restore();
6197    if (redrawHorizontally || redrawVertically) {
6198      const image = tmpCanvas.canvas;
6199      if (redrawHorizontally) {
6200        canvasWidth = xstep;
6201      }
6202      if (redrawVertically) {
6203        canvasHeight = ystep;
6204      }
6205      const dimx2 = this.getSizeAndScale(canvasWidth, this.ctx.canvas.width, combinedScaleX);
6206      const dimy2 = this.getSizeAndScale(canvasHeight, this.ctx.canvas.height, combinedScaleY);
6207      const xSize = dimx2.size;
6208      const ySize = dimy2.size;
6209      const tmpCanvas2 = owner.cachedCanvases.getCanvas("pattern-workaround", xSize, ySize);
6210      const tmpCtx2 = tmpCanvas2.context;
6211      const ii = redrawHorizontally ? Math.floor(width / xstep) : 0;
6212      const jj = redrawVertically ? Math.floor(height / ystep) : 0;
6213      for (let i = 0; i <= ii; i++) {
6214        for (let j = 0; j <= jj; j++) {
6215          tmpCtx2.drawImage(image, xSize * i, ySize * j, xSize, ySize, 0, 0, xSize, ySize);
6216        }
6217      }
6218      return {
6219        canvas: tmpCanvas2.canvas,
6220        scaleX: dimx2.scale,
6221        scaleY: dimy2.scale,
6222        offsetX: x0,
6223        offsetY: y0
6224      };
6225    }
6226    return {
6227      canvas: tmpCanvas.canvas,
6228      scaleX: dimx.scale,
6229      scaleY: dimy.scale,
6230      offsetX: x0,
6231      offsetY: y0
6232    };
6233  }
6234  getSizeAndScale(step, realOutputSize, scale) {
6235    const maxSize = Math.max(TilingPattern.MAX_PATTERN_SIZE, realOutputSize);
6236    let size = Math.ceil(step * scale);
6237    if (size >= maxSize) {
6238      size = maxSize;
6239    } else {
6240      scale = size / step;
6241    }
6242    return {
6243      scale,
6244      size
6245    };
6246  }
6247  clipBbox(graphics, x0, y0, x1, y1) {
6248    const bboxWidth = x1 - x0;
6249    const bboxHeight = y1 - y0;
6250    graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight);
6251    graphics.current.updateRectMinMax(getCurrentTransform(graphics.ctx), [x0, y0, x1, y1]);
6252    graphics.clip();
6253    graphics.endPath();
6254  }
6255  setFillAndStrokeStyleToContext(graphics, paintType, color) {
6256    const context = graphics.ctx,
6257      current = graphics.current;
6258    switch (paintType) {
6259      case PaintType.COLORED:
6260        const ctx = this.ctx;
6261        context.fillStyle = ctx.fillStyle;
6262        context.strokeStyle = ctx.strokeStyle;
6263        current.fillColor = ctx.fillStyle;
6264        current.strokeColor = ctx.strokeStyle;
6265        break;
6266      case PaintType.UNCOLORED:
6267        const cssColor = Util.makeHexColor(color[0], color[1], color[2]);
6268        context.fillStyle = cssColor;
6269        context.strokeStyle = cssColor;
6270        current.fillColor = cssColor;
6271        current.strokeColor = cssColor;
6272        break;
6273      default:
6274        throw new FormatError(`Unsupported paint type: ${paintType}`);
6275    }
6276  }
6277  getPattern(ctx, owner, inverse, pathType) {
6278    let matrix = inverse;
6279    if (pathType !== PathType.SHADING) {
6280      matrix = Util.transform(matrix, owner.baseTransform);
vendor: 5,655 bytes, lines 6281-6454
6281      if (this.matrix) {
6282        matrix = Util.transform(matrix, this.matrix);
6283      }
6284    }
6285    const temporaryPatternCanvas = this.createPatternCanvas(owner);
6286    let domMatrix = new DOMMatrix(matrix);
6287    domMatrix = domMatrix.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY);
6288    domMatrix = domMatrix.scale(1 / temporaryPatternCanvas.scaleX, 1 / temporaryPatternCanvas.scaleY);
6289    const pattern = ctx.createPattern(temporaryPatternCanvas.canvas, "repeat");
6290    pattern.setTransform(domMatrix);
6291    return pattern;
6292  }
6293}
6294
6295;// ./src/shared/image_utils.js
6296
6297function convertToRGBA(params) {
6298  switch (params.kind) {
6299    case ImageKind.GRAYSCALE_1BPP:
6300      return convertBlackAndWhiteToRGBA(params);
6301    case ImageKind.RGB_24BPP:
6302      return convertRGBToRGBA(params);
6303  }
6304  return null;
6305}
6306function convertBlackAndWhiteToRGBA({
6307  src,
6308  srcPos = 0,
6309  dest,
6310  width,
6311  height,
6312  nonBlackColor = 0xffffffff,
6313  inverseDecode = false
6314}) {
6315  const black = util_FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff;
6316  const [zeroMapping, oneMapping] = inverseDecode ? [nonBlackColor, black] : [black, nonBlackColor];
6317  const widthInSource = width >> 3;
6318  const widthRemainder = width & 7;
6319  const srcLength = src.length;
6320  dest = new Uint32Array(dest.buffer);
6321  let destPos = 0;
6322  for (let i = 0; i < height; i++) {
6323    for (const max = srcPos + widthInSource; srcPos < max; srcPos++) {
6324      const elem = srcPos < srcLength ? src[srcPos] : 255;
6325      dest[destPos++] = elem & 0b10000000 ? oneMapping : zeroMapping;
6326      dest[destPos++] = elem & 0b1000000 ? oneMapping : zeroMapping;
6327      dest[destPos++] = elem & 0b100000 ? oneMapping : zeroMapping;
6328      dest[destPos++] = elem & 0b10000 ? oneMapping : zeroMapping;
6329      dest[destPos++] = elem & 0b1000 ? oneMapping : zeroMapping;
6330      dest[destPos++] = elem & 0b100 ? oneMapping : zeroMapping;
6331      dest[destPos++] = elem & 0b10 ? oneMapping : zeroMapping;
6332      dest[destPos++] = elem & 0b1 ? oneMapping : zeroMapping;
6333    }
6334    if (widthRemainder === 0) {
6335      continue;
6336    }
6337    const elem = srcPos < srcLength ? src[srcPos++] : 255;
6338    for (let j = 0; j < widthRemainder; j++) {
6339      dest[destPos++] = elem & 1 << 7 - j ? oneMapping : zeroMapping;
6340    }
6341  }
6342  return {
6343    srcPos,
6344    destPos
6345  };
6346}
6347function convertRGBToRGBA({
6348  src,
6349  srcPos = 0,
6350  dest,
6351  destPos = 0,
6352  width,
6353  height
6354}) {
6355  let i = 0;
6356  const len32 = src.length >> 2;
6357  const src32 = new Uint32Array(src.buffer, srcPos, len32);
6358  if (FeatureTest.isLittleEndian) {
6359    for (; i < len32 - 2; i += 3, destPos += 4) {
6360      const s1 = src32[i];
6361      const s2 = src32[i + 1];
6362      const s3 = src32[i + 2];
6363      dest[destPos] = s1 | 0xff000000;
6364      dest[destPos + 1] = s1 >>> 24 | s2 << 8 | 0xff000000;
6365      dest[destPos + 2] = s2 >>> 16 | s3 << 16 | 0xff000000;
6366      dest[destPos + 3] = s3 >>> 8 | 0xff000000;
6367    }
6368    for (let j = i * 4, jj = src.length; j < jj; j += 3) {
6369      dest[destPos++] = src[j] | src[j + 1] << 8 | src[j + 2] << 16 | 0xff000000;
6370    }
6371  } else {
6372    for (; i < len32 - 2; i += 3, destPos += 4) {
6373      const s1 = src32[i];
6374      const s2 = src32[i + 1];
6375      const s3 = src32[i + 2];
6376      dest[destPos] = s1 | 0xff;
6377      dest[destPos + 1] = s1 << 24 | s2 >>> 8 | 0xff;
6378      dest[destPos + 2] = s2 << 16 | s3 >>> 16 | 0xff;
6379      dest[destPos + 3] = s3 << 8 | 0xff;
6380    }
6381    for (let j = i * 4, jj = src.length; j < jj; j += 3) {
6382      dest[destPos++] = src[j] << 24 | src[j + 1] << 16 | src[j + 2] << 8 | 0xff;
6383    }
6384  }
6385  return {
6386    srcPos,
6387    destPos
6388  };
6389}
6390function grayToRGBA(src, dest) {
6391  if (FeatureTest.isLittleEndian) {
6392    for (let i = 0, ii = src.length; i < ii; i++) {
6393      dest[i] = src[i] * 0x10101 | 0xff000000;
6394    }
6395  } else {
6396    for (let i = 0, ii = src.length; i < ii; i++) {
6397      dest[i] = src[i] * 0x1010100 | 0x000000ff;
6398    }
6399  }
6400}
6401
6402;// ./src/display/canvas.js
6403
6404
6405
6406
6407const MIN_FONT_SIZE = 16;
6408const MAX_FONT_SIZE = 100;
6409const EXECUTION_TIME = 15;
6410const EXECUTION_STEPS = 10;
6411const MAX_SIZE_TO_COMPILE = 1000;
6412const FULL_CHUNK_HEIGHT = 16;
6413function mirrorContextOperations(ctx, destCtx) {
6414  if (ctx._removeMirroring) {
6415    throw new Error("Context is already forwarding operations.");
6416  }
6417  ctx.__originalSave = ctx.save;
6418  ctx.__originalRestore = ctx.restore;
6419  ctx.__originalRotate = ctx.rotate;
6420  ctx.__originalScale = ctx.scale;
6421  ctx.__originalTranslate = ctx.translate;
6422  ctx.__originalTransform = ctx.transform;
6423  ctx.__originalSetTransform = ctx.setTransform;
6424  ctx.__originalResetTransform = ctx.resetTransform;
6425  ctx.__originalClip = ctx.clip;
6426  ctx.__originalMoveTo = ctx.moveTo;
6427  ctx.__originalLineTo = ctx.lineTo;
6428  ctx.__originalBezierCurveTo = ctx.bezierCurveTo;
6429  ctx.__originalRect = ctx.rect;
6430  ctx.__originalClosePath = ctx.closePath;
6431  ctx.__originalBeginPath = ctx.beginPath;
6432  ctx._removeMirroring = () => {
6433    ctx.save = ctx.__originalSave;
6434    ctx.restore = ctx.__originalRestore;
6435    ctx.rotate = ctx.__originalRotate;
6436    ctx.scale = ctx.__originalScale;
6437    ctx.translate = ctx.__originalTranslate;
6438    ctx.transform = ctx.__originalTransform;
6439    ctx.setTransform = ctx.__originalSetTransform;
6440    ctx.resetTransform = ctx.__originalResetTransform;
6441    ctx.clip = ctx.__originalClip;
6442    ctx.moveTo = ctx.__originalMoveTo;
6443    ctx.lineTo = ctx.__originalLineTo;
6444    ctx.bezierCurveTo = ctx.__originalBezierCurveTo;
6445    ctx.rect = ctx.__originalRect;
6446    ctx.closePath = ctx.__originalClosePath;
6447    ctx.beginPath = ctx.__originalBeginPath;
6448    delete ctx._removeMirroring;
6449  };
6450  ctx.save = function ctxSave() {
6451    destCtx.save();
6452    this.__originalSave();
6453  };
6454  ctx.restore = function ctxRestore() {
6455    destCtx.restore();
6456    this.__originalRestore();
6457  };
6458  ctx.translate = function ctxTranslate(x, y) {
6459    destCtx.translate(x, y);
6460    this.__originalTranslate(x, y);
6461  };
6462  ctx.scale = function ctxScale(x, y) {
6463    destCtx.scale(x, y);
6464    this.__originalScale(x, y);
6465  };
6466  ctx.transform = function ctxTransform(a, b, c, d, e, f) {
6467    destCtx.transform(a, b, c, d, e, f);
6468    this.__originalTransform(a, b, c, d, e, f);
6469  };
6470  ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) {
6471    destCtx.setTransform(a, b, c, d, e, f);
6472    this.__originalSetTransform(a, b, c, d, e, f);
6473  };
6474  ctx.resetTransform = function ctxResetTransform() {
6475    destCtx.resetTransform();
6476    this.__originalResetTransform();
6477  };
6478  ctx.rotate = function ctxRotate(angle) {
6479    destCtx.rotate(angle);
6480    this.__originalRotate(angle);
6481  };
6482  ctx.clip = function ctxRotate(rule) {
6483    destCtx.clip(rule);
6484    this.__originalClip(rule);
6485  };
6486  ctx.moveTo = function (x, y) {
6487    destCtx.moveTo(x, y);
6488    this.__originalMoveTo(x, y);
6489  };
6490  ctx.lineTo = function (x, y) {
6491    destCtx.lineTo(x, y);
6492    this.__originalLineTo(x, y);
6493  };
6494  ctx.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) {
6495    destCtx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
6496    this.__originalBezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
6497  };
6498  ctx.rect = function (x, y, width, height) {
6499    destCtx.rect(x, y, width, height);
6500    this.__originalRect(x, y, width, height);
6501  };
6502  ctx.closePath = function () {
6503    destCtx.closePath();
6504    this.__originalClosePath();
6505  };
6506  ctx.beginPath = function () {
6507    destCtx.beginPath();
6508    this.__originalBeginPath();
6509  };
6510}
6511class CachedCanvases {
6512  constructor(canvasFactory) {
6513    this.canvasFactory = canvasFactory;
6514    this.cache = Object.create(null);
6515  }
6516  getCanvas(id, width, height) {
6517    let canvasEntry;
6518    if (this.cache[id] !== undefined) {
6519      canvasEntry = this.cache[id];
6520      this.canvasFactory.reset(canvasEntry, width, height);
6521    } else {
6522      canvasEntry = this.canvasFactory.create(width, height);
6523      this.cache[id] = canvasEntry;
6524    }
6525    return canvasEntry;
6526  }
6527  delete(id) {
6528    delete this.cache[id];
6529  }
6530  clear() {
6531    for (const id in this.cache) {
6532      const canvasEntry = this.cache[id];
6533      this.canvasFactory.destroy(canvasEntry);
6534      delete this.cache[id];
6535    }
6536  }
6537}
6538function drawImageAtIntegerCoords(ctx, srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH) {
6539  const [a, b, c, d, tx, ty] = getCurrentTransform(ctx);
6540  if (b === 0 && c === 0) {
6541    const tlX = destX * a + tx;
6542    const rTlX = Math.round(tlX);
6543    const tlY = destY * d + ty;
6544    const rTlY = Math.round(tlY);
6545    const brX = (destX + destW) * a + tx;
6546    const rWidth = Math.abs(Math.round(brX) - rTlX) || 1;
6547    const brY = (destY + destH) * d + ty;
6548    const rHeight = Math.abs(Math.round(brY) - rTlY) || 1;
6549    ctx.setTransform(Math.sign(a), 0, 0, Math.sign(d), rTlX, rTlY);
6550    ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rWidth, rHeight);
6551    ctx.setTransform(a, b, c, d, tx, ty);
6552    return [rWidth, rHeight];
6553  }
6554  if (a === 0 && d === 0) {
6555    const tlX = destY * c + tx;
6556    const rTlX = Math.round(tlX);
6557    const tlY = destX * b + ty;
6558    const rTlY = Math.round(tlY);
6559    const brX = (destY + destH) * c + tx;
6560    const rWidth = Math.abs(Math.round(brX) - rTlX) || 1;
6561    const brY = (destX + destW) * b + ty;
6562    const rHeight = Math.abs(Math.round(brY) - rTlY) || 1;
6563    ctx.setTransform(0, Math.sign(b), Math.sign(c), 0, rTlX, rTlY);
6564    ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rHeight, rWidth);
6565    ctx.setTransform(a, b, c, d, tx, ty);
6566    return [rHeight, rWidth];
6567  }
6568  ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH);
6569  const scaleX = Math.hypot(a, b);
6570  const scaleY = Math.hypot(c, d);
6571  return [scaleX * destW, scaleY * destH];
6572}
6573function compileType3Glyph(imgData) {
6574  const {
6575    width,
6576    height
6577  } = imgData;
6578  if (width > MAX_SIZE_TO_COMPILE || height > MAX_SIZE_TO_COMPILE) {
6579    return null;
6580  }
6581  const POINT_TO_PROCESS_LIMIT = 1000;
6582  const POINT_TYPES = new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]);
6583  const width1 = width + 1;
6584  let points = new Uint8Array(width1 * (height + 1));
6585  let i, j, j0;
6586  const lineSize = width + 7 & ~7;
6587  let data = new Uint8Array(lineSize * height),
6588    pos = 0;
6589  for (const elem of imgData.data) {
6590    let mask = 128;
6591    while (mask > 0) {
6592      data[pos++] = elem & mask ? 0 : 255;
6593      mask >>= 1;
6594    }
6595  }
6596  let count = 0;
6597  pos = 0;
6598  if (data[pos] !== 0) {
6599    points[0] = 1;
6600    ++count;
6601  }
6602  for (j = 1; j < width; j++) {
6603    if (data[pos] !== data[pos + 1]) {
6604      points[j] = data[pos] ? 2 : 1;
6605      ++count;
6606    }
6607    pos++;
6608  }
6609  if (data[pos] !== 0) {
6610    points[j] = 2;
6611    ++count;
6612  }
6613  for (i = 1; i < height; i++) {
6614    pos = i * lineSize;
6615    j0 = i * width1;
6616    if (data[pos - lineSize] !== data[pos]) {
6617      points[j0] = data[pos] ? 1 : 8;
6618      ++count;
6619    }
6620    let sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0);
6621    for (j = 1; j < width; j++) {
6622      sum = (sum >> 2) + (data[pos + 1] ? 4 : 0) + (data[pos - lineSize + 1] ? 8 : 0);
6623      if (POINT_TYPES[sum]) {
6624        points[j0 + j] = POINT_TYPES[sum];
6625        ++count;
6626      }
6627      pos++;
6628    }
6629    if (data[pos - lineSize] !== data[pos]) {
6630      points[j0 + j] = data[pos] ? 2 : 4;
6631      ++count;
6632    }
6633    if (count > POINT_TO_PROCESS_LIMIT) {
6634      return null;
6635    }
6636  }
6637  pos = lineSize * (height - 1);
6638  j0 = i * width1;
6639  if (data[pos] !== 0) {
6640    points[j0] = 8;
6641    ++count;
6642  }
6643  for (j = 1; j < width; j++) {
6644    if (data[pos] !== data[pos + 1]) {
6645      points[j0 + j] = data[pos] ? 4 : 8;
6646      ++count;
6647    }
6648    pos++;
6649  }
6650  if (data[pos] !== 0) {
6651    points[j0 + j] = 4;
6652    ++count;
6653  }
6654  if (count > POINT_TO_PROCESS_LIMIT) {
6655    return null;
6656  }
6657  const steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]);
6658  const path = new Path2D();
6659  for (i = 0; count && i <= height; i++) {
6660    let p = i * width1;
6661    const end = p + width;
6662    while (p < end && !points[p]) {
6663      p++;
6664    }
6665    if (p === end) {
6666      continue;
6667    }
6668    path.moveTo(p % width1, i);
6669    const p0 = p;
6670    let type = points[p];
6671    do {
6672      const step = steps[type];
6673      do {
6674        p += step;
6675      } while (!points[p]);
6676      const pp = points[p];
6677      if (pp !== 5 && pp !== 10) {
6678        type = pp;
6679        points[p] = 0;
6680      } else {
6681        type = pp & 0x33 * type >> 4;
6682        points[p] &= type >> 2 | type << 2;
6683      }
6684      path.lineTo(p % width1, p / width1 | 0);
6685      if (!points[p]) {
6686        --count;
6687      }
6688    } while (p0 !== p);
6689    --i;
6690  }
6691  data = null;
6692  points = null;
6693  const drawOutline = function (c) {
6694    c.save();
6695    c.scale(1 / width, -1 / height);
6696    c.translate(0, -height);
6697    c.fill(path);
6698    c.beginPath();
6699    c.restore();
6700  };
6701  return drawOutline;
6702}
6703class CanvasExtraState {
6704  constructor(width, height) {
6705    this.alphaIsShape = false;
6706    this.fontSize = 0;
6707    this.fontSizeScale = 1;
6708    this.textMatrix = IDENTITY_MATRIX;
6709    this.textMatrixScale = 1;
6710    this.fontMatrix = FONT_IDENTITY_MATRIX;
6711    this.leading = 0;
6712    this.x = 0;
6713    this.y = 0;
6714    this.lineX = 0;
6715    this.lineY = 0;
6716    this.charSpacing = 0;
6717    this.wordSpacing = 0;
6718    this.textHScale = 1;
6719    this.textRenderingMode = TextRenderingMode.FILL;
6720    this.textRise = 0;
6721    this.fillColor = "#000000";
6722    this.strokeColor = "#000000";
6723    this.patternFill = false;
6724    this.fillAlpha = 1;
6725    this.strokeAlpha = 1;
6726    this.lineWidth = 1;
6727    this.activeSMask = null;
6728    this.transferMaps = "none";
6729    this.startNewPathAndClipBox([0, 0, width, height]);
6730  }
6731  clone() {
6732    const clone = Object.create(this);
6733    clone.clipBox = this.clipBox.slice();
6734    return clone;
6735  }
6736  setCurrentPoint(x, y) {
6737    this.x = x;
6738    this.y = y;
6739  }
6740  updatePathMinMax(transform, x, y) {
6741    [x, y] = Util.applyTransform([x, y], transform);
6742    this.minX = Math.min(this.minX, x);
6743    this.minY = Math.min(this.minY, y);
6744    this.maxX = Math.max(this.maxX, x);
6745    this.maxY = Math.max(this.maxY, y);
6746  }
6747  updateRectMinMax(transform, rect) {
6748    const p1 = Util.applyTransform(rect, transform);
6749    const p2 = Util.applyTransform(rect.slice(2), transform);
6750    const p3 = Util.applyTransform([rect[0], rect[3]], transform);
6751    const p4 = Util.applyTransform([rect[2], rect[1]], transform);
6752    this.minX = Math.min(this.minX, p1[0], p2[0], p3[0], p4[0]);
6753    this.minY = Math.min(this.minY, p1[1], p2[1], p3[1], p4[1]);
6754    this.maxX = Math.max(this.maxX, p1[0], p2[0], p3[0], p4[0]);
6755    this.maxY = Math.max(this.maxY, p1[1], p2[1], p3[1], p4[1]);
6756  }
6757  updateScalingPathMinMax(transform, minMax) {
6758    Util.scaleMinMax(transform, minMax);
6759    this.minX = Math.min(this.minX, minMax[0]);
6760    this.minY = Math.min(this.minY, minMax[1]);
6761    this.maxX = Math.max(this.maxX, minMax[2]);
6762    this.maxY = Math.max(this.maxY, minMax[3]);
6763  }
6764  updateCurvePathMinMax(transform, x0, y0, x1, y1, x2, y2, x3, y3, minMax) {
6765    const box = Util.bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3, minMax);
6766    if (minMax) {
6767      return;
6768    }
6769    this.updateRectMinMax(transform, box);
6770  }
6771  getPathBoundingBox(pathType = PathType.FILL, transform = null) {
6772    const box = [this.minX, this.minY, this.maxX, this.maxY];
6773    if (pathType === PathType.STROKE) {
6774      if (!transform) {
6775        unreachable("Stroke bounding box must include transform.");
6776      }
6777      const scale = Util.singularValueDecompose2dScale(transform);
6778      const xStrokePad = scale[0] * this.lineWidth / 2;
6779      const yStrokePad = scale[1] * this.lineWidth / 2;
6780      box[0] -= xStrokePad;
6781      box[1] -= yStrokePad;
6782      box[2] += xStrokePad;
6783      box[3] += yStrokePad;
6784    }
6785    return box;
6786  }
6787  updateClipFromPath() {
6788    const intersect = Util.intersect(this.clipBox, this.getPathBoundingBox());
6789    this.startNewPathAndClipBox(intersect || [0, 0, 0, 0]);
6790  }
6791  isEmptyClip() {
6792    return this.minX === Infinity;
6793  }
6794  startNewPathAndClipBox(box) {
6795    this.clipBox = box;
6796    this.minX = Infinity;
6797    this.minY = Infinity;
6798    this.maxX = 0;
6799    this.maxY = 0;
6800  }
6801  getClippedPathBoundingBox(pathType = PathType.FILL, transform = null) {
6802    return Util.intersect(this.clipBox, this.getPathBoundingBox(pathType, transform));
6803  }
6804}
6805function putBinaryImageData(ctx, imgData) {
6806  if (typeof ImageData !== "undefined" && imgData instanceof ImageData) {
6807    ctx.putImageData(imgData, 0, 0);
6808    return;
6809  }
6810  const height = imgData.height,
6811    width = imgData.width;
6812  const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
6813  const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
6814  const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
6815  const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
6816  let srcPos = 0,
6817    destPos;
6818  const src = imgData.data;
6819  const dest = chunkImgData.data;
6820  let i, j, thisChunkHeight, elemsInThisChunk;
6821  if (imgData.kind === util_ImageKind.GRAYSCALE_1BPP) {
6822    const srcLength = src.byteLength;
6823    const dest32 = new Uint32Array(dest.buffer, 0, dest.byteLength >> 2);
6824    const dest32DataLength = dest32.length;
6825    const fullSrcDiff = width + 7 >> 3;
6826    const white = 0xffffffff;
6827    const black = util_FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff;
6828    for (i = 0; i < totalChunks; i++) {
6829      thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight;
6830      destPos = 0;
6831      for (j = 0; j < thisChunkHeight; j++) {
6832        const srcDiff = srcLength - srcPos;
6833        let k = 0;
vendor: 14,515 bytes, lines 6834-7234
6834        const kEnd = srcDiff > fullSrcDiff ? width : srcDiff * 8 - 7;
6835        const kEndUnrolled = kEnd & ~7;
6836        let mask = 0;
6837        let srcByte = 0;
6838        for (; k < kEndUnrolled; k += 8) {
6839          srcByte = src[srcPos++];
6840          dest32[destPos++] = srcByte & 128 ? white : black;
6841          dest32[destPos++] = srcByte & 64 ? white : black;
6842          dest32[destPos++] = srcByte & 32 ? white : black;
6843          dest32[destPos++] = srcByte & 16 ? white : black;
6844          dest32[destPos++] = srcByte & 8 ? white : black;
6845          dest32[destPos++] = srcByte & 4 ? white : black;
6846          dest32[destPos++] = srcByte & 2 ? white : black;
6847          dest32[destPos++] = srcByte & 1 ? white : black;
6848        }
6849        for (; k < kEnd; k++) {
6850          if (mask === 0) {
6851            srcByte = src[srcPos++];
6852            mask = 128;
6853          }
6854          dest32[destPos++] = srcByte & mask ? white : black;
6855          mask >>= 1;
6856        }
6857      }
6858      while (destPos < dest32DataLength) {
6859        dest32[destPos++] = 0;
6860      }
6861      ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
6862    }
6863  } else if (imgData.kind === util_ImageKind.RGBA_32BPP) {
6864    j = 0;
6865    elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4;
6866    for (i = 0; i < fullChunks; i++) {
6867      dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
6868      srcPos += elemsInThisChunk;
6869      ctx.putImageData(chunkImgData, 0, j);
6870      j += FULL_CHUNK_HEIGHT;
6871    }
6872    if (i < totalChunks) {
6873      elemsInThisChunk = width * partialChunkHeight * 4;
6874      dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
6875      ctx.putImageData(chunkImgData, 0, j);
6876    }
6877  } else if (imgData.kind === util_ImageKind.RGB_24BPP) {
6878    thisChunkHeight = FULL_CHUNK_HEIGHT;
6879    elemsInThisChunk = width * thisChunkHeight;
6880    for (i = 0; i < totalChunks; i++) {
6881      if (i >= fullChunks) {
6882        thisChunkHeight = partialChunkHeight;
6883        elemsInThisChunk = width * thisChunkHeight;
6884      }
6885      destPos = 0;
6886      for (j = elemsInThisChunk; j--;) {
6887        dest[destPos++] = src[srcPos++];
6888        dest[destPos++] = src[srcPos++];
6889        dest[destPos++] = src[srcPos++];
6890        dest[destPos++] = 255;
6891      }
6892      ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
6893    }
6894  } else {
6895    throw new Error(`bad image kind: ${imgData.kind}`);
6896  }
6897}
6898function putBinaryImageMask(ctx, imgData) {
6899  if (imgData.bitmap) {
6900    ctx.drawImage(imgData.bitmap, 0, 0);
6901    return;
6902  }
6903  const height = imgData.height,
6904    width = imgData.width;
6905  const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
6906  const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
6907  const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
6908  const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
6909  let srcPos = 0;
6910  const src = imgData.data;
6911  const dest = chunkImgData.data;
6912  for (let i = 0; i < totalChunks; i++) {
6913    const thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight;
6914    ({
6915      srcPos
6916    } = convertBlackAndWhiteToRGBA({
6917      src,
6918      srcPos,
6919      dest,
6920      width,
6921      height: thisChunkHeight,
6922      nonBlackColor: 0
6923    }));
6924    ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
6925  }
6926}
6927function copyCtxState(sourceCtx, destCtx) {
6928  const properties = ["strokeStyle", "fillStyle", "fillRule", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "globalCompositeOperation", "font", "filter"];
6929  for (const property of properties) {
6930    if (sourceCtx[property] !== undefined) {
6931      destCtx[property] = sourceCtx[property];
6932    }
6933  }
6934  if (sourceCtx.setLineDash !== undefined) {
6935    destCtx.setLineDash(sourceCtx.getLineDash());
6936    destCtx.lineDashOffset = sourceCtx.lineDashOffset;
6937  }
6938}
6939function resetCtxToDefault(ctx) {
6940  ctx.strokeStyle = ctx.fillStyle = "#000000";
6941  ctx.fillRule = "nonzero";
6942  ctx.globalAlpha = 1;
6943  ctx.lineWidth = 1;
6944  ctx.lineCap = "butt";
6945  ctx.lineJoin = "miter";
6946  ctx.miterLimit = 10;
6947  ctx.globalCompositeOperation = "source-over";
6948  ctx.font = "10px sans-serif";
6949  if (ctx.setLineDash !== undefined) {
6950    ctx.setLineDash([]);
6951    ctx.lineDashOffset = 0;
6952  }
6953  if (!isNodeJS) {
6954    const {
6955      filter
6956    } = ctx;
6957    if (filter !== "none" && filter !== "") {
6958      ctx.filter = "none";
6959    }
6960  }
6961}
6962function getImageSmoothingEnabled(transform, interpolate) {
6963  if (interpolate) {
6964    return true;
6965  }
6966  const scale = Util.singularValueDecompose2dScale(transform);
6967  scale[0] = Math.fround(scale[0]);
6968  scale[1] = Math.fround(scale[1]);
6969  const actualScale = Math.fround((globalThis.devicePixelRatio || 1) * PixelsPerInch.PDF_TO_CSS_UNITS);
6970  return scale[0] <= actualScale && scale[1] <= actualScale;
6971}
6972const LINE_CAP_STYLES = ["butt", "round", "square"];
6973const LINE_JOIN_STYLES = ["miter", "round", "bevel"];
6974const NORMAL_CLIP = {};
6975const EO_CLIP = {};
6976class CanvasGraphics {
6977  constructor(canvasCtx, commonObjs, objs, canvasFactory, filterFactory, {
6978    optionalContentConfig,
6979    markedContentStack = null
6980  }, annotationCanvasMap, pageColors) {
6981    this.ctx = canvasCtx;
6982    this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height);
6983    this.stateStack = [];
6984    this.pendingClip = null;
6985    this.pendingEOFill = false;
6986    this.res = null;
6987    this.xobjs = null;
6988    this.commonObjs = commonObjs;
6989    this.objs = objs;
6990    this.canvasFactory = canvasFactory;
6991    this.filterFactory = filterFactory;
6992    this.groupStack = [];
6993    this.processingType3 = null;
6994    this.baseTransform = null;
6995    this.baseTransformStack = [];
6996    this.groupLevel = 0;
6997    this.smaskStack = [];
6998    this.smaskCounter = 0;
6999    this.tempSMask = null;
7000    this.suspendedCtx = null;
7001    this.contentVisible = true;
7002    this.markedContentStack = markedContentStack || [];
7003    this.optionalContentConfig = optionalContentConfig;
7004    this.cachedCanvases = new CachedCanvases(this.canvasFactory);
7005    this.cachedPatterns = new Map();
7006    this.annotationCanvasMap = annotationCanvasMap;
7007    this.viewportScale = 1;
7008    this.outputScaleX = 1;
7009    this.outputScaleY = 1;
7010    this.pageColors = pageColors;
7011    this._cachedScaleForStroking = [-1, 0];
7012    this._cachedGetSinglePixelWidth = null;
7013    this._cachedBitmapsMap = new Map();
7014  }
7015  getObject(data, fallback = null) {
7016    if (typeof data === "string") {
7017      return data.startsWith("g_") ? this.commonObjs.get(data) : this.objs.get(data);
7018    }
7019    return fallback;
7020  }
7021  beginDrawing({
7022    transform,
7023    viewport,
7024    transparency = false,
7025    background = null
7026  }) {
7027    const width = this.ctx.canvas.width;
7028    const height = this.ctx.canvas.height;
7029    const savedFillStyle = this.ctx.fillStyle;
7030    this.ctx.fillStyle = background || "#ffffff";
7031    this.ctx.fillRect(0, 0, width, height);
7032    this.ctx.fillStyle = savedFillStyle;
7033    if (transparency) {
7034      const transparentCanvas = this.cachedCanvases.getCanvas("transparent", width, height);
7035      this.compositeCtx = this.ctx;
7036      this.transparentCanvas = transparentCanvas.canvas;
7037      this.ctx = transparentCanvas.context;
7038      this.ctx.save();
7039      this.ctx.transform(...getCurrentTransform(this.compositeCtx));
7040    }
7041    this.ctx.save();
7042    resetCtxToDefault(this.ctx);
7043    if (transform) {
7044      this.ctx.transform(...transform);
7045      this.outputScaleX = transform[0];
7046      this.outputScaleY = transform[0];
7047    }
7048    this.ctx.transform(...viewport.transform);
7049    this.viewportScale = viewport.scale;
7050    this.baseTransform = getCurrentTransform(this.ctx);
7051  }
7052  executeOperatorList(operatorList, executionStartIdx, continueCallback, stepper) {
7053    const argsArray = operatorList.argsArray;
7054    const fnArray = operatorList.fnArray;
7055    let i = executionStartIdx || 0;
7056    const argsArrayLen = argsArray.length;
7057    if (argsArrayLen === i) {
7058      return i;
7059    }
7060    const chunkOperations = argsArrayLen - i > EXECUTION_STEPS && typeof continueCallback === "function";
7061    const endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;
7062    let steps = 0;
7063    const commonObjs = this.commonObjs;
7064    const objs = this.objs;
7065    let fnId;
7066    while (true) {
7067      if (stepper !== undefined && i === stepper.nextBreakPoint) {
7068        stepper.breakIt(i, continueCallback);
7069        return i;
7070      }
7071      fnId = fnArray[i];
7072      if (fnId !== OPS.dependency) {
7073        this[fnId].apply(this, argsArray[i]);
7074      } else {
7075        for (const depObjId of argsArray[i]) {
7076          const objsPool = depObjId.startsWith("g_") ? commonObjs : objs;
7077          if (!objsPool.has(depObjId)) {
7078            objsPool.get(depObjId, continueCallback);
7079            return i;
7080          }
7081        }
7082      }
7083      i++;
7084      if (i === argsArrayLen) {
7085        return i;
7086      }
7087      if (chunkOperations && ++steps > EXECUTION_STEPS) {
7088        if (Date.now() > endTime) {
7089          continueCallback();
7090          return i;
7091        }
7092        steps = 0;
7093      }
7094    }
7095  }
7096  #restoreInitialState() {
7097    while (this.stateStack.length || this.inSMaskMode) {
7098      this.restore();
7099    }
7100    this.current.activeSMask = null;
7101    this.ctx.restore();
7102    if (this.transparentCanvas) {
7103      this.ctx = this.compositeCtx;
7104      this.ctx.save();
7105      this.ctx.setTransform(1, 0, 0, 1, 0, 0);
7106      this.ctx.drawImage(this.transparentCanvas, 0, 0);
7107      this.ctx.restore();
7108      this.transparentCanvas = null;
7109    }
7110  }
7111  endDrawing() {
7112    this.#restoreInitialState();
7113    this.cachedCanvases.clear();
7114    this.cachedPatterns.clear();
7115    for (const cache of this._cachedBitmapsMap.values()) {
7116      for (const canvas of cache.values()) {
7117        if (typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement) {
7118          canvas.width = canvas.height = 0;
7119        }
7120      }
7121      cache.clear();
7122    }
7123    this._cachedBitmapsMap.clear();
7124    this.#drawFilter();
7125  }
7126  #drawFilter() {
7127    if (this.pageColors) {
7128      const hcmFilterId = this.filterFactory.addHCMFilter(this.pageColors.foreground, this.pageColors.background);
7129      if (hcmFilterId !== "none") {
7130        const savedFilter = this.ctx.filter;
7131        this.ctx.filter = hcmFilterId;
7132        this.ctx.drawImage(this.ctx.canvas, 0, 0);
7133        this.ctx.filter = savedFilter;
7134      }
7135    }
7136  }
7137  _scaleImage(img, inverseTransform) {
7138    const width = img.width ?? img.displayWidth;
7139    const height = img.height ?? img.displayHeight;
7140    let widthScale = Math.max(Math.hypot(inverseTransform[0], inverseTransform[1]), 1);
7141    let heightScale = Math.max(Math.hypot(inverseTransform[2], inverseTransform[3]), 1);
7142    let paintWidth = width,
7143      paintHeight = height;
7144    let tmpCanvasId = "prescale1";
7145    let tmpCanvas, tmpCtx;
7146    while (widthScale > 2 && paintWidth > 1 || heightScale > 2 && paintHeight > 1) {
7147      let newWidth = paintWidth,
7148        newHeight = paintHeight;
7149      if (widthScale > 2 && paintWidth > 1) {
7150        newWidth = paintWidth >= 16384 ? Math.floor(paintWidth / 2) - 1 || 1 : Math.ceil(paintWidth / 2);
7151        widthScale /= paintWidth / newWidth;
7152      }
7153      if (heightScale > 2 && paintHeight > 1) {
7154        newHeight = paintHeight >= 16384 ? Math.floor(paintHeight / 2) - 1 || 1 : Math.ceil(paintHeight) / 2;
7155        heightScale /= paintHeight / newHeight;
7156      }
7157      tmpCanvas = this.cachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight);
7158      tmpCtx = tmpCanvas.context;
7159      tmpCtx.clearRect(0, 0, newWidth, newHeight);
7160      tmpCtx.drawImage(img, 0, 0, paintWidth, paintHeight, 0, 0, newWidth, newHeight);
7161      img = tmpCanvas.canvas;
7162      paintWidth = newWidth;
7163      paintHeight = newHeight;
7164      tmpCanvasId = tmpCanvasId === "prescale1" ? "prescale2" : "prescale1";
7165    }
7166    return {
7167      img,
7168      paintWidth,
7169      paintHeight
7170    };
7171  }
7172  _createMaskCanvas(img) {
7173    const ctx = this.ctx;
7174    const {
7175      width,
7176      height
7177    } = img;
7178    const fillColor = this.current.fillColor;
7179    const isPatternFill = this.current.patternFill;
7180    const currentTransform = getCurrentTransform(ctx);
7181    let cache, cacheKey, scaled, maskCanvas;
7182    if ((img.bitmap || img.data) && img.count > 1) {
7183      const mainKey = img.bitmap || img.data.buffer;
7184      cacheKey = JSON.stringify(isPatternFill ? currentTransform : [currentTransform.slice(0, 4), fillColor]);
7185      cache = this._cachedBitmapsMap.get(mainKey);
7186      if (!cache) {
7187        cache = new Map();
7188        this._cachedBitmapsMap.set(mainKey, cache);
7189      }
7190      const cachedImage = cache.get(cacheKey);
7191      if (cachedImage && !isPatternFill) {
7192        const offsetX = Math.round(Math.min(currentTransform[0], currentTransform[2]) + currentTransform[4]);
7193        const offsetY = Math.round(Math.min(currentTransform[1], currentTransform[3]) + currentTransform[5]);
7194        return {
7195          canvas: cachedImage,
7196          offsetX,
7197          offsetY
7198        };
7199      }
7200      scaled = cachedImage;
7201    }
7202    if (!scaled) {
7203      maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
7204      putBinaryImageMask(maskCanvas.context, img);
7205    }
7206    let maskToCanvas = Util.transform(currentTransform, [1 / width, 0, 0, -1 / height, 0, 0]);
7207    maskToCanvas = Util.transform(maskToCanvas, [1, 0, 0, 1, 0, -height]);
7208    const [minX, minY, maxX, maxY] = Util.getAxialAlignedBoundingBox([0, 0, width, height], maskToCanvas);
7209    const drawnWidth = Math.round(maxX - minX) || 1;
7210    const drawnHeight = Math.round(maxY - minY) || 1;
7211    const fillCanvas = this.cachedCanvases.getCanvas("fillCanvas", drawnWidth, drawnHeight);
7212    const fillCtx = fillCanvas.context;
7213    const offsetX = minX;
7214    const offsetY = minY;
7215    fillCtx.translate(-offsetX, -offsetY);
7216    fillCtx.transform(...maskToCanvas);
7217    if (!scaled) {
7218      scaled = this._scaleImage(maskCanvas.canvas, getCurrentTransformInverse(fillCtx));
7219      scaled = scaled.img;
7220      if (cache && isPatternFill) {
7221        cache.set(cacheKey, scaled);
7222      }
7223    }
7224    fillCtx.imageSmoothingEnabled = getImageSmoothingEnabled(getCurrentTransform(fillCtx), img.interpolate);
7225    drawImageAtIntegerCoords(fillCtx, scaled, 0, 0, scaled.width, scaled.height, 0, 0, width, height);
7226    fillCtx.globalCompositeOperation = "source-in";
7227    const inverse = Util.transform(getCurrentTransformInverse(fillCtx), [1, 0, 0, 1, -offsetX, -offsetY]);
7228    fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx, this, inverse, PathType.FILL) : fillColor;
7229    fillCtx.fillRect(0, 0, width, height);
7230    if (cache && !isPatternFill) {
7231      this.cachedCanvases.delete("fillCanvas");
7232      cache.set(cacheKey, fillCanvas.canvas);
7233    }
7234    return {
7235      canvas: fillCanvas.canvas,
7236      offsetX: Math.round(offsetX),
7237      offsetY: Math.round(offsetY)
7238    };
7239  }
7240  setLineWidth(width) {
7241    if (width !== this.current.lineWidth) {
7242      this._cachedScaleForStroking[0] = -1;
7243    }
7244    this.current.lineWidth = width;
7245    this.ctx.lineWidth = width;
7246  }
7247  setLineCap(style) {
7248    this.ctx.lineCap = LINE_CAP_STYLES[style];
7249  }
7250  setLineJoin(style) {
7251    this.ctx.lineJoin = LINE_JOIN_STYLES[style];
7252  }
7253  setMiterLimit(limit) {
7254    this.ctx.miterLimit = limit;
7255  }
7256  setDash(dashArray, dashPhase) {
7257    const ctx = this.ctx;
7258    if (ctx.setLineDash !== undefined) {
7259      ctx.setLineDash(dashArray);
7260      ctx.lineDashOffset = dashPhase;
7261    }
7262  }
7263  setRenderingIntent(intent) {}
7264  setFlatness(flatness) {}
7265  setGState(states) {
7266    for (const [key, value] of states) {
7267      switch (key) {
7268        case "LW":
7269          this.setLineWidth(value);
7270          break;
7271        case "LC":
7272          this.setLineCap(value);
7273          break;
7274        case "LJ":
7275          this.setLineJoin(value);
7276          break;
7277        case "ML":
7278          this.setMiterLimit(value);
7279          break;
7280        case "D":
7281          this.setDash(value[0], value[1]);
7282          break;
7283        case "RI":
7284          this.setRenderingIntent(value);
7285          break;
7286        case "FL":
7287          this.setFlatness(value);
7288          break;
7289        case "Font":
7290          this.setFont(value[0], value[1]);
7291          break;
7292        case "CA":
7293          this.current.strokeAlpha = value;
7294          break;
7295        case "ca":
7296          this.current.fillAlpha = value;
7297          this.ctx.globalAlpha = value;
7298          break;
7299        case "BM":
7300          this.ctx.globalCompositeOperation = value;
7301          break;
7302        case "SMask":
7303          this.current.activeSMask = value ? this.tempSMask : null;
7304          this.tempSMask = null;
7305          this.checkSMaskState();
7306          break;
7307        case "TR":
7308          this.ctx.filter = this.current.transferMaps = this.filterFactory.addFilter(value);
7309          break;
7310      }
7311    }
7312  }
7313  get inSMaskMode() {
7314    return !!this.suspendedCtx;
7315  }
7316  checkSMaskState() {
7317    const inSMaskMode = this.inSMaskMode;
7318    if (this.current.activeSMask && !inSMaskMode) {
7319      this.beginSMaskMode();
7320    } else if (!this.current.activeSMask && inSMaskMode) {
7321      this.endSMaskMode();
7322    }
7323  }
7324  beginSMaskMode() {
7325    if (this.inSMaskMode) {
7326      throw new Error("beginSMaskMode called while already in smask mode");
7327    }
7328    const drawnWidth = this.ctx.canvas.width;
7329    const drawnHeight = this.ctx.canvas.height;
7330    const cacheId = "smaskGroupAt" + this.groupLevel;
7331    const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight);
7332    this.suspendedCtx = this.ctx;
7333    this.ctx = scratchCanvas.context;
7334    const ctx = this.ctx;
7335    ctx.setTransform(...getCurrentTransform(this.suspendedCtx));
7336    copyCtxState(this.suspendedCtx, ctx);
7337    mirrorContextOperations(ctx, this.suspendedCtx);
7338    this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
7339  }
7340  endSMaskMode() {
7341    if (!this.inSMaskMode) {
7342      throw new Error("endSMaskMode called while not in smask mode");
7343    }
7344    this.ctx._removeMirroring();
7345    copyCtxState(this.ctx, this.suspendedCtx);
7346    this.ctx = this.suspendedCtx;
7347    this.suspendedCtx = null;
7348  }
7349  compose(dirtyBox) {
7350    if (!this.current.activeSMask) {
7351      return;
7352    }
7353    if (!dirtyBox) {
7354      dirtyBox = [0, 0, this.ctx.canvas.width, this.ctx.canvas.height];
7355    } else {
7356      dirtyBox[0] = Math.floor(dirtyBox[0]);
7357      dirtyBox[1] = Math.floor(dirtyBox[1]);
7358      dirtyBox[2] = Math.ceil(dirtyBox[2]);
7359      dirtyBox[3] = Math.ceil(dirtyBox[3]);
7360    }
7361    const smask = this.current.activeSMask;
7362    const suspendedCtx = this.suspendedCtx;
7363    this.composeSMask(suspendedCtx, smask, this.ctx, dirtyBox);
7364    this.ctx.save();
7365    this.ctx.setTransform(1, 0, 0, 1, 0, 0);
7366    this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
7367    this.ctx.restore();
7368  }
7369  composeSMask(ctx, smask, layerCtx, layerBox) {
7370    const layerOffsetX = layerBox[0];
7371    const layerOffsetY = layerBox[1];
7372    const layerWidth = layerBox[2] - layerOffsetX;
7373    const layerHeight = layerBox[3] - layerOffsetY;
7374    if (layerWidth === 0 || layerHeight === 0) {
7375      return;
7376    }
7377    this.genericComposeSMask(smask.context, layerCtx, layerWidth, layerHeight, smask.subtype, smask.backdrop, smask.transferMap, layerOffsetX, layerOffsetY, smask.offsetX, smask.offsetY);
7378    ctx.save();
7379    ctx.globalAlpha = 1;
7380    ctx.globalCompositeOperation = "source-over";
7381    ctx.setTransform(1, 0, 0, 1, 0, 0);
7382    ctx.drawImage(layerCtx.canvas, 0, 0);
7383    ctx.restore();
7384  }
7385  genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop, transferMap, layerOffsetX, layerOffsetY, maskOffsetX, maskOffsetY) {
7386    let maskCanvas = maskCtx.canvas;
7387    let maskX = layerOffsetX - maskOffsetX;
7388    let maskY = layerOffsetY - maskOffsetY;
7389    if (backdrop) {
7390      const backdropRGB = Util.makeHexColor(...backdrop);
7391      if (maskX < 0 || maskY < 0 || maskX + width > maskCanvas.width || maskY + height > maskCanvas.height) {
7392        const canvas = this.cachedCanvases.getCanvas("maskExtension", width, height);
7393        const ctx = canvas.context;
7394        ctx.drawImage(maskCanvas, -maskX, -maskY);
7395        ctx.globalCompositeOperation = "destination-atop";
7396        ctx.fillStyle = backdropRGB;
7397        ctx.fillRect(0, 0, width, height);
7398        ctx.globalCompositeOperation = "source-over";
7399        maskCanvas = canvas.canvas;
7400        maskX = maskY = 0;
7401      } else {
7402        maskCtx.save();
7403        maskCtx.globalAlpha = 1;
7404        maskCtx.setTransform(1, 0, 0, 1, 0, 0);
7405        const clip = new Path2D();
7406        clip.rect(maskX, maskY, width, height);
7407        maskCtx.clip(clip);
7408        maskCtx.globalCompositeOperation = "destination-atop";
7409        maskCtx.fillStyle = backdropRGB;
7410        maskCtx.fillRect(maskX, maskY, width, height);
7411        maskCtx.restore();
7412      }
7413    }
7414    layerCtx.save();
7415    layerCtx.globalAlpha = 1;
7416    layerCtx.setTransform(1, 0, 0, 1, 0, 0);
7417    if (subtype === "Alpha" && transferMap) {
7418      layerCtx.filter = this.filterFactory.addAlphaFilter(transferMap);
7419    } else if (subtype === "Luminosity") {
7420      layerCtx.filter = this.filterFactory.addLuminosityFilter(transferMap);
7421    }
7422    const clip = new Path2D();
7423    clip.rect(layerOffsetX, layerOffsetY, width, height);
7424    layerCtx.clip(clip);
7425    layerCtx.globalCompositeOperation = "destination-in";
7426    layerCtx.drawImage(maskCanvas, maskX, maskY, width, height, layerOffsetX, layerOffsetY, width, height);
7427    layerCtx.restore();
7428  }
7429  save() {
7430    if (this.inSMaskMode) {
7431      copyCtxState(this.ctx, this.suspendedCtx);
7432      this.suspendedCtx.save();
7433    } else {
7434      this.ctx.save();
7435    }
7436    const old = this.current;
7437    this.stateStack.push(old);
7438    this.current = old.clone();
7439  }
7440  restore() {
7441    if (this.stateStack.length === 0 && this.inSMaskMode) {
7442      this.endSMaskMode();
7443    }
7444    if (this.stateStack.length !== 0) {
7445      this.current = this.stateStack.pop();
7446      if (this.inSMaskMode) {
7447        this.suspendedCtx.restore();
7448        copyCtxState(this.suspendedCtx, this.ctx);
7449      } else {
7450        this.ctx.restore();
7451      }
7452      this.checkSMaskState();
7453      this.pendingClip = null;
7454      this._cachedScaleForStroking[0] = -1;
7455      this._cachedGetSinglePixelWidth = null;
7456    }
7457  }
7458  transform(a, b, c, d, e, f) {
7459    this.ctx.transform(a, b, c, d, e, f);
7460    this._cachedScaleForStroking[0] = -1;
7461    this._cachedGetSinglePixelWidth = null;
7462  }
7463  constructPath(ops, args, minMax) {
7464    const ctx = this.ctx;
7465    const current = this.current;
7466    let x = current.x,
7467      y = current.y;
7468    let startX, startY;
7469    const currentTransform = getCurrentTransform(ctx);
7470    const isScalingMatrix = currentTransform[0] === 0 && currentTransform[3] === 0 || currentTransform[1] === 0 && currentTransform[2] === 0;
7471    const minMaxForBezier = isScalingMatrix ? minMax.slice(0) : null;
7472    for (let i = 0, j = 0, ii = ops.length; i < ii; i++) {
7473      switch (ops[i] | 0) {
7474        case OPS.rectangle:
7475          x = args[j++];
7476          y = args[j++];
7477          const width = args[j++];
7478          const height = args[j++];
7479          const xw = x + width;
7480          const yh = y + height;
7481          ctx.moveTo(x, y);
7482          if (width === 0 || height === 0) {
7483            ctx.lineTo(xw, yh);
7484          } else {
7485            ctx.lineTo(xw, y);
7486            ctx.lineTo(xw, yh);
7487            ctx.lineTo(x, yh);
7488          }
7489          if (!isScalingMatrix) {
7490            current.updateRectMinMax(currentTransform, [x, y, xw, yh]);
7491          }
7492          ctx.closePath();
7493          break;
7494        case OPS.moveTo:
7495          x = args[j++];
7496          y = args[j++];
7497          ctx.moveTo(x, y);
7498          if (!isScalingMatrix) {
7499            current.updatePathMinMax(currentTransform, x, y);
7500          }
7501          break;
7502        case OPS.lineTo:
7503          x = args[j++];
7504          y = args[j++];
7505          ctx.lineTo(x, y);
7506          if (!isScalingMatrix) {
7507            current.updatePathMinMax(currentTransform, x, y);
7508          }
7509          break;
7510        case OPS.curveTo:
7511          startX = x;
7512          startY = y;
7513          x = args[j + 4];
7514          y = args[j + 5];
7515          ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y);
7516          current.updateCurvePathMinMax(currentTransform, startX, startY, args[j], args[j + 1], args[j + 2], args[j + 3], x, y, minMaxForBezier);
7517          j += 6;
7518          break;
7519        case OPS.curveTo2:
7520          startX = x;
7521          startY = y;
7522          ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]);
7523          current.updateCurvePathMinMax(currentTransform, startX, startY, x, y, args[j], args[j + 1], args[j + 2], args[j + 3], minMaxForBezier);
7524          x = args[j + 2];
7525          y = args[j + 3];
7526          j += 4;
7527          break;
7528        case OPS.curveTo3:
7529          startX = x;
7530          startY = y;
7531          x = args[j + 2];
7532          y = args[j + 3];
7533          ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
7534          current.updateCurvePathMinMax(currentTransform, startX, startY, args[j], args[j + 1], x, y, x, y, minMaxForBezier);
7535          j += 4;
7536          break;
7537        case OPS.closePath:
7538          ctx.closePath();
7539          break;
7540      }
7541    }
7542    if (isScalingMatrix) {
7543      current.updateScalingPathMinMax(currentTransform, minMaxForBezier);
7544    }
7545    current.setCurrentPoint(x, y);
7546  }
7547  closePath() {
7548    this.ctx.closePath();
7549  }
7550  stroke(consumePath = true) {
7551    const ctx = this.ctx;
7552    const strokeColor = this.current.strokeColor;
7553    ctx.globalAlpha = this.current.strokeAlpha;
7554    if (this.contentVisible) {
7555      if (typeof strokeColor === "object" && strokeColor?.getPattern) {
7556        ctx.save();
7557        ctx.strokeStyle = strokeColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.STROKE);
7558        this.rescaleAndStroke(false);
7559        ctx.restore();
7560      } else {
7561        this.rescaleAndStroke(true);
7562      }
7563    }
7564    if (consumePath) {
7565      this.consumePath(this.current.getClippedPathBoundingBox());
7566    }
7567    ctx.globalAlpha = this.current.fillAlpha;
7568  }
7569  closeStroke() {
7570    this.closePath();
7571    this.stroke();
7572  }
7573  fill(consumePath = true) {
7574    const ctx = this.ctx;
7575    const fillColor = this.current.fillColor;
7576    const isPatternFill = this.current.patternFill;
7577    let needRestore = false;
7578    if (isPatternFill) {
7579      ctx.save();
7580      ctx.fillStyle = fillColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.FILL);
7581      needRestore = true;
7582    }
7583    const intersect = this.current.getClippedPathBoundingBox();
7584    if (this.contentVisible && intersect !== null) {
7585      if (this.pendingEOFill) {
7586        ctx.fill("evenodd");
7587        this.pendingEOFill = false;
7588      } else {
7589        ctx.fill();
7590      }
7591    }
7592    if (needRestore) {
7593      ctx.restore();
7594    }
7595    if (consumePath) {
7596      this.consumePath(intersect);
7597    }
7598  }
7599  eoFill() {
7600    this.pendingEOFill = true;
7601    this.fill();
7602  }
7603  fillStroke() {
7604    this.fill(false);
7605    this.stroke(false);
7606    this.consumePath();
7607  }
7608  eoFillStroke() {
7609    this.pendingEOFill = true;
7610    this.fillStroke();
7611  }
7612  closeFillStroke() {
7613    this.closePath();
7614    this.fillStroke();
7615  }
7616  closeEOFillStroke() {
7617    this.pendingEOFill = true;
7618    this.closePath();
7619    this.fillStroke();
7620  }
7621  endPath() {
7622    this.consumePath();
7623  }
7624  clip() {
7625    this.pendingClip = NORMAL_CLIP;
7626  }
7627  eoClip() {
7628    this.pendingClip = EO_CLIP;
7629  }
7630  beginText() {
7631    this.current.textMatrix = IDENTITY_MATRIX;
7632    this.current.textMatrixScale = 1;
7633    this.current.x = this.current.lineX = 0;
7634    this.current.y = this.current.lineY = 0;
7635  }
7636  endText() {
7637    const paths = this.pendingTextPaths;
7638    const ctx = this.ctx;
7639    if (paths === undefined) {
7640      ctx.beginPath();
7641      return;
7642    }
7643    ctx.save();
7644    ctx.beginPath();
7645    for (const path of paths) {
7646      ctx.setTransform(...path.transform);
7647      ctx.translate(path.x, path.y);
7648      path.addToPath(ctx, path.fontSize);
7649    }
7650    ctx.restore();
7651    ctx.clip();
7652    ctx.beginPath();
7653    delete this.pendingTextPaths;
7654  }
7655  setCharSpacing(spacing) {
7656    this.current.charSpacing = spacing;
7657  }
7658  setWordSpacing(spacing) {
7659    this.current.wordSpacing = spacing;
7660  }
7661  setHScale(scale) {
7662    this.current.textHScale = scale / 100;
7663  }
7664  setLeading(leading) {
7665    this.current.leading = -leading;
7666  }
7667  setFont(fontRefName, size) {
7668    const fontObj = this.commonObjs.get(fontRefName);
7669    const current = this.current;
7670    if (!fontObj) {
7671      throw new Error(`Can't find font for ${fontRefName}`);
7672    }
7673    current.fontMatrix = fontObj.fontMatrix || FONT_IDENTITY_MATRIX;
7674    if (current.fontMatrix[0] === 0 || current.fontMatrix[3] === 0) {
7675      warn("Invalid font matrix for font " + fontRefName);
7676    }
7677    if (size < 0) {
7678      size = -size;
7679      current.fontDirection = -1;
7680    } else {
7681      current.fontDirection = 1;
7682    }
7683    this.current.font = fontObj;
7684    this.current.fontSize = size;
7685    if (fontObj.isType3Font) {
7686      return;
7687    }
7688    const name = fontObj.loadedName || "sans-serif";
7689    const typeface = fontObj.systemFontInfo?.css || `"${name}", ${fontObj.fallbackName}`;
7690    let bold = "normal";
7691    if (fontObj.black) {
7692      bold = "900";
7693    } else if (fontObj.bold) {
7694      bold = "bold";
7695    }
7696    const italic = fontObj.italic ? "italic" : "normal";
7697    let browserFontSize = size;
7698    if (size < MIN_FONT_SIZE) {
7699      browserFontSize = MIN_FONT_SIZE;
7700    } else if (size > MAX_FONT_SIZE) {
7701      browserFontSize = MAX_FONT_SIZE;
7702    }
7703    this.current.fontSizeScale = size / browserFontSize;
7704    this.ctx.font = `${italic} ${bold} ${browserFontSize}px ${typeface}`;
7705  }
7706  setTextRenderingMode(mode) {
7707    this.current.textRenderingMode = mode;
7708  }
7709  setTextRise(rise) {
7710    this.current.textRise = rise;
7711  }
7712  moveText(x, y) {
7713    this.current.x = this.current.lineX += x;
7714    this.current.y = this.current.lineY += y;
7715  }
7716  setLeadingMoveText(x, y) {
7717    this.setLeading(-y);
7718    this.moveText(x, y);
7719  }
7720  setTextMatrix(a, b, c, d, e, f) {
7721    this.current.textMatrix = [a, b, c, d, e, f];
7722    this.current.textMatrixScale = Math.hypot(a, b);
7723    this.current.x = this.current.lineX = 0;
7724    this.current.y = this.current.lineY = 0;
7725  }
7726  nextLine() {
7727    this.moveText(0, this.current.leading);
7728  }
7729  paintChar(character, x, y, patternTransform) {
7730    const ctx = this.ctx;
7731    const current = this.current;
7732    const font = current.font;
7733    const textRenderingMode = current.textRenderingMode;
7734    const fontSize = current.fontSize / current.fontSizeScale;
7735    const fillStrokeMode = textRenderingMode & TextRenderingMode.FILL_STROKE_MASK;
7736    const isAddToPathSet = !!(textRenderingMode & TextRenderingMode.ADD_TO_PATH_FLAG);
7737    const patternFill = current.patternFill && !font.missingFile;
7738    let addToPath;
7739    if (font.disableFontFace || isAddToPathSet || patternFill) {
7740      addToPath = font.getPathGenerator(this.commonObjs, character);
7741    }
7742    if (font.disableFontFace || patternFill) {
7743      ctx.save();
7744      ctx.translate(x, y);
7745      ctx.beginPath();
7746      addToPath(ctx, fontSize);
7747      if (patternTransform) {
7748        ctx.setTransform(...patternTransform);
7749      }
7750      if (fillStrokeMode === TextRenderingMode.FILL || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
7751        ctx.fill();
7752      }
7753      if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
7754        ctx.stroke();
7755      }
vendor: 3,502 bytes, lines 7756-7861
7756      ctx.restore();
7757    } else {
7758      if (fillStrokeMode === TextRenderingMode.FILL || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
7759        ctx.fillText(character, x, y);
7760      }
7761      if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
7762        ctx.strokeText(character, x, y);
7763      }
7764    }
7765    if (isAddToPathSet) {
7766      const paths = this.pendingTextPaths ||= [];
7767      paths.push({
7768        transform: getCurrentTransform(ctx),
7769        x,
7770        y,
7771        fontSize,
7772        addToPath
7773      });
7774    }
7775  }
7776  get isFontSubpixelAAEnabled() {
7777    const {
7778      context: ctx
7779    } = this.cachedCanvases.getCanvas("isFontSubpixelAAEnabled", 10, 10);
7780    ctx.scale(1.5, 1);
7781    ctx.fillText("I", 0, 10);
7782    const data = ctx.getImageData(0, 0, 10, 10).data;
7783    let enabled = false;
7784    for (let i = 3; i < data.length; i += 4) {
7785      if (data[i] > 0 && data[i] < 255) {
7786        enabled = true;
7787        break;
7788      }
7789    }
7790    return shadow(this, "isFontSubpixelAAEnabled", enabled);
7791  }
7792  showText(glyphs) {
7793    const current = this.current;
7794    const font = current.font;
7795    if (font.isType3Font) {
7796      return this.showType3Text(glyphs);
7797    }
7798    const fontSize = current.fontSize;
7799    if (fontSize === 0) {
7800      return undefined;
7801    }
7802    const ctx = this.ctx;
7803    const fontSizeScale = current.fontSizeScale;
7804    const charSpacing = current.charSpacing;
7805    const wordSpacing = current.wordSpacing;
7806    const fontDirection = current.fontDirection;
7807    const textHScale = current.textHScale * fontDirection;
7808    const glyphsLength = glyphs.length;
7809    const vertical = font.vertical;
7810    const spacingDir = vertical ? 1 : -1;
7811    const defaultVMetrics = font.defaultVMetrics;
7812    const widthAdvanceScale = fontSize * current.fontMatrix[0];
7813    const simpleFillText = current.textRenderingMode === TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill;
7814    ctx.save();
7815    ctx.transform(...current.textMatrix);
7816    ctx.translate(current.x, current.y + current.textRise);
7817    if (fontDirection > 0) {
7818      ctx.scale(textHScale, -1);
7819    } else {
7820      ctx.scale(textHScale, 1);
7821    }
7822    let patternTransform;
7823    if (current.patternFill) {
7824      ctx.save();
7825      const pattern = current.fillColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.FILL);
7826      patternTransform = getCurrentTransform(ctx);
7827      ctx.restore();
7828      ctx.fillStyle = pattern;
7829    }
7830    let lineWidth = current.lineWidth;
7831    const scale = current.textMatrixScale;
7832    if (scale === 0 || lineWidth === 0) {
7833      const fillStrokeMode = current.textRenderingMode & TextRenderingMode.FILL_STROKE_MASK;
7834      if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
7835        lineWidth = this.getSinglePixelWidth();
7836      }
7837    } else {
7838      lineWidth /= scale;
7839    }
7840    if (fontSizeScale !== 1.0) {
7841      ctx.scale(fontSizeScale, fontSizeScale);
7842      lineWidth /= fontSizeScale;
7843    }
7844    ctx.lineWidth = lineWidth;
7845    if (font.isInvalidPDFjsFont) {
7846      const chars = [];
7847      let width = 0;
7848      for (const glyph of glyphs) {
7849        chars.push(glyph.unicode);
7850        width += glyph.width;
7851      }
7852      ctx.fillText(chars.join(""), 0, 0);
7853      current.x += width * widthAdvanceScale * textHScale;
7854      ctx.restore();
7855      this.compose();
7856      return undefined;
7857    }
7858    let x = 0,
7859      i;
7860    for (i = 0; i < glyphsLength; ++i) {
7861      const glyph = glyphs[i];
vendor: 3,283 bytes, lines 7862-7946
7862      if (typeof glyph === "number") {
7863        x += spacingDir * glyph * fontSize / 1000;
7864        continue;
7865      }
7866      let restoreNeeded = false;
7867      const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
7868      const character = glyph.fontChar;
7869      const accent = glyph.accent;
7870      let scaledX, scaledY;
7871      let width = glyph.width;
7872      if (vertical) {
7873        const vmetric = glyph.vmetric || defaultVMetrics;
7874        const vx = -(glyph.vmetric ? vmetric[1] : width * 0.5) * widthAdvanceScale;
7875        const vy = vmetric[2] * widthAdvanceScale;
7876        width = vmetric ? -vmetric[0] : width;
7877        scaledX = vx / fontSizeScale;
7878        scaledY = (x + vy) / fontSizeScale;
7879      } else {
7880        scaledX = x / fontSizeScale;
7881        scaledY = 0;
7882      }
7883      if (font.remeasure && width > 0) {
7884        const measuredWidth = ctx.measureText(character).width * 1000 / fontSize * fontSizeScale;
7885        if (width < measuredWidth && this.isFontSubpixelAAEnabled) {
7886          const characterScaleX = width / measuredWidth;
7887          restoreNeeded = true;
7888          ctx.save();
7889          ctx.scale(characterScaleX, 1);
7890          scaledX /= characterScaleX;
7891        } else if (width !== measuredWidth) {
7892          scaledX += (width - measuredWidth) / 2000 * fontSize / fontSizeScale;
7893        }
7894      }
7895      if (this.contentVisible && (glyph.isInFont || font.missingFile)) {
7896        if (simpleFillText && !accent) {
7897          ctx.fillText(character, scaledX, scaledY);
7898        } else {
7899          this.paintChar(character, scaledX, scaledY, patternTransform);
7900          if (accent) {
7901            const scaledAccentX = scaledX + fontSize * accent.offset.x / fontSizeScale;
7902            const scaledAccentY = scaledY - fontSize * accent.offset.y / fontSizeScale;
7903            this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY, patternTransform);
7904          }
7905        }
7906      }
7907      const charWidth = vertical ? width * widthAdvanceScale - spacing * fontDirection : width * widthAdvanceScale + spacing * fontDirection;
7908      x += charWidth;
7909      if (restoreNeeded) {
7910        ctx.restore();
7911      }
7912    }
7913    if (vertical) {
7914      current.y -= x;
7915    } else {
7916      current.x += x * textHScale;
7917    }
7918    ctx.restore();
7919    this.compose();
7920    return undefined;
7921  }
7922  showType3Text(glyphs) {
7923    const ctx = this.ctx;
7924    const current = this.current;
7925    const font = current.font;
7926    const fontSize = current.fontSize;
7927    const fontDirection = current.fontDirection;
7928    const spacingDir = font.vertical ? 1 : -1;
7929    const charSpacing = current.charSpacing;
7930    const wordSpacing = current.wordSpacing;
7931    const textHScale = current.textHScale * fontDirection;
7932    const fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
7933    const glyphsLength = glyphs.length;
7934    const isTextInvisible = current.textRenderingMode === TextRenderingMode.INVISIBLE;
7935    let i, glyph, width, spacingLength;
7936    if (isTextInvisible || fontSize === 0) {
7937      return;
7938    }
7939    this._cachedScaleForStroking[0] = -1;
7940    this._cachedGetSinglePixelWidth = null;
7941    ctx.save();
7942    ctx.transform(...current.textMatrix);
7943    ctx.translate(current.x, current.y);
7944    ctx.scale(textHScale, fontDirection);
7945    for (i = 0; i < glyphsLength; ++i) {
7946      glyph = glyphs[i];
7947      if (typeof glyph === "number") {
7948        spacingLength = spacingDir * glyph * fontSize / 1000;
7949        this.ctx.translate(spacingLength, 0);
7950        current.x += spacingLength * textHScale;
7951        continue;
7952      }
7953      const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
7954      const operatorList = font.charProcOperatorList[glyph.operatorListId];
7955      if (!operatorList) {
7956        warn(`Type3 character "${glyph.operatorListId}" is not available.`);
7957        continue;
7958      }
7959      if (this.contentVisible) {
7960        this.processingType3 = glyph;
7961        this.save();
7962        ctx.scale(fontSize, fontSize);
7963        ctx.transform(...fontMatrix);
7964        this.executeOperatorList(operatorList);
7965        this.restore();
7966      }
7967      const transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
7968      width = transformed[0] * fontSize + spacing;
7969      ctx.translate(width, 0);
7970      current.x += width * textHScale;
7971    }
7972    ctx.restore();
7973    this.processingType3 = null;
7974  }
7975  setCharWidth(xWidth, yWidth) {}
7976  setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) {
7977    this.ctx.rect(llx, lly, urx - llx, ury - lly);
7978    this.ctx.clip();
7979    this.endPath();
7980  }
7981  getColorN_Pattern(IR) {
7982    let pattern;
7983    if (IR[0] === "TilingPattern") {
7984      const color = IR[1];
7985      const baseTransform = this.baseTransform || getCurrentTransform(this.ctx);
7986      const canvasGraphicsFactory = {
7987        createCanvasGraphics: ctx => new CanvasGraphics(ctx, this.commonObjs, this.objs, this.canvasFactory, this.filterFactory, {
7988          optionalContentConfig: this.optionalContentConfig,
7989          markedContentStack: this.markedContentStack
7990        })
7991      };
7992      pattern = new TilingPattern(IR, color, this.ctx, canvasGraphicsFactory, baseTransform);
7993    } else {
7994      pattern = this._getPattern(IR[1], IR[2]);
7995    }
7996    return pattern;
7997  }
7998  setStrokeColorN() {
7999    this.current.strokeColor = this.getColorN_Pattern(arguments);
8000  }
8001  setFillColorN() {
8002    this.current.fillColor = this.getColorN_Pattern(arguments);
8003    this.current.patternFill = true;
8004  }
8005  setStrokeRGBColor(r, g, b) {
8006    this.ctx.strokeStyle = this.current.strokeColor = Util.makeHexColor(r, g, b);
8007  }
8008  setStrokeTransparent() {
8009    this.ctx.strokeStyle = this.current.strokeColor = "transparent";
8010  }
8011  setFillRGBColor(r, g, b) {
8012    this.ctx.fillStyle = this.current.fillColor = Util.makeHexColor(r, g, b);
8013    this.current.patternFill = false;
8014  }
8015  setFillTransparent() {
8016    this.ctx.fillStyle = this.current.fillColor = "transparent";
8017    this.current.patternFill = false;
8018  }
8019  _getPattern(objId, matrix = null) {
8020    let pattern;
8021    if (this.cachedPatterns.has(objId)) {
8022      pattern = this.cachedPatterns.get(objId);
8023    } else {
8024      pattern = getShadingPattern(this.getObject(objId));
8025      this.cachedPatterns.set(objId, pattern);
8026    }
8027    if (matrix) {
8028      pattern.matrix = matrix;
8029    }
8030    return pattern;
8031  }
8032  shadingFill(objId) {
8033    if (!this.contentVisible) {
8034      return;
8035    }
8036    const ctx = this.ctx;
8037    this.save();
8038    const pattern = this._getPattern(objId);
8039    ctx.fillStyle = pattern.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.SHADING);
8040    const inv = getCurrentTransformInverse(ctx);
8041    if (inv) {
8042      const {
8043        width,
8044        height
8045      } = ctx.canvas;
8046      const [x0, y0, x1, y1] = Util.getAxialAlignedBoundingBox([0, 0, width, height], inv);
8047      this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
8048    } else {
8049      this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
8050    }
8051    this.compose(this.current.getClippedPathBoundingBox());
8052    this.restore();
8053  }
8054  beginInlineImage() {
8055    unreachable("Should not call beginInlineImage");
8056  }
8057  beginImageData() {
8058    unreachable("Should not call beginImageData");
8059  }
8060  paintFormXObjectBegin(matrix, bbox) {
8061    if (!this.contentVisible) {
8062      return;
8063    }
8064    this.save();
8065    this.baseTransformStack.push(this.baseTransform);
8066    if (matrix) {
8067      this.transform(...matrix);
8068    }
8069    this.baseTransform = getCurrentTransform(this.ctx);
8070    if (bbox) {
8071      const width = bbox[2] - bbox[0];
8072      const height = bbox[3] - bbox[1];
8073      this.ctx.rect(bbox[0], bbox[1], width, height);
8074      this.current.updateRectMinMax(getCurrentTransform(this.ctx), bbox);
8075      this.clip();
8076      this.endPath();
8077    }
8078  }
8079  paintFormXObjectEnd() {
8080    if (!this.contentVisible) {
8081      return;
8082    }
8083    this.restore();
8084    this.baseTransform = this.baseTransformStack.pop();
8085  }
8086  beginGroup(group) {
8087    if (!this.contentVisible) {
8088      return;
8089    }
8090    this.save();
8091    if (this.inSMaskMode) {
8092      this.endSMaskMode();
8093      this.current.activeSMask = null;
8094    }
8095    const currentCtx = this.ctx;
8096    if (!group.isolated) {
8097      info("TODO: Support non-isolated groups.");
8098    }
8099    if (group.knockout) {
8100      warn("Knockout groups not supported.");
8101    }
8102    const currentTransform = getCurrentTransform(currentCtx);
8103    if (group.matrix) {
8104      currentCtx.transform(...group.matrix);
8105    }
8106    if (!group.bbox) {
8107      throw new Error("Bounding box is required.");
8108    }
8109    let bounds = Util.getAxialAlignedBoundingBox(group.bbox, getCurrentTransform(currentCtx));
8110    const canvasBounds = [0, 0, currentCtx.canvas.width, currentCtx.canvas.height];
8111    bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
8112    const offsetX = Math.floor(bounds[0]);
8113    const offsetY = Math.floor(bounds[1]);
8114    const drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
8115    const drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
8116    this.current.startNewPathAndClipBox([0, 0, drawnWidth, drawnHeight]);
8117    let cacheId = "groupAt" + this.groupLevel;
8118    if (group.smask) {
8119      cacheId += "_smask_" + this.smaskCounter++ % 2;
8120    }
8121    const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight);
8122    const groupCtx = scratchCanvas.context;
8123    groupCtx.translate(-offsetX, -offsetY);
8124    groupCtx.transform(...currentTransform);
8125    if (group.smask) {
8126      this.smaskStack.push({
8127        canvas: scratchCanvas.canvas,
8128        context: groupCtx,
8129        offsetX,
8130        offsetY,
8131        subtype: group.smask.subtype,
8132        backdrop: group.smask.backdrop,
8133        transferMap: group.smask.transferMap || null,
8134        startTransformInverse: null
8135      });
8136    } else {
8137      currentCtx.setTransform(1, 0, 0, 1, 0, 0);
8138      currentCtx.translate(offsetX, offsetY);
8139      currentCtx.save();
8140    }
8141    copyCtxState(currentCtx, groupCtx);
8142    this.ctx = groupCtx;
8143    this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
8144    this.groupStack.push(currentCtx);
8145    this.groupLevel++;
8146  }
8147  endGroup(group) {
8148    if (!this.contentVisible) {
8149      return;
8150    }
8151    this.groupLevel--;
8152    const groupCtx = this.ctx;
8153    const ctx = this.groupStack.pop();
8154    this.ctx = ctx;
8155    this.ctx.imageSmoothingEnabled = false;
8156    if (group.smask) {
8157      this.tempSMask = this.smaskStack.pop();
8158      this.restore();
8159    } else {
8160      this.ctx.restore();
8161      const currentMtx = getCurrentTransform(this.ctx);
8162      this.restore();
8163      this.ctx.save();
8164      this.ctx.setTransform(...currentMtx);
8165      const dirtyBox = Util.getAxialAlignedBoundingBox([0, 0, groupCtx.canvas.width, groupCtx.canvas.height], currentMtx);
8166      this.ctx.drawImage(groupCtx.canvas, 0, 0);
8167      this.ctx.restore();
8168      this.compose(dirtyBox);
8169    }
8170  }
8171  beginAnnotation(id, rect, transform, matrix, hasOwnCanvas) {
8172    this.#restoreInitialState();
8173    resetCtxToDefault(this.ctx);
8174    this.ctx.save();
8175    this.save();
8176    if (this.baseTransform) {
8177      this.ctx.setTransform(...this.baseTransform);
8178    }
8179    if (rect) {
8180      const width = rect[2] - rect[0];
8181      const height = rect[3] - rect[1];
8182      if (hasOwnCanvas && this.annotationCanvasMap) {
8183        transform = transform.slice();
8184        transform[4] -= rect[0];
8185        transform[5] -= rect[1];
8186        rect = rect.slice();
8187        rect[0] = rect[1] = 0;
8188        rect[2] = width;
8189        rect[3] = height;
8190        const [scaleX, scaleY] = Util.singularValueDecompose2dScale(getCurrentTransform(this.ctx));
8191        const {
8192          viewportScale
8193        } = this;
8194        const canvasWidth = Math.ceil(width * this.outputScaleX * viewportScale);
8195        const canvasHeight = Math.ceil(height * this.outputScaleY * viewportScale);
8196        this.annotationCanvas = this.canvasFactory.create(canvasWidth, canvasHeight);
8197        const {
8198          canvas,
8199          context
8200        } = this.annotationCanvas;
8201        this.annotationCanvasMap.set(id, canvas);
8202        this.annotationCanvas.savedCtx = this.ctx;
8203        this.ctx = context;
8204        this.ctx.save();
8205        this.ctx.setTransform(scaleX, 0, 0, -scaleY, 0, height * scaleY);
8206        resetCtxToDefault(this.ctx);
8207      } else {
8208        resetCtxToDefault(this.ctx);
8209        this.endPath();
8210        this.ctx.rect(rect[0], rect[1], width, height);
8211        this.ctx.clip();
8212        this.ctx.beginPath();
8213      }
8214    }
8215    this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height);
8216    this.transform(...transform);
8217    this.transform(...matrix);
8218  }
8219  endAnnotation() {
8220    if (this.annotationCanvas) {
8221      this.ctx.restore();
8222      this.#drawFilter();
8223      this.ctx = this.annotationCanvas.savedCtx;
8224      delete this.annotationCanvas.savedCtx;
8225      delete this.annotationCanvas;
8226    }
8227  }
8228  paintImageMaskXObject(img) {
8229    if (!this.contentVisible) {
8230      return;
8231    }
8232    const count = img.count;
8233    img = this.getObject(img.data, img);
8234    img.count = count;
8235    const ctx = this.ctx;
8236    const glyph = this.processingType3;
8237    if (glyph) {
8238      if (glyph.compiled === undefined) {
8239        glyph.compiled = compileType3Glyph(img);
8240      }
8241      if (glyph.compiled) {
8242        glyph.compiled(ctx);
8243        return;
8244      }
8245    }
8246    const mask = this._createMaskCanvas(img);
8247    const maskCanvas = mask.canvas;
8248    ctx.save();
8249    ctx.setTransform(1, 0, 0, 1, 0, 0);
8250    ctx.drawImage(maskCanvas, mask.offsetX, mask.offsetY);
8251    ctx.restore();
8252    this.compose();
8253  }
8254  paintImageMaskXObjectRepeat(img, scaleX, skewX = 0, skewY = 0, scaleY, positions) {
8255    if (!this.contentVisible) {
8256      return;
8257    }
8258    img = this.getObject(img.data, img);
8259    const ctx = this.ctx;
8260    ctx.save();
8261    const currentTransform = getCurrentTransform(ctx);
8262    ctx.transform(scaleX, skewX, skewY, scaleY, 0, 0);
8263    const mask = this._createMaskCanvas(img);
8264    ctx.setTransform(1, 0, 0, 1, mask.offsetX - currentTransform[4], mask.offsetY - currentTransform[5]);
8265    for (let i = 0, ii = positions.length; i < ii; i += 2) {
8266      const trans = Util.transform(currentTransform, [scaleX, skewX, skewY, scaleY, positions[i], positions[i + 1]]);
8267      const [x, y] = Util.applyTransform([0, 0], trans);
8268      ctx.drawImage(mask.canvas, x, y);
8269    }
8270    ctx.restore();
8271    this.compose();
8272  }
8273  paintImageMaskXObjectGroup(images) {
8274    if (!this.contentVisible) {
8275      return;
8276    }
8277    const ctx = this.ctx;
8278    const fillColor = this.current.fillColor;
8279    const isPatternFill = this.current.patternFill;
8280    for (const image of images) {
8281      const {
8282        data,
8283        width,
8284        height,
8285        transform
8286      } = image;
8287      const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
8288      const maskCtx = maskCanvas.context;
8289      maskCtx.save();
8290      const img = this.getObject(data, image);
8291      putBinaryImageMask(maskCtx, img);
8292      maskCtx.globalCompositeOperation = "source-in";
8293      maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, getCurrentTransformInverse(ctx), PathType.FILL) : fillColor;
8294      maskCtx.fillRect(0, 0, width, height);
vendor: 4,749 bytes, lines 8295-8458
8295      maskCtx.restore();
8296      ctx.save();
8297      ctx.transform(...transform);
8298      ctx.scale(1, -1);
8299      drawImageAtIntegerCoords(ctx, maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
8300      ctx.restore();
8301    }
8302    this.compose();
8303  }
8304  paintImageXObject(objId) {
8305    if (!this.contentVisible) {
8306      return;
8307    }
8308    const imgData = this.getObject(objId);
8309    if (!imgData) {
8310      warn("Dependent image isn't ready yet");
8311      return;
8312    }
8313    this.paintInlineImageXObject(imgData);
8314  }
8315  paintImageXObjectRepeat(objId, scaleX, scaleY, positions) {
8316    if (!this.contentVisible) {
8317      return;
8318    }
8319    const imgData = this.getObject(objId);
8320    if (!imgData) {
8321      warn("Dependent image isn't ready yet");
8322      return;
8323    }
8324    const width = imgData.width;
8325    const height = imgData.height;
8326    const map = [];
8327    for (let i = 0, ii = positions.length; i < ii; i += 2) {
8328      map.push({
8329        transform: [scaleX, 0, 0, scaleY, positions[i], positions[i + 1]],
8330        x: 0,
8331        y: 0,
8332        w: width,
8333        h: height
8334      });
8335    }
8336    this.paintInlineImageXObjectGroup(imgData, map);
8337  }
8338  applyTransferMapsToCanvas(ctx) {
8339    if (this.current.transferMaps !== "none") {
8340      ctx.filter = this.current.transferMaps;
8341      ctx.drawImage(ctx.canvas, 0, 0);
8342      ctx.filter = "none";
8343    }
8344    return ctx.canvas;
8345  }
8346  applyTransferMapsToBitmap(imgData) {
8347    if (this.current.transferMaps === "none") {
8348      return imgData.bitmap;
8349    }
8350    const {
8351      bitmap,
8352      width,
8353      height
8354    } = imgData;
8355    const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height);
8356    const tmpCtx = tmpCanvas.context;
8357    tmpCtx.filter = this.current.transferMaps;
8358    tmpCtx.drawImage(bitmap, 0, 0);
8359    tmpCtx.filter = "none";
8360    return tmpCanvas.canvas;
8361  }
8362  paintInlineImageXObject(imgData) {
8363    if (!this.contentVisible) {
8364      return;
8365    }
8366    const width = imgData.width;
8367    const height = imgData.height;
8368    const ctx = this.ctx;
8369    this.save();
8370    if (!isNodeJS) {
8371      const {
8372        filter
8373      } = ctx;
8374      if (filter !== "none" && filter !== "") {
8375        ctx.filter = "none";
8376      }
8377    }
8378    ctx.scale(1 / width, -1 / height);
8379    let imgToPaint;
8380    if (imgData.bitmap) {
8381      imgToPaint = this.applyTransferMapsToBitmap(imgData);
8382    } else if (typeof HTMLElement === "function" && imgData instanceof HTMLElement || !imgData.data) {
8383      imgToPaint = imgData;
8384    } else {
8385      const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height);
8386      const tmpCtx = tmpCanvas.context;
8387      putBinaryImageData(tmpCtx, imgData);
8388      imgToPaint = this.applyTransferMapsToCanvas(tmpCtx);
8389    }
8390    const scaled = this._scaleImage(imgToPaint, getCurrentTransformInverse(ctx));
8391    ctx.imageSmoothingEnabled = getImageSmoothingEnabled(getCurrentTransform(ctx), imgData.interpolate);
8392    drawImageAtIntegerCoords(ctx, scaled.img, 0, 0, scaled.paintWidth, scaled.paintHeight, 0, -height, width, height);
8393    this.compose();
8394    this.restore();
8395  }
8396  paintInlineImageXObjectGroup(imgData, map) {
8397    if (!this.contentVisible) {
8398      return;
8399    }
8400    const ctx = this.ctx;
8401    let imgToPaint;
8402    if (imgData.bitmap) {
8403      imgToPaint = imgData.bitmap;
8404    } else {
8405      const w = imgData.width;
8406      const h = imgData.height;
8407      const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", w, h);
8408      const tmpCtx = tmpCanvas.context;
8409      putBinaryImageData(tmpCtx, imgData);
8410      imgToPaint = this.applyTransferMapsToCanvas(tmpCtx);
8411    }
8412    for (const entry of map) {
8413      ctx.save();
8414      ctx.transform(...entry.transform);
8415      ctx.scale(1, -1);
8416      drawImageAtIntegerCoords(ctx, imgToPaint, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1);
8417      ctx.restore();
8418    }
8419    this.compose();
8420  }
8421  paintSolidColorImageMask() {
8422    if (!this.contentVisible) {
8423      return;
8424    }
8425    this.ctx.fillRect(0, 0, 1, 1);
8426    this.compose();
8427  }
8428  markPoint(tag) {}
8429  markPointProps(tag, properties) {}
8430  beginMarkedContent(tag) {
8431    this.markedContentStack.push({
8432      visible: true
8433    });
8434  }
8435  beginMarkedContentProps(tag, properties) {
8436    if (tag === "OC") {
8437      this.markedContentStack.push({
8438        visible: this.optionalContentConfig.isVisible(properties)
8439      });
8440    } else {
8441      this.markedContentStack.push({
8442        visible: true
8443      });
8444    }
8445    this.contentVisible = this.isContentVisible();
8446  }
8447  endMarkedContent() {
8448    this.markedContentStack.pop();
8449    this.contentVisible = this.isContentVisible();
8450  }
8451  beginCompat() {}
8452  endCompat() {}
8453  consumePath(clipBox) {
8454    const isEmpty = this.current.isEmptyClip();
8455    if (this.pendingClip) {
8456      this.current.updateClipFromPath();
8457    }
8458    if (!this.pendingClip) {
vendor: 16,943 bytes, lines 8459-9045
8459      this.compose(clipBox);
8460    }
8461    const ctx = this.ctx;
8462    if (this.pendingClip) {
8463      if (!isEmpty) {
8464        if (this.pendingClip === EO_CLIP) {
8465          ctx.clip("evenodd");
8466        } else {
8467          ctx.clip();
8468        }
8469      }
8470      this.pendingClip = null;
8471    }
8472    this.current.startNewPathAndClipBox(this.current.clipBox);
8473    ctx.beginPath();
8474  }
8475  getSinglePixelWidth() {
8476    if (!this._cachedGetSinglePixelWidth) {
8477      const m = getCurrentTransform(this.ctx);
8478      if (m[1] === 0 && m[2] === 0) {
8479        this._cachedGetSinglePixelWidth = 1 / Math.min(Math.abs(m[0]), Math.abs(m[3]));
8480      } else {
8481        const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]);
8482        const normX = Math.hypot(m[0], m[2]);
8483        const normY = Math.hypot(m[1], m[3]);
8484        this._cachedGetSinglePixelWidth = Math.max(normX, normY) / absDet;
8485      }
8486    }
8487    return this._cachedGetSinglePixelWidth;
8488  }
8489  getScaleForStroking() {
8490    if (this._cachedScaleForStroking[0] === -1) {
8491      const {
8492        lineWidth
8493      } = this.current;
8494      const {
8495        a,
8496        b,
8497        c,
8498        d
8499      } = this.ctx.getTransform();
8500      let scaleX, scaleY;
8501      if (b === 0 && c === 0) {
8502        const normX = Math.abs(a);
8503        const normY = Math.abs(d);
8504        if (normX === normY) {
8505          if (lineWidth === 0) {
8506            scaleX = scaleY = 1 / normX;
8507          } else {
8508            const scaledLineWidth = normX * lineWidth;
8509            scaleX = scaleY = scaledLineWidth < 1 ? 1 / scaledLineWidth : 1;
8510          }
8511        } else if (lineWidth === 0) {
8512          scaleX = 1 / normX;
8513          scaleY = 1 / normY;
8514        } else {
8515          const scaledXLineWidth = normX * lineWidth;
8516          const scaledYLineWidth = normY * lineWidth;
8517          scaleX = scaledXLineWidth < 1 ? 1 / scaledXLineWidth : 1;
8518          scaleY = scaledYLineWidth < 1 ? 1 / scaledYLineWidth : 1;
8519        }
8520      } else {
8521        const absDet = Math.abs(a * d - b * c);
8522        const normX = Math.hypot(a, b);
8523        const normY = Math.hypot(c, d);
8524        if (lineWidth === 0) {
8525          scaleX = normY / absDet;
8526          scaleY = normX / absDet;
8527        } else {
8528          const baseArea = lineWidth * absDet;
8529          scaleX = normY > baseArea ? normY / baseArea : 1;
8530          scaleY = normX > baseArea ? normX / baseArea : 1;
8531        }
8532      }
8533      this._cachedScaleForStroking[0] = scaleX;
8534      this._cachedScaleForStroking[1] = scaleY;
8535    }
8536    return this._cachedScaleForStroking;
8537  }
8538  rescaleAndStroke(saveRestore) {
8539    const {
8540      ctx
8541    } = this;
8542    const {
8543      lineWidth
8544    } = this.current;
8545    const [scaleX, scaleY] = this.getScaleForStroking();
8546    ctx.lineWidth = lineWidth || 1;
8547    if (scaleX === 1 && scaleY === 1) {
8548      ctx.stroke();
8549      return;
8550    }
8551    const dashes = ctx.getLineDash();
8552    if (saveRestore) {
8553      ctx.save();
8554    }
8555    ctx.scale(scaleX, scaleY);
8556    if (dashes.length > 0) {
8557      const scale = Math.max(scaleX, scaleY);
8558      ctx.setLineDash(dashes.map(x => x / scale));
8559      ctx.lineDashOffset /= scale;
8560    }
8561    ctx.stroke();
8562    if (saveRestore) {
8563      ctx.restore();
8564    }
8565  }
8566  isContentVisible() {
8567    for (let i = this.markedContentStack.length - 1; i >= 0; i--) {
8568      if (!this.markedContentStack[i].visible) {
8569        return false;
8570      }
8571    }
8572    return true;
8573  }
8574}
8575for (const op in OPS) {
8576  if (CanvasGraphics.prototype[op] !== undefined) {
8577    CanvasGraphics.prototype[OPS[op]] = CanvasGraphics.prototype[op];
8578  }
8579}
8580
8581;// ./src/display/worker_options.js
8582class GlobalWorkerOptions {
8583  static #port = null;
8584  static #src = "";
8585  static get workerPort() {
8586    return this.#port;
8587  }
8588  static set workerPort(val) {
8589    if (!(typeof Worker !== "undefined" && val instanceof Worker) && val !== null) {
8590      throw new Error("Invalid `workerPort` type.");
8591    }
8592    this.#port = val;
8593  }
8594  static get workerSrc() {
8595    return this.#src;
8596  }
8597  static set workerSrc(val) {
8598    if (typeof val !== "string") {
8599      throw new Error("Invalid `workerSrc` type.");
8600    }
8601    this.#src = val;
8602  }
8603}
8604
8605;// ./src/shared/message_handler.js
8606
8607const CallbackKind = {
8608  UNKNOWN: 0,
8609  DATA: 1,
8610  ERROR: 2
8611};
8612const StreamKind = {
8613  UNKNOWN: 0,
8614  CANCEL: 1,
8615  CANCEL_COMPLETE: 2,
8616  CLOSE: 3,
8617  ENQUEUE: 4,
8618  ERROR: 5,
8619  PULL: 6,
8620  PULL_COMPLETE: 7,
8621  START_COMPLETE: 8
8622};
8623function wrapReason(reason) {
8624  if (!(reason instanceof Error || typeof reason === "object" && reason !== null)) {
8625    unreachable('wrapReason: Expected "reason" to be a (possibly cloned) Error.');
8626  }
8627  switch (reason.name) {
8628    case "AbortException":
8629      return new AbortException(reason.message);
8630    case "MissingPDFException":
8631      return new MissingPDFException(reason.message);
8632    case "PasswordException":
8633      return new PasswordException(reason.message, reason.code);
8634    case "UnexpectedResponseException":
8635      return new UnexpectedResponseException(reason.message, reason.status);
8636    case "UnknownErrorException":
8637      return new UnknownErrorException(reason.message, reason.details);
8638    default:
8639      return new UnknownErrorException(reason.message, reason.toString());
8640  }
8641}
8642class MessageHandler {
8643  #messageAC = new AbortController();
8644  constructor(sourceName, targetName, comObj) {
8645    this.sourceName = sourceName;
8646    this.targetName = targetName;
8647    this.comObj = comObj;
8648    this.callbackId = 1;
8649    this.streamId = 1;
8650    this.streamSinks = Object.create(null);
8651    this.streamControllers = Object.create(null);
8652    this.callbackCapabilities = Object.create(null);
8653    this.actionHandler = Object.create(null);
8654    comObj.addEventListener("message", this.#onMessage.bind(this), {
8655      signal: this.#messageAC.signal
8656    });
8657  }
8658  #onMessage({
8659    data
8660  }) {
8661    if (data.targetName !== this.sourceName) {
8662      return;
8663    }
8664    if (data.stream) {
8665      this.#processStreamMessage(data);
8666      return;
8667    }
8668    if (data.callback) {
8669      const callbackId = data.callbackId;
8670      const capability = this.callbackCapabilities[callbackId];
8671      if (!capability) {
8672        throw new Error(`Cannot resolve callback ${callbackId}`);
8673      }
8674      delete this.callbackCapabilities[callbackId];
8675      if (data.callback === CallbackKind.DATA) {
8676        capability.resolve(data.data);
8677      } else if (data.callback === CallbackKind.ERROR) {
8678        capability.reject(wrapReason(data.reason));
8679      } else {
8680        throw new Error("Unexpected callback case");
8681      }
8682      return;
8683    }
8684    const action = this.actionHandler[data.action];
8685    if (!action) {
8686      throw new Error(`Unknown action from worker: ${data.action}`);
8687    }
8688    if (data.callbackId) {
8689      const sourceName = this.sourceName,
8690        targetName = data.sourceName,
8691        comObj = this.comObj;
8692      new Promise(function (resolve) {
8693        resolve(action(data.data));
8694      }).then(function (result) {
8695        comObj.postMessage({
8696          sourceName,
8697          targetName,
8698          callback: CallbackKind.DATA,
8699          callbackId: data.callbackId,
8700          data: result
8701        });
8702      }, function (reason) {
8703        comObj.postMessage({
8704          sourceName,
8705          targetName,
8706          callback: CallbackKind.ERROR,
8707          callbackId: data.callbackId,
8708          reason: wrapReason(reason)
8709        });
8710      });
8711      return;
8712    }
8713    if (data.streamId) {
8714      this.#createStreamSink(data);
8715      return;
8716    }
8717    action(data.data);
8718  }
8719  on(actionName, handler) {
8720    const ah = this.actionHandler;
8721    if (ah[actionName]) {
8722      throw new Error(`There is already an actionName called "${actionName}"`);
8723    }
8724    ah[actionName] = handler;
8725  }
8726  send(actionName, data, transfers) {
8727    this.comObj.postMessage({
8728      sourceName: this.sourceName,
8729      targetName: this.targetName,
8730      action: actionName,
8731      data
8732    }, transfers);
8733  }
8734  sendWithPromise(actionName, data, transfers) {
8735    const callbackId = this.callbackId++;
8736    const capability = Promise.withResolvers();
8737    this.callbackCapabilities[callbackId] = capability;
8738    try {
8739      this.comObj.postMessage({
8740        sourceName: this.sourceName,
8741        targetName: this.targetName,
8742        action: actionName,
8743        callbackId,
8744        data
8745      }, transfers);
8746    } catch (ex) {
8747      capability.reject(ex);
8748    }
8749    return capability.promise;
8750  }
8751  sendWithStream(actionName, data, queueingStrategy, transfers) {
8752    const streamId = this.streamId++,
8753      sourceName = this.sourceName,
8754      targetName = this.targetName,
8755      comObj = this.comObj;
8756    return new ReadableStream({
8757      start: controller => {
8758        const startCapability = Promise.withResolvers();
8759        this.streamControllers[streamId] = {
8760          controller,
8761          startCall: startCapability,
8762          pullCall: null,
8763          cancelCall: null,
8764          isClosed: false
8765        };
8766        comObj.postMessage({
8767          sourceName,
8768          targetName,
8769          action: actionName,
8770          streamId,
8771          data,
8772          desiredSize: controller.desiredSize
8773        }, transfers);
8774        return startCapability.promise;
8775      },
8776      pull: controller => {
8777        const pullCapability = Promise.withResolvers();
8778        this.streamControllers[streamId].pullCall = pullCapability;
8779        comObj.postMessage({
8780          sourceName,
8781          targetName,
8782          stream: StreamKind.PULL,
8783          streamId,
8784          desiredSize: controller.desiredSize
8785        });
8786        return pullCapability.promise;
8787      },
8788      cancel: reason => {
8789        assert(reason instanceof Error, "cancel must have a valid reason");
8790        const cancelCapability = Promise.withResolvers();
8791        this.streamControllers[streamId].cancelCall = cancelCapability;
8792        this.streamControllers[streamId].isClosed = true;
8793        comObj.postMessage({
8794          sourceName,
8795          targetName,
8796          stream: StreamKind.CANCEL,
8797          streamId,
8798          reason: wrapReason(reason)
8799        });
8800        return cancelCapability.promise;
8801      }
8802    }, queueingStrategy);
8803  }
8804  #createStreamSink(data) {
8805    const streamId = data.streamId,
8806      sourceName = this.sourceName,
8807      targetName = data.sourceName,
8808      comObj = this.comObj;
8809    const self = this,
8810      action = this.actionHandler[data.action];
8811    const streamSink = {
8812      enqueue(chunk, size = 1, transfers) {
8813        if (this.isCancelled) {
8814          return;
8815        }
8816        const lastDesiredSize = this.desiredSize;
8817        this.desiredSize -= size;
8818        if (lastDesiredSize > 0 && this.desiredSize <= 0) {
8819          this.sinkCapability = Promise.withResolvers();
8820          this.ready = this.sinkCapability.promise;
8821        }
8822        comObj.postMessage({
8823          sourceName,
8824          targetName,
8825          stream: StreamKind.ENQUEUE,
8826          streamId,
8827          chunk
8828        }, transfers);
8829      },
8830      close() {
8831        if (this.isCancelled) {
8832          return;
8833        }
8834        this.isCancelled = true;
8835        comObj.postMessage({
8836          sourceName,
8837          targetName,
8838          stream: StreamKind.CLOSE,
8839          streamId
8840        });
8841        delete self.streamSinks[streamId];
8842      },
8843      error(reason) {
8844        assert(reason instanceof Error, "error must have a valid reason");
8845        if (this.isCancelled) {
8846          return;
8847        }
8848        this.isCancelled = true;
8849        comObj.postMessage({
8850          sourceName,
8851          targetName,
8852          stream: StreamKind.ERROR,
8853          streamId,
8854          reason: wrapReason(reason)
8855        });
8856      },
8857      sinkCapability: Promise.withResolvers(),
8858      onPull: null,
8859      onCancel: null,
8860      isCancelled: false,
8861      desiredSize: data.desiredSize,
8862      ready: null
8863    };
8864    streamSink.sinkCapability.resolve();
8865    streamSink.ready = streamSink.sinkCapability.promise;
8866    this.streamSinks[streamId] = streamSink;
8867    new Promise(function (resolve) {
8868      resolve(action(data.data, streamSink));
8869    }).then(function () {
8870      comObj.postMessage({
8871        sourceName,
8872        targetName,
8873        stream: StreamKind.START_COMPLETE,
8874        streamId,
8875        success: true
8876      });
8877    }, function (reason) {
8878      comObj.postMessage({
8879        sourceName,
8880        targetName,
8881        stream: StreamKind.START_COMPLETE,
8882        streamId,
8883        reason: wrapReason(reason)
8884      });
8885    });
8886  }
8887  #processStreamMessage(data) {
8888    const streamId = data.streamId,
8889      sourceName = this.sourceName,
8890      targetName = data.sourceName,
8891      comObj = this.comObj;
8892    const streamController = this.streamControllers[streamId],
8893      streamSink = this.streamSinks[streamId];
8894    switch (data.stream) {
8895      case StreamKind.START_COMPLETE:
8896        if (data.success) {
8897          streamController.startCall.resolve();
8898        } else {
8899          streamController.startCall.reject(wrapReason(data.reason));
8900        }
8901        break;
8902      case StreamKind.PULL_COMPLETE:
8903        if (data.success) {
8904          streamController.pullCall.resolve();
8905        } else {
8906          streamController.pullCall.reject(wrapReason(data.reason));
8907        }
8908        break;
8909      case StreamKind.PULL:
8910        if (!streamSink) {
8911          comObj.postMessage({
8912            sourceName,
8913            targetName,
8914            stream: StreamKind.PULL_COMPLETE,
8915            streamId,
8916            success: true
8917          });
8918          break;
8919        }
8920        if (streamSink.desiredSize <= 0 && data.desiredSize > 0) {
8921          streamSink.sinkCapability.resolve();
8922        }
8923        streamSink.desiredSize = data.desiredSize;
8924        new Promise(function (resolve) {
8925          resolve(streamSink.onPull?.());
8926        }).then(function () {
8927          comObj.postMessage({
8928            sourceName,
8929            targetName,
8930            stream: StreamKind.PULL_COMPLETE,
8931            streamId,
8932            success: true
8933          });
8934        }, function (reason) {
8935          comObj.postMessage({
8936            sourceName,
8937            targetName,
8938            stream: StreamKind.PULL_COMPLETE,
8939            streamId,
8940            reason: wrapReason(reason)
8941          });
8942        });
8943        break;
8944      case StreamKind.ENQUEUE:
8945        assert(streamController, "enqueue should have stream controller");
8946        if (streamController.isClosed) {
8947          break;
8948        }
8949        streamController.controller.enqueue(data.chunk);
8950        break;
8951      case StreamKind.CLOSE:
8952        assert(streamController, "close should have stream controller");
8953        if (streamController.isClosed) {
8954          break;
8955        }
8956        streamController.isClosed = true;
8957        streamController.controller.close();
8958        this.#deleteStreamController(streamController, streamId);
8959        break;
8960      case StreamKind.ERROR:
8961        assert(streamController, "error should have stream controller");
8962        streamController.controller.error(wrapReason(data.reason));
8963        this.#deleteStreamController(streamController, streamId);
8964        break;
8965      case StreamKind.CANCEL_COMPLETE:
8966        if (data.success) {
8967          streamController.cancelCall.resolve();
8968        } else {
8969          streamController.cancelCall.reject(wrapReason(data.reason));
8970        }
8971        this.#deleteStreamController(streamController, streamId);
8972        break;
8973      case StreamKind.CANCEL:
8974        if (!streamSink) {
8975          break;
8976        }
8977        new Promise(function (resolve) {
8978          resolve(streamSink.onCancel?.(wrapReason(data.reason)));
8979        }).then(function () {
8980          comObj.postMessage({
8981            sourceName,
8982            targetName,
8983            stream: StreamKind.CANCEL_COMPLETE,
8984            streamId,
8985            success: true
8986          });
8987        }, function (reason) {
8988          comObj.postMessage({
8989            sourceName,
8990            targetName,
8991            stream: StreamKind.CANCEL_COMPLETE,
8992            streamId,
8993            reason: wrapReason(reason)
8994          });
8995        });
8996        streamSink.sinkCapability.reject(wrapReason(data.reason));
8997        streamSink.isCancelled = true;
8998        delete this.streamSinks[streamId];
8999        break;
9000      default:
9001        throw new Error("Unexpected stream case");
9002    }
9003  }
9004  async #deleteStreamController(streamController, streamId) {
9005    await Promise.allSettled([streamController.startCall?.promise, streamController.pullCall?.promise, streamController.cancelCall?.promise]);
9006    delete this.streamControllers[streamId];
9007  }
9008  destroy() {
9009    this.#messageAC?.abort();
9010    this.#messageAC = null;
9011  }
9012}
9013
9014;// ./src/display/metadata.js
9015
9016class Metadata {
9017  #metadataMap;
9018  #data;
9019  constructor({
9020    parsedData,
9021    rawData
9022  }) {
9023    this.#metadataMap = parsedData;
9024    this.#data = rawData;
9025  }
9026  getRaw() {
9027    return this.#data;
9028  }
9029  get(name) {
9030    return this.#metadataMap.get(name) ?? null;
9031  }
9032  getAll() {
9033    return objectFromMap(this.#metadataMap);
9034  }
9035  has(name) {
9036    return this.#metadataMap.has(name);
9037  }
9038}
9039
9040;// ./src/display/optional_content_config.js
9041
9042
9043const INTERNAL = Symbol("INTERNAL");
9044class OptionalContentGroup {
9045  #isDisplay = false;
vendor: 13,465 bytes, lines 9046-9537
9046  #isPrint = false;
9047  #userSet = false;
9048  #visible = true;
9049  constructor(renderingIntent, {
9050    name,
9051    intent,
9052    usage,
9053    rbGroups
9054  }) {
9055    this.#isDisplay = !!(renderingIntent & RenderingIntentFlag.DISPLAY);
9056    this.#isPrint = !!(renderingIntent & RenderingIntentFlag.PRINT);
9057    this.name = name;
9058    this.intent = intent;
9059    this.usage = usage;
9060    this.rbGroups = rbGroups;
9061  }
9062  get visible() {
9063    if (this.#userSet) {
9064      return this.#visible;
9065    }
9066    if (!this.#visible) {
9067      return false;
9068    }
9069    const {
9070      print,
9071      view
9072    } = this.usage;
9073    if (this.#isDisplay) {
9074      return view?.viewState !== "OFF";
9075    } else if (this.#isPrint) {
9076      return print?.printState !== "OFF";
9077    }
9078    return true;
9079  }
9080  _setVisible(internal, visible, userSet = false) {
9081    if (internal !== INTERNAL) {
9082      unreachable("Internal method `_setVisible` called.");
9083    }
9084    this.#userSet = userSet;
9085    this.#visible = visible;
9086  }
9087}
9088class OptionalContentConfig {
9089  #cachedGetHash = null;
9090  #groups = new Map();
9091  #initialHash = null;
9092  #order = null;
9093  constructor(data, renderingIntent = RenderingIntentFlag.DISPLAY) {
9094    this.renderingIntent = renderingIntent;
9095    this.name = null;
9096    this.creator = null;
9097    if (data === null) {
9098      return;
9099    }
9100    this.name = data.name;
9101    this.creator = data.creator;
9102    this.#order = data.order;
9103    for (const group of data.groups) {
9104      this.#groups.set(group.id, new OptionalContentGroup(renderingIntent, group));
9105    }
9106    if (data.baseState === "OFF") {
9107      for (const group of this.#groups.values()) {
9108        group._setVisible(INTERNAL, false);
9109      }
9110    }
9111    for (const on of data.on) {
9112      this.#groups.get(on)._setVisible(INTERNAL, true);
9113    }
9114    for (const off of data.off) {
9115      this.#groups.get(off)._setVisible(INTERNAL, false);
9116    }
9117    this.#initialHash = this.getHash();
9118  }
9119  #evaluateVisibilityExpression(array) {
9120    const length = array.length;
9121    if (length < 2) {
9122      return true;
9123    }
9124    const operator = array[0];
9125    for (let i = 1; i < length; i++) {
9126      const element = array[i];
9127      let state;
9128      if (Array.isArray(element)) {
9129        state = this.#evaluateVisibilityExpression(element);
9130      } else if (this.#groups.has(element)) {
9131        state = this.#groups.get(element).visible;
9132      } else {
9133        warn(`Optional content group not found: ${element}`);
9134        return true;
9135      }
9136      switch (operator) {
9137        case "And":
9138          if (!state) {
9139            return false;
9140          }
9141          break;
9142        case "Or":
9143          if (state) {
9144            return true;
9145          }
9146          break;
9147        case "Not":
9148          return !state;
9149        default:
9150          return true;
9151      }
9152    }
9153    return operator === "And";
9154  }
9155  isVisible(group) {
9156    if (this.#groups.size === 0) {
9157      return true;
9158    }
9159    if (!group) {
9160      info("Optional content group not defined.");
9161      return true;
9162    }
9163    if (group.type === "OCG") {
9164      if (!this.#groups.has(group.id)) {
9165        warn(`Optional content group not found: ${group.id}`);
9166        return true;
9167      }
9168      return this.#groups.get(group.id).visible;
9169    } else if (group.type === "OCMD") {
9170      if (group.expression) {
9171        return this.#evaluateVisibilityExpression(group.expression);
9172      }
9173      if (!group.policy || group.policy === "AnyOn") {
9174        for (const id of group.ids) {
9175          if (!this.#groups.has(id)) {
9176            warn(`Optional content group not found: ${id}`);
9177            return true;
9178          }
9179          if (this.#groups.get(id).visible) {
9180            return true;
9181          }
9182        }
9183        return false;
9184      } else if (group.policy === "AllOn") {
9185        for (const id of group.ids) {
9186          if (!this.#groups.has(id)) {
9187            warn(`Optional content group not found: ${id}`);
9188            return true;
9189          }
9190          if (!this.#groups.get(id).visible) {
9191            return false;
9192          }
9193        }
9194        return true;
9195      } else if (group.policy === "AnyOff") {
9196        for (const id of group.ids) {
9197          if (!this.#groups.has(id)) {
9198            warn(`Optional content group not found: ${id}`);
9199            return true;
9200          }
9201          if (!this.#groups.get(id).visible) {
9202            return true;
9203          }
9204        }
9205        return false;
9206      } else if (group.policy === "AllOff") {
9207        for (const id of group.ids) {
9208          if (!this.#groups.has(id)) {
9209            warn(`Optional content group not found: ${id}`);
9210            return true;
9211          }
9212          if (this.#groups.get(id).visible) {
9213            return false;
9214          }
9215        }
9216        return true;
9217      }
9218      warn(`Unknown optional content policy ${group.policy}.`);
9219      return true;
9220    }
9221    warn(`Unknown group type ${group.type}.`);
9222    return true;
9223  }
9224  setVisibility(id, visible = true, preserveRB = true) {
9225    const group = this.#groups.get(id);
9226    if (!group) {
9227      warn(`Optional content group not found: ${id}`);
9228      return;
9229    }
9230    if (preserveRB && visible && group.rbGroups.length) {
9231      for (const rbGroup of group.rbGroups) {
9232        for (const otherId of rbGroup) {
9233          if (otherId !== id) {
9234            this.#groups.get(otherId)?._setVisible(INTERNAL, false, true);
9235          }
9236        }
9237      }
9238    }
9239    group._setVisible(INTERNAL, !!visible, true);
9240    this.#cachedGetHash = null;
9241  }
9242  setOCGState({
9243    state,
9244    preserveRB
9245  }) {
9246    let operator;
9247    for (const elem of state) {
9248      switch (elem) {
9249        case "ON":
9250        case "OFF":
9251        case "Toggle":
9252          operator = elem;
9253          continue;
9254      }
9255      const group = this.#groups.get(elem);
9256      if (!group) {
9257        continue;
9258      }
9259      switch (operator) {
9260        case "ON":
9261          this.setVisibility(elem, true, preserveRB);
9262          break;
9263        case "OFF":
9264          this.setVisibility(elem, false, preserveRB);
9265          break;
9266        case "Toggle":
9267          this.setVisibility(elem, !group.visible, preserveRB);
9268          break;
9269      }
9270    }
9271    this.#cachedGetHash = null;
9272  }
9273  get hasInitialVisibility() {
9274    return this.#initialHash === null || this.getHash() === this.#initialHash;
9275  }
9276  getOrder() {
9277    if (!this.#groups.size) {
9278      return null;
9279    }
9280    if (this.#order) {
9281      return this.#order.slice();
9282    }
9283    return [...this.#groups.keys()];
9284  }
9285  getGroups() {
9286    return this.#groups.size > 0 ? objectFromMap(this.#groups) : null;
9287  }
9288  getGroup(id) {
9289    return this.#groups.get(id) || null;
9290  }
9291  getHash() {
9292    if (this.#cachedGetHash !== null) {
9293      return this.#cachedGetHash;
9294    }
9295    const hash = new MurmurHash3_64();
9296    for (const [id, group] of this.#groups) {
9297      hash.update(`${id}:${group.visible}`);
9298    }
9299    return this.#cachedGetHash = hash.hexdigest();
9300  }
9301}
9302
9303;// ./src/display/transport_stream.js
9304
9305
9306class PDFDataTransportStream {
9307  constructor(pdfDataRangeTransport, {
9308    disableRange = false,
9309    disableStream = false
9310  }) {
9311    assert(pdfDataRangeTransport, 'PDFDataTransportStream - missing required "pdfDataRangeTransport" argument.');
9312    const {
9313      length,
9314      initialData,
9315      progressiveDone,
9316      contentDispositionFilename
9317    } = pdfDataRangeTransport;
9318    this._queuedChunks = [];
9319    this._progressiveDone = progressiveDone;
9320    this._contentDispositionFilename = contentDispositionFilename;
9321    if (initialData?.length > 0) {
9322      const buffer = initialData instanceof Uint8Array && initialData.byteLength === initialData.buffer.byteLength ? initialData.buffer : new Uint8Array(initialData).buffer;
9323      this._queuedChunks.push(buffer);
9324    }
9325    this._pdfDataRangeTransport = pdfDataRangeTransport;
9326    this._isStreamingSupported = !disableStream;
9327    this._isRangeSupported = !disableRange;
9328    this._contentLength = length;
9329    this._fullRequestReader = null;
9330    this._rangeReaders = [];
9331    pdfDataRangeTransport.addRangeListener((begin, chunk) => {
9332      this._onReceiveData({
9333        begin,
9334        chunk
9335      });
9336    });
9337    pdfDataRangeTransport.addProgressListener((loaded, total) => {
9338      this._onProgress({
9339        loaded,
9340        total
9341      });
9342    });
9343    pdfDataRangeTransport.addProgressiveReadListener(chunk => {
9344      this._onReceiveData({
9345        chunk
9346      });
9347    });
9348    pdfDataRangeTransport.addProgressiveDoneListener(() => {
9349      this._onProgressiveDone();
9350    });
9351    pdfDataRangeTransport.transportReady();
9352  }
9353  _onReceiveData({
9354    begin,
9355    chunk
9356  }) {
9357    const buffer = chunk instanceof Uint8Array && chunk.byteLength === chunk.buffer.byteLength ? chunk.buffer : new Uint8Array(chunk).buffer;
9358    if (begin === undefined) {
9359      if (this._fullRequestReader) {
9360        this._fullRequestReader._enqueue(buffer);
9361      } else {
9362        this._queuedChunks.push(buffer);
9363      }
9364    } else {
9365      const found = this._rangeReaders.some(function (rangeReader) {
9366        if (rangeReader._begin !== begin) {
9367          return false;
9368        }
9369        rangeReader._enqueue(buffer);
9370        return true;
9371      });
9372      assert(found, "_onReceiveData - no `PDFDataTransportStreamRangeReader` instance found.");
9373    }
9374  }
9375  get _progressiveDataLength() {
9376    return this._fullRequestReader?._loaded ?? 0;
9377  }
9378  _onProgress(evt) {
9379    if (evt.total === undefined) {
9380      this._rangeReaders[0]?.onProgress?.({
9381        loaded: evt.loaded
9382      });
9383    } else {
9384      this._fullRequestReader?.onProgress?.({
9385        loaded: evt.loaded,
9386        total: evt.total
9387      });
9388    }
9389  }
9390  _onProgressiveDone() {
9391    this._fullRequestReader?.progressiveDone();
9392    this._progressiveDone = true;
9393  }
9394  _removeRangeReader(reader) {
9395    const i = this._rangeReaders.indexOf(reader);
9396    if (i >= 0) {
9397      this._rangeReaders.splice(i, 1);
9398    }
9399  }
9400  getFullReader() {
9401    assert(!this._fullRequestReader, "PDFDataTransportStream.getFullReader can only be called once.");
9402    const queuedChunks = this._queuedChunks;
9403    this._queuedChunks = null;
9404    return new PDFDataTransportStreamReader(this, queuedChunks, this._progressiveDone, this._contentDispositionFilename);
9405  }
9406  getRangeReader(begin, end) {
9407    if (end <= this._progressiveDataLength) {
9408      return null;
9409    }
9410    const reader = new PDFDataTransportStreamRangeReader(this, begin, end);
9411    this._pdfDataRangeTransport.requestDataRange(begin, end);
9412    this._rangeReaders.push(reader);
9413    return reader;
9414  }
9415  cancelAllRequests(reason) {
9416    this._fullRequestReader?.cancel(reason);
9417    for (const reader of this._rangeReaders.slice(0)) {
9418      reader.cancel(reason);
9419    }
9420    this._pdfDataRangeTransport.abort();
9421  }
9422}
9423class PDFDataTransportStreamReader {
9424  constructor(stream, queuedChunks, progressiveDone = false, contentDispositionFilename = null) {
9425    this._stream = stream;
9426    this._done = progressiveDone || false;
9427    this._filename = isPdfFile(contentDispositionFilename) ? contentDispositionFilename : null;
9428    this._queuedChunks = queuedChunks || [];
9429    this._loaded = 0;
9430    for (const chunk of this._queuedChunks) {
9431      this._loaded += chunk.byteLength;
9432    }
9433    this._requests = [];
9434    this._headersReady = Promise.resolve();
9435    stream._fullRequestReader = this;
9436    this.onProgress = null;
9437  }
9438  _enqueue(chunk) {
9439    if (this._done) {
9440      return;
9441    }
9442    if (this._requests.length > 0) {
9443      const requestCapability = this._requests.shift();
9444      requestCapability.resolve({
9445        value: chunk,
9446        done: false
9447      });
9448    } else {
9449      this._queuedChunks.push(chunk);
9450    }
9451    this._loaded += chunk.byteLength;
9452  }
9453  get headersReady() {
9454    return this._headersReady;
9455  }
9456  get filename() {
9457    return this._filename;
9458  }
9459  get isRangeSupported() {
9460    return this._stream._isRangeSupported;
9461  }
9462  get isStreamingSupported() {
9463    return this._stream._isStreamingSupported;
9464  }
9465  get contentLength() {
9466    return this._stream._contentLength;
9467  }
9468  async read() {
9469    if (this._queuedChunks.length > 0) {
9470      const chunk = this._queuedChunks.shift();
9471      return {
9472        value: chunk,
9473        done: false
9474      };
9475    }
9476    if (this._done) {
9477      return {
9478        value: undefined,
9479        done: true
9480      };
9481    }
9482    const requestCapability = Promise.withResolvers();
9483    this._requests.push(requestCapability);
9484    return requestCapability.promise;
9485  }
9486  cancel(reason) {
9487    this._done = true;
9488    for (const requestCapability of this._requests) {
9489      requestCapability.resolve({
9490        value: undefined,
9491        done: true
9492      });
9493    }
9494    this._requests.length = 0;
9495  }
9496  progressiveDone() {
9497    if (this._done) {
9498      return;
9499    }
9500    this._done = true;
9501  }
9502}
9503class PDFDataTransportStreamRangeReader {
9504  constructor(stream, begin, end) {
9505    this._stream = stream;
9506    this._begin = begin;
9507    this._end = end;
9508    this._queuedChunk = null;
9509    this._requests = [];
9510    this._done = false;
9511    this.onProgress = null;
9512  }
9513  _enqueue(chunk) {
9514    if (this._done) {
9515      return;
9516    }
9517    if (this._requests.length === 0) {
9518      this._queuedChunk = chunk;
9519    } else {
9520      const requestsCapability = this._requests.shift();
9521      requestsCapability.resolve({
9522        value: chunk,
9523        done: false
9524      });
9525      for (const requestCapability of this._requests) {
9526        requestCapability.resolve({
9527          value: undefined,
9528          done: true
9529        });
9530      }
9531      this._requests.length = 0;
9532    }
9533    this._done = true;
9534    this._stream._removeRangeReader(this);
9535  }
9536  get isStreamingSupported() {
9537    return false;
vendor: 4,523 bytes, lines 9538-9692
9538  }
9539  async read() {
9540    if (this._queuedChunk) {
9541      const chunk = this._queuedChunk;
9542      this._queuedChunk = null;
9543      return {
9544        value: chunk,
9545        done: false
9546      };
9547    }
9548    if (this._done) {
9549      return {
9550        value: undefined,
9551        done: true
9552      };
9553    }
9554    const requestCapability = Promise.withResolvers();
9555    this._requests.push(requestCapability);
9556    return requestCapability.promise;
9557  }
9558  cancel(reason) {
9559    this._done = true;
9560    for (const requestCapability of this._requests) {
9561      requestCapability.resolve({
9562        value: undefined,
9563        done: true
9564      });
9565    }
9566    this._requests.length = 0;
9567    this._stream._removeRangeReader(this);
9568  }
9569}
9570
9571;// ./src/display/content_disposition.js
9572
9573function getFilenameFromContentDispositionHeader(contentDisposition) {
9574  let needsEncodingFixup = true;
9575  let tmp = toParamRegExp("filename\\*", "i").exec(contentDisposition);
9576  if (tmp) {
9577    tmp = tmp[1];
9578    let filename = rfc2616unquote(tmp);
9579    filename = unescape(filename);
9580    filename = rfc5987decode(filename);
9581    filename = rfc2047decode(filename);
9582    return fixupEncoding(filename);
9583  }
9584  tmp = rfc2231getparam(contentDisposition);
9585  if (tmp) {
9586    const filename = rfc2047decode(tmp);
9587    return fixupEncoding(filename);
9588  }
9589  tmp = toParamRegExp("filename", "i").exec(contentDisposition);
9590  if (tmp) {
9591    tmp = tmp[1];
9592    let filename = rfc2616unquote(tmp);
9593    filename = rfc2047decode(filename);
9594    return fixupEncoding(filename);
9595  }
9596  function toParamRegExp(attributePattern, flags) {
9597    return new RegExp("(?:^|;)\\s*" + attributePattern + "\\s*=\\s*" + "(" + '[^";\\s][^;\\s]*' + "|" + '"(?:[^"\\\\]|\\\\"?)+"?' + ")", flags);
9598  }
9599  function textdecode(encoding, value) {
9600    if (encoding) {
9601      if (!/^[\x00-\xFF]+$/.test(value)) {
9602        return value;
9603      }
9604      try {
9605        const decoder = new TextDecoder(encoding, {
9606          fatal: true
9607        });
9608        const buffer = stringToBytes(value);
9609        value = decoder.decode(buffer);
9610        needsEncodingFixup = false;
9611      } catch {}
9612    }
9613    return value;
9614  }
9615  function fixupEncoding(value) {
9616    if (needsEncodingFixup && /[\x80-\xff]/.test(value)) {
9617      value = textdecode("utf-8", value);
9618      if (needsEncodingFixup) {
9619        value = textdecode("iso-8859-1", value);
9620      }
9621    }
9622    return value;
9623  }
9624  function rfc2231getparam(contentDispositionStr) {
9625    const matches = [];
9626    let match;
9627    const iter = toParamRegExp("filename\\*((?!0\\d)\\d+)(\\*?)", "ig");
9628    while ((match = iter.exec(contentDispositionStr)) !== null) {
9629      let [, n, quot, part] = match;
9630      n = parseInt(n, 10);
9631      if (n in matches) {
9632        if (n === 0) {
9633          break;
9634        }
9635        continue;
9636      }
9637      matches[n] = [quot, part];
9638    }
9639    const parts = [];
9640    for (let n = 0; n < matches.length; ++n) {
9641      if (!(n in matches)) {
9642        break;
9643      }
9644      let [quot, part] = matches[n];
9645      part = rfc2616unquote(part);
9646      if (quot) {
9647        part = unescape(part);
9648        if (n === 0) {
9649          part = rfc5987decode(part);
9650        }
9651      }
9652      parts.push(part);
9653    }
9654    return parts.join("");
9655  }
9656  function rfc2616unquote(value) {
9657    if (value.startsWith('"')) {
9658      const parts = value.slice(1).split('\\"');
9659      for (let i = 0; i < parts.length; ++i) {
9660        const quotindex = parts[i].indexOf('"');
9661        if (quotindex !== -1) {
9662          parts[i] = parts[i].slice(0, quotindex);
9663          parts.length = i + 1;
9664        }
9665        parts[i] = parts[i].replaceAll(/\\(.)/g, "$1");
9666      }
9667      value = parts.join('"');
9668    }
9669    return value;
9670  }
9671  function rfc5987decode(extvalue) {
9672    const encodingend = extvalue.indexOf("'");
9673    if (encodingend === -1) {
9674      return extvalue;
9675    }
9676    const encoding = extvalue.slice(0, encodingend);
9677    const langvalue = extvalue.slice(encodingend + 1);
9678    const value = langvalue.replace(/^[^']*'/, "");
9679    return textdecode(encoding, value);
9680  }
9681  function rfc2047decode(value) {
9682    if (!value.startsWith("=?") || /[\x00-\x19\x80-\xff]/.test(value)) {
9683      return value;
9684    }
9685    return value.replaceAll(/=\?([\w-]*)\?([QqBb])\?((?:[^?]|\?(?!=))*)\?=/g, function (matches, charset, encoding, text) {
9686      if (encoding === "q" || encoding === "Q") {
9687        text = text.replaceAll("_", " ");
9688        text = text.replaceAll(/=([0-9a-fA-F]{2})/g, function (match, hex) {
9689          return String.fromCharCode(parseInt(hex, 16));
9690        });
9691        return textdecode(charset, text);
9692      }
vendor: 6,807 bytes, lines 9693-9927
9693      try {
9694        text = atob(text);
9695      } catch {}
9696      return textdecode(charset, text);
9697    });
9698  }
9699  return "";
9700}
9701
9702;// ./src/display/network_utils.js
9703
9704
9705
9706function createHeaders(isHttp, httpHeaders) {
9707  const headers = new Headers();
9708  if (!isHttp || !httpHeaders || typeof httpHeaders !== "object") {
9709    return headers;
9710  }
9711  for (const key in httpHeaders) {
9712    const val = httpHeaders[key];
9713    if (val !== undefined) {
9714      headers.append(key, val);
9715    }
9716  }
9717  return headers;
9718}
9719function validateRangeRequestCapabilities({
9720  responseHeaders,
9721  isHttp,
9722  rangeChunkSize,
9723  disableRange
9724}) {
9725  const returnValues = {
9726    allowRangeRequests: false,
9727    suggestedLength: undefined
9728  };
9729  const length = parseInt(responseHeaders.get("Content-Length"), 10);
9730  if (!Number.isInteger(length)) {
9731    return returnValues;
9732  }
9733  returnValues.suggestedLength = length;
9734  if (length <= 2 * rangeChunkSize) {
9735    return returnValues;
9736  }
9737  if (disableRange || !isHttp) {
9738    return returnValues;
9739  }
9740  if (responseHeaders.get("Accept-Ranges") !== "bytes") {
9741    return returnValues;
9742  }
9743  const contentEncoding = responseHeaders.get("Content-Encoding") || "identity";
9744  if (contentEncoding !== "identity") {
9745    return returnValues;
9746  }
9747  returnValues.allowRangeRequests = true;
9748  return returnValues;
9749}
9750function extractFilenameFromHeader(responseHeaders) {
9751  const contentDisposition = responseHeaders.get("Content-Disposition");
9752  if (contentDisposition) {
9753    let filename = getFilenameFromContentDispositionHeader(contentDisposition);
9754    if (filename.includes("%")) {
9755      try {
9756        filename = decodeURIComponent(filename);
9757      } catch {}
9758    }
9759    if (isPdfFile(filename)) {
9760      return filename;
9761    }
9762  }
9763  return null;
9764}
9765function createResponseStatusError(status, url) {
9766  if (status === 404 || status === 0 && url.startsWith("file:")) {
9767    return new MissingPDFException('Missing PDF "' + url + '".');
9768  }
9769  return new UnexpectedResponseException(`Unexpected server response (${status}) while retrieving PDF "${url}".`, status);
9770}
9771function validateResponseStatus(status) {
9772  return status === 200 || status === 206;
9773}
9774
9775;// ./src/display/fetch_stream.js
9776
9777
9778function createFetchOptions(headers, withCredentials, abortController) {
9779  return {
9780    method: "GET",
9781    headers,
9782    signal: abortController.signal,
9783    mode: "cors",
9784    credentials: withCredentials ? "include" : "same-origin",
9785    redirect: "follow"
9786  };
9787}
9788function getArrayBuffer(val) {
9789  if (val instanceof Uint8Array) {
9790    return val.buffer;
9791  }
9792  if (val instanceof ArrayBuffer) {
9793    return val;
9794  }
9795  warn(`getArrayBuffer - unexpected data format: ${val}`);
9796  return new Uint8Array(val).buffer;
9797}
9798class PDFFetchStream {
9799  constructor(source) {
9800    this.source = source;
9801    this.isHttp = /^https?:/i.test(source.url);
9802    this.headers = createHeaders(this.isHttp, source.httpHeaders);
9803    this._fullRequestReader = null;
9804    this._rangeRequestReaders = [];
9805  }
9806  get _progressiveDataLength() {
9807    return this._fullRequestReader?._loaded ?? 0;
9808  }
9809  getFullReader() {
9810    assert(!this._fullRequestReader, "PDFFetchStream.getFullReader can only be called once.");
9811    this._fullRequestReader = new PDFFetchStreamReader(this);
9812    return this._fullRequestReader;
9813  }
9814  getRangeReader(begin, end) {
9815    if (end <= this._progressiveDataLength) {
9816      return null;
9817    }
9818    const reader = new PDFFetchStreamRangeReader(this, begin, end);
9819    this._rangeRequestReaders.push(reader);
9820    return reader;
9821  }
9822  cancelAllRequests(reason) {
9823    this._fullRequestReader?.cancel(reason);
9824    for (const reader of this._rangeRequestReaders.slice(0)) {
9825      reader.cancel(reason);
9826    }
9827  }
9828}
9829class PDFFetchStreamReader {
9830  constructor(stream) {
9831    this._stream = stream;
9832    this._reader = null;
9833    this._loaded = 0;
9834    this._filename = null;
9835    const source = stream.source;
9836    this._withCredentials = source.withCredentials || false;
9837    this._contentLength = source.length;
9838    this._headersCapability = Promise.withResolvers();
9839    this._disableRange = source.disableRange || false;
9840    this._rangeChunkSize = source.rangeChunkSize;
9841    if (!this._rangeChunkSize && !this._disableRange) {
9842      this._disableRange = true;
9843    }
9844    this._abortController = new AbortController();
9845    this._isStreamingSupported = !source.disableStream;
9846    this._isRangeSupported = !source.disableRange;
9847    const headers = new Headers(stream.headers);
9848    const url = source.url;
9849    fetch(url, createFetchOptions(headers, this._withCredentials, this._abortController)).then(response => {
9850      if (!validateResponseStatus(response.status)) {
9851        throw createResponseStatusError(response.status, url);
9852      }
9853      this._reader = response.body.getReader();
9854      this._headersCapability.resolve();
9855      const responseHeaders = response.headers;
9856      const {
9857        allowRangeRequests,
9858        suggestedLength
9859      } = validateRangeRequestCapabilities({
9860        responseHeaders,
9861        isHttp: stream.isHttp,
9862        rangeChunkSize: this._rangeChunkSize,
9863        disableRange: this._disableRange
9864      });
9865      this._isRangeSupported = allowRangeRequests;
9866      this._contentLength = suggestedLength || this._contentLength;
9867      this._filename = extractFilenameFromHeader(responseHeaders);
9868      if (!this._isStreamingSupported && this._isRangeSupported) {
9869        this.cancel(new AbortException("Streaming is disabled."));
9870      }
9871    }).catch(this._headersCapability.reject);
9872    this.onProgress = null;
9873  }
9874  get headersReady() {
9875    return this._headersCapability.promise;
9876  }
9877  get filename() {
9878    return this._filename;
9879  }
9880  get contentLength() {
9881    return this._contentLength;
9882  }
9883  get isRangeSupported() {
9884    return this._isRangeSupported;
9885  }
9886  get isStreamingSupported() {
9887    return this._isStreamingSupported;
9888  }
9889  async read() {
9890    await this._headersCapability.promise;
9891    const {
9892      value,
9893      done
9894    } = await this._reader.read();
9895    if (done) {
9896      return {
9897        value,
9898        done
9899      };
9900    }
9901    this._loaded += value.byteLength;
9902    this.onProgress?.({
9903      loaded: this._loaded,
9904      total: this._contentLength
9905    });
9906    return {
9907      value: getArrayBuffer(value),
9908      done: false
9909    };
9910  }
9911  cancel(reason) {
9912    this._reader?.cancel(reason);
9913    this._abortController.abort();
9914  }
9915}
9916class PDFFetchStreamRangeReader {
9917  constructor(stream, begin, end) {
9918    this._stream = stream;
9919    this._reader = null;
9920    this._loaded = 0;
9921    const source = stream.source;
9922    this._withCredentials = source.withCredentials || false;
9923    this._readCapability = Promise.withResolvers();
9924    this._isStreamingSupported = !source.disableStream;
9925    this._abortController = new AbortController();
9926    const headers = new Headers(stream.headers);
9927    headers.append("Range", `bytes=${begin}
9927-${end - 1}`);
9928    const url = source.url;
9929    fetch(url, createFetchOptions(headers, this._withCredentials, this._abortController)).then(response => {
9930      if (!validateResponseStatus(response.status)) {
9931        throw createResponseStatusError(response.status, url);
9932      }
9933      this._readCapability.resolve();
9934      this._reader = response.body.getReader();
9935    }).catch(this._readCapability.reject);
9936    this.onProgress = null;
9937  }
9938  get isStreamingSupported() {
9939    return this._isStreamingSupported;
9940  }
9941  async read() {
9942    await this._readCapability.promise;
9943    const {
9944      value,
9945      done
9946    } = await this._reader.read();
9947    if (done) {
9948      return {
9949        value,
9950        done
9951      };
9952    }
9953    this._loaded += value.byteLength;
9954    this.onProgress?.({
9955      loaded: this._loaded
9956    });
9957    return {
9958      value: getArrayBuffer(value),
9959      done: false
9960    };
9961  }
9962  cancel(reason) {
9963    this._reader?.cancel(reason);
9964    this._abortController.abort();
9965  }
9966}
9967
9968;// ./src/display/network.js
9969
9970
9971const OK_RESPONSE = 200;
9972const PARTIAL_CONTENT_RESPONSE = 206;
9973function network_getArrayBuffer(xhr) {
9974  const data = xhr.response;
9975  if (typeof data !== "string") {
9976    return data;
9977  }
9978  return stringToBytes(data).buffer;
9979}
9980class NetworkManager {
9981  constructor({
9982    url,
9983    httpHeaders,
9984    withCredentials
9985  }) {
9986    this.url = url;
9987    this.isHttp = /^https?:/i.test(url);
9988    this.headers = createHeaders(this.isHttp, httpHeaders);
9989    this.withCredentials = withCredentials || false;
9990    this.currXhrId = 0;
9991    this.pendingRequests = Object.create(null);
9992  }
9993  requestRange(begin, end, listeners) {
9994    const args = {
9995      begin,
9996      end
9997    };
9998    for (const prop in listeners) {
9999      args[prop] = listeners[prop];
10000    }
10001    return this.request(args);
10002  }
10003  requestFull(listeners) {
10004    return this.request(listeners);
10005  }
10006  request(args) {
10007    const xhr = new XMLHttpRequest();
10008    const xhrId = this.currXhrId++;
10009    const pendingRequest = this.pendingRequests[xhrId] = {
10010      xhr
10011    };
10012    xhr.open("GET", this.url);
10013    xhr.withCredentials = this.withCredentials;
10014    for (const [key, val] of this.headers) {
10015      xhr.setRequestHeader(key, val);
10016    }
10017    if (this.isHttp && "begin" in args && "end" in args) {
10018      xhr.setRequestHeader("Range", `bytes=${args.begin}-${args.end - 1}`);
10019      pendingRequest.expectedStatus = PARTIAL_CONTENT_RESPONSE;
10020    } else {
10021      pendingRequest.expectedStatus = OK_RESPONSE;
10022    }
10023    xhr.responseType = "arraybuffer";
10024    if (args.onError) {
10025      xhr.onerror = function (evt) {
10026        args.onError(xhr.status);
10027      };
10028    }
10029    xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
10030    xhr.onprogress = this.onProgress.bind(this, xhrId);
10031    pendingRequest.onHeadersReceived = args.onHeadersReceived;
10032    pendingRequest.onDone = args.onDone;
10033    pendingRequest.onError = args.onError;
10034    pendingRequest.onProgress = args.onProgress;
10035    xhr.send(null);
10036    return xhrId;
10037  }
10038  onProgress(xhrId, evt) {
10039    const pendingRequest = this.pendingRequests[xhrId];
10040    if (!pendingRequest) {
10041      return;
10042    }
10043    pendingRequest.onProgress?.(evt);
10044  }
10045  onStateChange(xhrId, evt) {
10046    const pendingRequest = this.pendingRequests[xhrId];
10047    if (!pendingRequest) {
10048      return;
10049    }
10050    const xhr = pendingRequest.xhr;
10051    if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {
10052      pendingRequest.onHeadersReceived();
10053      delete pendingRequest.onHeadersReceived;
10054    }
10055    if (xhr.readyState !== 4) {
10056      return;
10057    }
10058    if (!(xhrId in this.pendingRequests)) {
10059      return;
10060    }
10061    delete this.pendingRequests[xhrId];
10062    if (xhr.status === 0 && this.isHttp) {
10063      pendingRequest.onError?.(xhr.status);
10064      return;
10065    }
10066    const xhrStatus = xhr.status || OK_RESPONSE;
10067    const ok_response_on_range_request = xhrStatus === OK_RESPONSE && pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;
10068    if (!ok_response_on_range_request && xhrStatus !== pendingRequest.expectedStatus) {
10069      pendingRequest.onError?.(xhr.status);
10070      return;
10071    }
10072    const chunk = network_getArrayBuffer(xhr);
10073    if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
10074      const rangeHeader = xhr.getResponseHeader("Content-Range");
10075      const matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
10076      pendingRequest.onDone({
10077        begin: parseInt(matches[1], 10),
10078        chunk
10079      });
10080    } else if (chunk) {
10081      pendingRequest.onDone({
10082        begin: 0,
10083        chunk
10084      });
10085    } else {
10086      pendingRequest.onError?.(xhr.status);
10087    }
10088  }
10089  getRequestXhr(xhrId) {
10090    return this.pendingRequests[xhrId].xhr;
10091  }
10092  isPendingRequest(xhrId) {
10093    return xhrId in this.pendingRequests;
10094  }
vendor: 5,309 bytes, lines 10095-10271
10095  abortRequest(xhrId) {
10096    const xhr = this.pendingRequests[xhrId].xhr;
10097    delete this.pendingRequests[xhrId];
10098    xhr.abort();
10099  }
10100}
10101class PDFNetworkStream {
10102  constructor(source) {
10103    this._source = source;
10104    this._manager = new NetworkManager(source);
10105    this._rangeChunkSize = source.rangeChunkSize;
10106    this._fullRequestReader = null;
10107    this._rangeRequestReaders = [];
10108  }
10109  _onRangeRequestReaderClosed(reader) {
10110    const i = this._rangeRequestReaders.indexOf(reader);
10111    if (i >= 0) {
10112      this._rangeRequestReaders.splice(i, 1);
10113    }
10114  }
10115  getFullReader() {
10116    assert(!this._fullRequestReader, "PDFNetworkStream.getFullReader can only be called once.");
10117    this._fullRequestReader = new PDFNetworkStreamFullRequestReader(this._manager, this._source);
10118    return this._fullRequestReader;
10119  }
10120  getRangeReader(begin, end) {
10121    const reader = new PDFNetworkStreamRangeRequestReader(this._manager, begin, end);
10122    reader.onClosed = this._onRangeRequestReaderClosed.bind(this);
10123    this._rangeRequestReaders.push(reader);
10124    return reader;
10125  }
10126  cancelAllRequests(reason) {
10127    this._fullRequestReader?.cancel(reason);
10128    for (const reader of this._rangeRequestReaders.slice(0)) {
10129      reader.cancel(reason);
10130    }
10131  }
10132}
10133class PDFNetworkStreamFullRequestReader {
10134  constructor(manager, source) {
10135    this._manager = manager;
10136    const args = {
10137      onHeadersReceived: this._onHeadersReceived.bind(this),
10138      onDone: this._onDone.bind(this),
10139      onError: this._onError.bind(this),
10140      onProgress: this._onProgress.bind(this)
10141    };
10142    this._url = source.url;
10143    this._fullRequestId = manager.requestFull(args);
10144    this._headersCapability = Promise.withResolvers();
10145    this._disableRange = source.disableRange || false;
10146    this._contentLength = source.length;
10147    this._rangeChunkSize = source.rangeChunkSize;
10148    if (!this._rangeChunkSize && !this._disableRange) {
10149      this._disableRange = true;
10150    }
10151    this._isStreamingSupported = false;
10152    this._isRangeSupported = false;
10153    this._cachedChunks = [];
10154    this._requests = [];
10155    this._done = false;
10156    this._storedError = undefined;
10157    this._filename = null;
10158    this.onProgress = null;
10159  }
10160  _onHeadersReceived() {
10161    const fullRequestXhrId = this._fullRequestId;
10162    const fullRequestXhr = this._manager.getRequestXhr(fullRequestXhrId);
10163    const responseHeaders = new Headers(fullRequestXhr.getAllResponseHeaders().trim().split(/[\r\n]+/).map(x => {
10164      const [key, ...val] = x.split(": ");
10165      return [key, val.join(": ")];
10166    }));
10167    const {
10168      allowRangeRequests,
10169      suggestedLength
10170    } = validateRangeRequestCapabilities({
10171      responseHeaders,
10172      isHttp: this._manager.isHttp,
10173      rangeChunkSize: this._rangeChunkSize,
10174      disableRange: this._disableRange
10175    });
10176    if (allowRangeRequests) {
10177      this._isRangeSupported = true;
10178    }
10179    this._contentLength = suggestedLength || this._contentLength;
10180    this._filename = extractFilenameFromHeader(responseHeaders);
10181    if (this._isRangeSupported) {
10182      this._manager.abortRequest(fullRequestXhrId);
10183    }
10184    this._headersCapability.resolve();
10185  }
10186  _onDone(data) {
10187    if (data) {
10188      if (this._requests.length > 0) {
10189        const requestCapability = this._requests.shift();
10190        requestCapability.resolve({
10191          value: data.chunk,
10192          done: false
10193        });
10194      } else {
10195        this._cachedChunks.push(data.chunk);
10196      }
10197    }
10198    this._done = true;
10199    if (this._cachedChunks.length > 0) {
10200      return;
10201    }
10202    for (const requestCapability of this._requests) {
10203      requestCapability.resolve({
10204        value: undefined,
10205        done: true
10206      });
10207    }
10208    this._requests.length = 0;
10209  }
10210  _onError(status) {
10211    this._storedError = createResponseStatusError(status, this._url);
10212    this._headersCapability.reject(this._storedError);
10213    for (const requestCapability of this._requests) {
10214      requestCapability.reject(this._storedError);
10215    }
10216    this._requests.length = 0;
10217    this._cachedChunks.length = 0;
10218  }
10219  _onProgress(evt) {
10220    this.onProgress?.({
10221      loaded: evt.loaded,
10222      total: evt.lengthComputable ? evt.total : this._contentLength
10223    });
10224  }
10225  get filename() {
10226    return this._filename;
10227  }
10228  get isRangeSupported() {
10229    return this._isRangeSupported;
10230  }
10231  get isStreamingSupported() {
10232    return this._isStreamingSupported;
10233  }
10234  get contentLength() {
10235    return this._contentLength;
10236  }
10237  get headersReady() {
10238    return this._headersCapability.promise;
10239  }
10240  async read() {
10241    if (this._storedError) {
10242      throw this._storedError;
10243    }
10244    if (this._cachedChunks.length > 0) {
10245      const chunk = this._cachedChunks.shift();
10246      return {
10247        value: chunk,
10248        done: false
10249      };
10250    }
10251    if (this._done) {
10252      return {
10253        value: undefined,
10254        done: true
10255      };
10256    }
10257    const requestCapability = Promise.withResolvers();
10258    this._requests.push(requestCapability);
10259    return requestCapability.promise;
10260  }
10261  cancel(reason) {
10262    this._done = true;
10263    this._headersCapability.reject(reason);
10264    for (const requestCapability of this._requests) {
10265      requestCapability.resolve({
10266        value: undefined,
10267        done: true
10268      });
10269    }
10270    this._requests.length = 0;
10271    if (this._manager.isPendingRequest(this._fullRequestId)) {
10272      this._manager.abortRequest(this._fullRequestId);
10273    }
10274    this._fullRequestReader = null;
10275  }
10276}
10277class PDFNetworkStreamRangeRequestReader {
10278  constructor(manager, begin, end) {
10279    this._manager = manager;
10280    const args = {
10281      onDone: this._onDone.bind(this),
10282      onError: this._onError.bind(this),
10283      onProgress: this._onProgress.bind(this)
10284    };
10285    this._url = manager.url;
10286    this._requestId = manager.requestRange(begin, end, args);
10287    this._requests = [];
10288    this._queuedChunk = null;
10289    this._done = false;
10290    this._storedError = undefined;
10291    this.onProgress = null;
10292    this.onClosed = null;
10293  }
10294  _close() {
10295    this.onClosed?.(this);
10296  }
10297  _onDone(data) {
10298    const chunk = data.chunk;
10299    if (this._requests.length > 0) {
10300      const requestCapability = this._requests.shift();
10301      requestCapability.resolve({
10302        value: chunk,
10303        done: false
10304      });
10305    } else {
10306      this._queuedChunk = chunk;
10307    }
10308    this._done = true;
10309    for (const requestCapability of this._requests) {
10310      requestCapability.resolve({
10311        value: undefined,
10312        done: true
10313      });
10314    }
10315    this._requests.length = 0;
10316    this._close();
10317  }
10318  _onError(status) {
10319    this._storedError = createResponseStatusError(status, this._url);
10320    for (const requestCapability of this._requests) {
10321      requestCapability.reject(this._storedError);
10322    }
10323    this._requests.length = 0;
10324    this._queuedChunk = null;
10325  }
10326  _onProgress(evt) {
10327    if (!this.isStreamingSupported) {
10328      this.onProgress?.({
10329        loaded: evt.loaded
10330      });
10331    }
10332  }
10333  get isStreamingSupported() {
10334    return false;
10335  }
10336  async read() {
10337    if (this._storedError) {
10338      throw this._storedError;
10339    }
10340    if (this._queuedChunk !== null) {
10341      const chunk = this._queuedChunk;
10342      this._queuedChunk = null;
10343      return {
10344        value: chunk,
10345        done: false
10346      };
10347    }
10348    if (this._done) {
10349      return {
10350        value: undefined,
10351        done: true
10352      };
10353    }
10354    const requestCapability = Promise.withResolvers();
10355    this._requests.push(requestCapability);
10356    return requestCapability.promise;
10357  }
10358  cancel(reason) {
10359    this._done = true;
10360    for (const requestCapability of this._requests) {
10361      requestCapability.resolve({
10362        value: undefined,
10363        done: true
10364      });
10365    }
10366    this._requests.length = 0;
10367    if (this._manager.isPendingRequest(this._requestId)) {
10368      this._manager.abortRequest(this._requestId);
10369    }
10370    this._close();
10371  }
10372}
10373
10374;// ./src/display/node_stream.js
10375
10376
10377
10378const urlRegex = /^[a-z][a-z0-9\-+.]+:/i;
10379function parseUrlOrPath(sourceUrl) {
10380  if (urlRegex.test(sourceUrl)) {
10381    return new URL(sourceUrl);
10382  }
10383  const url = NodePackages.get("url");
10384  return new URL(url.pathToFileURL(sourceUrl));
10385}
10386function createRequest(url, headers, callback) {
10387  if (url.protocol === "http:") {
10388    const http = NodePackages.get("http");
10389    return http.request(url, {
10390      headers
10391    }, callback);
10392  }
10393  const https = NodePackages.get("https");
10394  return https.request(url, {
10395    headers
10396  }, callback);
10397}
10398class PDFNodeStream {
10399  constructor(source) {
10400    this.source = source;
10401    this.url = parseUrlOrPath(source.url);
10402    this.isHttp = this.url.protocol === "http:" || this.url.protocol === "https:";
10403    this.isFsUrl = this.url.protocol === "file:";
10404    this.headers = createHeaders(this.isHttp, source.httpHeaders);
10405    this._fullRequestReader = null;
10406    this._rangeRequestReaders = [];
10407  }
10408  get _progressiveDataLength() {
10409    return this._fullRequestReader?._loaded ?? 0;
10410  }
10411  getFullReader() {
10412    assert(!this._fullRequestReader, "PDFNodeStream.getFullReader can only be called once.");
10413    this._fullRequestReader = this.isFsUrl ? new PDFNodeStreamFsFullReader(this) : new PDFNodeStreamFullReader(this);
10414    return this._fullRequestReader;
10415  }
10416  getRangeReader(start, end) {
10417    if (end <= this._progressiveDataLength) {
10418      return null;
10419    }
10420    const rangeReader = this.isFsUrl ? new PDFNodeStreamFsRangeReader(this, start, end) : new PDFNodeStreamRangeReader(this, start, end);
10421    this._rangeRequestReaders.push(rangeReader);
10422    return rangeReader;
10423  }
10424  cancelAllRequests(reason) {
10425    this._fullRequestReader?.cancel(reason);
10426    for (const reader of this._rangeRequestReaders.slice(0)) {
10427      reader.cancel(reason);
10428    }
10429  }
10430}
10431class BaseFullReader {
10432  constructor(stream) {
10433    this._url = stream.url;
10434    this._done = false;
10435    this._storedError = null;
10436    this.onProgress = null;
10437    const source = stream.source;
10438    this._contentLength = source.length;
10439    this._loaded = 0;
10440    this._filename = null;
10441    this._disableRange = source.disableRange || false;
10442    this._rangeChunkSize = source.rangeChunkSize;
10443    if (!this._rangeChunkSize && !this._disableRange) {
10444      this._disableRange = true;
10445    }
10446    this._isStreamingSupported = !source.disableStream;
10447    this._isRangeSupported = !source.disableRange;
10448    this._readableStream = null;
10449    this._readCapability = Promise.withResolvers();
10450    this._headersCapability = Promise.withResolvers();
10451  }
10452  get headersReady() {
10453    return this._headersCapability.promise;
10454  }
10455  get filename() {
10456    return this._filename;
10457  }
10458  get contentLength() {
10459    return this._contentLength;
10460  }
10461  get isRangeSupported() {
10462    return this._isRangeSupported;
10463  }
10464  get isStreamingSupported() {
10465    return this._isStreamingSupported;
10466  }
10467  async read() {
10468    await this._readCapability.promise;
10469    if (this._done) {
10470      return {
10471        value: undefined,
10472        done: true
10473      };
10474    }
10475    if (this._storedError) {
10476      throw this._storedError;
10477    }
10478    const chunk = this._readableStream.read();
10479    if (chunk === null) {
10480      this._readCapability = Promise.withResolvers();
10481      return this.read();
10482    }
10483    this._loaded += chunk.length;
10484    this.onProgress?.({
10485      loaded: this._loaded,
10486      total: this._contentLength
10487    });
10488    const buffer = new Uint8Array(chunk).buffer;
10489    return {
10490      value: buffer,
10491      done: false
10492    };
10493  }
10494  cancel(reason) {
10495    if (!this._readableStream) {
10496      this._error(reason);
10497      return;
10498    }
10499    this._readableStream.destroy(reason);
10500  }
10501  _error(reason) {
10502    this._storedError = reason;
10503    this._readCapability.resolve();
10504  }
10505  _setReadableStream(readableStream) {
10506    this._readableStream = readableStream;
10507    readableStream.on("readable", () => {
10508      this._readCapability.resolve();
10509    });
10510    readableStream.on("end", () => {
10511      readableStream.destroy();
10512      this._done = true;
10513      this._readCapability.resolve();
10514    });
10515    readableStream.on("error", reason => {
10516      this._error(reason);
10517    });
10518    if (!this._isStreamingSupported && this._isRangeSupported) {
10519      this._error(new AbortException("streaming is disabled"));
10520    }
10521    if (this._storedError) {
10522      this._readableStream.destroy(this._storedError);
10523    }
10524  }
10525}
10526class BaseRangeReader {
10527  constructor(stream) {
10528    this._url = stream.url;
10529    this._done = false;
10530    this._storedError = null;
10531    this.onProgress = null;
10532    this._loaded = 0;
10533    this._readableStream = null;
10534    this._readCapability = Promise.withResolvers();
10535    const source = stream.source;
10536    this._isStreamingSupported = !source.disableStream;
10537  }
10538  get isStreamingSupported() {
10539    return this._isStreamingSupported;
10540  }
10541  async read() {
10542    await this._readCapability.promise;
10543    if (this._done) {
10544      return {
10545        value: undefined,
10546        done: true
10547      };
10548    }
10549    if (this._storedError) {
10550      throw this._storedError;
10551    }
10552    const chunk = this._readableStream.read();
10553    if (chunk === null) {
10554      this._readCapability = Promise.withResolvers();
10555      return this.read();
10556    }
10557    this._loaded += chunk.length;
10558    this.onProgress?.({
10559      loaded: this._loaded
10560    });
10561    const buffer = new Uint8Array(chunk).buffer;
10562    return {
10563      value: buffer,
10564      done: false
10565    };
10566  }
10567  cancel(reason) {
10568    if (!this._readableStream) {
10569      this._error(reason);
10570      return;
10571    }
10572    this._readableStream.destroy(reason);
10573  }
10574  _error(reason) {
10575    this._storedError = reason;
10576    this._readCapability.resolve();
10577  }
10578  _setReadableStream(readableStream) {
10579    this._readableStream = readableStream;
10580    readableStream.on("readable", () => {
10581      this._readCapability.resolve();
10582    });
10583    readableStream.on("end", () => {
10584      readableStream.destroy();
10585      this._done = true;
10586      this._readCapability.resolve();
10587    });
10588    readableStream.on("error", reason => {
10589      this._error(reason);
10590    });
10591    if (this._storedError) {
10592      this._readableStream.destroy(this._storedError);
10593    }
10594  }
10595}
10596class PDFNodeStreamFullReader extends BaseFullReader {
10597  constructor(stream) {
10598    super(stream);
10599    const headers = Object.fromEntries(stream.headers);
10600    const handleResponse = response => {
10601      if (response.statusCode === 404) {
10602        const error = new MissingPDFException(`Missing PDF "${this._url}".`);
10603        this._storedError = error;
10604        this._headersCapability.reject(error);
10605        return;
10606      }
10607      this._headersCapability.resolve();
10608      this._setReadableStream(response);
10609      const responseHeaders = new Headers(this._readableStream.headers);
10610      const {
10611        allowRangeRequests,
10612        suggestedLength
10613      } = validateRangeRequestCapabilities({
10614        responseHeaders,
10615        isHttp: stream.isHttp,
10616        rangeChunkSize: this._rangeChunkSize,
10617        disableRange: this._disableRange
10618      });
10619      this._isRangeSupported = allowRangeRequests;
10620      this._contentLength = suggestedLength || this._contentLength;
10621      this._filename = extractFilenameFromHeader(responseHeaders);
10622    };
10623    this._request = createRequest(this._url, headers, handleResponse);
10624    this._request.on("error", reason => {
10625      this._storedError = reason;
10626      this._headersCapability.reject(reason);
10627    });
10628    this._request.end();
10629  }
10630}
10631class PDFNodeStreamRangeReader extends BaseRangeReader {
10632  constructor(stream, start, end) {
10633    super(stream);
10634    const headers = Object.fromEntries(stream.headers);
10635    headers.Range = `bytes=${start}-${end - 1}`;
10636    const handleResponse = response => {
10637      if (response.statusCode === 404) {
10638        const error = new MissingPDFException(`Missing PDF "${this._url}".`);
10639        this._storedError = error;
10640        return;
10641      }
10642      this._setReadableStream(response);
10643    };
10644    this._request = createRequest(this._url, headers, handleResponse);
10645    this._request.on("error", reason => {
10646      this._storedError = reason;
10647    });
10648    this._request.end();
10649  }
10650}
10651class PDFNodeStreamFsFullReader extends BaseFullReader {
10652  constructor(stream) {
10653    super(stream);
10654    const fs = NodePackages.get("fs");
10655    fs.promises.lstat(this._url).then(stat => {
10656      this._contentLength = stat.size;
10657      this._setReadableStream(fs.createReadStream(this._url));
10658      this._headersCapability.resolve();
10659    }, error => {
10660      if (error.code === "ENOENT") {
10661        error = new MissingPDFException(`Missing PDF "${this._url}".`);
10662      }
10663      this._storedError = error;
10664      this._headersCapability.reject(error);
10665    });
10666  }
10667}
10668class PDFNodeStreamFsRangeReader extends BaseRangeReader {
10669  constructor(stream, start, end) {
10670    super(stream);
10671    const fs = NodePackages.get("fs");
10672    this._setReadableStream(fs.createReadStream(this._url, {
10673      start,
10674      end: end - 1
10675    }));
10676  }
10677}
10678
10679;// ./src/display/text_layer.js
10680
10681
10682const MAX_TEXT_DIVS_TO_RENDER = 100000;
10683const DEFAULT_FONT_SIZE = 30;
10684const DEFAULT_FONT_ASCENT = 0.8;
10685class TextLayer {
10686  #capability = Promise.withResolvers();
10687  #container = null;
10688  #disableProcessItems = false;
vendor: 8,985 bytes, lines 10689-10973
10689  #fontInspectorEnabled = !!globalThis.FontInspector?.enabled;
10690  #lang = null;
10691  #layoutTextParams = null;
10692  #pageHeight = 0;
10693  #pageWidth = 0;
10694  #reader = null;
10695  #rootContainer = null;
10696  #rotation = 0;
10697  #scale = 0;
10698  #styleCache = Object.create(null);
10699  #textContentItemsStr = [];
10700  #textContentSource = null;
10701  #textDivs = [];
10702  #textDivProperties = new WeakMap();
10703  #transform = null;
10704  static #ascentCache = new Map();
10705  static #canvasContexts = new Map();
10706  static #canvasCtxFonts = new WeakMap();
10707  static #minFontSize = null;
10708  static #pendingTextLayers = new Set();
10709  constructor({
10710    textContentSource,
10711    container,
10712    viewport
10713  }) {
10714    if (textContentSource instanceof ReadableStream) {
10715      this.#textContentSource = textContentSource;
10716    } else if (typeof textContentSource === "object") {
10717      this.#textContentSource = new ReadableStream({
10718        start(controller) {
10719          controller.enqueue(textContentSource);
10720          controller.close();
10721        }
10722      });
10723    } else {
10724      throw new Error('No "textContentSource" parameter specified.');
10725    }
10726    this.#container = this.#rootContainer = container;
10727    this.#scale = viewport.scale * (globalThis.devicePixelRatio || 1);
10728    this.#rotation = viewport.rotation;
10729    this.#layoutTextParams = {
10730      div: null,
10731      properties: null,
10732      ctx: null
10733    };
10734    const {
10735      pageWidth,
10736      pageHeight,
10737      pageX,
10738      pageY
10739    } = viewport.rawDims;
10740    this.#transform = [1, 0, 0, -1, -pageX, pageY + pageHeight];
10741    this.#pageWidth = pageWidth;
10742    this.#pageHeight = pageHeight;
10743    TextLayer.#ensureMinFontSizeComputed();
10744    setLayerDimensions(container, viewport);
10745    this.#capability.promise.finally(() => {
10746      TextLayer.#pendingTextLayers.delete(this);
10747      this.#layoutTextParams = null;
10748      this.#styleCache = null;
10749    }).catch(() => {});
10750  }
10751  static get fontFamilyMap() {
10752    const {
10753      isWindows,
10754      isFirefox
10755    } = util_FeatureTest.platform;
10756    return shadow(this, "fontFamilyMap", new Map([["sans-serif", `${isWindows && isFirefox ? "Calibri, " : ""}sans-serif`], ["monospace", `${isWindows && isFirefox ? "Lucida Console, " : ""}monospace`]]));
10757  }
10758  render() {
10759    const pump = () => {
10760      this.#reader.read().then(({
10761        value,
10762        done
10763      }) => {
10764        if (done) {
10765          this.#capability.resolve();
10766          return;
10767        }
10768        this.#lang ??= value.lang;
10769        Object.assign(this.#styleCache, value.styles);
10770        this.#processItems(value.items);
10771        pump();
10772      }, this.#capability.reject);
10773    };
10774    this.#reader = this.#textContentSource.getReader();
10775    TextLayer.#pendingTextLayers.add(this);
10776    pump();
10777    return this.#capability.promise;
10778  }
10779  update({
10780    viewport,
10781    onBefore = null
10782  }) {
10783    const scale = viewport.scale * (globalThis.devicePixelRatio || 1);
10784    const rotation = viewport.rotation;
10785    if (rotation !== this.#rotation) {
10786      onBefore?.();
10787      this.#rotation = rotation;
10788      setLayerDimensions(this.#rootContainer, {
10789        rotation
10790      });
10791    }
10792    if (scale !== this.#scale) {
10793      onBefore?.();
10794      this.#scale = scale;
10795      const params = {
10796        div: null,
10797        properties: null,
10798        ctx: TextLayer.#getCtx(this.#lang)
10799      };
10800      for (const div of this.#textDivs) {
10801        params.properties = this.#textDivProperties.get(div);
10802        params.div = div;
10803        this.#layout(params);
10804      }
10805    }
10806  }
10807  cancel() {
10808    const abortEx = new AbortException("TextLayer task cancelled.");
10809    this.#reader?.cancel(abortEx).catch(() => {});
10810    this.#reader = null;
10811    this.#capability.reject(abortEx);
10812  }
10813  get textDivs() {
10814    return this.#textDivs;
10815  }
10816  get textContentItemsStr() {
10817    return this.#textContentItemsStr;
10818  }
10819  #processItems(items) {
10820    if (this.#disableProcessItems) {
10821      return;
10822    }
10823    this.#layoutTextParams.ctx ??= TextLayer.#getCtx(this.#lang);
10824    const textDivs = this.#textDivs,
10825      textContentItemsStr = this.#textContentItemsStr;
10826    for (const item of items) {
10827      if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER) {
10828        warn("Ignoring additional textDivs for performance reasons.");
10829        this.#disableProcessItems = true;
10830        return;
10831      }
10832      if (item.str === undefined) {
10833        if (item.type === "beginMarkedContentProps" || item.type === "beginMarkedContent") {
10834          const parent = this.#container;
10835          this.#container = document.createElement("span");
10836          this.#container.classList.add("markedContent");
10837          if (item.id !== null) {
10838            this.#container.setAttribute("id", `${item.id}`);
10839          }
10840          parent.append(this.#container);
10841        } else if (item.type === "endMarkedContent") {
10842          this.#container = this.#container.parentNode;
10843        }
10844        continue;
10845      }
10846      textContentItemsStr.push(item.str);
10847      this.#appendText(item);
10848    }
10849  }
10850  #appendText(geom) {
10851    const textDiv = document.createElement("span");
10852    const textDivProperties = {
10853      angle: 0,
10854      canvasWidth: 0,
10855      hasText: geom.str !== "",
10856      hasEOL: geom.hasEOL,
10857      fontSize: 0
10858    };
10859    this.#textDivs.push(textDiv);
10860    const tx = Util.transform(this.#transform, geom.transform);
10861    let angle = Math.atan2(tx[1], tx[0]);
10862    const style = this.#styleCache[geom.fontName];
10863    if (style.vertical) {
10864      angle += Math.PI / 2;
10865    }
10866    let fontFamily = this.#fontInspectorEnabled && style.fontSubstitution || style.fontFamily;
10867    fontFamily = TextLayer.fontFamilyMap.get(fontFamily) || fontFamily;
10868    const fontHeight = Math.hypot(tx[2], tx[3]);
10869    const fontAscent = fontHeight * TextLayer.#getAscent(fontFamily, this.#lang);
10870    let left, top;
10871    if (angle === 0) {
10872      left = tx[4];
10873      top = tx[5] - fontAscent;
10874    } else {
10875      left = tx[4] + fontAscent * Math.sin(angle);
10876      top = tx[5] - fontAscent * Math.cos(angle);
10877    }
10878    const scaleFactorStr = "calc(var(--scale-factor)*";
10879    const divStyle = textDiv.style;
10880    if (this.#container === this.#rootContainer) {
10881      divStyle.left = `${(100 * left / this.#pageWidth).toFixed(2)}%`;
10882      divStyle.top = `${(100 * top / this.#pageHeight).toFixed(2)}%`;
10883    } else {
10884      divStyle.left = `${scaleFactorStr}${left.toFixed(2)}px)`;
10885      divStyle.top = `${scaleFactorStr}${top.toFixed(2)}px)`;
10886    }
10887    divStyle.fontSize = `${scaleFactorStr}${(TextLayer.#minFontSize * fontHeight).toFixed(2)}px)`;
10888    divStyle.fontFamily = fontFamily;
10889    textDivProperties.fontSize = fontHeight;
10890    textDiv.setAttribute("role", "presentation");
10891    textDiv.textContent = geom.str;
10892    textDiv.dir = geom.dir;
10893    if (this.#fontInspectorEnabled) {
10894      textDiv.dataset.fontName = style.fontSubstitutionLoadedName || geom.fontName;
10895    }
10896    if (angle !== 0) {
10897      textDivProperties.angle = angle * (180 / Math.PI);
10898    }
10899    let shouldScaleText = false;
10900    if (geom.str.length > 1) {
10901      shouldScaleText = true;
10902    } else if (geom.str !== " " && geom.transform[0] !== geom.transform[3]) {
10903      const absScaleX = Math.abs(geom.transform[0]),
10904        absScaleY = Math.abs(geom.transform[3]);
10905      if (absScaleX !== absScaleY && Math.max(absScaleX, absScaleY) / Math.min(absScaleX, absScaleY) > 1.5) {
10906        shouldScaleText = true;
10907      }
10908    }
10909    if (shouldScaleText) {
10910      textDivProperties.canvasWidth = style.vertical ? geom.height : geom.width;
10911    }
10912    this.#textDivProperties.set(textDiv, textDivProperties);
10913    this.#layoutTextParams.div = textDiv;
10914    this.#layoutTextParams.properties = textDivProperties;
10915    this.#layout(this.#layoutTextParams);
10916    if (textDivProperties.hasText) {
10917      this.#container.append(textDiv);
10918    }
10919    if (textDivProperties.hasEOL) {
10920      const br = document.createElement("br");
10921      br.setAttribute("role", "presentation");
10922      this.#container.append(br);
10923    }
10924  }
10925  #layout(params) {
10926    const {
10927      div,
10928      properties,
10929      ctx
10930    } = params;
10931    const {
10932      style
10933    } = div;
10934    let transform = "";
10935    if (TextLayer.#minFontSize > 1) {
10936      transform = `scale(${1 / TextLayer.#minFontSize})`;
10937    }
10938    if (properties.canvasWidth !== 0 && properties.hasText) {
10939      const {
10940        fontFamily
10941      } = style;
10942      const {
10943        canvasWidth,
10944        fontSize
10945      } = properties;
10946      TextLayer.#ensureCtxFont(ctx, fontSize * this.#scale, fontFamily);
10947      const {
10948        width
10949      } = ctx.measureText(div.textContent);
10950      if (width > 0) {
10951        transform = `scaleX(${canvasWidth * this.#scale / width}) ${transform}`;
10952      }
10953    }
10954    if (properties.angle !== 0) {
10955      transform = `rotate(${properties.angle}deg) ${transform}`;
10956    }
10957    if (transform.length > 0) {
10958      style.transform = transform;
10959    }
10960  }
10961  static cleanup() {
10962    if (this.#pendingTextLayers.size > 0) {
10963      return;
10964    }
10965    this.#ascentCache.clear();
10966    for (const {
10967      canvas
10968    } of this.#canvasContexts.values()) {
10969      canvas.remove();
10970    }
10971    this.#canvasContexts.clear();
10972  }
10973  static #getCtx(lang = null) {
10974    let ctx = this.#canvasContexts.get(lang ||= "");
10975    if (!ctx) {
10976      const canvas = document.createElement("canvas");
10977      canvas.className = "hiddenCanvasElement";
10978      canvas.lang = lang;
10979      document.body.append(canvas);
10980      ctx = canvas.getContext("2d", {
10981        alpha: false,
10982        willReadFrequently: true
10983      });
10984      this.#canvasContexts.set(lang, ctx);
10985      this.#canvasCtxFonts.set(ctx, {
10986        size: 0,
10987        family: ""
10988      });
10989    }
10990    return ctx;
10991  }
10992  static #ensureCtxFont(ctx, size, family) {
10993    const cached = this.#canvasCtxFonts.get(ctx);
10994    if (size === cached.size && family === cached.family) {
10995      return;
10996    }
10997    ctx.font = `${size}px ${family}`;
10998    cached.size = size;
10999    cached.family = family;
11000  }
11001  static #ensureMinFontSizeComputed() {
11002    if (this.#minFontSize !== null) {
11003      return;
11004    }
11005    const div = document.createElement("div");
11006    div.style.opacity = 0;
11007    div.style.lineHeight = 1;
11008    div.style.fontSize = "1px";
11009    div.style.position = "absolute";
11010    div.textContent = "X";
11011    document.body.append(div);
11012    this.#minFontSize = div.getBoundingClientRect().height;
11013    div.remove();
11014  }
11015  static #getAscent(fontFamily, lang) {
11016    const cachedAscent = this.#ascentCache.get(fontFamily);
11017    if (cachedAscent) {
11018      return cachedAscent;
11019    }
11020    const ctx = this.#getCtx(lang);
11021    ctx.canvas.width = ctx.canvas.height = DEFAULT_FONT_SIZE;
11022    this.#ensureCtxFont(ctx, DEFAULT_FONT_SIZE, fontFamily);
11023    const metrics = ctx.measureText("");
11024    let ascent = metrics.fontBoundingBoxAscent;
11025    let descent = Math.abs(metrics.fontBoundingBoxDescent);
11026    if (ascent) {
11027      const ratio = ascent / (ascent + descent);
11028      this.#ascentCache.set(fontFamily, ratio);
11029      ctx.canvas.width = ctx.canvas.height = 0;
11030      return ratio;
11031    }
11032    ctx.strokeStyle = "red";
11033    ctx.clearRect(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE);
11034    ctx.strokeText("g", 0, 0);
11035    let pixels = ctx.getImageData(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE).data;
11036    descent = 0;
11037    for (let i = pixels.length - 1 - 3; i >= 0; i -= 4) {
11038      if (pixels[i] > 0) {
11039        descent = Math.ceil(i / 4 / DEFAULT_FONT_SIZE);
11040        break;
11041      }
11042    }
11043    ctx.clearRect(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE);
11044    ctx.strokeText("A", 0, DEFAULT_FONT_SIZE);
11045    pixels = ctx.getImageData(0, 0, DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE).data;
11046    ascent = 0;
11047    for (let i = 0, ii = pixels.length; i < ii; i += 4) {
11048      if (pixels[i] > 0) {
11049        ascent = DEFAULT_FONT_SIZE - Math.floor(i / 4 / DEFAULT_FONT_SIZE);
11050        break;
11051      }
11052    }
11053    ctx.canvas.width = ctx.canvas.height = 0;
11054    const ratio = ascent ? ascent / (ascent + descent) : DEFAULT_FONT_ASCENT;
11055    this.#ascentCache.set(fontFamily, ratio);
11056    return ratio;
11057  }
11058}
11059
11060;// ./src/display/xfa_text.js
11061class XfaText {
11062  static textContent(xfa) {
11063    const items = [];
11064    const output = {
11065      items,
11066      styles: Object.create(null)
11067    };
11068    function walk(node) {
11069      if (!node) {
11070        return;
11071      }
11072      let str = null;
11073      const name = node.name;
11074      if (name === "#text") {
11075        str = node.value;
11076      } else if (!XfaText.shouldBuildText(name)) {
11077        return;
11078      } else if (node?.attributes?.textContent) {
11079        str = node.attributes.textContent;
11080      } else if (node.value) {
11081        str = node.value;
11082      }
11083      if (str !== null) {
11084        items.push({
11085          str
11086        });
11087      }
11088      if (!node.children) {
11089        return;
11090      }
11091      for (const child of node.children) {
11092        walk(child);
11093      }
11094    }
11095    walk(xfa);
11096    return output;
11097  }
11098  static shouldBuildText(name) {
11099    return !(name === "textarea" || name === "input" || name === "option" || name === "select");
11100  }
11101}
11102
11103;// ./src/display/api.js
11104
11105
11106
11107
11108
11109
11110
11111
11112
11113
11114
11115
11116
11117
11118
11119
11120
11121
11122
11123
11124const DEFAULT_RANGE_CHUNK_SIZE = 65536;
11125const RENDERING_CANCELLED_TIMEOUT = 100;
11126const DELAYED_CLEANUP_TIMEOUT = 5000;
11127const DefaultCanvasFactory = isNodeJS ? NodeCanvasFactory : DOMCanvasFactory;
11128const DefaultCMapReaderFactory = isNodeJS ? NodeCMapReaderFactory : DOMCMapReaderFactory;
11129const DefaultFilterFactory = isNodeJS ? NodeFilterFactory : DOMFilterFactory;
11130const DefaultStandardFontDataFactory = isNodeJS ? NodeStandardFontDataFactory : DOMStandardFontDataFactory;
11131function getDocument(src = {}) {
11132  if (typeof src === "string" || src instanceof URL) {
11133    src = {
11134      url: src
11135    };
11136  } else if (src instanceof ArrayBuffer || ArrayBuffer.isView(src)) {
11137    src = {
11138      data: src
11139    };
11140  }
11141  const task = new PDFDocumentLoadingTask();
11142  const {
11143    docId
11144  } = task;
11145  const url = src.url ? getUrlProp(src.url) : null;
11146  const data = src.data ? getDataProp(src.data) : null;
11147  const httpHeaders = src.httpHeaders || null;
11148  const withCredentials = src.withCredentials === true;
11149  const password = src.password ?? null;
11150  const rangeTransport = src.range instanceof PDFDataRangeTransport ? src.range : null;
11151  const rangeChunkSize = Number.isInteger(src.rangeChunkSize) && src.rangeChunkSize > 0 ? src.rangeChunkSize : DEFAULT_RANGE_CHUNK_SIZE;
11152  let worker = src.worker instanceof PDFWorker ? src.worker : null;
11153  const verbosity = src.verbosity;
11154  const docBaseUrl = typeof src.docBaseUrl === "string" && !isDataScheme(src.docBaseUrl) ? src.docBaseUrl : null;
11155  const cMapUrl = typeof src.cMapUrl === "string" ? src.cMapUrl : null;
11156  const cMapPacked = src.cMapPacked !== false;
11157  const CMapReaderFactory = src.CMapReaderFactory || DefaultCMapReaderFactory;
11158  const standardFontDataUrl = typeof src.standardFontDataUrl === "string" ? src.standardFontDataUrl : null;
11159  const StandardFontDataFactory = src.StandardFontDataFactory || DefaultStandardFontDataFactory;
11160  const ignoreErrors = src.stopAtErrors !== true;
11161  const maxImageSize = Number.isInteger(src.maxImageSize) && src.maxImageSize > -1 ? src.maxImageSize : -1;
11162  const isEvalSupported = src.isEvalSupported !== false;
11163  const isOffscreenCanvasSupported = typeof src.isOffscreenCanvasSupported === "boolean" ? src.isOffscreenCanvasSupported : !isNodeJS;
11164  const isChrome = typeof src.isChrome === "boolean" ? src.isChrome : !util_FeatureTest.platform.isFirefox && typeof window !== "undefined" && !!window?.chrome;
11165  const canvasMaxAreaInBytes = Number.isInteger(src.canvasMaxAreaInBytes) ? src.canvasMaxAreaInBytes : 
11165-1;
11166  const disableFontFace = typeof src.disableFontFace === "boolean" ? src.disableFontFace : isNodeJS;
11167  const fontExtraProperties = src.fontExtraProperties === true;
11168  const enableXfa = src.enableXfa === true;
11169  const ownerDocument = src.ownerDocument || globalThis.document;
11170  const disableRange = src.disableRange === true;
11171  const disableStream = src.disableStream === true;
11172  const disableAutoFetch = src.disableAutoFetch === true;
11173  const pdfBug = src.pdfBug === true;
11174  const CanvasFactory = src.CanvasFactory || DefaultCanvasFactory;
11175  const FilterFactory = src.FilterFactory || DefaultFilterFactory;
11176  const enableHWA = src.enableHWA === true;
11177  const length = rangeTransport ? rangeTransport.length : src.length ?? NaN;
11178  const useSystemFonts = typeof src.useSystemFonts === "boolean" ? src.useSystemFonts : !isNodeJS && !disableFontFace;
11179  const useWorkerFetch = typeof src.useWorkerFetch === "boolean" ? src.useWorkerFetch : CMapReaderFactory === DOMCMapReaderFactory && StandardFontDataFactory === DOMStandardFontDataFactory && cMapUrl && standardFontDataUrl && isValidFetchUrl(cMapUrl, document.baseURI) && isValidFetchUrl(standardFontDataUrl, document.baseURI);
11180  if (src.canvasFactory) {
11181    deprecated("`canvasFactory`-instance option, please use `CanvasFactory` instead.");
11182  }
11183  if (src.filterFactory) {
11184    deprecated("`filterFactory`-instance option, please use `FilterFactory` instead.");
11185  }
11186  const styleElement = null;
11187  setVerbosityLevel(verbosity);
11188  const transportFactory = {
11189    canvasFactory: new CanvasFactory({
11190      ownerDocument,
11191      enableHWA
11192    }),
11193    filterFactory: new FilterFactory({
11194      docId,
11195      ownerDocument
11196    }),
11197    cMapReaderFactory: useWorkerFetch ? null : new CMapReaderFactory({
11198      baseUrl: cMapUrl,
11199      isCompressed: cMapPacked
11200    }),
11201    standardFontDataFactory: useWorkerFetch ? null : new StandardFontDataFactory({
11202      baseUrl: standardFontDataUrl
11203    })
11204  };
11205  if (!worker) {
11206    const workerParams = {
11207      verbosity,
11208      port: GlobalWorkerOptions.workerPort
11209    };
11210    worker = workerParams.port ? PDFWorker.fromPort(workerParams) : new PDFWorker(workerParams);
11211    task._worker = worker;
11212  }
11213  const docParams = {
11214    docId,
11215    apiVersion: "4.8.69",
11216    data,
11217    password,
11218    disableAutoFetch,
11219    rangeChunkSize,
11220    length,
11221    docBaseUrl,
11222    enableXfa,
11223    evaluatorOptions: {
11224      maxImageSize,
11225      disableFontFace,
11226      ignoreErrors,
11227      isEvalSupported,
11228      isOffscreenCanvasSupported,
11229      isChrome,
11230      canvasMaxAreaInBytes,
11231      fontExtraProperties,
11232      useSystemFonts,
11233      cMapUrl: useWorkerFetch ? cMapUrl : null,
11234      standardFontDataUrl: useWorkerFetch ? standardFontDataUrl : null
11235    }
11236  };
11237  const transportParams = {
11238    disableFontFace,
11239    fontExtraProperties,
11240    ownerDocument,
11241    pdfBug,
11242    styleElement,
11243    loadingParams: {
11244      disableAutoFetch,
11245      enableXfa
11246    }
11247  };
11248  worker.promise.then(function () {
11249    if (task.destroyed) {
11250      throw new Error("Loading aborted");
11251    }
11252    if (worker.destroyed) {
11253      throw new Error("Worker was destroyed");
11254    }
11255    const workerIdPromise = worker.messageHandler.sendWithPromise("GetDocRequest", docParams, data ? [data.buffer] : null);
11256    let networkStream;
11257    if (rangeTransport) {
11258      networkStream = new PDFDataTransportStream(rangeTransport, {
11259        disableRange,
11260        disableStream
11261      });
11262    } else if (!data) {
11263      if (!url) {
11264        throw new Error("getDocument - no `url` parameter provided.");
11265      }
11266      let NetworkStream;
11267      if (isNodeJS) {
11268        const isFetchSupported = typeof fetch !== "undefined" && typeof Response !== "undefined" && "body" in Response.prototype;
11269        NetworkStream = isFetchSupported && isValidFetchUrl(url) ? PDFFetchStream : PDFNodeStream;
11270      } else {
11271        NetworkStream = isValidFetchUrl(url) ? PDFFetchStream : PDFNetworkStream;
11272      }
11273      networkStream = new NetworkStream({
11274        url,
11275        length,
11276        httpHeaders,
11277        withCredentials,
11278        rangeChunkSize,
11279        disableRange,
11280        disableStream
11281      });
11282    }
11283    return workerIdPromise.then(workerId => {
11284      if (task.destroyed) {
11285        throw new Error("Loading aborted");
11286      }
11287      if (worker.destroyed) {
11288        throw new Error("Worker was destroyed");
11289      }
11290      const messageHandler = new MessageHandler(docId, workerId, worker.port);
11291      const transport = new WorkerTransport(messageHandler, task, networkStream, transportParams, transportFactory);
11292      task._transport = transport;
11293      messageHandler.send("Ready", null);
11294    });
11295  }).catch(task._capability.reject);
11296  return task;
11297}
11298function getUrlProp(val) {
11299  if (val instanceof URL) {
11300    return val.href;
11301  }
11302  try {
11303    return new URL(val, window.location).href;
11304  } catch {
11305    if (isNodeJS && typeof val === "string") {
11306      return val;
11307    }
11308  }
11309  throw new Error("Invalid PDF url data: " + "either string or URL-object is expected in the url property.");
11310}
11311function getDataProp(val) {
11312  if (isNodeJS && typeof Buffer !== "undefined" && val instanceof Buffer) {
11313    throw new Error("Please provide binary data as `Uint8Array`, rather than `Buffer`.");
11314  }
11315  if (val instanceof Uint8Array && val.byteLength === val.buffer.byteLength) {
11316    return val;
11317  }
11318  if (typeof val === "string") {
11319    return stringToBytes(val);
11320  }
11321  if (val instanceof ArrayBuffer || ArrayBuffer.isView(val) || typeof val === "object" && !isNaN(val?.length)) {
11322    return new Uint8Array(val);
11323  }
11324  throw new Error("Invalid PDF binary data: either TypedArray, " + "string, or array-like object is expected in the data property.");
11325}
11326function isRefProxy(ref) {
11327  return typeof ref === "object" && Number.isInteger(ref?.num) && ref.num >= 0 && Number.isInteger(ref?.gen) && ref.gen >= 0;
11328}
11329class PDFDocumentLoadingTask {
11330  static #docId = 0;
11331  constructor() {
11332    this._capability = Promise.withResolvers();
11333    this._transport = null;
11334    this._worker = null;
11335    this.docId = `d${PDFDocumentLoadingTask.#docId++}`;
11336    this.destroyed = false;
vendor: 13,882 bytes, lines 11337-11821
11337    this.onPassword = null;
11338    this.onProgress = null;
11339  }
11340  get promise() {
11341    return this._capability.promise;
11342  }
11343  async destroy() {
11344    this.destroyed = true;
11345    try {
11346      if (this._worker?.port) {
11347        this._worker._pendingDestroy = true;
11348      }
11349      await this._transport?.destroy();
11350    } catch (ex) {
11351      if (this._worker?.port) {
11352        delete this._worker._pendingDestroy;
11353      }
11354      throw ex;
11355    }
11356    this._transport = null;
11357    if (this._worker) {
11358      this._worker.destroy();
11359      this._worker = null;
11360    }
11361  }
11362}
11363class PDFDataRangeTransport {
11364  constructor(length, initialData, progressiveDone = false, contentDispositionFilename = null) {
11365    this.length = length;
11366    this.initialData = initialData;
11367    this.progressiveDone = progressiveDone;
11368    this.contentDispositionFilename = contentDispositionFilename;
11369    this._rangeListeners = [];
11370    this._progressListeners = [];
11371    this._progressiveReadListeners = [];
11372    this._progressiveDoneListeners = [];
11373    this._readyCapability = Promise.withResolvers();
11374  }
11375  addRangeListener(listener) {
11376    this._rangeListeners.push(listener);
11377  }
11378  addProgressListener(listener) {
11379    this._progressListeners.push(listener);
11380  }
11381  addProgressiveReadListener(listener) {
11382    this._progressiveReadListeners.push(listener);
11383  }
11384  addProgressiveDoneListener(listener) {
11385    this._progressiveDoneListeners.push(listener);
11386  }
11387  onDataRange(begin, chunk) {
11388    for (const listener of this._rangeListeners) {
11389      listener(begin, chunk);
11390    }
11391  }
11392  onDataProgress(loaded, total) {
11393    this._readyCapability.promise.then(() => {
11394      for (const listener of this._progressListeners) {
11395        listener(loaded, total);
11396      }
11397    });
11398  }
11399  onDataProgressiveRead(chunk) {
11400    this._readyCapability.promise.then(() => {
11401      for (const listener of this._progressiveReadListeners) {
11402        listener(chunk);
11403      }
11404    });
11405  }
11406  onDataProgressiveDone() {
11407    this._readyCapability.promise.then(() => {
11408      for (const listener of this._progressiveDoneListeners) {
11409        listener();
11410      }
11411    });
11412  }
11413  transportReady() {
11414    this._readyCapability.resolve();
11415  }
11416  requestDataRange(begin, end) {
11417    unreachable("Abstract method PDFDataRangeTransport.requestDataRange");
11418  }
11419  abort() {}
11420}
11421class PDFDocumentProxy {
11422  constructor(pdfInfo, transport) {
11423    this._pdfInfo = pdfInfo;
11424    this._transport = transport;
11425  }
11426  get annotationStorage() {
11427    return this._transport.annotationStorage;
11428  }
11429  get canvasFactory() {
11430    return this._transport.canvasFactory;
11431  }
11432  get filterFactory() {
11433    return this._transport.filterFactory;
11434  }
11435  get numPages() {
11436    return this._pdfInfo.numPages;
11437  }
11438  get fingerprints() {
11439    return this._pdfInfo.fingerprints;
11440  }
11441  get isPureXfa() {
11442    return shadow(this, "isPureXfa", !!this._transport._htmlForXfa);
11443  }
11444  get allXfaHtml() {
11445    return this._transport._htmlForXfa;
11446  }
11447  getPage(pageNumber) {
11448    return this._transport.getPage(pageNumber);
11449  }
11450  getPageIndex(ref) {
11451    return this._transport.getPageIndex(ref);
11452  }
11453  getDestinations() {
11454    return this._transport.getDestinations();
11455  }
11456  getDestination(id) {
11457    return this._transport.getDestination(id);
11458  }
11459  getPageLabels() {
11460    return this._transport.getPageLabels();
11461  }
11462  getPageLayout() {
11463    return this._transport.getPageLayout();
11464  }
11465  getPageMode() {
11466    return this._transport.getPageMode();
11467  }
11468  getViewerPreferences() {
11469    return this._transport.getViewerPreferences();
11470  }
11471  getOpenAction() {
11472    return this._transport.getOpenAction();
11473  }
11474  getAttachments() {
11475    return this._transport.getAttachments();
11476  }
11477  getJSActions() {
11478    return this._transport.getDocJSActions();
11479  }
11480  getOutline() {
11481    return this._transport.getOutline();
11482  }
11483  getOptionalContentConfig({
11484    intent = "display"
11485  } = {}) {
11486    const {
11487      renderingIntent
11488    } = this._transport.getRenderingIntent(intent);
11489    return this._transport.getOptionalContentConfig(renderingIntent);
11490  }
11491  getPermissions() {
11492    return this._transport.getPermissions();
11493  }
11494  getMetadata() {
11495    return this._transport.getMetadata();
11496  }
11497  getMarkInfo() {
11498    return this._transport.getMarkInfo();
11499  }
11500  getData() {
11501    return this._transport.getData();
11502  }
11503  saveDocument() {
11504    return this._transport.saveDocument();
11505  }
11506  getDownloadInfo() {
11507    return this._transport.downloadInfoCapability.promise;
11508  }
11509  cleanup(keepLoadedFonts = false) {
11510    return this._transport.startCleanup(keepLoadedFonts || this.isPureXfa);
11511  }
11512  destroy() {
11513    return this.loadingTask.destroy();
11514  }
11515  cachedPageNumber(ref) {
11516    return this._transport.cachedPageNumber(ref);
11517  }
11518  get loadingParams() {
11519    return this._transport.loadingParams;
11520  }
11521  get loadingTask() {
11522    return this._transport.loadingTask;
11523  }
11524  getFieldObjects() {
11525    return this._transport.getFieldObjects();
11526  }
11527  hasJSActions() {
11528    return this._transport.hasJSActions();
11529  }
11530  getCalculationOrderIds() {
11531    return this._transport.getCalculationOrderIds();
11532  }
11533}
11534class PDFPageProxy {
11535  #delayedCleanupTimeout = null;
11536  #pendingCleanup = false;
11537  constructor(pageIndex, pageInfo, transport, pdfBug = false) {
11538    this._pageIndex = pageIndex;
11539    this._pageInfo = pageInfo;
11540    this._transport = transport;
11541    this._stats = pdfBug ? new StatTimer() : null;
11542    this._pdfBug = pdfBug;
11543    this.commonObjs = transport.commonObjs;
11544    this.objs = new PDFObjects();
11545    this._maybeCleanupAfterRender = false;
11546    this._intentStates = new Map();
11547    this.destroyed = false;
11548  }
11549  get pageNumber() {
11550    return this._pageIndex + 1;
11551  }
11552  get rotate() {
11553    return this._pageInfo.rotate;
11554  }
11555  get ref() {
11556    return this._pageInfo.ref;
11557  }
11558  get userUnit() {
11559    return this._pageInfo.userUnit;
11560  }
11561  get view() {
11562    return this._pageInfo.view;
11563  }
11564  getViewport({
11565    scale,
11566    rotation = this.rotate,
11567    offsetX = 0,
11568    offsetY = 0,
11569    dontFlip = false
11570  } = {}) {
11571    return new PageViewport({
11572      viewBox: this.view,
11573      scale,
11574      rotation,
11575      offsetX,
11576      offsetY,
11577      dontFlip
11578    });
11579  }
11580  getAnnotations({
11581    intent = "display"
11582  } = {}) {
11583    const {
11584      renderingIntent
11585    } = this._transport.getRenderingIntent(intent);
11586    return this._transport.getAnnotations(this._pageIndex, renderingIntent);
11587  }
11588  getJSActions() {
11589    return this._transport.getPageJSActions(this._pageIndex);
11590  }
11591  get filterFactory() {
11592    return this._transport.filterFactory;
11593  }
11594  get isPureXfa() {
11595    return shadow(this, "isPureXfa", !!this._transport._htmlForXfa);
11596  }
11597  async getXfa() {
11598    return this._transport._htmlForXfa?.children[this._pageIndex] || null;
11599  }
11600  render({
11601    canvasContext,
11602    viewport,
11603    intent = "display",
11604    annotationMode = AnnotationMode.ENABLE,
11605    transform = null,
11606    background = null,
11607    optionalContentConfigPromise = null,
11608    annotationCanvasMap = null,
11609    pageColors = null,
11610    printAnnotationStorage = null,
11611    isEditing = false
11612  }) {
11613    this._stats?.time("Overall");
11614    const intentArgs = this._transport.getRenderingIntent(intent, annotationMode, printAnnotationStorage, isEditing);
11615    const {
11616      renderingIntent,
11617      cacheKey
11618    } = intentArgs;
11619    this.#pendingCleanup = false;
11620    this.#abortDelayedCleanup();
11621    optionalContentConfigPromise ||= this._transport.getOptionalContentConfig(renderingIntent);
11622    let intentState = this._intentStates.get(cacheKey);
11623    if (!intentState) {
11624      intentState = Object.create(null);
11625      this._intentStates.set(cacheKey, intentState);
11626    }
11627    if (intentState.streamReaderCancelTimeout) {
11628      clearTimeout(intentState.streamReaderCancelTimeout);
11629      intentState.streamReaderCancelTimeout = null;
11630    }
11631    const intentPrint = !!(renderingIntent & RenderingIntentFlag.PRINT);
11632    if (!intentState.displayReadyCapability) {
11633      intentState.displayReadyCapability = Promise.withResolvers();
11634      intentState.operatorList = {
11635        fnArray: [],
11636        argsArray: [],
11637        lastChunk: false,
11638        separateAnnots: null
11639      };
11640      this._stats?.time("Page Request");
11641      this._pumpOperatorList(intentArgs);
11642    }
11643    const complete = error => {
11644      intentState.renderTasks.delete(internalRenderTask);
11645      if (this._maybeCleanupAfterRender || intentPrint) {
11646        this.#pendingCleanup = true;
11647      }
11648      this.#tryCleanup(!intentPrint);
11649      if (error) {
11650        internalRenderTask.capability.reject(error);
11651        this._abortOperatorList({
11652          intentState,
11653          reason: error instanceof Error ? error : new Error(error)
11654        });
11655      } else {
11656        internalRenderTask.capability.resolve();
11657      }
11658      if (this._stats) {
11659        this._stats.timeEnd("Rendering");
11660        this._stats.timeEnd("Overall");
11661        if (globalThis.Stats?.enabled) {
11662          globalThis.Stats.add(this.pageNumber, this._stats);
11663        }
11664      }
11665    };
11666    const internalRenderTask = new InternalRenderTask({
11667      callback: complete,
11668      params: {
11669        canvasContext,
11670        viewport,
11671        transform,
11672        background
11673      },
11674      objs: this.objs,
11675      commonObjs: this.commonObjs,
11676      annotationCanvasMap,
11677      operatorList: intentState.operatorList,
11678      pageIndex: this._pageIndex,
11679      canvasFactory: this._transport.canvasFactory,
11680      filterFactory: this._transport.filterFactory,
11681      useRequestAnimationFrame: !intentPrint,
11682      pdfBug: this._pdfBug,
11683      pageColors
11684    });
11685    (intentState.renderTasks ||= new Set()).add(internalRenderTask);
11686    const renderTask = internalRenderTask.task;
11687    Promise.all([intentState.displayReadyCapability.promise, optionalContentConfigPromise]).then(([transparency, optionalContentConfig]) => {
11688      if (this.destroyed) {
11689        complete();
11690        return;
11691      }
11692      this._stats?.time("Rendering");
11693      if (!(optionalContentConfig.renderingIntent & renderingIntent)) {
11694        throw new Error("Must use the same `intent`-argument when calling the `PDFPageProxy.render` " + "and `PDFDocumentProxy.getOptionalContentConfig` methods.");
11695      }
11696      internalRenderTask.initializeGraphics({
11697        transparency,
11698        optionalContentConfig
11699      });
11700      internalRenderTask.operatorListChanged();
11701    }).catch(complete);
11702    return renderTask;
11703  }
11704  getOperatorList({
11705    intent = "display",
11706    annotationMode = AnnotationMode.ENABLE,
11707    printAnnotationStorage = null,
11708    isEditing = false
11709  } = {}) {
11710    function operatorListChanged() {
11711      if (intentState.operatorList.lastChunk) {
11712        intentState.opListReadCapability.resolve(intentState.operatorList);
11713        intentState.renderTasks.delete(opListTask);
11714      }
11715    }
11716    const intentArgs = this._transport.getRenderingIntent(intent, annotationMode, printAnnotationStorage, isEditing, true);
11717    let intentState = this._intentStates.get(intentArgs.cacheKey);
11718    if (!intentState) {
11719      intentState = Object.create(null);
11720      this._intentStates.set(intentArgs.cacheKey, intentState);
11721    }
11722    let opListTask;
11723    if (!intentState.opListReadCapability) {
11724      opListTask = Object.create(null);
11725      opListTask.operatorListChanged = operatorListChanged;
11726      intentState.opListReadCapability = Promise.withResolvers();
11727      (intentState.renderTasks ||= new Set()).add(opListTask);
11728      intentState.operatorList = {
11729        fnArray: [],
11730        argsArray: [],
11731        lastChunk: false,
11732        separateAnnots: null
11733      };
11734      this._stats?.time("Page Request");
11735      this._pumpOperatorList(intentArgs);
11736    }
11737    return intentState.opListReadCapability.promise;
11738  }
11739  streamTextContent({
11740    includeMarkedContent = false,
11741    disableNormalization = false
11742  } = {}) {
11743    const TEXT_CONTENT_CHUNK_SIZE = 100;
11744    return this._transport.messageHandler.sendWithStream("GetTextContent", {
11745      pageIndex: this._pageIndex,
11746      includeMarkedContent: includeMarkedContent === true,
11747      disableNormalization: disableNormalization === true
11748    }, {
11749      highWaterMark: TEXT_CONTENT_CHUNK_SIZE,
11750      size(textContent) {
11751        return textContent.items.length;
11752      }
11753    });
11754  }
11755  getTextContent(params = {}) {
11756    if (this._transport._htmlForXfa) {
11757      return this.getXfa().then(xfa => XfaText.textContent(xfa));
11758    }
11759    const readableStream = this.streamTextContent(params);
11760    return new Promise(function (resolve, reject) {
11761      function pump() {
11762        reader.read().then(function ({
11763          value,
11764          done
11765        }) {
11766          if (done) {
11767            resolve(textContent);
11768            return;
11769          }
11770          textContent.lang ??= value.lang;
11771          Object.assign(textContent.styles, value.styles);
11772          textContent.items.push(...value.items);
11773          pump();
11774        }, reject);
11775      }
11776      const reader = readableStream.getReader();
11777      const textContent = {
11778        items: [],
11779        styles: Object.create(null),
11780        lang: null
11781      };
11782      pump();
11783    });
11784  }
11785  getStructTree() {
11786    return this._transport.getStructTree(this._pageIndex);
11787  }
11788  _destroy() {
11789    this.destroyed = true;
11790    const waitOn = [];
11791    for (const intentState of this._intentStates.values()) {
11792      this._abortOperatorList({
11793        intentState,
11794        reason: new Error("Page was destroyed."),
11795        force: true
11796      });
11797      if (intentState.opListReadCapability) {
11798        continue;
11799      }
11800      for (const internalRenderTask of intentState.renderTasks) {
11801        waitOn.push(internalRenderTask.completed);
11802        internalRenderTask.cancel();
11803      }
11804    }
11805    this.objs.clear();
11806    this.#pendingCleanup = false;
11807    this.#abortDelayedCleanup();
11808    return Promise.all(waitOn);
11809  }
11810  cleanup(resetStats = false) {
11811    this.#pendingCleanup = true;
11812    const success = this.#tryCleanup(false);
11813    if (resetStats && success) {
11814      this._stats &&= new StatTimer();
11815    }
11816    return success;
11817  }
11818  #tryCleanup(delayed = false) {
11819    this.#abortDelayedCleanup();
11820    if (!this.#pendingCleanup || this.destroyed) {
11821      return false;
vendor: 5,769 bytes, lines 11822-12022
11822    }
11823    if (delayed) {
11824      this.#delayedCleanupTimeout = setTimeout(() => {
11825        this.#delayedCleanupTimeout = null;
11826        this.#tryCleanup(false);
11827      }, DELAYED_CLEANUP_TIMEOUT);
11828      return false;
11829    }
11830    for (const {
11831      renderTasks,
11832      operatorList
11833    } of this._intentStates.values()) {
11834      if (renderTasks.size > 0 || !operatorList.lastChunk) {
11835        return false;
11836      }
11837    }
11838    this._intentStates.clear();
11839    this.objs.clear();
11840    this.#pendingCleanup = false;
11841    return true;
11842  }
11843  #abortDelayedCleanup() {
11844    if (this.#delayedCleanupTimeout) {
11845      clearTimeout(this.#delayedCleanupTimeout);
11846      this.#delayedCleanupTimeout = null;
11847    }
11848  }
11849  _startRenderPage(transparency, cacheKey) {
11850    const intentState = this._intentStates.get(cacheKey);
11851    if (!intentState) {
11852      return;
11853    }
11854    this._stats?.timeEnd("Page Request");
11855    intentState.displayReadyCapability?.resolve(transparency);
11856  }
11857  _renderPageChunk(operatorListChunk, intentState) {
11858    for (let i = 0, ii = operatorListChunk.length; i < ii; i++) {
11859      intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
11860      intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]);
11861    }
11862    intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
11863    intentState.operatorList.separateAnnots = operatorListChunk.separateAnnots;
11864    for (const internalRenderTask of intentState.renderTasks) {
11865      internalRenderTask.operatorListChanged();
11866    }
11867    if (operatorListChunk.lastChunk) {
11868      this.#tryCleanup(true);
11869    }
11870  }
11871  _pumpOperatorList({
11872    renderingIntent,
11873    cacheKey,
11874    annotationStorageSerializable,
11875    modifiedIds
11876  }) {
11877    const {
11878      map,
11879      transfer
11880    } = annotationStorageSerializable;
11881    const readableStream = this._transport.messageHandler.sendWithStream("GetOperatorList", {
11882      pageIndex: this._pageIndex,
11883      intent: renderingIntent,
11884      cacheKey,
11885      annotationStorage: map,
11886      modifiedIds
11887    }, transfer);
11888    const reader = readableStream.getReader();
11889    const intentState = this._intentStates.get(cacheKey);
11890    intentState.streamReader = reader;
11891    const pump = () => {
11892      reader.read().then(({
11893        value,
11894        done
11895      }) => {
11896        if (done) {
11897          intentState.streamReader = null;
11898          return;
11899        }
11900        if (this._transport.destroyed) {
11901          return;
11902        }
11903        this._renderPageChunk(value, intentState);
11904        pump();
11905      }, reason => {
11906        intentState.streamReader = null;
11907        if (this._transport.destroyed) {
11908          return;
11909        }
11910        if (intentState.operatorList) {
11911          intentState.operatorList.lastChunk = true;
11912          for (const internalRenderTask of intentState.renderTasks) {
11913            internalRenderTask.operatorListChanged();
11914          }
11915          this.#tryCleanup(true);
11916        }
11917        if (intentState.displayReadyCapability) {
11918          intentState.displayReadyCapability.reject(reason);
11919        } else if (intentState.opListReadCapability) {
11920          intentState.opListReadCapability.reject(reason);
11921        } else {
11922          throw reason;
11923        }
11924      });
11925    };
11926    pump();
11927  }
11928  _abortOperatorList({
11929    intentState,
11930    reason,
11931    force = false
11932  }) {
11933    if (!intentState.streamReader) {
11934      return;
11935    }
11936    if (intentState.streamReaderCancelTimeout) {
11937      clearTimeout(intentState.streamReaderCancelTimeout);
11938      intentState.streamReaderCancelTimeout = null;
11939    }
11940    if (!force) {
11941      if (intentState.renderTasks.size > 0) {
11942        return;
11943      }
11944      if (reason instanceof RenderingCancelledException) {
11945        let delay = RENDERING_CANCELLED_TIMEOUT;
11946        if (reason.extraDelay > 0 && reason.extraDelay < 1000) {
11947          delay += reason.extraDelay;
11948        }
11949        intentState.streamReaderCancelTimeout = setTimeout(() => {
11950          intentState.streamReaderCancelTimeout = null;
11951          this._abortOperatorList({
11952            intentState,
11953            reason,
11954            force: true
11955          });
11956        }, delay);
11957        return;
11958      }
11959    }
11960    intentState.streamReader.cancel(new AbortException(reason.message)).catch(() => {});
11961    intentState.streamReader = null;
11962    if (this._transport.destroyed) {
11963      return;
11964    }
11965    for (const [curCacheKey, curIntentState] of this._intentStates) {
11966      if (curIntentState === intentState) {
11967        this._intentStates.delete(curCacheKey);
11968        break;
11969      }
11970    }
11971    this.cleanup();
11972  }
11973  get stats() {
11974    return this._stats;
11975  }
11976}
11977class LoopbackPort {
11978  #listeners = new Map();
11979  #deferred = Promise.resolve();
11980  postMessage(obj, transfer) {
11981    const event = {
11982      data: structuredClone(obj, transfer ? {
11983        transfer
11984      } : null)
11985    };
11986    this.#deferred.then(() => {
11987      for (const [listener] of this.#listeners) {
11988        listener.call(this, event);
11989      }
11990    });
11991  }
11992  addEventListener(name, listener, options = null) {
11993    let rmAbort = null;
11994    if (options?.signal instanceof AbortSignal) {
11995      const {
11996        signal
11997      } = options;
11998      if (signal.aborted) {
11999        warn("LoopbackPort - cannot use an `aborted` signal.");
12000        return;
12001      }
12002      const onAbort = () => this.removeEventListener(name, listener);
12003      rmAbort = () => signal.removeEventListener("abort", onAbort);
12004      signal.addEventListener("abort", onAbort);
12005    }
12006    this.#listeners.set(listener, rmAbort);
12007  }
12008  removeEventListener(name, listener) {
12009    const rmAbort = this.#listeners.get(listener);
12010    rmAbort?.();
12011    this.#listeners.delete(listener);
12012  }
12013  terminate() {
12014    for (const [, rmAbort] of this.#listeners) {
12015      rmAbort?.();
12016    }
12017    this.#listeners.clear();
12018  }
12019}
12020class PDFWorker {
12021  static #fakeWorkerId = 0;
12022  static #isWorkerDisabled = false;
12023  static #workerPorts;
12024  static {
12025    if (isNodeJS) {
12026      this.#isWorkerDisabled = true;
12027      GlobalWorkerOptions.workerSrc ||= "./pdf.worker.js";
12028    }
12029    this._isSameOrigin = (baseUrl, otherUrl) => {
12030      let base;
12031      try {
12032        base = new URL(baseUrl);
12033        if (!base.origin || base.origin === "null") {
12034          return false;
12035        }
12036      } catch {
12037        return false;
12038      }
12039      const other = new URL(otherUrl, base);
12040      return base.origin === other.origin;
12041    };
12042    this._createCDNWrapper = url => {
12043      const wrapper = `await import("${url}");`;
12044      return URL.createObjectURL(new Blob([wrapper], {
12045        type: "text/javascript"
12046      }));
12047    };
12048  }
12049  constructor({
12050    name = null,
12051    port = null,
12052    verbosity = getVerbosityLevel()
12053  } = {}) {
12054    this.name = name;
12055    this.destroyed = false;
12056    this.verbosity = verbosity;
12057    this._readyCapability = Promise.withResolvers();
12058    this._port = null;
12059    this._webWorker = null;
12060    this._messageHandler = null;
12061    if (port) {
12062      if (PDFWorker.#workerPorts?.has(port)) {
12063        throw new Error("Cannot use more than one PDFWorker per port.");
12064      }
12065      (PDFWorker.#workerPorts ||= new WeakMap()).set(port, this);
12066      this._initializeFromPort(port);
12067      return;
12068    }
12069    this._initialize();
12070  }
12071  get promise() {
12072    if (isNodeJS) {
12073      return Promise.all([NodePackages.promise, this._readyCapability.promise]);
12074    }
12075    return this._readyCapability.promise;
12076  }
12077  #resolve() {
12078    this._readyCapability.resolve();
12079    this._messageHandler.send("configure", {
12080      verbosity: this.verbosity
12081    });
12082  }
12083  get port() {
12084    return this._port;
12085  }
12086  get messageHandler() {
12087    return this._messageHandler;
12088  }
12089  _initializeFromPort(port) {
12090    this._port = port;
12091    this._messageHandler = new MessageHandler("main", "worker", port);
12092    this._messageHandler.on("ready", function () {});
12093    this.#resolve();
12094  }
12095  _initialize() {
12096    if (PDFWorker.#isWorkerDisabled || PDFWorker.#mainThreadWorkerMessageHandler) {
12097      this._setupFakeWorker();
12098      return;
12099    }
12100    let {
12101      workerSrc
12102    } = PDFWorker;
12103    try {
12104      if (!PDFWorker._isSameOrigin(window.location.href, workerSrc)) {
12105        workerSrc = PDFWorker._createCDNWrapper(new URL(workerSrc, window.location).href);
12106      }
12107      const worker = new Worker(workerSrc, {
12108        type: "module"
12109      });
12110      const messageHandler = new MessageHandler("main", "worker", worker);
12111      const terminateEarly = () => {
12112        ac.abort();
12113        messageHandler.destroy();
12114        worker.terminate();
12115        if (this.destroyed) {
12116          this._readyCapability.reject(new Error("Worker was destroyed"));
12117        } else {
12118          this._setupFakeWorker();
12119        }
12120      };
12121      const ac = new AbortController();
12122      worker.addEventListener("error", () => {
12123        if (!this._webWorker) {
12124          terminateEarly();
12125        }
12126      }, {
12127        signal: ac.signal
12128      });
12129      messageHandler.on("test", data => {
12130        ac.abort();
12131        if (this.destroyed || !data) {
12132          terminateEarly();
12133          return;
12134        }
12135        this._messageHandler = messageHandler;
12136        this._port = worker;
12137        this._webWorker = worker;
12138        this.#resolve();
12139      });
12140      messageHandler.on("ready", data => {
12141        ac.abort();
12142        if (this.destroyed) {
12143          terminateEarly();
12144          return;
12145        }
12146        try {
12147          sendTest();
12148        } catch {
12149          this._setupFakeWorker();
12150        }
12151      });
12152      const sendTest = () => {
12153        const testObj = new Uint8Array();
12154        messageHandler.send("test", testObj, [testObj.buffer]);
12155      };
12156      sendTest();
12157      return;
12158    } catch {
12159      info("The worker has been disabled.");
12160    }
12161    this._setupFakeWorker();
12162  }
12163  _setupFakeWorker() {
12164    if (!PDFWorker.#isWorkerDisabled) {
12165      warn("Setting up fake worker.");
12166      PDFWorker.#isWorkerDisabled = true;
12167    }
12168    PDFWorker._setupFakeWorkerGlobal.then(WorkerMessageHandler => {
12169      if (this.destroyed) {
12170        this._readyCapability.reject(new Error("Worker was destroyed"));
12171        return;
12172      }
12173      const port = new LoopbackPort();
12174      this._port = port;
vendor: 5,740 bytes, lines 12175-12336
12175      const id = `fake${PDFWorker.#fakeWorkerId++}`;
12176      const workerHandler = new MessageHandler(id + "_worker", id, port);
12177      WorkerMessageHandler.setup(workerHandler, port);
12178      this._messageHandler = new MessageHandler(id, id + "_worker", port);
12179      this.#resolve();
12180    }).catch(reason => {
12181      this._readyCapability.reject(new Error(`Setting up fake worker failed: "${reason.message}".`));
12182    });
12183  }
12184  destroy() {
12185    this.destroyed = true;
12186    if (this._webWorker) {
12187      this._webWorker.terminate();
12188      this._webWorker = null;
12189    }
12190    PDFWorker.#workerPorts?.delete(this._port);
12191    this._port = null;
12192    if (this._messageHandler) {
12193      this._messageHandler.destroy();
12194      this._messageHandler = null;
12195    }
12196  }
12197  static fromPort(params) {
12198    if (!params?.port) {
12199      throw new Error("PDFWorker.fromPort - invalid method signature.");
12200    }
12201    const cachedPort = this.#workerPorts?.get(params.port);
12202    if (cachedPort) {
12203      if (cachedPort._pendingDestroy) {
12204        throw new Error("PDFWorker.fromPort - the worker is being destroyed.\n" + "Please remember to await `PDFDocumentLoadingTask.destroy()`-calls.");
12205      }
12206      return cachedPort;
12207    }
12208    return new PDFWorker(params);
12209  }
12210  static get workerSrc() {
12211    if (GlobalWorkerOptions.workerSrc) {
12212      return GlobalWorkerOptions.workerSrc;
12213    }
12214    throw new Error('No "GlobalWorkerOptions.workerSrc" specified.');
12215  }
12216  static get #mainThreadWorkerMessageHandler() {
12217    try {
12218      return globalThis.pdfjsWorker?.WorkerMessageHandler || null;
12219    } catch {
12220      return null;
12221    }
12222  }
12223  static get _setupFakeWorkerGlobal() {
12224    const loader = async () => {
12225      if (this.#mainThreadWorkerMessageHandler) {
12226        return this.#mainThreadWorkerMessageHandler;
12227      }
12228      const worker = await import(/*webpackIgnore: true*/this.workerSrc);
12229      return worker.WorkerMessageHandler;
12230    };
12231    return shadow(this, "_setupFakeWorkerGlobal", loader());
12232  }
12233}
12234class WorkerTransport {
12235  #methodPromises = new Map();
12236  #pageCache = new Map();
12237  #pagePromises = new Map();
12238  #pageRefCache = new Map();
12239  #passwordCapability = null;
12240  constructor(messageHandler, loadingTask, networkStream, params, factory) {
12241    this.messageHandler = messageHandler;
12242    this.loadingTask = loadingTask;
12243    this.commonObjs = new PDFObjects();
12244    this.fontLoader = new FontLoader({
12245      ownerDocument: params.ownerDocument,
12246      styleElement: params.styleElement
12247    });
12248    this.loadingParams = params.loadingParams;
12249    this._params = params;
12250    this.canvasFactory = factory.canvasFactory;
12251    this.filterFactory = factory.filterFactory;
12252    this.cMapReaderFactory = factory.cMapReaderFactory;
12253    this.standardFontDataFactory = factory.standardFontDataFactory;
12254    this.destroyed = false;
12255    this.destroyCapability = null;
12256    this._networkStream = networkStream;
12257    this._fullReader = null;
12258    this._lastProgress = null;
12259    this.downloadInfoCapability = Promise.withResolvers();
12260    this.setupMessageHandler();
12261  }
12262  #cacheSimpleMethod(name, data = null) {
12263    const cachedPromise = this.#methodPromises.get(name);
12264    if (cachedPromise) {
12265      return cachedPromise;
12266    }
12267    const promise = this.messageHandler.sendWithPromise(name, data);
12268    this.#methodPromises.set(name, promise);
12269    return promise;
12270  }
12271  get annotationStorage() {
12272    return shadow(this, "annotationStorage", new AnnotationStorage());
12273  }
12274  getRenderingIntent(intent, annotationMode = AnnotationMode.ENABLE, printAnnotationStorage = null, isEditing = false, isOpList = false) {
12275    let renderingIntent = RenderingIntentFlag.DISPLAY;
12276    let annotationStorageSerializable = SerializableEmpty;
12277    switch (intent) {
12278      case "any":
12279        renderingIntent = RenderingIntentFlag.ANY;
12280        break;
12281      case "display":
12282        break;
12283      case "print":
12284        renderingIntent = RenderingIntentFlag.PRINT;
12285        break;
12286      default:
12287        warn(`getRenderingIntent - invalid intent: ${intent}`);
12288    }
12289    const annotationStorage = renderingIntent & RenderingIntentFlag.PRINT && printAnnotationStorage instanceof PrintAnnotationStorage ? printAnnotationStorage : this.annotationStorage;
12290    switch (annotationMode) {
12291      case AnnotationMode.DISABLE:
12292        renderingIntent += RenderingIntentFlag.ANNOTATIONS_DISABLE;
12293        break;
12294      case AnnotationMode.ENABLE:
12295        break;
12296      case AnnotationMode.ENABLE_FORMS:
12297        renderingIntent += RenderingIntentFlag.ANNOTATIONS_FORMS;
12298        break;
12299      case AnnotationMode.ENABLE_STORAGE:
12300        renderingIntent += RenderingIntentFlag.ANNOTATIONS_STORAGE;
12301        annotationStorageSerializable = annotationStorage.serializable;
12302        break;
12303      default:
12304        warn(`getRenderingIntent - invalid annotationMode: ${annotationMode}`);
12305    }
12306    if (isEditing) {
12307      renderingIntent += RenderingIntentFlag.IS_EDITING;
12308    }
12309    if (isOpList) {
12310      renderingIntent += RenderingIntentFlag.OPLIST;
12311    }
12312    const {
12313      ids: modifiedIds,
12314      hash: modifiedIdsHash
12315    } = annotationStorage.modifiedIds;
12316    const cacheKeyBuf = [renderingIntent, annotationStorageSerializable.hash, modifiedIdsHash];
12317    return {
12318      renderingIntent,
12319      cacheKey: cacheKeyBuf.join("_"),
12320      annotationStorageSerializable,
12321      modifiedIds
12322    };
12323  }
12324  destroy() {
12325    if (this.destroyCapability) {
12326      return this.destroyCapability.promise;
12327    }
12328    this.destroyed = true;
12329    this.destroyCapability = Promise.withResolvers();
12330    this.#passwordCapability?.reject(new Error("Worker was destroyed during onPassword callback"));
12331    const waitOn = [];
12332    for (const page of this.#pageCache.values()) {
12333      waitOn.push(page._destroy());
12334    }
12335    this.#pageCache.clear();
12336    this.#pagePromises.clear();
12337    this.#pageRefCache.clear();
12338    if (this.hasOwnProperty("annotationStorage")) {
12339      this.annotationStorage.resetModified();
12340    }
12341    const terminated = this.messageHandler.sendWithPromise("Terminate", null);
12342    waitOn.push(terminated);
12343    Promise.all(waitOn).then(() => {
12344      this.commonObjs.clear();
12345      this.fontLoader.clear();
12346      this.#methodPromises.clear();
12347      this.filterFactory.destroy();
12348      TextLayer.cleanup();
12349      this._networkStream?.cancelAllRequests(new AbortException("Worker was terminated."));
12350      if (this.messageHandler) {
12351        this.messageHandler.destroy();
12352        this.messageHandler = null;
12353      }
12354      this.destroyCapability.resolve();
12355    }, this.destroyCapability.reject);
12356    return this.destroyCapability.promise;
12357  }
12358  setupMessageHandler() {
12359    const {
12360      messageHandler,
12361      loadingTask
12362    } = this;
12363    messageHandler.on("GetReader", (data, sink) => {
12364      assert(this._networkStream, "GetReader - no `IPDFStream` instance available.");
12365      this._fullReader = this._networkStream.getFullReader();
12366      this._fullReader.onProgress = evt => {
12367        this._lastProgress = {
12368          loaded: evt.loaded,
12369          total: evt.total
12370        };
12371      };
12372      sink.onPull = () => {
12373        this._fullReader.read().then(function ({
12374          value,
12375          done
12376        }) {
12377          if (done) {
12378            sink.close();
12379            return;
12380          }
12381          assert(value instanceof ArrayBuffer, "GetReader - expected an ArrayBuffer.");
12382          sink.enqueue(new Uint8Array(value), 1, [value]);
12383        }).catch(reason => {
12384          sink.error(reason);
12385        });
12386      };
12387      sink.onCancel = reason => {
12388        this._fullReader.cancel(reason);
12389        sink.ready.catch(readyReason => {
12390          if (this.destroyed) {
12391            return;
12392          }
12393          throw readyReason;
12394        });
12395      };
12396    });
12397    messageHandler.on("ReaderHeadersReady", async data => {
12398      await this._fullReader.headersReady;
12399      const {
12400        isStreamingSupported,
12401        isRangeSupported,
12402        contentLength
12403      } = this._fullReader;
12404      if (!isStreamingSupported || !isRangeSupported) {
12405        if (this._lastProgress) {
12406          loadingTask.onProgress?.(this._lastProgress);
12407        }
12408        this._fullReader.onProgress = evt => {
12409          loadingTask.onProgress?.({
12410            loaded: evt.loaded,
12411            total: evt.total
12412          });
12413        };
12414      }
12415      return {
12416        isStreamingSupported,
12417        isRangeSupported,
12418        contentLength
12419      };
12420    });
12421    messageHandler.on("GetRangeReader", (data, sink) => {
12422      assert(this._networkStream, "GetRangeReader - no `IPDFStream` instance available.");
12423      const rangeReader = this._networkStream.getRangeReader(data.begin, data.end);
12424      if (!rangeReader) {
12425        sink.close();
12426        return;
12427      }
12428      sink.onPull = () => {
12429        rangeReader.read().then(function ({
12430          value,
12431          done
12432        }) {
12433          if (done) {
12434            sink.close();
12435            return;
12436          }
12437          assert(value instanceof ArrayBuffer, "GetRangeReader - expected an ArrayBuffer.");
12438          sink.enqueue(new Uint8Array(value), 1, [value]);
12439        }).catch(reason => {
12440          sink.error(reason);
12441        });
12442      };
12443      sink.onCancel = reason => {
12444        rangeReader.cancel(reason);
12445        sink.ready.catch(readyReason => {
12446          if (this.destroyed) {
12447            return;
12448          }
12449          throw readyReason;
12450        });
12451      };
12452    });
12453    messageHandler.on("GetDoc", ({
12454      pdfInfo
12455    }) => {
12456      this._numPages = pdfInfo.numPages;
12457      this._htmlForXfa = pdfInfo.htmlForXfa;
12458      delete pdfInfo.htmlForXfa;
12459      loadingTask._capability.resolve(new PDFDocumentProxy(pdfInfo, this));
12460    });
12461    messageHandler.on("DocException", function (ex) {
12462      let reason;
12463      switch (ex.name) {
12464        case "PasswordException":
12465          reason = new PasswordException(ex.message, ex.code);
12466          break;
12467        case "InvalidPDFException":
12468          reason = new InvalidPDFException(ex.message);
12469          break;
12470        case "MissingPDFException":
12471          reason = new MissingPDFException(ex.message);
12472          break;
12473        case "UnexpectedResponseException":
12474          reason = new UnexpectedResponseException(ex.message, ex.status);
12475          break;
12476        case "UnknownErrorException":
12477          reason = new UnknownErrorException(ex.message, ex.details);
12478          break;
12479        default:
12480          unreachable("DocException - expected a valid Error.");
12481      }
12482      loadingTask._capability.reject(reason);
12483    });
12484    messageHandler.on("PasswordRequest", exception => {
12485      this.#passwordCapability = Promise.withResolvers();
12486      if (loadingTask.onPassword) {
12487        const updatePassword = password => {
12488          if (password instanceof Error) {
12489            this.#passwordCapability.reject(password);
12490          } else {
12491            this.#passwordCapability.resolve({
12492              password
12493            });
12494          }
12495        };
12496        try {
12497          loadingTask.onPassword(updatePassword, exception.code);
12498        } catch (ex) {
12499          this.#passwordCapability.reject(ex);
12500        }
12501      } else {
12502        this.#passwordCapability.reject(new PasswordException(exception.message, exception.code));
12503      }
12504      return this.#passwordCapability.promise;
12505    });
12506    messageHandler.on("DataLoaded", data => {
12507      loadingTask.onProgress?.({
12508        loaded: data.length,
12509        total: data.length
12510      });
12511      this.downloadInfoCapability.resolve(data);
12512    });
12513    messageHandler.on("StartRenderPage", data => {
12514      if (this.destroyed) {
12515        return;
12516      }
12517      const page = this.#pageCache.get(data.pageIndex);
12518      page._startRenderPage(data.transparency, data.cacheKey);
12519    });
12520    messageHandler.on("commonobj", ([id, type, exportedData]) => {
12521      if (this.destroyed) {
12522        return null;
12523      }
12524      if (this.commonObjs.has(id)) {
12525        return null;
12526      }
12527      switch (type) {
12528        case "Font":
12529          const {
12530            disableFontFace,
12531            fontExtraProperties,
12532            pdfBug
12533          } = this._params;
12534          if ("error" in exportedData) {
12535            const exportedError = exportedData.error;
12536            warn(`Error during font loading: ${exportedError}`);
12537            this.commonObjs.resolve(id, exportedError);
12538            break;
12539          }
12540          const inspectFont = pdfBug && globalThis.FontInspector?.enabled ? (font, url) => globalThis.FontInspector.fontAdded(font, url) : null;
12541          const font = new FontFaceObject(exportedData, {
12542            disableFontFace,
12543            inspectFont
12544          });
12545          this.fontLoader.bind(font).catch(() => messageHandler.sendWithPromise("FontFallback", {
12546            id
12547          })).finally(() => {
12548            if (!fontExtraProperties && font.data) {
12549              font.data = null;
12550            }
12551            this.commonObjs.resolve(id, font);
12552          });
12553          break;
12554        case "CopyLocalImage":
12555          const {
12556            imageRef
12557          } = exportedData;
12558          assert(imageRef, "The imageRef must be defined.");
12559          for (const pageProxy of this.#pageCache.values()) {
12560            for (const [, data] of pageProxy.objs) {
12561              if (data?.ref !== imageRef) {
12562                continue;
12563              }
12564              if (!data.dataLen) {
12565                return null;
12566              }
12567              this.commonObjs.resolve(id, structuredClone(data));
12568              return data.dataLen;
12569            }
12570          }
12571          break;
12572        case "FontPath":
12573        case "Image":
12574        case "Pattern":
12575          this.commonObjs.resolve(id, exportedData);
12576          break;
12577        default:
12578          throw new Error(`Got unknown common object type ${type}`);
12579      }
12580      return null;
12581    });
12582    messageHandler.on("obj", ([id, pageIndex, type, imageData]) => {
12583      if (this.destroyed) {
12584        return;
12585      }
12586      const pageProxy = this.#pageCache.get(pageIndex);
12587      if (pageProxy.objs.has(id)) {
12588        return;
12589      }
12590      if (pageProxy._intentStates.size === 0) {
12591        imageData?.bitmap?.close();
12592        return;
12593      }
12594      switch (type) {
12595        case "Image":
12596          pageProxy.objs.resolve(id, imageData);
12597          if (imageData?.dataLen > MAX_IMAGE_SIZE_TO_CACHE) {
12598            pageProxy._maybeCleanupAfterRender = true;
12599          }
12600          break;
12601        case "Pattern":
12602          pageProxy.objs.resolve(id, imageData);
12603          break;
12604        default:
12605          throw new Error(`Got unknown object type ${type}`);
12606      }
12607    });
12608    messageHandler.on("DocProgress", data => {
12609      if (this.destroyed) {
12610        return;
12611      }
12612      loadingTask.onProgress?.({
12613        loaded: data.loaded,
12614        total: data.total
12615      });
12616    });
12617    messageHandler.on("FetchBuiltInCMap", async data => {
12618      if (this.destroyed) {
12619        throw new Error("Worker was destroyed.");
12620      }
12621      if (!this.cMapReaderFactory) {
12622        throw new Error("CMapReaderFactory not initialized, see the `useWorkerFetch` parameter.");
12623      }
12624      return this.cMapReaderFactory.fetch(data);
12625    });
12626    messageHandler.on("FetchStandardFontData", async data => {
12627      if (this.destroyed) {
12628        throw new Error("Worker was destroyed.");
12629      }
12630      if (!this.standardFontDataFactory) {
12631        throw new Error("StandardFontDataFactory not initialized, see the `useWorkerFetch` parameter.");
12632      }
12633      return this.standardFontDataFactory.fetch(data);
12634    });
12635  }
12636  getData() {
12637    return this.messageHandler.sendWithPromise("GetData", null);
12638  }
12639  saveDocument() {
12640    if (this.annotationStorage.size <= 0) {
12641      warn("saveDocument called while `annotationStorage` is empty, " + "please use the getData-method instead.");
12642    }
12643    const {
12644      map,
12645      transfer
12646    } = this.annotationStorage.serializable;
12647    return this.messageHandler.sendWithPromise("SaveDocument", {
12648      isPureXfa: !!this._htmlForXfa,
12649      numPages: this._numPages,
12650      annotationStorage: map,
12651      filename: this._fullReader?.filename ?? null
12652    }, transfer).finally(() => {
12653      this.annotationStorage.resetModified();
12654    });
12655  }
12656  getPage(pageNumber) {
12657    if (!Number.isInteger(pageNumber) || pageNumber <= 0 || pageNumber > this._numPages) {
12658      return Promise.reject(new Error("Invalid page request."));
12659    }
12660    const pageIndex = pageNumber - 1,
12661      cachedPromise = this.#pagePromises.get(pageIndex);
12662    if (cachedPromise) {
12663      return cachedPromise;
12664    }
12665    const promise = this.messageHandler.sendWithPromise("GetPage", {
12666      pageIndex
12667    }).then(pageInfo => {
12668      if (this.destroyed) {
12669        throw new Error("Transport destroyed");
12670      }
12671      if (pageInfo.refStr) {
vendor: 19,015 bytes, lines 12672-13320
12672        this.#pageRefCache.set(pageInfo.refStr, pageNumber);
12673      }
12674      const page = new PDFPageProxy(pageIndex, pageInfo, this, this._params.pdfBug);
12675      this.#pageCache.set(pageIndex, page);
12676      return page;
12677    });
12678    this.#pagePromises.set(pageIndex, promise);
12679    return promise;
12680  }
12681  getPageIndex(ref) {
12682    if (!isRefProxy(ref)) {
12683      return Promise.reject(new Error("Invalid pageIndex request."));
12684    }
12685    return this.messageHandler.sendWithPromise("GetPageIndex", {
12686      num: ref.num,
12687      gen: ref.gen
12688    });
12689  }
12690  getAnnotations(pageIndex, intent) {
12691    return this.messageHandler.sendWithPromise("GetAnnotations", {
12692      pageIndex,
12693      intent
12694    });
12695  }
12696  getFieldObjects() {
12697    return this.#cacheSimpleMethod("GetFieldObjects");
12698  }
12699  hasJSActions() {
12700    return this.#cacheSimpleMethod("HasJSActions");
12701  }
12702  getCalculationOrderIds() {
12703    return this.messageHandler.sendWithPromise("GetCalculationOrderIds", null);
12704  }
12705  getDestinations() {
12706    return this.messageHandler.sendWithPromise("GetDestinations", null);
12707  }
12708  getDestination(id) {
12709    if (typeof id !== "string") {
12710      return Promise.reject(new Error("Invalid destination request."));
12711    }
12712    return this.messageHandler.sendWithPromise("GetDestination", {
12713      id
12714    });
12715  }
12716  getPageLabels() {
12717    return this.messageHandler.sendWithPromise("GetPageLabels", null);
12718  }
12719  getPageLayout() {
12720    return this.messageHandler.sendWithPromise("GetPageLayout", null);
12721  }
12722  getPageMode() {
12723    return this.messageHandler.sendWithPromise("GetPageMode", null);
12724  }
12725  getViewerPreferences() {
12726    return this.messageHandler.sendWithPromise("GetViewerPreferences", null);
12727  }
12728  getOpenAction() {
12729    return this.messageHandler.sendWithPromise("GetOpenAction", null);
12730  }
12731  getAttachments() {
12732    return this.messageHandler.sendWithPromise("GetAttachments", null);
12733  }
12734  getDocJSActions() {
12735    return this.#cacheSimpleMethod("GetDocJSActions");
12736  }
12737  getPageJSActions(pageIndex) {
12738    return this.messageHandler.sendWithPromise("GetPageJSActions", {
12739      pageIndex
12740    });
12741  }
12742  getStructTree(pageIndex) {
12743    return this.messageHandler.sendWithPromise("GetStructTree", {
12744      pageIndex
12745    });
12746  }
12747  getOutline() {
12748    return this.messageHandler.sendWithPromise("GetOutline", null);
12749  }
12750  getOptionalContentConfig(renderingIntent) {
12751    return this.#cacheSimpleMethod("GetOptionalContentConfig").then(data => new OptionalContentConfig(data, renderingIntent));
12752  }
12753  getPermissions() {
12754    return this.messageHandler.sendWithPromise("GetPermissions", null);
12755  }
12756  getMetadata() {
12757    const name = "GetMetadata",
12758      cachedPromise = this.#methodPromises.get(name);
12759    if (cachedPromise) {
12760      return cachedPromise;
12761    }
12762    const promise = this.messageHandler.sendWithPromise(name, null).then(results => ({
12763      info: results[0],
12764      metadata: results[1] ? new Metadata(results[1]) : null,
12765      contentDispositionFilename: this._fullReader?.filename ?? null,
12766      contentLength: this._fullReader?.contentLength ?? null
12767    }));
12768    this.#methodPromises.set(name, promise);
12769    return promise;
12770  }
12771  getMarkInfo() {
12772    return this.messageHandler.sendWithPromise("GetMarkInfo", null);
12773  }
12774  async startCleanup(keepLoadedFonts = false) {
12775    if (this.destroyed) {
12776      return;
12777    }
12778    await this.messageHandler.sendWithPromise("Cleanup", null);
12779    for (const page of this.#pageCache.values()) {
12780      const cleanupSuccessful = page.cleanup();
12781      if (!cleanupSuccessful) {
12782        throw new Error(`startCleanup: Page ${page.pageNumber} is currently rendering.`);
12783      }
12784    }
12785    this.commonObjs.clear();
12786    if (!keepLoadedFonts) {
12787      this.fontLoader.clear();
12788    }
12789    this.#methodPromises.clear();
12790    this.filterFactory.destroy(true);
12791    TextLayer.cleanup();
12792  }
12793  cachedPageNumber(ref) {
12794    if (!isRefProxy(ref)) {
12795      return null;
12796    }
12797    const refStr = ref.gen === 0 ? `${ref.num}R` : `${ref.num}R${ref.gen}`;
12798    return this.#pageRefCache.get(refStr) ?? null;
12799  }
12800}
12801const INITIAL_DATA = Symbol("INITIAL_DATA");
12802class PDFObjects {
12803  #objs = Object.create(null);
12804  #ensureObj(objId) {
12805    return this.#objs[objId] ||= {
12806      ...Promise.withResolvers(),
12807      data: INITIAL_DATA
12808    };
12809  }
12810  get(objId, callback = null) {
12811    if (callback) {
12812      const obj = this.#ensureObj(objId);
12813      obj.promise.then(() => callback(obj.data));
12814      return null;
12815    }
12816    const obj = this.#objs[objId];
12817    if (!obj || obj.data === INITIAL_DATA) {
12818      throw new Error(`Requesting object that isn't resolved yet ${objId}.`);
12819    }
12820    return obj.data;
12821  }
12822  has(objId) {
12823    const obj = this.#objs[objId];
12824    return !!obj && obj.data !== INITIAL_DATA;
12825  }
12826  resolve(objId, data = null) {
12827    const obj = this.#ensureObj(objId);
12828    obj.data = data;
12829    obj.resolve();
12830  }
12831  clear() {
12832    for (const objId in this.#objs) {
12833      const {
12834        data
12835      } = this.#objs[objId];
12836      data?.bitmap?.close();
12837    }
12838    this.#objs = Object.create(null);
12839  }
12840  *[Symbol.iterator]() {
12841    for (const objId in this.#objs) {
12842      const {
12843        data
12844      } = this.#objs[objId];
12845      if (data === INITIAL_DATA) {
12846        continue;
12847      }
12848      yield [objId, data];
12849    }
12850  }
12851}
12852class RenderTask {
12853  #internalRenderTask = null;
12854  constructor(internalRenderTask) {
12855    this.#internalRenderTask = internalRenderTask;
12856    this.onContinue = null;
12857  }
12858  get promise() {
12859    return this.#internalRenderTask.capability.promise;
12860  }
12861  cancel(extraDelay = 0) {
12862    this.#internalRenderTask.cancel(null, extraDelay);
12863  }
12864  get separateAnnots() {
12865    const {
12866      separateAnnots
12867    } = this.#internalRenderTask.operatorList;
12868    if (!separateAnnots) {
12869      return false;
12870    }
12871    const {
12872      annotationCanvasMap
12873    } = this.#internalRenderTask;
12874    return separateAnnots.form || separateAnnots.canvas && annotationCanvasMap?.size > 0;
12875  }
12876}
12877class InternalRenderTask {
12878  #rAF = null;
12879  static #canvasInUse = new WeakSet();
12880  constructor({
12881    callback,
12882    params,
12883    objs,
12884    commonObjs,
12885    annotationCanvasMap,
12886    operatorList,
12887    pageIndex,
12888    canvasFactory,
12889    filterFactory,
12890    useRequestAnimationFrame = false,
12891    pdfBug = false,
12892    pageColors = null
12893  }) {
12894    this.callback = callback;
12895    this.params = params;
12896    this.objs = objs;
12897    this.commonObjs = commonObjs;
12898    this.annotationCanvasMap = annotationCanvasMap;
12899    this.operatorListIdx = null;
12900    this.operatorList = operatorList;
12901    this._pageIndex = pageIndex;
12902    this.canvasFactory = canvasFactory;
12903    this.filterFactory = filterFactory;
12904    this._pdfBug = pdfBug;
12905    this.pageColors = pageColors;
12906    this.running = false;
12907    this.graphicsReadyCallback = null;
12908    this.graphicsReady = false;
12909    this._useRequestAnimationFrame = useRequestAnimationFrame === true && typeof window !== "undefined";
12910    this.cancelled = false;
12911    this.capability = Promise.withResolvers();
12912    this.task = new RenderTask(this);
12913    this._cancelBound = this.cancel.bind(this);
12914    this._continueBound = this._continue.bind(this);
12915    this._scheduleNextBound = this._scheduleNext.bind(this);
12916    this._nextBound = this._next.bind(this);
12917    this._canvas = params.canvasContext.canvas;
12918  }
12919  get completed() {
12920    return this.capability.promise.catch(function () {});
12921  }
12922  initializeGraphics({
12923    transparency = false,
12924    optionalContentConfig
12925  }) {
12926    if (this.cancelled) {
12927      return;
12928    }
12929    if (this._canvas) {
12930      if (InternalRenderTask.#canvasInUse.has(this._canvas)) {
12931        throw new Error("Cannot use the same canvas during multiple render() operations. " + "Use different canvas or ensure previous operations were " + "cancelled or completed.");
12932      }
12933      InternalRenderTask.#canvasInUse.add(this._canvas);
12934    }
12935    if (this._pdfBug && globalThis.StepperManager?.enabled) {
12936      this.stepper = globalThis.StepperManager.create(this._pageIndex);
12937      this.stepper.init(this.operatorList);
12938      this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
12939    }
12940    const {
12941      canvasContext,
12942      viewport,
12943      transform,
12944      background
12945    } = this.params;
12946    this.gfx = new CanvasGraphics(canvasContext, this.commonObjs, this.objs, this.canvasFactory, this.filterFactory, {
12947      optionalContentConfig
12948    }, this.annotationCanvasMap, this.pageColors);
12949    this.gfx.beginDrawing({
12950      transform,
12951      viewport,
12952      transparency,
12953      background
12954    });
12955    this.operatorListIdx = 0;
12956    this.graphicsReady = true;
12957    this.graphicsReadyCallback?.();
12958  }
12959  cancel(error = null, extraDelay = 0) {
12960    this.running = false;
12961    this.cancelled = true;
12962    this.gfx?.endDrawing();
12963    if (this.#rAF) {
12964      window.cancelAnimationFrame(this.#rAF);
12965      this.#rAF = null;
12966    }
12967    InternalRenderTask.#canvasInUse.delete(this._canvas);
12968    this.callback(error || new RenderingCancelledException(`Rendering cancelled, page ${this._pageIndex + 1}`, extraDelay));
12969  }
12970  operatorListChanged() {
12971    if (!this.graphicsReady) {
12972      this.graphicsReadyCallback ||= this._continueBound;
12973      return;
12974    }
12975    this.stepper?.updateOperatorList(this.operatorList);
12976    if (this.running) {
12977      return;
12978    }
12979    this._continue();
12980  }
12981  _continue() {
12982    this.running = true;
12983    if (this.cancelled) {
12984      return;
12985    }
12986    if (this.task.onContinue) {
12987      this.task.onContinue(this._scheduleNextBound);
12988    } else {
12989      this._scheduleNext();
12990    }
12991  }
12992  _scheduleNext() {
12993    if (this._useRequestAnimationFrame) {
12994      this.#rAF = window.requestAnimationFrame(() => {
12995        this.#rAF = null;
12996        this._nextBound().catch(this._cancelBound);
12997      });
12998    } else {
12999      Promise.resolve().then(this._nextBound).catch(this._cancelBound);
13000    }
13001  }
13002  async _next() {
13003    if (this.cancelled) {
13004      return;
13005    }
13006    this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList, this.operatorListIdx, this._continueBound, this.stepper);
13007    if (this.operatorListIdx === this.operatorList.argsArray.length) {
13008      this.running = false;
13009      if (this.operatorList.lastChunk) {
13010        this.gfx.endDrawing();
13011        InternalRenderTask.#canvasInUse.delete(this._canvas);
13012        this.callback();
13013      }
13014    }
13015  }
13016}
13017const version = "4.8.69";
13018const build = "3634dab10";
13019
13020;// ./src/shared/scripting_utils.js
13021function makeColorComp(n) {
13022  return Math.floor(Math.max(0, Math.min(1, n)) * 255).toString(16).padStart(2, "0");
13023}
13024function scaleAndClamp(x) {
13025  return Math.max(0, Math.min(255, 255 * x));
13026}
13027class ColorConverters {
13028  static CMYK_G([c, y, m, k]) {
13029    return ["G", 1 - Math.min(1, 0.3 * c + 0.59 * m + 0.11 * y + k)];
13030  }
13031  static G_CMYK([g]) {
13032    return ["CMYK", 0, 0, 0, 1 - g];
13033  }
13034  static G_RGB([g]) {
13035    return ["RGB", g, g, g];
13036  }
13037  static G_rgb([g]) {
13038    g = scaleAndClamp(g);
13039    return [g, g, g];
13040  }
13041  static G_HTML([g]) {
13042    const G = makeColorComp(g);
13043    return `#${G}${G}${G}`;
13044  }
13045  static RGB_G([r, g, b]) {
13046    return ["G", 0.3 * r + 0.59 * g + 0.11 * b];
13047  }
13048  static RGB_rgb(color) {
13049    return color.map(scaleAndClamp);
13050  }
13051  static RGB_HTML(color) {
13052    return `#${color.map(makeColorComp).join("")}`;
13053  }
13054  static T_HTML() {
13055    return "#00000000";
13056  }
13057  static T_rgb() {
13058    return [null];
13059  }
13060  static CMYK_RGB([c, y, m, k]) {
13061    return ["RGB", 1 - Math.min(1, c + k), 1 - Math.min(1, m + k), 1 - Math.min(1, y + k)];
13062  }
13063  static CMYK_rgb([c, y, m, k]) {
13064    return [scaleAndClamp(1 - Math.min(1, c + k)), scaleAndClamp(1 - Math.min(1, m + k)), scaleAndClamp(1 - Math.min(1, y + k))];
13065  }
13066  static CMYK_HTML(components) {
13067    const rgb = this.CMYK_RGB(components).slice(1);
13068    return this.RGB_HTML(rgb);
13069  }
13070  static RGB_CMYK([r, g, b]) {
13071    const c = 1 - r;
13072    const m = 1 - g;
13073    const y = 1 - b;
13074    const k = Math.min(c, m, y);
13075    return ["CMYK", c, m, y, k];
13076  }
13077}
13078
13079;// ./src/display/svg_factory.js
13080
13081
13082class BaseSVGFactory {
13083  create(width, height, skipDimensions = false) {
13084    if (width <= 0 || height <= 0) {
13085      throw new Error("Invalid SVG dimensions");
13086    }
13087    const svg = this._createSVG("svg:svg");
13088    svg.setAttribute("version", "1.1");
13089    if (!skipDimensions) {
13090      svg.setAttribute("width", `${width}px`);
13091      svg.setAttribute("height", `${height}px`);
13092    }
13093    svg.setAttribute("preserveAspectRatio", "none");
13094    svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
13095    return svg;
13096  }
13097  createElement(type) {
13098    if (typeof type !== "string") {
13099      throw new Error("Invalid SVG element type");
13100    }
13101    return this._createSVG(type);
13102  }
13103  _createSVG(type) {
13104    unreachable("Abstract method `_createSVG` called.");
13105  }
13106}
13107class DOMSVGFactory extends BaseSVGFactory {
13108  _createSVG(type) {
13109    return document.createElementNS(SVG_NS, type);
13110  }
13111}
13112
13113;// ./src/display/xfa_layer.js
13114
13115class XfaLayer {
13116  static setupStorage(html, id, element, storage, intent) {
13117    const storedData = storage.getValue(id, {
13118      value: null
13119    });
13120    switch (element.name) {
13121      case "textarea":
13122        if (storedData.value !== null) {
13123          html.textContent = storedData.value;
13124        }
13125        if (intent === "print") {
13126          break;
13127        }
13128        html.addEventListener("input", event => {
13129          storage.setValue(id, {
13130            value: event.target.value
13131          });
13132        });
13133        break;
13134      case "input":
13135        if (element.attributes.type === "radio" || element.attributes.type === "checkbox") {
13136          if (storedData.value === element.attributes.xfaOn) {
13137            html.setAttribute("checked", true);
13138          } else if (storedData.value === element.attributes.xfaOff) {
13139            html.removeAttribute("checked");
13140          }
13141          if (intent === "print") {
13142            break;
13143          }
13144          html.addEventListener("change", event => {
13145            storage.setValue(id, {
13146              value: event.target.checked ? event.target.getAttribute("xfaOn") : event.target.getAttribute("xfaOff")
13147            });
13148          });
13149        } else {
13150          if (storedData.value !== null) {
13151            html.setAttribute("value", storedData.value);
13152          }
13153          if (intent === "print") {
13154            break;
13155          }
13156          html.addEventListener("input", event => {
13157            storage.setValue(id, {
13158              value: event.target.value
13159            });
13160          });
13161        }
13162        break;
13163      case "select":
13164        if (storedData.value !== null) {
13165          html.setAttribute("value", storedData.value);
13166          for (const option of element.children) {
13167            if (option.attributes.value === storedData.value) {
13168              option.attributes.selected = true;
13169            } else if (option.attributes.hasOwnProperty("selected")) {
13170              delete option.attributes.selected;
13171            }
13172          }
13173        }
13174        html.addEventListener("input", event => {
13175          const options = event.target.options;
13176          const value = options.selectedIndex === -1 ? "" : options[options.selectedIndex].value;
13177          storage.setValue(id, {
13178            value
13179          });
13180        });
13181        break;
13182    }
13183  }
13184  static setAttributes({
13185    html,
13186    element,
13187    storage = null,
13188    intent,
13189    linkService
13190  }) {
13191    const {
13192      attributes
13193    } = element;
13194    const isHTMLAnchorElement = html instanceof HTMLAnchorElement;
13195    if (attributes.type === "radio") {
13196      attributes.name = `${attributes.name}-${intent}`;
13197    }
13198    for (const [key, value] of Object.entries(attributes)) {
13199      if (value === null || value === undefined) {
13200        continue;
13201      }
13202      switch (key) {
13203        case "class":
13204          if (value.length) {
13205            html.setAttribute(key, value.join(" "));
13206          }
13207          break;
13208        case "dataId":
13209          break;
13210        case "id":
13211          html.setAttribute("data-element-id", value);
13212          break;
13213        case "style":
13214          Object.assign(html.style, value);
13215          break;
13216        case "textContent":
13217          html.textContent = value;
13218          break;
13219        default:
13220          if (!isHTMLAnchorElement || key !== "href" && key !== "newWindow") {
13221            html.setAttribute(key, value);
13222          }
13223      }
13224    }
13225    if (isHTMLAnchorElement) {
13226      linkService.addLinkAttributes(html, attributes.href, attributes.newWindow);
13227    }
13228    if (storage && attributes.dataId) {
13229      this.setupStorage(html, attributes.dataId, element, storage);
13230    }
13231  }
13232  static render(parameters) {
13233    const storage = parameters.annotationStorage;
13234    const linkService = parameters.linkService;
13235    const root = parameters.xfaHtml;
13236    const intent = parameters.intent || "display";
13237    const rootHtml = document.createElement(root.name);
13238    if (root.attributes) {
13239      this.setAttributes({
13240        html: rootHtml,
13241        element: root,
13242        intent,
13243        linkService
13244      });
13245    }
13246    const isNotForRichText = intent !== "richText";
13247    const rootDiv = parameters.div;
13248    rootDiv.append(rootHtml);
13249    if (parameters.viewport) {
13250      const transform = `matrix(${parameters.viewport.transform.join(",")})`;
13251      rootDiv.style.transform = transform;
13252    }
13253    if (isNotForRichText) {
13254      rootDiv.setAttribute("class", "xfaLayer xfaFont");
13255    }
13256    const textDivs = [];
13257    if (root.children.length === 0) {
13258      if (root.value) {
13259        const node = document.createTextNode(root.value);
13260        rootHtml.append(node);
13261        if (isNotForRichText && XfaText.shouldBuildText(root.name)) {
13262          textDivs.push(node);
13263        }
13264      }
13265      return {
13266        textDivs
13267      };
13268    }
13269    const stack = [[root, -1, rootHtml]];
13270    while (stack.length > 0) {
13271      const [parent, i, html] = stack.at(-1);
13272      if (i + 1 === parent.children.length) {
13273        stack.pop();
13274        continue;
13275      }
13276      const child = parent.children[++stack.at(-1)[1]];
13277      if (child === null) {
13278        continue;
13279      }
13280      const {
13281        name
13282      } = child;
13283      if (name === "#text") {
13284        const node = document.createTextNode(child.value);
13285        textDivs.push(node);
13286        html.append(node);
13287        continue;
13288      }
13289      const childHtml = child?.attributes?.xmlns ? document.createElementNS(child.attributes.xmlns, name) : document.createElement(name);
13290      html.append(childHtml);
13291      if (child.attributes) {
13292        this.setAttributes({
13293          html: childHtml,
13294          element: child,
13295          storage,
13296          intent,
13297          linkService
13298        });
13299      }
13300      if (child.children?.length > 0) {
13301        stack.push([child, -1, childHtml]);
13302      } else if (child.value) {
13303        const node = document.createTextNode(child.value);
13304        if (isNotForRichText && XfaText.shouldBuildText(name)) {
13305          textDivs.push(node);
13306        }
13307        childHtml.append(node);
13308      }
13309    }
13310    for (const el of rootDiv.querySelectorAll(".xfaNonInteractive input, .xfaNonInteractive textarea")) {
13311      el.setAttribute("readOnly", true);
13312    }
13313    return {
13314      textDivs
13315    };
13316  }
13317  static update(parameters) {
13318    const transform = `matrix(${parameters.viewport.transform.join(",")})`;
13319    parameters.div.style.transform = transform;
13320    parameters.div.hidden = false;
vendor: 11,731 bytes, lines 13321-13697
13321  }
13322}
13323
13324;// ./src/display/annotation_layer.js
13325
13326
13327
13328
13329
13330
13331const DEFAULT_TAB_INDEX = 1000;
13332const annotation_layer_DEFAULT_FONT_SIZE = 9;
13333const GetElementsByNameSet = new WeakSet();
13334function getRectDims(rect) {
13335  return {
13336    width: rect[2] - rect[0],
13337    height: rect[3] - rect[1]
13338  };
13339}
13340class AnnotationElementFactory {
13341  static create(parameters) {
13342    const subtype = parameters.data.annotationType;
13343    switch (subtype) {
13344      case AnnotationType.LINK:
13345        return new LinkAnnotationElement(parameters);
13346      case AnnotationType.TEXT:
13347        return new TextAnnotationElement(parameters);
13348      case AnnotationType.WIDGET:
13349        const fieldType = parameters.data.fieldType;
13350        switch (fieldType) {
13351          case "Tx":
13352            return new TextWidgetAnnotationElement(parameters);
13353          case "Btn":
13354            if (parameters.data.radioButton) {
13355              return new RadioButtonWidgetAnnotationElement(parameters);
13356            } else if (parameters.data.checkBox) {
13357              return new CheckboxWidgetAnnotationElement(parameters);
13358            }
13359            return new PushButtonWidgetAnnotationElement(parameters);
13360          case "Ch":
13361            return new ChoiceWidgetAnnotationElement(parameters);
13362          case "Sig":
13363            return new SignatureWidgetAnnotationElement(parameters);
13364        }
13365        return new WidgetAnnotationElement(parameters);
13366      case AnnotationType.POPUP:
13367        return new PopupAnnotationElement(parameters);
13368      case AnnotationType.FREETEXT:
13369        return new FreeTextAnnotationElement(parameters);
13370      case AnnotationType.LINE:
13371        return new LineAnnotationElement(parameters);
13372      case AnnotationType.SQUARE:
13373        return new SquareAnnotationElement(parameters);
13374      case AnnotationType.CIRCLE:
13375        return new CircleAnnotationElement(parameters);
13376      case AnnotationType.POLYLINE:
13377        return new PolylineAnnotationElement(parameters);
13378      case AnnotationType.CARET:
13379        return new CaretAnnotationElement(parameters);
13380      case AnnotationType.INK:
13381        return new InkAnnotationElement(parameters);
13382      case AnnotationType.POLYGON:
13383        return new PolygonAnnotationElement(parameters);
13384      case AnnotationType.HIGHLIGHT:
13385        return new HighlightAnnotationElement(parameters);
13386      case AnnotationType.UNDERLINE:
13387        return new UnderlineAnnotationElement(parameters);
13388      case AnnotationType.SQUIGGLY:
13389        return new SquigglyAnnotationElement(parameters);
13390      case AnnotationType.STRIKEOUT:
13391        return new StrikeOutAnnotationElement(parameters);
13392      case AnnotationType.STAMP:
13393        return new StampAnnotationElement(parameters);
13394      case AnnotationType.FILEATTACHMENT:
13395        return new FileAttachmentAnnotationElement(parameters);
13396      default:
13397        return new AnnotationElement(parameters);
13398    }
13399  }
13400}
13401class AnnotationElement {
13402  #updates = null;
13403  #hasBorder = false;
13404  #popupElement = null;
13405  constructor(parameters, {
13406    isRenderable = false,
13407    ignoreBorder = false,
13408    createQuadrilaterals = false
13409  } = {}) {
13410    this.isRenderable = isRenderable;
13411    this.data = parameters.data;
13412    this.layer = parameters.layer;
13413    this.linkService = parameters.linkService;
13414    this.downloadManager = parameters.downloadManager;
13415    this.imageResourcesPath = parameters.imageResourcesPath;
13416    this.renderForms = parameters.renderForms;
13417    this.svgFactory = parameters.svgFactory;
13418    this.annotationStorage = parameters.annotationStorage;
13419    this.enableScripting = parameters.enableScripting;
13420    this.hasJSActions = parameters.hasJSActions;
13421    this._fieldObjects = parameters.fieldObjects;
13422    this.parent = parameters.parent;
13423    if (isRenderable) {
13424      this.container = this._createContainer(ignoreBorder);
13425    }
13426    if (createQuadrilaterals) {
13427      this._createQuadrilaterals();
13428    }
13429  }
13430  static _hasPopupData({
13431    titleObj,
13432    contentsObj,
13433    richText
13434  }) {
13435    return !!(titleObj?.str || contentsObj?.str || richText?.str);
13436  }
13437  get _isEditable() {
13438    return this.data.isEditable;
13439  }
13440  get hasPopupData() {
13441    return AnnotationElement._hasPopupData(this.data);
13442  }
13443  updateEdited(params) {
13444    if (!this.container) {
13445      return;
13446    }
13447    this.#updates ||= {
13448      rect: this.data.rect.slice(0)
13449    };
13450    const {
13451      rect
13452    } = params;
13453    if (rect) {
13454      this.#setRectEdited(rect);
13455    }
13456    this.#popupElement?.popup.updateEdited(params);
13457  }
13458  resetEdited() {
13459    if (!this.#updates) {
13460      return;
13461    }
13462    this.#setRectEdited(this.#updates.rect);
13463    this.#popupElement?.popup.resetEdited();
13464    this.#updates = null;
13465  }
13466  #setRectEdited(rect) {
13467    const {
13468      container: {
13469        style
13470      },
13471      data: {
13472        rect: currentRect,
13473        rotation
13474      },
13475      parent: {
13476        viewport: {
13477          rawDims: {
13478            pageWidth,
13479            pageHeight,
13480            pageX,
13481            pageY
13482          }
13483        }
13484      }
13485    } = this;
13486    currentRect?.splice(0, 4, ...rect);
13487    const {
13488      width,
13489      height
13490    } = getRectDims(rect);
13491    style.left = `${100 * (rect[0] - pageX) / pageWidth}%`;
13492    style.top = `${100 * (pageHeight - rect[3] + pageY) / pageHeight}%`;
13493    if (rotation === 0) {
13494      style.width = `${100 * width / pageWidth}%`;
13495      style.height = `${100 * height / pageHeight}%`;
13496    } else {
13497      this.setRotation(rotation);
13498    }
13499  }
13500  _createContainer(ignoreBorder) {
13501    const {
13502      data,
13503      parent: {
13504        page,
13505        viewport
13506      }
13507    } = this;
13508    const container = document.createElement("section");
13509    container.setAttribute("data-annotation-id", data.id);
13510    if (!(this instanceof WidgetAnnotationElement)) {
13511      container.tabIndex = DEFAULT_TAB_INDEX;
13512    }
13513    const {
13514      style
13515    } = container;
13516    style.zIndex = this.parent.zIndex++;
13517    if (data.alternativeText) {
13518      container.title = data.alternativeText;
13519    }
13520    if (data.noRotate) {
13521      container.classList.add("norotate");
13522    }
13523    if (!data.rect || this instanceof PopupAnnotationElement) {
13524      const {
13525        rotation
13526      } = data;
13527      if (!data.hasOwnCanvas && rotation !== 0) {
13528        this.setRotation(rotation, container);
13529      }
13530      return container;
13531    }
13532    const {
13533      width,
13534      height
13535    } = getRectDims(data.rect);
13536    if (!ignoreBorder && data.borderStyle.width > 0) {
13537      style.borderWidth = `${data.borderStyle.width}px`;
13538      const horizontalRadius = data.borderStyle.horizontalCornerRadius;
13539      const verticalRadius = data.borderStyle.verticalCornerRadius;
13540      if (horizontalRadius > 0 || verticalRadius > 0) {
13541        const radius = `calc(${horizontalRadius}px * var(--scale-factor)) / calc(${verticalRadius}px * var(--scale-factor))`;
13542        style.borderRadius = radius;
13543      } else if (this instanceof RadioButtonWidgetAnnotationElement) {
13544        const radius = `calc(${width}px * var(--scale-factor)) / calc(${height}px * var(--scale-factor))`;
13545        style.borderRadius = radius;
13546      }
13547      switch (data.borderStyle.style) {
13548        case AnnotationBorderStyleType.SOLID:
13549          style.borderStyle = "solid";
13550          break;
13551        case AnnotationBorderStyleType.DASHED:
13552          style.borderStyle = "dashed";
13553          break;
13554        case AnnotationBorderStyleType.BEVELED:
13555          warn("Unimplemented border style: beveled");
13556          break;
13557        case AnnotationBorderStyleType.INSET:
13558          warn("Unimplemented border style: inset");
13559          break;
13560        case AnnotationBorderStyleType.UNDERLINE:
13561          style.borderBottomStyle = "solid";
13562          break;
13563        default:
13564          break;
13565      }
13566      const borderColor = data.borderColor || null;
13567      if (borderColor) {
13568        this.#hasBorder = true;
13569        style.borderColor = Util.makeHexColor(borderColor[0] | 0, borderColor[1] | 0, borderColor[2] | 0);
13570      } else {
13571        style.borderWidth = 0;
13572      }
13573    }
13574    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]]);
13575    const {
13576      pageWidth,
13577      pageHeight,
13578      pageX,
13579      pageY
13580    } = viewport.rawDims;
13581    style.left = `${100 * (rect[0] - pageX) / pageWidth}%`;
13582    style.top = `${100 * (rect[1] - pageY) / pageHeight}%`;
13583    const {
13584      rotation
13585    } = data;
13586    if (data.hasOwnCanvas || rotation === 0) {
13587      style.width = `${100 * width / pageWidth}%`;
13588      style.height = `${100 * height / pageHeight}%`;
13589    } else {
13590      this.setRotation(rotation, container);
13591    }
13592    return container;
13593  }
13594  setRotation(angle, container = this.container) {
13595    if (!this.data.rect) {
13596      return;
13597    }
13598    const {
13599      pageWidth,
13600      pageHeight
13601    } = this.parent.viewport.rawDims;
13602    const {
13603      width,
13604      height
13605    } = getRectDims(this.data.rect);
13606    let elementWidth, elementHeight;
13607    if (angle % 180 === 0) {
13608      elementWidth = 100 * width / pageWidth;
13609      elementHeight = 100 * height / pageHeight;
13610    } else {
13611      elementWidth = 100 * height / pageWidth;
13612      elementHeight = 100 * width / pageHeight;
13613    }
13614    container.style.width = `${elementWidth}%`;
13615    container.style.height = `${elementHeight}%`;
13616    container.setAttribute("data-main-rotation", (360 - angle) % 360);
13617  }
13618  get _commonActions() {
13619    const setColor = (jsName, styleName, event) => {
13620      const color = event.detail[jsName];
13621      const colorType = color[0];
13622      const colorArray = color.slice(1);
13623      event.target.style[styleName] = ColorConverters[`${colorType}_HTML`](colorArray);
13624      this.annotationStorage.setValue(this.data.id, {
13625        [styleName]: ColorConverters[`${colorType}_rgb`](colorArray)
13626      });
13627    };
13628    return shadow(this, "_commonActions", {
13629      display: event => {
13630        const {
13631          display
13632        } = event.detail;
13633        const hidden = display % 2 === 1;
13634        this.container.style.visibility = hidden ? "hidden" : "visible";
13635        this.annotationStorage.setValue(this.data.id, {
13636          noView: hidden,
13637          noPrint: display === 1 || display === 2
13638        });
13639      },
13640      print: event => {
13641        this.annotationStorage.setValue(this.data.id, {
13642          noPrint: !event.detail.print
13643        });
13644      },
13645      hidden: event => {
13646        const {
13647          hidden
13648        } = event.detail;
13649        this.container.style.visibility = hidden ? "hidden" : "visible";
13650        this.annotationStorage.setValue(this.data.id, {
13651          noPrint: hidden,
13652          noView: hidden
13653        });
13654      },
13655      focus: event => {
13656        setTimeout(() => event.target.focus({
13657          preventScroll: false
13658        }), 0);
13659      },
13660      userName: event => {
13661        event.target.title = event.detail.userName;
13662      },
13663      readonly: event => {
13664        event.target.disabled = event.detail.readonly;
13665      },
13666      required: event => {
13667        this._setRequired(event.target, event.detail.required);
13668      },
13669      bgColor: event => {
13670        setColor("bgColor", "backgroundColor", event);
13671      },
13672      fillColor: event => {
13673        setColor("fillColor", "backgroundColor", event);
13674      },
13675      fgColor: event => {
13676        setColor("fgColor", "color", event);
13677      },
13678      textColor: event => {
13679        setColor("textColor", "color", event);
13680      },
13681      borderColor: event => {
13682        setColor("borderColor", "borderColor", event);
13683      },
13684      strokeColor: event => {
13685        setColor("strokeColor", "borderColor", event);
13686      },
13687      rotation: event => {
13688        const angle = event.detail.rotation;
13689        this.setRotation(angle);
13690        this.annotationStorage.setValue(this.data.id, {
13691          rotation: angle
13692        });
13693      }
13694    });
13695  }
13696  _dispatchEventFromSandbox(actions, jsEvent) {
13697    const commonActions = this._commonActions;
vendor: 16,194 bytes, lines 13698-14238
13698    for (const name of Object.keys(jsEvent.detail)) {
13699      const action = actions[name] || commonActions[name];
13700      action?.(jsEvent);
13701    }
13702  }
13703  _setDefaultPropertiesFromJS(element) {
13704    if (!this.enableScripting) {
13705      return;
13706    }
13707    const storedData = this.annotationStorage.getRawValue(this.data.id);
13708    if (!storedData) {
13709      return;
13710    }
13711    const commonActions = this._commonActions;
13712    for (const [actionName, detail] of Object.entries(storedData)) {
13713      const action = commonActions[actionName];
13714      if (action) {
13715        const eventProxy = {
13716          detail: {
13717            [actionName]: detail
13718          },
13719          target: element
13720        };
13721        action(eventProxy);
13722        delete storedData[actionName];
13723      }
13724    }
13725  }
13726  _createQuadrilaterals() {
13727    if (!this.container) {
13728      return;
13729    }
13730    const {
13731      quadPoints
13732    } = this.data;
13733    if (!quadPoints) {
13734      return;
13735    }
13736    const [rectBlX, rectBlY, rectTrX, rectTrY] = this.data.rect.map(x => Math.fround(x));
13737    if (quadPoints.length === 8) {
13738      const [trX, trY, blX, blY] = quadPoints.subarray(2, 6);
13739      if (rectTrX === trX && rectTrY === trY && rectBlX === blX && rectBlY === blY) {
13740        return;
13741      }
13742    }
13743    const {
13744      style
13745    } = this.container;
13746    let svgBuffer;
13747    if (this.#hasBorder) {
13748      const {
13749        borderColor,
13750        borderWidth
13751      } = style;
13752      style.borderWidth = 0;
13753      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}">`];
13754      this.container.classList.add("hasBorder");
13755    }
13756    const width = rectTrX - rectBlX;
13757    const height = rectTrY - rectBlY;
13758    const {
13759      svgFactory
13760    } = this;
13761    const svg = svgFactory.createElement("svg");
13762    svg.classList.add("quadrilateralsContainer");
13763    svg.setAttribute("width", 0);
13764    svg.setAttribute("height", 0);
13765    const defs = svgFactory.createElement("defs");
13766    svg.append(defs);
13767    const clipPath = svgFactory.createElement("clipPath");
13768    const id = `clippath_${this.data.id}`;
13769    clipPath.setAttribute("id", id);
13770    clipPath.setAttribute("clipPathUnits", "objectBoundingBox");
13771    defs.append(clipPath);
13772    for (let i = 2, ii = quadPoints.length; i < ii; i += 8) {
13773      const trX = quadPoints[i];
13774      const trY = quadPoints[i + 1];
13775      const blX = quadPoints[i + 2];
13776      const blY = quadPoints[i + 3];
13777      const rect = svgFactory.createElement("rect");
13778      const x = (blX - rectBlX) / width;
13779      const y = (rectTrY - trY) / height;
13780      const rectWidth = (trX - blX) / width;
13781      const rectHeight = (trY - blY) / height;
13782      rect.setAttribute("x", x);
13783      rect.setAttribute("y", y);
13784      rect.setAttribute("width", rectWidth);
13785      rect.setAttribute("height", rectHeight);
13786      clipPath.append(rect);
13787      svgBuffer?.push(`<rect vector-effect="non-scaling-stroke" x="${x}" y="${y}" width="${rectWidth}" height="${rectHeight}"/>`);
13788    }
13789    if (this.#hasBorder) {
13790      svgBuffer.push(`</g></svg>')`);
13791      style.backgroundImage = svgBuffer.join("");
13792    }
13793    this.container.append(svg);
13794    this.container.style.clipPath = `url(#${id})`;
13795  }
13796  _createPopup() {
13797    const {
13798      data
13799    } = this;
13800    const popup = this.#popupElement = new PopupAnnotationElement({
13801      data: {
13802        color: data.color,
13803        titleObj: data.titleObj,
13804        modificationDate: data.modificationDate,
13805        contentsObj: data.contentsObj,
13806        richText: data.richText,
13807        parentRect: data.rect,
13808        borderStyle: 0,
13809        id: `popup_${data.id}`,
13810        rotation: data.rotation
13811      },
13812      parent: this.parent,
13813      elements: [this]
13814    });
13815    this.parent.div.append(popup.render());
13816  }
13817  render() {
13818    unreachable("Abstract method `AnnotationElement.render` called");
13819  }
13820  _getElementsByName(name, skipId = null) {
13821    const fields = [];
13822    if (this._fieldObjects) {
13823      const fieldObj = this._fieldObjects[name];
13824      if (fieldObj) {
13825        for (const {
13826          page,
13827          id,
13828          exportValues
13829        } of fieldObj) {
13830          if (page === -1) {
13831            continue;
13832          }
13833          if (id === skipId) {
13834            continue;
13835          }
13836          const exportValue = typeof exportValues === "string" ? exportValues : null;
13837          const domElement = document.querySelector(`[data-element-id="${id}"]`);
13838          if (domElement && !GetElementsByNameSet.has(domElement)) {
13839            warn(`_getElementsByName - element not allowed: ${id}`);
13840            continue;
13841          }
13842          fields.push({
13843            id,
13844            exportValue,
13845            domElement
13846          });
13847        }
13848      }
13849      return fields;
13850    }
13851    for (const domElement of document.getElementsByName(name)) {
13852      const {
13853        exportValue
13854      } = domElement;
13855      const id = domElement.getAttribute("data-element-id");
13856      if (id === skipId) {
13857        continue;
13858      }
13859      if (!GetElementsByNameSet.has(domElement)) {
13860        continue;
13861      }
13862      fields.push({
13863        id,
13864        exportValue,
13865        domElement
13866      });
13867    }
13868    return fields;
13869  }
13870  show() {
13871    if (this.container) {
13872      this.container.hidden = false;
13873    }
13874    this.popup?.maybeShow();
13875  }
13876  hide() {
13877    if (this.container) {
13878      this.container.hidden = true;
13879    }
13880    this.popup?.forceHide();
13881  }
13882  getElementsToTriggerPopup() {
13883    return this.container;
13884  }
13885  addHighlightArea() {
13886    const triggers = this.getElementsToTriggerPopup();
13887    if (Array.isArray(triggers)) {
13888      for (const element of triggers) {
13889        element.classList.add("highlightArea");
13890      }
13891    } else {
13892      triggers.classList.add("highlightArea");
13893    }
13894  }
13895  _editOnDoubleClick() {
13896    if (!this._isEditable) {
13897      return;
13898    }
13899    const {
13900      annotationEditorType: mode,
13901      data: {
13902        id: editId
13903      }
13904    } = this;
13905    this.container.addEventListener("dblclick", () => {
13906      this.linkService.eventBus?.dispatch("switchannotationeditormode", {
13907        source: this,
13908        mode,
13909        editId
13910      });
13911    });
13912  }
13913}
13914class LinkAnnotationElement extends AnnotationElement {
13915  constructor(parameters, options = null) {
13916    super(parameters, {
13917      isRenderable: true,
13918      ignoreBorder: !!options?.ignoreBorder,
13919      createQuadrilaterals: true
13920    });
13921    this.isTooltipOnly = parameters.data.isTooltipOnly;
13922  }
13923  render() {
13924    const {
13925      data,
13926      linkService
13927    } = this;
13928    const link = document.createElement("a");
13929    link.setAttribute("data-element-id", data.id);
13930    let isBound = false;
13931    if (data.url) {
13932      linkService.addLinkAttributes(link, data.url, data.newWindow);
13933      isBound = true;
13934    } else if (data.action) {
13935      this._bindNamedAction(link, data.action);
13936      isBound = true;
13937    } else if (data.attachment) {
13938      this.#bindAttachment(link, data.attachment, data.attachmentDest);
13939      isBound = true;
13940    } else if (data.setOCGState) {
13941      this.#bindSetOCGState(link, data.setOCGState);
13942      isBound = true;
13943    } else if (data.dest) {
13944      this._bindLink(link, data.dest);
13945      isBound = true;
13946    } else {
13947      if (data.actions && (data.actions.Action || data.actions["Mouse Up"] || data.actions["Mouse Down"]) && this.enableScripting && this.hasJSActions) {
13948        this._bindJSAction(link, data);
13949        isBound = true;
13950      }
13951      if (data.resetForm) {
13952        this._bindResetFormAction(link, data.resetForm);
13953        isBound = true;
13954      } else if (this.isTooltipOnly && !isBound) {
13955        this._bindLink(link, "");
13956        isBound = true;
13957      }
13958    }
13959    this.container.classList.add("linkAnnotation");
13960    if (isBound) {
13961      this.container.append(link);
13962    }
13963    return this.container;
13964  }
13965  #setInternalLink() {
13966    this.container.setAttribute("data-internal-link", "");
13967  }
13968  _bindLink(link, destination) {
13969    link.href = this.linkService.getDestinationHash(destination);
13970    link.onclick = () => {
13971      if (destination) {
13972        this.linkService.goToDestination(destination);
13973      }
13974      return false;
13975    };
13976    if (destination || destination === "") {
13977      this.#setInternalLink();
13978    }
13979  }
13980  _bindNamedAction(link, action) {
13981    link.href = this.linkService.getAnchorUrl("");
13982    link.onclick = () => {
13983      this.linkService.executeNamedAction(action);
13984      return false;
13985    };
13986    this.#setInternalLink();
13987  }
13988  #bindAttachment(link, attachment, dest = null) {
13989    link.href = this.linkService.getAnchorUrl("");
13990    if (attachment.description) {
13991      link.title = attachment.description;
13992    }
13993    link.onclick = () => {
13994      this.downloadManager?.openOrDownloadData(attachment.content, attachment.filename, dest);
13995      return false;
13996    };
13997    this.#setInternalLink();
13998  }
13999  #bindSetOCGState(link, action) {
14000    link.href = this.linkService.getAnchorUrl("");
14001    link.onclick = () => {
14002      this.linkService.executeSetOCGState(action);
14003      return false;
14004    };
14005    this.#setInternalLink();
14006  }
14007  _bindJSAction(link, data) {
14008    link.href = this.linkService.getAnchorUrl("");
14009    const map = new Map([["Action", "onclick"], ["Mouse Up", "onmouseup"], ["Mouse Down", "onmousedown"]]);
14010    for (const name of Object.keys(data.actions)) {
14011      const jsName = map.get(name);
14012      if (!jsName) {
14013        continue;
14014      }
14015      link[jsName] = () => {
14016        this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
14017          source: this,
14018          detail: {
14019            id: data.id,
14020            name
14021          }
14022        });
14023        return false;
14024      };
14025    }
14026    if (!link.onclick) {
14027      link.onclick = () => false;
14028    }
14029    this.#setInternalLink();
14030  }
14031  _bindResetFormAction(link, resetForm) {
14032    const otherClickAction = link.onclick;
14033    if (!otherClickAction) {
14034      link.href = this.linkService.getAnchorUrl("");
14035    }
14036    this.#setInternalLink();
14037    if (!this._fieldObjects) {
14038      warn(`_bindResetFormAction - "resetForm" action not supported, ` + "ensure that the `fieldObjects` parameter is provided.");
14039      if (!otherClickAction) {
14040        link.onclick = () => false;
14041      }
14042      return;
14043    }
14044    link.onclick = () => {
14045      otherClickAction?.();
14046      const {
14047        fields: resetFormFields,
14048        refs: resetFormRefs,
14049        include
14050      } = resetForm;
14051      const allFields = [];
14052      if (resetFormFields.length !== 0 || resetFormRefs.length !== 0) {
14053        const fieldIds = new Set(resetFormRefs);
14054        for (const fieldName of resetFormFields) {
14055          const fields = this._fieldObjects[fieldName] || [];
14056          for (const {
14057            id
14058          } of fields) {
14059            fieldIds.add(id);
14060          }
14061        }
14062        for (const fields of Object.values(this._fieldObjects)) {
14063          for (const field of fields) {
14064            if (fieldIds.has(field.id) === include) {
14065              allFields.push(field);
14066            }
14067          }
14068        }
14069      } else {
14070        for (const fields of Object.values(this._fieldObjects)) {
14071          allFields.push(...fields);
14072        }
14073      }
14074      const storage = this.annotationStorage;
14075      const allIds = [];
14076      for (const field of allFields) {
14077        const {
14078          id
14079        } = field;
14080        allIds.push(id);
14081        switch (field.type) {
14082          case "text":
14083            {
14084              const value = field.defaultValue || "";
14085              storage.setValue(id, {
14086                value
14087              });
14088              break;
14089            }
14090          case "checkbox":
14091          case "radiobutton":
14092            {
14093              const value = field.defaultValue === field.exportValues;
14094              storage.setValue(id, {
14095                value
14096              });
14097              break;
14098            }
14099          case "combobox":
14100          case "listbox":
14101            {
14102              const value = field.defaultValue || "";
14103              storage.setValue(id, {
14104                value
14105              });
14106              break;
14107            }
14108          default:
14109            continue;
14110        }
14111        const domElement = document.querySelector(`[data-element-id="${id}"]`);
14112        if (!domElement) {
14113          continue;
14114        } else if (!GetElementsByNameSet.has(domElement)) {
14115          warn(`_bindResetFormAction - element not allowed: ${id}`);
14116          continue;
14117        }
14118        domElement.dispatchEvent(new Event("resetform"));
14119      }
14120      if (this.enableScripting) {
14121        this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
14122          source: this,
14123          detail: {
14124            id: "app",
14125            ids: allIds,
14126            name: "ResetForm"
14127          }
14128        });
14129      }
14130      return false;
14131    };
14132  }
14133}
14134class TextAnnotationElement extends AnnotationElement {
14135  constructor(parameters) {
14136    super(parameters, {
14137      isRenderable: true
14138    });
14139  }
14140  render() {
14141    this.container.classList.add("textAnnotation");
14142    const image = document.createElement("img");
14143    image.src = this.imageResourcesPath + "annotation-" + this.data.name.toLowerCase() + ".svg";
14144    image.setAttribute("data-l10n-id", "pdfjs-text-annotation-type");
14145    image.setAttribute("data-l10n-args", JSON.stringify({
14146      type: this.data.name
14147    }));
14148    if (!this.data.popupRef && this.hasPopupData) {
14149      this._createPopup();
14150    }
14151    this.container.append(image);
14152    return this.container;
14153  }
14154}
14155class WidgetAnnotationElement extends AnnotationElement {
14156  render() {
14157    return this.container;
14158  }
14159  showElementAndHideCanvas(element) {
14160    if (this.data.hasOwnCanvas) {
14161      if (element.previousSibling?.nodeName === "CANVAS") {
14162        element.previousSibling.hidden = true;
14163      }
14164      element.hidden = false;
14165    }
14166  }
14167  _getKeyModifier(event) {
14168    return util_FeatureTest.platform.isMac ? event.metaKey : event.ctrlKey;
14169  }
14170  _setEventListener(element, elementData, baseName, eventName, valueGetter) {
14171    if (baseName.includes("mouse")) {
14172      element.addEventListener(baseName, event => {
14173        this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
14174          source: this,
14175          detail: {
14176            id: this.data.id,
14177            name: eventName,
14178            value: valueGetter(event),
14179            shift: event.shiftKey,
14180            modifier: this._getKeyModifier(event)
14181          }
14182        });
14183      });
14184    } else {
14185      element.addEventListener(baseName, event => {
14186        if (baseName === "blur") {
14187          if (!elementData.focused || !event.relatedTarget) {
14188            return;
14189          }
14190          elementData.focused = false;
14191        } else if (baseName === "focus") {
14192          if (elementData.focused) {
14193            return;
14194          }
14195          elementData.focused = true;
14196        }
14197        if (!valueGetter) {
14198          return;
14199        }
14200        this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
14201          source: this,
14202          detail: {
14203            id: this.data.id,
14204            name: eventName,
14205            value: valueGetter(event)
14206          }
14207        });
14208      });
14209    }
14210  }
14211  _setEventListeners(element, elementData, names, getter) {
14212    for (const [baseName, eventName] of names) {
14213      if (eventName === "Action" || this.data.actions?.[eventName]) {
14214        if (eventName === "Focus" || eventName === "Blur") {
14215          elementData ||= {
14216            focused: false
14217          };
14218        }
14219        this._setEventListener(element, elementData, baseName, eventName, getter);
14220        if (eventName === "Focus" && !this.data.actions?.Blur) {
14221          this._setEventListener(element, elementData, "blur", "Blur", null);
14222        } else if (eventName === "Blur" && !this.data.actions?.Focus) {
14223          this._setEventListener(element, elementData, "focus", "Focus", null);
14224        }
14225      }
14226    }
14227  }
14228  _setBackgroundColor(element) {
14229    const color = this.data.backgroundColor || null;
14230    element.style.backgroundColor = color === null ? "transparent" : Util.makeHexColor(color[0], color[1], color[2]);
14231  }
14232  _setTextStyle(element) {
14233    const TEXT_ALIGNMENT = ["left", "center", "right"];
14234    const {
14235      fontColor
14236    } = this.data.defaultAppearanceData;
14237    const fontSize = this.data.defaultAppearanceData.fontSize || annotation_layer_DEFAULT_FONT_SIZE;
14238    const style = element.style;
vendor: 26,419 bytes, lines 14239-14982
14239    let computedFontSize;
14240    const BORDER_SIZE = 2;
14241    const roundToOneDecimal = x => Math.round(10 * x) / 10;
14242    if (this.data.multiLine) {
14243      const height = Math.abs(this.data.rect[3] - this.data.rect[1] - BORDER_SIZE);
14244      const numberOfLines = Math.round(height / (LINE_FACTOR * fontSize)) || 1;
14245      const lineHeight = height / numberOfLines;
14246      computedFontSize = Math.min(fontSize, roundToOneDecimal(lineHeight / LINE_FACTOR));
14247    } else {
14248      const height = Math.abs(this.data.rect[3] - this.data.rect[1] - BORDER_SIZE);
14249      computedFontSize = Math.min(fontSize, roundToOneDecimal(height / LINE_FACTOR));
14250    }
14251    style.fontSize = `calc(${computedFontSize}px * var(--scale-factor))`;
14252    style.color = Util.makeHexColor(fontColor[0], fontColor[1], fontColor[2]);
14253    if (this.data.textAlignment !== null) {
14254      style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment];
14255    }
14256  }
14257  _setRequired(element, isRequired) {
14258    if (isRequired) {
14259      element.setAttribute("required", true);
14260    } else {
14261      element.removeAttribute("required");
14262    }
14263    element.setAttribute("aria-required", isRequired);
14264  }
14265}
14266class TextWidgetAnnotationElement extends WidgetAnnotationElement {
14267  constructor(parameters) {
14268    const isRenderable = parameters.renderForms || parameters.data.hasOwnCanvas || !parameters.data.hasAppearance && !!parameters.data.fieldValue;
14269    super(parameters, {
14270      isRenderable
14271    });
14272  }
14273  setPropertyOnSiblings(base, key, value, keyInStorage) {
14274    const storage = this.annotationStorage;
14275    for (const element of this._getElementsByName(base.name, base.id)) {
14276      if (element.domElement) {
14277        element.domElement[key] = value;
14278      }
14279      storage.setValue(element.id, {
14280        [keyInStorage]: value
14281      });
14282    }
14283  }
14284  render() {
14285    const storage = this.annotationStorage;
14286    const id = this.data.id;
14287    this.container.classList.add("textWidgetAnnotation");
14288    let element = null;
14289    if (this.renderForms) {
14290      const storedData = storage.getValue(id, {
14291        value: this.data.fieldValue
14292      });
14293      let textContent = storedData.value || "";
14294      const maxLen = storage.getValue(id, {
14295        charLimit: this.data.maxLen
14296      }).charLimit;
14297      if (maxLen && textContent.length > maxLen) {
14298        textContent = textContent.slice(0, maxLen);
14299      }
14300      let fieldFormattedValues = storedData.formattedValue || this.data.textContent?.join("\n") || null;
14301      if (fieldFormattedValues && this.data.comb) {
14302        fieldFormattedValues = fieldFormattedValues.replaceAll(/\s+/g, "");
14303      }
14304      const elementData = {
14305        userValue: textContent,
14306        formattedValue: fieldFormattedValues,
14307        lastCommittedValue: null,
14308        commitKey: 1,
14309        focused: false
14310      };
14311      if (this.data.multiLine) {
14312        element = document.createElement("textarea");
14313        element.textContent = fieldFormattedValues ?? textContent;
14314        if (this.data.doNotScroll) {
14315          element.style.overflowY = "hidden";
14316        }
14317      } else {
14318        element = document.createElement("input");
14319        element.type = "text";
14320        element.setAttribute("value", fieldFormattedValues ?? textContent);
14321        if (this.data.doNotScroll) {
14322          element.style.overflowX = "hidden";
14323        }
14324      }
14325      if (this.data.hasOwnCanvas) {
14326        element.hidden = true;
14327      }
14328      GetElementsByNameSet.add(element);
14329      element.setAttribute("data-element-id", id);
14330      element.disabled = this.data.readOnly;
14331      element.name = this.data.fieldName;
14332      element.tabIndex = DEFAULT_TAB_INDEX;
14333      this._setRequired(element, this.data.required);
14334      if (maxLen) {
14335        element.maxLength = maxLen;
14336      }
14337      element.addEventListener("input", event => {
14338        storage.setValue(id, {
14339          value: event.target.value
14340        });
14341        this.setPropertyOnSiblings(element, "value", event.target.value, "value");
14342        elementData.formattedValue = null;
14343      });
14344      element.addEventListener("resetform", event => {
14345        const defaultValue = this.data.defaultFieldValue ?? "";
14346        element.value = elementData.userValue = defaultValue;
14347        elementData.formattedValue = null;
14348      });
14349      let blurListener = event => {
14350        const {
14351          formattedValue
14352        } = elementData;
14353        if (formattedValue !== null && formattedValue !== undefined) {
14354          event.target.value = formattedValue;
14355        }
14356        event.target.scrollLeft = 0;
14357      };
14358      if (this.enableScripting && this.hasJSActions) {
14359        element.addEventListener("focus", event => {
14360          if (elementData.focused) {
14361            return;
14362          }
14363          const {
14364            target
14365          } = event;
14366          if (elementData.userValue) {
14367            target.value = elementData.userValue;
14368          }
14369          elementData.lastCommittedValue = target.value;
14370          elementData.commitKey = 1;
14371          if (!this.data.actions?.Focus) {
14372            elementData.focused = true;
14373          }
14374        });
14375        element.addEventListener("updatefromsandbox", jsEvent => {
14376          this.showElementAndHideCanvas(jsEvent.target);
14377          const actions = {
14378            value(event) {
14379              elementData.userValue = event.detail.value ?? "";
14380              storage.setValue(id, {
14381                value: elementData.userValue.toString()
14382              });
14383              event.target.value = elementData.userValue;
14384            },
14385            formattedValue(event) {
14386              const {
14387                formattedValue
14388              } = event.detail;
14389              elementData.formattedValue = formattedValue;
14390              if (formattedValue !== null && formattedValue !== undefined && event.target !== document.activeElement) {
14391                event.target.value = formattedValue;
14392              }
14393              storage.setValue(id, {
14394                formattedValue
14395              });
14396            },
14397            selRange(event) {
14398              event.target.setSelectionRange(...event.detail.selRange);
14399            },
14400            charLimit: event => {
14401              const {
14402                charLimit
14403              } = event.detail;
14404              const {
14405                target
14406              } = event;
14407              if (charLimit === 0) {
14408                target.removeAttribute("maxLength");
14409                return;
14410              }
14411              target.setAttribute("maxLength", charLimit);
14412              let value = elementData.userValue;
14413              if (!value || value.length <= charLimit) {
14414                return;
14415              }
14416              value = value.slice(0, charLimit);
14417              target.value = elementData.userValue = value;
14418              storage.setValue(id, {
14419                value
14420              });
14421              this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
14422                source: this,
14423                detail: {
14424                  id,
14425                  name: "Keystroke",
14426                  value,
14427                  willCommit: true,
14428                  commitKey: 1,
14429                  selStart: target.selectionStart,
14430                  selEnd: target.selectionEnd
14431                }
14432              });
14433            }
14434          };
14435          this._dispatchEventFromSandbox(actions, jsEvent);
14436        });
14437        element.addEventListener("keydown", event => {
14438          elementData.commitKey = 1;
14439          let commitKey = -1;
14440          if (event.key === "Escape") {
14441            commitKey = 0;
14442          } else if (event.key === "Enter" && !this.data.multiLine) {
14443            commitKey = 2;
14444          } else if (event.key === "Tab") {
14445            elementData.commitKey = 3;
14446          }
14447          if (commitKey === -1) {
14448            return;
14449          }
14450          const {
14451            value
14452          } = event.target;
14453          if (elementData.lastCommittedValue === value) {
14454            return;
14455          }
14456          elementData.lastCommittedValue = value;
14457          elementData.userValue = value;
14458          this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
14459            source: this,
14460            detail: {
14461              id,
14462              name: "Keystroke",
14463              value,
14464              willCommit: true,
14465              commitKey,
14466              selStart: event.target.selectionStart,
14467              selEnd: event.target.selectionEnd
14468            }
14469          });
14470        });
14471        const _blurListener = blurListener;
14472        blurListener = null;
14473        element.addEventListener("blur", event => {
14474          if (!elementData.focused || !event.relatedTarget) {
14475            return;
14476          }
14477          if (!this.data.actions?.Blur) {
14478            elementData.focused = false;
14479          }
14480          const {
14481            value
14482          } = event.target;
14483          elementData.userValue = value;
14484          if (elementData.lastCommittedValue !== value) {
14485            this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
14486              source: this,
14487              detail: {
14488                id,
14489                name: "Keystroke",
14490                value,
14491                willCommit: true,
14492                commitKey: elementData.commitKey,
14493                selStart: event.target.selectionStart,
14494                selEnd: event.target.selectionEnd
14495              }
14496            });
14497          }
14498          _blurListener(event);
14499        });
14500        if (this.data.actions?.Keystroke) {
14501          element.addEventListener("beforeinput", event => {
14502            elementData.lastCommittedValue = null;
14503            const {
14504              data,
14505              target
14506            } = event;
14507            const {
14508              value,
14509              selectionStart,
14510              selectionEnd
14511            } = target;
14512            let selStart = selectionStart,
14513              selEnd = selectionEnd;
14514            switch (event.inputType) {
14515              case "deleteWordBackward":
14516                {
14517                  const match = value.substring(0, selectionStart).match(/\w*[^\w]*$/);
14518                  if (match) {
14519                    selStart -= match[0].length;
14520                  }
14521                  break;
14522                }
14523              case "deleteWordForward":
14524                {
14525                  const match = value.substring(selectionStart).match(/^[^\w]*\w*/);
14526                  if (match) {
14527                    selEnd += match[0].length;
14528                  }
14529                  break;
14530                }
14531              case "deleteContentBackward":
14532                if (selectionStart === selectionEnd) {
14533                  selStart -= 1;
14534                }
14535                break;
14536              case "deleteContentForward":
14537                if (selectionStart === selectionEnd) {
14538                  selEnd += 1;
14539                }
14540                break;
14541            }
14542            event.preventDefault();
14543            this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
14544              source: this,
14545              detail: {
14546                id,
14547                name: "Keystroke",
14548                value,
14549                change: data || "",
14550                willCommit: false,
14551                selStart,
14552                selEnd
14553              }
14554            });
14555          });
14556        }
14557        this._setEventListeners(element, elementData, [["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.value);
14558      }
14559      if (blurListener) {
14560        element.addEventListener("blur", blurListener);
14561      }
14562      if (this.data.comb) {
14563        const fieldWidth = this.data.rect[2] - this.data.rect[0];
14564        const combWidth = fieldWidth / maxLen;
14565        element.classList.add("comb");
14566        element.style.letterSpacing = `calc(${combWidth}px * var(--scale-factor) - 1ch)`;
14567      }
14568    } else {
14569      element = document.createElement("div");
14570      element.textContent = this.data.fieldValue;
14571      element.style.verticalAlign = "middle";
14572      element.style.display = "table-cell";
14573      if (this.data.hasOwnCanvas) {
14574        element.hidden = true;
14575      }
14576    }
14577    this._setTextStyle(element);
14578    this._setBackgroundColor(element);
14579    this._setDefaultPropertiesFromJS(element);
14580    this.container.append(element);
14581    return this.container;
14582  }
14583}
14584class SignatureWidgetAnnotationElement extends WidgetAnnotationElement {
14585  constructor(parameters) {
14586    super(parameters, {
14587      isRenderable: !!parameters.data.hasOwnCanvas
14588    });
14589  }
14590}
14591class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
14592  constructor(parameters) {
14593    super(parameters, {
14594      isRenderable: parameters.renderForms
14595    });
14596  }
14597  render() {
14598    const storage = this.annotationStorage;
14599    const data = this.data;
14600    const id = data.id;
14601    let value = storage.getValue(id, {
14602      value: data.exportValue === data.fieldValue
14603    }).value;
14604    if (typeof value === "string") {
14605      value = value !== "Off";
14606      storage.setValue(id, {
14607        value
14608      });
14609    }
14610    this.container.classList.add("buttonWidgetAnnotation", "checkBox");
14611    const element = document.createElement("input");
14612    GetElementsByNameSet.add(element);
14613    element.setAttribute("data-element-id", id);
14614    element.disabled = data.readOnly;
14615    this._setRequired(element, this.data.required);
14616    element.type = "checkbox";
14617    element.name = data.fieldName;
14618    if (value) {
14619      element.setAttribute("checked", true);
14620    }
14621    element.setAttribute("exportValue", data.exportValue);
14622    element.tabIndex = DEFAULT_TAB_INDEX;
14623    element.addEventListener("change", event => {
14624      const {
14625        name,
14626        checked
14627      } = event.target;
14628      for (const checkbox of this._getElementsByName(name, id)) {
14629        const curChecked = checked && checkbox.exportValue === data.exportValue;
14630        if (checkbox.domElement) {
14631          checkbox.domElement.checked = curChecked;
14632        }
14633        storage.setValue(checkbox.id, {
14634          value: curChecked
14635        });
14636      }
14637      storage.setValue(id, {
14638        value: checked
14639      });
14640    });
14641    element.addEventListener("resetform", event => {
14642      const defaultValue = data.defaultFieldValue || "Off";
14643      event.target.checked = defaultValue === data.exportValue;
14644    });
14645    if (this.enableScripting && this.hasJSActions) {
14646      element.addEventListener("updatefromsandbox", jsEvent => {
14647        const actions = {
14648          value(event) {
14649            event.target.checked = event.detail.value !== "Off";
14650            storage.setValue(id, {
14651              value: event.target.checked
14652            });
14653          }
14654        };
14655        this._dispatchEventFromSandbox(actions, jsEvent);
14656      });
14657      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);
14658    }
14659    this._setBackgroundColor(element);
14660    this._setDefaultPropertiesFromJS(element);
14661    this.container.append(element);
14662    return this.container;
14663  }
14664}
14665class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
14666  constructor(parameters) {
14667    super(parameters, {
14668      isRenderable: parameters.renderForms
14669    });
14670  }
14671  render() {
14672    this.container.classList.add("buttonWidgetAnnotation", "radioButton");
14673    const storage = this.annotationStorage;
14674    const data = this.data;
14675    const id = data.id;
14676    let value = storage.getValue(id, {
14677      value: data.fieldValue === data.buttonValue
14678    }).value;
14679    if (typeof value === "string") {
14680      value = value !== data.buttonValue;
14681      storage.setValue(id, {
14682        value
14683      });
14684    }
14685    if (value) {
14686      for (const radio of this._getElementsByName(data.fieldName, id)) {
14687        storage.setValue(radio.id, {
14688          value: false
14689        });
14690      }
14691    }
14692    const element = document.createElement("input");
14693    GetElementsByNameSet.add(element);
14694    element.setAttribute("data-element-id", id);
14695    element.disabled = data.readOnly;
14696    this._setRequired(element, this.data.required);
14697    element.type = "radio";
14698    element.name = data.fieldName;
14699    if (value) {
14700      element.setAttribute("checked", true);
14701    }
14702    element.tabIndex = DEFAULT_TAB_INDEX;
14703    element.addEventListener("change", event => {
14704      const {
14705        name,
14706        checked
14707      } = event.target;
14708      for (const radio of this._getElementsByName(name, id)) {
14709        storage.setValue(radio.id, {
14710          value: false
14711        });
14712      }
14713      storage.setValue(id, {
14714        value: checked
14715      });
14716    });
14717    element.addEventListener("resetform", event => {
14718      const defaultValue = data.defaultFieldValue;
14719      event.target.checked = defaultValue !== null && defaultValue !== undefined && defaultValue === data.buttonValue;
14720    });
14721    if (this.enableScripting && this.hasJSActions) {
14722      const pdfButtonValue = data.buttonValue;
14723      element.addEventListener("updatefromsandbox", jsEvent => {
14724        const actions = {
14725          value: event => {
14726            const checked = pdfButtonValue === event.detail.value;
14727            for (const radio of this._getElementsByName(event.target.name)) {
14728              const curChecked = checked && radio.id === id;
14729              if (radio.domElement) {
14730                radio.domElement.checked = curChecked;
14731              }
14732              storage.setValue(radio.id, {
14733                value: curChecked
14734              });
14735            }
14736          }
14737        };
14738        this._dispatchEventFromSandbox(actions, jsEvent);
14739      });
14740      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);
14741    }
14742    this._setBackgroundColor(element);
14743    this._setDefaultPropertiesFromJS(element);
14744    this.container.append(element);
14745    return this.container;
14746  }
14747}
14748class PushButtonWidgetAnnotationElement extends LinkAnnotationElement {
14749  constructor(parameters) {
14750    super(parameters, {
14751      ignoreBorder: parameters.data.hasAppearance
14752    });
14753  }
14754  render() {
14755    const container = super.render();
14756    container.classList.add("buttonWidgetAnnotation", "pushButton");
14757    const linkElement = container.lastChild;
14758    if (this.enableScripting && this.hasJSActions && linkElement) {
14759      this._setDefaultPropertiesFromJS(linkElement);
14760      linkElement.addEventListener("updatefromsandbox", jsEvent => {
14761        this._dispatchEventFromSandbox({}, jsEvent);
14762      });
14763    }
14764    return container;
14765  }
14766}
14767class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
14768  constructor(parameters) {
14769    super(parameters, {
14770      isRenderable: parameters.renderForms
14771    });
14772  }
14773  render() {
14774    this.container.classList.add("choiceWidgetAnnotation");
14775    const storage = this.annotationStorage;
14776    const id = this.data.id;
14777    const storedData = storage.getValue(id, {
14778      value: this.data.fieldValue
14779    });
14780    const selectElement = document.createElement("select");
14781    GetElementsByNameSet.add(selectElement);
14782    selectElement.setAttribute("data-element-id", id);
14783    selectElement.disabled = this.data.readOnly;
14784    this._setRequired(selectElement, this.data.required);
14785    selectElement.name = this.data.fieldName;
14786    selectElement.tabIndex = DEFAULT_TAB_INDEX;
14787    let addAnEmptyEntry = this.data.combo && this.data.options.length > 0;
14788    if (!this.data.combo) {
14789      selectElement.size = this.data.options.length;
14790      if (this.data.multiSelect) {
14791        selectElement.multiple = true;
14792      }
14793    }
14794    selectElement.addEventListener("resetform", event => {
14795      const defaultValue = this.data.defaultFieldValue;
14796      for (const option of selectElement.options) {
14797        option.selected = option.value === defaultValue;
14798      }
14799    });
14800    for (const option of this.data.options) {
14801      const optionElement = document.createElement("option");
14802      optionElement.textContent = option.displayValue;
14803      optionElement.value = option.exportValue;
14804      if (storedData.value.includes(option.exportValue)) {
14805        optionElement.setAttribute("selected", true);
14806        addAnEmptyEntry = false;
14807      }
14808      selectElement.append(optionElement);
14809    }
14810    let removeEmptyEntry = null;
14811    if (addAnEmptyEntry) {
14812      const noneOptionElement = document.createElement("option");
14813      noneOptionElement.value = " ";
14814      noneOptionElement.setAttribute("hidden", true);
14815      noneOptionElement.setAttribute("selected", true);
14816      selectElement.prepend(noneOptionElement);
14817      removeEmptyEntry = () => {
14818        noneOptionElement.remove();
14819        selectElement.removeEventListener("input", removeEmptyEntry);
14820        removeEmptyEntry = null;
14821      };
14822      selectElement.addEventListener("input", removeEmptyEntry);
14823    }
14824    const getValue = isExport => {
14825      const name = isExport ? "value" : "textContent";
14826      const {
14827        options,
14828        multiple
14829      } = selectElement;
14830      if (!multiple) {
14831        return options.selectedIndex === -1 ? null : options[options.selectedIndex][name];
14832      }
14833      return Array.prototype.filter.call(options, option => option.selected).map(option => option[name]);
14834    };
14835    let selectedValues = getValue(false);
14836    const getItems = event => {
14837      const options = event.target.options;
14838      return Array.prototype.map.call(options, option => ({
14839        displayValue: option.textContent,
14840        exportValue: option.value
14841      }));
14842    };
14843    if (this.enableScripting && this.hasJSActions) {
14844      selectElement.addEventListener("updatefromsandbox", jsEvent => {
14845        const actions = {
14846          value(event) {
14847            removeEmptyEntry?.();
14848            const value = event.detail.value;
14849            const values = new Set(Array.isArray(value) ? value : [value]);
14850            for (const option of selectElement.options) {
14851              option.selected = values.has(option.value);
14852            }
14853            storage.setValue(id, {
14854              value: getValue(true)
14855            });
14856            selectedValues = getValue(false);
14857          },
14858          multipleSelection(event) {
14859            selectElement.multiple = true;
14860          },
14861          remove(event) {
14862            const options = selectElement.options;
14863            const index = event.detail.remove;
14864            options[index].selected = false;
14865            selectElement.remove(index);
14866            if (options.length > 0) {
14867              const i = Array.prototype.findIndex.call(options, option => option.selected);
14868              if (i === -1) {
14869                options[0].selected = true;
14870              }
14871            }
14872            storage.setValue(id, {
14873              value: getValue(true),
14874              items: getItems(event)
14875            });
14876            selectedValues = getValue(false);
14877          },
14878          clear(event) {
14879            while (selectElement.length !== 0) {
14880              selectElement.remove(0);
14881            }
14882            storage.setValue(id, {
14883              value: null,
14884              items: []
14885            });
14886            selectedValues = getValue(false);
14887          },
14888          insert(event) {
14889            const {
14890              index,
14891              displayValue,
14892              exportValue
14893            } = event.detail.insert;
14894            const selectChild = selectElement.children[index];
14895            const optionElement = document.createElement("option");
14896            optionElement.textContent = displayValue;
14897            optionElement.value = exportValue;
14898            if (selectChild) {
14899              selectChild.before(optionElement);
14900            } else {
14901              selectElement.append(optionElement);
14902            }
14903            storage.setValue(id, {
14904              value: getValue(true),
14905              items: getItems(event)
14906            });
14907            selectedValues = getValue(false);
14908          },
14909          items(event) {
14910            const {
14911              items
14912            } = event.detail;
14913            while (selectElement.length !== 0) {
14914              selectElement.remove(0);
14915            }
14916            for (const item of items) {
14917              const {
14918                displayValue,
14919                exportValue
14920              } = item;
14921              const optionElement = document.createElement("option");
14922              optionElement.textContent = displayValue;
14923              optionElement.value = exportValue;
14924              selectElement.append(optionElement);
14925            }
14926            if (selectElement.options.length > 0) {
14927              selectElement.options[0].selected = true;
14928            }
14929            storage.setValue(id, {
14930              value: getValue(true),
14931              items: getItems(event)
14932            });
14933            selectedValues = getValue(false);
14934          },
14935          indices(event) {
14936            const indices = new Set(event.detail.indices);
14937            for (const option of event.target.options) {
14938              option.selected = indices.has(option.index);
14939            }
14940            storage.setValue(id, {
14941              value: getValue(true)
14942            });
14943            selectedValues = getValue(false);
14944          },
14945          editable(event) {
14946            event.target.disabled = !event.detail.editable;
14947          }
14948        };
14949        this._dispatchEventFromSandbox(actions, jsEvent);
14950      });
14951      selectElement.addEventListener("input", event => {
14952        const exportValue = getValue(true);
14953        const change = getValue(false);
14954        storage.setValue(id, {
14955          value: exportValue
14956        });
14957        event.preventDefault();
14958        this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
14959          source: this,
14960          detail: {
14961            id,
14962            name: "Keystroke",
14963            value: selectedValues,
14964            change,
14965            changeEx: exportValue,
14966            willCommit: false,
14967            commitKey: 1,
14968            keyDown: false
14969          }
14970        });
14971      });
14972      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);
14973    } else {
14974      selectElement.addEventListener("input", function (event) {
14975        storage.setValue(id, {
14976          value: getValue(true)
14977        });
14978      });
14979    }
14980    if (this.data.combo) {
14981      this._setTextStyle(selectElement);
14982    } else {}
14983    this._setBackgroundColor(selectElement);
14984    this._setDefaultPropertiesFromJS(selectElement);
14985    this.container.append(selectElement);
14986    return this.container;
14987  }
14988}
14989class PopupAnnotationElement extends AnnotationElement {
14990  constructor(parameters) {
14991    const {
14992      data,
14993      elements
14994    } = parameters;
14995    super(parameters, {
14996      isRenderable: AnnotationElement._hasPopupData(data)
14997    });
14998    this.elements = elements;
14999    this.popup = null;
15000  }
15001  render() {
15002    this.container.classList.add("popupAnnotation");
15003    const popup = this.popup = new PopupElement({
15004      container: this.container,
15005      color: this.data.color,
15006      titleObj: this.data.titleObj,
15007      modificationDate: this.data.modificationDate,
15008      contentsObj: this.data.contentsObj,
15009      richText: this.data.richText,
15010      rect: this.data.rect,
15011      parentRect: this.data.parentRect || null,
15012      parent: this.parent,
15013      elements: this.elements,
15014      open: this.data.open
15015    });
15016    const elementIds = [];
15017    for (const element of this.elements) {
15018      element.popup = popup;
15019      element.container.ariaHasPopup = "dialog";
15020      elementIds.push(element.data.id);
15021      element.addHighlightArea();
15022    }
15023    this.container.setAttribute("aria-controls", elementIds.map(id => `${AnnotationPrefix}${id}`).join(","));
15024    return this.container;
15025  }
15026}
15027class PopupElement {
15028  #boundKeyDown = this.#keyDown.bind(this);
15029  #boundHide = this.#hide.bind(this);
15030  #boundShow = this.#show.bind(this);
15031  #boundToggle = this.#toggle.bind(this);
15032  #color = null;
15033  #container = null;
15034  #contentsObj = null;
15035  #dateObj = null;
15036  #elements = null;
15037  #parent = null;
15038  #parentRect = null;
15039  #pinned = false;
15040  #popup = null;
15041  #position = null;
15042  #rect = null;
15043  #richText = null;
15044  #titleObj = null;
15045  #updates = null;
15046  #wasVisible = false;
15047  constructor({
15048    container,
15049    color,
15050    elements,
15051    titleObj,
15052    modificationDate,
15053    contentsObj,
15054    richText,
15055    parent,
15056    rect,
15057    parentRect,
15058    open
15059  }) {
15060    this.#container = container;
15061    this.#titleObj = titleObj;
15062    this.#contentsObj = contentsObj;
15063    this.#richText = richText;
15064    this.#parent = parent;
15065    this.#color = color;
15066    this.#rect = rect;
15067    this.#parentRect = parentRect;
15068    this.#elements = elements;
15069    this.#dateObj = PDFDateString.toDateObject(modificationDate);
15070    this.trigger = elements.flatMap(e => e.getElementsToTriggerPopup());
15071    for (const element of this.trigger) {
15072      element.addEventListener("click", this.#boundToggle);
15073      element.addEventListener("mouseenter", this.#boundShow);
15074      element.addEventListener("mouseleave", this.#boundHide);
15075      element.classList.add("popupTriggerArea");
15076    }
15077    for (const element of elements) {
15078      element.container?.addEventListener("keydown", this.#boundKeyDown);
15079    }
15080    this.#container.hidden = true;
15081    if (open) {
15082      this.#toggle();
15083    }
15084  }
15085  render() {
15086    if (this.#popup) {
15087      return;
15088    }
15089    const popup = this.#popup = document.createElement("div");
15090    popup.className = "popup";
15091    if (this.#color) {
15092      const baseColor = popup.style.outlineColor = Util.makeHexColor(...this.#color);
15093      if (CSS.supports("background-color", "color-mix(in srgb, red 30%, white)")) {
15094        popup.style.backgroundColor = `color-mix(in srgb, ${baseColor} 30%, white)`;
15095      } else {
15096        const BACKGROUND_ENLIGHT = 0.7;
15097        popup.style.backgroundColor = Util.makeHexColor(...this.#color.map(c => Math.floor(BACKGROUND_ENLIGHT * (255 - c) + c)));
15098      }
15099    }
15100    const header = document.createElement("span");
15101    header.className = "header";
15102    const title = document.createElement("h1");
15103    header.append(title);
15104    ({
15105      dir: title.dir,
15106      str: title.textContent
15107    } = this.#titleObj);
15108    popup.append(header);
15109    if (this.#dateObj) {
15110      const modificationDate = document.createElement("span");
15111      modificationDate.classList.add("popupDate");
15112      modificationDate.setAttribute("data-l10n-id", "pdfjs-annotation-date-time-string");
15113      modificationDate.setAttribute("data-l10n-args", JSON.stringify({
15114        dateObj: this.#dateObj.valueOf()
15115      }));
15116      header.append(modificationDate);
15117    }
15118    const html = this.#html;
15119    if (html) {
15120      XfaLayer.render({
15121        xfaHtml: html,
15122        intent: "richText",
15123        div: popup
15124      });
15125      popup.lastChild.classList.add("richText", "popupContent");
15126    } else {
15127      const contents = this._formatContents(this.#contentsObj);
15128      popup.append(contents);
15129    }
15130    this.#container.append(popup);
15131  }
15132  get #html() {
15133    const richText = this.#richText;
15134    const contentsObj = this.#contentsObj;
15135    if (richText?.str && (!contentsObj?.str || contentsObj.str === richText.str)) {
15136      return this.#richText.html || null;
15137    }
15138    return null;
15139  }
15140  get #fontSize() {
15141    return this.#html?.attributes?.style?.fontSize || 0;
15142  }
15143  get #fontColor() {
15144    return this.#html?.attributes?.style?.color || null;
15145  }
15146  #makePopupContent(text) {
15147    const popupLines = [];
15148    const popupContent = {
15149      str: text,
15150      html: {
15151        name: "div",
15152        attributes: {
15153          dir: "auto"
15154        },
15155        children: [{
15156          name: "p",
15157          children: popupLines
15158        }]
15159      }
15160    };
15161    const lineAttributes = {
15162      style: {
15163        color: this.#fontColor,
15164        fontSize: this.#fontSize ? `calc(${this.#fontSize}px * var(--scale-factor))` : ""
15165      }
15166    };
15167    for (const line of text.split("\n")) {
15168      popupLines.push({
15169        name: "span",
15170        value: line,
15171        attributes: lineAttributes
15172      });
15173    }
15174    return popupContent;
15175  }
15176  _formatContents({
15177    str,
15178    dir
15179  }) {
15180    const p = document.createElement("p");
15181    p.classList.add("popupContent");
15182    p.dir = dir;
15183    const lines = str.split(/(?:\r\n?|\n)/);
15184    for (let i = 0, ii = lines.length; i < ii; ++i) {
15185      const line = lines[i];
15186      p.append(document.createTextNode(line));
15187      if (i < ii - 1) {
15188        p.append(document.createElement("br"));
15189      }
15190    }
15191    return p;
15192  }
15193  #keyDown(event) {
15194    if (event.altKey || event.shiftKey || event.ctrlKey || event.metaKey) {
15195      return;
15196    }
15197    if (event.key === "Enter" || event.key === "Escape" && this.#pinned) {
vendor: 16,979 bytes, lines 15198-15789
15198      this.#toggle();
15199    }
15200  }
15201  updateEdited({
15202    rect,
15203    popupContent
15204  }) {
15205    this.#updates ||= {
15206      contentsObj: this.#contentsObj,
15207      richText: this.#richText
15208    };
15209    if (rect) {
15210      this.#position = null;
15211    }
15212    if (popupContent) {
15213      this.#richText = this.#makePopupContent(popupContent);
15214      this.#contentsObj = null;
15215    }
15216    this.#popup?.remove();
15217    this.#popup = null;
15218  }
15219  resetEdited() {
15220    if (!this.#updates) {
15221      return;
15222    }
15223    ({
15224      contentsObj: this.#contentsObj,
15225      richText: this.#richText
15226    } = this.#updates);
15227    this.#updates = null;
15228    this.#popup?.remove();
15229    this.#popup = null;
15230    this.#position = null;
15231  }
15232  #setPosition() {
15233    if (this.#position !== null) {
15234      return;
15235    }
15236    const {
15237      page: {
15238        view
15239      },
15240      viewport: {
15241        rawDims: {
15242          pageWidth,
15243          pageHeight,
15244          pageX,
15245          pageY
15246        }
15247      }
15248    } = this.#parent;
15249    let useParentRect = !!this.#parentRect;
15250    let rect = useParentRect ? this.#parentRect : this.#rect;
15251    for (const element of this.#elements) {
15252      if (!rect || Util.intersect(element.data.rect, rect) !== null) {
15253        rect = element.data.rect;
15254        useParentRect = true;
15255        break;
15256      }
15257    }
15258    const normalizedRect = Util.normalizeRect([rect[0], view[3] - rect[1] + view[1], rect[2], view[3] - rect[3] + view[1]]);
15259    const HORIZONTAL_SPACE_AFTER_ANNOTATION = 5;
15260    const parentWidth = useParentRect ? rect[2] - rect[0] + HORIZONTAL_SPACE_AFTER_ANNOTATION : 0;
15261    const popupLeft = normalizedRect[0] + parentWidth;
15262    const popupTop = normalizedRect[1];
15263    this.#position = [100 * (popupLeft - pageX) / pageWidth, 100 * (popupTop - pageY) / pageHeight];
15264    const {
15265      style
15266    } = this.#container;
15267    style.left = `${this.#position[0]}%`;
15268    style.top = `${this.#position[1]}%`;
15269  }
15270  #toggle() {
15271    this.#pinned = !this.#pinned;
15272    if (this.#pinned) {
15273      this.#show();
15274      this.#container.addEventListener("click", this.#boundToggle);
15275      this.#container.addEventListener("keydown", this.#boundKeyDown);
15276    } else {
15277      this.#hide();
15278      this.#container.removeEventListener("click", this.#boundToggle);
15279      this.#container.removeEventListener("keydown", this.#boundKeyDown);
15280    }
15281  }
15282  #show() {
15283    if (!this.#popup) {
15284      this.render();
15285    }
15286    if (!this.isVisible) {
15287      this.#setPosition();
15288      this.#container.hidden = false;
15289      this.#container.style.zIndex = parseInt(this.#container.style.zIndex) + 1000;
15290    } else if (this.#pinned) {
15291      this.#container.classList.add("focused");
15292    }
15293  }
15294  #hide() {
15295    this.#container.classList.remove("focused");
15296    if (this.#pinned || !this.isVisible) {
15297      return;
15298    }
15299    this.#container.hidden = true;
15300    this.#container.style.zIndex = parseInt(this.#container.style.zIndex) - 1000;
15301  }
15302  forceHide() {
15303    this.#wasVisible = this.isVisible;
15304    if (!this.#wasVisible) {
15305      return;
15306    }
15307    this.#container.hidden = true;
15308  }
15309  maybeShow() {
15310    if (!this.#wasVisible) {
15311      return;
15312    }
15313    if (!this.#popup) {
15314      this.#show();
15315    }
15316    this.#wasVisible = false;
15317    this.#container.hidden = false;
15318  }
15319  get isVisible() {
15320    return this.#container.hidden === false;
15321  }
15322}
15323class FreeTextAnnotationElement extends AnnotationElement {
15324  constructor(parameters) {
15325    super(parameters, {
15326      isRenderable: true,
15327      ignoreBorder: true
15328    });
15329    this.textContent = parameters.data.textContent;
15330    this.textPosition = parameters.data.textPosition;
15331    this.annotationEditorType = AnnotationEditorType.FREETEXT;
15332  }
15333  render() {
15334    this.container.classList.add("freeTextAnnotation");
15335    if (this.textContent) {
15336      const content = document.createElement("div");
15337      content.classList.add("annotationTextContent");
15338      content.setAttribute("role", "comment");
15339      for (const line of this.textContent) {
15340        const lineSpan = document.createElement("span");
15341        lineSpan.textContent = line;
15342        content.append(lineSpan);
15343      }
15344      this.container.append(content);
15345    }
15346    if (!this.data.popupRef && this.hasPopupData) {
15347      this._createPopup();
15348    }
15349    this._editOnDoubleClick();
15350    return this.container;
15351  }
15352}
15353class LineAnnotationElement extends AnnotationElement {
15354  #line = null;
15355  constructor(parameters) {
15356    super(parameters, {
15357      isRenderable: true,
15358      ignoreBorder: true
15359    });
15360  }
15361  render() {
15362    this.container.classList.add("lineAnnotation");
15363    const data = this.data;
15364    const {
15365      width,
15366      height
15367    } = getRectDims(data.rect);
15368    const svg = this.svgFactory.create(width, height, true);
15369    const line = this.#line = this.svgFactory.createElement("svg:line");
15370    line.setAttribute("x1", data.rect[2] - data.lineCoordinates[0]);
15371    line.setAttribute("y1", data.rect[3] - data.lineCoordinates[1]);
15372    line.setAttribute("x2", data.rect[2] - data.lineCoordinates[2]);
15373    line.setAttribute("y2", data.rect[3] - data.lineCoordinates[3]);
15374    line.setAttribute("stroke-width", data.borderStyle.width || 1);
15375    line.setAttribute("stroke", "transparent");
15376    line.setAttribute("fill", "transparent");
15377    svg.append(line);
15378    this.container.append(svg);
15379    if (!data.popupRef && this.hasPopupData) {
15380      this._createPopup();
15381    }
15382    return this.container;
15383  }
15384  getElementsToTriggerPopup() {
15385    return this.#line;
15386  }
15387  addHighlightArea() {
15388    this.container.classList.add("highlightArea");
15389  }
15390}
15391class SquareAnnotationElement extends AnnotationElement {
15392  #square = null;
15393  constructor(parameters) {
15394    super(parameters, {
15395      isRenderable: true,
15396      ignoreBorder: true
15397    });
15398  }
15399  render() {
15400    this.container.classList.add("squareAnnotation");
15401    const data = this.data;
15402    const {
15403      width,
15404      height
15405    } = getRectDims(data.rect);
15406    const svg = this.svgFactory.create(width, height, true);
15407    const borderWidth = data.borderStyle.width;
15408    const square = this.#square = this.svgFactory.createElement("svg:rect");
15409    square.setAttribute("x", borderWidth / 2);
15410    square.setAttribute("y", borderWidth / 2);
15411    square.setAttribute("width", width - borderWidth);
15412    square.setAttribute("height", height - borderWidth);
15413    square.setAttribute("stroke-width", borderWidth || 1);
15414    square.setAttribute("stroke", "transparent");
15415    square.setAttribute("fill", "transparent");
15416    svg.append(square);
15417    this.container.append(svg);
15418    if (!data.popupRef && this.hasPopupData) {
15419      this._createPopup();
15420    }
15421    return this.container;
15422  }
15423  getElementsToTriggerPopup() {
15424    return this.#square;
15425  }
15426  addHighlightArea() {
15427    this.container.classList.add("highlightArea");
15428  }
15429}
15430class CircleAnnotationElement extends AnnotationElement {
15431  #circle = null;
15432  constructor(parameters) {
15433    super(parameters, {
15434      isRenderable: true,
15435      ignoreBorder: true
15436    });
15437  }
15438  render() {
15439    this.container.classList.add("circleAnnotation");
15440    const data = this.data;
15441    const {
15442      width,
15443      height
15444    } = getRectDims(data.rect);
15445    const svg = this.svgFactory.create(width, height, true);
15446    const borderWidth = data.borderStyle.width;
15447    const circle = this.#circle = this.svgFactory.createElement("svg:ellipse");
15448    circle.setAttribute("cx", width / 2);
15449    circle.setAttribute("cy", height / 2);
15450    circle.setAttribute("rx", width / 2 - borderWidth / 2);
15451    circle.setAttribute("ry", height / 2 - borderWidth / 2);
15452    circle.setAttribute("stroke-width", borderWidth || 1);
15453    circle.setAttribute("stroke", "transparent");
15454    circle.setAttribute("fill", "transparent");
15455    svg.append(circle);
15456    this.container.append(svg);
15457    if (!data.popupRef && this.hasPopupData) {
15458      this._createPopup();
15459    }
15460    return this.container;
15461  }
15462  getElementsToTriggerPopup() {
15463    return this.#circle;
15464  }
15465  addHighlightArea() {
15466    this.container.classList.add("highlightArea");
15467  }
15468}
15469class PolylineAnnotationElement extends AnnotationElement {
15470  #polyline = null;
15471  constructor(parameters) {
15472    super(parameters, {
15473      isRenderable: true,
15474      ignoreBorder: true
15475    });
15476    this.containerClassName = "polylineAnnotation";
15477    this.svgElementName = "svg:polyline";
15478  }
15479  render() {
15480    this.container.classList.add(this.containerClassName);
15481    const {
15482      data: {
15483        rect,
15484        vertices,
15485        borderStyle,
15486        popupRef
15487      }
15488    } = this;
15489    if (!vertices) {
15490      return this.container;
15491    }
15492    const {
15493      width,
15494      height
15495    } = getRectDims(rect);
15496    const svg = this.svgFactory.create(width, height, true);
15497    let points = [];
15498    for (let i = 0, ii = vertices.length; i < ii; i += 2) {
15499      const x = vertices[i] - rect[0];
15500      const y = rect[3] - vertices[i + 1];
15501      points.push(`${x},${y}`);
15502    }
15503    points = points.join(" ");
15504    const polyline = this.#polyline = this.svgFactory.createElement(this.svgElementName);
15505    polyline.setAttribute("points", points);
15506    polyline.setAttribute("stroke-width", borderStyle.width || 1);
15507    polyline.setAttribute("stroke", "transparent");
15508    polyline.setAttribute("fill", "transparent");
15509    svg.append(polyline);
15510    this.container.append(svg);
15511    if (!popupRef && this.hasPopupData) {
15512      this._createPopup();
15513    }
15514    return this.container;
15515  }
15516  getElementsToTriggerPopup() {
15517    return this.#polyline;
15518  }
15519  addHighlightArea() {
15520    this.container.classList.add("highlightArea");
15521  }
15522}
15523class PolygonAnnotationElement extends PolylineAnnotationElement {
15524  constructor(parameters) {
15525    super(parameters);
15526    this.containerClassName = "polygonAnnotation";
15527    this.svgElementName = "svg:polygon";
15528  }
15529}
15530class CaretAnnotationElement extends AnnotationElement {
15531  constructor(parameters) {
15532    super(parameters, {
15533      isRenderable: true,
15534      ignoreBorder: true
15535    });
15536  }
15537  render() {
15538    this.container.classList.add("caretAnnotation");
15539    if (!this.data.popupRef && this.hasPopupData) {
15540      this._createPopup();
15541    }
15542    return this.container;
15543  }
15544}
15545class InkAnnotationElement extends AnnotationElement {
15546  #polylines = [];
15547  constructor(parameters) {
15548    super(parameters, {
15549      isRenderable: true,
15550      ignoreBorder: true
15551    });
15552    this.containerClassName = "inkAnnotation";
15553    this.svgElementName = "svg:polyline";
15554    this.annotationEditorType = this.data.it === "InkHighlight" ? AnnotationEditorType.HIGHLIGHT : AnnotationEditorType.INK;
15555  }
15556  render() {
15557    this.container.classList.add(this.containerClassName);
15558    const {
15559      data: {
15560        rect,
15561        inkLists,
15562        borderStyle,
15563        popupRef
15564      }
15565    } = this;
15566    const {
15567      width,
15568      height
15569    } = getRectDims(rect);
15570    const svg = this.svgFactory.create(width, height, true);
15571    for (const inkList of inkLists) {
15572      let points = [];
15573      for (let i = 0, ii = inkList.length; i < ii; i += 2) {
15574        const x = inkList[i] - rect[0];
15575        const y = rect[3] - inkList[i + 1];
15576        points.push(`${x},${y}`);
15577      }
15578      points = points.join(" ");
15579      const polyline = this.svgFactory.createElement(this.svgElementName);
15580      this.#polylines.push(polyline);
15581      polyline.setAttribute("points", points);
15582      polyline.setAttribute("stroke-width", borderStyle.width || 1);
15583      polyline.setAttribute("stroke", "transparent");
15584      polyline.setAttribute("fill", "transparent");
15585      svg.append(polyline);
15586    }
15587    if (!popupRef && this.hasPopupData) {
15588      this._createPopup();
15589    }
15590    this.container.append(svg);
15591    this._editOnDoubleClick();
15592    return this.container;
15593  }
15594  getElementsToTriggerPopup() {
15595    return this.#polylines;
15596  }
15597  addHighlightArea() {
15598    this.container.classList.add("highlightArea");
15599  }
15600}
15601class HighlightAnnotationElement extends AnnotationElement {
15602  constructor(parameters) {
15603    super(parameters, {
15604      isRenderable: true,
15605      ignoreBorder: true,
15606      createQuadrilaterals: true
15607    });
15608    this.annotationEditorType = AnnotationEditorType.HIGHLIGHT;
15609  }
15610  render() {
15611    if (!this.data.popupRef && this.hasPopupData) {
15612      this._createPopup();
15613    }
15614    this.container.classList.add("highlightAnnotation");
15615    this._editOnDoubleClick();
15616    return this.container;
15617  }
15618}
15619class UnderlineAnnotationElement extends AnnotationElement {
15620  constructor(parameters) {
15621    super(parameters, {
15622      isRenderable: true,
15623      ignoreBorder: true,
15624      createQuadrilaterals: true
15625    });
15626  }
15627  render() {
15628    if (!this.data.popupRef && this.hasPopupData) {
15629      this._createPopup();
15630    }
15631    this.container.classList.add("underlineAnnotation");
15632    return this.container;
15633  }
15634}
15635class SquigglyAnnotationElement extends AnnotationElement {
15636  constructor(parameters) {
15637    super(parameters, {
15638      isRenderable: true,
15639      ignoreBorder: true,
15640      createQuadrilaterals: true
15641    });
15642  }
15643  render() {
15644    if (!this.data.popupRef && this.hasPopupData) {
15645      this._createPopup();
15646    }
15647    this.container.classList.add("squigglyAnnotation");
15648    return this.container;
15649  }
15650}
15651class StrikeOutAnnotationElement extends AnnotationElement {
15652  constructor(parameters) {
15653    super(parameters, {
15654      isRenderable: true,
15655      ignoreBorder: true,
15656      createQuadrilaterals: true
15657    });
15658  }
15659  render() {
15660    if (!this.data.popupRef && this.hasPopupData) {
15661      this._createPopup();
15662    }
15663    this.container.classList.add("strikeoutAnnotation");
15664    return this.container;
15665  }
15666}
15667class StampAnnotationElement extends AnnotationElement {
15668  constructor(parameters) {
15669    super(parameters, {
15670      isRenderable: true,
15671      ignoreBorder: true
15672    });
15673    this.annotationEditorType = AnnotationEditorType.STAMP;
15674  }
15675  render() {
15676    this.container.classList.add("stampAnnotation");
15677    this.container.setAttribute("role", "img");
15678    if (!this.data.popupRef && this.hasPopupData) {
15679      this._createPopup();
15680    }
15681    this._editOnDoubleClick();
15682    return this.container;
15683  }
15684}
15685class FileAttachmentAnnotationElement extends AnnotationElement {
15686  #trigger = null;
15687  constructor(parameters) {
15688    super(parameters, {
15689      isRenderable: true
15690    });
15691    const {
15692      file
15693    } = this.data;
15694    this.filename = file.filename;
15695    this.content = file.content;
15696    this.linkService.eventBus?.dispatch("fileattachmentannotation", {
15697      source: this,
15698      ...file
15699    });
15700  }
15701  render() {
15702    this.container.classList.add("fileAttachmentAnnotation");
15703    const {
15704      container,
15705      data
15706    } = this;
15707    let trigger;
15708    if (data.hasAppearance || data.fillAlpha === 0) {
15709      trigger = document.createElement("div");
15710    } else {
15711      trigger = document.createElement("img");
15712      trigger.src = `${this.imageResourcesPath}annotation-${/paperclip/i.test(data.name) ? "paperclip" : "pushpin"}.svg`;
15713      if (data.fillAlpha && data.fillAlpha < 1) {
15714        trigger.style = `filter: opacity(${Math.round(data.fillAlpha * 100)}%);`;
15715      }
15716    }
15717    trigger.addEventListener("dblclick", this.#download.bind(this));
15718    this.#trigger = trigger;
15719    const {
15720      isMac
15721    } = util_FeatureTest.platform;
15722    container.addEventListener("keydown", evt => {
15723      if (evt.key === "Enter" && (isMac ? evt.metaKey : evt.ctrlKey)) {
15724        this.#download();
15725      }
15726    });
15727    if (!data.popupRef && this.hasPopupData) {
15728      this._createPopup();
15729    } else {
15730      trigger.classList.add("popupTriggerArea");
15731    }
15732    container.append(trigger);
15733    return container;
15734  }
15735  getElementsToTriggerPopup() {
15736    return this.#trigger;
15737  }
15738  addHighlightArea() {
15739    this.container.classList.add("highlightArea");
15740  }
15741  #download() {
15742    this.downloadManager?.openOrDownloadData(this.content, this.filename);
15743  }
15744}
15745class AnnotationLayer {
15746  #accessibilityManager = null;
15747  #annotationCanvasMap = null;
15748  #editableAnnotations = new Map();
15749  #structTreeLayer = null;
15750  constructor({
15751    div,
15752    accessibilityManager,
15753    annotationCanvasMap,
15754    annotationEditorUIManager,
15755    page,
15756    viewport,
15757    structTreeLayer
15758  }) {
15759    this.div = div;
15760    this.#accessibilityManager = accessibilityManager;
15761    this.#annotationCanvasMap = annotationCanvasMap;
15762    this.#structTreeLayer = structTreeLayer || null;
15763    this.page = page;
15764    this.viewport = viewport;
15765    this.zIndex = 0;
15766    this._annotationEditorUIManager = annotationEditorUIManager;
15767  }
15768  hasEditableAnnotations() {
15769    return this.#editableAnnotations.size > 0;
15770  }
15771  async #appendElement(element, id) {
15772    const contentElement = element.firstChild || element;
15773    const annotationId = contentElement.id = `${AnnotationPrefix}${id}`;
15774    const ariaAttributes = await this.#structTreeLayer?.getAriaAttributes(annotationId);
15775    if (ariaAttributes) {
15776      for (const [key, value] of ariaAttributes) {
15777        contentElement.setAttribute(key, value);
15778      }
15779    }
15780    this.div.append(element);
15781    this.#accessibilityManager?.moveElementInDOM(this.div, element, contentElement, false);
15782  }
15783  async render(params) {
15784    const {
15785      annotations
15786    } = params;
15787    const layer = this.div;
15788    setLayerDimensions(layer, this.viewport);
15789    const popupToElements = new Map();
15790    const elementParams = {
15791      data: null,
15792      layer,
15793      linkService: params.linkService,
15794      downloadManager: params.downloadManager,
15795      imageResourcesPath: params.imageResourcesPath || "",
15796      renderForms: params.renderForms !== false,
15797      svgFactory: new DOMSVGFactory(),
15798      annotationStorage: params.annotationStorage || new AnnotationStorage(),
15799      enableScripting: params.enableScripting === true,
15800      hasJSActions: params.hasJSActions,
15801      fieldObjects: params.fieldObjects,
15802      parent: this,
15803      elements: null
15804    };
15805    for (const data of annotations) {
15806      if (data.noHTML) {
15807        continue;
15808      }
15809      const isPopupAnnotation = data.annotationType === AnnotationType.POPUP;
15810      if (!isPopupAnnotation) {
15811        const {
15812          width,
15813          height
15814        } = getRectDims(data.rect);
15815        if (width <= 0 || height <= 0) {
15816          continue;
15817        }
15818      } else {
15819        const elements = popupToElements.get(data.id);
15820        if (!elements) {
15821          continue;
15822        }
vendor: 4,533 bytes, lines 15823-15960
15823        elementParams.elements = elements;
15824      }
15825      elementParams.data = data;
15826      const element = AnnotationElementFactory.create(elementParams);
15827      if (!element.isRenderable) {
15828        continue;
15829      }
15830      if (!isPopupAnnotation && data.popupRef) {
15831        const elements = popupToElements.get(data.popupRef);
15832        if (!elements) {
15833          popupToElements.set(data.popupRef, [element]);
15834        } else {
15835          elements.push(element);
15836        }
15837      }
15838      const rendered = element.render();
15839      if (data.hidden) {
15840        rendered.style.visibility = "hidden";
15841      }
15842      await this.#appendElement(rendered, data.id);
15843      if (element._isEditable) {
15844        this.#editableAnnotations.set(element.data.id, element);
15845        this._annotationEditorUIManager?.renderAnnotationElement(element);
15846      }
15847    }
15848    this.#setAnnotationCanvasMap();
15849  }
15850  update({
15851    viewport
15852  }) {
15853    const layer = this.div;
15854    this.viewport = viewport;
15855    setLayerDimensions(layer, {
15856      rotation: viewport.rotation
15857    });
15858    this.#setAnnotationCanvasMap();
15859    layer.hidden = false;
15860  }
15861  #setAnnotationCanvasMap() {
15862    if (!this.#annotationCanvasMap) {
15863      return;
15864    }
15865    const layer = this.div;
15866    for (const [id, canvas] of this.#annotationCanvasMap) {
15867      const element = layer.querySelector(`[data-annotation-id="${id}"]`);
15868      if (!element) {
15869        continue;
15870      }
15871      canvas.className = "annotationContent";
15872      const {
15873        firstChild
15874      } = element;
15875      if (!firstChild) {
15876        element.append(canvas);
15877      } else if (firstChild.nodeName === "CANVAS") {
15878        firstChild.replaceWith(canvas);
15879      } else if (!firstChild.classList.contains("annotationContent")) {
15880        firstChild.before(canvas);
15881      } else {
15882        firstChild.after(canvas);
15883      }
15884    }
15885    this.#annotationCanvasMap.clear();
15886  }
15887  getEditableAnnotations() {
15888    return Array.from(this.#editableAnnotations.values());
15889  }
15890  getEditableAnnotation(id) {
15891    return this.#editableAnnotations.get(id);
15892  }
15893}
15894
15895;// ./src/display/editor/freetext.js
15896
15897
15898
15899
15900const EOL_PATTERN = /\r\n?|\n/g;
15901class FreeTextEditor extends AnnotationEditor {
15902  #color;
15903  #content = "";
15904  #editorDivId = `${this.id}-editor`;
15905  #editModeAC = null;
15906  #fontSize;
15907  static _freeTextDefaultContent = "";
15908  static _internalPadding = 0;
15909  static _defaultColor = null;
15910  static _defaultFontSize = 10;
15911  static get _keyboardManager() {
15912    const proto = FreeTextEditor.prototype;
15913    const arrowChecker = self => self.isEmpty();
15914    const small = AnnotationEditorUIManager.TRANSLATE_SMALL;
15915    const big = AnnotationEditorUIManager.TRANSLATE_BIG;
15916    return shadow(this, "_keyboardManager", new KeyboardManager([[["ctrl+s", "mac+meta+s", "ctrl+p", "mac+meta+p"], proto.commitOrRemove, {
15917      bubbles: true
15918    }], [["ctrl+Enter", "mac+meta+Enter", "Escape", "mac+Escape"], proto.commitOrRemove], [["ArrowLeft", "mac+ArrowLeft"], proto._translateEmpty, {
15919      args: [-small, 0],
15920      checker: arrowChecker
15921    }], [["ctrl+ArrowLeft", "mac+shift+ArrowLeft"], proto._translateEmpty, {
15922      args: [-big, 0],
15923      checker: arrowChecker
15924    }], [["ArrowRight", "mac+ArrowRight"], proto._translateEmpty, {
15925      args: [small, 0],
15926      checker: arrowChecker
15927    }], [["ctrl+ArrowRight", "mac+shift+ArrowRight"], proto._translateEmpty, {
15928      args: [big, 0],
15929      checker: arrowChecker
15930    }], [["ArrowUp", "mac+ArrowUp"], proto._translateEmpty, {
15931      args: [0, -small],
15932      checker: arrowChecker
15933    }], [["ctrl+ArrowUp", "mac+shift+ArrowUp"], proto._translateEmpty, {
15934      args: [0, -big],
15935      checker: arrowChecker
15936    }], [["ArrowDown", "mac+ArrowDown"], proto._translateEmpty, {
15937      args: [0, small],
15938      checker: arrowChecker
15939    }], [["ctrl+ArrowDown", "mac+shift+ArrowDown"], proto._translateEmpty, {
15940      args: [0, big],
15941      checker: arrowChecker
15942    }]]));
15943  }
15944  static _type = "freetext";
15945  static _editorType = AnnotationEditorType.FREETEXT;
15946  constructor(params) {
15947    super({
15948      ...params,
15949      name: "freeTextEditor"
15950    });
15951    this.#color = params.color || FreeTextEditor._defaultColor || AnnotationEditor._defaultLineColor;
15952    this.#fontSize = params.fontSize || FreeTextEditor._defaultFontSize;
15953  }
15954  static initialize(l10n, uiManager) {
15955    AnnotationEditor.initialize(l10n, uiManager);
15956    const style = getComputedStyle(document.documentElement);
15957    this._internalPadding = parseFloat(style.getPropertyValue("--freetext-padding"));
15958  }
15959  static updateDefaultParams(type, value) {
15960    switch (type) {
vendor: 10,244 bytes, lines 15961-16290
15961      case AnnotationEditorParamsType.FREETEXT_SIZE:
15962        FreeTextEditor._defaultFontSize = value;
15963        break;
15964      case AnnotationEditorParamsType.FREETEXT_COLOR:
15965        FreeTextEditor._defaultColor = value;
15966        break;
15967    }
15968  }
15969  updateParams(type, value) {
15970    switch (type) {
15971      case AnnotationEditorParamsType.FREETEXT_SIZE:
15972        this.#updateFontSize(value);
15973        break;
15974      case AnnotationEditorParamsType.FREETEXT_COLOR:
15975        this.#updateColor(value);
15976        break;
15977    }
15978  }
15979  static get defaultPropertiesToUpdate() {
15980    return [[AnnotationEditorParamsType.FREETEXT_SIZE, FreeTextEditor._defaultFontSize], [AnnotationEditorParamsType.FREETEXT_COLOR, FreeTextEditor._defaultColor || AnnotationEditor._defaultLineColor]];
15981  }
15982  get propertiesToUpdate() {
15983    return [[AnnotationEditorParamsType.FREETEXT_SIZE, this.#fontSize], [AnnotationEditorParamsType.FREETEXT_COLOR, this.#color]];
15984  }
15985  #updateFontSize(fontSize) {
15986    const setFontsize = size => {
15987      this.editorDiv.style.fontSize = `calc(${size}px * var(--scale-factor))`;
15988      this.translate(0, -(size - this.#fontSize) * this.parentScale);
15989      this.#fontSize = size;
15990      this.#setEditorDimensions();
15991    };
15992    const savedFontsize = this.#fontSize;
15993    this.addCommands({
15994      cmd: setFontsize.bind(this, fontSize),
15995      undo: setFontsize.bind(this, savedFontsize),
15996      post: this._uiManager.updateUI.bind(this._uiManager, this),
15997      mustExec: true,
15998      type: AnnotationEditorParamsType.FREETEXT_SIZE,
15999      overwriteIfSameType: true,
16000      keepUndo: true
16001    });
16002  }
16003  #updateColor(color) {
16004    const setColor = col => {
16005      this.#color = this.editorDiv.style.color = col;
16006    };
16007    const savedColor = this.#color;
16008    this.addCommands({
16009      cmd: setColor.bind(this, color),
16010      undo: setColor.bind(this, savedColor),
16011      post: this._uiManager.updateUI.bind(this._uiManager, this),
16012      mustExec: true,
16013      type: AnnotationEditorParamsType.FREETEXT_COLOR,
16014      overwriteIfSameType: true,
16015      keepUndo: true
16016    });
16017  }
16018  _translateEmpty(x, y) {
16019    this._uiManager.translateSelectedEditors(x, y, true);
16020  }
16021  getInitialTranslation() {
16022    const scale = this.parentScale;
16023    return [-FreeTextEditor._internalPadding * scale, -(FreeTextEditor._internalPadding + this.#fontSize) * scale];
16024  }
16025  rebuild() {
16026    if (!this.parent) {
16027      return;
16028    }
16029    super.rebuild();
16030    if (this.div === null) {
16031      return;
16032    }
16033    if (!this.isAttachedToDOM) {
16034      this.parent.add(this);
16035    }
16036  }
16037  enableEditMode() {
16038    if (this.isInEditMode()) {
16039      return;
16040    }
16041    this.parent.setEditingState(false);
16042    this.parent.updateToolbar(AnnotationEditorType.FREETEXT);
16043    super.enableEditMode();
16044    this.overlayDiv.classList.remove("enabled");
16045    this.editorDiv.contentEditable = true;
16046    this._isDraggable = false;
16047    this.div.removeAttribute("aria-activedescendant");
16048    this.#editModeAC = new AbortController();
16049    const signal = this._uiManager.combinedSignal(this.#editModeAC);
16050    this.editorDiv.addEventListener("keydown", this.editorDivKeydown.bind(this), {
16051      signal
16052    });
16053    this.editorDiv.addEventListener("focus", this.editorDivFocus.bind(this), {
16054      signal
16055    });
16056    this.editorDiv.addEventListener("blur", this.editorDivBlur.bind(this), {
16057      signal
16058    });
16059    this.editorDiv.addEventListener("input", this.editorDivInput.bind(this), {
16060      signal
16061    });
16062    this.editorDiv.addEventListener("paste", this.editorDivPaste.bind(this), {
16063      signal
16064    });
16065  }
16066  disableEditMode() {
16067    if (!this.isInEditMode()) {
16068      return;
16069    }
16070    this.parent.setEditingState(true);
16071    super.disableEditMode();
16072    this.overlayDiv.classList.add("enabled");
16073    this.editorDiv.contentEditable = false;
16074    this.div.setAttribute("aria-activedescendant", this.#editorDivId);
16075    this._isDraggable = true;
16076    this.#editModeAC?.abort();
16077    this.#editModeAC = null;
16078    this.div.focus({
16079      preventScroll: true
16080    });
16081    this.isEditing = false;
16082    this.parent.div.classList.add("freetextEditing");
16083  }
16084  focusin(event) {
16085    if (!this._focusEventsAllowed) {
16086      return;
16087    }
16088    super.focusin(event);
16089    if (event.target !== this.editorDiv) {
16090      this.editorDiv.focus();
16091    }
16092  }
16093  onceAdded() {
16094    if (this.width) {
16095      return;
16096    }
16097    this.enableEditMode();
16098    this.editorDiv.focus();
16099    if (this._initialOptions?.isCentered) {
16100      this.center();
16101    }
16102    this._initialOptions = null;
16103  }
16104  isEmpty() {
16105    return !this.editorDiv || this.editorDiv.innerText.trim() === "";
16106  }
16107  remove() {
16108    this.isEditing = false;
16109    if (this.parent) {
16110      this.parent.setEditingState(true);
16111      this.parent.div.classList.add("freetextEditing");
16112    }
16113    super.remove();
16114  }
16115  #extractText() {
16116    const buffer = [];
16117    this.editorDiv.normalize();
16118    let prevChild = null;
16119    for (const child of this.editorDiv.childNodes) {
16120      if (prevChild?.nodeType === Node.TEXT_NODE && child.nodeName === "BR") {
16121        continue;
16122      }
16123      buffer.push(FreeTextEditor.#getNodeContent(child));
16124      prevChild = child;
16125    }
16126    return buffer.join("\n");
16127  }
16128  #setEditorDimensions() {
16129    const [parentWidth, parentHeight] = this.parentDimensions;
16130    let rect;
16131    if (this.isAttachedToDOM) {
16132      rect = this.div.getBoundingClientRect();
16133    } else {
16134      const {
16135        currentLayer,
16136        div
16137      } = this;
16138      const savedDisplay = div.style.display;
16139      const savedVisibility = div.classList.contains("hidden");
16140      div.classList.remove("hidden");
16141      div.style.display = "hidden";
16142      currentLayer.div.append(this.div);
16143      rect = div.getBoundingClientRect();
16144      div.remove();
16145      div.style.display = savedDisplay;
16146      div.classList.toggle("hidden", savedVisibility);
16147    }
16148    if (this.rotation % 180 === this.parentRotation % 180) {
16149      this.width = rect.width / parentWidth;
16150      this.height = rect.height / parentHeight;
16151    } else {
16152      this.width = rect.height / parentWidth;
16153      this.height = rect.width / parentHeight;
16154    }
16155    this.fixAndSetPosition();
16156  }
16157  commit() {
16158    if (!this.isInEditMode()) {
16159      return;
16160    }
16161    super.commit();
16162    this.disableEditMode();
16163    const savedText = this.#content;
16164    const newText = this.#content = this.#extractText().trimEnd();
16165    if (savedText === newText) {
16166      return;
16167    }
16168    const setText = text => {
16169      this.#content = text;
16170      if (!text) {
16171        this.remove();
16172        return;
16173      }
16174      this.#setContent();
16175      this._uiManager.rebuild(this);
16176      this.#setEditorDimensions();
16177    };
16178    this.addCommands({
16179      cmd: () => {
16180        setText(newText);
16181      },
16182      undo: () => {
16183        setText(savedText);
16184      },
16185      mustExec: false
16186    });
16187    this.#setEditorDimensions();
16188  }
16189  shouldGetKeyboardEvents() {
16190    return this.isInEditMode();
16191  }
16192  enterInEditMode() {
16193    this.enableEditMode();
16194    this.editorDiv.focus();
16195  }
16196  dblclick(event) {
16197    this.enterInEditMode();
16198  }
16199  keydown(event) {
16200    if (event.target === this.div && event.key === "Enter") {
16201      this.enterInEditMode();
16202      event.preventDefault();
16203    }
16204  }
16205  editorDivKeydown(event) {
16206    FreeTextEditor._keyboardManager.exec(this, event);
16207  }
16208  editorDivFocus(event) {
16209    this.isEditing = true;
16210  }
16211  editorDivBlur(event) {
16212    this.isEditing = false;
16213  }
16214  editorDivInput(event) {
16215    this.parent.div.classList.toggle("freetextEditing", this.isEmpty());
16216  }
16217  disableEditing() {
16218    this.editorDiv.setAttribute("role", "comment");
16219    this.editorDiv.removeAttribute("aria-multiline");
16220  }
16221  enableEditing() {
16222    this.editorDiv.setAttribute("role", "textbox");
16223    this.editorDiv.setAttribute("aria-multiline", true);
16224  }
16225  render() {
16226    if (this.div) {
16227      return this.div;
16228    }
16229    let baseX, baseY;
16230    if (this.width) {
16231      baseX = this.x;
16232      baseY = this.y;
16233    }
16234    super.render();
16235    this.editorDiv = document.createElement("div");
16236    this.editorDiv.className = "internal";
16237    this.editorDiv.setAttribute("id", this.#editorDivId);
16238    this.editorDiv.setAttribute("data-l10n-id", "pdfjs-free-text2");
16239    this.editorDiv.setAttribute("data-l10n-attrs", "default-content");
16240    this.enableEditing();
16241    this.editorDiv.contentEditable = true;
16242    const {
16243      style
16244    } = this.editorDiv;
16245    style.fontSize = `calc(${this.#fontSize}px * var(--scale-factor))`;
16246    style.color = this.#color;
16247    this.div.append(this.editorDiv);
16248    this.overlayDiv = document.createElement("div");
16249    this.overlayDiv.classList.add("overlay", "enabled");
16250    this.div.append(this.overlayDiv);
16251    bindEvents(this, this.div, ["dblclick", "keydown"]);
16252    if (this.width) {
16253      const [parentWidth, parentHeight] = this.parentDimensions;
16254      if (this.annotationElementId) {
16255        const {
16256          position
16257        } = this._initialData;
16258        let [tx, ty] = this.getInitialTranslation();
16259        [tx, ty] = this.pageTranslationToScreen(tx, ty);
16260        const [pageWidth, pageHeight] = this.pageDimensions;
16261        const [pageX, pageY] = this.pageTranslation;
16262        let posX, posY;
16263        switch (this.rotation) {
16264          case 0:
16265            posX = baseX + (position[0] - pageX) / pageWidth;
16266            posY = baseY + this.height - (position[1] - pageY) / pageHeight;
16267            break;
16268          case 90:
16269            posX = baseX + (position[0] - pageX) / pageWidth;
16270            posY = baseY - (position[1] - pageY) / pageHeight;
16271            [tx, ty] = [ty, -tx];
16272            break;
16273          case 180:
16274            posX = baseX - this.width + (position[0] - pageX) / pageWidth;
16275            posY = baseY - (position[1] - pageY) / pageHeight;
16276            [tx, ty] = [-tx, -ty];
16277            break;
16278          case 270:
16279            posX = baseX + (position[0] - pageX - this.height * pageHeight) / pageWidth;
16280            posY = baseY + (position[1] - pageY - this.width * pageWidth) / pageHeight;
16281            [tx, ty] = [-ty, tx];
16282            break;
16283        }
16284        this.setAt(posX * parentWidth, posY * parentHeight, tx, ty);
16285      } else {
16286        this.setAt(baseX * parentWidth, baseY * parentHeight, this.width * parentWidth, this.height * parentHeight);
16287      }
16288      this.#setContent();
16289      this._isDraggable = true;
16290      this.editorDiv.contentEditable = false;
vendor: 46,341 bytes, lines 16291-17718
16291    } else {
16292      this._isDraggable = false;
16293      this.editorDiv.contentEditable = true;
16294    }
16295    return this.div;
16296  }
16297  static #getNodeContent(node) {
16298    return (node.nodeType === Node.TEXT_NODE ? node.nodeValue : node.innerText).replaceAll(EOL_PATTERN, "");
16299  }
16300  editorDivPaste(event) {
16301    const clipboardData = event.clipboardData || window.clipboardData;
16302    const {
16303      types
16304    } = clipboardData;
16305    if (types.length === 1 && types[0] === "text/plain") {
16306      return;
16307    }
16308    event.preventDefault();
16309    const paste = FreeTextEditor.#deserializeContent(clipboardData.getData("text") || "").replaceAll(EOL_PATTERN, "\n");
16310    if (!paste) {
16311      return;
16312    }
16313    const selection = window.getSelection();
16314    if (!selection.rangeCount) {
16315      return;
16316    }
16317    this.editorDiv.normalize();
16318    selection.deleteFromDocument();
16319    const range = selection.getRangeAt(0);
16320    if (!paste.includes("\n")) {
16321      range.insertNode(document.createTextNode(paste));
16322      this.editorDiv.normalize();
16323      selection.collapseToStart();
16324      return;
16325    }
16326    const {
16327      startContainer,
16328      startOffset
16329    } = range;
16330    const bufferBefore = [];
16331    const bufferAfter = [];
16332    if (startContainer.nodeType === Node.TEXT_NODE) {
16333      const parent = startContainer.parentElement;
16334      bufferAfter.push(startContainer.nodeValue.slice(startOffset).replaceAll(EOL_PATTERN, ""));
16335      if (parent !== this.editorDiv) {
16336        let buffer = bufferBefore;
16337        for (const child of this.editorDiv.childNodes) {
16338          if (child === parent) {
16339            buffer = bufferAfter;
16340            continue;
16341          }
16342          buffer.push(FreeTextEditor.#getNodeContent(child));
16343        }
16344      }
16345      bufferBefore.push(startContainer.nodeValue.slice(0, startOffset).replaceAll(EOL_PATTERN, ""));
16346    } else if (startContainer === this.editorDiv) {
16347      let buffer = bufferBefore;
16348      let i = 0;
16349      for (const child of this.editorDiv.childNodes) {
16350        if (i++ === startOffset) {
16351          buffer = bufferAfter;
16352        }
16353        buffer.push(FreeTextEditor.#getNodeContent(child));
16354      }
16355    }
16356    this.#content = `${bufferBefore.join("\n")}${paste}${bufferAfter.join("\n")}`;
16357    this.#setContent();
16358    const newRange = new Range();
16359    let beforeLength = bufferBefore.reduce((acc, line) => acc + line.length, 0);
16360    for (const {
16361      firstChild
16362    } of this.editorDiv.childNodes) {
16363      if (firstChild.nodeType === Node.TEXT_NODE) {
16364        const length = firstChild.nodeValue.length;
16365        if (beforeLength <= length) {
16366          newRange.setStart(firstChild, beforeLength);
16367          newRange.setEnd(firstChild, beforeLength);
16368          break;
16369        }
16370        beforeLength -= length;
16371      }
16372    }
16373    selection.removeAllRanges();
16374    selection.addRange(newRange);
16375  }
16376  #setContent() {
16377    this.editorDiv.replaceChildren();
16378    if (!this.#content) {
16379      return;
16380    }
16381    for (const line of this.#content.split("\n")) {
16382      const div = document.createElement("div");
16383      div.append(line ? document.createTextNode(line) : document.createElement("br"));
16384      this.editorDiv.append(div);
16385    }
16386  }
16387  #serializeContent() {
16388    return this.#content.replaceAll("\xa0", " ");
16389  }
16390  static #deserializeContent(content) {
16391    return content.replaceAll(" ", "\xa0");
16392  }
16393  get contentDiv() {
16394    return this.editorDiv;
16395  }
16396  static async deserialize(data, parent, uiManager) {
16397    let initialData = null;
16398    if (data instanceof FreeTextAnnotationElement) {
16399      const {
16400        data: {
16401          defaultAppearanceData: {
16402            fontSize,
16403            fontColor
16404          },
16405          rect,
16406          rotation,
16407          id,
16408          popupRef
16409        },
16410        textContent,
16411        textPosition,
16412        parent: {
16413          page: {
16414            pageNumber
16415          }
16416        }
16417      } = data;
16418      if (!textContent || textContent.length === 0) {
16419        return null;
16420      }
16421      initialData = data = {
16422        annotationType: AnnotationEditorType.FREETEXT,
16423        color: Array.from(fontColor),
16424        fontSize,
16425        value: textContent.join("\n"),
16426        position: textPosition,
16427        pageIndex: pageNumber - 1,
16428        rect: rect.slice(0),
16429        rotation,
16430        id,
16431        deleted: false,
16432        popupRef
16433      };
16434    }
16435    const editor = await super.deserialize(data, parent, uiManager);
16436    editor.#fontSize = data.fontSize;
16437    editor.#color = Util.makeHexColor(...data.color);
16438    editor.#content = FreeTextEditor.#deserializeContent(data.value);
16439    editor.annotationElementId = data.id || null;
16440    editor._initialData = initialData;
16441    return editor;
16442  }
16443  serialize(isForCopying = false) {
16444    if (this.isEmpty()) {
16445      return null;
16446    }
16447    if (this.deleted) {
16448      return this.serializeDeleted();
16449    }
16450    const padding = FreeTextEditor._internalPadding * this.parentScale;
16451    const rect = this.getRect(padding, padding);
16452    const color = AnnotationEditor._colorManager.convert(this.isAttachedToDOM ? getComputedStyle(this.editorDiv).color : this.#color);
16453    const serialized = {
16454      annotationType: AnnotationEditorType.FREETEXT,
16455      color,
16456      fontSize: this.#fontSize,
16457      value: this.#serializeContent(),
16458      pageIndex: this.pageIndex,
16459      rect,
16460      rotation: this.rotation,
16461      structTreeParentId: this._structTreeParentId
16462    };
16463    if (isForCopying) {
16464      return serialized;
16465    }
16466    if (this.annotationElementId && !this.#hasElementChanged(serialized)) {
16467      return null;
16468    }
16469    serialized.id = this.annotationElementId;
16470    return serialized;
16471  }
16472  #hasElementChanged(serialized) {
16473    const {
16474      value,
16475      fontSize,
16476      color,
16477      pageIndex
16478    } = this._initialData;
16479    return this._hasBeenMoved || serialized.value !== value || serialized.fontSize !== fontSize || serialized.color.some((c, i) => c !== color[i]) || serialized.pageIndex !== pageIndex;
16480  }
16481  renderAnnotationElement(annotation) {
16482    const content = super.renderAnnotationElement(annotation);
16483    if (this.deleted) {
16484      return content;
16485    }
16486    const {
16487      style
16488    } = content;
16489    style.fontSize = `calc(${this.#fontSize}px * var(--scale-factor))`;
16490    style.color = this.#color;
16491    content.replaceChildren();
16492    for (const line of this.#content.split("\n")) {
16493      const div = document.createElement("div");
16494      div.append(line ? document.createTextNode(line) : document.createElement("br"));
16495      content.append(div);
16496    }
16497    const padding = FreeTextEditor._internalPadding * this.parentScale;
16498    annotation.updateEdited({
16499      rect: this.getRect(padding, padding),
16500      popupContent: this.#content
16501    });
16502    return content;
16503  }
16504  resetAnnotationElement(annotation) {
16505    super.resetAnnotationElement(annotation);
16506    annotation.resetEdited();
16507  }
16508}
16509
16510;// ./src/display/editor/drawers/outline.js
16511
16512class Outline {
16513  toSVGPath() {
16514    unreachable("Abstract method `toSVGPath` must be implemented.");
16515  }
16516  get box() {
16517    unreachable("Abstract getter `box` must be implemented.");
16518  }
16519  serialize(_bbox, _rotation) {
16520    unreachable("Abstract method `serialize` must be implemented.");
16521  }
16522  get classNamesForDrawing() {
16523    unreachable("Abstract getter `classNamesForDrawing` must be implemented.");
16524  }
16525  get classNamesForOutlining() {
16526    unreachable("Abstract getter `classNamesForOutlining` must be implemented.");
16527  }
16528  get mustRemoveSelfIntersections() {
16529    return false;
16530  }
16531}
16532
16533;// ./src/display/editor/drawers/freedraw.js
16534
16535
16536class FreeDrawOutliner {
16537  #box;
16538  #bottom = [];
16539  #innerMargin;
16540  #isLTR;
16541  #top = [];
16542  #last = new Float64Array(18);
16543  #lastX;
16544  #lastY;
16545  #min;
16546  #min_dist;
16547  #scaleFactor;
16548  #thickness;
16549  #points = [];
16550  static #MIN_DIST = 8;
16551  static #MIN_DIFF = 2;
16552  static #MIN = FreeDrawOutliner.#MIN_DIST + FreeDrawOutliner.#MIN_DIFF;
16553  constructor({
16554    x,
16555    y
16556  }, box, scaleFactor, thickness, isLTR, innerMargin = 0) {
16557    this.#box = box;
16558    this.#thickness = thickness * scaleFactor;
16559    this.#isLTR = isLTR;
16560    this.#last.set([NaN, NaN, NaN, NaN, x, y], 6);
16561    this.#innerMargin = innerMargin;
16562    this.#min_dist = FreeDrawOutliner.#MIN_DIST * scaleFactor;
16563    this.#min = FreeDrawOutliner.#MIN * scaleFactor;
16564    this.#scaleFactor = scaleFactor;
16565    this.#points.push(x, y);
16566  }
16567  isEmpty() {
16568    return isNaN(this.#last[8]);
16569  }
16570  #getLastCoords() {
16571    const lastTop = this.#last.subarray(4, 6);
16572    const lastBottom = this.#last.subarray(16, 18);
16573    const [x, y, width, height] = this.#box;
16574    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];
16575  }
16576  add({
16577    x,
16578    y
16579  }) {
16580    this.#lastX = x;
16581    this.#lastY = y;
16582    const [layerX, layerY, layerWidth, layerHeight] = this.#box;
16583    let [x1, y1, x2, y2] = this.#last.subarray(8, 12);
16584    const diffX = x - x2;
16585    const diffY = y - y2;
16586    const d = Math.hypot(diffX, diffY);
16587    if (d < this.#min) {
16588      return false;
16589    }
16590    const diffD = d - this.#min_dist;
16591    const K = diffD / d;
16592    const shiftX = K * diffX;
16593    const shiftY = K * diffY;
16594    let x0 = x1;
16595    let y0 = y1;
16596    x1 = x2;
16597    y1 = y2;
16598    x2 += shiftX;
16599    y2 += shiftY;
16600    this.#points?.push(x, y);
16601    const nX = -shiftY / diffD;
16602    const nY = shiftX / diffD;
16603    const thX = nX * this.#thickness;
16604    const thY = nY * this.#thickness;
16605    this.#last.set(this.#last.subarray(2, 8), 0);
16606    this.#last.set([x2 + thX, y2 + thY], 4);
16607    this.#last.set(this.#last.subarray(14, 18), 12);
16608    this.#last.set([x2 - thX, y2 - thY], 16);
16609    if (isNaN(this.#last[6])) {
16610      if (this.#top.length === 0) {
16611        this.#last.set([x1 + thX, y1 + thY], 2);
16612        this.#top.push(NaN, NaN, NaN, NaN, (x1 + thX - layerX) / layerWidth, (y1 + thY - layerY) / layerHeight);
16613        this.#last.set([x1 - thX, y1 - thY], 14);
16614        this.#bottom.push(NaN, NaN, NaN, NaN, (x1 - thX - layerX) / layerWidth, (y1 - thY - layerY) / layerHeight);
16615      }
16616      this.#last.set([x0, y0, x1, y1, x2, y2], 6);
16617      return !this.isEmpty();
16618    }
16619    this.#last.set([x0, y0, x1, y1, x2, y2], 6);
16620    const angle = Math.abs(Math.atan2(y0 - y1, x0 - x1) - Math.atan2(shiftY, shiftX));
16621    if (angle < Math.PI / 2) {
16622      [x1, y1, x2, y2] = this.#last.subarray(2, 6);
16623      this.#top.push(NaN, NaN, NaN, NaN, ((x1 + x2) / 2 - layerX) / layerWidth, ((y1 + y2) / 2 - layerY) / layerHeight);
16624      [x1, y1, x0, y0] = this.#last.subarray(14, 18);
16625      this.#bottom.push(NaN, NaN, NaN, NaN, ((x0 + x1) / 2 - layerX) / layerWidth, ((y0 + y1) / 2 - layerY) / layerHeight);
16626      return true;
16627    }
16628    [x0, y0, x1, y1, x2, y2] = this.#last.subarray(0, 6);
16629    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);
16630    [x2, y2, x1, y1, x0, y0] = this.#last.subarray(12, 18);
16631    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);
16632    return true;
16633  }
16634  toSVGPath() {
16635    if (this.isEmpty()) {
16636      return "";
16637    }
16638    const top = this.#top;
16639    const bottom = this.#bottom;
16640    if (isNaN(this.#last[6]) && !this.isEmpty()) {
16641      return this.#toSVGPathTwoPoints();
16642    }
16643    const buffer = [];
16644    buffer.push(`M${top[4]} ${top[5]}`);
16645    for (let i = 6; i < top.length; i += 6) {
16646      if (isNaN(top[i])) {
16647        buffer.push(`L${top[i + 4]} ${top[i + 5]}`);
16648      } else {
16649        buffer.push(`C${top[i]} ${top[i + 1]} ${top[i + 2]} ${top[i + 3]} ${top[i + 4]} ${top[i + 5]}`);
16650      }
16651    }
16652    this.#toSVGPathEnd(buffer);
16653    for (let i = bottom.length - 6; i >= 6; i -= 6) {
16654      if (isNaN(bottom[i])) {
16655        buffer.push(`L${bottom[i + 4]} ${bottom[i + 5]}`);
16656      } else {
16657        buffer.push(`C${bottom[i]} ${bottom[i + 1]} ${bottom[i + 2]} ${bottom[i + 3]} ${bottom[i + 4]} ${bottom[i + 5]}`);
16658      }
16659    }
16660    this.#toSVGPathStart(buffer);
16661    return buffer.join(" ");
16662  }
16663  #toSVGPathTwoPoints() {
16664    const [x, y, width, height] = this.#box;
16665    const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
16666    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`;
16667  }
16668  #toSVGPathStart(buffer) {
16669    const bottom = this.#bottom;
16670    buffer.push(`L${bottom[4]} ${bottom[5]} Z`);
16671  }
16672  #toSVGPathEnd(buffer) {
16673    const [x, y, width, height] = this.#box;
16674    const lastTop = this.#last.subarray(4, 6);
16675    const lastBottom = this.#last.subarray(16, 18);
16676    const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
16677    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}`);
16678  }
16679  newFreeDrawOutline(outline, points, box, scaleFactor, innerMargin, isLTR) {
16680    return new FreeDrawOutline(outline, points, box, scaleFactor, innerMargin, isLTR);
16681  }
16682  getOutlines() {
16683    const top = this.#top;
16684    const bottom = this.#bottom;
16685    const last = this.#last;
16686    const [layerX, layerY, layerWidth, layerHeight] = this.#box;
16687    const points = new Float64Array((this.#points?.length ?? 0) + 2);
16688    for (let i = 0, ii = points.length - 2; i < ii; i += 2) {
16689      points[i] = (this.#points[i] - layerX) / layerWidth;
16690      points[i + 1] = (this.#points[i + 1] - layerY) / layerHeight;
16691    }
16692    points[points.length - 2] = (this.#lastX - layerX) / layerWidth;
16693    points[points.length - 1] = (this.#lastY - layerY) / layerHeight;
16694    if (isNaN(last[6]) && !this.isEmpty()) {
16695      return this.#getOutlineTwoPoints(points);
16696    }
16697    const outline = new Float64Array(this.#top.length + 24 + this.#bottom.length);
16698    let N = top.length;
16699    for (let i = 0; i < N; i += 2) {
16700      if (isNaN(top[i])) {
16701        outline[i] = outline[i + 1] = NaN;
16702        continue;
16703      }
16704      outline[i] = top[i];
16705      outline[i + 1] = top[i + 1];
16706    }
16707    N = this.#getOutlineEnd(outline, N);
16708    for (let i = bottom.length - 6; i >= 6; i -= 6) {
16709      for (let j = 0; j < 6; j += 2) {
16710        if (isNaN(bottom[i + j])) {
16711          outline[N] = outline[N + 1] = NaN;
16712          N += 2;
16713          continue;
16714        }
16715        outline[N] = bottom[i + j];
16716        outline[N + 1] = bottom[i + j + 1];
16717        N += 2;
16718      }
16719    }
16720    this.#getOutlineStart(outline, N);
16721    return this.newFreeDrawOutline(outline, points, this.#box, this.#scaleFactor, this.#innerMargin, this.#isLTR);
16722  }
16723  #getOutlineTwoPoints(points) {
16724    const last = this.#last;
16725    const [layerX, layerY, layerWidth, layerHeight] = this.#box;
16726    const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
16727    const outline = new Float64Array(36);
16728    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);
16729    return this.newFreeDrawOutline(outline, points, this.#box, this.#scaleFactor, this.#innerMargin, this.#isLTR);
16730  }
16731  #getOutlineStart(outline, pos) {
16732    const bottom = this.#bottom;
16733    outline.set([NaN, NaN, NaN, NaN, bottom[4], bottom[5]], pos);
16734    return pos += 6;
16735  }
16736  #getOutlineEnd(outline, pos) {
16737    const lastTop = this.#last.subarray(4, 6);
16738    const lastBottom = this.#last.subarray(16, 18);
16739    const [layerX, layerY, layerWidth, layerHeight] = this.#box;
16740    const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
16741    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);
16742    return pos += 24;
16743  }
16744}
16745class FreeDrawOutline extends Outline {
16746  #box;
16747  #bbox = null;
16748  #innerMargin;
16749  #isLTR;
16750  #points;
16751  #scaleFactor;
16752  #outline;
16753  constructor(outline, points, box, scaleFactor, innerMargin, isLTR) {
16754    super();
16755    this.#outline = outline;
16756    this.#points = points;
16757    this.#box = box;
16758    this.#scaleFactor = scaleFactor;
16759    this.#innerMargin = innerMargin;
16760    this.#isLTR = isLTR;
16761    this.#computeMinMax(isLTR);
16762    const {
16763      x,
16764      y,
16765      width,
16766      height
16767    } = this.#bbox;
16768    for (let i = 0, ii = outline.length; i < ii; i += 2) {
16769      outline[i] = (outline[i] - x) / width;
16770      outline[i + 1] = (outline[i + 1] - y) / height;
16771    }
16772    for (let i = 0, ii = points.length; i < ii; i += 2) {
16773      points[i] = (points[i] - x) / width;
16774      points[i + 1] = (points[i + 1] - y) / height;
16775    }
16776  }
16777  toSVGPath() {
16778    const buffer = [`M${this.#outline[4]} ${this.#outline[5]}`];
16779    for (let i = 6, ii = this.#outline.length; i < ii; i += 6) {
16780      if (isNaN(this.#outline[i])) {
16781        buffer.push(`L${this.#outline[i + 4]} ${this.#outline[i + 5]}`);
16782        continue;
16783      }
16784      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]}`);
16785    }
16786    buffer.push("Z");
16787    return buffer.join(" ");
16788  }
16789  serialize([blX, blY, trX, trY], rotation) {
16790    const width = trX - blX;
16791    const height = trY - blY;
16792    let outline;
16793    let points;
16794    switch (rotation) {
16795      case 0:
16796        outline = this.#rescale(this.#outline, blX, trY, width, -height);
16797        points = this.#rescale(this.#points, blX, trY, width, -height);
16798        break;
16799      case 90:
16800        outline = this.#rescaleAndSwap(this.#outline, blX, blY, width, height);
16801        points = this.#rescaleAndSwap(this.#points, blX, blY, width, height);
16802        break;
16803      case 180:
16804        outline = this.#rescale(this.#outline, trX, blY, -width, height);
16805        points = this.#rescale(this.#points, trX, blY, -width, height);
16806        break;
16807      case 270:
16808        outline = this.#rescaleAndSwap(this.#outline, trX, trY, -width, -height);
16809        points = this.#rescaleAndSwap(this.#points, trX, trY, -width, -height);
16810        break;
16811    }
16812    return {
16813      outline: Array.from(outline),
16814      points: [Array.from(points)]
16815    };
16816  }
16817  #rescale(src, tx, ty, sx, sy) {
16818    const dest = new Float64Array(src.length);
16819    for (let i = 0, ii = src.length; i < ii; i += 2) {
16820      dest[i] = tx + src[i] * sx;
16821      dest[i + 1] = ty + src[i + 1] * sy;
16822    }
16823    return dest;
16824  }
16825  #rescaleAndSwap(src, tx, ty, sx, sy) {
16826    const dest = new Float64Array(src.length);
16827    for (let i = 0, ii = src.length; i < ii; i += 2) {
16828      dest[i] = tx + src[i + 1] * sx;
16829      dest[i + 1] = ty + src[i] * sy;
16830    }
16831    return dest;
16832  }
16833  #computeMinMax(isLTR) {
16834    const outline = this.#outline;
16835    let lastX = outline[4];
16836    let lastY = outline[5];
16837    let minX = lastX;
16838    let minY = lastY;
16839    let maxX = lastX;
16840    let maxY = lastY;
16841    let lastPointX = lastX;
16842    let lastPointY = lastY;
16843    const ltrCallback = isLTR ? Math.max : Math.min;
16844    for (let i = 6, ii = outline.length; i < ii; i += 6) {
16845      if (isNaN(outline[i])) {
16846        minX = Math.min(minX, outline[i + 4]);
16847        minY = Math.min(minY, outline[i + 5]);
16848        maxX = Math.max(maxX, outline[i + 4]);
16849        maxY = Math.max(maxY, outline[i + 5]);
16850        if (lastPointY < outline[i + 5]) {
16851          lastPointX = outline[i + 4];
16852          lastPointY = outline[i + 5];
16853        } else if (lastPointY === outline[i + 5]) {
16854          lastPointX = ltrCallback(lastPointX, outline[i + 4]);
16855        }
16856      } else {
16857        const bbox = Util.bezierBoundingBox(lastX, lastY, ...outline.slice(i, i + 6));
16858        minX = Math.min(minX, bbox[0]);
16859        minY = Math.min(minY, bbox[1]);
16860        maxX = Math.max(maxX, bbox[2]);
16861        maxY = Math.max(maxY, bbox[3]);
16862        if (lastPointY < bbox[3]) {
16863          lastPointX = bbox[2];
16864          lastPointY = bbox[3];
16865        } else if (lastPointY === bbox[3]) {
16866          lastPointX = ltrCallback(lastPointX, bbox[2]);
16867        }
16868      }
16869      lastX = outline[i + 4];
16870      lastY = outline[i + 5];
16871    }
16872    const x = minX - this.#innerMargin,
16873      y = minY - this.#innerMargin,
16874      width = maxX - minX + 2 * this.#innerMargin,
16875      height = maxY - minY + 2 * this.#innerMargin;
16876    this.#bbox = {
16877      x,
16878      y,
16879      width,
16880      height,
16881      lastPoint: [lastPointX, lastPointY]
16882    };
16883  }
16884  get box() {
16885    return this.#bbox;
16886  }
16887  newOutliner(point, box, scaleFactor, thickness, isLTR, innerMargin = 0) {
16888    return new FreeDrawOutliner(point, box, scaleFactor, thickness, isLTR, innerMargin);
16889  }
16890  getNewOutline(thickness, innerMargin) {
16891    const {
16892      x,
16893      y,
16894      width,
16895      height
16896    } = this.#bbox;
16897    const [layerX, layerY, layerWidth, layerHeight] = this.#box;
16898    const sx = width * layerWidth;
16899    const sy = height * layerHeight;
16900    const tx = x * layerWidth + layerX;
16901    const ty = y * layerHeight + layerY;
16902    const outliner = this.newOutliner({
16903      x: this.#points[0] * sx + tx,
16904      y: this.#points[1] * sy + ty
16905    }, this.#box, this.#scaleFactor, thickness, this.#isLTR, innerMargin ?? this.#innerMargin);
16906    for (let i = 2; i < this.#points.length; i += 2) {
16907      outliner.add({
16908        x: this.#points[i] * sx + tx,
16909        y: this.#points[i + 1] * sy + ty
16910      });
16911    }
16912    return outliner.getOutlines();
16913  }
16914  get mustRemoveSelfIntersections() {
16915    return true;
16916  }
16917}
16918
16919;// ./src/display/editor/drawers/highlight.js
16920
16921
16922class HighlightOutliner {
16923  #box;
16924  #verticalEdges = [];
16925  #intervals = [];
16926  constructor(boxes, borderWidth = 0, innerMargin = 0, isLTR = true) {
16927    let minX = Infinity;
16928    let maxX = -Infinity;
16929    let minY = Infinity;
16930    let maxY = -Infinity;
16931    const NUMBER_OF_DIGITS = 4;
16932    const EPSILON = 10 ** -NUMBER_OF_DIGITS;
16933    for (const {
16934      x,
16935      y,
16936      width,
16937      height
16938    } of boxes) {
16939      const x1 = Math.floor((x - borderWidth) / EPSILON) * EPSILON;
16940      const x2 = Math.ceil((x + width + borderWidth) / EPSILON) * EPSILON;
16941      const y1 = Math.floor((y - borderWidth) / EPSILON) * EPSILON;
16942      const y2 = Math.ceil((y + height + borderWidth) / EPSILON) * EPSILON;
16943      const left = [x1, y1, y2, true];
16944      const right = [x2, y1, y2, false];
16945      this.#verticalEdges.push(left, right);
16946      minX = Math.min(minX, x1);
16947      maxX = Math.max(maxX, x2);
16948      minY = Math.min(minY, y1);
16949      maxY = Math.max(maxY, y2);
16950    }
16951    const bboxWidth = maxX - minX + 2 * innerMargin;
16952    const bboxHeight = maxY - minY + 2 * innerMargin;
16953    const shiftedMinX = minX - innerMargin;
16954    const shiftedMinY = minY - innerMargin;
16955    const lastEdge = this.#verticalEdges.at(isLTR ? -1 : -2);
16956    const lastPoint = [lastEdge[0], lastEdge[2]];
16957    for (const edge of this.#verticalEdges) {
16958      const [x, y1, y2] = edge;
16959      edge[0] = (x - shiftedMinX) / bboxWidth;
16960      edge[1] = (y1 - shiftedMinY) / bboxHeight;
16961      edge[2] = (y2 - shiftedMinY) / bboxHeight;
16962    }
16963    this.#box = {
16964      x: shiftedMinX,
16965      y: shiftedMinY,
16966      width: bboxWidth,
16967      height: bboxHeight,
16968      lastPoint
16969    };
16970  }
16971  getOutlines() {
16972    this.#verticalEdges.sort((a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2]);
16973    const outlineVerticalEdges = [];
16974    for (const edge of this.#verticalEdges) {
16975      if (edge[3]) {
16976        outlineVerticalEdges.push(...this.#breakEdge(edge));
16977        this.#insert(edge);
16978      } else {
16979        this.#remove(edge);
16980        outlineVerticalEdges.push(...this.#breakEdge(edge));
16981      }
16982    }
16983    return this.#getOutlines(outlineVerticalEdges);
16984  }
16985  #getOutlines(outlineVerticalEdges) {
16986    const edges = [];
16987    const allEdges = new Set();
16988    for (const edge of outlineVerticalEdges) {
16989      const [x, y1, y2] = edge;
16990      edges.push([x, y1, edge], [x, y2, edge]);
16991    }
16992    edges.sort((a, b) => a[1] - b[1] || a[0] - b[0]);
16993    for (let i = 0, ii = edges.length; i < ii; i += 2) {
16994      const edge1 = edges[i][2];
16995      const edge2 = edges[i + 1][2];
16996      edge1.push(edge2);
16997      edge2.push(edge1);
16998      allEdges.add(edge1);
16999      allEdges.add(edge2);
17000    }
17001    const outlines = [];
17002    let outline;
17003    while (allEdges.size > 0) {
17004      const edge = allEdges.values().next().value;
17005      let [x, y1, y2, edge1, edge2] = edge;
17006      allEdges.delete(edge);
17007      let lastPointX = x;
17008      let lastPointY = y1;
17009      outline = [x, y2];
17010      outlines.push(outline);
17011      while (true) {
17012        let e;
17013        if (allEdges.has(edge1)) {
17014          e = edge1;
17015        } else if (allEdges.has(edge2)) {
17016          e = edge2;
17017        } else {
17018          break;
17019        }
17020        allEdges.delete(e);
17021        [x, y1, y2, edge1, edge2] = e;
17022        if (lastPointX !== x) {
17023          outline.push(lastPointX, lastPointY, x, lastPointY === y1 ? y1 : y2);
17024          lastPointX = x;
17025        }
17026        lastPointY = lastPointY === y1 ? y2 : y1;
17027      }
17028      outline.push(lastPointX, lastPointY);
17029    }
17030    return new HighlightOutline(outlines, this.#box);
17031  }
17032  #binarySearch(y) {
17033    const array = this.#intervals;
17034    let start = 0;
17035    let end = array.length - 1;
17036    while (start <= end) {
17037      const middle = start + end >> 1;
17038      const y1 = array[middle][0];
17039      if (y1 === y) {
17040        return middle;
17041      }
17042      if (y1 < y) {
17043        start = middle + 1;
17044      } else {
17045        end = middle - 1;
17046      }
17047    }
17048    return end + 1;
17049  }
17050  #insert([, y1, y2]) {
17051    const index = this.#binarySearch(y1);
17052    this.#intervals.splice(index, 0, [y1, y2]);
17053  }
17054  #remove([, y1, y2]) {
17055    const index = this.#binarySearch(y1);
17056    for (let i = index; i < this.#intervals.length; i++) {
17057      const [start, end] = this.#intervals[i];
17058      if (start !== y1) {
17059        break;
17060      }
17061      if (start === y1 && end === y2) {
17062        this.#intervals.splice(i, 1);
17063        return;
17064      }
17065    }
17066    for (let i = index - 1; i >= 0; i--) {
17067      const [start, end] = this.#intervals[i];
17068      if (start !== y1) {
17069        break;
17070      }
17071      if (start === y1 && end === y2) {
17072        this.#intervals.splice(i, 1);
17073        return;
17074      }
17075    }
17076  }
17077  #breakEdge(edge) {
17078    const [x, y1, y2] = edge;
17079    const results = [[x, y1, y2]];
17080    const index = this.#binarySearch(y2);
17081    for (let i = 0; i < index; i++) {
17082      const [start, end] = this.#intervals[i];
17083      for (let j = 0, jj = results.length; j < jj; j++) {
17084        const [, y3, y4] = results[j];
17085        if (end <= y3 || y4 <= start) {
17086          continue;
17087        }
17088        if (y3 >= start) {
17089          if (y4 > end) {
17090            results[j][1] = end;
17091          } else {
17092            if (jj === 1) {
17093              return [];
17094            }
17095            results.splice(j, 1);
17096            j--;
17097            jj--;
17098          }
17099          continue;
17100        }
17101        results[j][2] = start;
17102        if (y4 > end) {
17103          results.push([x, end, y4]);
17104        }
17105      }
17106    }
17107    return results;
17108  }
17109}
17110class HighlightOutline extends Outline {
17111  #box;
17112  #outlines;
17113  constructor(outlines, box) {
17114    super();
17115    this.#outlines = outlines;
17116    this.#box = box;
17117  }
17118  toSVGPath() {
17119    const buffer = [];
17120    for (const polygon of this.#outlines) {
17121      let [prevX, prevY] = polygon;
17122      buffer.push(`M${prevX} ${prevY}`);
17123      for (let i = 2; i < polygon.length; i += 2) {
17124        const x = polygon[i];
17125        const y = polygon[i + 1];
17126        if (x === prevX) {
17127          buffer.push(`V${y}`);
17128          prevY = y;
17129        } else if (y === prevY) {
17130          buffer.push(`H${x}`);
17131          prevX = x;
17132        }
17133      }
17134      buffer.push("Z");
17135    }
17136    return buffer.join(" ");
17137  }
17138  serialize([blX, blY, trX, trY], _rotation) {
17139    const outlines = [];
17140    const width = trX - blX;
17141    const height = trY - blY;
17142    for (const outline of this.#outlines) {
17143      const points = new Array(outline.length);
17144      for (let i = 0; i < outline.length; i += 2) {
17145        points[i] = blX + outline[i] * width;
17146        points[i + 1] = trY - outline[i + 1] * height;
17147      }
17148      outlines.push(points);
17149    }
17150    return outlines;
17151  }
17152  get box() {
17153    return this.#box;
17154  }
17155  get classNamesForDrawing() {
17156    return ["highlight"];
17157  }
17158  get classNamesForOutlining() {
17159    return ["highlightOutline"];
17160  }
17161}
17162class FreeHighlightOutliner extends FreeDrawOutliner {
17163  newFreeDrawOutline(outline, points, box, scaleFactor, innerMargin, isLTR) {
17164    return new FreeHighlightOutline(outline, points, box, scaleFactor, innerMargin, isLTR);
17165  }
17166  get classNamesForDrawing() {
17167    return ["highlight", "free"];
17168  }
17169}
17170class FreeHighlightOutline extends FreeDrawOutline {
17171  get classNamesForDrawing() {
17172    return ["highlight", "free"];
17173  }
17174  get classNamesForOutlining() {
17175    return ["highlightOutline", "free"];
17176  }
17177  newOutliner(point, box, scaleFactor, thickness, isLTR, innerMargin = 0) {
17178    return new FreeHighlightOutliner(point, box, scaleFactor, thickness, isLTR, innerMargin);
17179  }
17180}
17181
17182;// ./src/display/editor/color_picker.js
17183
17184
17185
17186class ColorPicker {
17187  #button = null;
17188  #buttonSwatch = null;
17189  #defaultColor;
17190  #dropdown = null;
17191  #dropdownWasFromKeyboard = false;
17192  #isMainColorPicker = false;
17193  #editor = null;
17194  #eventBus;
17195  #openDropdownAC = null;
17196  #uiManager = null;
17197  #type;
17198  static #l10nColor = null;
17199  static get _keyboardManager() {
17200    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]]));
17201  }
17202  constructor({
17203    editor = null,
17204    uiManager = null
17205  }) {
17206    if (editor) {
17207      this.#isMainColorPicker = false;
17208      this.#type = AnnotationEditorParamsType.HIGHLIGHT_COLOR;
17209      this.#editor = editor;
17210    } else {
17211      this.#isMainColorPicker = true;
17212      this.#type = AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR;
17213    }
17214    this.#uiManager = editor?._uiManager || uiManager;
17215    this.#eventBus = this.#uiManager._eventBus;
17216    this.#defaultColor = editor?.color || this.#uiManager?.highlightColors.values().next().value || "#FFFF98";
17217    ColorPicker.#l10nColor ||= Object.freeze({
17218      blue: "pdfjs-editor-colorpicker-blue",
17219      green: "pdfjs-editor-colorpicker-green",
17220      pink: "pdfjs-editor-colorpicker-pink",
17221      red: "pdfjs-editor-colorpicker-red",
17222      yellow: "pdfjs-editor-colorpicker-yellow"
17223    });
17224  }
17225  renderButton() {
17226    const button = this.#button = document.createElement("button");
17227    button.className = "colorPicker";
17228    button.tabIndex = "0";
17229    button.setAttribute("data-l10n-id", "pdfjs-editor-colorpicker-button");
17230    button.setAttribute("aria-haspopup", true);
17231    const signal = this.#uiManager._signal;
17232    button.addEventListener("click", this.#openDropdown.bind(this), {
17233      signal
17234    });
17235    button.addEventListener("keydown", this.#keyDown.bind(this), {
17236      signal
17237    });
17238    const swatch = this.#buttonSwatch = document.createElement("span");
17239    swatch.className = "swatch";
17240    swatch.setAttribute("aria-hidden", true);
17241    swatch.style.backgroundColor = this.#defaultColor;
17242    button.append(swatch);
17243    return button;
17244  }
17245  renderMainDropdown() {
17246    const dropdown = this.#dropdown = this.#getDropdownRoot();
17247    dropdown.setAttribute("aria-orientation", "horizontal");
17248    dropdown.setAttribute("aria-labelledby", "highlightColorPickerLabel");
17249    return dropdown;
17250  }
17251  #getDropdownRoot() {
17252    const div = document.createElement("div");
17253    const signal = this.#uiManager._signal;
17254    div.addEventListener("contextmenu", noContextMenu, {
17255      signal
17256    });
17257    div.className = "dropdown";
17258    div.role = "listbox";
17259    div.setAttribute("aria-multiselectable", false);
17260    div.setAttribute("aria-orientation", "vertical");
17261    div.setAttribute("data-l10n-id", "pdfjs-editor-colorpicker-dropdown");
17262    for (const [name, color] of this.#uiManager.highlightColors) {
17263      const button = document.createElement("button");
17264      button.tabIndex = "0";
17265      button.role = "option";
17266      button.setAttribute("data-color", color);
17267      button.title = name;
17268      button.setAttribute("data-l10n-id", ColorPicker.#l10nColor[name]);
17269      const swatch = document.createElement("span");
17270      button.append(swatch);
17271      swatch.className = "swatch";
17272      swatch.style.backgroundColor = color;
17273      button.setAttribute("aria-selected", color === this.#defaultColor);
17274      button.addEventListener("click", this.#colorSelect.bind(this, color), {
17275        signal
17276      });
17277      div.append(button);
17278    }
17279    div.addEventListener("keydown", this.#keyDown.bind(this), {
17280      signal
17281    });
17282    return div;
17283  }
17284  #colorSelect(color, event) {
17285    event.stopPropagation();
17286    this.#eventBus.dispatch("switchannotationeditorparams", {
17287      source: this,
17288      type: this.#type,
17289      value: color
17290    });
17291  }
17292  _colorSelectFromKeyboard(event) {
17293    if (event.target === this.#button) {
17294      this.#openDropdown(event);
17295      return;
17296    }
17297    const color = event.target.getAttribute("data-color");
17298    if (!color) {
17299      return;
17300    }
17301    this.#colorSelect(color, event);
17302  }
17303  _moveToNext(event) {
17304    if (!this.#isDropdownVisible) {
17305      this.#openDropdown(event);
17306      return;
17307    }
17308    if (event.target === this.#button) {
17309      this.#dropdown.firstChild?.focus();
17310      return;
17311    }
17312    event.target.nextSibling?.focus();
17313  }
17314  _moveToPrevious(event) {
17315    if (event.target === this.#dropdown?.firstChild || event.target === this.#button) {
17316      if (this.#isDropdownVisible) {
17317        this._hideDropdownFromKeyboard();
17318      }
17319      return;
17320    }
17321    if (!this.#isDropdownVisible) {
17322      this.#openDropdown(event);
17323    }
17324    event.target.previousSibling?.focus();
17325  }
17326  _moveToBeginning(event) {
17327    if (!this.#isDropdownVisible) {
17328      this.#openDropdown(event);
17329      return;
17330    }
17331    this.#dropdown.firstChild?.focus();
17332  }
17333  _moveToEnd(event) {
17334    if (!this.#isDropdownVisible) {
17335      this.#openDropdown(event);
17336      return;
17337    }
17338    this.#dropdown.lastChild?.focus();
17339  }
17340  #keyDown(event) {
17341    ColorPicker._keyboardManager.exec(this, event);
17342  }
17343  #openDropdown(event) {
17344    if (this.#isDropdownVisible) {
17345      this.hideDropdown();
17346      return;
17347    }
17348    this.#dropdownWasFromKeyboard = event.detail === 0;
17349    if (!this.#openDropdownAC) {
17350      this.#openDropdownAC = new AbortController();
17351      window.addEventListener("pointerdown", this.#pointerDown.bind(this), {
17352        signal: this.#uiManager.combinedSignal(this.#openDropdownAC)
17353      });
17354    }
17355    if (this.#dropdown) {
17356      this.#dropdown.classList.remove("hidden");
17357      return;
17358    }
17359    const root = this.#dropdown = this.#getDropdownRoot();
17360    this.#button.append(root);
17361  }
17362  #pointerDown(event) {
17363    if (this.#dropdown?.contains(event.target)) {
17364      return;
17365    }
17366    this.hideDropdown();
17367  }
17368  hideDropdown() {
17369    this.#dropdown?.classList.add("hidden");
17370    this.#openDropdownAC?.abort();
17371    this.#openDropdownAC = null;
17372  }
17373  get #isDropdownVisible() {
17374    return this.#dropdown && !this.#dropdown.classList.contains("hidden");
17375  }
17376  _hideDropdownFromKeyboard() {
17377    if (this.#isMainColorPicker) {
17378      return;
17379    }
17380    if (!this.#isDropdownVisible) {
17381      this.#editor?.unselect();
17382      return;
17383    }
17384    this.hideDropdown();
17385    this.#button.focus({
17386      preventScroll: true,
17387      focusVisible: this.#dropdownWasFromKeyboard
17388    });
17389  }
17390  updateColor(color) {
17391    if (this.#buttonSwatch) {
17392      this.#buttonSwatch.style.backgroundColor = color;
17393    }
17394    if (!this.#dropdown) {
17395      return;
17396    }
17397    const i = this.#uiManager.highlightColors.values();
17398    for (const child of this.#dropdown.children) {
17399      child.setAttribute("aria-selected", i.next().value === color);
17400    }
17401  }
17402  destroy() {
17403    this.#button?.remove();
17404    this.#button = null;
17405    this.#buttonSwatch = null;
17406    this.#dropdown?.remove();
17407    this.#dropdown = null;
17408  }
17409}
17410
17411;// ./src/display/editor/highlight.js
17412
17413
17414
17415
17416
17417
17418
17419class HighlightEditor extends AnnotationEditor {
17420  #anchorNode = null;
17421  #anchorOffset = 0;
17422  #boxes;
17423  #clipPathId = null;
17424  #colorPicker = null;
17425  #focusOutlines = null;
17426  #focusNode = null;
17427  #focusOffset = 0;
17428  #highlightDiv = null;
17429  #highlightOutlines = null;
17430  #id = null;
17431  #isFreeHighlight = false;
17432  #lastPoint = null;
17433  #opacity;
17434  #outlineId = null;
17435  #text = "";
17436  #thickness;
17437  #methodOfCreation = "";
17438  static _defaultColor = null;
17439  static _defaultOpacity = 1;
17440  static _defaultThickness = 12;
17441  static _type = "highlight";
17442  static _editorType = AnnotationEditorType.HIGHLIGHT;
17443  static _freeHighlightId = -1;
17444  static _freeHighlight = null;
17445  static _freeHighlightClipId = "";
17446  static get _keyboardManager() {
17447    const proto = HighlightEditor.prototype;
17448    return shadow(this, "_keyboardManager", new KeyboardManager([[["ArrowLeft", "mac+ArrowLeft"], proto._moveCaret, {
17449      args: [0]
17450    }], [["ArrowRight", "mac+ArrowRight"], proto._moveCaret, {
17451      args: [1]
17452    }], [["ArrowUp", "mac+ArrowUp"], proto._moveCaret, {
17453      args: [2]
17454    }], [["ArrowDown", "mac+ArrowDown"], proto._moveCaret, {
17455      args: [3]
17456    }]]));
17457  }
17458  constructor(params) {
17459    super({
17460      ...params,
17461      name: "highlightEditor"
17462    });
17463    this.color = params.color || HighlightEditor._defaultColor;
17464    this.#thickness = params.thickness || HighlightEditor._defaultThickness;
17465    this.#opacity = params.opacity || HighlightEditor._defaultOpacity;
17466    this.#boxes = params.boxes || null;
17467    this.#methodOfCreation = params.methodOfCreation || "";
17468    this.#text = params.text || "";
17469    this._isDraggable = false;
17470    if (params.highlightId > -1) {
17471      this.#isFreeHighlight = true;
17472      this.#createFreeOutlines(params);
17473      this.#addToDrawLayer();
17474    } else if (this.#boxes) {
17475      this.#anchorNode = params.anchorNode;
17476      this.#anchorOffset = params.anchorOffset;
17477      this.#focusNode = params.focusNode;
17478      this.#focusOffset = params.focusOffset;
17479      this.#createOutlines();
17480      this.#addToDrawLayer();
17481      this.rotate(this.rotation);
17482    }
17483  }
17484  get telemetryInitialData() {
17485    return {
17486      action: "added",
17487      type: this.#isFreeHighlight ? "free_highlight" : "highlight",
17488      color: this._uiManager.highlightColorNames.get(this.color),
17489      thickness: this.#thickness,
17490      methodOfCreation: this.#methodOfCreation
17491    };
17492  }
17493  get telemetryFinalData() {
17494    return {
17495      type: "highlight",
17496      color: this._uiManager.highlightColorNames.get(this.color)
17497    };
17498  }
17499  static computeTelemetryFinalData(data) {
17500    return {
17501      numberOfColors: data.get("color").size
17502    };
17503  }
17504  #createOutlines() {
17505    const outliner = new HighlightOutliner(this.#boxes, 0.001);
17506    this.#highlightOutlines = outliner.getOutlines();
17507    ({
17508      x: this.x,
17509      y: this.y,
17510      width: this.width,
17511      height: this.height
17512    } = this.#highlightOutlines.box);
17513    const outlinerForOutline = new HighlightOutliner(this.#boxes, 0.0025, 0.001, this._uiManager.direction === "ltr");
17514    this.#focusOutlines = outlinerForOutline.getOutlines();
17515    const {
17516      lastPoint
17517    } = this.#focusOutlines.box;
17518    this.#lastPoint = [(lastPoint[0] - this.x) / this.width, (lastPoint[1] - this.y) / this.height];
17519  }
17520  #createFreeOutlines({
17521    highlightOutlines,
17522    highlightId,
17523    clipPathId
17524  }) {
17525    this.#highlightOutlines = highlightOutlines;
17526    const extraThickness = 1.5;
17527    this.#focusOutlines = highlightOutlines.getNewOutline(this.#thickness / 2 + extraThickness, 0.0025);
17528    if (highlightId >= 0) {
17529      this.#id = highlightId;
17530      this.#clipPathId = clipPathId;
17531      this.parent.drawLayer.finalizeLine(highlightId, highlightOutlines);
17532      this.#outlineId = this.parent.drawLayer.drawOutline(this.#focusOutlines);
17533    } else if (this.parent) {
17534      const angle = this.parent.viewport.rotation;
17535      this.parent.drawLayer.updateLine(this.#id, highlightOutlines);
17536      this.parent.drawLayer.updateBox(this.#id, HighlightEditor.#rotateBbox(this.#highlightOutlines.box, (angle - this.rotation + 360) % 360));
17537      this.parent.drawLayer.updateLine(this.#outlineId, this.#focusOutlines);
17538      this.parent.drawLayer.updateBox(this.#outlineId, HighlightEditor.#rotateBbox(this.#focusOutlines.box, angle));
17539    }
17540    const {
17541      x,
17542      y,
17543      width,
17544      height
17545    } = highlightOutlines.box;
17546    switch (this.rotation) {
17547      case 0:
17548        this.x = x;
17549        this.y = y;
17550        this.width = width;
17551        this.height = height;
17552        break;
17553      case 90:
17554        {
17555          const [pageWidth, pageHeight] = this.parentDimensions;
17556          this.x = y;
17557          this.y = 1 - x;
17558          this.width = width * pageHeight / pageWidth;
17559          this.height = height * pageWidth / pageHeight;
17560          break;
17561        }
17562      case 180:
17563        this.x = 1 - x;
17564        this.y = 1 - y;
17565        this.width = width;
17566        this.height = height;
17567        break;
17568      case 270:
17569        {
17570          const [pageWidth, pageHeight] = this.parentDimensions;
17571          this.x = 1 - y;
17572          this.y = x;
17573          this.width = width * pageHeight / pageWidth;
17574          this.height = height * pageWidth / pageHeight;
17575          break;
17576        }
17577    }
17578    const {
17579      lastPoint
17580    } = this.#focusOutlines.box;
17581    this.#lastPoint = [(lastPoint[0] - x) / width, (lastPoint[1] - y) / height];
17582  }
17583  static initialize(l10n, uiManager) {
17584    AnnotationEditor.initialize(l10n, uiManager);
17585    HighlightEditor._defaultColor ||= uiManager.highlightColors?.values().next().value || "#fff066";
17586  }
17587  static updateDefaultParams(type, value) {
17588    switch (type) {
17589      case AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR:
17590        HighlightEditor._defaultColor = value;
17591        break;
17592      case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS:
17593        HighlightEditor._defaultThickness = value;
17594        break;
17595    }
17596  }
17597  translateInPage(x, y) {}
17598  get toolbarPosition() {
17599    return this.#lastPoint;
17600  }
17601  updateParams(type, value) {
17602    switch (type) {
17603      case AnnotationEditorParamsType.HIGHLIGHT_COLOR:
17604        this.#updateColor(value);
17605        break;
17606      case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS:
17607        this.#updateThickness(value);
17608        break;
17609    }
17610  }
17611  static get defaultPropertiesToUpdate() {
17612    return [[AnnotationEditorParamsType.HIGHLIGHT_DEFAULT_COLOR, HighlightEditor._defaultColor], [AnnotationEditorParamsType.HIGHLIGHT_THICKNESS, HighlightEditor._defaultThickness]];
17613  }
17614  get propertiesToUpdate() {
17615    return [[AnnotationEditorParamsType.HIGHLIGHT_COLOR, this.color || HighlightEditor._defaultColor], [AnnotationEditorParamsType.HIGHLIGHT_THICKNESS, this.#thickness || HighlightEditor._defaultThickness], [AnnotationEditorParamsType.HIGHLIGHT_FREE, this.#isFreeHighlight]];
17616  }
17617  #updateColor(color) {
17618    const setColorAndOpacity = (col, opa) => {
17619      this.color = col;
17620      this.parent?.drawLayer.changeColor(this.#id, col);
17621      this.#colorPicker?.updateColor(col);
17622      this.#opacity = opa;
17623      this.parent?.drawLayer.changeOpacity(this.#id, opa);
17624    };
17625    const savedColor = this.color;
17626    const savedOpacity = this.#opacity;
17627    this.addCommands({
17628      cmd: setColorAndOpacity.bind(this, color, HighlightEditor._defaultOpacity),
17629      undo: setColorAndOpacity.bind(this, savedColor, savedOpacity),
17630      post: this._uiManager.updateUI.bind(this._uiManager, this),
17631      mustExec: true,
17632      type: AnnotationEditorParamsType.HIGHLIGHT_COLOR,
17633      overwriteIfSameType: true,
17634      keepUndo: true
17635    });
17636    this._reportTelemetry({
17637      action: "color_changed",
17638      color: this._uiManager.highlightColorNames.get(color)
17639    }, true);
17640  }
17641  #updateThickness(thickness) {
17642    const savedThickness = this.#thickness;
17643    const setThickness = th => {
17644      this.#thickness = th;
17645      this.#changeThickness(th);
17646    };
17647    this.addCommands({
17648      cmd: setThickness.bind(this, thickness),
17649      undo: setThickness.bind(this, savedThickness),
17650      post: this._uiManager.updateUI.bind(this._uiManager, this),
17651      mustExec: true,
17652      type: AnnotationEditorParamsType.INK_THICKNESS,
17653      overwriteIfSameType: true,
17654      keepUndo: true
17655    });
17656    this._reportTelemetry({
17657      action: "thickness_changed",
17658      thickness
17659    }, true);
17660  }
17661  async addEditToolbar() {
17662    const toolbar = await super.addEditToolbar();
17663    if (!toolbar) {
17664      return null;
17665    }
17666    if (this._uiManager.highlightColors) {
17667      this.#colorPicker = new ColorPicker({
17668        editor: this
17669      });
17670      toolbar.addColorPicker(this.#colorPicker);
17671    }
17672    return toolbar;
17673  }
17674  disableEditing() {
17675    super.disableEditing();
17676    this.div.classList.toggle("disabled", true);
17677  }
17678  enableEditing() {
17679    super.enableEditing();
17680    this.div.classList.toggle("disabled", false);
17681  }
17682  fixAndSetPosition() {
17683    return super.fixAndSetPosition(this.#getRotation());
17684  }
17685  getBaseTranslation() {
17686    return [0, 0];
17687  }
17688  getRect(tx, ty) {
17689    return super.getRect(tx, ty, this.#getRotation());
17690  }
17691  onceAdded() {
17692    if (!this.annotationElementId) {
17693      this.parent.addUndoableEditor(this);
17694    }
17695    this.div.focus();
17696  }
17697  remove() {
17698    this.#cleanDrawLayer();
17699    this._reportTelemetry({
17700      action: "deleted"
17701    });
17702    super.remove();
17703  }
17704  rebuild() {
17705    if (!this.parent) {
17706      return;
17707    }
17708    super.rebuild();
17709    if (this.div === null) {
17710      return;
17711    }
17712    this.#addToDrawLayer();
17713    if (!this.isAttachedToDOM) {
17714      this.parent.add(this);
17715    }
17716  }
17717  setParent(parent) {
17718    let mustBeSelected = false;
17719    if (this.parent && !parent) {
17720      this.#cleanDrawLayer();
17721    } else if (parent) {
17722      this.#addToDrawLayer(parent);
17723      mustBeSelected = !this.parent && this.div?.classList.contains("selectedEditor");
17724    }
17725    super.setParent(parent);
17726    this.show(this._isVisible);
17727    if (mustBeSelected) {
17728      this.select();
17729    }
17730  }
17731  #changeThickness(thickness) {
17732    if (!this.#isFreeHighlight) {
17733      return;
17734    }
17735    this.#createFreeOutlines({
17736      highlightOutlines: this.#highlightOutlines.getNewOutline(thickness / 2)
17737    });
17738    this.fixAndSetPosition();
17739    const [parentWidth, parentHeight] = this.parentDimensions;
17740    this.setDims(this.width * parentWidth, this.height * parentHeight);
17741  }
17742  #cleanDrawLayer() {
17743    if (this.#id === null || !this.parent) {
17744      return;
17745    }
17746    this.parent.drawLayer.remove(this.#id);
17747    this.#id = null;
17748    this.parent.drawLayer.remove(this.#outlineId);
17749    this.#outlineId = null;
17750  }
17751  #addToDrawLayer(parent = this.parent) {
17752    if (this.#id !== null) {
17753      return;
17754    }
17755    ({
17756      id: this.#id,
17757      clipPathId: this.#clipPathId
17758    } = parent.drawLayer.draw(this.#highlightOutlines, this.color, this.#opacity));
17759    this.#outlineId = parent.drawLayer.drawOutline(this.#focusOutlines);
17760    if (this.#highlightDiv) {
17761      this.#highlightDiv.style.clipPath = this.#clipPathId;
17762    }
17763  }
17764  static #rotateBbox({
17765    x,
17766    y,
17767    width,
17768    height
17769  }, angle) {
17770    switch (angle) {
17771      case 90:
17772        return {
17773          x: 1 - y - height,
17774          y: x,
17775          width: height,
17776          height: width
17777        };
17778      case 180:
17779        return {
17780          x: 1 - x - width,
17781          y: 1 - y - height,
17782          width,
17783          height
17784        };
17785      case 270:
17786        return {
17787          x: y,
17788          y: 1 - x - width,
17789          width: height,
17790          height: width
17791        };
17792    }
17793    return {
17794      x,
17795      y,
17796      width,
17797      height
17798    };
17799  }
17800  rotate(angle) {
17801    const {
17802      drawLayer
17803    } = this.parent;
17804    let box;
17805    if (this.#isFreeHighlight) {
17806      angle = (angle - this.rotation + 360) % 360;
17807      box = HighlightEditor.#rotateBbox(this.#highlightOutlines.box, angle);
17808    } else {
17809      box = HighlightEditor.#rotateBbox(this, angle);
17810    }
17811    drawLayer.rotate(this.#id, angle);
17812    drawLayer.rotate(this.#outlineId, angle);
17813    drawLayer.updateBox(this.#id, box);
17814    drawLayer.updateBox(this.#outlineId, HighlightEditor.#rotateBbox(this.#focusOutlines.box, angle));
17815  }
17816  render() {
17817    if (this.div) {
17818      return this.div;
17819    }
17820    const div = super.render();
17821    if (this.#text) {
17822      div.setAttribute("aria-label", this.#text);
17823      div.setAttribute("role", "mark");
17824    }
17825    if (this.#isFreeHighlight) {
17826      div.classList.add("free");
17827    } else {
17828      this.div.addEventListener("keydown", this.#keydown.bind(this), {
17829        signal: this._uiManager._signal
17830      });
17831    }
17832    const highlightDiv = this.#highlightDiv = document.createElement("div");
17833    div.append(highlightDiv);
17834    highlightDiv.setAttribute("aria-hidden", "true");
17835    highlightDiv.className = "internal";
17836    highlightDiv.style.clipPath = this.#clipPathId;
17837    const [parentWidth, parentHeight] = this.parentDimensions;
17838    this.setDims(this.width * parentWidth, this.height * parentHeight);
17839    bindEvents(this, this.#highlightDiv, ["pointerover", "pointerleave"]);
17840    this.enableEditing();
17841    return div;
17842  }
17843  pointerover() {
17844    if (!this.isSelected) {
17845      this.parent.drawLayer.addClass(this.#outlineId, "hovered");
17846    }
17847  }
17848  pointerleave() {
17849    if (!this.isSelected) {
17850      this.parent.drawLayer.removeClass(this.#outlineId, "hovered");
17851    }
17852  }
17853  #keydown(event) {
17854    HighlightEditor._keyboardManager.exec(this, event);
17855  }
17856  _moveCaret(direction) {
17857    this.parent.unselect(this);
17858    switch (direction) {
17859      case 0:
17860      case 2:
17861        this.#setCaret(true);
17862        break;
17863      case 1:
17864      case 3:
17865        this.#setCaret(false);
17866        break;
17867    }
17868  }
17869  #setCaret(start) {
17870    if (!this.#anchorNode) {
17871      return;
17872    }
17873    const selection = window.getSelection();
17874    if (start) {
17875      selection.setPosition(this.#anchorNode, this.#anchorOffset);
17876    } else {
17877      selection.setPosition(this.#focusNode, this.#focusOffset);
17878    }
17879  }
17880  select() {
17881    super.select();
17882    if (!this.#outlineId) {
17883      return;
17884    }
17885    this.parent?.drawLayer.removeClass(this.#outlineId, "hovered");
17886    this.parent?.drawLayer.addClass(this.#outlineId, "selected");
17887  }
17888  unselect() {
17889    super.unselect();
17890    if (!this.#outlineId) {
17891      return;
17892    }
17893    this.parent?.drawLayer.removeClass(this.#outlineId, "selected");
17894    if (!this.#isFreeHighlight) {
17895      this.#setCaret(false);
17896    }
17897  }
17898  get _mustFixPosition() {
17899    return !this.#isFreeHighlight;
17900  }
17901  show(visible = this._isVisible) {
17902    super.show(visible);
17903    if (this.parent) {
17904      this.parent.drawLayer.show(this.#id, visible);
17905      this.parent.drawLayer.show(this.#outlineId, visible);
17906    }
17907  }
17908  #getRotation() {
17909    return this.#isFreeHighlight ? this.rotation : 0;
17910  }
17911  #serializeBoxes() {
17912    if (this.#isFreeHighlight) {
17913      return null;
17914    }
17915    const [pageWidth, pageHeight] = this.pageDimensions;
17916    const [pageX, pageY] = this.pageTranslation;
17917    const boxes = this.#boxes;
17918    const quadPoints = new Float32Array(boxes.length * 8);
17919    let i = 0;
17920    for (const {
17921      x,
17922      y,
17923      width,
17924      height
17925    } of boxes) {
17926      const sx = x * pageWidth + pageX;
17927      const sy = (1 - y - height) * pageHeight + pageY;
17928      quadPoints[i] = quadPoints[i + 4] = sx;
17929      quadPoints[i + 1] = quadPoints[i + 3] = sy;
17930      quadPoints[i + 2] = quadPoints[i + 6] = sx + width * pageWidth;
17931      quadPoints[i + 5] = quadPoints[i + 7] = sy + height * pageHeight;
17932      i += 8;
17933    }
17934    return quadPoints;
17935  }
17936  #serializeOutlines(rect) {
17937    return this.#highlightOutlines.serialize(rect, this.#getRotation());
17938  }
17939  static startHighlighting(parent, isLTR, {
17940    target: textLayer,
17941    x,
17942    y
17943  }) {
17944    const {
17945      x: layerX,
17946      y: layerY,
17947      width: parentWidth,
17948      height: parentHeight
17949    } = textLayer.getBoundingClientRect();
17950    const ac = new AbortController();
17951    const signal = parent.combinedSignal(ac);
17952    const pointerDown = e => {
17953      e.preventDefault();
17954      e.stopPropagation();
17955    };
17956    const pointerUpCallback = e => {
17957      ac.abort();
17958      this.#endHighlight(parent, e);
17959    };
17960    window.addEventListener("blur", pointerUpCallback, {
17961      signal
17962    });
17963    window.addEventListener("pointerup", pointerUpCallback, {
17964      signal
17965    });
17966    window.addEventListener("pointerdown", pointerDown, {
vendor: 4,479 bytes, lines 17967-18118
17967      capture: true,
17968      passive: false,
17969      signal
17970    });
17971    window.addEventListener("contextmenu", noContextMenu, {
17972      signal
17973    });
17974    textLayer.addEventListener("pointermove", this.#highlightMove.bind(this, parent), {
17975      signal
17976    });
17977    this._freeHighlight = new FreeHighlightOutliner({
17978      x,
17979      y
17980    }, [layerX, layerY, parentWidth, parentHeight], parent.scale, this._defaultThickness / 2, isLTR, 0.001);
17981    ({
17982      id: this._freeHighlightId,
17983      clipPathId: this._freeHighlightClipId
17984    } = parent.drawLayer.draw(this._freeHighlight, this._defaultColor, this._defaultOpacity, true));
17985  }
17986  static #highlightMove(parent, event) {
17987    if (this._freeHighlight.add(event)) {
17988      parent.drawLayer.updatePath(this._freeHighlightId, this._freeHighlight);
17989    }
17990  }
17991  static #endHighlight(parent, event) {
17992    if (!this._freeHighlight.isEmpty()) {
17993      parent.createAndAddNewEditor(event, false, {
17994        highlightId: this._freeHighlightId,
17995        highlightOutlines: this._freeHighlight.getOutlines(),
17996        clipPathId: this._freeHighlightClipId,
17997        methodOfCreation: "main_toolbar"
17998      });
17999    } else {
18000      parent.drawLayer.remove(this._freeHighlightId);
18001    }
18002    this._freeHighlightId = -1;
18003    this._freeHighlight = null;
18004    this._freeHighlightClipId = "";
18005  }
18006  static async deserialize(data, parent, uiManager) {
18007    let initialData = null;
18008    if (data instanceof HighlightAnnotationElement) {
18009      const {
18010        data: {
18011          quadPoints,
18012          rect,
18013          rotation,
18014          id,
18015          color,
18016          opacity,
18017          popupRef
18018        },
18019        parent: {
18020          page: {
18021            pageNumber
18022          }
18023        }
18024      } = data;
18025      initialData = data = {
18026        annotationType: AnnotationEditorType.HIGHLIGHT,
18027        color: Array.from(color),
18028        opacity,
18029        quadPoints,
18030        boxes: null,
18031        pageIndex: pageNumber - 1,
18032        rect: rect.slice(0),
18033        rotation,
18034        id,
18035        deleted: false,
18036        popupRef
18037      };
18038    } else if (data instanceof InkAnnotationElement) {
18039      const {
18040        data: {
18041          inkLists,
18042          rect,
18043          rotation,
18044          id,
18045          color,
18046          borderStyle: {
18047            rawWidth: thickness
18048          },
18049          popupRef
18050        },
18051        parent: {
18052          page: {
18053            pageNumber
18054          }
18055        }
18056      } = data;
18057      initialData = data = {
18058        annotationType: AnnotationEditorType.HIGHLIGHT,
18059        color: Array.from(color),
18060        thickness,
18061        inkLists,
18062        boxes: null,
18063        pageIndex: pageNumber - 1,
18064        rect: rect.slice(0),
18065        rotation,
18066        id,
18067        deleted: false,
18068        popupRef
18069      };
18070    }
18071    const {
18072      color,
18073      quadPoints,
18074      inkLists,
18075      opacity
18076    } = data;
18077    const editor = await super.deserialize(data, parent, uiManager);
18078    editor.color = Util.makeHexColor(...color);
18079    editor.#opacity = opacity || 1;
18080    if (inkLists) {
18081      editor.#thickness = data.thickness;
18082    }
18083    editor.annotationElementId = data.id || null;
18084    editor._initialData = initialData;
18085    const [pageWidth, pageHeight] = editor.pageDimensions;
18086    const [pageX, pageY] = editor.pageTranslation;
18087    if (quadPoints) {
18088      const boxes = editor.#boxes = [];
18089      for (let i = 0; i < quadPoints.length; i += 8) {
18090        boxes.push({
18091          x: (quadPoints[i] - pageX) / pageWidth,
18092          y: 1 - (quadPoints[i + 1] - pageY) / pageHeight,
18093          width: (quadPoints[i + 2] - quadPoints[i]) / pageWidth,
18094          height: (quadPoints[i + 1] - quadPoints[i + 5]) / pageHeight
18095        });
18096      }
18097      editor.#createOutlines();
18098      editor.#addToDrawLayer();
18099      editor.rotate(editor.rotation);
18100    } else if (inkLists) {
18101      editor.#isFreeHighlight = true;
18102      const points = inkLists[0];
18103      const point = {
18104        x: points[0] - pageX,
18105        y: pageHeight - (points[1] - pageY)
18106      };
18107      const outliner = new FreeHighlightOutliner(point, [0, 0, pageWidth, pageHeight], 1, editor.#thickness / 2, true, 0.001);
18108      for (let i = 0, ii = points.length; i < ii; i += 2) {
18109        point.x = points[i] - pageX;
18110        point.y = pageHeight - (points[i + 1] - pageY);
18111        outliner.add(point);
18112      }
18113      const {
18114        id,
18115        clipPathId
18116      } = parent.drawLayer.draw(outliner, editor.color, editor._defaultOpacity, true);
18117      editor.#createFreeOutlines({
18118        highlightOutlines: outliner.getOutlines(),
18119        highlightId: id,
18120        clipPathId
18121      });
18122      editor.#addToDrawLayer();
18123    }
18124    return editor;
18125  }
18126  serialize(isForCopying = false) {
18127    if (this.isEmpty() || isForCopying) {
18128      return null;
18129    }
18130    if (this.deleted) {
18131      return this.serializeDeleted();
18132    }
18133    const rect = this.getRect(0, 0);
18134    const color = AnnotationEditor._colorManager.convert(this.color);
18135    const serialized = {
18136      annotationType: AnnotationEditorType.HIGHLIGHT,
18137      color,
18138      opacity: this.#opacity,
18139      thickness: this.#thickness,
18140      quadPoints: this.#serializeBoxes(),
18141      outlines: this.#serializeOutlines(rect),
18142      pageIndex: this.pageIndex,
18143      rect,
18144      rotation: this.#getRotation(),
18145      structTreeParentId: this._structTreeParentId
18146    };
18147    if (this.annotationElementId && !this.#hasElementChanged(serialized)) {
18148      return null;
18149    }
18150    serialized.id = this.annotationElementId;
18151    return serialized;
18152  }
18153  #hasElementChanged(serialized) {
18154    const {
18155      color
18156    } = this._initialData;
18157    return serialized.color.some((c, i) => c !== color[i]);
18158  }
18159  renderAnnotationElement(annotation) {
18160    annotation.updateEdited({
18161      rect: this.getRect(0, 0)
18162    });
18163    return null;
18164  }
18165  static canCreateNewEmptyEditor() {
18166    return false;
18167  }
18168}
18169
18170;// ./src/display/editor/ink.js
18171
18172
18173
18174
18175
18176class InkEditor extends AnnotationEditor {
18177  #baseHeight = 0;
18178  #baseWidth = 0;
18179  #canvasContextMenuTimeoutId = null;
18180  #currentPath2D = new Path2D();
18181  #disableEditing = false;
18182  #drawingAC = null;
18183  #hasSomethingToDraw = false;
18184  #isCanvasInitialized = false;
18185  #observer = null;
18186  #pointerdownAC = null;
18187  #realWidth = 0;
18188  #realHeight = 0;
18189  #requestFrameCallback = null;
18190  static _defaultColor = null;
18191  static _defaultOpacity = 1;
18192  static _defaultThickness = 1;
18193  static _type = "ink";
18194  static _editorType = AnnotationEditorType.INK;
18195  constructor(params) {
18196    super({
18197      ...params,
18198      name: "inkEditor"
18199    });
18200    this.color = params.color || null;
18201    this.thickness = params.thickness || null;
18202    this.opacity = params.opacity || null;
18203    this.paths = [];
18204    this.bezierPath2D = [];
18205    this.allRawPaths = [];
18206    this.currentPath = [];
18207    this.scaleFactor = 1;
18208    this.translationX = this.translationY = 0;
18209    this.x = 0;
18210    this.y = 0;
18211    this._willKeepAspectRatio = true;
18212  }
18213  static initialize(l10n, uiManager) {
18214    AnnotationEditor.initialize(l10n, uiManager);
18215  }
18216  static updateDefaultParams(type, value) {
18217    switch (type) {
18218      case AnnotationEditorParamsType.INK_THICKNESS:
18219        InkEditor._defaultThickness = value;
18220        break;
18221      case AnnotationEditorParamsType.INK_COLOR:
18222        InkEditor._defaultColor = value;
18223        break;
18224      case AnnotationEditorParamsType.INK_OPACITY:
18225        InkEditor._defaultOpacity = value / 100;
18226        break;
18227    }
18228  }
18229  updateParams(type, value) {
18230    switch (type) {
18231      case AnnotationEditorParamsType.INK_THICKNESS:
18232        this.#updateThickness(value);
18233        break;
18234      case AnnotationEditorParamsType.INK_COLOR:
18235        this.#updateColor(value);
18236        break;
18237      case AnnotationEditorParamsType.INK_OPACITY:
18238        this.#updateOpacity(value);
18239        break;
18240    }
18241  }
18242  static get defaultPropertiesToUpdate() {
18243    return [[AnnotationEditorParamsType.INK_THICKNESS, InkEditor._defaultThickness], [AnnotationEditorParamsType.INK_COLOR, InkEditor._defaultColor || AnnotationEditor._defaultLineColor], [AnnotationEditorParamsType.INK_OPACITY, Math.round(InkEditor._defaultOpacity * 100)]];
18244  }
18245  get propertiesToUpdate() {
18246    return [[AnnotationEditorParamsType.INK_THICKNESS, this.thickness || InkEditor._defaultThickness], [AnnotationEditorParamsType.INK_COLOR, this.color || InkEditor._defaultColor || AnnotationEditor._defaultLineColor], [AnnotationEditorParamsType.INK_OPACITY, Math.round(100 * (this.opacity ?? InkEditor._defaultOpacity))]];
18247  }
18248  #updateThickness(thickness) {
18249    const setThickness = th => {
18250      this.thickness = th;
18251      this.#fitToContent();
18252    };
18253    const savedThickness = this.thickness;
18254    this.addCommands({
18255      cmd: setThickness.bind(this, thickness),
18256      undo: setThickness.bind(this, savedThickness),
18257      post: this._uiManager.updateUI.bind(this._uiManager, this),
18258      mustExec: true,
18259      type: AnnotationEditorParamsType.INK_THICKNESS,
18260      overwriteIfSameType: true,
18261      keepUndo: true
18262    });
18263  }
18264  #updateColor(color) {
18265    const setColor = col => {
18266      this.color = col;
18267      this.#redraw();
18268    };
18269    const savedColor = this.color;
18270    this.addCommands({
18271      cmd: setColor.bind(this, color),
18272      undo: setColor.bind(this, savedColor),
18273      post: this._uiManager.updateUI.bind(this._uiManager, this),
18274      mustExec: true,
18275      type: AnnotationEditorParamsType.INK_COLOR,
18276      overwriteIfSameType: true,
18277      keepUndo: true
18278    });
18279  }
18280  #updateOpacity(opacity) {
18281    const setOpacity = op => {
18282      this.opacity = op;
18283      this.#redraw();
18284    };
18285    opacity /= 100;
18286    const savedOpacity = this.opacity;
18287    this.addCommands({
18288      cmd: setOpacity.bind(this, opacity),
18289      undo: setOpacity.bind(this, savedOpacity),
18290      post: this._uiManager.updateUI.bind(this._uiManager, this),
18291      mustExec: true,
18292      type: AnnotationEditorParamsType.INK_OPACITY,
18293      overwriteIfSameType: true,
18294      keepUndo: true
18295    });
18296  }
18297  rebuild() {
18298    if (!this.parent) {
18299      return;
18300    }
18301    super.rebuild();
18302    if (this.div === null) {
18303      return;
18304    }
18305    if (!this.canvas) {
18306      this.#createCanvas();
18307      this.#createObserver();
18308    }
18309    if (!this.isAttachedToDOM) {
18310      this.parent.add(this);
18311      this.#setCanvasDims();
18312    }
18313    this.#fitToContent();
18314  }
18315  remove() {
18316    if (this.canvas === null) {
18317      return;
18318    }
18319    if (!this.isEmpty()) {
18320      this.commit();
18321    }
18322    this.canvas.width = this.canvas.height = 0;
18323    this.canvas.remove();
18324    this.canvas = null;
18325    if (this.#canvasContextMenuTimeoutId) {
18326      clearTimeout(this.#canvasContextMenuTimeoutId);
18327      this.#canvasContextMenuTimeoutId = null;
18328    }
18329    this.#observer?.disconnect();
18330    this.#observer = null;
18331    super.remove();
18332  }
18333  setParent(parent) {
18334    if (!this.parent && parent) {
18335      this._uiManager.removeShouldRescale(this);
18336    } else if (this.parent && parent === null) {
18337      this._uiManager.addShouldRescale(this);
18338    }
18339    super.setParent(parent);
18340  }
18341  onScaleChanging() {
18342    const [parentWidth, parentHeight] = this.parentDimensions;
18343    const width = this.width * parentWidth;
18344    const height = this.height * parentHeight;
18345    this.setDimensions(width, height);
18346  }
18347  enableEditMode() {
18348    if (this.#disableEditing || this.canvas === null) {
18349      return;
18350    }
18351    super.enableEditMode();
18352    this._isDraggable = false;
18353    this.#addPointerdownListener();
18354  }
18355  disableEditMode() {
18356    if (!this.isInEditMode() || this.canvas === null) {
18357      return;
18358    }
18359    super.disableEditMode();
18360    this._isDraggable = !this.isEmpty();
18361    this.div.classList.remove("editing");
18362    this.#removePointerdownListener();
18363  }
18364  onceAdded() {
18365    this._isDraggable = !this.isEmpty();
18366  }
18367  isEmpty() {
18368    return this.paths.length === 0 || this.paths.length === 1 && this.paths[0].length === 0;
18369  }
18370  #getInitialBBox() {
18371    const {
18372      parentRotation,
18373      parentDimensions: [width, height]
18374    } = this;
18375    switch (parentRotation) {
18376      case 90:
18377        return [0, height, height, width];
18378      case 180:
18379        return [width, height, width, height];
18380      case 270:
18381        return [width, 0, height, width];
18382      default:
18383        return [0, 0, width, height];
18384    }
18385  }
18386  #setStroke() {
18387    const {
18388      ctx,
18389      color,
18390      opacity,
18391      thickness,
18392      parentScale,
18393      scaleFactor
18394    } = this;
18395    ctx.lineWidth = thickness * parentScale / scaleFactor;
18396    ctx.lineCap = "round";
18397    ctx.lineJoin = "round";
18398    ctx.miterLimit = 10;
18399    ctx.strokeStyle = `${color}${opacityToHex(opacity)}`;
18400  }
18401  #startDrawing(x, y) {
18402    this.canvas.addEventListener("contextmenu", noContextMenu, {
18403      signal: this._uiManager._signal
18404    });
18405    this.#removePointerdownListener();
18406    this.#drawingAC = new AbortController();
18407    const signal = this._uiManager.combinedSignal(this.#drawingAC);
18408    this.canvas.addEventListener("pointerleave", this.canvasPointerleave.bind(this), {
18409      signal
18410    });
18411    this.canvas.addEventListener("pointermove", this.canvasPointermove.bind(this), {
18412      signal
18413    });
18414    this.canvas.addEventListener("pointerup", this.canvasPointerup.bind(this), {
18415      signal
18416    });
18417    this.isEditing = true;
18418    if (!this.#isCanvasInitialized) {
18419      this.#isCanvasInitialized = true;
18420      this.#setCanvasDims();
18421      this.thickness ||= InkEditor._defaultThickness;
18422      this.color ||= InkEditor._defaultColor || AnnotationEditor._defaultLineColor;
18423      this.opacity ??= InkEditor._defaultOpacity;
18424    }
18425    this.currentPath.push([x, y]);
18426    this.#hasSomethingToDraw = false;
18427    this.#setStroke();
18428    this.#requestFrameCallback = () => {
18429      this.#drawPoints();
18430      if (this.#requestFrameCallback) {
18431        window.requestAnimationFrame(this.#requestFrameCallback);
18432      }
18433    };
18434    window.requestAnimationFrame(this.#requestFrameCallback);
18435  }
18436  #draw(x, y) {
18437    const [lastX, lastY] = this.currentPath.at(-1);
18438    if (this.currentPath.length > 1 && x === lastX && y === lastY) {
18439      return;
18440    }
18441    const currentPath = this.currentPath;
18442    let path2D = this.#currentPath2D;
18443    currentPath.push([x, y]);
18444    this.#hasSomethingToDraw = true;
18445    if (currentPath.length <= 2) {
18446      path2D.moveTo(...currentPath[0]);
18447      path2D.lineTo(x, y);
18448      return;
18449    }
18450    if (currentPath.length === 3) {
18451      this.#currentPath2D = path2D = new Path2D();
18452      path2D.moveTo(...currentPath[0]);
18453    }
18454    this.#makeBezierCurve(path2D, ...currentPath.at(-3), ...currentPath.at(-2), x, y);
18455  }
18456  #endPath() {
18457    if (this.currentPath.length === 0) {
18458      return;
18459    }
18460    const lastPoint = this.currentPath.at(-1);
18461    this.#currentPath2D.lineTo(...lastPoint);
18462  }
18463  #stopDrawing(x, y) {
18464    this.#requestFrameCallback = null;
18465    x = Math.min(Math.max(x, 0), this.canvas.width);
18466    y = Math.min(Math.max(y, 0), this.canvas.height);
18467    this.#draw(x, y);
18468    this.#endPath();
18469    let bezier;
18470    if (this.currentPath.length !== 1) {
18471      bezier = this.#generateBezierPoints();
18472    } else {
18473      const xy = [x, y];
18474      bezier = [[xy, xy.slice(), xy.slice(), xy]];
18475    }
18476    const path2D = this.#currentPath2D;
18477    const currentPath = this.currentPath;
18478    this.currentPath = [];
18479    this.#currentPath2D = new Path2D();
18480    const cmd = () => {
18481      this.allRawPaths.push(currentPath);
18482      this.paths.push(bezier);
18483      this.bezierPath2D.push(path2D);
18484      this._uiManager.rebuild(this);
18485    };
18486    const undo = () => {
18487      this.allRawPaths.pop();
18488      this.paths.pop();
18489      this.bezierPath2D.pop();
18490      if (this.paths.length === 0) {
18491        this.remove();
18492      } else {
18493        if (!this.canvas) {
18494          this.#createCanvas();
18495          this.#createObserver();
18496        }
18497        this.#fitToContent();
18498      }
18499    };
18500    this.addCommands({
18501      cmd,
18502      undo,
18503      mustExec: true
18504    });
18505  }
18506  #drawPoints() {
18507    if (!this.#hasSomethingToDraw) {
18508      return;
18509    }
18510    this.#hasSomethingToDraw = false;
18511    const thickness = Math.ceil(this.thickness * this.parentScale);
18512    const lastPoints = this.currentPath.slice(-3);
18513    const x = lastPoints.map(xy => xy[0]);
18514    const y = lastPoints.map(xy => xy[1]);
18515    const xMin = Math.min(...x) - thickness;
18516    const xMax = Math.max(...x) + thickness;
18517    const yMin = Math.min(...y) - thickness;
18518    const yMax = Math.max(...y) + thickness;
18519    const {
18520      ctx
18521    } = this;
18522    ctx.save();
18523    ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
18524    for (const path of this.bezierPath2D) {
18525      ctx.stroke(path);
18526    }
18527    ctx.stroke(this.#currentPath2D);
18528    ctx.restore();
18529  }
18530  #makeBezierCurve(path2D, x0, y0, x1, y1, x2, y2) {
18531    const prevX = (x0 + x1) / 2;
18532    const prevY = (y0 + y1) / 2;
18533    const x3 = (x1 + x2) / 2;
18534    const y3 = (y1 + y2) / 2;
18535    path2D.bezierCurveTo(prevX + 2 * (x1 - prevX) / 3, prevY + 2 * (y1 - prevY) / 3, x3 + 2 * (x1 - x3) / 3, y3 + 2 * (y1 - y3) / 3, x3, y3);
18536  }
18537  #generateBezierPoints() {
18538    const path = this.currentPath;
18539    if (path.length <= 2) {
18540      return [[path[0], path[0], path.at(-1), path.at(-1)]];
18541    }
18542    const bezierPoints = [];
18543    let i;
18544    let [x0, y0] = path[0];
18545    for (i = 1; i < path.length - 2; i++) {
18546      const [x1, y1] = path[i];
18547      const [x2, y2] = path[i + 1];
18548      const x3 = (x1 + x2) / 2;
18549      const y3 = (y1 + y2) / 2;
18550      const control1 = [x0 + 2 * (x1 - x0) / 3, y0 + 2 * (y1 - y0) / 3];
18551      const control2 = [x3 + 2 * (x1 - x3) / 3, y3 + 2 * (y1 - y3) / 3];
18552      bezierPoints.push([[x0, y0], control1, control2, [x3, y3]]);
18553      [x0, y0] = [x3, y3];
18554    }
18555    const [x1, y1] = path[i];
18556    const [x2, y2] = path[i + 1];
18557    const control1 = [x0 + 2 * (x1 - x0) / 3, y0 + 2 * (y1 - y0) / 3];
18558    const control2 = [x2 + 2 * (x1 - x2) / 3, y2 + 2 * (y1 - y2) / 3];
18559    bezierPoints.push([[x0, y0], control1, control2, [x2, y2]]);
18560    return bezierPoints;
18561  }
18562  #redraw() {
18563    if (this.isEmpty()) {
18564      this.#updateTransform();
18565      return;
18566    }
18567    this.#setStroke();
18568    const {
18569      canvas,
18570      ctx
18571    } = this;
18572    ctx.setTransform(1, 0, 0, 1, 0, 0);
18573    ctx.clearRect(0, 0, canvas.width, canvas.height);
18574    this.#updateTransform();
18575    for (const path of this.bezierPath2D) {
18576      ctx.stroke(path);
18577    }
18578  }
18579  commit() {
18580    if (this.#disableEditing) {
18581      return;
18582    }
18583    super.commit();
18584    this.isEditing = false;
18585    this.disableEditMode();
18586    this.setInForeground();
18587    this.#disableEditing = true;
18588    this.div.classList.add("disabled");
18589    this.#fitToContent(true);
18590    this.select();
18591    this.parent.addInkEditorIfNeeded(true);
18592    this.moveInDOM();
18593    this.div.focus({
18594      preventScroll: true
18595    });
18596  }
18597  focusin(event) {
18598    if (!this._focusEventsAllowed) {
18599      return;
18600    }
18601    super.focusin(event);
18602    this.enableEditMode();
18603  }
18604  #addPointerdownListener() {
18605    if (this.#pointerdownAC) {
18606      return;
18607    }
18608    this.#pointerdownAC = new AbortController();
18609    const signal = this._uiManager.combinedSignal(this.#pointerdownAC);
18610    this.canvas.addEventListener("pointerdown", this.canvasPointerdown.bind(this), {
18611      signal
18612    });
18613  }
18614  #removePointerdownListener() {
18615    this.pointerdownAC?.abort();
18616    this.pointerdownAC = null;
18617  }
18618  canvasPointerdown(event) {
18619    if (event.button !== 0 || !this.isInEditMode() || this.#disableEditing) {
18620      return;
18621    }
18622    this.setInForeground();
18623    event.preventDefault();
18624    if (!this.div.contains(document.activeElement)) {
18625      this.div.focus({
18626        preventScroll: true
18627      });
18628    }
18629    this.#startDrawing(event.offsetX, event.offsetY);
18630  }
18631  canvasPointermove(event) {
18632    event.preventDefault();
18633    this.#draw(event.offsetX, event.offsetY);
18634  }
18635  canvasPointerup(event) {
18636    event.preventDefault();
18637    this.#endDrawing(event);
18638  }
18639  canvasPointerleave(event) {
18640    this.#endDrawing(event);
18641  }
18642  #endDrawing(event) {
18643    this.#drawingAC?.abort();
18644    this.#drawingAC = null;
18645    this.#addPointerdownListener();
18646    if (this.#canvasContextMenuTimeoutId) {
18647      clearTimeout(this.#canvasContextMenuTimeoutId);
18648    }
18649    this.#canvasContextMenuTimeoutId = setTimeout(() => {
18650      this.#canvasContextMenuTimeoutId = null;
18651      this.canvas.removeEventListener("contextmenu", noContextMenu);
18652    }, 10);
18653    this.#stopDrawing(event.offsetX, event.offsetY);
18654    this.addToAnnotationStorage();
18655    this.setInBackground();
18656  }
18657  #createCanvas() {
18658    this.canvas = document.createElement("canvas");
18659    this.canvas.width = this.canvas.height = 0;
18660    this.canvas.className = "inkEditorCanvas";
18661    this.canvas.setAttribute("data-l10n-id", "pdfjs-ink-canvas");
18662    this.div.append(this.canvas);
18663    this.ctx = this.canvas.getContext("2d");
18664  }
18665  #createObserver() {
18666    this.#observer = new ResizeObserver(entries => {
18667      const rect = entries[0].contentRect;
18668      if (rect.width && rect.height) {
18669        this.setDimensions(rect.width, rect.height);
18670      }
18671    });
18672    this.#observer.observe(this.div);
18673    this._uiManager._signal.addEventListener("abort", () => {
18674      this.#observer?.disconnect();
18675      this.#observer = null;
18676    }, {
18677      once: true
18678    });
18679  }
18680  get isResizable() {
18681    return !this.isEmpty() && this.#disableEditing;
18682  }
18683  render() {
18684    if (this.div) {
18685      return this.div;
18686    }
18687    let baseX, baseY;
18688    if (this.width) {
18689      baseX = this.x;
18690      baseY = this.y;
18691    }
18692    super.render();
18693    this.div.setAttribute("data-l10n-id", "pdfjs-ink");
18694    const [x, y, w, h] = this.#getInitialBBox();
18695    this.setAt(x, y, 0, 0);
18696    this.setDims(w, h);
18697    this.#createCanvas();
18698    if (this.width) {
18699      const [parentWidth, parentHeight] = this.parentDimensions;
18700      this.setAspectRatio(this.width * parentWidth, this.height * parentHeight);
18701      this.setAt(baseX * parentWidth, baseY * parentHeight, this.width * parentWidth, this.height * parentHeight);
18702      this.#isCanvasInitialized = true;
18703      this.#setCanvasDims();
18704      this.setDims(this.width * parentWidth, this.height * parentHeight);
18705      this.#redraw();
18706      this.div.classList.add("disabled");
18707    } else {
18708      this.div.classList.add("editing");
18709      this.enableEditMode();
18710    }
18711    this.#createObserver();
18712    return this.div;
18713  }
18714  #setCanvasDims() {
18715    if (!this.#isCanvasInitialized) {
18716      return;
18717    }
18718    const [parentWidth, parentHeight] = this.parentDimensions;
18719    this.canvas.width = Math.ceil(this.width * parentWidth);
18720    this.canvas.height = Math.ceil(this.height * parentHeight);
18721    this.#updateTransform();
18722  }
18723  setDimensions(width, height) {
18724    const roundedWidth = Math.round(width);
18725    const roundedHeight = Math.round(height);
18726    if (this.#realWidth === roundedWidth && this.#realHeight === rounded
18726Height) {
18727      return;
18728    }
18729    this.#realWidth = roundedWidth;
18730    this.#realHeight = roundedHeight;
18731    this.canvas.style.visibility = "hidden";
18732    const [parentWidth, parentHeight] = this.parentDimensions;
18733    this.width = width / parentWidth;
18734    this.height = height / parentHeight;
18735    this.fixAndSetPosition();
18736    if (this.#disableEditing) {
18737      this.#setScaleFactor(width, height);
18738    }
18739    this.#setCanvasDims();
18740    this.#redraw();
18741    this.canvas.style.visibility = "visible";
18742    this.fixDims();
18743  }
18744  #setScaleFactor(width, height) {
18745    const padding = this.#getPadding();
18746    const scaleFactorW = (width - padding) / this.#baseWidth;
18747    const scaleFactorH = (height - padding) / this.#baseHeight;
18748    this.scaleFactor = Math.min(scaleFactorW, scaleFactorH);
18749  }
18750  #updateTransform() {
18751    const padding = this.#getPadding() / 2;
18752    this.ctx.setTransform(this.scaleFactor, 0, 0, this.scaleFactor, this.translationX * this.scaleFactor + padding, this.translationY * this.scaleFactor + padding);
18753  }
18754  static #buildPath2D(bezier) {
18755    const path2D = new Path2D();
18756    for (let i = 0, ii = bezier.length; i < ii; i++) {
18757      const [first, control1, control2, second] = bezier[i];
18758      if (i === 0) {
18759        path2D.moveTo(...first);
18760      }
18761      path2D.bezierCurveTo(control1[0], control1[1], control2[0], control2[1], second[0], second[1]);
18762    }
18763    return path2D;
18764  }
18765  static #toPDFCoordinates(points, rect, rotation) {
18766    const [blX, blY, trX, trY] = rect;
18767    switch (rotation) {
18768      case 0:
18769        for (let i = 0, ii = points.length; i < ii; i += 2) {
18770          points[i] += blX;
18771          points[i + 1] = trY - points[i + 1];
18772        }
18773        break;
18774      case 90:
18775        for (let i = 0, ii = points.length; i < ii; i += 2) {
18776          const x = points[i];
18777          points[i] = points[i + 1] + blX;
18778          points[i + 1] = x + blY;
18779        }
18780        break;
18781      case 180:
18782        for (let i = 0, ii = points.length; i < ii; i += 2) {
18783          points[i] = trX - points[i];
18784          points[i + 1] += blY;
18785        }
18786        break;
18787      case 270:
18788        for (let i = 0, ii = points.length; i < ii; i += 2) {
18789          const x = points[i];
18790          points[i] = trX - points[i + 1];
18791          points[i + 1] = trY - x;
18792        }
18793        break;
18794      default:
18795        throw new Error("Invalid rotation");
18796    }
18797    return points;
18798  }
18799  static #fromPDFCoordinates(points, rect, rotation) {
18800    const [blX, blY, trX, trY] = rect;
18801    switch (rotation) {
18802      case 0:
18803        for (let i = 0, ii = points.length; i < ii; i += 2) {
18804          points[i] -= blX;
18805          points[i + 1] = trY - points[i + 1];
18806        }
18807        break;
18808      case 90:
18809        for (let i = 0, ii = points.length; i < ii; i += 2) {
18810          const x = points[i];
18811          points[i] = points[i + 1] - blY;
18812          points[i + 1] = x - blX;
18813        }
18814        break;
18815      case 180:
18816        for (let i = 0, ii = points.length; i < ii; i += 2) {
18817          points[i] = trX - points[i];
18818          points[i + 1] -= blY;
18819        }
18820        break;
18821      case 270:
18822        for (let i = 0, ii = points.length; i < ii; i += 2) {
18823          const x = points[i];
18824          points[i] = trY - points[i + 1];
18825          points[i + 1] = trX - x;
18826        }
18827        break;
18828      default:
18829        throw new Error("Invalid rotation");
18830    }
18831    return points;
18832  }
18833  #serializePaths(s, tx, ty, rect) {
18834    const paths = [];
18835    const padding = this.thickness / 2;
18836    const shiftX = s * tx + padding;
18837    const shiftY = s * ty + padding;
18838    for (const bezier of this.paths) {
18839      const buffer = [];
18840      const points = [];
18841      for (let j = 0, jj = bezier.length; j < jj; j++) {
18842        const [first, control1, control2, second] = bezier[j];
18843        if (first[0] === second[0] && first[1] === second[1] && jj === 1) {
18844          const p0 = s * first[0] + shiftX;
18845          const p1 = s * first[1] + shiftY;
18846          buffer.push(p0, p1);
18847          points.push(p0, p1);
18848          break;
18849        }
18850        const p10 = s * first[0] + shiftX;
18851        const p11 = s * first[1] + shiftY;
18852        const p20 = s * control1[0] + shiftX;
18853        const p21 = s * control1[1] + shiftY;
18854        const p30 = s * control2[0] + shiftX;
18855        const p31 = s * control2[1] + shiftY;
18856        const p40 = s * second[0] + shiftX;
18857        const p41 = s * second[1] + shiftY;
18858        if (j === 0) {
18859          buffer.push(p10, p11);
18860          points.push(p10, p11);
18861        }
18862        buffer.push(p20, p21, p30, p31, p40, p41);
18863        points.push(p20, p21);
18864        if (j === jj - 1) {
18865          points.push(p40, p41);
18866        }
18867      }
18868      paths.push({
18869        bezier: InkEditor.#toPDFCoordinates(buffer, rect, this.rotation),
18870        points: InkEditor.#toPDFCoordinates(points, rect, this.rotation)
18871      });
18872    }
18873    return paths;
18874  }
18875  #getBbox() {
18876    let xMin = Infinity;
18877    let xMax = -Infinity;
18878    let yMin = Infinity;
18879    let yMax = -Infinity;
18880    for (const path of this.paths) {
18881      for (const [first, control1, control2, second] of path) {
18882        const bbox = Util.bezierBoundingBox(...first, ...control1, ...control2, ...second);
18883        xMin = Math.min(xMin, bbox[0]);
18884        yMin = Math.min(yMin, bbox[1]);
18885        xMax = Math.max(xMax, bbox[2]);
18886        yMax = Math.max(yMax, bbox[3]);
18887      }
18888    }
18889    return [xMin, yMin, xMax, yMax];
18890  }
18891  #getPadding() {
18892    return this.#disableEditing ? Math.ceil(this.thickness * this.parentScale) : 0;
18893  }
18894  #fitToContent(firstTime = false) {
18895    if (this.isEmpty()) {
18896      return;
18897    }
18898    if (!this.#disableEditing) {
18899      this.#redraw();
18900      return;
18901    }
18902    const bbox = this.#getBbox();
18903    const padding = this.#getPadding();
18904    this.#baseWidth = Math.max(AnnotationEditor.MIN_SIZE, bbox[2] - bbox[0]);
18905    this.#baseHeight = Math.max(AnnotationEditor.MIN_SIZE, bbox[3] - bbox[1]);
18906    const width = Math.ceil(padding + this.#baseWidth * this.scaleFactor);
18907    const height = Math.ceil(padding + this.#baseHeight * this.scaleFactor);
18908    const [parentWidth, parentHeight] = this.parentDimensions;
18909    this.width = width / parentWidth;
18910    this.height = height / parentHeight;
18911    this.setAspectRatio(width, height);
18912    const prevTranslationX = this.translationX;
18913    const prevTranslationY = this.translationY;
18914    this.translationX = -bbox[0];
18915    this.translationY = -bbox[1];
18916    this.#setCanvasDims();
18917    this.#redraw();
18918    this.#realWidth = width;
18919    this.#realHeight = height;
18920    this.setDims(width, height);
18921    const unscaledPadding = firstTime ? padding / this.scaleFactor / 2 : 0;
18922    this.translate(prevTranslationX - this.translationX - unscaledPadding, prevTranslationY - this.translationY - unscaledPadding);
18923  }
18924  static async deserialize(data, parent, uiManager) {
18925    if (data instanceof InkAnnotationElement) {
18926      return null;
18927    }
18928    const editor = await super.deserialize(data, parent, uiManager);
18929    editor.thickness = data.thickness;
18930    editor.color = Util.makeHexColor(...data.color);
18931    editor.opacity = data.opacity;
18932    const [pageWidth, pageHeight] = editor.pageDimensions;
18933    const width = editor.width * pageWidth;
18934    const height = editor.height * pageHeight;
18935    const scaleFactor = editor.parentScale;
18936    const padding = data.thickness / 2;
18937    editor.#disableEditing = true;
18938    editor.#realWidth = Math.round(width);
18939    editor.#realHeight = Math.round(height);
18940    const {
18941      paths,
18942      rect,
18943      rotation
18944    } = data;
18945    for (let {
18946      bezier
18947    } of paths) {
18948      bezier = InkEditor.#fromPDFCoordinates(bezier, rect, rotation);
18949      const path = [];
18950      editor.paths.push(path);
18951      let p0 = scaleFactor * (bezier[0] - padding);
18952      let p1 = scaleFactor * (bezier[1] - padding);
18953      for (let i = 2, ii = bezier.length; i < ii; i += 6) {
18954        const p10 = scaleFactor * (bezier[i] - padding);
18955        const p11 = scaleFactor * (bezier[i + 1] - padding);
18956        const p20 = scaleFactor * (bezier[i + 2] - padding);
18957        const p21 = scaleFactor * (bezier[i + 3] - padding);
18958        const p30 = scaleFactor * (bezier[i + 4] - padding);
18959        const p31 = scaleFactor * (bezier[i + 5] - padding);
18960        path.push([[p0, p1], [p10, p11], [p20, p21], [p30, p31]]);
18961        p0 = p30;
18962        p1 = p31;
18963      }
18964      const path2D = this.#buildPath2D(path);
18965      editor.bezierPath2D.push(path2D);
18966    }
18967    const bbox = editor.#getBbox();
18968    editor.#baseWidth = Math.max(AnnotationEditor.MIN_SIZE, bbox[2] - bbox[0]);
18969    editor.#baseHeight = Math.max(AnnotationEditor.MIN_SIZE, bbox[3] - bbox[1]);
18970    editor.#setScaleFactor(width, height);
18971    return editor;
18972  }
18973  serialize() {
18974    if (this.isEmpty()) {
18975      return null;
18976    }
18977    const rect = this.getRect(0, 0);
18978    const color = AnnotationEditor._colorManager.convert(this.ctx.strokeStyle);
18979    return {
18980      annotationType: AnnotationEditorType.INK,
18981      color,
18982      thickness: this.thickness,
18983      opacity: this.opacity,
18984      paths: this.#serializePaths(this.scaleFactor / this.parentScale, this.translationX, this.translationY, rect),
18985      pageIndex: this.pageIndex,
18986      rect,
18987      rotation: this.rotation,
18988      structTreeParentId: this._structTreeParentId
18989    };
18990  }
18991}
18992
18993;// ./src/display/editor/stamp.js
18994
18995
18996
18997
18998class StampEditor extends AnnotationEditor {
18999  #bitmap = null;
19000  #bitmapId = null;
19001  #bitmapPromise = null;
19002  #bitmapUrl = null;
19003  #bitmapFile = null;
19004  #bitmapFileName = "";
19005  #canvas = null;
19006  #observer = null;
19007  #resizeTimeoutId = null;
19008  #isSvg = false;
19009  #hasBeenAddedInUndoStack = false;
19010  static _type = "stamp";
19011  static _editorType = AnnotationEditorType.STAMP;
19012  constructor(params) {
19013    super({
19014      ...params,
19015      name: "stampEditor"
19016    });
19017    this.#bitmapUrl = params.bitmapUrl;
19018    this.#bitmapFile = params.bitmapFile;
19019  }
19020  static initialize(l10n, uiManager) {
19021    AnnotationEditor.initialize(l10n, uiManager);
19022  }
19023  static get supportedTypes() {
19024    const types = ["apng", "avif", "bmp", "gif", "jpeg", "png", "svg+xml", "webp", "x-icon"];
19025    return shadow(this, "supportedTypes", types.map(type => `image/${type}`));
19026  }
19027  static get supportedTypesStr() {
19028    return shadow(this, "supportedTypesStr", this.supportedTypes.join(","));
19029  }
19030  static isHandlingMimeForPasting(mime) {
19031    return this.supportedTypes.includes(mime);
19032  }
19033  static paste(item, parent) {
19034    parent.pasteEditor(AnnotationEditorType.STAMP, {
19035      bitmapFile: item.getAsFile()
19036    });
19037  }
19038  altTextFinish() {
19039    if (this._uiManager.useNewAltTextFlow) {
19040      this.div.hidden = false;
vendor: 7,184 bytes, lines 19041-19290
19041    }
19042    super.altTextFinish();
19043  }
19044  get telemetryFinalData() {
19045    return {
19046      type: "stamp",
19047      hasAltText: !!this.altTextData?.altText
19048    };
19049  }
19050  static computeTelemetryFinalData(data) {
19051    const hasAltTextStats = data.get("hasAltText");
19052    return {
19053      hasAltText: hasAltTextStats.get(true) ?? 0,
19054      hasNoAltText: hasAltTextStats.get(false) ?? 0
19055    };
19056  }
19057  #getBitmapFetched(data, fromId = false) {
19058    if (!data) {
19059      this.remove();
19060      return;
19061    }
19062    this.#bitmap = data.bitmap;
19063    if (!fromId) {
19064      this.#bitmapId = data.id;
19065      this.#isSvg = data.isSvg;
19066    }
19067    if (data.file) {
19068      this.#bitmapFileName = data.file.name;
19069    }
19070    this.#createCanvas();
19071  }
19072  #getBitmapDone() {
19073    this.#bitmapPromise = null;
19074    this._uiManager.enableWaiting(false);
19075    if (!this.#canvas) {
19076      return;
19077    }
19078    if (this._uiManager.useNewAltTextWhenAddingImage && this._uiManager.useNewAltTextFlow && this.#bitmap) {
19079      this._editToolbar.hide();
19080      this._uiManager.editAltText(this, true);
19081      return;
19082    }
19083    if (!this._uiManager.useNewAltTextWhenAddingImage && this._uiManager.useNewAltTextFlow && this.#bitmap) {
19084      this._reportTelemetry({
19085        action: "pdfjs.image.image_added",
19086        data: {
19087          alt_text_modal: false,
19088          alt_text_type: "empty"
19089        }
19090      });
19091      try {
19092        this.mlGuessAltText();
19093      } catch {}
19094    }
19095    this.div.focus();
19096  }
19097  async mlGuessAltText(imageData = null, updateAltTextData = true) {
19098    if (this.hasAltTextData()) {
19099      return null;
19100    }
19101    const {
19102      mlManager
19103    } = this._uiManager;
19104    if (!mlManager) {
19105      throw new Error("No ML.");
19106    }
19107    if (!(await mlManager.isEnabledFor("altText"))) {
19108      throw new Error("ML isn't enabled for alt text.");
19109    }
19110    const {
19111      data,
19112      width,
19113      height
19114    } = imageData || this.copyCanvas(null, null, true).imageData;
19115    const response = await mlManager.guess({
19116      name: "altText",
19117      request: {
19118        data,
19119        width,
19120        height,
19121        channels: data.length / (width * height)
19122      }
19123    });
19124    if (!response) {
19125      throw new Error("No response from the AI service.");
19126    }
19127    if (response.error) {
19128      throw new Error("Error from the AI service.");
19129    }
19130    if (response.cancel) {
19131      return null;
19132    }
19133    if (!response.output) {
19134      throw new Error("No valid response from the AI service.");
19135    }
19136    const altText = response.output;
19137    await this.setGuessedAltText(altText);
19138    if (updateAltTextData && !this.hasAltTextData()) {
19139      this.altTextData = {
19140        alt: altText,
19141        decorative: false
19142      };
19143    }
19144    return altText;
19145  }
19146  #getBitmap() {
19147    if (this.#bitmapId) {
19148      this._uiManager.enableWaiting(true);
19149      this._uiManager.imageManager.getFromId(this.#bitmapId).then(data => this.#getBitmapFetched(data, true)).finally(() => this.#getBitmapDone());
19150      return;
19151    }
19152    if (this.#bitmapUrl) {
19153      const url = this.#bitmapUrl;
19154      this.#bitmapUrl = null;
19155      this._uiManager.enableWaiting(true);
19156      this.#bitmapPromise = this._uiManager.imageManager.getFromUrl(url).then(data => this.#getBitmapFetched(data)).finally(() => this.#getBitmapDone());
19157      return;
19158    }
19159    if (this.#bitmapFile) {
19160      const file = this.#bitmapFile;
19161      this.#bitmapFile = null;
19162      this._uiManager.enableWaiting(true);
19163      this.#bitmapPromise = this._uiManager.imageManager.getFromFile(file).then(data => this.#getBitmapFetched(data)).finally(() => this.#getBitmapDone());
19164      return;
19165    }
19166    const input = document.createElement("input");
19167    input.type = "file";
19168    input.accept = StampEditor.supportedTypesStr;
19169    const signal = this._uiManager._signal;
19170    this.#bitmapPromise = new Promise(resolve => {
19171      input.addEventListener("change", async () => {
19172        if (!input.files || input.files.length === 0) {
19173          this.remove();
19174        } else {
19175          this._uiManager.enableWaiting(true);
19176          const data = await this._uiManager.imageManager.getFromFile(input.files[0]);
19177          this._reportTelemetry({
19178            action: "pdfjs.image.image_selected",
19179            data: {
19180              alt_text_modal: this._uiManager.useNewAltTextFlow
19181            }
19182          });
19183          this.#getBitmapFetched(data);
19184        }
19185        resolve();
19186      }, {
19187        signal
19188      });
19189      input.addEventListener("cancel", () => {
19190        this.remove();
19191        resolve();
19192      }, {
19193        signal
19194      });
19195    }).finally(() => this.#getBitmapDone());
19196    input.click();
19197  }
19198  remove() {
19199    if (this.#bitmapId) {
19200      this.#bitmap = null;
19201      this._uiManager.imageManager.deleteId(this.#bitmapId);
19202      this.#canvas?.remove();
19203      this.#canvas = null;
19204      this.#observer?.disconnect();
19205      this.#observer = null;
19206      if (this.#resizeTimeoutId) {
19207        clearTimeout(this.#resizeTimeoutId);
19208        this.#resizeTimeoutId = null;
19209      }
19210    }
19211    super.remove();
19212  }
19213  rebuild() {
19214    if (!this.parent) {
19215      if (this.#bitmapId) {
19216        this.#getBitmap();
19217      }
19218      return;
19219    }
19220    super.rebuild();
19221    if (this.div === null) {
19222      return;
19223    }
19224    if (this.#bitmapId && this.#canvas === null) {
19225      this.#getBitmap();
19226    }
19227    if (!this.isAttachedToDOM) {
19228      this.parent.add(this);
19229    }
19230  }
19231  onceAdded() {
19232    this._isDraggable = true;
19233    this.div.focus();
19234  }
19235  isEmpty() {
19236    return !(this.#bitmapPromise || this.#bitmap || this.#bitmapUrl || this.#bitmapFile || this.#bitmapId);
19237  }
19238  get isResizable() {
19239    return true;
19240  }
19241  render() {
19242    if (this.div) {
19243      return this.div;
19244    }
19245    let baseX, baseY;
19246    if (this.width) {
19247      baseX = this.x;
19248      baseY = this.y;
19249    }
19250    super.render();
19251    this.div.hidden = true;
19252    this.div.setAttribute("role", "figure");
19253    this.addAltTextButton();
19254    if (this.#bitmap) {
19255      this.#createCanvas();
19256    } else {
19257      this.#getBitmap();
19258    }
19259    if (this.width && !this.annotationElementId) {
19260      const [parentWidth, parentHeight] = this.parentDimensions;
19261      this.setAt(baseX * parentWidth, baseY * parentHeight, this.width * parentWidth, this.height * parentHeight);
19262    }
19263    return this.div;
19264  }
19265  #createCanvas() {
19266    const {
19267      div
19268    } = this;
19269    let {
19270      width,
19271      height
19272    } = this.#bitmap;
19273    const [pageWidth, pageHeight] = this.pageDimensions;
19274    const MAX_RATIO = 0.75;
19275    if (this.width) {
19276      width = this.width * pageWidth;
19277      height = this.height * pageHeight;
19278    } else if (width > MAX_RATIO * pageWidth || height > MAX_RATIO * pageHeight) {
19279      const factor = Math.min(MAX_RATIO * pageWidth / width, MAX_RATIO * pageHeight / height);
19280      width *= factor;
19281      height *= factor;
19282    }
19283    const [parentWidth, parentHeight] = this.parentDimensions;
19284    this.setDims(width * parentWidth / pageWidth, height * parentHeight / pageHeight);
19285    this._uiManager.enableWaiting(false);
19286    const canvas = this.#canvas = document.createElement("canvas");
19287    canvas.setAttribute("role", "img");
19288    this.addContainer(canvas);
19289    if (!this._uiManager.useNewAltTextWhenAddingImage || !this._uiManager.useNewAltTextFlow || this.annotationElementId) {
19290      div.hidden = false;
vendor: 5,372 bytes, lines 19291-19434
19291    }
19292    this.#drawBitmap(width, height);
19293    this.#createObserver();
19294    if (!this.#hasBeenAddedInUndoStack) {
19295      this.parent.addUndoableEditor(this);
19296      this.#hasBeenAddedInUndoStack = true;
19297    }
19298    this._reportTelemetry({
19299      action: "inserted_image"
19300    });
19301    if (this.#bitmapFileName) {
19302      canvas.setAttribute("aria-label", this.#bitmapFileName);
19303    }
19304  }
19305  copyCanvas(maxDataDimension, maxPreviewDimension, createImageData = false) {
19306    if (!maxDataDimension) {
19307      maxDataDimension = 224;
19308    }
19309    const {
19310      width: bitmapWidth,
19311      height: bitmapHeight
19312    } = this.#bitmap;
19313    const outputScale = new OutputScale();
19314    let bitmap = this.#bitmap;
19315    let width = bitmapWidth,
19316      height = bitmapHeight;
19317    let canvas = null;
19318    if (maxPreviewDimension) {
19319      if (bitmapWidth > maxPreviewDimension || bitmapHeight > maxPreviewDimension) {
19320        const ratio = Math.min(maxPreviewDimension / bitmapWidth, maxPreviewDimension / bitmapHeight);
19321        width = Math.floor(bitmapWidth * ratio);
19322        height = Math.floor(bitmapHeight * ratio);
19323      }
19324      canvas = document.createElement("canvas");
19325      const scaledWidth = canvas.width = Math.ceil(width * outputScale.sx);
19326      const scaledHeight = canvas.height = Math.ceil(height * outputScale.sy);
19327      if (!this.#isSvg) {
19328        bitmap = this.#scaleBitmap(scaledWidth, scaledHeight);
19329      }
19330      const ctx = canvas.getContext("2d");
19331      ctx.filter = this._uiManager.hcmFilter;
19332      let white = "white",
19333        black = "#cfcfd8";
19334      if (this._uiManager.hcmFilter !== "none") {
19335        black = "black";
19336      } else if (window.matchMedia?.("(prefers-color-scheme: dark)").matches) {
19337        white = "#8f8f9d";
19338        black = "#42414d";
19339      }
19340      const boxDim = 15;
19341      const boxDimWidth = boxDim * outputScale.sx;
19342      const boxDimHeight = boxDim * outputScale.sy;
19343      const pattern = new OffscreenCanvas(boxDimWidth * 2, boxDimHeight * 2);
19344      const patternCtx = pattern.getContext("2d");
19345      patternCtx.fillStyle = white;
19346      patternCtx.fillRect(0, 0, boxDimWidth * 2, boxDimHeight * 2);
19347      patternCtx.fillStyle = black;
19348      patternCtx.fillRect(0, 0, boxDimWidth, boxDimHeight);
19349      patternCtx.fillRect(boxDimWidth, boxDimHeight, boxDimWidth, boxDimHeight);
19350      ctx.fillStyle = ctx.createPattern(pattern, "repeat");
19351      ctx.fillRect(0, 0, scaledWidth, scaledHeight);
19352      ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, scaledWidth, scaledHeight);
19353    }
19354    let imageData = null;
19355    if (createImageData) {
19356      let dataWidth, dataHeight;
19357      if (outputScale.symmetric && bitmap.width < maxDataDimension && bitmap.height < maxDataDimension) {
19358        dataWidth = bitmap.width;
19359        dataHeight = bitmap.height;
19360      } else {
19361        bitmap = this.#bitmap;
19362        if (bitmapWidth > maxDataDimension || bitmapHeight > maxDataDimension) {
19363          const ratio = Math.min(maxDataDimension / bitmapWidth, maxDataDimension / bitmapHeight);
19364          dataWidth = Math.floor(bitmapWidth * ratio);
19365          dataHeight = Math.floor(bitmapHeight * ratio);
19366          if (!this.#isSvg) {
19367            bitmap = this.#scaleBitmap(dataWidth, dataHeight);
19368          }
19369        }
19370      }
19371      const offscreen = new OffscreenCanvas(dataWidth, dataHeight);
19372      const offscreenCtx = offscreen.getContext("2d", {
19373        willReadFrequently: true
19374      });
19375      offscreenCtx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, dataWidth, dataHeight);
19376      imageData = {
19377        width: dataWidth,
19378        height: dataHeight,
19379        data: offscreenCtx.getImageData(0, 0, dataWidth, dataHeight).data
19380      };
19381    }
19382    return {
19383      canvas,
19384      width,
19385      height,
19386      imageData
19387    };
19388  }
19389  #setDimensions(width, height) {
19390    const [parentWidth, parentHeight] = this.parentDimensions;
19391    this.width = width / parentWidth;
19392    this.height = height / parentHeight;
19393    if (this._initialOptions?.isCentered) {
19394      this.center();
19395    } else {
19396      this.fixAndSetPosition();
19397    }
19398    this._initialOptions = null;
19399    if (this.#resizeTimeoutId !== null) {
19400      clearTimeout(this.#resizeTimeoutId);
19401    }
19402    const TIME_TO_WAIT = 200;
19403    this.#resizeTimeoutId = setTimeout(() => {
19404      this.#resizeTimeoutId = null;
19405      this.#drawBitmap(width, height);
19406    }, TIME_TO_WAIT);
19407  }
19408  #scaleBitmap(width, height) {
19409    const {
19410      width: bitmapWidth,
19411      height: bitmapHeight
19412    } = this.#bitmap;
19413    let newWidth = bitmapWidth;
19414    let newHeight = bitmapHeight;
19415    let bitmap = this.#bitmap;
19416    while (newWidth > 2 * width || newHeight > 2 * height) {
19417      const prevWidth = newWidth;
19418      const prevHeight = newHeight;
19419      if (newWidth > 2 * width) {
19420        newWidth = newWidth >= 16384 ? Math.floor(newWidth / 2) - 1 : Math.ceil(newWidth / 2);
19421      }
19422      if (newHeight > 2 * height) {
19423        newHeight = newHeight >= 16384 ? Math.floor(newHeight / 2) - 1 : Math.ceil(newHeight / 2);
19424      }
19425      const offscreen = new OffscreenCanvas(newWidth, newHeight);
19426      const ctx = offscreen.getContext("2d");
19427      ctx.drawImage(bitmap, 0, 0, prevWidth, prevHeight, 0, 0, newWidth, newHeight);
19428      bitmap = offscreen.transferToImageBitmap();
19429    }
19430    return bitmap;
19431  }
19432  #drawBitmap(width, height) {
19433    const outputScale = new OutputScale();
19434    const scaledWidth = Math.ceil(width * outputScale.sx);
vendor: 9,717 bytes, lines 19435-19759
19435    const scaledHeight = Math.ceil(height * outputScale.sy);
19436    const canvas = this.#canvas;
19437    if (!canvas || canvas.width === scaledWidth && canvas.height === scaledHeight) {
19438      return;
19439    }
19440    canvas.width = scaledWidth;
19441    canvas.height = scaledHeight;
19442    const bitmap = this.#isSvg ? this.#bitmap : this.#scaleBitmap(scaledWidth, scaledHeight);
19443    const ctx = canvas.getContext("2d");
19444    ctx.filter = this._uiManager.hcmFilter;
19445    ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, scaledWidth, scaledHeight);
19446  }
19447  getImageForAltText() {
19448    return this.#canvas;
19449  }
19450  #serializeBitmap(toUrl) {
19451    if (toUrl) {
19452      if (this.#isSvg) {
19453        const url = this._uiManager.imageManager.getSvgUrl(this.#bitmapId);
19454        if (url) {
19455          return url;
19456        }
19457      }
19458      const canvas = document.createElement("canvas");
19459      ({
19460        width: canvas.width,
19461        height: canvas.height
19462      } = this.#bitmap);
19463      const ctx = canvas.getContext("2d");
19464      ctx.drawImage(this.#bitmap, 0, 0);
19465      return canvas.toDataURL();
19466    }
19467    if (this.#isSvg) {
19468      const [pageWidth, pageHeight] = this.pageDimensions;
19469      const width = Math.round(this.width * pageWidth * PixelsPerInch.PDF_TO_CSS_UNITS);
19470      const height = Math.round(this.height * pageHeight * PixelsPerInch.PDF_TO_CSS_UNITS);
19471      const offscreen = new OffscreenCanvas(width, height);
19472      const ctx = offscreen.getContext("2d");
19473      ctx.drawImage(this.#bitmap, 0, 0, this.#bitmap.width, this.#bitmap.height, 0, 0, width, height);
19474      return offscreen.transferToImageBitmap();
19475    }
19476    return structuredClone(this.#bitmap);
19477  }
19478  #createObserver() {
19479    if (!this._uiManager._signal) {
19480      return;
19481    }
19482    this.#observer = new ResizeObserver(entries => {
19483      const rect = entries[0].contentRect;
19484      if (rect.width && rect.height) {
19485        this.#setDimensions(rect.width, rect.height);
19486      }
19487    });
19488    this.#observer.observe(this.div);
19489    this._uiManager._signal.addEventListener("abort", () => {
19490      this.#observer?.disconnect();
19491      this.#observer = null;
19492    }, {
19493      once: true
19494    });
19495  }
19496  static async deserialize(data, parent, uiManager) {
19497    let initialData = null;
19498    if (data instanceof StampAnnotationElement) {
19499      const {
19500        data: {
19501          rect,
19502          rotation,
19503          id,
19504          structParent,
19505          popupRef
19506        },
19507        container,
19508        parent: {
19509          page: {
19510            pageNumber
19511          }
19512        }
19513      } = data;
19514      const canvas = container.querySelector("canvas");
19515      const imageData = uiManager.imageManager.getFromCanvas(container.id, canvas);
19516      canvas.remove();
19517      const altText = (await parent._structTree.getAriaAttributes(`${AnnotationPrefix}${id}`))?.get("aria-label") || "";
19518      initialData = data = {
19519        annotationType: AnnotationEditorType.STAMP,
19520        bitmapId: imageData.id,
19521        bitmap: imageData.bitmap,
19522        pageIndex: pageNumber - 1,
19523        rect: rect.slice(0),
19524        rotation,
19525        id,
19526        deleted: false,
19527        accessibilityData: {
19528          decorative: false,
19529          altText
19530        },
19531        isSvg: false,
19532        structParent,
19533        popupRef
19534      };
19535    }
19536    const editor = await super.deserialize(data, parent, uiManager);
19537    const {
19538      rect,
19539      bitmap,
19540      bitmapUrl,
19541      bitmapId,
19542      isSvg,
19543      accessibilityData
19544    } = data;
19545    if (bitmapId && uiManager.imageManager.isValidId(bitmapId)) {
19546      editor.#bitmapId = bitmapId;
19547      if (bitmap) {
19548        editor.#bitmap = bitmap;
19549      }
19550    } else {
19551      editor.#bitmapUrl = bitmapUrl;
19552    }
19553    editor.#isSvg = isSvg;
19554    const [parentWidth, parentHeight] = editor.pageDimensions;
19555    editor.width = (rect[2] - rect[0]) / parentWidth;
19556    editor.height = (rect[3] - rect[1]) / parentHeight;
19557    editor.annotationElementId = data.id || null;
19558    if (accessibilityData) {
19559      editor.altTextData = accessibilityData;
19560    }
19561    editor._initialData = initialData;
19562    editor.#hasBeenAddedInUndoStack = !!initialData;
19563    return editor;
19564  }
19565  serialize(isForCopying = false, context = null) {
19566    if (this.isEmpty()) {
19567      return null;
19568    }
19569    if (this.deleted) {
19570      return this.serializeDeleted();
19571    }
19572    const serialized = {
19573      annotationType: AnnotationEditorType.STAMP,
19574      bitmapId: this.#bitmapId,
19575      pageIndex: this.pageIndex,
19576      rect: this.getRect(0, 0),
19577      rotation: this.rotation,
19578      isSvg: this.#isSvg,
19579      structTreeParentId: this._structTreeParentId
19580    };
19581    if (isForCopying) {
19582      serialized.bitmapUrl = this.#serializeBitmap(true);
19583      serialized.accessibilityData = this.serializeAltText(true);
19584      return serialized;
19585    }
19586    const {
19587      decorative,
19588      altText
19589    } = this.serializeAltText(false);
19590    if (!decorative && altText) {
19591      serialized.accessibilityData = {
19592        type: "Figure",
19593        alt: altText
19594      };
19595    }
19596    if (this.annotationElementId) {
19597      const changes = this.#hasElementChanged(serialized);
19598      if (changes.isSame) {
19599        return null;
19600      }
19601      if (changes.isSameAltText) {
19602        delete serialized.accessibilityData;
19603      } else {
19604        serialized.accessibilityData.structParent = this._initialData.structParent ?? -1;
19605      }
19606    }
19607    serialized.id = this.annotationElementId;
19608    if (context === null) {
19609      return serialized;
19610    }
19611    context.stamps ||= new Map();
19612    const area = this.#isSvg ? (serialized.rect[2] - serialized.rect[0]) * (serialized.rect[3] - serialized.rect[1]) : null;
19613    if (!context.stamps.has(this.#bitmapId)) {
19614      context.stamps.set(this.#bitmapId, {
19615        area,
19616        serialized
19617      });
19618      serialized.bitmap = this.#serializeBitmap(false);
19619    } else if (this.#isSvg) {
19620      const prevData = context.stamps.get(this.#bitmapId);
19621      if (area > prevData.area) {
19622        prevData.area = area;
19623        prevData.serialized.bitmap.close();
19624        prevData.serialized.bitmap = this.#serializeBitmap(false);
19625      }
19626    }
19627    return serialized;
19628  }
19629  #hasElementChanged(serialized) {
19630    const {
19631      rect,
19632      pageIndex,
19633      accessibilityData: {
19634        altText
19635      }
19636    } = this._initialData;
19637    const isSameRect = serialized.rect.every((x, i) => Math.abs(x - rect[i]) < 1);
19638    const isSamePageIndex = serialized.pageIndex === pageIndex;
19639    const isSameAltText = (serialized.accessibilityData?.alt || "") === altText;
19640    return {
19641      isSame: isSameRect && isSamePageIndex && isSameAltText,
19642      isSameAltText
19643    };
19644  }
19645  renderAnnotationElement(annotation) {
19646    annotation.updateEdited({
19647      rect: this.getRect(0, 0)
19648    });
19649    return null;
19650  }
19651}
19652
19653;// ./src/display/editor/annotation_editor_layer.js
19654
19655
19656
19657
19658
19659
19660
19661class AnnotationEditorLayer {
19662  #accessibilityManager;
19663  #allowClick = false;
19664  #annotationLayer = null;
19665  #clickAC = null;
19666  #editorFocusTimeoutId = null;
19667  #editors = new Map();
19668  #hadPointerDown = false;
19669  #isCleaningUp = false;
19670  #isDisabling = false;
19671  #textLayer = null;
19672  #textSelectionAC = null;
19673  #uiManager;
19674  static _initialized = false;
19675  static #editorTypes = new Map([FreeTextEditor, InkEditor, StampEditor, HighlightEditor].map(type => [type._editorType, type]));
19676  constructor({
19677    uiManager,
19678    pageIndex,
19679    div,
19680    structTreeLayer,
19681    accessibilityManager,
19682    annotationLayer,
19683    drawLayer,
19684    textLayer,
19685    viewport,
19686    l10n
19687  }) {
19688    const editorTypes = [...AnnotationEditorLayer.#editorTypes.values()];
19689    if (!AnnotationEditorLayer._initialized) {
19690      AnnotationEditorLayer._initialized = true;
19691      for (const editorType of editorTypes) {
19692        editorType.initialize(l10n, uiManager);
19693      }
19694    }
19695    uiManager.registerEditorTypes(editorTypes);
19696    this.#uiManager = uiManager;
19697    this.pageIndex = pageIndex;
19698    this.div = div;
19699    this.#accessibilityManager = accessibilityManager;
19700    this.#annotationLayer = annotationLayer;
19701    this.viewport = viewport;
19702    this.#textLayer = textLayer;
19703    this.drawLayer = drawLayer;
19704    this._structTree = structTreeLayer;
19705    this.#uiManager.addLayer(this);
19706  }
19707  get isEmpty() {
19708    return this.#editors.size === 0;
19709  }
19710  get isInvisible() {
19711    return this.isEmpty && this.#uiManager.getMode() === AnnotationEditorType.NONE;
19712  }
19713  updateToolbar(mode) {
19714    this.#uiManager.updateToolbar(mode);
19715  }
19716  updateMode(mode = this.#uiManager.getMode()) {
19717    this.#cleanup();
19718    switch (mode) {
19719      case AnnotationEditorType.NONE:
19720        this.disableTextSelection();
19721        this.togglePointerEvents(false);
19722        this.toggleAnnotationLayerPointerEvents(true);
19723        this.disableClick();
19724        return;
19725      case AnnotationEditorType.INK:
19726        this.addInkEditorIfNeeded(false);
19727        this.disableTextSelection();
19728        this.togglePointerEvents(true);
19729        this.disableClick();
19730        break;
19731      case AnnotationEditorType.HIGHLIGHT:
19732        this.enableTextSelection();
19733        this.togglePointerEvents(false);
19734        this.disableClick();
19735        break;
19736      default:
19737        this.disableTextSelection();
19738        this.togglePointerEvents(true);
19739        this.enableClick();
19740    }
19741    this.toggleAnnotationLayerPointerEvents(false);
19742    const {
19743      classList
19744    } = this.div;
19745    for (const editorType of AnnotationEditorLayer.#editorTypes.values()) {
19746      classList.toggle(`${editorType._type}Editing`, mode === editorType._editorType);
19747    }
19748    this.div.hidden = false;
19749  }
19750  hasTextLayer(textLayer) {
19751    return textLayer === this.#textLayer?.div;
19752  }
19753  addInkEditorIfNeeded(isCommitting) {
19754    if (this.#uiManager.getMode() !== AnnotationEditorType.INK) {
19755      return;
19756    }
19757    if (!isCommitting) {
19758      for (const editor of this.#editors.values()) {
19759        if (editor.isEmpty()) {
vendor: 6,583 bytes, lines 19760-19974
19760          editor.setInBackground();
19761          return;
19762        }
19763      }
19764    }
19765    const editor = this.createAndAddNewEditor({
19766      offsetX: 0,
19767      offsetY: 0
19768    }, false);
19769    editor.setInBackground();
19770  }
19771  setEditingState(isEditing) {
19772    this.#uiManager.setEditingState(isEditing);
19773  }
19774  addCommands(params) {
19775    this.#uiManager.addCommands(params);
19776  }
19777  toggleDrawing(enabled = false) {
19778    this.div.classList.toggle("drawing", !enabled);
19779  }
19780  togglePointerEvents(enabled = false) {
19781    this.div.classList.toggle("disabled", !enabled);
19782  }
19783  toggleAnnotationLayerPointerEvents(enabled = false) {
19784    this.#annotationLayer?.div.classList.toggle("disabled", !enabled);
19785  }
19786  async enable() {
19787    this.div.tabIndex = 0;
19788    this.togglePointerEvents(true);
19789    const annotationElementIds = new Set();
19790    for (const editor of this.#editors.values()) {
19791      editor.enableEditing();
19792      editor.show(true);
19793      if (editor.annotationElementId) {
19794        this.#uiManager.removeChangedExistingAnnotation(editor);
19795        annotationElementIds.add(editor.annotationElementId);
19796      }
19797    }
19798    if (!this.#annotationLayer) {
19799      return;
19800    }
19801    const editables = this.#annotationLayer.getEditableAnnotations();
19802    for (const editable of editables) {
19803      editable.hide();
19804      if (this.#uiManager.isDeletedAnnotationElement(editable.data.id)) {
19805        continue;
19806      }
19807      if (annotationElementIds.has(editable.data.id)) {
19808        continue;
19809      }
19810      const editor = await this.deserialize(editable);
19811      if (!editor) {
19812        continue;
19813      }
19814      this.addOrRebuild(editor);
19815      editor.enableEditing();
19816    }
19817  }
19818  disable() {
19819    this.#isDisabling = true;
19820    this.div.tabIndex = -1;
19821    this.togglePointerEvents(false);
19822    const changedAnnotations = new Map();
19823    const resetAnnotations = new Map();
19824    for (const editor of this.#editors.values()) {
19825      editor.disableEditing();
19826      if (!editor.annotationElementId) {
19827        continue;
19828      }
19829      if (editor.serialize() !== null) {
19830        changedAnnotations.set(editor.annotationElementId, editor);
19831        continue;
19832      } else {
19833        resetAnnotations.set(editor.annotationElementId, editor);
19834      }
19835      this.getEditableAnnotation(editor.annotationElementId)?.show();
19836      editor.remove();
19837    }
19838    if (this.#annotationLayer) {
19839      const editables = this.#annotationLayer.getEditableAnnotations();
19840      for (const editable of editables) {
19841        const {
19842          id
19843        } = editable.data;
19844        if (this.#uiManager.isDeletedAnnotationElement(id)) {
19845          continue;
19846        }
19847        let editor = resetAnnotations.get(id);
19848        if (editor) {
19849          editor.resetAnnotationElement(editable);
19850          editor.show(false);
19851          editable.show();
19852          continue;
19853        }
19854        editor = changedAnnotations.get(id);
19855        if (editor) {
19856          this.#uiManager.addChangedExistingAnnotation(editor);
19857          if (editor.renderAnnotationElement(editable)) {
19858            editor.show(false);
19859          }
19860        }
19861        editable.show();
19862      }
19863    }
19864    this.#cleanup();
19865    if (this.isEmpty) {
19866      this.div.hidden = true;
19867    }
19868    const {
19869      classList
19870    } = this.div;
19871    for (const editorType of AnnotationEditorLayer.#editorTypes.values()) {
19872      classList.remove(`${editorType._type}Editing`);
19873    }
19874    this.disableTextSelection();
19875    this.toggleAnnotationLayerPointerEvents(true);
19876    this.#isDisabling = false;
19877  }
19878  getEditableAnnotation(id) {
19879    return this.#annotationLayer?.getEditableAnnotation(id) || null;
19880  }
19881  setActiveEditor(editor) {
19882    const currentActive = this.#uiManager.getActive();
19883    if (currentActive === editor) {
19884      return;
19885    }
19886    this.#uiManager.setActiveEditor(editor);
19887  }
19888  enableTextSelection() {
19889    this.div.tabIndex = -1;
19890    if (this.#textLayer?.div && !this.#textSelectionAC) {
19891      this.#textSelectionAC = new AbortController();
19892      const signal = this.#uiManager.combinedSignal(this.#textSelectionAC);
19893      this.#textLayer.div.addEventListener("pointerdown", this.#textLayerPointerDown.bind(this), {
19894        signal
19895      });
19896      this.#textLayer.div.classList.add("highlighting");
19897    }
19898  }
19899  disableTextSelection() {
19900    this.div.tabIndex = 0;
19901    if (this.#textLayer?.div && this.#textSelectionAC) {
19902      this.#textSelectionAC.abort();
19903      this.#textSelectionAC = null;
19904      this.#textLayer.div.classList.remove("highlighting");
19905    }
19906  }
19907  #textLayerPointerDown(event) {
19908    this.#uiManager.unselectAll();
19909    const {
19910      target
19911    } = event;
19912    if (target === this.#textLayer.div || (target.getAttribute("role") === "img" || target.classList.contains("endOfContent")) && this.#textLayer.div.contains(target)) {
19913      const {
19914        isMac
19915      } = util_FeatureTest.platform;
19916      if (event.button !== 0 || event.ctrlKey && isMac) {
19917        return;
19918      }
19919      this.#uiManager.showAllEditors("highlight", true, true);
19920      this.#textLayer.div.classList.add("free");
19921      this.toggleDrawing();
19922      HighlightEditor.startHighlighting(this, this.#uiManager.direction === "ltr", {
19923        target: this.#textLayer.div,
19924        x: event.x,
19925        y: event.y
19926      });
19927      this.#textLayer.div.addEventListener("pointerup", () => {
19928        this.#textLayer.div.classList.remove("free");
19929        this.toggleDrawing(true);
19930      }, {
19931        once: true,
19932        signal: this.#uiManager._signal
19933      });
19934      event.preventDefault();
19935    }
19936  }
19937  enableClick() {
19938    if (this.#clickAC) {
19939      return;
19940    }
19941    this.#clickAC = new AbortController();
19942    const signal = this.#uiManager.combinedSignal(this.#clickAC);
19943    this.div.addEventListener("pointerdown", this.pointerdown.bind(this), {
19944      signal
19945    });
19946    this.div.addEventListener("pointerup", this.pointerup.bind(this), {
19947      signal
19948    });
19949  }
19950  disableClick() {
19951    this.#clickAC?.abort();
19952    this.#clickAC = null;
19953  }
19954  attach(editor) {
19955    this.#editors.set(editor.id, editor);
19956    const {
19957      annotationElementId
19958    } = editor;
19959    if (annotationElementId && this.#uiManager.isDeletedAnnotationElement(annotationElementId)) {
19960      this.#uiManager.removeDeletedAnnotationElement(editor);
19961    }
19962  }
19963  detach(editor) {
19964    this.#editors.delete(editor.id);
19965    this.#accessibilityManager?.removePointerInTextLayer(editor.contentDiv);
19966    if (!this.#isDisabling && editor.annotationElementId) {
19967      this.#uiManager.addDeletedAnnotationElement(editor);
19968    }
19969  }
19970  remove(editor) {
19971    this.detach(editor);
19972    this.#uiManager.removeEditor(editor);
19973    editor.div.remove();
19974    editor.isAttachedToDOM = false;
vendor: 5,011 bytes, lines 19975-20159
19975    if (!this.#isCleaningUp) {
19976      this.addInkEditorIfNeeded(false);
19977    }
19978  }
19979  changeParent(editor) {
19980    if (editor.parent === this) {
19981      return;
19982    }
19983    if (editor.parent && editor.annotationElementId) {
19984      this.#uiManager.addDeletedAnnotationElement(editor.annotationElementId);
19985      AnnotationEditor.deleteAnnotationElement(editor);
19986      editor.annotationElementId = null;
19987    }
19988    this.attach(editor);
19989    editor.parent?.detach(editor);
19990    editor.setParent(this);
19991    if (editor.div && editor.isAttachedToDOM) {
19992      editor.div.remove();
19993      this.div.append(editor.div);
19994    }
19995  }
19996  add(editor) {
19997    if (editor.parent === this && editor.isAttachedToDOM) {
19998      return;
19999    }
20000    this.changeParent(editor);
20001    this.#uiManager.addEditor(editor);
20002    this.attach(editor);
20003    if (!editor.isAttachedToDOM) {
20004      const div = editor.render();
20005      this.div.append(div);
20006      editor.isAttachedToDOM = true;
20007    }
20008    editor.fixAndSetPosition();
20009    editor.onceAdded();
20010    this.#uiManager.addToAnnotationStorage(editor);
20011    editor._reportTelemetry(editor.telemetryInitialData);
20012  }
20013  moveEditorInDOM(editor) {
20014    if (!editor.isAttachedToDOM) {
20015      return;
20016    }
20017    const {
20018      activeElement
20019    } = document;
20020    if (editor.div.contains(activeElement) && !this.#editorFocusTimeoutId) {
20021      editor._focusEventsAllowed = false;
20022      this.#editorFocusTimeoutId = setTimeout(() => {
20023        this.#editorFocusTimeoutId = null;
20024        if (!editor.div.contains(document.activeElement)) {
20025          editor.div.addEventListener("focusin", () => {
20026            editor._focusEventsAllowed = true;
20027          }, {
20028            once: true,
20029            signal: this.#uiManager._signal
20030          });
20031          activeElement.focus();
20032        } else {
20033          editor._focusEventsAllowed = true;
20034        }
20035      }, 0);
20036    }
20037    editor._structTreeParentId = this.#accessibilityManager?.moveElementInDOM(this.div, editor.div, editor.contentDiv, true);
20038  }
20039  addOrRebuild(editor) {
20040    if (editor.needsToBeRebuilt()) {
20041      editor.parent ||= this;
20042      editor.rebuild();
20043      editor.show();
20044    } else {
20045      this.add(editor);
20046    }
20047  }
20048  addUndoableEditor(editor) {
20049    const cmd = () => editor._uiManager.rebuild(editor);
20050    const undo = () => {
20051      editor.remove();
20052    };
20053    this.addCommands({
20054      cmd,
20055      undo,
20056      mustExec: false
20057    });
20058  }
20059  getNextId() {
20060    return this.#uiManager.getId();
20061  }
20062  get #currentEditorType() {
20063    return AnnotationEditorLayer.#editorTypes.get(this.#uiManager.getMode());
20064  }
20065  combinedSignal(ac) {
20066    return this.#uiManager.combinedSignal(ac);
20067  }
20068  #createNewEditor(params) {
20069    const editorType = this.#currentEditorType;
20070    return editorType ? new editorType.prototype.constructor(params) : null;
20071  }
20072  canCreateNewEmptyEditor() {
20073    return this.#currentEditorType?.canCreateNewEmptyEditor();
20074  }
20075  pasteEditor(mode, params) {
20076    this.#uiManager.updateToolbar(mode);
20077    this.#uiManager.updateMode(mode);
20078    const {
20079      offsetX,
20080      offsetY
20081    } = this.#getCenterPoint();
20082    const id = this.getNextId();
20083    const editor = this.#createNewEditor({
20084      parent: this,
20085      id,
20086      x: offsetX,
20087      y: offsetY,
20088      uiManager: this.#uiManager,
20089      isCentered: true,
20090      ...params
20091    });
20092    if (editor) {
20093      this.add(editor);
20094    }
20095  }
20096  async deserialize(data) {
20097    return (await AnnotationEditorLayer.#editorTypes.get(data.annotationType ?? data.annotationEditorType)?.deserialize(data, this, this.#uiManager)) || null;
20098  }
20099  createAndAddNewEditor(event, isCentered, data = {}) {
20100    const id = this.getNextId();
20101    const editor = this.#createNewEditor({
20102      parent: this,
20103      id,
20104      x: event.offsetX,
20105      y: event.offsetY,
20106      uiManager: this.#uiManager,
20107      isCentered,
20108      ...data
20109    });
20110    if (editor) {
20111      this.add(editor);
20112    }
20113    return editor;
20114  }
20115  #getCenterPoint() {
20116    const {
20117      x,
20118      y,
20119      width,
20120      height
20121    } = this.div.getBoundingClientRect();
20122    const tlX = Math.max(0, x);
20123    const tlY = Math.max(0, y);
20124    const brX = Math.min(window.innerWidth, x + width);
20125    const brY = Math.min(window.innerHeight, y + height);
20126    const centerX = (tlX + brX) / 2 - x;
20127    const centerY = (tlY + brY) / 2 - y;
20128    const [offsetX, offsetY] = this.viewport.rotation % 180 === 0 ? [centerX, centerY] : [centerY, centerX];
20129    return {
20130      offsetX,
20131      offsetY
20132    };
20133  }
20134  addNewEditor() {
20135    this.createAndAddNewEditor(this.#getCenterPoint(), true);
20136  }
20137  setSelected(editor) {
20138    this.#uiManager.setSelected(editor);
20139  }
20140  toggleSelected(editor) {
20141    this.#uiManager.toggleSelected(editor);
20142  }
20143  unselect(editor) {
20144    this.#uiManager.unselect(editor);
20145  }
20146  pointerup(event) {
20147    const {
20148      isMac
20149    } = util_FeatureTest.platform;
20150    if (event.button !== 0 || event.ctrlKey && isMac) {
20151      return;
20152    }
20153    if (event.target !== this.div) {
20154      return;
20155    }
20156    if (!this.#hadPointerDown) {
20157      return;
20158    }
20159    this.#hadPointerDown = false;
vendor: 14,263 bytes, lines 20160-20521
20160    if (!this.#allowClick) {
20161      this.#allowClick = true;
20162      return;
20163    }
20164    if (this.#uiManager.getMode() === AnnotationEditorType.STAMP) {
20165      this.#uiManager.unselectAll();
20166      return;
20167    }
20168    this.createAndAddNewEditor(event, false);
20169  }
20170  pointerdown(event) {
20171    if (this.#uiManager.getMode() === AnnotationEditorType.HIGHLIGHT) {
20172      this.enableTextSelection();
20173    }
20174    if (this.#hadPointerDown) {
20175      this.#hadPointerDown = false;
20176      return;
20177    }
20178    const {
20179      isMac
20180    } = util_FeatureTest.platform;
20181    if (event.button !== 0 || event.ctrlKey && isMac) {
20182      return;
20183    }
20184    if (event.target !== this.div) {
20185      return;
20186    }
20187    this.#hadPointerDown = true;
20188    const editor = this.#uiManager.getActive();
20189    this.#allowClick = !editor || editor.isEmpty();
20190  }
20191  findNewParent(editor, x, y) {
20192    const layer = this.#uiManager.findParent(x, y);
20193    if (layer === null || layer === this) {
20194      return false;
20195    }
20196    layer.changeParent(editor);
20197    return true;
20198  }
20199  destroy() {
20200    if (this.#uiManager.getActive()?.parent === this) {
20201      this.#uiManager.commitOrRemove();
20202      this.#uiManager.setActiveEditor(null);
20203    }
20204    if (this.#editorFocusTimeoutId) {
20205      clearTimeout(this.#editorFocusTimeoutId);
20206      this.#editorFocusTimeoutId = null;
20207    }
20208    for (const editor of this.#editors.values()) {
20209      this.#accessibilityManager?.removePointerInTextLayer(editor.contentDiv);
20210      editor.setParent(null);
20211      editor.isAttachedToDOM = false;
20212      editor.div.remove();
20213    }
20214    this.div = null;
20215    this.#editors.clear();
20216    this.#uiManager.removeLayer(this);
20217  }
20218  #cleanup() {
20219    this.#isCleaningUp = true;
20220    for (const editor of this.#editors.values()) {
20221      if (editor.isEmpty()) {
20222        editor.remove();
20223      }
20224    }
20225    this.#isCleaningUp = false;
20226  }
20227  render({
20228    viewport
20229  }) {
20230    this.viewport = viewport;
20231    setLayerDimensions(this.div, viewport);
20232    for (const editor of this.#uiManager.getEditors(this.pageIndex)) {
20233      this.add(editor);
20234      editor.rebuild();
20235    }
20236    this.updateMode();
20237  }
20238  update({
20239    viewport
20240  }) {
20241    this.#uiManager.commitOrRemove();
20242    this.#cleanup();
20243    const oldRotation = this.viewport.rotation;
20244    const rotation = viewport.rotation;
20245    this.viewport = viewport;
20246    setLayerDimensions(this.div, {
20247      rotation
20248    });
20249    if (oldRotation !== rotation) {
20250      for (const editor of this.#editors.values()) {
20251        editor.rotate(rotation);
20252      }
20253    }
20254    this.addInkEditorIfNeeded(false);
20255  }
20256  get pageDimensions() {
20257    const {
20258      pageWidth,
20259      pageHeight
20260    } = this.viewport.rawDims;
20261    return [pageWidth, pageHeight];
20262  }
20263  get scale() {
20264    return this.#uiManager.viewParameters.realScale;
20265  }
20266}
20267
20268;// ./src/display/draw_layer.js
20269
20270
20271class DrawLayer {
20272  #parent = null;
20273  #id = 0;
20274  #mapping = new Map();
20275  #toUpdate = new Map();
20276  constructor({
20277    pageIndex
20278  }) {
20279    this.pageIndex = pageIndex;
20280  }
20281  setParent(parent) {
20282    if (!this.#parent) {
20283      this.#parent = parent;
20284      return;
20285    }
20286    if (this.#parent !== parent) {
20287      if (this.#mapping.size > 0) {
20288        for (const root of this.#mapping.values()) {
20289          root.remove();
20290          parent.append(root);
20291        }
20292      }
20293      this.#parent = parent;
20294    }
20295  }
20296  static get _svgFactory() {
20297    return shadow(this, "_svgFactory", new DOMSVGFactory());
20298  }
20299  static #setBox(element, {
20300    x = 0,
20301    y = 0,
20302    width = 1,
20303    height = 1
20304  } = {}) {
20305    const {
20306      style
20307    } = element;
20308    style.top = `${100 * y}%`;
20309    style.left = `${100 * x}%`;
20310    style.width = `${100 * width}%`;
20311    style.height = `${100 * height}%`;
20312  }
20313  #createSVG(box) {
20314    const svg = DrawLayer._svgFactory.create(1, 1, true);
20315    this.#parent.append(svg);
20316    svg.setAttribute("aria-hidden", true);
20317    DrawLayer.#setBox(svg, box);
20318    return svg;
20319  }
20320  #createClipPath(defs, pathId) {
20321    const clipPath = DrawLayer._svgFactory.createElement("clipPath");
20322    defs.append(clipPath);
20323    const clipPathId = `clip_${pathId}`;
20324    clipPath.setAttribute("id", clipPathId);
20325    clipPath.setAttribute("clipPathUnits", "objectBoundingBox");
20326    const clipPathUse = DrawLayer._svgFactory.createElement("use");
20327    clipPath.append(clipPathUse);
20328    clipPathUse.setAttribute("href", `#${pathId}`);
20329    clipPathUse.classList.add("clip");
20330    return clipPathId;
20331  }
20332  draw(outlines, color, opacity, isPathUpdatable = false) {
20333    const id = this.#id++;
20334    const root = this.#createSVG(outlines.box);
20335    root.classList.add(...outlines.classNamesForDrawing);
20336    const defs = DrawLayer._svgFactory.createElement("defs");
20337    root.append(defs);
20338    const path = DrawLayer._svgFactory.createElement("path");
20339    defs.append(path);
20340    const pathId = `path_p${this.pageIndex}_${id}`;
20341    path.setAttribute("id", pathId);
20342    path.setAttribute("d", outlines.toSVGPath());
20343    if (isPathUpdatable) {
20344      this.#toUpdate.set(id, path);
20345    }
20346    const clipPathId = this.#createClipPath(defs, pathId);
20347    const use = DrawLayer._svgFactory.createElement("use");
20348    root.append(use);
20349    root.setAttribute("fill", color);
20350    root.setAttribute("fill-opacity", opacity);
20351    use.setAttribute("href", `#${pathId}`);
20352    this.#mapping.set(id, root);
20353    return {
20354      id,
20355      clipPathId: `url(#${clipPathId})`
20356    };
20357  }
20358  drawOutline(outlines) {
20359    const id = this.#id++;
20360    const root = this.#createSVG(outlines.box);
20361    root.classList.add(...outlines.classNamesForOutlining);
20362    const defs = DrawLayer._svgFactory.createElement("defs");
20363    root.append(defs);
20364    const path = DrawLayer._svgFactory.createElement("path");
20365    defs.append(path);
20366    const pathId = `path_p${this.pageIndex}_${id}`;
20367    path.setAttribute("id", pathId);
20368    path.setAttribute("d", outlines.toSVGPath());
20369    path.setAttribute("vector-effect", "non-scaling-stroke");
20370    let maskId;
20371    if (outlines.mustRemoveSelfIntersections) {
20372      const mask = DrawLayer._svgFactory.createElement("mask");
20373      defs.append(mask);
20374      maskId = `mask_p${this.pageIndex}_${id}`;
20375      mask.setAttribute("id", maskId);
20376      mask.setAttribute("maskUnits", "objectBoundingBox");
20377      const rect = DrawLayer._svgFactory.createElement("rect");
20378      mask.append(rect);
20379      rect.setAttribute("width", "1");
20380      rect.setAttribute("height", "1");
20381      rect.setAttribute("fill", "white");
20382      const use = DrawLayer._svgFactory.createElement("use");
20383      mask.append(use);
20384      use.setAttribute("href", `#${pathId}`);
20385      use.setAttribute("stroke", "none");
20386      use.setAttribute("fill", "black");
20387      use.setAttribute("fill-rule", "nonzero");
20388      use.classList.add("mask");
20389    }
20390    const use1 = DrawLayer._svgFactory.createElement("use");
20391    root.append(use1);
20392    use1.setAttribute("href", `#${pathId}`);
20393    if (maskId) {
20394      use1.setAttribute("mask", `url(#${maskId})`);
20395    }
20396    const use2 = use1.cloneNode();
20397    root.append(use2);
20398    use1.classList.add("mainOutline");
20399    use2.classList.add("secondaryOutline");
20400    this.#mapping.set(id, root);
20401    return id;
20402  }
20403  finalizeLine(id, line) {
20404    const path = this.#toUpdate.get(id);
20405    this.#toUpdate.delete(id);
20406    this.updateBox(id, line.box);
20407    path.setAttribute("d", line.toSVGPath());
20408  }
20409  updateLine(id, line) {
20410    const root = this.#mapping.get(id);
20411    const defs = root.firstChild;
20412    const path = defs.firstChild;
20413    path.setAttribute("d", line.toSVGPath());
20414  }
20415  updatePath(id, line) {
20416    this.#toUpdate.get(id).setAttribute("d", line.toSVGPath());
20417  }
20418  updateBox(id, box) {
20419    DrawLayer.#setBox(this.#mapping.get(id), box);
20420  }
20421  show(id, visible) {
20422    this.#mapping.get(id).classList.toggle("hidden", !visible);
20423  }
20424  rotate(id, angle) {
20425    this.#mapping.get(id).setAttribute("data-main-rotation", angle);
20426  }
20427  changeColor(id, color) {
20428    this.#mapping.get(id).setAttribute("fill", color);
20429  }
20430  changeOpacity(id, opacity) {
20431    this.#mapping.get(id).setAttribute("fill-opacity", opacity);
20432  }
20433  addClass(id, className) {
20434    this.#mapping.get(id).classList.add(className);
20435  }
20436  removeClass(id, className) {
20437    this.#mapping.get(id).classList.remove(className);
20438  }
20439  getSVGRoot(id) {
20440    return this.#mapping.get(id);
20441  }
20442  remove(id) {
20443    this.#toUpdate.delete(id);
20444    if (this.#parent === null) {
20445      return;
20446    }
20447    this.#mapping.get(id).remove();
20448    this.#mapping.delete(id);
20449  }
20450  destroy() {
20451    this.#parent = null;
20452    for (const root of this.#mapping.values()) {
20453      root.remove();
20454    }
20455    this.#mapping.clear();
20456    this.#toUpdate.clear();
20457  }
20458}
20459
20460;// ./src/pdf.js
20461
20462
20463
20464
20465
20466
20467
20468
20469
20470
20471
20472
20473
20474const pdfjsVersion = "4.8.69";
20475const pdfjsBuild = "3634dab10";
20476
20477var __webpack_exports__AbortException = __webpack_exports__.AbortException;
20478var __webpack_exports__AnnotationEditorLayer = __webpack_exports__.AnnotationEditorLayer;
20479var __webpack_exports__AnnotationEditorParamsType = __webpack_exports__.AnnotationEditorParamsType;
20480var __webpack_exports__AnnotationEditorType = __webpack_exports__.AnnotationEditorType;
20481var __webpack_exports__AnnotationEditorUIManager = __webpack_exports__.AnnotationEditorUIManager;
20482var __webpack_exports__AnnotationLayer = __webpack_exports__.AnnotationLayer;
20483var __webpack_exports__AnnotationMode = __webpack_exports__.AnnotationMode;
20484var __webpack_exports__ColorPicker = __webpack_exports__.ColorPicker;
20485var __webpack_exports__DOMSVGFactory = __webpack_exports__.DOMSVGFactory;
20486var __webpack_exports__DrawLayer = __webpack_exports__.DrawLayer;
20487var __webpack_exports__FeatureTest = __webpack_exports__.FeatureTest;
20488var __webpack_exports__GlobalWorkerOptions = __webpack_exports__.GlobalWorkerOptions;
20489var __webpack_exports__ImageKind = __webpack_exports__.ImageKind;
20490var __webpack_exports__InvalidPDFException = __webpack_exports__.InvalidPDFException;
20491var __webpack_exports__MissingPDFException = __webpack_exports__.MissingPDFException;
20492var __webpack_exports__OPS = __webpack_exports__.OPS;
20493var __webpack_exports__OutputScale = __webpack_exports__.OutputScale;
20494var __webpack_exports__PDFDataRangeTransport = __webpack_exports__.PDFDataRangeTransport;
20495var __webpack_exports__PDFDateString = __webpack_exports__.PDFDateString;
20496var __webpack_exports__PDFWorker = __webpack_exports__.PDFWorker;
20497var __webpack_exports__PasswordResponses = __webpack_exports__.PasswordResponses;
20498var __webpack_exports__PermissionFlag = __webpack_exports__.PermissionFlag;
20499var __webpack_exports__PixelsPerInch = __webpack_exports__.PixelsPerInch;
20500var __webpack_exports__RenderingCancelledException = __webpack_exports__.RenderingCancelledException;
20501var __webpack_exports__TextLayer = __webpack_exports__.TextLayer;
20502var __webpack_exports__UnexpectedResponseException = __webpack_exports__.UnexpectedResponseException;
20503var __webpack_exports__Util = __webpack_exports__.Util;
20504var __webpack_exports__VerbosityLevel = __webpack_exports__.VerbosityLevel;
20505var __webpack_exports__XfaLayer = __webpack_exports__.XfaLayer;
20506var __webpack_exports__build = __webpack_exports__.build;
20507var __webpack_exports__createValidAbsoluteUrl = __webpack_exports__.createValidAbsoluteUrl;
20508var __webpack_exports__fetchData = __webpack_exports__.fetchData;
20509var __webpack_exports__getDocument = __webpack_exports__.getDocument;
20510var __webpack_exports__getFilenameFromUrl = __webpack_exports__.getFilenameFromUrl;
20511var __webpack_exports__getPdfFilenameFromUrl = __webpack_exports__.getPdfFilenameFromUrl;
20512var __webpack_exports__getXfaPageViewport = __webpack_exports__.getXfaPageViewport;
20513var __webpack_exports__isDataScheme = __webpack_exports__.isDataScheme;
20514var __webpack_exports__isPdfFile = __webpack_exports__.isPdfFile;
20515var __webpack_exports__noContextMenu = __webpack_exports__.noContextMenu;
20516var __webpack_exports__normalizeUnicode = __webpack_exports__.normalizeUnicode;
20517var __webpack_exports__setLayerDimensions = __webpack_exports__.setLayerDimensions;
20518var __webpack_exports__shadow = __webpack_exports__.shadow;
20519var __webpack_exports__version = __webpack_exports__.version;
20520export { __webpack_exports__AbortException as AbortException, __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__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__MissingPDFException as MissingPDFException, __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__TextLayer as TextLayer, __webpack_exports__UnexpectedResponseException as UnexpectedResponseException, __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__version as version };
20521
20522//# sourceMappingURL=pdf.mjs.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.