PageSourceSearch

https://magazine.wikimilano.it/vendor/pdfjs/pdf.js

js wikimilano.it collected 2026-10-02 08:12:27 UTC 849,976 bytes, 27,924 lines download raw bytes

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/**
24 * pdfjsVersion = 6.1.200
25 * pdfjsBuild = 6353acefe
26 */
27
28;// ./src/shared/util.js
29const isNodeJS = typeof process === "object" && process + "" === "[object process]" && !process.versions.nw && !(process.versions.electron && process.type && process.type !== "browser");
30const BBOX_INIT = [Infinity, Infinity, -Infinity, -Infinity];
31const F32_BBOX_INIT = new Float32Array(BBOX_INIT);
32const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
33const LINE_FACTOR = 1.35;
34const LINE_DESCENT_FACTOR = 0.35;
35const BASELINE_FACTOR = LINE_DESCENT_FACTOR / LINE_FACTOR
vendor: 9,864 bytes, lines 35-483
35;
36const SVG_NS = "http://www.w3.org/2000/svg";
37const RenderingIntentFlag = {
38  ANY: 0x01,
39  DISPLAY: 0x02,
40  PRINT: 0x04,
41  SAVE: 0x08,
42  ANNOTATIONS_FORMS: 0x10,
43  ANNOTATIONS_STORAGE: 0x20,
44  ANNOTATIONS_DISABLE: 0x40,
45  IS_EDITING: 0x80,
46  OPLIST: 0x100
47};
48const AnnotationMode = {
49  DISABLE: 0,
50  ENABLE: 1,
51  ENABLE_FORMS: 2,
52  ENABLE_STORAGE: 3
53};
54const AnnotationPrefix = "pdfjs_internal_id_";
55const AnnotationEditorPrefix = "pdfjs_internal_editor_";
56const AnnotationEditorType = {
57  DISABLE: -1,
58  NONE: 0,
59  FREETEXT: 3,
60  HIGHLIGHT: 9,
61  STAMP: 13,
62  INK: 15,
63  POPUP: 16,
64  SIGNATURE: 101,
65  COMMENT: 102
66};
67const AnnotationEditorParamsType = {
68  RESIZE: 1,
69  CREATE: 2,
70  FREETEXT_SIZE: 11,
71  FREETEXT_COLOR: 12,
72  FREETEXT_OPACITY: 13,
73  INK_COLOR: 21,
74  INK_THICKNESS: 22,
75  INK_OPACITY: 23,
76  INK_COLOR_AND_OPACITY: 24,
77  HIGHLIGHT_COLOR: 31,
78  HIGHLIGHT_THICKNESS: 32,
79  HIGHLIGHT_FREE: 33,
80  HIGHLIGHT_SHOW_ALL: 34,
81  DRAW_STEP: 41
82};
83const PermissionFlag = {
84  PRINT: 0x04,
85  MODIFY_CONTENTS: 0x08,
86  COPY: 0x10,
87  MODIFY_ANNOTATIONS: 0x20,
88  FILL_INTERACTIVE_FORMS: 0x100,
89  COPY_FOR_ACCESSIBILITY: 0x200,
90  ASSEMBLE: 0x400,
91  PRINT_HIGH_QUALITY: 0x800
92};
93const MeshFigureType = (/* unused pure expression or super */ null && ({
94  TRIANGLES: 1,
95  LATTICE: 2,
96  PATCH: 3
97}));
98const TextRenderingMode = {
99  FILL: 0,
100  STROKE: 1,
101  FILL_STROKE: 2,
102  INVISIBLE: 3,
103  FILL_ADD_TO_PATH: 4,
104  STROKE_ADD_TO_PATH: 5,
105  FILL_STROKE_ADD_TO_PATH: 6,
106  ADD_TO_PATH: 7,
107  FILL_STROKE_MASK: 3,
108  ADD_TO_PATH_FLAG: 4
109};
110const ImageKind = {
111  GRAYSCALE_1BPP: 1,
112  RGB_24BPP: 2,
113  RGBA_32BPP: 3
114};
115const AnnotationType = {
116  TEXT: 1,
117  LINK: 2,
118  FREETEXT: 3,
119  LINE: 4,
120  SQUARE: 5,
121  CIRCLE: 6,
122  POLYGON: 7,
123  POLYLINE: 8,
124  HIGHLIGHT: 9,
125  UNDERLINE: 10,
126  SQUIGGLY: 11,
127  STRIKEOUT: 12,
128  STAMP: 13,
129  CARET: 14,
130  INK: 15,
131  POPUP: 16,
132  FILEATTACHMENT: 17,
133  SOUND: 18,
134  MOVIE: 19,
135  WIDGET: 20,
136  SCREEN: 21,
137  PRINTERMARK: 22,
138  TRAPNET: 23,
139  WATERMARK: 24,
140  THREED: 25,
141  REDACT: 26,
142  RICHMEDIA: 27
143};
144const AnnotationReplyType = (/* unused pure expression or super */ null && ({
145  GROUP: "Group",
146  REPLY: "R"
147}));
148const AnnotationRenditionOperation = (/* unused pure expression or super */ null && ({
149  PLAY_OR_RESUME: 0,
150  STOP: 1,
151  PAUSE: 2,
152  RESUME: 3,
153  PLAY: 4
154}));
155const AnnotationFlag = (/* unused pure expression or super */ null && ({
156  INVISIBLE: 0x01,
157  HIDDEN: 0x02,
158  PRINT: 0x04,
159  NOZOOM: 0x08,
160  NOROTATE: 0x10,
161  NOVIEW: 0x20,
162  READONLY: 0x40,
163  LOCKED: 0x80,
164  TOGGLENOVIEW: 0x100,
165  LOCKEDCONTENTS: 0x200
166}));
167const AnnotationFieldFlag = (/* unused pure expression or super */ null && ({
168  READONLY: 0x0000001,
169  REQUIRED: 0x0000002,
170  NOEXPORT: 0x0000004,
171  MULTILINE: 0x0001000,
172  PASSWORD: 0x0002000,
173  NOTOGGLETOOFF: 0x0004000,
174  RADIO: 0x0008000,
175  PUSHBUTTON: 0x0010000,
176  COMBO: 0x0020000,
177  EDIT: 0x0040000,
178  SORT: 0x0080000,
179  FILESELECT: 0x0100000,
180  MULTISELECT: 0x0200000,
181  DONOTSPELLCHECK: 0x0400000,
182  DONOTSCROLL: 0x0800000,
183  COMB: 0x1000000,
184  RICHTEXT: 0x2000000,
185  RADIOSINUNISON: 0x2000000,
186  COMMITONSELCHANGE: 0x4000000
187}));
188const AnnotationBorderStyleType = {
189  SOLID: 1,
190  DASHED: 2,
191  BEVELED: 3,
192  INSET: 4,
193  UNDERLINE: 5
194};
195const AnnotationActionEventType = (/* unused pure expression or super */ null && ({
196  E: "Mouse Enter",
197  X: "Mouse Exit",
198  D: "Mouse Down",
199  U: "Mouse Up",
200  Fo: "Focus",
201  Bl: "Blur",
202  PO: "PageOpen",
203  PC: "PageClose",
204  PV: "PageVisible",
205  PI: "PageInvisible",
206  K: "Keystroke",
207  F: "Format",
208  V: "Validate",
209  C: "Calculate"
210}));
211const DocumentActionEventType = (/* unused pure expression or super */ null && ({
212  WC: "WillClose",
213  WS: "WillSave",
214  DS: "DidSave",
215  WP: "WillPrint",
216  DP: "DidPrint"
217}));
218const PageActionEventType = (/* unused pure expression or super */ null && ({
219  O: "PageOpen",
220  C: "PageClose"
221}));
222const VerbosityLevel = {
223  ERRORS: 0,
224  WARNINGS: 1,
225  INFOS: 5
226};
227const OPS = {
228  dependency: 1,
229  setLineWidth: 2,
230  setLineCap: 3,
231  setLineJoin: 4,
232  setMiterLimit: 5,
233  setDash: 6,
234  setRenderingIntent: 7,
235  setFlatness: 8,
236  setGState: 9,
237  save: 10,
238  restore: 11,
239  transform: 12,
240  moveTo: 13,
241  lineTo: 14,
242  curveTo: 15,
243  curveTo2: 16,
244  curveTo3: 17,
245  closePath: 18,
246  rectangle: 19,
247  stroke: 20,
248  closeStroke: 21,
249  fill: 22,
250  eoFill: 23,
251  fillStroke: 24,
252  eoFillStroke: 25,
253  closeFillStroke: 26,
254  closeEOFillStroke: 27,
255  endPath: 28,
256  clip: 29,
257  eoClip: 30,
258  beginText: 31,
259  endText: 32,
260  setCharSpacing: 33,
261  setWordSpacing: 34,
262  setHScale: 35,
263  setLeading: 36,
264  setFont: 37,
265  setTextRenderingMode: 38,
266  setTextRise: 39,
267  moveText: 40,
268  setLeadingMoveText: 41,
269  setTextMatrix: 42,
270  nextLine: 43,
271  showText: 44,
272  showSpacedText: 45,
273  nextLineShowText: 46,
274  nextLineSetSpacingShowText: 47,
275  setCharWidth: 48,
276  setCharWidthAndBounds: 49,
277  setStrokeColorSpace: 50,
278  setFillColorSpace: 51,
279  setStrokeColor: 52,
280  setStrokeColorN: 53,
281  setFillColor: 54,
282  setFillColorN: 55,
283  setStrokeGray: 56,
284  setFillGray: 57,
285  setStrokeRGBColor: 58,
286  setFillRGBColor: 59,
287  setStrokeCMYKColor: 60,
288  setFillCMYKColor: 61,
289  shadingFill: 62,
290  beginInlineImage: 63,
291  beginImageData: 64,
292  endInlineImage: 65,
293  paintXObject: 66,
294  markPoint: 67,
295  markPointProps: 68,
296  beginMarkedContent: 69,
297  beginMarkedContentProps: 70,
298  endMarkedContent: 71,
299  beginCompat: 72,
300  endCompat: 73,
301  paintFormXObjectBegin: 74,
302  paintFormXObjectEnd: 75,
303  beginGroup: 76,
304  endGroup: 77,
305  beginAnnotation: 80,
306  endAnnotation: 81,
307  paintImageMaskXObject: 83,
308  paintImageMaskXObjectGroup: 84,
309  paintImageXObject: 85,
310  paintInlineImageXObject: 86,
311  paintInlineImageXObjectGroup: 87,
312  paintImageXObjectRepeat: 88,
313  paintImageMaskXObjectRepeat: 89,
314  paintSolidColorImageMask: 90,
315  constructPath: 91,
316  setStrokeTransparent: 92,
317  setFillTransparent: 93,
318  rawFillPath: 94
319};
320const DrawOPS = {
321  moveTo: 0,
322  lineTo: 1,
323  curveTo: 2,
324  quadraticCurveTo: 3,
325  closePath: 4
326};
327const PasswordResponses = {
328  NEED_PASSWORD: 1,
329  INCORRECT_PASSWORD: 2
330};
331let verbosity = VerbosityLevel.WARNINGS;
332function setVerbosityLevel(level) {
333  if (Number.isInteger(level)) {
334    verbosity = level;
335  }
336}
337function getVerbosityLevel() {
338  return verbosity;
339}
340function info(msg) {
341  if (verbosity >= VerbosityLevel.INFOS) {
342    console.info(`Info: ${msg}`);
343  }
344}
345function warn(msg) {
346  if (verbosity >= VerbosityLevel.WARNINGS) {
347    console.warn(`Warning: ${msg}`);
348  }
349}
350function unreachable(msg) {
351  throw new Error(msg);
352}
353function assert(cond, msg) {
354  if (!cond) {
355    unreachable(msg);
356  }
357}
358function _isValidProtocol(url) {
359  switch (url?.protocol) {
360    case "http:":
361    case "https:":
362    case "ftp:":
363    case "mailto:":
364    case "tel:":
365      return true;
366    default:
367      return false;
368  }
369}
370function createValidAbsoluteUrl(url, baseUrl = null, options = null) {
371  if (!url) {
372    return null;
373  }
374  if (options && typeof url === "string") {
375    if (options.addDefaultProtocol && url.startsWith("www.")) {
376      const dots = url.match(/\./g);
377      if (dots?.length >= 2) {
378        url = `http://${url}`;
379      }
380    }
381    if (options.tryConvertEncoding) {
382      try {
383        url = stringToUTF8String(url);
384      } catch {}
385    }
386  }
387  const absoluteUrl = baseUrl ? URL.parse(url, baseUrl) : URL.parse(url);
388  return _isValidProtocol(absoluteUrl) ? absoluteUrl : null;
389}
390function updateUrlHash(url, hash, allowRel = false) {
391  const res = URL.parse(url);
392  if (res) {
393    res.hash = hash;
394    return res.href;
395  }
396  if (allowRel && createValidAbsoluteUrl(url, "http://example.com")) {
397    return url.split("#", 1)[0] + `${hash ? `#${hash}` : ""}`;
398  }
399  return "";
400}
401function stripPath(str) {
402  return str.substring(str.lastIndexOf("/") + 1);
403}
404function shadow(obj, prop, value, nonSerializable = false) {
405  Object.defineProperty(obj, prop, {
406    value,
407    enumerable: !nonSerializable,
408    configurable: true,
409    writable: false
410  });
411  return value;
412}
413const BaseException = function BaseExceptionClosure() {
414  function BaseException(message, name) {
415    this.message = message;
416    this.name = name;
417  }
418  BaseException.prototype = new Error();
419  BaseException.constructor = BaseException;
420  return BaseException;
421}();
422class PasswordException extends BaseException {
423  constructor(msg, code) {
424    super(msg, "PasswordException");
425    this.code = code;
426  }
427}
428class UnknownErrorException extends BaseException {
429  constructor(msg, details) {
430    super(msg, "UnknownErrorException");
431    this.details = details;
432  }
433}
434class InvalidPDFException extends BaseException {
435  constructor(msg) {
436    super(msg, "InvalidPDFException");
437  }
438}
439class ResponseException extends BaseException {
440  constructor(msg, status, missing) {
441    super(msg, "ResponseException");
442    this.status = status;
443    this.missing = missing;
444  }
445}
446class FormatError extends BaseException {
447  constructor(msg) {
448    super(msg, "FormatError");
449  }
450}
451class AbortException extends BaseException {
452  constructor(msg) {
453    super(msg, "AbortException");
454  }
455}
456function bytesToString(bytes) {
457  if (typeof bytes !== "object" || bytes?.length === undefined) {
458    unreachable("Invalid argument for bytesToString");
459  }
460  const length = bytes.length;
461  const MAX_ARGUMENT_COUNT = 8192;
462  if (length < MAX_ARGUMENT_COUNT) {
463    return String.fromCharCode.apply(null, bytes);
464  }
465  const strBuf = [];
466  for (let i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
467    const chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
468    const chunk = bytes.subarray(i, chunkEnd);
469    strBuf.push(String.fromCharCode.apply(null, chunk));
470  }
471  return strBuf.join("");
472}
473function stringToBytes(str) {
474  if (typeof str !== "string") {
475    unreachable("Invalid argument for stringToBytes");
476  }
477  const length = str.length;
478  const bytes = new Uint8Array(length);
479  for (let i = 0; i < length; ++i) {
480    bytes[i] = str.charCodeAt(i) & 0xff;
481  }
482  return bytes;
483}
vendor: 13,109 bytes, lines 484-893
484function objectSize(obj) {
485  return Object.keys(obj).length;
486}
487class FeatureTest {
488  static get isLittleEndian() {
489    const buffer8 = new Uint8Array(4);
490    buffer8[0] = 1;
491    const view32 = new Uint32Array(buffer8.buffer, 0, 1);
492    return shadow(this, "isLittleEndian", view32[0] === 1);
493  }
494  static get isOffscreenCanvasSupported() {
495    return shadow(this, "isOffscreenCanvasSupported", typeof OffscreenCanvas !== "undefined");
496  }
497  static get isImageDecoderSupported() {
498    return shadow(this, "isImageDecoderSupported", typeof ImageDecoder !== "undefined");
499  }
500  static get isFloat16ArraySupported() {
501    return shadow(this, "isFloat16ArraySupported", typeof Float16Array !== "undefined");
502  }
503  static get isSanitizerSupported() {
504    return shadow(this, "isSanitizerSupported", typeof Sanitizer !== "undefined");
505  }
506  static get platform() {
507    const {
508      platform,
509      userAgent
510    } = navigator;
511    return shadow(this, "platform", {
512      isAndroid: userAgent.includes("Android"),
513      isLinux: platform.includes("Linux"),
514      isMac: platform.includes("Mac"),
515      isWindows: platform.includes("Win"),
516      isFirefox: userAgent.includes("Firefox")
517    });
518  }
519  static get isCanvasFilterSupported() {
520    let ctx;
521    if (this.isOffscreenCanvasSupported) {
522      ctx = new OffscreenCanvas(1, 1).getContext("2d");
523    } else if (typeof document !== "undefined") {
524      ctx = document.createElement("canvas").getContext("2d");
525    }
526    return shadow(this, "isCanvasFilterSupported", ctx?.filter !== undefined);
527  }
528  static get isAlphaColorInputSupported() {
529    if (typeof document === "undefined") {
530      return shadow(this, "isAlphaColorInputSupported", false);
531    }
532    const input = document.createElement("input");
533    input.type = "color";
534    input.setAttribute("alpha", "");
535    input.value = "#ff000080";
536    return shadow(this, "isAlphaColorInputSupported", input.value !== "#ff0000");
537  }
538  static get isBackdropFilterSupported() {
539    return shadow(this, "isBackdropFilterSupported", typeof CSS !== "undefined" && CSS.supports("backdrop-filter", "blur(1px)"));
540  }
541}
542class Util {
543  static get hexNums() {
544    return shadow(this, "hexNums", Array.from(Array(256).keys(), n => n.toString(16).padStart(2, "0")));
545  }
546  static makeHexColor(r, g, b) {
547    return `#${this.hexNums[r]}${this.hexNums[g]}${this.hexNums[b]}`;
548  }
549  static transform(m1, m2) {
550    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]];
551  }
552  static multiplyByDOMMatrix(m, md) {
553    return [m[0] * md.a + m[2] * md.b, m[1] * md.a + m[3] * md.b, m[0] * md.c + m[2] * md.d, m[1] * md.c + m[3] * md.d, m[0] * md.e + m[2] * md.f + m[4], m[1] * md.e + m[3] * md.f + m[5]];
554  }
555  static applyTransform(p, m, pos = 0) {
556    const p0 = p[pos];
557    const p1 = p[pos + 1];
558    p[pos] = p0 * m[0] + p1 * m[2] + m[4];
559    p[pos + 1] = p0 * m[1] + p1 * m[3] + m[5];
560  }
561  static applyTransformToBezier(p, transform, pos = 0) {
562    const m0 = transform[0];
563    const m1 = transform[1];
564    const m2 = transform[2];
565    const m3 = transform[3];
566    const m4 = transform[4];
567    const m5 = transform[5];
568    for (let i = 0; i < 6; i += 2) {
569      const pI = p[pos + i];
570      const pI1 = p[pos + i + 1];
571      p[pos + i] = pI * m0 + pI1 * m2 + m4;
572      p[pos + i + 1] = pI * m1 + pI1 * m3 + m5;
573    }
574  }
575  static applyInverseTransform(p, m) {
576    const p0 = p[0];
577    const p1 = p[1];
578    const d = m[0] * m[3] - m[1] * m[2];
579    p[0] = (p0 * m[3] - p1 * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
580    p[1] = (-p0 * m[1] + p1 * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
581  }
582  static axialAlignedBoundingBox(rect, transform, output) {
583    const m0 = transform[0];
584    const m1 = transform[1];
585    const m2 = transform[2];
586    const m3 = transform[3];
587    const m4 = transform[4];
588    const m5 = transform[5];
589    const r0 = rect[0];
590    const r1 = rect[1];
591    const r2 = rect[2];
592    const r3 = rect[3];
593    let a0 = m0 * r0 + m4;
594    let a2 = a0;
595    let a1 = m0 * r2 + m4;
596    let a3 = a1;
597    let b0 = m3 * r1 + m5;
598    let b2 = b0;
599    let b1 = m3 * r3 + m5;
600    let b3 = b1;
601    if (m1 !== 0 || m2 !== 0) {
602      const m1r0 = m1 * r0;
603      const m1r2 = m1 * r2;
604      const m2r1 = m2 * r1;
605      const m2r3 = m2 * r3;
606      a0 += m2r1;
607      a3 += m2r1;
608      a1 += m2r3;
609      a2 += m2r3;
610      b0 += m1r0;
611      b3 += m1r0;
612      b1 += m1r2;
613      b2 += m1r2;
614    }
615    output[0] = Math.min(output[0], a0, a1, a2, a3);
616    output[1] = Math.min(output[1], b0, b1, b2, b3);
617    output[2] = Math.max(output[2], a0, a1, a2, a3);
618    output[3] = Math.max(output[3], b0, b1, b2, b3);
619  }
620  static inverseTransform(m) {
621    const d = m[0] * m[3] - m[1] * m[2];
622    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];
623  }
624  static singularValueDecompose2dScale(matrix, output) {
625    const m0 = matrix[0];
626    const m1 = matrix[1];
627    const m2 = matrix[2];
628    const m3 = matrix[3];
629    const a = m0 ** 2 + m1 ** 2;
630    const b = m0 * m2 + m1 * m3;
631    const c = m2 ** 2 + m3 ** 2;
632    const first = (a + c) / 2;
633    const second = Math.sqrt(first ** 2 - (a * c - b ** 2));
634    output[0] = Math.sqrt(first + second || 1);
635    output[1] = Math.sqrt(first - second || 1);
636  }
637  static normalizeRect(rect) {
638    const r = rect.slice(0);
639    if (rect[0] > rect[2]) {
640      r[0] = rect[2];
641      r[2] = rect[0];
642    }
643    if (rect[1] > rect[3]) {
644      r[1] = rect[3];
645      r[3] = rect[1];
646    }
647    return r;
648  }
649  static intersect(rect1, rect2) {
650    const xLow = Math.max(Math.min(rect1[0], rect1[2]), Math.min(rect2[0], rect2[2]));
651    const xHigh = Math.min(Math.max(rect1[0], rect1[2]), Math.max(rect2[0], rect2[2]));
652    if (xLow > xHigh) {
653      return null;
654    }
655    const yLow = Math.max(Math.min(rect1[1], rect1[3]), Math.min(rect2[1], rect2[3]));
656    const yHigh = Math.min(Math.max(rect1[1], rect1[3]), Math.max(rect2[1], rect2[3]));
657    if (yLow > yHigh) {
658      return null;
659    }
660    return [xLow, yLow, xHigh, yHigh];
661  }
662  static pointBoundingBox(x, y, minMax) {
663    minMax[0] = Math.min(minMax[0], x);
664    minMax[1] = Math.min(minMax[1], y);
665    minMax[2] = Math.max(minMax[2], x);
666    minMax[3] = Math.max(minMax[3], y);
667  }
668  static rectBoundingBox(x0, y0, x1, y1, minMax) {
669    minMax[0] = Math.min(minMax[0], x0, x1);
670    minMax[1] = Math.min(minMax[1], y0, y1);
671    minMax[2] = Math.max(minMax[2], x0, x1);
672    minMax[3] = Math.max(minMax[3], y0, y1);
673  }
674  static #getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, t, minMax) {
675    if (t <= 0 || t >= 1) {
676      return;
677    }
678    const mt = 1 - t;
679    const tt = t * t;
680    const ttt = tt * t;
681    const x = mt * (mt * (mt * x0 + 3 * t * x1) + 3 * tt * x2) + ttt * x3;
682    const y = mt * (mt * (mt * y0 + 3 * t * y1) + 3 * tt * y2) + ttt * y3;
683    minMax[0] = Math.min(minMax[0], x);
684    minMax[1] = Math.min(minMax[1], y);
685    minMax[2] = Math.max(minMax[2], x);
686    minMax[3] = Math.max(minMax[3], y);
687  }
688  static #getExtremum(x0, x1, x2, x3, y0, y1, y2, y3, a, b, c, minMax) {
689    if (Math.abs(a) < 1e-12) {
690      if (Math.abs(b) >= 1e-12) {
691        this.#getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, -c / b, minMax);
692      }
693      return;
694    }
695    const delta = b ** 2 - 4 * c * a;
696    if (delta < 0) {
697      return;
698    }
699    const sqrtDelta = Math.sqrt(delta);
700    const a2 = 2 * a;
701    this.#getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, (-b + sqrtDelta) / a2, minMax);
702    this.#getExtremumOnCurve(x0, x1, x2, x3, y0, y1, y2, y3, (-b - sqrtDelta) / a2, minMax);
703  }
704  static bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3, minMax) {
705    minMax[0] = Math.min(minMax[0], x0, x3);
706    minMax[1] = Math.min(minMax[1], y0, y3);
707    minMax[2] = Math.max(minMax[2], x0, x3);
708    minMax[3] = Math.max(minMax[3], y0, y3);
709    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);
710    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);
711  }
712}
713function stringToUTF8String(str) {
714  return decodeURIComponent(escape(str));
715}
716function utf8StringToString(str) {
717  return unescape(encodeURIComponent(str));
718}
719function isArrayEqual(arr1, arr2) {
720  if (arr1.length !== arr2.length) {
721    return false;
722  }
723  for (let i = 0, ii = arr1.length; i < ii; i++) {
724    if (arr1[i] !== arr2[i]) {
725      return false;
726    }
727  }
728  return true;
729}
730let NormalizeRegex = null;
731let NormalizationMap = null;
732function normalizeUnicode(str) {
733  if (!NormalizeRegex) {
734    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;
735    NormalizationMap = new Map([["ſt", "ſt"]]);
736  }
737  return str.replaceAll(NormalizeRegex, (_, p1, p2) => p1 ? p1.normalize("NFKC") : NormalizationMap.get(p2));
738}
739function getUuid() {
740  if (typeof crypto.randomUUID === "function") {
741    return crypto.randomUUID();
742  }
743  const buf = new Uint8Array(32);
744  crypto.getRandomValues(buf);
745  return bytesToString(buf);
746}
747function _isValidExplicitDest(validRef, validName, dest) {
748  if (!Array.isArray(dest) || dest.length < 2) {
749    return false;
750  }
751  const [page, zoom, ...args] = dest;
752  if (!validRef(page) && !Number.isInteger(page)) {
753    return false;
754  }
755  if (!validName(zoom)) {
756    return false;
757  }
758  const argsLen = args.length;
759  let allowNull = true;
760  switch (zoom.name) {
761    case "XYZ":
762      if (argsLen < 2 || argsLen > 3) {
763        return false;
764      }
765      break;
766    case "Fit":
767    case "FitB":
768      return argsLen === 0;
769    case "FitH":
770    case "FitBH":
771    case "FitV":
772    case "FitBV":
773      if (argsLen > 1) {
774        return false;
775      }
776      break;
777    case "FitR":
778      if (argsLen !== 4) {
779        return false;
780      }
781      allowNull = false;
782      break;
783    default:
784      return false;
785  }
786  for (const arg of args) {
787    if (typeof arg === "number" || allowNull && arg === null) {
788      continue;
789    }
790    return false;
791  }
792  return true;
793}
794const makeArr = () => [];
795const makeMap = () => new Map();
796const makeObj = () => Object.create(null);
797
798;// ./src/shared/math_clamp.js
799function MathClamp(v, min, max) {
800  return Math.min(Math.max(v, min), max);
801}
802
803;// ./src/display/page_viewport.js
804
805class PageViewport {
806  constructor({
807    viewBox,
808    userUnit,
809    scale,
810    rotation,
811    offsetX = 0,
812    offsetY = 0,
813    dontFlip = false
814  }) {
815    this.viewBox = viewBox;
816    this.userUnit = userUnit;
817    this.scale = scale;
818    this.rotation = rotation;
819    this.offsetX = offsetX;
820    this.offsetY = offsetY;
821    scale *= userUnit;
822    const centerX = (viewBox[2] + viewBox[0]) / 2;
823    const centerY = (viewBox[3] + viewBox[1]) / 2;
824    let rotateA, rotateB, rotateC, rotateD;
825    rotation %= 360;
826    if (rotation < 0) {
827      rotation += 360;
828    }
829    switch (rotation) {
830      case 180:
831        rotateA = -1;
832        rotateB = 0;
833        rotateC = 0;
834        rotateD = 1;
835        break;
836      case 90:
837        rotateA = 0;
838        rotateB = 1;
839        rotateC = 1;
840        rotateD = 0;
841        break;
842      case 270:
843        rotateA = 0;
844        rotateB = -1;
845        rotateC = -1;
846        rotateD = 0;
847        break;
848      case 0:
849        rotateA = 1;
850        rotateB = 0;
851        rotateC = 0;
852        rotateD = -1;
853        break;
854      default:
855        throw new Error("PageViewport: Invalid rotation, must be a multiple of 90 degrees.");
856    }
857    if (dontFlip) {
858      rotateC = -rotateC;
859      rotateD = -rotateD;
860    }
861    let offsetCanvasX, offsetCanvasY;
862    let width, height;
863    if (rotateA === 0) {
864      offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
865      offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
866      width = (viewBox[3] - viewBox[1]) * scale;
867      height = (viewBox[2] - viewBox[0]) * scale;
868    } else {
869      offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
870      offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
871      width = (viewBox[2] - viewBox[0]) * scale;
872      height = (viewBox[3] - viewBox[1]) * scale;
873    }
874    this.transform = [rotateA * scale, rotateB * scale, rotateC * scale, rotateD * scale, offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY];
875    this.width = width;
876    this.height = height;
877  }
878  get rawDims() {
879    const dims = this.viewBox;
880    return shadow(this, "rawDims", {
881      pageWidth: dims[2] - dims[0],
882      pageHeight: dims[3] - dims[1],
883      pageX: dims[0],
884      pageY: dims[1]
885    });
886  }
887  clone({
888    scale = this.scale,
889    rotation = this.rotation,
890    offsetX = this.offsetX,
891    offsetY = this.offsetY,
892    dontFlip = false
893  }
vendor: 7,759 bytes, lines 893-1167
893 = {}) {
894    return new PageViewport({
895      viewBox: this.viewBox.slice(),
896      userUnit: this.userUnit,
897      scale,
898      rotation,
899      offsetX,
900      offsetY,
901      dontFlip
902    });
903  }
904  convertToViewportPoint(x, y) {
905    const p = [x, y];
906    Util.applyTransform(p, this.transform);
907    return p;
908  }
909  convertToPdfPoint(x, y) {
910    const p = [x, y];
911    Util.applyInverseTransform(p, this.transform);
912    return p;
913  }
914}
915
916;// ./src/display/xfa_text.js
917class XfaText {
918  static textContent(xfa) {
919    const items = [];
920    const output = {
921      items,
922      styles: Object.create(null)
923    };
924    function walk(node) {
925      if (!node) {
926        return;
927      }
928      let str = null;
929      const name = node.name;
930      if (name === "#text") {
931        str = node.value;
932      } else if (!XfaText.shouldBuildText(name)) {
933        return;
934      } else if (node?.attributes?.textContent) {
935        str = node.attributes.textContent;
936      } else if (node.value) {
937        str = node.value;
938      }
939      if (str !== null) {
940        items.push({
941          str
942        });
943      }
944      if (!node.children) {
945        return;
946      }
947      for (const child of node.children) {
948        walk(child);
949      }
950    }
951    walk(xfa);
952    return output;
953  }
954  static shouldBuildText(name) {
955    return !(name === "textarea" || name === "input" || name === "option" || name === "select");
956  }
957}
958
959;// ./src/display/xfa_layer.js
960
961
962class XfaLayer {
963  static setupStorage(html, id, element, storage, intent) {
964    const storedData = storage.getValue(id, {
965      value: null
966    });
967    switch (element.name) {
968      case "textarea":
969        if (storedData.value !== null) {
970          html.textContent = storedData.value;
971        }
972        if (intent === "print") {
973          break;
974        }
975        html.addEventListener("input", event => {
976          storage.setValue(id, {
977            value: event.target.value
978          });
979        });
980        break;
981      case "input":
982        if (element.attributes.type === "radio" || element.attributes.type === "checkbox") {
983          if (storedData.value === element.attributes.xfaOn) {
984            html.setAttribute("checked", true);
985          } else if (storedData.value === element.attributes.xfaOff) {
986            html.removeAttribute("checked");
987          }
988          if (intent === "print") {
989            break;
990          }
991          html.addEventListener("change", event => {
992            storage.setValue(id, {
993              value: event.target.checked ? event.target.getAttribute("xfaOn") : event.target.getAttribute("xfaOff")
994            });
995          });
996        } else {
997          if (storedData.value !== null) {
998            html.setAttribute("value", storedData.value);
999          }
1000          if (intent === "print") {
1001            break;
1002          }
1003          html.addEventListener("input", event => {
1004            storage.setValue(id, {
1005              value: event.target.value
1006            });
1007          });
1008        }
1009        break;
1010      case "select":
1011        if (storedData.value !== null) {
1012          html.setAttribute("value", storedData.value);
1013          for (const option of element.children) {
1014            if (option.attributes.value === storedData.value) {
1015              option.attributes.selected = true;
1016            } else if (Object.hasOwn(option.attributes, "selected")) {
1017              delete option.attributes.selected;
1018            }
1019          }
1020        }
1021        html.addEventListener("input", event => {
1022          const options = event.target.options;
1023          const value = options.selectedIndex === -1 ? "" : options[options.selectedIndex].value;
1024          storage.setValue(id, {
1025            value
1026          });
1027        });
1028        break;
1029    }
1030  }
1031  static setAttributes({
1032    html,
1033    element,
1034    storage = null,
1035    intent,
1036    linkService
1037  }) {
1038    const {
1039      attributes
1040    } = element;
1041    const isHTMLAnchorElement = html instanceof HTMLAnchorElement;
1042    if (attributes.type === "radio") {
1043      attributes.name = `${attributes.name}-${intent}`;
1044    }
1045    for (const [key, value] of Object.entries(attributes)) {
1046      if (value === null || value === undefined) {
1047        continue;
1048      }
1049      switch (key) {
1050        case "class":
1051          if (value.length) {
1052            html.setAttribute(key, value.join(" "));
1053          }
1054          break;
1055        case "dataId":
1056          break;
1057        case "id":
1058          html.setAttribute("data-element-id", value);
1059          break;
1060        case "style":
1061          Object.assign(html.style, value);
1062          break;
1063        case "textContent":
1064          html.textContent = value;
1065          break;
1066        default:
1067          if (!isHTMLAnchorElement || key !== "href" && key !== "newWindow") {
1068            html.setAttribute(key, value);
1069          }
1070      }
1071    }
1072    if (isHTMLAnchorElement) {
1073      linkService.addLinkAttributes(html, attributes.href, attributes.newWindow);
1074    }
1075    if (storage && attributes.dataId) {
1076      this.setupStorage(html, attributes.dataId, element, storage);
1077    }
1078  }
1079  static render(parameters) {
1080    const storage = parameters.annotationStorage;
1081    const linkService = parameters.linkService;
1082    const root = parameters.xfaHtml;
1083    const intent = parameters.intent || "display";
1084    const rootHtml = document.createElement(root.name);
1085    if (root.attributes) {
1086      this.setAttributes({
1087        html: rootHtml,
1088        element: root,
1089        intent,
1090        linkService
1091      });
1092    }
1093    const isNotForRichText = intent !== "richText";
1094    const rootDiv = parameters.div;
1095    rootDiv.append(rootHtml);
1096    if (parameters.viewport) {
1097      const transform = `matrix(${parameters.viewport.transform.join(",")})`;
1098      rootDiv.style.transform = transform;
1099    }
1100    if (isNotForRichText) {
1101      rootDiv.setAttribute("class", "xfaLayer xfaFont");
1102    }
1103    const textDivs = [];
1104    if (root.children.length === 0) {
1105      if (root.value) {
1106        const node = document.createTextNode(root.value);
1107        rootHtml.append(node);
1108        if (isNotForRichText && XfaText.shouldBuildText(root.name)) {
1109          textDivs.push(node);
1110        }
1111      }
1112      return {
1113        textDivs
1114      };
1115    }
1116    const stack = [[root, -1, rootHtml]];
1117    while (stack.length > 0) {
1118      const [parent, i, html] = stack.at(-1);
1119      if (i + 1 === parent.children.length) {
1120        stack.pop();
1121        continue;
1122      }
1123      const child = parent.children[++stack.at(-1)[1]];
1124      if (child === null) {
1125        continue;
1126      }
1127      const {
1128        name
1129      } = child;
1130      if (name === "#text") {
1131        const node = document.createTextNode(child.value);
1132        textDivs.push(node);
1133        html.append(node);
1134        continue;
1135      }
1136      const childHtml = child?.attributes?.xmlns ? document.createElementNS(child.attributes.xmlns, name) : document.createElement(name);
1137      html.append(childHtml);
1138      if (child.attributes) {
1139        this.setAttributes({
1140          html: childHtml,
1141          element: child,
1142          storage,
1143          intent,
1144          linkService
1145        });
1146      }
1147      if (child.children?.length > 0) {
1148        stack.push([child, -1, childHtml]);
1149      } else if (child.value) {
1150        const node = document.createTextNode(child.value);
1151        if (isNotForRichText && XfaText.shouldBuildText(name)) {
1152          textDivs.push(node);
1153        }
1154        childHtml.append(node);
1155      }
1156    }
1157    for (const el of rootDiv.querySelectorAll(".xfaNonInteractive input, .xfaNonInteractive textarea")) {
1158      el.setAttribute("readOnly", true);
1159    }
1160    return {
1161      textDivs
1162    };
1163  }
1164  static update(parameters) {
1165    const transform = `matrix(${parameters.viewport.transform.join(",")})`;
1166    parameters.div.style.transform = transform;
1167    parameters.div.hidden = false;
vendor: 3,846 bytes, lines 1168-1316
1168  }
1169  static getPageViewport(xfaPage, {
1170    scale = 1,
1171    rotation = 0
1172  }) {
1173    const {
1174      width,
1175      height
1176    } = xfaPage.attributes.style;
1177    return new PageViewport({
1178      viewBox: [0, 0, parseInt(width, 10), parseInt(height, 10)],
1179      userUnit: 1,
1180      scale,
1181      rotation
1182    });
1183  }
1184}
1185
1186;// ./src/display/display_utils.js
1187
1188
1189
1190
1191class PixelsPerInch {
1192  static CSS = 96.0;
1193  static PDF = 72.0;
1194  static PDF_TO_CSS_UNITS = this.CSS / this.PDF;
1195}
1196async function fetchData(url, type = "text") {
1197  if (isValidFetchUrl(url, document.baseURI)) {
1198    const response = await fetch(url);
1199    if (!response.ok) {
1200      throw new Error(response.statusText);
1201    }
1202    switch (type) {
1203      case "blob":
1204        return response.blob();
1205      case "bytes":
1206        return response.bytes();
1207      case "json":
1208        return response.json();
1209    }
1210    return response.text();
1211  }
1212  return new Promise((resolve, reject) => {
1213    const request = new XMLHttpRequest();
1214    request.open("GET", url, true);
1215    request.responseType = type === "bytes" ? "arraybuffer" : type;
1216    request.onreadystatechange = () => {
1217      if (request.readyState !== XMLHttpRequest.DONE) {
1218        return;
1219      }
1220      if (request.status === 200 || request.status === 0) {
1221        switch (type) {
1222          case "bytes":
1223            resolve(new Uint8Array(request.response));
1224            return;
1225          case "blob":
1226          case "json":
1227            resolve(request.response);
1228            return;
1229        }
1230        resolve(request.responseText);
1231        return;
1232      }
1233      reject(new Error(request.statusText));
1234    };
1235    request.send(null);
1236  });
1237}
1238class RenderingCancelledException extends BaseException {
1239  constructor(msg, extraDelay = 0) {
1240    super(msg, "RenderingCancelledException");
1241    this.extraDelay = extraDelay;
1242  }
1243}
1244function isDataScheme(url) {
1245  const ii = url.length;
1246  let i = 0;
1247  while (i < ii && url[i].trim() === "") {
1248    i++;
1249  }
1250  return url.substring(i, i + 5).toLowerCase() === "data:";
1251}
1252function isPdfFile(filename) {
1253  return typeof filename === "string" && /\.pdf$/i.test(filename);
1254}
1255function getFilenameFromUrl(url) {
1256  [url] = url.split(/[#?]/, 1);
1257  return stripPath(url);
1258}
1259function getPdfFilenameFromUrl(url, defaultFilename = "document.pdf") {
1260  if (typeof url !== "string") {
1261    return defaultFilename;
1262  }
1263  if (isDataScheme(url)) {
1264    warn('getPdfFilenameFromUrl: ignore "data:"-URL for performance reasons.');
1265    return defaultFilename;
1266  }
1267  const getURL = urlString => {
1268    try {
1269      return new URL(urlString);
1270    } catch {}
1271    try {
1272      return new URL(decodeURIComponent(urlString));
1273    } catch {}
1274    try {
1275      return new URL(urlString, "https://foo.bar");
1276    } catch {}
1277    try {
1278      return new URL(decodeURIComponent(urlString), "https://foo.bar");
1279    } catch {}
1280    return null;
1281  };
1282  const newURL = getURL(url);
1283  if (!newURL) {
1284    return defaultFilename;
1285  }
1286  const decode = name => {
1287    try {
1288      let decoded = decodeURIComponent(name);
1289      if (decoded.includes("/")) {
1290        decoded = stripPath(decoded);
1291        if (decoded.length === 4 && pdfRegex.test(decoded)) {
1292          return name;
1293        }
1294      }
1295      return decoded;
1296    } catch {
1297      return name;
1298    }
1299  };
1300  const pdfRegex = /\.pdf$/i;
1301  const filename = stripPath(newURL.pathname);
1302  if (pdfRegex.test(filename)) {
1303    return decode(filename);
1304  }
1305  if (newURL.searchParams.size > 0) {
1306    const getLast = iterator => [...iterator].findLast(v => pdfRegex.test(v));
1307    const name = getLast(newURL.searchParams.values()) ?? getLast(newURL.searchParams.keys());
1308    if (name) {
1309      return decode(name);
1310    }
1311  }
1312  if (newURL.hash) {
1313    const reFilename = /[^/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
1314    const hashFilename = reFilename.exec(newURL.hash);
1315    if (hashFilename) {
1316      return decode(hashFilename[0]);
vendor: 18,746 bytes, lines 1316-1959
1316
1317    }
1318  }
1319  return defaultFilename;
1320}
1321class StatTimer {
1322  #started = new Map();
1323  times = [];
1324  time(name) {
1325    if (this.#started.has(name)) {
1326      warn(`Timer is already running for ${name}`);
1327    }
1328    this.#started.set(name, Date.now());
1329  }
1330  timeEnd(name) {
1331    if (!this.#started.has(name)) {
1332      warn(`Timer has not been started for ${name}`);
1333    }
1334    this.times.push({
1335      name,
1336      start: this.#started.get(name),
1337      end: Date.now()
1338    });
1339    this.#started.delete(name);
1340  }
1341  toString() {
1342    const longest = Math.max(...this.times.map(t => t.name.length));
1343    return this.times.map(t => `${t.name.padEnd(longest)} ${t.end - t.start}ms\n`).join("");
1344  }
1345}
1346function isValidFetchUrl(url, baseUrl) {
1347  const res = baseUrl ? URL.parse(url, baseUrl) : URL.parse(url);
1348  return /https?:/.test(res?.protocol ?? "");
1349}
1350function noContextMenu(e) {
1351  e.preventDefault();
1352}
1353function stopEvent(e) {
1354  e.preventDefault();
1355  e.stopPropagation();
1356}
1357function deprecated(details) {
1358  console.log("Deprecated API usage: " + details);
1359}
1360class PDFDateString {
1361  static #regex;
1362  static toDateObject(input) {
1363    if (input instanceof Date) {
1364      return input;
1365    }
1366    if (!input || typeof input !== "string") {
1367      return null;
1368    }
1369    this.#regex ||= new RegExp("^D:" + "(\\d{4})" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "(\\d{2})?" + "([Z|+\\-])?" + "(\\d{2})?" + "'?" + "(\\d{2})?" + "'?");
1370    const matches = this.#regex.exec(input);
1371    if (!matches) {
1372      return null;
1373    }
1374    const year = parseInt(matches[1], 10);
1375    let month = parseInt(matches[2], 10);
1376    month = month >= 1 && month <= 12 ? month - 1 : 0;
1377    let day = parseInt(matches[3], 10);
1378    day = day >= 1 && day <= 31 ? day : 1;
1379    let hour = parseInt(matches[4], 10);
1380    hour = hour >= 0 && hour <= 23 ? hour : 0;
1381    let minute = parseInt(matches[5], 10);
1382    minute = minute >= 0 && minute <= 59 ? minute : 0;
1383    let second = parseInt(matches[6], 10);
1384    second = second >= 0 && second <= 59 ? second : 0;
1385    const universalTimeRelation = matches[7] || "Z";
1386    let offsetHour = parseInt(matches[8], 10);
1387    offsetHour = offsetHour >= 0 && offsetHour <= 23 ? offsetHour : 0;
1388    let offsetMinute = parseInt(matches[9], 10) || 0;
1389    offsetMinute = offsetMinute >= 0 && offsetMinute <= 59 ? offsetMinute : 0;
1390    if (universalTimeRelation === "-") {
1391      hour += offsetHour;
1392      minute += offsetMinute;
1393    } else if (universalTimeRelation === "+") {
1394      hour -= offsetHour;
1395      minute -= offsetMinute;
1396    }
1397    return new Date(Date.UTC(year, month, day, hour, minute, second));
1398  }
1399}
1400function getRGBA(color) {
1401  if (color.startsWith("#")) {
1402    const hex = color.slice(1);
1403    return [parseInt(hex.slice(0, 2), 16), parseInt(hex.slice(2, 4), 16), parseInt(hex.slice(4, 6), 16), hex.length >= 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1];
1404  }
1405  if (color.startsWith("rgb(")) {
1406    const [r, g, b] = color.slice(4, -1).split(",").map(x => parseInt(x, 10));
1407    return [r, g, b, 1];
1408  }
1409  if (color.startsWith("rgba(")) {
1410    const parts = color.slice(5, -1).split(",");
1411    return [parseInt(parts[0], 10), parseInt(parts[1], 10), parseInt(parts[2], 10), parseFloat(parts[3])];
1412  }
1413  const m = color.match(/^color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+|none))?\)$/);
1414  if (m) {
1415    return [Math.round(parseFloat(m[1]) * 255), Math.round(parseFloat(m[2]) * 255), Math.round(parseFloat(m[3]) * 255), m[4] !== undefined && m[4] !== "none" ? parseFloat(m[4]) : 1];
1416  }
1417  return null;
1418}
1419function getRGB(color) {
1420  const rgba = getRGBA(color);
1421  if (!rgba) {
1422    warn(`Not a valid color format: "${color}"`);
1423    return [0, 0, 0];
1424  }
1425  return rgba.slice(0, 3);
1426}
1427function getColorValues(colors) {
1428  const span = document.createElement("span");
1429  span.style.visibility = "hidden";
1430  span.style.colorScheme = "only light";
1431  document.body.append(span);
1432  for (const name of colors.keys()) {
1433    span.style.color = name;
1434    const computedColor = window.getComputedStyle(span).color;
1435    colors.set(name, getRGB(computedColor));
1436  }
1437  span.remove();
1438}
1439function getCurrentTransform(ctx) {
1440  const {
1441    a,
1442    b,
1443    c,
1444    d,
1445    e,
1446    f
1447  } = ctx.getTransform();
1448  return [a, b, c, d, e, f];
1449}
1450function getCurrentTransformInverse(ctx) {
1451  const {
1452    a,
1453    b,
1454    c,
1455    d,
1456    e,
1457    f
1458  } = ctx.getTransform().invertSelf();
1459  return [a, b, c, d, e, f];
1460}
1461function setLayerDimensions(div, viewport, mustFlip = false, mustRotate = true) {
1462  if (viewport instanceof PageViewport) {
1463    const {
1464      pageWidth,
1465      pageHeight
1466    } = viewport.rawDims;
1467    const {
1468      style
1469    } = div;
1470    const widthStr = `round(down, var(--total-scale-factor) * ${pageWidth}px, var(--scale-round-x))`,
1471      heightStr = `round(down, var(--total-scale-factor) * ${pageHeight}px, var(--scale-round-y))`;
1472    if (!mustFlip || viewport.rotation % 180 === 0) {
1473      style.width = widthStr;
1474      style.height = heightStr;
1475    } else {
1476      style.width = heightStr;
1477      style.height = widthStr;
1478    }
1479  }
1480  if (mustRotate) {
1481    div.setAttribute("data-main-rotation", viewport.rotation);
1482  }
1483}
1484class OutputScale {
1485  constructor() {
1486    const {
1487      pixelRatio
1488    } = OutputScale;
1489    this.sx = pixelRatio;
1490    this.sy = pixelRatio;
1491  }
1492  get scaled() {
1493    return this.sx !== 1 || this.sy !== 1;
1494  }
1495  get symmetric() {
1496    return this.sx === this.sy;
1497  }
1498  limitCanvas(width, height, maxPixels, maxDim, capAreaFactor = -1) {
1499    let maxAreaScale = Infinity,
1500      maxWidthScale = Infinity,
1501      maxHeightScale = Infinity;
1502    maxPixels = OutputScale.capPixels(maxPixels, capAreaFactor);
1503    if (maxPixels > 0) {
1504      maxAreaScale = Math.sqrt(maxPixels / (width * height));
1505    }
1506    if (maxDim !== -1) {
1507      maxWidthScale = maxDim / width;
1508      maxHeightScale = maxDim / height;
1509    }
1510    const maxScale = Math.min(maxAreaScale, maxWidthScale, maxHeightScale);
1511    if (this.sx > maxScale || this.sy > maxScale) {
1512      this.sx = maxScale;
1513      this.sy = maxScale;
1514      return true;
1515    }
1516    return false;
1517  }
1518  static get pixelRatio() {
1519    return globalThis.devicePixelRatio || 1;
1520  }
1521  static capPixels(maxPixels, capAreaFactor) {
1522    if (capAreaFactor >= 0) {
1523      const winPixels = Math.ceil(window.screen.availWidth * window.screen.availHeight * this.pixelRatio ** 2 * (1 + capAreaFactor / 100));
1524      return maxPixels > 0 ? Math.min(maxPixels, winPixels) : winPixels;
1525    }
1526    return maxPixels;
1527  }
1528}
1529const SupportedImageMimeTypes = ["image/apng", "image/avif", "image/bmp", "image/gif", "image/jpeg", "image/png", "image/svg+xml", "image/webp", "image/x-icon"];
1530class ColorScheme {
1531  static get isDarkMode() {
1532    return shadow(this, "isDarkMode", !!window?.matchMedia?.("(prefers-color-scheme: dark)").matches);
1533  }
1534}
1535class CSSConstants {
1536  static get commentForegroundColor() {
1537    const element = document.createElement("span");
1538    element.classList.add("comment", "sidebar");
1539    const {
1540      style
1541    } = element;
1542    style.width = style.height = "0";
1543    style.display = "none";
1544    style.color = "var(--comment-fg-color)";
1545    document.body.append(element);
1546    const {
1547      color
1548    } = window.getComputedStyle(element);
1549    element.remove();
1550    return shadow(this, "commentForegroundColor", getRGB(color));
1551  }
1552}
1553function applyOpacity(color, opacity) {
1554  opacity = MathClamp(opacity ?? 1, 0, 1);
1555  const white = 255 * (1 - opacity);
1556  return color.map(c => Math.round(c * opacity + white));
1557}
1558function RGBToHSL(rgb, output) {
1559  const r = rgb[0] / 255;
1560  const g = rgb[1] / 255;
1561  const b = rgb[2] / 255;
1562  const max = Math.max(r, g, b);
1563  const min = Math.min(r, g, b);
1564  const l = (max + min) / 2;
1565  if (max === min) {
1566    output[0] = output[1] = 0;
1567  } else {
1568    const d = max - min;
1569    output[1] = l < 0.5 ? d / (max + min) : d / (2 - max - min);
1570    switch (max) {
1571      case r:
1572        output[0] = ((g - b) / d + (g < b ? 6 : 0)) * 60;
1573        break;
1574      case g:
1575        output[0] = ((b - r) / d + 2) * 60;
1576        break;
1577      case b:
1578        output[0] = ((r - g) / d + 4) * 60;
1579        break;
1580    }
1581  }
1582  output[2] = l;
1583}
1584function HSLToRGB(hsl, output) {
1585  const h = hsl[0];
1586  const s = hsl[1];
1587  const l = hsl[2];
1588  const c = (1 - Math.abs(2 * l - 1)) * s;
1589  const x = c * (1 - Math.abs(h / 60 % 2 - 1));
1590  const m = l - c / 2;
1591  switch (Math.floor(h / 60)) {
1592    case 0:
1593      output[0] = c + m;
1594      output[1] = x + m;
1595      output[2] = m;
1596      break;
1597    case 1:
1598      output[0] = x + m;
1599      output[1] = c + m;
1600      output[2] = m;
1601      break;
1602    case 2:
1603      output[0] = m;
1604      output[1] = c + m;
1605      output[2] = x + m;
1606      break;
1607    case 3:
1608      output[0] = m;
1609      output[1] = x + m;
1610      output[2] = c + m;
1611      break;
1612    case 4:
1613      output[0] = x + m;
1614      output[1] = m;
1615      output[2] = c + m;
1616      break;
1617    case 5:
1618    case 6:
1619      output[0] = c + m;
1620      output[1] = m;
1621      output[2] = x + m;
1622      break;
1623  }
1624}
1625function computeLuminance(x) {
1626  return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
1627}
1628function contrastRatio(hsl1, hsl2, output) {
1629  HSLToRGB(hsl1, output);
1630  output.map(computeLuminance);
1631  const lum1 = 0.2126 * output[0] + 0.7152 * output[1] + 0.0722 * output[2];
1632  HSLToRGB(hsl2, output);
1633  output.map(computeLuminance);
1634  const lum2 = 0.2126 * output[0] + 0.7152 * output[1] + 0.0722 * output[2];
1635  return lum1 > lum2 ? (lum1 + 0.05) / (lum2 + 0.05) : (lum2 + 0.05) / (lum1 + 0.05);
1636}
1637const contrastCache = new Map();
1638function findContrastColor(baseColor, fixedColor) {
1639  const key = baseColor[0] + baseColor[1] * 0x100 + baseColor[2] * 0x10000 + fixedColor[0] * 0x1000000 + fixedColor[1] * 0x100000000 + fixedColor[2] * 0x10000000000;
1640  let cachedValue = contrastCache.get(key);
1641  if (cachedValue) {
1642    return cachedValue;
1643  }
1644  const array = new Float32Array(9);
1645  const output = array.subarray(0, 3);
1646  const baseHSL = array.subarray(3, 6);
1647  RGBToHSL(baseColor, baseHSL);
1648  const fixedHSL = array.subarray(6, 9);
1649  RGBToHSL(fixedColor, fixedHSL);
1650  const isFixedColorDark = fixedHSL[2] < 0.5;
1651  const minContrast = isFixedColorDark ? 12 : 4.5;
1652  baseHSL[2] = isFixedColorDark ? Math.sqrt(baseHSL[2]) : 1 - Math.sqrt(1 - baseHSL[2]);
1653  if (contrastRatio(baseHSL, fixedHSL, output) < minContrast) {
1654    let start, end;
1655    if (isFixedColorDark) {
1656      start = baseHSL[2];
1657      end = 1;
1658    } else {
1659      start = 0;
1660      end = baseHSL[2];
1661    }
1662    const PRECISION = 0.005;
1663    while (end - start > PRECISION) {
1664      const mid = baseHSL[2] = (start + end) / 2;
1665      if (isFixedColorDark === contrastRatio(baseHSL, fixedHSL, output) < minContrast) {
1666        start = mid;
1667      } else {
1668        end = mid;
1669      }
1670    }
1671    baseHSL[2] = isFixedColorDark ? end : start;
1672  }
1673  HSLToRGB(baseHSL, output);
1674  cachedValue = Util.makeHexColor(Math.round(output[0] * 255), Math.round(output[1] * 255), Math.round(output[2] * 255));
1675  contrastCache.set(key, cachedValue);
1676  return cachedValue;
1677}
1678function renderRichText({
1679  html,
1680  dir,
1681  className
1682}, container) {
1683  const fragment = document.createDocumentFragment();
1684  if (typeof html === "string") {
1685    const p = document.createElement("p");
1686    p.dir = dir || "auto";
1687    const lines = html.split(/\r\n?|\n/);
1688    for (let i = 0, ii = lines.length; i < ii; ++i) {
1689      const line = lines[i];
1690      p.append(document.createTextNode(line));
1691      if (i < ii - 1) {
1692        p.append(document.createElement("br"));
1693      }
1694    }
1695    fragment.append(p);
1696  } else {
1697    XfaLayer.render({
1698      xfaHtml: html,
1699      div: fragment,
1700      intent: "richText"
1701    });
1702  }
1703  fragment.firstElementChild.classList.add("richText", className);
1704  container.append(fragment);
1705}
1706function makePathFromDrawOPS(data) {
1707  const path = new Path2D();
1708  if (!data) {
1709    return path;
1710  }
1711  for (let i = 0, ii = data.length; i < ii;) {
1712    switch (data[i++]) {
1713      case DrawOPS.moveTo:
1714        path.moveTo(data[i++], data[i++]);
1715        break;
1716      case DrawOPS.lineTo:
1717        path.lineTo(data[i++], data[i++]);
1718        break;
1719      case DrawOPS.curveTo:
1720        path.bezierCurveTo(data[i++], data[i++], data[i++], data[i++], data[i++], data[i++]);
1721        break;
1722      case DrawOPS.quadraticCurveTo:
1723        path.quadraticCurveTo(data[i++], data[i++], data[i++], data[i++]);
1724        break;
1725      case DrawOPS.closePath:
1726        path.closePath();
1727        break;
1728      default:
1729        warn(`Unrecognized drawing path operator: ${data[i - 1]}`);
1730        break;
1731    }
1732  }
1733  return path;
1734}
1735
1736;// ./src/display/editor/toolbar.js
1737
1738class EditorToolbar {
1739  #toolbar = null;
1740  #colorPicker = null;
1741  #editor;
1742  #buttons = null;
1743  #altText = null;
1744  #comment = null;
1745  #commentButtonDivider = null;
1746  #signatureDescriptionButton = null;
1747  static #l10nRemove = null;
1748  constructor(editor) {
1749    this.#editor = editor;
1750    EditorToolbar.#l10nRemove ||= Object.freeze({
1751      freetext: "pdfjs-editor-remove-freetext-button",
1752      highlight: "pdfjs-editor-remove-highlight-button",
1753      ink: "pdfjs-editor-remove-ink-button",
1754      stamp: "pdfjs-editor-remove-stamp-button",
1755      signature: "pdfjs-editor-remove-signature-button"
1756    });
1757  }
1758  render() {
1759    const editToolbar = this.#toolbar = document.createElement("div");
1760    editToolbar.classList.add("editToolbar", "hidden");
1761    editToolbar.setAttribute("role", "toolbar");
1762    const signal = this.#editor._uiManager._signal;
1763    if (signal instanceof AbortSignal && !signal.aborted) {
1764      editToolbar.addEventListener("contextmenu", noContextMenu, {
1765        signal
1766      });
1767      editToolbar.addEventListener("pointerdown", EditorToolbar.#pointerDown, {
1768        signal
1769      });
1770    }
1771    const buttons = this.#buttons = document.createElement("div");
1772    buttons.className = "buttons";
1773    editToolbar.append(buttons);
1774    const position = this.#editor.toolbarPosition;
1775    if (position) {
1776      const {
1777        style
1778      } = editToolbar;
1779      const x = this.#editor._uiManager.direction === "ltr" ? 1 - position[0] : position[0];
1780      style.insetInlineEnd = `${100 * x}%`;
1781      style.top = `calc(${100 * position[1]}% + var(--editor-toolbar-vert-offset))`;
1782    }
1783    return editToolbar;
1784  }
1785  get div() {
1786    return this.#toolbar;
1787  }
1788  static #pointerDown(e) {
1789    e.stopPropagation();
1790  }
1791  #focusIn(e) {
1792    this.#editor._focusEventsAllowed = false;
1793    stopEvent(e);
1794  }
1795  #focusOut(e) {
1796    this.#editor._focusEventsAllowed = true;
1797    stopEvent(e);
1798  }
1799  #addListenersToElement(element) {
1800    const signal = this.#editor._uiManager._signal;
1801    if (!(signal instanceof AbortSignal) || signal.aborted) {
1802      return false;
1803    }
1804    element.addEventListener("focusin", this.#focusIn.bind(this), {
1805      capture: true,
1806      signal
1807    });
1808    element.addEventListener("focusout", this.#focusOut.bind(this), {
1809      capture: true,
1810      signal
1811    });
1812    element.addEventListener("contextmenu", noContextMenu, {
1813      signal
1814    });
1815    return true;
1816  }
1817  hide() {
1818    this.#toolbar.classList.add("hidden");
1819    this.#colorPicker?.hideDropdown();
1820  }
1821  show() {
1822    this.#toolbar.classList.remove("hidden");
1823    this.#altText?.shown();
1824    this.#comment?.shown();
1825  }
1826  addDeleteButton() {
1827    const {
1828      editorType,
1829      _uiManager
1830    } = this.#editor;
1831    const button = document.createElement("button");
1832    button.classList.add("basic", "deleteButton");
1833    button.tabIndex = 0;
1834    button.setAttribute("data-l10n-id", EditorToolbar.#l10nRemove[editorType]);
1835    if (this.#addListenersToElement(button)) {
1836      button.addEventListener("click", e => {
1837        _uiManager.delete();
1838      }, {
1839        signal: _uiManager._signal
1840      });
1841    }
1842    this.#buttons.append(button);
1843  }
1844  get #divider() {
1845    const divider = document.createElement("div");
1846    divider.className = "divider";
1847    return divider;
1848  }
1849  async addAltText(altText) {
1850    const button = await altText.render();
1851    this.#addListenersToElement(button);
1852    this.#buttons.append(button, this.#divider);
1853    this.#altText = altText;
1854  }
1855  addComment(comment, beforeElement = null) {
1856    if (this.#comment) {
1857      return;
1858    }
1859    const button = comment.renderForToolbar();
1860    if (!button) {
1861      return;
1862    }
1863    this.#addListenersToElement(button);
1864    const divider = this.#commentButtonDivider = this.#divider;
1865    if (!beforeElement) {
1866      this.#buttons.append(button, divider);
1867    } else {
1868      this.#buttons.insertBefore(button, beforeElement);
1869      this.#buttons.insertBefore(divider, beforeElement);
1870    }
1871    this.#comment = comment;
1872    comment.toolbar = this;
1873  }
1874  addColorPicker(colorPicker) {
1875    if (this.#colorPicker) {
1876      return;
1877    }
1878    this.#colorPicker = colorPicker;
1879    const button = colorPicker.renderButton();
1880    this.#addListenersToElement(button);
1881    this.#buttons.append(button, this.#divider);
1882  }
1883  async addEditSignatureButton(signatureManager) {
1884    const button = this.#signatureDescriptionButton = await signatureManager.renderEditButton(this.#editor);
1885    this.#addListenersToElement(button);
1886    this.#buttons.append(button, this.#divider);
1887  }
1888  removeButton(name) {
1889    switch (name) {
1890      case "comment":
1891        this.#comment?.removeToolbarCommentButton();
1892        this.#comment = null;
1893        this.#commentButtonDivider?.remove();
1894        this.#commentButtonDivider = null;
1895        break;
1896    }
1897  }
1898  async addButton(name, tool) {
1899    switch (name) {
1900      case "colorPicker":
1901        if (tool) {
1902          this.addColorPicker(tool);
1903        }
1904        break;
1905      case "altText":
1906        if (tool) {
1907          await this.addAltText(tool);
1908        }
1909        break;
1910      case "editSignature":
1911        if (tool) {
1912          await this.addEditSignatureButton(tool);
1913        }
1914        break;
1915      case "delete":
1916        this.addDeleteButton();
1917        break;
1918      case "comment":
1919        if (tool) {
1920          this.addComment(tool);
1921        }
1922        break;
1923    }
1924  }
1925  async addButtonBefore(name, tool, beforeSelector) {
1926    if (!tool && name === "comment") {
1927      return;
1928    }
1929    const beforeElement = this.#buttons.querySelector(beforeSelector);
1930    if (!beforeElement) {
1931      return;
1932    }
1933    if (name === "comment") {
1934      this.addComment(tool, beforeElement);
1935    }
1936  }
1937  updateEditSignatureButton(description) {
1938    if (this.#signatureDescriptionButton) {
1939      this.#signatureDescriptionButton.title = description;
1940    }
1941  }
1942  remove() {
1943    this.#toolbar.remove();
1944    this.#colorPicker?.destroy();
1945    this.#colorPicker = null;
1946  }
1947}
1948class FloatingToolbar {
1949  #buttons = null;
1950  #toolbar = null;
1951  #uiManager;
1952  constructor(uiManager) {
1953    this.#uiManager = uiManager;
1954  }
1955  #render() {
1956    const editToolbar = this.#toolbar = document.createElement("div");
1957    editToolbar.className = "editToolbar";
1958    editToolbar.setAttribute("role", "toolbar");
1959    
vendor: 2,469 bytes, lines 1959-2037
1959const signal = this.#uiManager._signal;
1960    if (signal instanceof AbortSignal && !signal.aborted) {
1961      editToolbar.addEventListener("contextmenu", noContextMenu, {
1962        signal
1963      });
1964    }
1965    const buttons = this.#buttons = document.createElement("div");
1966    buttons.className = "buttons";
1967    editToolbar.append(buttons);
1968    if (this.#uiManager.hasCommentManager()) {
1969      this.#makeButton("commentButton", `pdfjs-comment-floating-button`, "pdfjs-comment-floating-button-label", () => {
1970        this.#uiManager.commentSelection("floating_button");
1971      });
1972    }
1973    this.#makeButton("highlightButton", `pdfjs-highlight-floating-button1`, "pdfjs-highlight-floating-button-label", () => {
1974      this.#uiManager.highlightSelection("floating_button");
1975    });
1976    return editToolbar;
1977  }
1978  #getLastPoint(boxes, isLTR) {
1979    let lastY = 0;
1980    let lastX = 0;
1981    for (const box of boxes) {
1982      const y = box.y + box.height;
1983      if (y < lastY) {
1984        continue;
1985      }
1986      const x = box.x + (isLTR ? box.width : 0);
1987      if (y > lastY) {
1988        lastX = x;
1989        lastY = y;
1990        continue;
1991      }
1992      if (isLTR) {
1993        if (x > lastX) {
1994          lastX = x;
1995        }
1996      } else if (x < lastX) {
1997        lastX = x;
1998      }
1999    }
2000    return [isLTR ? 1 - lastX : lastX, lastY];
2001  }
2002  show(parent, boxes, isLTR) {
2003    const [x, y] = this.#getLastPoint(boxes, isLTR);
2004    const {
2005      style
2006    } = this.#toolbar ||= this.#render();
2007    parent.append(this.#toolbar);
2008    style.insetInlineEnd = `${100 * x}%`;
2009    style.top = `calc(${100 * y}% + var(--editor-toolbar-vert-offset))`;
2010  }
2011  hide() {
2012    this.#toolbar.remove();
2013  }
2014  #makeButton(buttonClass, l10nId, labelL10nId, clickHandler) {
2015    const button = document.createElement("button");
2016    button.classList.add("basic", buttonClass);
2017    button.tabIndex = 0;
2018    button.setAttribute("data-l10n-id", l10nId);
2019    const span = document.createElement("span");
2020    button.append(span);
2021    span.className = "visuallyHidden";
2022    span.setAttribute("data-l10n-id", labelL10nId);
2023    const signal = this.#uiManager._signal;
2024    if (signal instanceof AbortSignal && !signal.aborted) {
2025      button.addEventListener("contextmenu", noContextMenu, {
2026        signal
2027      });
2028      button.addEventListener("click", clickHandler, {
2029        signal
2030      });
2031    }
2032    this.#buttons.append(button);
2033  }
2034}
2035
2036;// ./src/shared/internal_evt.js
2037const INTERNAL_EVT = "068f09d6-5b37-4f77-a97a-f8ff4f253b68
vendor: 12,463 bytes, lines 2037-2517
2037";
2038const internalOpt = Object.freeze({
2039  internal: INTERNAL_EVT
2040});
2041
2042;// ./src/display/editor/tools.js
2043
2044
2045
2046
2047function bindEvents(obj, element, names) {
2048  for (const name of names) {
2049    element.addEventListener(name, obj[name].bind(obj));
2050  }
2051}
2052class CurrentPointers {
2053  static #pointerId = NaN;
2054  static #pointerIds = null;
2055  static #moveTimestamp = NaN;
2056  static #pointerType = null;
2057  static initializeAndAddPointerId(pointerId) {
2058    (CurrentPointers.#pointerIds ||= new Set()).add(pointerId);
2059  }
2060  static setPointer(pointerType, pointerId) {
2061    CurrentPointers.#pointerId ||= pointerId;
2062    CurrentPointers.#pointerType ??= pointerType;
2063  }
2064  static setTimeStamp(timeStamp) {
2065    CurrentPointers.#moveTimestamp = timeStamp;
2066  }
2067  static isSamePointerId(pointerId) {
2068    return CurrentPointers.#pointerId === pointerId;
2069  }
2070  static isSamePointerIdOrRemove(pointerId) {
2071    if (CurrentPointers.#pointerId === pointerId) {
2072      return true;
2073    }
2074    CurrentPointers.#pointerIds?.delete(pointerId);
2075    return false;
2076  }
2077  static isSamePointerType(pointerType) {
2078    return CurrentPointers.#pointerType === pointerType;
2079  }
2080  static isInitializedAndDifferentPointerType(pointerType) {
2081    return CurrentPointers.#pointerType !== null && !CurrentPointers.isSamePointerType(pointerType);
2082  }
2083  static isSameTimeStamp(timeStamp) {
2084    return CurrentPointers.#moveTimestamp === timeStamp;
2085  }
2086  static isUsingMultiplePointers() {
2087    return CurrentPointers.#pointerIds?.size >= 1;
2088  }
2089  static clearPointerType() {
2090    CurrentPointers.#pointerType = null;
2091  }
2092  static clearPointerIds() {
2093    CurrentPointers.#pointerId = NaN;
2094    CurrentPointers.#pointerIds = null;
2095  }
2096  static clearTimeStamp() {
2097    CurrentPointers.#moveTimestamp = NaN;
2098  }
2099}
2100class IdManager {
2101  #id = 0;
2102  get id() {
2103    return `${AnnotationEditorPrefix}${this.#id++}`;
2104  }
2105}
2106class ImageManager {
2107  #baseId = getUuid();
2108  #id = 0;
2109  #cache = null;
2110  static get _isSVGFittingCanvas() {
2111    const svg = `data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 1 1" width="1" height="1" xmlns="${SVG_NS}"><rect width="1" height="1" style="fill:red;"/></svg>`;
2112    const canvas = new OffscreenCanvas(1, 3);
2113    const ctx = canvas.getContext("2d", {
2114      willReadFrequently: true
2115    });
2116    const image = new Image();
2117    image.src = svg;
2118    const promise = image.decode().then(() => {
2119      ctx.drawImage(image, 0, 0, 1, 1, 0, 0, 1, 3);
2120      return new Uint32Array(ctx.getImageData(0, 0, 1, 1).data.buffer)[0] === 0;
2121    });
2122    return shadow(this, "_isSVGFittingCanvas", promise);
2123  }
2124  async #get(key, rawData) {
2125    this.#cache ||= new Map();
2126    let data = this.#cache.get(key);
2127    if (data === null) {
2128      return null;
2129    }
2130    if (data?.bitmap) {
2131      data.refCounter += 1;
2132      return data;
2133    }
2134    try {
2135      data ||= {
2136        bitmap: null,
2137        id: `image_${this.#baseId}_${this.#id++}`,
2138        refCounter: 0,
2139        isSvg: false
2140      };
2141      let image;
2142      if (typeof rawData === "string") {
2143        data.url = rawData;
2144        image = await fetchData(rawData, "blob");
2145      } else if (rawData instanceof File) {
2146        image = data.file = rawData;
2147      } else if (rawData instanceof Blob) {
2148        image = rawData;
2149      }
2150      if (image.type === "image/svg+xml") {
2151        const mustRemoveAspectRatioPromise = ImageManager._isSVGFittingCanvas;
2152        const fileReader = new FileReader();
2153        const imageElement = new Image();
2154        const imagePromise = new Promise((resolve, reject) => {
2155          imageElement.onload = () => {
2156            data.bitmap = imageElement;
2157            data.isSvg = true;
2158            resolve();
2159          };
2160          fileReader.onload = async () => {
2161            const url = data.svgUrl = fileReader.result;
2162            imageElement.src = (await mustRemoveAspectRatioPromise) ? `${url}#svgView(preserveAspectRatio(none))` : url;
2163          };
2164          imageElement.onerror = fileReader.onerror = reject;
2165        });
2166        fileReader.readAsDataURL(image);
2167        await imagePromise;
2168      } else {
2169        data.bitmap = await createImageBitmap(image);
2170      }
2171      data.refCounter = 1;
2172    } catch (e) {
2173      warn(e);
2174      data = null;
2175    }
2176    this.#cache.set(key, data);
2177    if (data) {
2178      this.#cache.set(data.id, data);
2179    }
2180    return data;
2181  }
2182  async getFromFile(file) {
2183    const {
2184      lastModified,
2185      name,
2186      size,
2187      type
2188    } = file;
2189    return this.#get(`${lastModified}_${name}_${size}_${type}`, file);
2190  }
2191  async getFromUrl(url) {
2192    return this.#get(url, url);
2193  }
2194  async getFromBlob(id, blobPromise) {
2195    const blob = await blobPromise;
2196    return this.#get(id, blob);
2197  }
2198  async getFromId(id) {
2199    this.#cache ||= new Map();
2200    const data = this.#cache.get(id);
2201    if (!data) {
2202      return null;
2203    }
2204    if (data.bitmap) {
2205      data.refCounter += 1;
2206      return data;
2207    }
2208    if (data.file) {
2209      return this.getFromFile(data.file);
2210    }
2211    if (data.blobPromise) {
2212      const {
2213        blobPromise
2214      } = data;
2215      delete data.blobPromise;
2216      return this.getFromBlob(data.id, blobPromise);
2217    }
2218    return this.getFromUrl(data.url);
2219  }
2220  getFromCanvas(id, canvas) {
2221    this.#cache ||= new Map();
2222    let data = this.#cache.get(id);
2223    if (data?.bitmap) {
2224      data.refCounter += 1;
2225      return data;
2226    }
2227    const offscreen = new OffscreenCanvas(canvas.width, canvas.height);
2228    const ctx = offscreen.getContext("2d");
2229    ctx.drawImage(canvas, 0, 0);
2230    data = {
2231      bitmap: offscreen.transferToImageBitmap(),
2232      id: `image_${this.#baseId}_${this.#id++}`,
2233      refCounter: 1,
2234      isSvg: false
2235    };
2236    this.#cache.set(id, data);
2237    this.#cache.set(data.id, data);
2238    return data;
2239  }
2240  getSvgUrl(id) {
2241    const data = this.#cache.get(id);
2242    if (!data?.isSvg) {
2243      return null;
2244    }
2245    return data.svgUrl;
2246  }
2247  deleteId(id) {
2248    this.#cache ||= new Map();
2249    const data = this.#cache.get(id);
2250    if (!data) {
2251      return;
2252    }
2253    data.refCounter -= 1;
2254    if (data.refCounter !== 0) {
2255      return;
2256    }
2257    const {
2258      bitmap
2259    } = data;
2260    if (!data.url && !data.file) {
2261      const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
2262      const ctx = canvas.getContext("bitmaprenderer");
2263      ctx.transferFromImageBitmap(bitmap);
2264      data.blobPromise = canvas.convertToBlob();
2265    }
2266    bitmap.close?.();
2267    data.bitmap = null;
2268  }
2269  isValidId(id) {
2270    return id.startsWith(`image_${this.#baseId}_`);
2271  }
2272}
2273class CommandManager {
2274  #commands = [];
2275  #locked = false;
2276  #maxSize;
2277  #position = -1;
2278  constructor(maxSize = 128) {
2279    this.#maxSize = maxSize;
2280  }
2281  add({
2282    cmd,
2283    undo,
2284    post,
2285    mustExec,
2286    type = NaN,
2287    overwriteIfSameType = false,
2288    keepUndo = false
2289  }) {
2290    if (mustExec) {
2291      cmd();
2292    }
2293    if (this.#locked) {
2294      return;
2295    }
2296    const save = {
2297      cmd,
2298      undo,
2299      post,
2300      type
2301    };
2302    if (this.#position === -1) {
2303      if (this.#commands.length > 0) {
2304        this.#commands.length = 0;
2305      }
2306      this.#position = 0;
2307      this.#commands.push(save);
2308      return;
2309    }
2310    if (overwriteIfSameType && this.#commands[this.#position].type === type) {
2311      if (keepUndo) {
2312        save.undo = this.#commands[this.#position].undo;
2313      }
2314      this.#commands[this.#position] = save;
2315      return;
2316    }
2317    const next = this.#position + 1;
2318    if (next === this.#maxSize) {
2319      this.#commands.splice(0, 1);
2320    } else {
2321      this.#position = next;
2322      if (next < this.#commands.length) {
2323        this.#commands.splice(next);
2324      }
2325    }
2326    this.#commands.push(save);
2327  }
2328  undo() {
2329    if (this.#position === -1) {
2330      return;
2331    }
2332    this.#locked = true;
2333    const {
2334      undo,
2335      post
2336    } = this.#commands[this.#position];
2337    undo();
2338    post?.();
2339    this.#locked = false;
2340    this.#position -= 1;
2341  }
2342  redo() {
2343    if (this.#position < this.#commands.length - 1) {
2344      this.#position += 1;
2345      this.#locked = true;
2346      const {
2347        cmd,
2348        post
2349      } = this.#commands[this.#position];
2350      cmd();
2351      post?.();
2352      this.#locked = false;
2353    }
2354  }
2355  hasSomethingToUndo() {
2356    return this.#position !== -1;
2357  }
2358  hasSomethingToRedo() {
2359    return this.#position < this.#commands.length - 1;
2360  }
2361  cleanType(type) {
2362    if (this.#position === -1) {
2363      return;
2364    }
2365    for (let i = this.#position; i >= 0; i--) {
2366      if (this.#commands[i].type !== type) {
2367        this.#commands.splice(i + 1, this.#position - i);
2368        this.#position = i;
2369        return;
2370      }
2371    }
2372    this.#commands.length = 0;
2373    this.#position = -1;
2374  }
2375  destroy() {
2376    this.#commands = null;
2377  }
2378}
2379class KeyboardManager {
2380  static ALT = 0x1;
2381  static CTRL = 0x2;
2382  static META = 0x4;
2383  static SHIFT = 0x8;
2384  constructor(callbacks) {
2385    this.callbacks = new Map();
2386    const {
2387      isMac
2388    } = FeatureTest.platform;
2389    for (const [keys, callback, options = {}] of callbacks) {
2390      const hasMacOverride = keys.some(k => k.startsWith("mac+"));
2391      for (const key of keys) {
2392        let shortcut = key;
2393        if (hasMacOverride) {
2394          const isMacKey = key.startsWith("mac+");
2395          if (isMac !== isMacKey) {
2396            continue;
2397          }
2398          if (isMacKey) {
2399            shortcut = key.slice(4);
2400          }
2401        }
2402        const [keyName, modifiers] = KeyboardManager.#parseShortcut(shortcut);
2403        if (keyName === null) {
2404          continue;
2405        }
2406        this.callbacks.getOrInsertComputed(keyName, makeArr).push({
2407          callback,
2408          options,
2409          modifiers
2410        });
2411      }
2412    }
2413  }
2414  static #parseShortcut(value) {
2415    let keyPart = null;
2416    let modifiers = 0;
2417    for (let part of value.split("+")) {
2418      part = part.trim();
2419      if (!part) {
2420        continue;
2421      }
2422      const upper = part.toUpperCase();
2423      const modifier = KeyboardManager[upper];
2424      if (modifier) {
2425        modifiers |= modifier;
2426        continue;
2427      }
2428      if (keyPart !== null) {
2429        warn(`KeyboardManager: multiple keys in shortcut "${value}"`);
2430        break;
2431      }
2432      keyPart = upper === "SPACE" ? " " : part;
2433    }
2434    if (keyPart === null) {
2435      warn(`KeyboardManager: no key found in shortcut "${value}"`);
2436    }
2437    return [keyPart, modifiers];
2438  }
2439  static #codeToKey(code) {
2440    const match = /^(?:Key([A-Z])|(?:Digit|Numpad)(\d))$/.exec(code);
2441    if (!match) {
2442      return null;
2443    }
2444    return match[1]?.toLowerCase() ?? match[2];
2445  }
2446  exec(self, event) {
2447    let shortcuts = this.callbacks.get(event.key);
2448    if (!shortcuts) {
2449      if (/^[a-z]$/i.test(event.key)) {
2450        return;
2451      }
2452      const fallback = KeyboardManager.#codeToKey(event.code);
2453      if (fallback === null || fallback === event.key) {
2454        return;
2455      }
2456      shortcuts = this.callbacks.get(fallback);
2457      if (!shortcuts) {
2458        return;
2459      }
2460    }
2461    const eventModifiers = (event.altKey ? KeyboardManager.ALT : 0) | (event.ctrlKey ? KeyboardManager.CTRL : 0) | (event.metaKey ? KeyboardManager.META : 0) | (event.shiftKey ? KeyboardManager.SHIFT : 0);
2462    const info = shortcuts.find(shortcut => shortcut.modifiers === eventModifiers);
2463    if (!info) {
2464      return;
2465    }
2466    const {
2467      callback,
2468      options: {
2469        bubbles = false,
2470        args = [],
2471        checker = null
2472      }
2473    } = info;
2474    if (checker && !checker(self, event)) {
2475      return;
2476    }
2477    callback.bind(self, ...args, event)();
2478    if (!bubbles) {
2479      stopEvent(event);
2480    }
2481  }
2482}
2483class ColorManager {
2484  static _colorsMapping = new Map([["CanvasText", [0, 0, 0]], ["Canvas", [255, 255, 255]]]);
2485  get _colors() {
2486    const colors = new Map([["CanvasText", null], ["Canvas", null]]);
2487    getColorValues(colors);
2488    return shadow(this, "_colors", colors);
2489  }
2490  convert(color) {
2491    const rgb = getRGB(color);
2492    if (!window.matchMedia("(forced-colors: active)").matches) {
2493      return rgb;
2494    }
2495    for (const [name, RGB] of this._colors) {
2496      if (RGB.every((x, i) => x === rgb[i])) {
2497        return ColorManager._colorsMapping.get(name);
2498      }
2499    }
2500    return rgb;
2501  }
2502  getHexCode(name) {
2503    const rgb = this._colors.get(name);
2504    if (!rgb) {
2505      return name;
2506    }
2507    return Util.makeHexColor(...rgb);
2508  }
2509}
2510class AnnotationEditorUIManager {
2511  #abortController = new AbortController();
2512  #activeEditor = null;
2513  #allEditableAnnotations = null;
2514  #allEditors = new Map();
2515  #allLayers = new Map();
2516  #savedAllLayers = null;
2517  #
vendor: 15,830 bytes, lines 2517-3017
2517altTextManager = null;
2518  #annotationStorage = null;
2519  #changedExistingAnnotations = null;
2520  #commandManager = new CommandManager();
2521  #commentManager = null;
2522  #copyPasteAC = null;
2523  #currentDrawingSession = null;
2524  #currentPageIndex = 0;
2525  #deletedAnnotationsElementIds = new Set();
2526  #draggingEditors = null;
2527  #editorTypes = null;
2528  #editorsToRescale = new Set();
2529  _editorUndoBar = null;
2530  #enableHighlightFloatingButton = false;
2531  #enableUpdatedAddImage = false;
2532  #enableNewAltTextWhenAddingImage = false;
2533  #filterFactory = null;
2534  #focusMainContainerTimeoutId = null;
2535  #focusManagerAC = null;
2536  #highlightColors = null;
2537  #highlightWhenShiftUp = false;
2538  #floatingToolbar = null;
2539  #idManager = new IdManager();
2540  #isEnabled = false;
2541  #isPointerDown = false;
2542  #isWaiting = false;
2543  #keyboardManagerAC = null;
2544  #lastActiveElement = null;
2545  #mainHighlightColorPicker = null;
2546  #missingCanvases = null;
2547  #mlManager = null;
2548  #mode = AnnotationEditorType.NONE;
2549  #selectedEditors = new Set();
2550  #selectedTextNode = null;
2551  #signatureManager = null;
2552  #pageColors = null;
2553  #showAllStates = null;
2554  #pdfDocument = null;
2555  #previousStates = {
2556    isEditing: false,
2557    isEmpty: true,
2558    hasSomethingToUndo: false,
2559    hasSomethingToRedo: false,
2560    hasSelectedEditor: false,
2561    hasSelectedText: false
2562  };
2563  #translation = [0, 0];
2564  #translationTimeoutId = null;
2565  #container = null;
2566  #viewer = null;
2567  #viewerAlert = null;
2568  #updateModeCapability = null;
2569  static TRANSLATE_SMALL = 1;
2570  static TRANSLATE_BIG = 10;
2571  static get _keyboardManager() {
2572    const proto = AnnotationEditorUIManager.prototype;
2573    const arrowChecker = self => self.#container.contains(document.activeElement) && document.activeElement.tagName !== "BUTTON" && self.hasSomethingToControl();
2574    const textInputChecker = (_self, {
2575      target: el
2576    }) => {
2577      if (el instanceof HTMLInputElement) {
2578        const {
2579          type
2580        } = el;
2581        return type !== "text" && type !== "number";
2582      }
2583      return true;
2584    };
2585    const small = this.TRANSLATE_SMALL;
2586    const big = this.TRANSLATE_BIG;
2587    return shadow(this, "_keyboardManager", new KeyboardManager([[["ctrl+a", "mac+meta+a"], proto.selectAll, {
2588      checker: textInputChecker
2589    }], [["ctrl+z", "mac+meta+z"], proto.undo, {
2590      checker: textInputChecker
2591    }], [["ctrl+y", "ctrl+shift+z", "mac+meta+shift+z", "ctrl+shift+Z", "mac+meta+shift+Z"], proto.redo, {
2592      checker: textInputChecker
2593    }], [["Backspace", "alt+Backspace", "ctrl+Backspace", "shift+Backspace", "mac+Backspace", "mac+alt+Backspace", "mac+ctrl+Backspace", "Delete", "ctrl+Delete", "shift+Delete", "mac+Delete"], proto.delete, {
2594      checker: textInputChecker
2595    }], [["Enter"], proto.addNewEditorFromKeyboard, {
2596      checker: (self, {
2597        target: el
2598      }) => !(el instanceof HTMLButtonElement) && self.#container.contains(el) && !self.isEnterHandled
2599    }], [["Space"], proto.addNewEditorFromKeyboard, {
2600      checker: (self, {
2601        target: el
2602      }) => !(el instanceof HTMLButtonElement) && self.#container.contains(document.activeElement)
2603    }], [["Escape"], proto.unselectAll], [["ArrowLeft"], proto.translateSelectedEditors, {
2604      args: [-small, 0],
2605      checker: arrowChecker
2606    }], [["ctrl+ArrowLeft", "mac+shift+ArrowLeft"], proto.translateSelectedEditors, {
2607      args: [-big, 0],
2608      checker: arrowChecker
2609    }], [["ArrowRight"], proto.translateSelectedEditors, {
2610      args: [small, 0],
2611      checker: arrowChecker
2612    }], [["ctrl+ArrowRight", "mac+shift+ArrowRight"], proto.translateSelectedEditors, {
2613      args: [big, 0],
2614      checker: arrowChecker
2615    }], [["ArrowUp"], proto.translateSelectedEditors, {
2616      args: [0, -small],
2617      checker: arrowChecker
2618    }], [["ctrl+ArrowUp", "mac+shift+ArrowUp"], proto.translateSelectedEditors, {
2619      args: [0, -big],
2620      checker: arrowChecker
2621    }], [["ArrowDown"], proto.translateSelectedEditors, {
2622      args: [0, small],
2623      checker: arrowChecker
2624    }], [["ctrl+ArrowDown", "mac+shift+ArrowDown"], proto.translateSelectedEditors, {
2625      args: [0, big],
2626      checker: arrowChecker
2627    }]]));
2628  }
2629  constructor(container, viewer, viewerAlert, altTextManager, commentManager, signatureManager, eventBus, pdfDocument, pageColors, highlightColors, enableHighlightFloatingButton, enableUpdatedAddImage, enableNewAltTextWhenAddingImage, mlManager, editorUndoBar, supportsPinchToZoom) {
2630    const signal = this._signal = this.#abortController.signal;
2631    this.#container = container;
2632    this.#viewer = viewer;
2633    this.#viewerAlert = viewerAlert;
2634    this.#altTextManager = altTextManager;
2635    this.#commentManager = commentManager;
2636    this.#signatureManager = signatureManager;
2637    this.#pdfDocument = pdfDocument;
2638    this._eventBus = eventBus;
2639    const evtOpts = {
2640      signal,
2641      ...internalOpt
2642    };
2643    eventBus.on("editingaction", this.onEditingAction.bind(this), evtOpts);
2644    eventBus.on("pagechanging", this.onPageChanging.bind(this), evtOpts);
2645    eventBus.on("scalechanging", this.onScaleChanging.bind(this), evtOpts);
2646    eventBus.on("rotationchanging", this.onRotationChanging.bind(this), evtOpts);
2647    eventBus.on("setpreference", this.onSetPreference.bind(this), evtOpts);
2648    eventBus.on("switchannotationeditorparams", evt => this.updateParams(evt.type, evt.value), evtOpts);
2649    window.addEventListener("pointerdown", () => {
2650      this.#isPointerDown = true;
2651    }, {
2652      capture: true,
2653      signal
2654    });
2655    window.addEventListener("pointerup", () => {
2656      this.#isPointerDown = false;
2657    }, {
2658      capture: true,
2659      signal
2660    });
2661    window.addEventListener("beforeunload", this.#beforeUnload.bind(this), {
2662      capture: true,
2663      signal
2664    });
2665    this.#addSelectionListener();
2666    this.#addDragAndDropListeners();
2667    this.#addKeyboardManager();
2668    this.#annotationStorage = pdfDocument.annotationStorage;
2669    this.#filterFactory = pdfDocument.filterFactory;
2670    this.#pageColors = pageColors;
2671    this.#highlightColors = highlightColors || null;
2672    this.#enableHighlightFloatingButton = enableHighlightFloatingButton;
2673    this.#enableUpdatedAddImage = enableUpdatedAddImage;
2674    this.#enableNewAltTextWhenAddingImage = enableNewAltTextWhenAddingImage;
2675    this.#mlManager = mlManager || null;
2676    this.viewParameters = {
2677      realScale: PixelsPerInch.PDF_TO_CSS_UNITS,
2678      rotation: 0
2679    };
2680    this.isShiftKeyDown = false;
2681    this._editorUndoBar = editorUndoBar || null;
2682    this._supportsPinchToZoom = supportsPinchToZoom !== false;
2683    commentManager?.setSidebarUiManager(this);
2684  }
2685  destroy() {
2686    this.#updateModeCapability?.resolve();
2687    this.#updateModeCapability = null;
2688    this.#abortController?.abort();
2689    this.#abortController = null;
2690    this._signal = null;
2691    for (const layer of this.#allLayers.values()) {
2692      layer.destroy();
2693    }
2694    this.#allLayers.clear();
2695    this.#allEditors.clear();
2696    this.#editorsToRescale.clear();
2697    this.#missingCanvases?.clear();
2698    this.#activeEditor = null;
2699    this.#selectedEditors.clear();
2700    this.#commandManager.destroy();
2701    this.#altTextManager?.destroy();
2702    this.#commentManager?.destroy();
2703    this.#signatureManager?.destroy();
2704    this.#floatingToolbar?.hide();
2705    this.#floatingToolbar = null;
2706    this.#mainHighlightColorPicker?.destroy();
2707    this.#mainHighlightColorPicker = null;
2708    this.#allEditableAnnotations = null;
2709    if (this.#focusMainContainerTimeoutId) {
2710      clearTimeout(this.#focusMainContainerTimeoutId);
2711      this.#focusMainContainerTimeoutId = null;
2712    }
2713    if (this.#translationTimeoutId) {
2714      clearTimeout(this.#translationTimeoutId);
2715      this.#translationTimeoutId = null;
2716    }
2717    this._editorUndoBar?.destroy();
2718    this.#pdfDocument = null;
2719  }
2720  combinedSignal(ac) {
2721    return AbortSignal.any([this._signal, ac.signal]);
2722  }
2723  get mlManager() {
2724    return this.#mlManager;
2725  }
2726  get useNewAltTextFlow() {
2727    return this.#enableUpdatedAddImage;
2728  }
2729  get useNewAltTextWhenAddingImage() {
2730    return this.#enableNewAltTextWhenAddingImage;
2731  }
2732  get hcmFilter() {
2733    return shadow(this, "hcmFilter", this.#pageColors ? this.#filterFactory.addHCMFilter(this.#pageColors.foreground, this.#pageColors.background) : "none");
2734  }
2735  get direction() {
2736    return shadow(this, "direction", getComputedStyle(this.#container).direction);
2737  }
2738  get _highlightColors() {
2739    return shadow(this, "_highlightColors", this.#highlightColors ? new Map(this.#highlightColors.split(",").map(pair => {
2740      pair = pair.split("=").map(x => x.trim());
2741      pair[1] = pair[1].toUpperCase();
2742      return pair;
2743    })) : null);
2744  }
2745  get highlightColors() {
2746    const {
2747      _highlightColors
2748    } = this;
2749    if (!_highlightColors) {
2750      return shadow(this, "highlightColors", null);
2751    }
2752    const map = new Map();
2753    const hasHCM = !!this.#pageColors;
2754    for (const [name, color] of _highlightColors) {
2755      const isNameForHCM = name.endsWith("_HCM");
2756      if (hasHCM && isNameForHCM) {
2757        map.set(name.replace("_HCM", ""), color);
2758        continue;
2759      }
2760      if (!hasHCM && !isNameForHCM) {
2761        map.set(name, color);
2762      }
2763    }
2764    return shadow(this, "highlightColors", map);
2765  }
2766  get highlightColorNames() {
2767    return shadow(this, "highlightColorNames", this.highlightColors ? new Map(Array.from(this.highlightColors, e => e.reverse())) : null);
2768  }
2769  getNonHCMColor(color) {
2770    if (!this._highlightColors) {
2771      return color;
2772    }
2773    const colorName = this.highlightColorNames.get(color);
2774    return this._highlightColors.get(colorName) || color;
2775  }
2776  getNonHCMColorName(color) {
2777    return this.highlightColorNames.get(color) || color;
2778  }
2779  setCurrentDrawingSession(layer) {
2780    if (layer) {
2781      this.unselectAll();
2782      this.disableUserSelect(true);
2783    } else {
2784      this.disableUserSelect(false);
2785    }
2786    this.#currentDrawingSession = layer;
2787  }
2788  setMainHighlightColorPicker(colorPicker) {
2789    this.#mainHighlightColorPicker = colorPicker;
2790  }
2791  editAltText(editor, firstTime = false) {
2792    this.#altTextManager?.editAltText(this, editor, firstTime);
2793  }
2794  hasCommentManager() {
2795    return !!this.#commentManager;
2796  }
2797  editComment(editor, posX, posY, options) {
2798    this.#commentManager?.showDialog(this, editor, posX, posY, options);
2799  }
2800  selectComment(pageIndex, uid) {
2801    const layer = this.#allLayers.get(pageIndex);
2802    const editor = layer?.getEditorByUID(uid);
2803    editor?.toggleComment(true, true);
2804  }
2805  updateComment(editor) {
2806    this.#commentManager?.updateComment(editor.getData());
2807  }
2808  updatePopupColor(editor) {
2809    this.#commentManager?.updatePopupColor(editor);
2810  }
2811  removeComment(editor) {
2812    this.#commentManager?.removeComments([editor.uid]);
2813  }
2814  deleteComment(editor, savedData) {
2815    const undo = () => {
2816      editor.comment = savedData;
2817    };
2818    const cmd = () => {
2819      this._editorUndoBar?.show(undo, "comment");
2820      this.toggleComment(null);
2821      editor.comment = null;
2822    };
2823    this.addCommands({
2824      cmd,
2825      undo,
2826      mustExec: true
2827    });
2828  }
2829  toggleComment(editor, isSelected, visibility = undefined) {
2830    this.#commentManager?.toggleCommentPopup(editor, isSelected, visibility);
2831  }
2832  makeCommentColor(color, opacity) {
2833    return color && this.#commentManager?.makeCommentColor(color, opacity) || null;
2834  }
2835  getCommentDialogElement() {
2836    return this.#commentManager?.dialogElement || null;
2837  }
2838  async waitForEditorsRendered(pageNumber) {
2839    if (this.#allLayers.has(pageNumber - 1)) {
2840      return;
2841    }
2842    const {
2843      resolve,
2844      promise
2845    } = Promise.withResolvers();
2846    const onEditorsRendered = evt => {
2847      if (evt.pageNumber === pageNumber) {
2848        this._eventBus.off("editorsrendered", onEditorsRendered);
2849        resolve();
2850      }
2851    };
2852    this._eventBus.on("editorsrendered", onEditorsRendered, internalOpt);
2853    await promise;
2854  }
2855  getSignature(editor) {
2856    this.#signatureManager?.getSignature({
2857      uiManager: this,
2858      editor
2859    });
2860  }
2861  get signatureManager() {
2862    return this.#signatureManager;
2863  }
2864  switchToMode(mode, callback) {
2865    this._eventBus.on("annotationeditormodechanged", callback, {
2866      once: true,
2867      signal: this._signal,
2868      ...internalOpt
2869    });
2870    this._eventBus.dispatch("showannotationeditorui", {
2871      source: this,
2872      mode
2873    });
2874  }
2875  setPreference(name, value) {
2876    this._eventBus.dispatch("setpreference", {
2877      source: this,
2878      name,
2879      value
2880    });
2881  }
2882  onSetPreference({
2883    name,
2884    value
2885  }) {
2886    switch (name) {
2887      case "enableNewAltTextWhenAddingImage":
2888        this.#enableNewAltTextWhenAddingImage = value;
2889        break;
2890    }
2891  }
2892  onPageChanging({
2893    pageNumber
2894  }) {
2895    this.#currentPageIndex = pageNumber - 1;
2896  }
2897  deletePage(id) {
2898    for (const editor of this.getEditors(id)) {
2899      editor.remove();
2900    }
2901    this.#allLayers.delete(id);
2902    if (this.#currentPageIndex === id) {
2903      this.#currentPageIndex = 0;
2904    }
2905  }
2906  focusMainContainer() {
2907    this.#container.focus();
2908  }
2909  findParent(x, y) {
2910    for (const layer of this.#allLayers.values()) {
2911      const {
2912        x: layerX,
2913        y: layerY,
2914        width,
2915        height
2916      } = layer.div.getBoundingClientRect();
2917      if (x >= layerX && x <= layerX + width && y >= layerY && y <= layerY + height) {
2918        return layer;
2919      }
2920    }
2921    return null;
2922  }
2923  disableUserSelect(value = false) {
2924    this.#viewer.classList.toggle("noUserSelect", value);
2925  }
2926  addShouldRescale(editor) {
2927    this.#editorsToRescale.add(editor);
2928  }
2929  removeShouldRescale(editor) {
2930    this.#editorsToRescale.delete(editor);
2931  }
2932  onScaleChanging({
2933    scale
2934  }) {
2935    this.commitOrRemove();
2936    this.viewParameters.realScale = scale * PixelsPerInch.PDF_TO_CSS_UNITS;
2937    for (const editor of this.#editorsToRescale) {
2938      editor.onScaleChanging();
2939    }
2940    this.#currentDrawingSession?.onScaleChanging();
2941  }
2942  onRotationChanging({
2943    pagesRotation
2944  }) {
2945    this.commitOrRemove();
2946    this.viewParameters.rotation = pagesRotation;
2947  }
2948  #getAnchorElementForSelection({
2949    anchorNode
2950  }) {
2951    return anchorNode.nodeType === Node.TEXT_NODE ? anchorNode.parentElement : anchorNode;
2952  }
2953  #getLayerForTextLayer(textLayer) {
2954    const {
2955      currentLayer
2956    } = this;
2957    if (currentLayer.hasTextLayer(textLayer)) {
2958      return currentLayer;
2959    }
2960    for (const layer of this.#allLayers.values()) {
2961      if (layer.hasTextLayer(textLayer)) {
2962        return layer;
2963      }
2964    }
2965    return null;
2966  }
2967  highlightSelection(methodOfCreation = "", comment = false) {
2968    const selection = document.getSelection();
2969    if (!selection || selection.isCollapsed) {
2970      return;
2971    }
2972    const {
2973      anchorNode,
2974      anchorOffset,
2975      focusNode,
2976      focusOffset
2977    } = selection;
2978    const text = selection.toString();
2979    const anchorElement = this.#getAnchorElementForSelection(selection);
2980    const textLayer = anchorElement.closest(".textLayer");
2981    const boxes = this.getSelectionBoxes(textLayer);
2982    if (!boxes) {
2983      return;
2984    }
2985    selection.empty();
2986    const layer = this.#getLayerForTextLayer(textLayer);
2987    const isNoneMode = this.#mode === AnnotationEditorType.NONE;
2988    const callback = () => {
2989      const editor = layer?.createAndAddNewEditor({
2990        x: 0,
2991        y: 0
2992      }, false, {
2993        methodOfCreation,
2994        boxes,
2995        anchorNode,
2996        anchorOffset,
2997        focusNode,
2998        focusOffset,
2999        text
3000      });
3001      if (isNoneMode) {
3002        this.showAllEditors("highlight", true, true);
3003      }
3004      if (comment) {
3005        editor?.editComment();
3006      }
3007    };
3008    if (isNoneMode) {
3009      this.switchToMode(AnnotationEditorType.HIGHLIGHT, callback);
3010      return;
3011    }
3012    callback();
3013  }
3014  commentSelection(methodOfCreation = "") {
3015    this.highlightSelection(methodOfCreation, true);
3016  }
3017  #beforeUnload(e
vendor: 10,355 bytes, lines 3017-3389
3017) {
3018    this.commitOrRemove();
3019    this.currentLayer?.endDrawingSession(false);
3020  }
3021  #displayFloatingToolbar() {
3022    const selection = document.getSelection();
3023    if (!selection || selection.isCollapsed) {
3024      return;
3025    }
3026    const anchorElement = this.#getAnchorElementForSelection(selection);
3027    const textLayer = anchorElement.closest(".textLayer");
3028    const boxes = this.getSelectionBoxes(textLayer);
3029    if (!boxes) {
3030      return;
3031    }
3032    this.#floatingToolbar ||= new FloatingToolbar(this);
3033    this.#floatingToolbar.show(textLayer, boxes, this.direction === "ltr");
3034  }
3035  getAndRemoveDataFromAnnotationStorage(annotationId) {
3036    if (!this.#annotationStorage) {
3037      return null;
3038    }
3039    const key = `${AnnotationEditorPrefix}${annotationId}`;
3040    const storedValue = this.#annotationStorage.getRawValue(key);
3041    if (storedValue) {
3042      this.#annotationStorage.remove(key);
3043    }
3044    return storedValue;
3045  }
3046  addToAnnotationStorage(editor) {
3047    if (!editor.isEmpty() && this.#annotationStorage && !this.#annotationStorage.has(editor.id)) {
3048      this.#annotationStorage.setValue(editor.id, editor);
3049    }
3050  }
3051  a11yAlert(messageId, args = null) {
3052    const viewerAlert = this.#viewerAlert;
3053    if (!viewerAlert) {
3054      return;
3055    }
3056    viewerAlert.setAttribute("data-l10n-id", messageId);
3057    if (args) {
3058      viewerAlert.setAttribute("data-l10n-args", JSON.stringify(args));
3059    } else {
3060      viewerAlert.removeAttribute("data-l10n-args");
3061    }
3062  }
3063  #selectionChange() {
3064    const selection = document.getSelection();
3065    if (!selection || selection.isCollapsed) {
3066      if (this.#selectedTextNode) {
3067        this.#floatingToolbar?.hide();
3068        this.#selectedTextNode = null;
3069        this.#dispatchUpdateStates({
3070          hasSelectedText: false
3071        });
3072      }
3073      return;
3074    }
3075    const {
3076      anchorNode
3077    } = selection;
3078    if (anchorNode === this.#selectedTextNode) {
3079      return;
3080    }
3081    const anchorElement = this.#getAnchorElementForSelection(selection);
3082    const textLayer = anchorElement.closest(".textLayer");
3083    if (!textLayer) {
3084      if (this.#selectedTextNode) {
3085        this.#floatingToolbar?.hide();
3086        this.#selectedTextNode = null;
3087        this.#dispatchUpdateStates({
3088          hasSelectedText: false
3089        });
3090      }
3091      return;
3092    }
3093    this.#floatingToolbar?.hide();
3094    this.#selectedTextNode = anchorNode;
3095    this.#dispatchUpdateStates({
3096      hasSelectedText: true
3097    });
3098    if (this.#mode !== AnnotationEditorType.HIGHLIGHT && this.#mode !== AnnotationEditorType.NONE) {
3099      return;
3100    }
3101    if (this.#mode === AnnotationEditorType.HIGHLIGHT) {
3102      this.showAllEditors("highlight", true, true);
3103    }
3104    this.#highlightWhenShiftUp = this.isShiftKeyDown;
3105    if (!this.isShiftKeyDown) {
3106      const activeLayer = this.#mode === AnnotationEditorType.HIGHLIGHT ? this.#getLayerForTextLayer(textLayer) : null;
3107      activeLayer?.toggleDrawing();
3108      if (this.#isPointerDown) {
3109        const ac = new AbortController();
3110        const signal = this.combinedSignal(ac);
3111        const pointerup = e => {
3112          if (e.type === "pointerup" && e.button !== 0) {
3113            return;
3114          }
3115          ac.abort();
3116          activeLayer?.toggleDrawing(true);
3117          if (e.type === "pointerup") {
3118            this.#onSelectEnd("main_toolbar");
3119          }
3120        };
3121        window.addEventListener("pointerup", pointerup, {
3122          signal
3123        });
3124        window.addEventListener("blur", pointerup, {
3125          signal
3126        });
3127      } else {
3128        activeLayer?.toggleDrawing(true);
3129        this.#onSelectEnd("main_toolbar");
3130      }
3131    }
3132  }
3133  #onSelectEnd(methodOfCreation = "") {
3134    if (this.#mode === AnnotationEditorType.HIGHLIGHT) {
3135      this.highlightSelection(methodOfCreation);
3136    } else if (this.#enableHighlightFloatingButton) {
3137      this.#displayFloatingToolbar();
3138    }
3139  }
3140  #addSelectionListener() {
3141    document.addEventListener("selectionchange", this.#selectionChange.bind(this), {
3142      signal: this._signal
3143    });
3144  }
3145  #addFocusManager() {
3146    if (this.#focusManagerAC) {
3147      return;
3148    }
3149    this.#focusManagerAC = new AbortController();
3150    const signal = this.combinedSignal(this.#focusManagerAC);
3151    window.addEventListener("focus", this.focus.bind(this), {
3152      signal
3153    });
3154    window.addEventListener("blur", this.blur.bind(this), {
3155      signal
3156    });
3157  }
3158  #removeFocusManager() {
3159    this.#focusManagerAC?.abort();
3160    this.#focusManagerAC = null;
3161  }
3162  blur() {
3163    this.isShiftKeyDown = false;
3164    if (this.#highlightWhenShiftUp) {
3165      this.#highlightWhenShiftUp = false;
3166      this.#onSelectEnd("main_toolbar");
3167    }
3168    if (!this.hasSelection) {
3169      return;
3170    }
3171    const {
3172      activeElement
3173    } = document;
3174    for (const editor of this.#selectedEditors) {
3175      if (editor.div.contains(activeElement)) {
3176        this.#lastActiveElement = [editor, activeElement];
3177        editor._focusEventsAllowed = false;
3178        break;
3179      }
3180    }
3181  }
3182  focus() {
3183    if (!this.#lastActiveElement) {
3184      return;
3185    }
3186    const [lastEditor, lastActiveElement] = this.#lastActiveElement;
3187    this.#lastActiveElement = null;
3188    lastActiveElement.addEventListener("focusin", () => {
3189      lastEditor._focusEventsAllowed = true;
3190    }, {
3191      once: true,
3192      signal: this._signal
3193    });
3194    lastActiveElement.focus();
3195  }
3196  #addKeyboardManager() {
3197    if (this.#keyboardManagerAC) {
3198      return;
3199    }
3200    this.#keyboardManagerAC = new AbortController();
3201    const signal = this.combinedSignal(this.#keyboardManagerAC);
3202    window.addEventListener("keydown", this.keydown.bind(this), {
3203      signal
3204    });
3205    window.addEventListener("keyup", this.keyup.bind(this), {
3206      signal
3207    });
3208  }
3209  #removeKeyboardManager() {
3210    this.#keyboardManagerAC?.abort();
3211    this.#keyboardManagerAC = null;
3212  }
3213  #addCopyPasteListeners() {
3214    if (this.#copyPasteAC) {
3215      return;
3216    }
3217    this.#copyPasteAC = new AbortController();
3218    const signal = this.combinedSignal(this.#copyPasteAC);
3219    document.addEventListener("copy", this.copy.bind(this), {
3220      signal
3221    });
3222    document.addEventListener("cut", this.cut.bind(this), {
3223      signal
3224    });
3225    document.addEventListener("paste", this.paste.bind(this), {
3226      signal
3227    });
3228  }
3229  #removeCopyPasteListeners() {
3230    this.#copyPasteAC?.abort();
3231    this.#copyPasteAC = null;
3232  }
3233  #addDragAndDropListeners() {
3234    const signal = this._signal;
3235    document.addEventListener("dragover", this.dragOver.bind(this), {
3236      signal
3237    });
3238    document.addEventListener("drop", this.drop.bind(this), {
3239      signal
3240    });
3241  }
3242  addEditListeners() {
3243    this.#addKeyboardManager();
3244    this.setEditingState(true);
3245  }
3246  removeEditListeners() {
3247    this.#removeKeyboardManager();
3248    this.setEditingState(false);
3249  }
3250  dragOver(event) {
3251    for (const {
3252      type
3253    } of event.dataTransfer.items) {
3254      for (const editorType of this.#editorTypes) {
3255        if (editorType.isHandlingMimeForPasting(type)) {
3256          event.dataTransfer.dropEffect = "copy";
3257          event.preventDefault();
3258          return;
3259        }
3260      }
3261    }
3262  }
3263  drop(event) {
3264    for (const item of event.dataTransfer.items) {
3265      for (const editorType of this.#editorTypes) {
3266        if (editorType.isHandlingMimeForPasting(item.type)) {
3267          editorType.paste(item, this.currentLayer);
3268          event.preventDefault();
3269          return;
3270        }
3271      }
3272    }
3273  }
3274  copy(event) {
3275    event.preventDefault();
3276    this.#activeEditor?.commitOrRemove();
3277    if (!this.hasSelection) {
3278      return;
3279    }
3280    const editors = [];
3281    for (const editor of this.#selectedEditors) {
3282      const serialized = editor.serialize(true);
3283      if (serialized) {
3284        editors.push(serialized);
3285      }
3286    }
3287    if (editors.length === 0) {
3288      return;
3289    }
3290    event.clipboardData.setData("application/pdfjs", JSON.stringify(editors));
3291  }
3292  cut(event) {
3293    this.copy(event);
3294    this.delete();
3295  }
3296  async paste(event) {
3297    event.preventDefault();
3298    const {
3299      clipboardData
3300    } = event;
3301    for (const item of clipboardData.items) {
3302      for (const editorType of this.#editorTypes) {
3303        if (editorType.isHandlingMimeForPasting(item.type)) {
3304          editorType.paste(item, this.currentLayer);
3305          return;
3306        }
3307      }
3308    }
3309    let data = clipboardData.getData("application/pdfjs");
3310    if (!data) {
3311      return;
3312    }
3313    try {
3314      data = JSON.parse(data);
3315    } catch (ex) {
3316      warn(`paste: "${ex.message}".`);
3317      return;
3318    }
3319    if (!Array.isArray(data)) {
3320      return;
3321    }
3322    this.unselectAll();
3323    const layer = this.currentLayer;
3324    try {
3325      const newEditors = [];
3326      for (const editor of data) {
3327        const deserializedEditor = await layer.deserialize(editor);
3328        if (!deserializedEditor) {
3329          return;
3330        }
3331        newEditors.push(deserializedEditor);
3332      }
3333      const cmd = () => {
3334        for (const editor of newEditors) {
3335          this.#addEditorToLayer(editor);
3336        }
3337        this.#selectEditors(newEditors);
3338      };
3339      const undo = () => {
3340        for (const editor of newEditors) {
3341          editor.remove();
3342        }
3343      };
3344      this.addCommands({
3345        cmd,
3346        undo,
3347        mustExec: true
3348      });
3349    } catch (ex) {
3350      warn(`paste: "${ex.message}".`);
3351    }
3352  }
3353  keydown(event) {
3354    if (!this.isShiftKeyDown && event.key === "Shift") {
3355      this.isShiftKeyDown = true;
3356    }
3357    if (this.#mode !== AnnotationEditorType.NONE && !this.isEditorHandlingKeyboard) {
3358      AnnotationEditorUIManager._keyboardManager.exec(this, event);
3359    }
3360  }
3361  keyup(event) {
3362    if (this.isShiftKeyDown && event.key === "Shift") {
3363      this.isShiftKeyDown = false;
3364      if (this.#highlightWhenShiftUp) {
3365        this.#highlightWhenShiftUp = false;
3366        this.#onSelectEnd("main_toolbar");
3367      }
3368    }
3369  }
3370  onEditingAction({
3371    name
3372  }) {
3373    switch (name) {
3374      case "undo":
3375      case "redo":
3376      case "delete":
3377      case "selectAll":
3378        this[name]();
3379        break;
3380      case "highlightSelection":
3381        this.highlightSelection("context_menu");
3382        break;
3383      case "commentSelection":
3384        this.commentSelection("context_menu");
3385        break;
3386    }
3387  }
3388  updatePageIndex(oldPageIndex, newPageIndex) {
3389    for (const editor of this.
3389getEditors(oldPageIndex)) {
3390      editor.pageIndex = newPageIndex;
3391    }
3392    const layer = this.#savedAllLayers.get(oldPageIndex);
3393    if (layer) {
3394      layer.pageIndex = newPageIndex;
3395      this.#allLayers.set(newPageIndex, layer);
3396      if (this.#isEnabled) {
3397        layer.enable();
3398      } else {
3399        layer.disable();
3400      }
3401    }
3402  }
3403  startUpdatePages() {
3404    this.#savedAllLayers = new Map(this.#allLayers);
3405    this.#allLayers.clear();
3406  }
3407  endUpdatePages() {
3408    this.#savedAllLayers
vendor: 25,619 bytes, lines 3408-4303
3408 = null;
3409  }
3410  clonePage(pageIndex, newPageIndex) {
3411    for (const editor of this.getEditors(pageIndex)) {
3412      const serialized = editor.serialize(editor.mode !== AnnotationEditorType.HIGHLIGHT);
3413      if (!serialized) {
3414        continue;
3415      }
3416      serialized.pageIndex = newPageIndex;
3417      serialized.id = this.getId();
3418      serialized.isClone = true;
3419      delete serialized.popupRef;
3420      this.#annotationStorage.setValue(serialized.id, serialized);
3421    }
3422  }
3423  findClonesForPage(layer) {
3424    const promises = [];
3425    const {
3426      pageIndex
3427    } = layer;
3428    for (const [id, editor] of this.#annotationStorage) {
3429      if (editor.pageIndex === pageIndex && editor.isClone) {
3430        this.#annotationStorage.remove(id);
3431        promises.push(layer.deserialize(editor).then(deserializedEditor => {
3432          if (deserializedEditor) {
3433            deserializedEditor.isClone = true;
3434            layer.addOrRebuild(deserializedEditor);
3435          }
3436        }));
3437      }
3438    }
3439    return Promise.all(promises);
3440  }
3441  #dispatchUpdateStates(details) {
3442    const hasChanged = Object.entries(details).some(([key, value]) => this.#previousStates[key] !== value);
3443    if (hasChanged) {
3444      this._eventBus.dispatch("editingstateschanged", {
3445        source: this,
3446        details: Object.assign(this.#previousStates, details)
3447      });
3448      if (this.#mode === AnnotationEditorType.HIGHLIGHT && details.hasSelectedEditor === false) {
3449        this.#dispatchUpdateUI([[AnnotationEditorParamsType.HIGHLIGHT_FREE, true]]);
3450      }
3451    }
3452  }
3453  #dispatchUpdateUI(details) {
3454    this._eventBus.dispatch("annotationeditorparamschanged", {
3455      source: this,
3456      details
3457    });
3458  }
3459  setEditingState(isEditing) {
3460    if (isEditing) {
3461      this.#addFocusManager();
3462      this.#addCopyPasteListeners();
3463      this.#dispatchUpdateStates({
3464        isEditing: this.#mode !== AnnotationEditorType.NONE,
3465        isEmpty: this.#isEmpty(),
3466        hasSomethingToUndo: this.#commandManager.hasSomethingToUndo(),
3467        hasSomethingToRedo: this.#commandManager.hasSomethingToRedo(),
3468        hasSelectedEditor: false
3469      });
3470    } else {
3471      this.#removeFocusManager();
3472      this.#removeCopyPasteListeners();
3473      this.#dispatchUpdateStates({
3474        isEditing: false
3475      });
3476      this.disableUserSelect(false);
3477    }
3478  }
3479  registerEditorTypes(types) {
3480    if (this.#editorTypes) {
3481      return;
3482    }
3483    this.#editorTypes = types;
3484    for (const editorType of this.#editorTypes) {
3485      this.#dispatchUpdateUI(editorType.defaultPropertiesToUpdate);
3486    }
3487  }
3488  getId() {
3489    return this.#idManager.id;
3490  }
3491  get currentLayer() {
3492    return this.#allLayers.get(this.#currentPageIndex);
3493  }
3494  getLayer(pageIndex) {
3495    return this.#allLayers.get(pageIndex);
3496  }
3497  get currentPageIndex() {
3498    return this.#currentPageIndex;
3499  }
3500  addLayer(layer) {
3501    this.#allLayers.set(layer.pageIndex, layer);
3502    if (this.#isEnabled) {
3503      layer.enable();
3504    } else {
3505      layer.disable();
3506    }
3507  }
3508  removeLayer(layer) {
3509    this.#allLayers.delete(layer.pageIndex);
3510  }
3511  async updateMode(mode, editId = null, isFromUser = false, isFromKeyboard = false, mustEnterInEditMode = false, editComment = false) {
3512    if (this.#mode === mode) {
3513      return;
3514    }
3515    if (this.#updateModeCapability) {
3516      await this.#updateModeCapability.promise;
3517      if (!this.#updateModeCapability) {
3518        return;
3519      }
3520    }
3521    this.#updateModeCapability = Promise.withResolvers();
3522    this.#currentDrawingSession?.commitOrRemove();
3523    if (this.#mode === AnnotationEditorType.POPUP) {
3524      this.#commentManager?.hideSidebar();
3525    }
3526    this.#commentManager?.destroyPopup();
3527    this.#mode = mode;
3528    if (mode === AnnotationEditorType.NONE) {
3529      this.setEditingState(false);
3530      this.#disableAll();
3531      for (const editor of this.#allEditors.values()) {
3532        editor.hideStandaloneCommentButton();
3533      }
3534      this._editorUndoBar?.hide();
3535      this.toggleComment(null);
3536      this.#updateModeCapability.resolve();
3537      return;
3538    }
3539    for (const editor of this.#allEditors.values()) {
3540      editor.addStandaloneCommentButton();
3541    }
3542    if (mode === AnnotationEditorType.SIGNATURE) {
3543      await this.#signatureManager?.loadSignatures();
3544    }
3545    if (isFromUser) {
3546      CurrentPointers.clearPointerType();
3547    }
3548    this.setEditingState(true);
3549    await this.#enableAll();
3550    this.unselectAll();
3551    for (const layer of this.#allLayers.values()) {
3552      layer.updateMode(mode);
3553    }
3554    if (mode === AnnotationEditorType.POPUP) {
3555      this.#allEditableAnnotations ||= await this.#pdfDocument.getAnnotationsByType(new Set(this.#editorTypes.map(editorClass => editorClass._editorType)));
3556      const elementIds = new Set();
3557      const allComments = [];
3558      for (const editor of this.#allEditors.values()) {
3559        const {
3560          annotationElementId,
3561          hasComment,
3562          deleted
3563        } = editor;
3564        if (annotationElementId) {
3565          elementIds.add(annotationElementId);
3566        }
3567        if (hasComment && !deleted) {
3568          allComments.push(editor.getData());
3569        }
3570      }
3571      for (const annotation of this.#allEditableAnnotations) {
3572        const {
3573          id,
3574          popupRef,
3575          contentsObj
3576        } = annotation;
3577        if (popupRef && contentsObj?.str && !elementIds.has(id) && !this.#deletedAnnotationsElementIds.has(id)) {
3578          allComments.push(annotation);
3579        }
3580      }
3581      this.#commentManager?.showSidebar(allComments);
3582    }
3583    if (!editId) {
3584      if (isFromKeyboard) {
3585        this.addNewEditorFromKeyboard();
3586      }
3587      this.#updateModeCapability.resolve();
3588      return;
3589    }
3590    for (const editor of this.#allEditors.values()) {
3591      if (editor.uid === editId) {
3592        this.setSelected(editor);
3593        if (editComment) {
3594          editor.editComment();
3595        } else if (mustEnterInEditMode) {
3596          editor.enterInEditMode();
3597        } else {
3598          editor.focus();
3599        }
3600      } else {
3601        editor.unselect();
3602      }
3603    }
3604    this.#updateModeCapability.resolve();
3605  }
3606  addNewEditorFromKeyboard() {
3607    if (this.currentLayer.canCreateNewEmptyEditor()) {
3608      this.currentLayer.addNewEditor();
3609    }
3610  }
3611  updateToolbar(options) {
3612    if (options.mode === this.#mode) {
3613      return;
3614    }
3615    this._eventBus.dispatch("switchannotationeditormode", {
3616      source: this,
3617      ...options
3618    });
3619  }
3620  updateParams(type, value) {
3621    if (!this.#editorTypes) {
3622      return;
3623    }
3624    switch (type) {
3625      case AnnotationEditorParamsType.CREATE:
3626        this.currentLayer.addNewEditor(value);
3627        return;
3628      case AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL:
3629        this._eventBus.dispatch("reporttelemetry", {
3630          source: this,
3631          details: {
3632            type: "editing",
3633            data: {
3634              type: "highlight",
3635              action: "toggle_visibility"
3636            }
3637          }
3638        });
3639        (this.#showAllStates ||= new Map()).set(type, value);
3640        this.showAllEditors("highlight", value);
3641        break;
3642    }
3643    if (this.hasSelection) {
3644      for (const editor of this.#selectedEditors) {
3645        editor.updateParams(type, value);
3646      }
3647    } else {
3648      for (const editorType of this.#editorTypes) {
3649        editorType.updateDefaultParams(type, value);
3650      }
3651    }
3652  }
3653  showAllEditors(type, visible, updateButton = false) {
3654    for (const editor of this.#allEditors.values()) {
3655      if (editor.editorType === type) {
3656        editor.show(visible);
3657      }
3658    }
3659    const state = this.#showAllStates?.get(AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL) ?? true;
3660    if (state !== visible) {
3661      this.#dispatchUpdateUI([[AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL, visible]]);
3662    }
3663  }
3664  enableWaiting(mustWait = false) {
3665    if (this.#isWaiting === mustWait) {
3666      return;
3667    }
3668    this.#isWaiting = mustWait;
3669    for (const layer of this.#allLayers.values()) {
3670      if (mustWait) {
3671        layer.disableClick();
3672      } else {
3673        layer.enableClick();
3674      }
3675      layer.div.classList.toggle("waiting", mustWait);
3676    }
3677  }
3678  async #enableAll() {
3679    if (!this.#isEnabled) {
3680      this.#isEnabled = true;
3681      const promises = [];
3682      for (const layer of this.#allLayers.values()) {
3683        promises.push(layer.enable());
3684      }
3685      await Promise.all(promises);
3686      for (const editor of this.#allEditors.values()) {
3687        editor.enable();
3688      }
3689    }
3690  }
3691  #disableAll() {
3692    this.unselectAll();
3693    if (this.#isEnabled) {
3694      this.#isEnabled = false;
3695      for (const layer of this.#allLayers.values()) {
3696        layer.disable();
3697      }
3698      for (const editor of this.#allEditors.values()) {
3699        editor.disable();
3700      }
3701    }
3702  }
3703  *getEditors(pageIndex) {
3704    for (const editor of this.#allEditors.values()) {
3705      if (editor.pageIndex === pageIndex) {
3706        yield editor;
3707      }
3708    }
3709  }
3710  getEditor(id) {
3711    return this.#allEditors.get(id);
3712  }
3713  addEditor(editor) {
3714    this.#allEditors.set(editor.id, editor);
3715  }
3716  removeEditor(editor) {
3717    if (editor.div.contains(document.activeElement)) {
3718      if (this.#focusMainContainerTimeoutId) {
3719        clearTimeout(this.#focusMainContainerTimeoutId);
3720      }
3721      this.#focusMainContainerTimeoutId = setTimeout(() => {
3722        this.focusMainContainer();
3723        this.#focusMainContainerTimeoutId = null;
3724      }, 0);
3725    }
3726    this.#allEditors.delete(editor.id);
3727    if (editor.annotationElementId) {
3728      this.#missingCanvases?.delete(editor.annotationElementId);
3729    }
3730    this.unselect(editor);
3731    if (!editor.annotationElementId || !this.#deletedAnnotationsElementIds.has(editor.annotationElementId)) {
3732      this.#annotationStorage?.remove(editor.id);
3733    }
3734  }
3735  addDeletedAnnotationElement(editor) {
3736    this.#deletedAnnotationsElementIds.add(editor.annotationElementId);
3737    this.addChangedExistingAnnotation(editor);
3738    editor.deleted = true;
3739  }
3740  isDeletedAnnotationElement(annotationElementId) {
3741    return this.#deletedAnnotationsElementIds.has(annotationElementId);
3742  }
3743  removeDeletedAnnotationElement(editor) {
3744    this.#deletedAnnotationsElementIds.delete(editor.annotationElementId);
3745    this.removeChangedExistingAnnotation(editor);
3746    editor.deleted = false;
3747  }
3748  #addEditorToLayer(editor) {
3749    const layer = this.#allLayers.get(editor.pageIndex);
3750    if (layer) {
3751      layer.addOrRebuild(editor);
3752    } else {
3753      this.addEditor(editor);
3754      this.addToAnnotationStorage(editor);
3755    }
3756  }
3757  setActiveEditor(editor) {
3758    if (this.#activeEditor === editor) {
3759      return;
3760    }
3761    this.#activeEditor = editor;
3762    if (editor) {
3763      this.#dispatchUpdateUI(editor.propertiesToUpdate);
3764    }
3765  }
3766  get #lastSelectedEditor() {
3767    let ed = null;
3768    for (ed of this.#selectedEditors) {}
3769    return ed;
3770  }
3771  updateUI(editor) {
3772    if (this.#lastSelectedEditor === editor) {
3773      this.#dispatchUpdateUI(editor.propertiesToUpdate);
3774    }
3775  }
3776  updateUIForDefaultProperties(editorType) {
3777    this.#dispatchUpdateUI(editorType.defaultPropertiesToUpdate);
3778  }
3779  toggleSelected(editor) {
3780    if (this.#selectedEditors.has(editor)) {
3781      this.#selectedEditors.delete(editor);
3782      editor.unselect();
3783      this.#dispatchUpdateStates({
3784        hasSelectedEditor: this.hasSelection
3785      });
3786      return;
3787    }
3788    this.#selectedEditors.add(editor);
3789    editor.select();
3790    this.#dispatchUpdateUI(editor.propertiesToUpdate);
3791    this.#dispatchUpdateStates({
3792      hasSelectedEditor: true
3793    });
3794  }
3795  setSelected(editor) {
3796    this.updateToolbar({
3797      mode: editor.mode,
3798      editId: editor.uid
3799    });
3800    this.#currentDrawingSession?.commitOrRemove();
3801    for (const ed of this.#selectedEditors) {
3802      if (ed !== editor) {
3803        ed.unselect();
3804      }
3805    }
3806    this.#commentManager?.destroyPopup();
3807    this.#selectedEditors.clear();
3808    this.#selectedEditors.add(editor);
3809    editor.select();
3810    this.#dispatchUpdateUI(editor.propertiesToUpdate);
3811    this.#dispatchUpdateStates({
3812      hasSelectedEditor: true
3813    });
3814  }
3815  get firstSelectedEditor() {
3816    return this.#selectedEditors.values().next().value;
3817  }
3818  unselect(editor) {
3819    editor.unselect();
3820    this.#selectedEditors.delete(editor);
3821    this.#dispatchUpdateStates({
3822      hasSelectedEditor: this.hasSelection
3823    });
3824  }
3825  get hasSelection() {
3826    return this.#selectedEditors.size !== 0;
3827  }
3828  get isEnterHandled() {
3829    return this.#selectedEditors.size === 1 && this.firstSelectedEditor.isEnterHandled;
3830  }
3831  undo() {
3832    this.#commandManager.undo();
3833    this.#dispatchUpdateStates({
3834      hasSomethingToUndo: this.#commandManager.hasSomethingToUndo(),
3835      hasSomethingToRedo: true,
3836      isEmpty: this.#isEmpty()
3837    });
3838    this._editorUndoBar?.hide();
3839  }
3840  redo() {
3841    this.#commandManager.redo();
3842    this.#dispatchUpdateStates({
3843      hasSomethingToUndo: true,
3844      hasSomethingToRedo: this.#commandManager.hasSomethingToRedo(),
3845      isEmpty: this.#isEmpty()
3846    });
3847  }
3848  addCommands(params) {
3849    this.#commandManager.add(params);
3850    this.#dispatchUpdateStates({
3851      hasSomethingToUndo: true,
3852      hasSomethingToRedo: false,
3853      isEmpty: this.#isEmpty()
3854    });
3855  }
3856  cleanUndoStack(type) {
3857    this.#commandManager.cleanType(type);
3858  }
3859  #isEmpty() {
3860    if (this.#allEditors.size === 0) {
3861      return true;
3862    }
3863    if (this.#allEditors.size === 1) {
3864      for (const editor of this.#allEditors.values()) {
3865        return editor.isEmpty();
3866      }
3867    }
3868    return false;
3869  }
3870  delete() {
3871    this.commitOrRemove();
3872    const drawingEditor = this.currentLayer?.endDrawingSession(true);
3873    if (!this.hasSelection && !drawingEditor) {
3874      return;
3875    }
3876    const editors = drawingEditor ? [drawingEditor] : [...this.#selectedEditors];
3877    const cmd = () => {
3878      this._editorUndoBar?.show(undo, editors.length === 1 ? editors[0].editorType : editors.length);
3879      for (const editor of editors) {
3880        editor.remove();
3881      }
3882    };
3883    const undo = () => {
3884      for (const editor of editors) {
3885        this.#addEditorToLayer(editor);
3886      }
3887    };
3888    this.addCommands({
3889      cmd,
3890      undo,
3891      mustExec: true
3892    });
3893  }
3894  commitOrRemove() {
3895    this.#activeEditor?.commitOrRemove();
3896  }
3897  hasSomethingToControl() {
3898    return this.#activeEditor || this.hasSelection;
3899  }
3900  #selectEditors(editors) {
3901    for (const editor of this.#selectedEditors) {
3902      editor.unselect();
3903    }
3904    this.#selectedEditors.clear();
3905    for (const editor of editors) {
3906      if (editor.isEmpty()) {
3907        continue;
3908      }
3909      this.#selectedEditors.add(editor);
3910      editor.select();
3911    }
3912    this.#dispatchUpdateStates({
3913      hasSelectedEditor: this.hasSelection
3914    });
3915  }
3916  selectAll() {
3917    for (const editor of this.#selectedEditors) {
3918      editor.commit();
3919    }
3920    this.#selectEditors(this.#allEditors.values());
3921  }
3922  unselectAll() {
3923    if (this.#activeEditor) {
3924      this.#activeEditor.commitOrRemove();
3925      if (this.#mode !== AnnotationEditorType.NONE) {
3926        return;
3927      }
3928    }
3929    if (this.#currentDrawingSession?.commitOrRemove()) {
3930      return;
3931    }
3932    this.#commentManager?.destroyPopup();
3933    if (!this.hasSelection) {
3934      return;
3935    }
3936    for (const editor of this.#selectedEditors) {
3937      editor.unselect();
3938    }
3939    this.#selectedEditors.clear();
3940    this.#dispatchUpdateStates({
3941      hasSelectedEditor: false
3942    });
3943  }
3944  translateSelectedEditors(x, y, noCommit = false) {
3945    if (!noCommit) {
3946      this.commitOrRemove();
3947    }
3948    if (!this.hasSelection) {
3949      return;
3950    }
3951    this.#translation[0] += x;
3952    this.#translation[1] += y;
3953    const [totalX, totalY] = this.#translation;
3954    const editors = [...this.#selectedEditors];
3955    const TIME_TO_WAIT = 1000;
3956    if (this.#translationTimeoutId) {
3957      clearTimeout(this.#translationTimeoutId);
3958    }
3959    this.#translationTimeoutId = setTimeout(() => {
3960      this.#translationTimeoutId = null;
3961      this.#translation[0] = this.#translation[1] = 0;
3962      this.addCommands({
3963        cmd: () => {
3964          for (const editor of editors) {
3965            if (this.#allEditors.has(editor.id)) {
3966              editor.translateInPage(totalX, totalY);
3967              editor.translationDone();
3968            }
3969          }
3970        },
3971        undo: () => {
3972          for (const editor of editors) {
3973            if (this.#allEditors.has(editor.id)) {
3974              editor.translateInPage(-totalX, -totalY);
3975              editor.translationDone();
3976            }
3977          }
3978        },
3979        mustExec: false
3980      });
3981    }, TIME_TO_WAIT);
3982    for (const editor of editors) {
3983      editor.translateInPage(x, y);
3984      editor.translationDone();
3985    }
3986  }
3987  setUpDragSession() {
3988    if (!this.hasSelection) {
3989      return;
3990    }
3991    this.disableUserSelect(true);
3992    this.#draggingEditors = new Map();
3993    for (const editor of this.#selectedEditors) {
3994      this.#draggingEditors.set(editor, {
3995        savedX: editor.x,
3996        savedY: editor.y,
3997        savedPageIndex: editor.pageIndex,
3998        newX: 0,
3999        newY: 0,
4000        newPageIndex: -1
4001      });
4002    }
4003  }
4004  endDragSession() {
4005    if (!this.#draggingEditors) {
4006      return false;
4007    }
4008    this.disableUserSelect(false);
4009    const map = this.#draggingEditors;
4010    this.#draggingEditors = null;
4011    let mustBeAddedInUndoStack = false;
4012    for (const [{
4013      x,
4014      y,
4015      pageIndex
4016    }, value] of map) {
4017      value.newX = x;
4018      value.newY = y;
4019      value.newPageIndex = pageIndex;
4020      mustBeAddedInUndoStack ||= x !== value.savedX || y !== value.savedY || pageIndex !== value.savedPageIndex;
4021    }
4022    if (!mustBeAddedInUndoStack) {
4023      return false;
4024    }
4025    const move = (editor, x, y, pageIndex) => {
4026      if (this.#allEditors.has(editor.id)) {
4027        const parent = this.#allLayers.get(pageIndex);
4028        if (parent) {
4029          editor._setParentAndPosition(parent, x, y);
4030        } else {
4031          editor.pageIndex = pageIndex;
4032          editor.x = x;
4033          editor.y = y;
4034        }
4035      }
4036    };
4037    this.addCommands({
4038      cmd: () => {
4039        for (const [editor, {
4040          newX,
4041          newY,
4042          newPageIndex
4043        }] of map) {
4044          move(editor, newX, newY, newPageIndex);
4045        }
4046      },
4047      undo: () => {
4048        for (const [editor, {
4049          savedX,
4050          savedY,
4051          savedPageIndex
4052        }] of map) {
4053          move(editor, savedX, savedY, savedPageIndex);
4054        }
4055      },
4056      mustExec: true
4057    });
4058    return true;
4059  }
4060  dragSelectedEditors(tx, ty) {
4061    if (!this.#draggingEditors) {
4062      return;
4063    }
4064    for (const editor of this.#draggingEditors.keys()) {
4065      editor.drag(tx, ty);
4066    }
4067  }
4068  rebuild(editor) {
4069    if (editor.parent === null) {
4070      const parent = this.getLayer(editor.pageIndex);
4071      if (parent) {
4072        parent.changeParent(editor);
4073        parent.addOrRebuild(editor);
4074      } else {
4075        this.addEditor(editor);
4076        this.addToAnnotationStorage(editor);
4077        editor.rebuild();
4078      }
4079    } else {
4080      editor.parent.addOrRebuild(editor);
4081    }
4082  }
4083  get isEditorHandlingKeyboard() {
4084    return this.getActive()?.shouldGetKeyboardEvents() || this.#selectedEditors.size === 1 && this.firstSelectedEditor.shouldGetKeyboardEvents();
4085  }
4086  isActive(editor) {
4087    return this.#activeEditor === editor;
4088  }
4089  getActive() {
4090    return this.#activeEditor;
4091  }
4092  getMode() {
4093    return this.#mode;
4094  }
4095  isEditingMode() {
4096    return this.#mode !== AnnotationEditorType.NONE;
4097  }
4098  get imageManager() {
4099    return shadow(this, "imageManager", new ImageManager());
4100  }
4101  getSelectionBoxes(textLayer) {
4102    if (!textLayer) {
4103      return null;
4104    }
4105    const selection = document.getSelection();
4106    for (let i = 0, ii = selection.rangeCount; i < ii; i++) {
4107      if (!textLayer.contains(selection.getRangeAt(i).commonAncestorContainer)) {
4108        return null;
4109      }
4110    }
4111    const {
4112      x: layerX,
4113      y: layerY,
4114      width: parentWidth,
4115      height: parentHeight
4116    } = textLayer.getBoundingClientRect();
4117    let rotator;
4118    switch (textLayer.getAttribute("data-main-rotation")) {
4119      case "90":
4120        rotator = (x, y, w, h) => ({
4121          x: (y - layerY) / parentHeight,
4122          y: 1 - (x + w - layerX) / parentWidth,
4123          width: h / parentHeight,
4124          height: w / parentWidth
4125        });
4126        break;
4127      case "180":
4128        rotator = (x, y, w, h) => ({
4129          x: 1 - (x + w - layerX) / parentWidth,
4130          y: 1 - (y + h - layerY) / parentHeight,
4131          width: w / parentWidth,
4132          height: h / parentHeight
4133        });
4134        break;
4135      case "270":
4136        rotator = (x, y, w, h) => ({
4137          x: 1 - (y + h - layerY) / parentHeight,
4138          y: (x - layerX) / parentWidth,
4139          width: h / parentHeight,
4140          height: w / parentWidth
4141        });
4142        break;
4143      default:
4144        rotator = (x, y, w, h) => ({
4145          x: (x - layerX) / parentWidth,
4146          y: (y - layerY) / parentHeight,
4147          width: w / parentWidth,
4148          height: h / parentHeight
4149        });
4150        break;
4151    }
4152    const boxes = [];
4153    for (let i = 0, ii = selection.rangeCount; i < ii; i++) {
4154      const range = selection.getRangeAt(i);
4155      if (range.collapsed) {
4156        continue;
4157      }
4158      for (const {
4159        x,
4160        y,
4161        width,
4162        height
4163      } of range.getClientRects()) {
4164        if (width === 0 || height === 0) {
4165          continue;
4166        }
4167        boxes.push(rotator(x, y, width, height));
4168      }
4169    }
4170    return boxes.length === 0 ? null : boxes;
4171  }
4172  addChangedExistingAnnotation({
4173    annotationElementId,
4174    id
4175  }) {
4176    (this.#changedExistingAnnotations ||= new Map()).set(annotationElementId, id);
4177  }
4178  removeChangedExistingAnnotation({
4179    annotationElementId
4180  }) {
4181    this.#changedExistingAnnotations?.delete(annotationElementId);
4182  }
4183  renderAnnotationElement(annotation) {
4184    const editorId = this.#changedExistingAnnotations?.get(annotation.data.id);
4185    if (!editorId) {
4186      return;
4187    }
4188    const editor = this.#annotationStorage.getRawValue(editorId);
4189    if (!editor) {
4190      return;
4191    }
4192    if (this.#mode === AnnotationEditorType.NONE && !editor.hasBeenModified) {
4193      return;
4194    }
4195    editor.renderAnnotationElement(annotation);
4196  }
4197  setMissingCanvas(annotationId, annotationElementId, canvas) {
4198    const editor = this.#missingCanvases?.get(annotationId);
4199    if (!editor) {
4200      return;
4201    }
4202    editor.setCanvas(annotationElementId, canvas);
4203    this.#missingCanvases.delete(annotationId);
4204  }
4205  addMissingCanvas(annotationId, editor) {
4206    (this.#missingCanvases ||= new Map()).set(annotationId, editor);
4207  }
4208}
4209
4210;// ./src/display/editor/alt_text.js
4211
4212class AltText {
4213  #altText = null;
4214  #altTextDecorative = false;
4215  #altTextButton = null;
4216  #altTextButtonLabel = null;
4217  #altTextTooltip = null;
4218  #altTextTooltipTimeout = null;
4219  #altTextWasFromKeyBoard = false;
4220  #badge = null;
4221  #editor = null;
4222  #guessedText = null;
4223  #textWithDisclaimer = null;
4224  #useNewAltTextFlow = false;
4225  static #l10nNewButton = null;
4226  static _l10n = null;
4227  constructor(editor) {
4228    this.#editor = editor;
4229    this.#useNewAltTextFlow = editor._uiManager.useNewAltTextFlow;
4230    AltText.#l10nNewButton ||= Object.freeze({
4231      added: "pdfjs-editor-new-alt-text-added-button",
4232      "added-label": "pdfjs-editor-new-alt-text-added-button-label",
4233      missing: "pdfjs-editor-new-alt-text-missing-button",
4234      "missing-label": "pdfjs-editor-new-alt-text-missing-button-label",
4235      review: "pdfjs-editor-new-alt-text-to-review-button",
4236      "review-label": "pdfjs-editor-new-alt-text-to-review-button-label"
4237    });
4238  }
4239  static initialize(l10n) {
4240    AltText._l10n ??= l10n;
4241  }
4242  async render() {
4243    const altText = this.#altTextButton = document.createElement("button");
4244    altText.className = "altText";
4245    altText.tabIndex = "0";
4246    const label = this.#altTextButtonLabel = document.createElement("span");
4247    altText.append(label);
4248    if (this.#useNewAltTextFlow) {
4249      altText.classList.add("new");
4250      altText.setAttribute("data-l10n-id", AltText.#l10nNewButton.missing);
4251      label.setAttribute("data-l10n-id", AltText.#l10nNewButton["missing-label"]);
4252    } else {
4253      altText.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-button");
4254      label.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-button-label");
4255    }
4256    const signal = this.#editor._uiManager._signal;
4257    altText.addEventListener("contextmenu", noContextMenu, {
4258      signal
4259    });
4260    altText.addEventListener("pointerdown", event => event.stopPropagation(), {
4261      signal
4262    });
4263    const onClick = event => {
4264      event.preventDefault();
4265      this.#editor._uiManager.editAltText(this.#editor);
4266      if (this.#useNewAltTextFlow) {
4267        this.#editor._reportTelemetry({
4268          action: "pdfjs.image.alt_text.image_status_label_clicked",
4269          data: {
4270            label: this.#label
4271          }
4272        });
4273      }
4274    };
4275    altText.addEventListener("click", onClick, {
4276      capture: true,
4277      signal
4278    });
4279    altText.addEventListener("keydown", event => {
4280      if (event.target === altText && event.key === "Enter") {
4281        this.#altTextWasFromKeyBoard = true;
4282        onClick(event);
4283      }
4284    }, {
4285      signal
4286    });
4287    await this.#setState();
4288    return altText;
4289  }
4290  get #label() {
4291    return this.#altText && "added" || this.#altText === null && this.guessedText && "review" || "missing";
4292  }
4293  finish() {
4294    if (!this.#altTextButton) {
4295      return;
4296    }
4297    this.#altTextButton.focus({
4298      focusVisible: this.#altTextWasFromKeyBoard
4299    });
4300    this.#altTextWasFromKeyBoard = false;
4301  }
4302  isEmpty() {
4303    
4303if (this.#useNewAltTextFlow) {
4304      return this.#altText === null;
4305    }
4306    return !this.#altText && !this.#altTextDecorative;
4307  }
4308  hasData() {
4309    if (this.#useNewAltTextFlow) {
4310      return this.#altText !== null || !!this.#guessedText;
4311    }
4312    return
vendor: 12,118 bytes, lines 4312-4748
4312 this.isEmpty();
4313  }
4314  get guessedText() {
4315    return this.#guessedText;
4316  }
4317  async setGuessedText(guessedText) {
4318    if (this.#altText !== null) {
4319      return;
4320    }
4321    this.#guessedText = guessedText;
4322    this.#textWithDisclaimer = await AltText._l10n.get("pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer", {
4323      generatedAltText: guessedText
4324    });
4325    this.#setState();
4326  }
4327  toggleAltTextBadge(visibility = false) {
4328    if (!this.#useNewAltTextFlow || this.#altText) {
4329      this.#badge?.remove();
4330      this.#badge = null;
4331      return;
4332    }
4333    if (!this.#badge) {
4334      const badge = this.#badge = document.createElement("div");
4335      badge.className = "noAltTextBadge";
4336      this.#editor.div.append(badge);
4337    }
4338    this.#badge.classList.toggle("hidden", !visibility);
4339  }
4340  serialize(isForCopying) {
4341    let altText = this.#altText;
4342    if (!isForCopying && this.#guessedText === altText) {
4343      altText = this.#textWithDisclaimer;
4344    }
4345    return {
4346      altText,
4347      decorative: this.#altTextDecorative,
4348      guessedText: this.#guessedText,
4349      textWithDisclaimer: this.#textWithDisclaimer
4350    };
4351  }
4352  get data() {
4353    return {
4354      altText: this.#altText,
4355      decorative: this.#altTextDecorative
4356    };
4357  }
4358  set data({
4359    altText,
4360    decorative,
4361    guessedText,
4362    textWithDisclaimer,
4363    cancel = false
4364  }) {
4365    if (guessedText) {
4366      this.#guessedText = guessedText;
4367      this.#textWithDisclaimer = textWithDisclaimer;
4368    }
4369    if (this.#altText === altText && this.#altTextDecorative === decorative) {
4370      return;
4371    }
4372    if (!cancel) {
4373      this.#altText = altText;
4374      this.#altTextDecorative = decorative;
4375    }
4376    this.#setState();
4377  }
4378  toggle(enabled = false) {
4379    if (!this.#altTextButton) {
4380      return;
4381    }
4382    if (!enabled && this.#altTextTooltipTimeout) {
4383      clearTimeout(this.#altTextTooltipTimeout);
4384      this.#altTextTooltipTimeout = null;
4385    }
4386    this.#altTextButton.disabled = !enabled;
4387  }
4388  shown() {
4389    this.#editor._reportTelemetry({
4390      action: "pdfjs.image.alt_text.image_status_label_displayed",
4391      data: {
4392        label: this.#label
4393      }
4394    });
4395  }
4396  destroy() {
4397    this.#altTextButton?.remove();
4398    this.#altTextButton = null;
4399    this.#altTextButtonLabel = null;
4400    this.#altTextTooltip = null;
4401    this.#badge?.remove();
4402    this.#badge = null;
4403  }
4404  async #setState() {
4405    const button = this.#altTextButton;
4406    if (!button) {
4407      return;
4408    }
4409    if (this.#useNewAltTextFlow) {
4410      button.classList.toggle("done", !!this.#altText);
4411      button.setAttribute("data-l10n-id", AltText.#l10nNewButton[this.#label]);
4412      this.#altTextButtonLabel?.setAttribute("data-l10n-id", AltText.#l10nNewButton[`${this.#label}-label`]);
4413      if (!this.#altText) {
4414        this.#altTextTooltip?.remove();
4415        return;
4416      }
4417    } else {
4418      if (!this.#altText && !this.#altTextDecorative) {
4419        button.classList.remove("done");
4420        this.#altTextTooltip?.remove();
4421        return;
4422      }
4423      button.classList.add("done");
4424      button.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-edit-button");
4425    }
4426    let tooltip = this.#altTextTooltip;
4427    if (!tooltip) {
4428      this.#altTextTooltip = tooltip = document.createElement("span");
4429      tooltip.className = "tooltip";
4430      tooltip.setAttribute("role", "tooltip");
4431      tooltip.id = `alt-text-tooltip-${this.#editor.id}`;
4432      const DELAY_TO_SHOW_TOOLTIP = 100;
4433      const signal = this.#editor._uiManager._signal;
4434      signal.addEventListener("abort", () => {
4435        clearTimeout(this.#altTextTooltipTimeout);
4436        this.#altTextTooltipTimeout = null;
4437      }, {
4438        once: true
4439      });
4440      button.addEventListener("mouseenter", () => {
4441        this.#altTextTooltipTimeout = setTimeout(() => {
4442          this.#altTextTooltipTimeout = null;
4443          this.#altTextTooltip.classList.add("show");
4444          this.#editor._reportTelemetry({
4445            action: "alt_text_tooltip"
4446          });
4447        }, DELAY_TO_SHOW_TOOLTIP);
4448      }, {
4449        signal
4450      });
4451      button.addEventListener("mouseleave", () => {
4452        if (this.#altTextTooltipTimeout) {
4453          clearTimeout(this.#altTextTooltipTimeout);
4454          this.#altTextTooltipTimeout = null;
4455        }
4456        this.#altTextTooltip?.classList.remove("show");
4457      }, {
4458        signal
4459      });
4460    }
4461    if (this.#altTextDecorative) {
4462      tooltip.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-decorative-tooltip");
4463    } else {
4464      tooltip.removeAttribute("data-l10n-id");
4465      tooltip.textContent = this.#altText;
4466    }
4467    if (!tooltip.parentNode) {
4468      button.append(tooltip);
4469    }
4470    const element = this.#editor.getElementForAltText();
4471    element?.setAttribute("aria-describedby", tooltip.id);
4472  }
4473}
4474
4475;// ./src/display/editor/comment.js
4476
4477class Comment {
4478  #commentStandaloneButton = null;
4479  #commentToolbarButton = null;
4480  #commentWasFromKeyBoard = false;
4481  #editor = null;
4482  #initialText = null;
4483  #richText = null;
4484  #text = null;
4485  #date = null;
4486  #deleted = false;
4487  #popupPosition = null;
4488  constructor(editor) {
4489    this.#editor = editor;
4490  }
4491  renderForToolbar() {
4492    const button = this.#commentToolbarButton = document.createElement("button");
4493    button.className = "comment";
4494    return this.#render(button, false);
4495  }
4496  renderForStandalone() {
4497    const button = this.#commentStandaloneButton = document.createElement("button");
4498    button.className = "annotationCommentButton";
4499    const position = this.#editor.commentButtonPosition;
4500    if (position) {
4501      const {
4502        style
4503      } = button;
4504      style.insetInlineEnd = `calc(${100 * (this.#editor._uiManager.direction === "ltr" ? 1 - position[0] : position[0])}% - var(--comment-button-dim))`;
4505      style.top = `calc(${100 * position[1]}% - var(--comment-button-dim))`;
4506      const color = this.#editor.commentButtonColor;
4507      if (color) {
4508        style.backgroundColor = color;
4509      }
4510    }
4511    return this.#render(button, true);
4512  }
4513  focusButton() {
4514    setTimeout(() => {
4515      (this.#commentStandaloneButton ?? this.#commentToolbarButton)?.focus();
4516    }, 0);
4517  }
4518  onUpdatedColor() {
4519    if (!this.#commentStandaloneButton) {
4520      return;
4521    }
4522    const color = this.#editor.commentButtonColor;
4523    if (color) {
4524      this.#commentStandaloneButton.style.backgroundColor = color;
4525    }
4526    this.#editor._uiManager.updatePopupColor(this.#editor);
4527  }
4528  get commentButtonWidth() {
4529    return (this.#commentStandaloneButton?.getBoundingClientRect().width ?? 0) / this.#editor.parent.boundingClientRect.width;
4530  }
4531  get commentPopupPositionInLayer() {
4532    if (this.#popupPosition) {
4533      return this.#popupPosition;
4534    }
4535    if (!this.#commentStandaloneButton) {
4536      return null;
4537    }
4538    const {
4539      x,
4540      y,
4541      height
4542    } = this.#commentStandaloneButton.getBoundingClientRect();
4543    const {
4544      x: parentX,
4545      y: parentY,
4546      width: parentWidth,
4547      height: parentHeight
4548    } = this.#editor.parent.boundingClientRect;
4549    return [(x - parentX) / parentWidth, (y + height - parentY) / parentHeight];
4550  }
4551  set commentPopupPositionInLayer(pos) {
4552    this.#popupPosition = pos;
4553  }
4554  hasDefaultPopupPosition() {
4555    return this.#popupPosition === null;
4556  }
4557  removeStandaloneCommentButton() {
4558    this.#commentStandaloneButton?.remove();
4559    this.#commentStandaloneButton = null;
4560  }
4561  removeToolbarCommentButton() {
4562    this.#commentToolbarButton?.remove();
4563    this.#commentToolbarButton = null;
4564  }
4565  setCommentButtonStates({
4566    selected,
4567    hasPopup
4568  }) {
4569    if (!this.#commentStandaloneButton) {
4570      return;
4571    }
4572    this.#commentStandaloneButton.classList.toggle("selected", selected);
4573    this.#commentStandaloneButton.ariaExpanded = hasPopup;
4574  }
4575  #render(comment, isStandalone) {
4576    if (!this.#editor._uiManager.hasCommentManager()) {
4577      return null;
4578    }
4579    comment.tabIndex = "0";
4580    comment.ariaHasPopup = "dialog";
4581    if (isStandalone) {
4582      comment.ariaControls = "commentPopup";
4583      comment.setAttribute("data-l10n-id", "pdfjs-show-comment-button");
4584    } else {
4585      comment.ariaControlsElements = [this.#editor._uiManager.getCommentDialogElement()];
4586      comment.setAttribute("data-l10n-id", "pdfjs-editor-add-comment-button");
4587    }
4588    const signal = this.#editor._uiManager._signal;
4589    if (!(signal instanceof AbortSignal) || signal.aborted) {
4590      return comment;
4591    }
4592    comment.addEventListener("contextmenu", noContextMenu, {
4593      signal
4594    });
4595    if (isStandalone) {
4596      comment.addEventListener("focusin", e => {
4597        this.#editor._focusEventsAllowed = false;
4598        stopEvent(e);
4599      }, {
4600        capture: true,
4601        signal
4602      });
4603      comment.addEventListener("focusout", e => {
4604        this.#editor._focusEventsAllowed = true;
4605        stopEvent(e);
4606      }, {
4607        capture: true,
4608        signal
4609      });
4610    }
4611    comment.addEventListener("pointerdown", event => event.stopPropagation(), {
4612      signal
4613    });
4614    const onClick = event => {
4615      event.preventDefault();
4616      if (comment === this.#commentToolbarButton) {
4617        this.edit();
4618      } else {
4619        this.#editor.toggleComment(true);
4620      }
4621    };
4622    comment.addEventListener("click", onClick, {
4623      capture: true,
4624      signal
4625    });
4626    comment.addEventListener("keydown", event => {
4627      if (event.target === comment && event.key === "Enter") {
4628        this.#commentWasFromKeyBoard = true;
4629        onClick(event);
4630      }
4631    }, {
4632      signal
4633    });
4634    comment.addEventListener("pointerenter", () => {
4635      this.#editor.toggleComment(false, true);
4636    }, {
4637      signal
4638    });
4639    comment.addEventListener("pointerleave", () => {
4640      this.#editor.toggleComment(false, false);
4641    }, {
4642      signal
4643    });
4644    return comment;
4645  }
4646  edit(options) {
4647    const position = this.commentPopupPositionInLayer;
4648    let posX, posY;
4649    if (position) {
4650      [posX, posY] = position;
4651    } else {
4652      [posX, posY] = this.#editor.commentButtonPosition;
4653      const {
4654        width,
4655        height,
4656        x,
4657        y
4658      } = this.#editor;
4659      posX = x + posX * width;
4660      posY = y + posY * height;
4661    }
4662    const parentDimensions = this.#editor.parent.boundingClientRect;
4663    const {
4664      x: parentX,
4665      y: parentY,
4666      width: parentWidth,
4667      height: parentHeight
4668    } = parentDimensions;
4669    this.#editor._uiManager.editComment(this.#editor, parentX + posX * parentWidth, parentY + posY * parentHeight, {
4670      ...options,
4671      parentDimensions
4672    });
4673  }
4674  finish() {
4675    if (!this.#commentToolbarButton) {
4676      return;
4677    }
4678    this.#commentToolbarButton.focus({
4679      focusVisible: this.#commentWasFromKeyBoard
4680    });
4681    this.#commentWasFromKeyBoard = false;
4682  }
4683  isDeleted() {
4684    return this.#deleted || this.#text === "";
4685  }
4686  isEmpty() {
4687    return this.#text === null;
4688  }
4689  hasBeenEdited() {
4690    return this.isDeleted() || this.#text !== this.#initialText;
4691  }
4692  serialize() {
4693    return this.data;
4694  }
4695  get data() {
4696    return {
4697      text: this.#text,
4698      richText: this.#richText,
4699      date: this.#date,
4700      deleted: this.isDeleted()
4701    };
4702  }
4703  set data(text) {
4704    if (text !== this.#text) {
4705      this.#richText = null;
4706    }
4707    if (text === null) {
4708      this.#text = "";
4709      this.#deleted = true;
4710      return;
4711    }
4712    this.#text = text;
4713    this.#date = new Date();
4714    this.#deleted = false;
4715  }
4716  restoreData({
4717    text,
4718    richText,
4719    date
4720  }) {
4721    this.#text = text;
4722    this.#richText = richText;
4723    this.#date = date;
4724    this.#deleted = false;
4725  }
4726  setInitialText(text, richText = null) {
4727    this.#initialText = text;
4728    this.data = text;
4729    this.#date = null;
4730    this.#richText = richText;
4731  }
4732  shown() {}
4733  destroy() {
4734    this.#commentToolbarButton?.remove();
4735    this.#commentToolbarButton = null;
4736    this.#commentStandaloneButton?.remove();
4737    this.#commentStandaloneButton = null;
4738    this.#text = "";
4739    this.#richText = null;
4740    this.#date = null;
4741    this.#editor = null;
4742    this.#commentWasFromKeyBoard = false;
4743    this.#deleted = false;
4744  }
4745}
4746
4747;// ./src/display/touch_manager.js
4748
vendor: 8,436 bytes, lines 4749-5028
4749class TouchManager {
4750  #container;
4751  #isPinching = false;
4752  #isPinchingStopped = null;
4753  #isPinchingDisabled;
4754  #onPinchStart;
4755  #onPinching;
4756  #onPinchEnd;
4757  #pointerDownAC = null;
4758  #signal;
4759  #touchInfo = null;
4760  #touchManagerAC;
4761  #touchMoveAC = null;
4762  constructor({
4763    container,
4764    isPinchingDisabled = null,
4765    isPinchingStopped = null,
4766    onPinchStart = null,
4767    onPinching = null,
4768    onPinchEnd = null,
4769    signal
4770  }) {
4771    this.#container = container;
4772    this.#isPinchingStopped = isPinchingStopped;
4773    this.#isPinchingDisabled = isPinchingDisabled;
4774    this.#onPinchStart = onPinchStart;
4775    this.#onPinching = onPinching;
4776    this.#onPinchEnd = onPinchEnd;
4777    this.#touchManagerAC = new AbortController();
4778    this.#signal = AbortSignal.any([signal, this.#touchManagerAC.signal]);
4779    container.addEventListener("touchstart", this.#onTouchStart.bind(this), {
4780      passive: false,
4781      signal: this.#signal
4782    });
4783  }
4784  get MIN_TOUCH_DISTANCE_TO_PINCH() {
4785    return 35 / OutputScale.pixelRatio;
4786  }
4787  #onTouchStart(evt) {
4788    if (this.#isPinchingDisabled?.()) {
4789      return;
4790    }
4791    if (evt.touches.length === 1) {
4792      if (this.#pointerDownAC) {
4793        return;
4794      }
4795      const pointerDownAC = this.#pointerDownAC = new AbortController();
4796      const signal = AbortSignal.any([this.#signal, pointerDownAC.signal]);
4797      const container = this.#container;
4798      const opts = {
4799        capture: true,
4800        signal,
4801        passive: false
4802      };
4803      const cancelPointerDown = e => {
4804        if (e.pointerType === "touch") {
4805          this.#pointerDownAC?.abort();
4806          this.#pointerDownAC = null;
4807        }
4808      };
4809      container.addEventListener("pointerdown", e => {
4810        if (e.pointerType === "touch") {
4811          stopEvent(e);
4812          cancelPointerDown(e);
4813        }
4814      }, opts);
4815      container.addEventListener("pointerup", cancelPointerDown, opts);
4816      container.addEventListener("pointercancel", cancelPointerDown, opts);
4817      return;
4818    }
4819    if (!this.#touchMoveAC) {
4820      this.#touchMoveAC = new AbortController();
4821      const signal = AbortSignal.any([this.#signal, this.#touchMoveAC.signal]);
4822      const container = this.#container;
4823      const opt = {
4824        signal,
4825        capture: false,
4826        passive: false
4827      };
4828      container.addEventListener("touchmove", this.#onTouchMove.bind(this), opt);
4829      const onTouchEnd = this.#onTouchEnd.bind(this);
4830      container.addEventListener("touchend", onTouchEnd, opt);
4831      container.addEventListener("touchcancel", onTouchEnd, opt);
4832      opt.capture = true;
4833      container.addEventListener("pointerdown", stopEvent, opt);
4834      container.addEventListener("pointermove", stopEvent, opt);
4835      container.addEventListener("pointercancel", stopEvent, opt);
4836      container.addEventListener("pointerup", stopEvent, opt);
4837      this.#onPinchStart?.();
4838    }
4839    stopEvent(evt);
4840    if (evt.touches.length !== 2 || this.#isPinchingStopped?.()) {
4841      this.#touchInfo = null;
4842      return;
4843    }
4844    let [touch0, touch1] = evt.touches;
4845    if (touch0.identifier > touch1.identifier) {
4846      [touch0, touch1] = [touch1, touch0];
4847    }
4848    this.#touchInfo = {
4849      touch0X: touch0.screenX,
4850      touch0Y: touch0.screenY,
4851      touch1X: touch1.screenX,
4852      touch1Y: touch1.screenY
4853    };
4854  }
4855  #onTouchMove(evt) {
4856    if (!this.#touchInfo || evt.touches.length !== 2) {
4857      return;
4858    }
4859    stopEvent(evt);
4860    let [touch0, touch1] = evt.touches;
4861    if (touch0.identifier > touch1.identifier) {
4862      [touch0, touch1] = [touch1, touch0];
4863    }
4864    const {
4865      screenX: screen0X,
4866      screenY: screen0Y
4867    } = touch0;
4868    const {
4869      screenX: screen1X,
4870      screenY: screen1Y
4871    } = touch1;
4872    const touchInfo = this.#touchInfo;
4873    const {
4874      touch0X: pTouch0X,
4875      touch0Y: pTouch0Y,
4876      touch1X: pTouch1X,
4877      touch1Y: pTouch1Y
4878    } = touchInfo;
4879    const prevGapX = pTouch1X - pTouch0X;
4880    const prevGapY = pTouch1Y - pTouch0Y;
4881    const currGapX = screen1X - screen0X;
4882    const currGapY = screen1Y - screen0Y;
4883    const distance = Math.hypot(currGapX, currGapY) || 1;
4884    const pDistance = Math.hypot(prevGapX, prevGapY) || 1;
4885    if (!this.#isPinching && Math.abs(pDistance - distance) <= TouchManager.MIN_TOUCH_DISTANCE_TO_PINCH) {
4886      return;
4887    }
4888    touchInfo.touch0X = screen0X;
4889    touchInfo.touch0Y = screen0Y;
4890    touchInfo.touch1X = screen1X;
4891    touchInfo.touch1Y = screen1Y;
4892    if (!this.#isPinching) {
4893      this.#isPinching = true;
4894      return;
4895    }
4896    const origin = [(screen0X + screen1X) / 2, (screen0Y + screen1Y) / 2];
4897    this.#onPinching?.(origin, pDistance, distance);
4898  }
4899  #onTouchEnd(evt) {
4900    if (evt.touches.length >= 2) {
4901      return;
4902    }
4903    if (this.#touchMoveAC) {
4904      this.#touchMoveAC.abort();
4905      this.#touchMoveAC = null;
4906      this.#onPinchEnd?.();
4907    }
4908    if (!this.#touchInfo) {
4909      return;
4910    }
4911    stopEvent(evt);
4912    this.#touchInfo = null;
4913    this.#isPinching = false;
4914  }
4915  destroy() {
4916    this.#touchManagerAC?.abort();
4917    this.#touchManagerAC = null;
4918    this.#pointerDownAC?.abort();
4919    this.#pointerDownAC = null;
4920  }
4921}
4922
4923;// ./src/display/editor/editor.js
4924
4925
4926
4927
4928
4929
4930
4931
4932class AnnotationEditor {
4933  #accessibilityData = null;
4934  #allResizerDivs = null;
4935  #altText = null;
4936  #comment = null;
4937  #commentStandaloneButton = null;
4938  #disabled = false;
4939  #dragPointerId = null;
4940  #dragPointerType = "";
4941  #resizersDiv = null;
4942  #lastPointerCoords = null;
4943  #savedDimensions = null;
4944  #fakeAnnotation = null;
4945  #focusAC = null;
4946  #focusedResizerName = "";
4947  #hasBeenClicked = false;
4948  #initialRect = null;
4949  #isEditing = false;
4950  #isInEditMode = false;
4951  #isResizerEnabledForKeyboard = false;
4952  #moveInDOMTimeout = null;
4953  #prevDragX = 0;
4954  #prevDragY = 0;
4955  #telemetryTimeouts = null;
4956  #touchManager = null;
4957  isSelected = false;
4958  _isCopy = false;
4959  _editToolbar = null;
4960  _initialOptions = Object.create(null);
4961  _initialData = null;
4962  _isVisible = true;
4963  _uiManager = null;
4964  _focusEventsAllowed = true;
4965  static _l10n = null;
4966  static _l10nAlert = null;
4967  static _l10nResizer = null;
4968  #isDraggable = false;
4969  #zIndex = AnnotationEditor._zIndex++;
4970  static _borderLineWidth = -1;
4971  static _colorManager = new ColorManager();
4972  static _zIndex = 1;
4973  static _telemetryTimeout = 1000;
4974  static get _resizerKeyboardManager() {
4975    const resize = AnnotationEditor.prototype._resizeWithKeyboard;
4976    const small = AnnotationEditorUIManager.TRANSLATE_SMALL;
4977    const big = AnnotationEditorUIManager.TRANSLATE_BIG;
4978    return shadow(this, "_resizerKeyboardManager", new KeyboardManager([[["ArrowLeft"], resize, {
4979      args: [-small, 0]
4980    }], [["ctrl+ArrowLeft", "mac+shift+ArrowLeft"], resize, {
4981      args: [-big, 0]
4982    }], [["ArrowRight"], resize, {
4983      args: [small, 0]
4984    }], [["ctrl+ArrowRight", "mac+shift+ArrowRight"], resize, {
4985      args: [big, 0]
4986    }], [["ArrowUp"], resize, {
4987      args: [0, -small]
4988    }], [["ctrl+ArrowUp", "mac+shift+ArrowUp"], resize, {
4989      args: [0, -big]
4990    }], [["ArrowDown"], resize, {
4991      args: [0, small]
4992    }], [["ctrl+ArrowDown", "mac+shift+ArrowDown"], resize, {
4993      args: [0, big]
4994    }], [["Escape"], AnnotationEditor.prototype._stopResizingWithKeyboard]]));
4995  }
4996  constructor(parameters) {
4997    this.parent = parameters.parent;
4998    this.id = parameters.id;
4999    this.width = this.height = null;
5000    this.pageIndex = parameters.parent.pageIndex;
5001    this.name = parameters.name;
5002    this.div = null;
5003    this._uiManager = parameters.uiManager;
5004    this.annotationElementId = null;
5005    this._willKeepAspectRatio = false;
5006    this._initialOptions.isCentered = parameters.isCentered;
5007    this._structTreeParentId = null;
5008    this.annotationElementId = parameters.annotationElementId || null;
5009    this.creationDate = parameters.creationDate || new Date();
5010    this.modificationDate = parameters.modificationDate || null;
5011    this.canAddComment = true;
5012    const {
5013      rotation,
5014      rawDims: {
5015        pageWidth,
5016        pageHeight,
5017        pageX,
5018        pageY
5019      }
5020    } = this.parent.viewport;
5021    this.rotation = rotation;
5022    this.pageRotation = (360 + rotation - this._uiManager.viewParameters.rotation) % 360;
5023    this.pageDimensions = [pageWidth, pageHeight];
5024    this.pageTranslation = [pageX, pageY];
5025    const [width, height] = this.parentDimensions;
5026    this.x = parameters.x / width;
5027    this.y = parameters.y / height;
5028    this.isAttachedToDOM = false;
vendor: 6,508 bytes, lines 5029-5263
5029    this.deleted = false;
5030  }
5031  updatePageIndex(newPageIndex) {
5032    this.pageIndex = newPageIndex;
5033  }
5034  get editorType() {
5035    return Object.getPrototypeOf(this).constructor._type;
5036  }
5037  get mode() {
5038    return Object.getPrototypeOf(this).constructor._editorType;
5039  }
5040  static get isDrawer() {
5041    return false;
5042  }
5043  static get _defaultLineColor() {
5044    return shadow(this, "_defaultLineColor", this._colorManager.getHexCode("CanvasText"));
5045  }
5046  static deleteAnnotationElement(editor) {
5047    const fakeEditor = new FakeEditor({
5048      id: editor._uiManager.getId(),
5049      parent: editor.parent,
5050      uiManager: editor._uiManager
5051    });
5052    fakeEditor.annotationElementId = editor.annotationElementId;
5053    fakeEditor.deleted = true;
5054    fakeEditor._uiManager.addToAnnotationStorage(fakeEditor);
5055  }
5056  static initialize(l10n, _uiManager) {
5057    AnnotationEditor._l10n ??= l10n;
5058    AnnotationEditor._l10nAlert ??= Object.freeze({
5059      highlight: "pdfjs-editor-highlight-added-alert",
5060      freetext: "pdfjs-editor-freetext-added-alert",
5061      ink: "pdfjs-editor-ink-added-alert",
5062      stamp: "pdfjs-editor-stamp-added-alert",
5063      signature: "pdfjs-editor-signature-added-alert"
5064    });
5065    AnnotationEditor._l10nResizer ??= Object.freeze({
5066      topLeft: "pdfjs-editor-resizer-top-left",
5067      topMiddle: "pdfjs-editor-resizer-top-middle",
5068      topRight: "pdfjs-editor-resizer-top-right",
5069      middleRight: "pdfjs-editor-resizer-middle-right",
5070      bottomRight: "pdfjs-editor-resizer-bottom-right",
5071      bottomMiddle: "pdfjs-editor-resizer-bottom-middle",
5072      bottomLeft: "pdfjs-editor-resizer-bottom-left",
5073      middleLeft: "pdfjs-editor-resizer-middle-left"
5074    });
5075    if (AnnotationEditor._borderLineWidth !== -1) {
5076      return;
5077    }
5078    const style = getComputedStyle(document.documentElement);
5079    AnnotationEditor._borderLineWidth = parseFloat(style.getPropertyValue("--outline-width")) || 0;
5080  }
5081  static updateDefaultParams(_type, _value) {}
5082  static get defaultPropertiesToUpdate() {
5083    return [];
5084  }
5085  static isHandlingMimeForPasting(mime) {
5086    return false;
5087  }
5088  static paste(item, parent) {
5089    unreachable("Not implemented");
5090  }
5091  get propertiesToUpdate() {
5092    return [];
5093  }
5094  get _isDraggable() {
5095    return this.#isDraggable;
5096  }
5097  set _isDraggable(value) {
5098    this.#isDraggable = value;
5099    this.div?.classList.toggle("draggable", value);
5100  }
5101  get uid() {
5102    return this.annotationElementId || this.id;
5103  }
5104  get isEnterHandled() {
5105    return true;
5106  }
5107  center() {
5108    const [pageWidth, pageHeight] = this.pageDimensions;
5109    switch (this.parentRotation) {
5110      case 90:
5111        this.x -= this.height * pageHeight / (pageWidth * 2);
5112        this.y += this.width * pageWidth / (pageHeight * 2);
5113        break;
5114      case 180:
5115        this.x += this.width / 2;
5116        this.y += this.height / 2;
5117        break;
5118      case 270:
5119        this.x += this.height * pageHeight / (pageWidth * 2);
5120        this.y -= this.width * pageWidth / (pageHeight * 2);
5121        break;
5122      default:
5123        this.x -= this.width / 2;
5124        this.y -= this.height / 2;
5125        break;
5126    }
5127    this.fixAndSetPosition();
5128  }
5129  addCommands(params) {
5130    this._uiManager.addCommands(params);
5131  }
5132  get currentLayer() {
5133    return this._uiManager.currentLayer;
5134  }
5135  setInBackground() {
5136    this.div.style.zIndex = 0;
5137  }
5138  setInForeground() {
5139    this.div.style.zIndex = this.#zIndex;
5140  }
5141  setParent(parent) {
5142    if (parent !== null) {
5143      this.pageIndex = parent.pageIndex;
5144      this.pageDimensions = parent.pageDimensions;
5145    } else {
5146      this.#stopResizing();
5147      this.#fakeAnnotation?.remove();
5148      this.#fakeAnnotation = null;
5149    }
5150    this.parent = parent;
5151  }
5152  focusin(event) {
5153    if (!this._focusEventsAllowed) {
5154      return;
5155    }
5156    if (!this.#hasBeenClicked) {
5157      this.parent.setSelected(this);
5158    } else {
5159      this.#hasBeenClicked = false;
5160    }
5161  }
5162  focusout(event) {
5163    if (!this._focusEventsAllowed) {
5164      return;
5165    }
5166    if (!this.isAttachedToDOM) {
5167      return;
5168    }
5169    const target = event.relatedTarget;
5170    if (target?.closest(`#${this.id}`)) {
5171      return;
5172    }
5173    event.preventDefault();
5174    if (!this.parent?.isMultipleSelection) {
5175      this.commitOrRemove();
5176    }
5177  }
5178  commitOrRemove() {
5179    if (this.isEmpty()) {
5180      this.remove();
5181    } else {
5182      this.commit();
5183    }
5184  }
5185  commit() {
5186    if (!this.isInEditMode()) {
5187      return;
5188    }
5189    this.addToAnnotationStorage();
5190  }
5191  addToAnnotationStorage() {
5192    this._uiManager.addToAnnotationStorage(this);
5193  }
5194  setAt(x, y, tx, ty) {
5195    const [width, height] = this.parentDimensions;
5196    [tx, ty] = this.screenToPageTranslation(tx, ty);
5197    this.x = (x + tx) / width;
5198    this.y = (y + ty) / height;
5199    this.fixAndSetPosition();
5200  }
5201  _moveAfterPaste(baseX, baseY) {
5202    if (this.isClone) {
5203      delete this.isClone;
5204      return;
5205    }
5206    const [parentWidth, parentHeight] = this.parentDimensions;
5207    this.setAt(baseX * parentWidth, baseY * parentHeight, this.width * parentWidth, this.height * parentHeight);
5208    this._onTranslated();
5209  }
5210  #translate([width, height], x, y) {
5211    [x, y] = this.screenToPageTranslation(x, y);
5212    this.x += x / width;
5213    this.y += y / height;
5214    this._onTranslating(this.x, this.y);
5215    this.fixAndSetPosition();
5216  }
5217  translate(x, y) {
5218    this.#translate(this.parentDimensions, x, y);
5219  }
5220  translateInPage(x, y) {
5221    this.#initialRect ||= [this.x, this.y, this.width, this.height];
5222    this.#translate(this.pageDimensions, x, y);
5223    this.div.scrollIntoView({
5224      block: "nearest"
5225    });
5226  }
5227  translationDone() {
5228    this._onTranslated(this.x, this.y);
5229  }
5230  drag(tx, ty) {
5231    this.#initialRect ||= [this.x, this.y, this.width, this.height];
5232    const {
5233      div,
5234      parentDimensions: [parentWidth, parentHeight]
5235    } = this;
5236    this.x += tx / parentWidth;
5237    this.y += ty / parentHeight;
5238    if (this.parent && (this.x < 0 || this.x > 1 || this.y < 0 || this.y > 1)) {
5239      const {
5240        x,
5241        y
5242      } = this.div.getBoundingClientRect();
5243      if (this.parent.findNewParent(this, x, y)) {
5244        this.x -= Math.floor(this.x);
5245        this.y -= Math.floor(this.y);
5246      }
5247    }
5248    let {
5249      x,
5250      y
5251    } = this;
5252    const [bx, by] = this.getBaseTranslation();
5253    x += bx;
5254    y += by;
5255    const {
5256      style
5257    } = div;
5258    style.left = `${(100 * x).toFixed(2)}%`;
5259    style.top = `${(100 * y).toFixed(2)}%`;
5260    this._onTranslating(x, y);
5261    div.scrollIntoView({
5262      block: "nearest"
5263    }
vendor: 17,821 bytes, lines 5263-5858
5263);
5264  }
5265  _onTranslating(x, y) {}
5266  _onTranslated(x, y) {}
5267  get _hasBeenMoved() {
5268    return !!this.#initialRect && (this.#initialRect[0] !== this.x || this.#initialRect[1] !== this.y);
5269  }
5270  get _hasBeenResized() {
5271    return !!this.#initialRect && (this.#initialRect[2] !== this.width || this.#initialRect[3] !== this.height);
5272  }
5273  getBaseTranslation() {
5274    const [parentWidth, parentHeight] = this.parentDimensions;
5275    const {
5276      _borderLineWidth
5277    } = AnnotationEditor;
5278    const x = _borderLineWidth / parentWidth;
5279    const y = _borderLineWidth / parentHeight;
5280    switch (this.rotation) {
5281      case 90:
5282        return [-x, y];
5283      case 180:
5284        return [x, y];
5285      case 270:
5286        return [x, -y];
5287      default:
5288        return [-x, -y];
5289    }
5290  }
5291  get _mustFixPosition() {
5292    return true;
5293  }
5294  fixAndSetPosition(rotation = this.rotation) {
5295    const {
5296      div: {
5297        style
5298      },
5299      pageDimensions: [pageWidth, pageHeight]
5300    } = this;
5301    let {
5302      x,
5303      y,
5304      width,
5305      height
5306    } = this;
5307    width *= pageWidth;
5308    height *= pageHeight;
5309    x *= pageWidth;
5310    y *= pageHeight;
5311    if (this._mustFixPosition) {
5312      switch (rotation) {
5313        case 0:
5314          x = MathClamp(x, 0, pageWidth - width);
5315          y = MathClamp(y, 0, pageHeight - height);
5316          break;
5317        case 90:
5318          x = MathClamp(x, 0, pageWidth - height);
5319          y = MathClamp(y, width, pageHeight);
5320          break;
5321        case 180:
5322          x = MathClamp(x, width, pageWidth);
5323          y = MathClamp(y, height, pageHeight);
5324          break;
5325        case 270:
5326          x = MathClamp(x, height, pageWidth);
5327          y = MathClamp(y, 0, pageHeight - width);
5328          break;
5329      }
5330    }
5331    this.x = x /= pageWidth;
5332    this.y = y /= pageHeight;
5333    const [bx, by] = this.getBaseTranslation();
5334    x += bx;
5335    y += by;
5336    style.left = `${(100 * x).toFixed(2)}%`;
5337    style.top = `${(100 * y).toFixed(2)}%`;
5338    this.moveInDOM();
5339  }
5340  static #rotatePoint(x, y, angle) {
5341    switch (angle) {
5342      case 90:
5343        return [y, -x];
5344      case 180:
5345        return [-x, -y];
5346      case 270:
5347        return [-y, x];
5348      default:
5349        return [x, y];
5350    }
5351  }
5352  screenToPageTranslation(x, y) {
5353    return AnnotationEditor.#rotatePoint(x, y, this.parentRotation);
5354  }
5355  pageTranslationToScreen(x, y) {
5356    return AnnotationEditor.#rotatePoint(x, y, 360 - this.parentRotation);
5357  }
5358  #getRotationMatrix(rotation) {
5359    switch (rotation) {
5360      case 90:
5361        {
5362          const [pageWidth, pageHeight] = this.pageDimensions;
5363          return [0, -pageWidth / pageHeight, pageHeight / pageWidth, 0];
5364        }
5365      case 180:
5366        return [-1, 0, 0, -1];
5367      case 270:
5368        {
5369          const [pageWidth, pageHeight] = this.pageDimensions;
5370          return [0, pageWidth / pageHeight, -pageHeight / pageWidth, 0];
5371        }
5372      default:
5373        return [1, 0, 0, 1];
5374    }
5375  }
5376  get parentScale() {
5377    return this._uiManager.viewParameters.realScale;
5378  }
5379  get parentRotation() {
5380    return (this._uiManager.viewParameters.rotation + this.pageRotation) % 360;
5381  }
5382  get parentDimensions() {
5383    const {
5384      parentScale,
5385      pageDimensions: [pageWidth, pageHeight]
5386    } = this;
5387    return [pageWidth * parentScale, pageHeight * parentScale];
5388  }
5389  setDims() {
5390    const {
5391      div: {
5392        style
5393      },
5394      width,
5395      height
5396    } = this;
5397    style.width = `${(100 * width).toFixed(2)}%`;
5398    style.height = `${(100 * height).toFixed(2)}%`;
5399  }
5400  getInitialTranslation() {
5401    return [0, 0];
5402  }
5403  #createResizers() {
5404    if (this.#resizersDiv) {
5405      return;
5406    }
5407    this.#resizersDiv = document.createElement("div");
5408    this.#resizersDiv.classList.add("resizers");
5409    const classes = this._willKeepAspectRatio ? ["topLeft", "topRight", "bottomRight", "bottomLeft"] : ["topLeft", "topMiddle", "topRight", "middleRight", "bottomRight", "bottomMiddle", "bottomLeft", "middleLeft"];
5410    const signal = this._uiManager._signal;
5411    for (const name of classes) {
5412      const div = document.createElement("div");
5413      this.#resizersDiv.append(div);
5414      div.classList.add("resizer", name);
5415      div.setAttribute("data-resizer-name", name);
5416      div.addEventListener("pointerdown", this.#resizerPointerdown.bind(this, name), {
5417        signal
5418      });
5419      div.addEventListener("contextmenu", noContextMenu, {
5420        signal
5421      });
5422      div.tabIndex = -1;
5423    }
5424    this.div.prepend(this.#resizersDiv);
5425  }
5426  #resizerPointerdown(name, event) {
5427    event.preventDefault();
5428    const {
5429      isMac
5430    } = FeatureTest.platform;
5431    if (event.button !== 0 || event.ctrlKey && isMac) {
5432      return;
5433    }
5434    this.#altText?.toggle(false);
5435    const savedDraggable = this._isDraggable;
5436    this._isDraggable = false;
5437    this.#lastPointerCoords = [event.screenX, event.screenY];
5438    const ac = new AbortController();
5439    const signal = this._uiManager.combinedSignal(ac);
5440    this.parent.togglePointerEvents(false);
5441    window.addEventListener("pointermove", this.#resizerPointermove.bind(this, name), {
5442      passive: true,
5443      capture: true,
5444      signal
5445    });
5446    window.addEventListener("touchmove", stopEvent, {
5447      passive: false,
5448      signal
5449    });
5450    window.addEventListener("contextmenu", noContextMenu, {
5451      signal
5452    });
5453    this.#savedDimensions = {
5454      savedX: this.x,
5455      savedY: this.y,
5456      savedWidth: this.width,
5457      savedHeight: this.height
5458    };
5459    const savedParentCursor = this.parent.div.style.cursor;
5460    const savedCursor = this.div.style.cursor;
5461    this.div.style.cursor = this.parent.div.style.cursor = window.getComputedStyle(event.target).cursor;
5462    const pointerUpCallback = () => {
5463      ac.abort();
5464      this.parent.togglePointerEvents(true);
5465      this.#altText?.toggle(true);
5466      this._isDraggable = savedDraggable;
5467      this.parent.div.style.cursor = savedParentCursor;
5468      this.div.style.cursor = savedCursor;
5469      this.#addResizeToUndoStack();
5470    };
5471    window.addEventListener("pointerup", pointerUpCallback, {
5472      signal
5473    });
5474    window.addEventListener("blur", pointerUpCallback, {
5475      signal
5476    });
5477  }
5478  #resize(x, y, width, height) {
5479    this.width = width;
5480    this.height = height;
5481    this.x = x;
5482    this.y = y;
5483    this.setDims();
5484    this.fixAndSetPosition();
5485    this._onResized();
5486  }
5487  _onResized() {}
5488  #addResizeToUndoStack() {
5489    if (!this.#savedDimensions) {
5490      return;
5491    }
5492    const {
5493      savedX,
5494      savedY,
5495      savedWidth,
5496      savedHeight
5497    } = this.#savedDimensions;
5498    this.#savedDimensions = null;
5499    const newX = this.x;
5500    const newY = this.y;
5501    const newWidth = this.width;
5502    const newHeight = this.height;
5503    if (newX === savedX && newY === savedY && newWidth === savedWidth && newHeight === savedHeight) {
5504      return;
5505    }
5506    this.addCommands({
5507      cmd: this.#resize.bind(this, newX, newY, newWidth, newHeight),
5508      undo: this.#resize.bind(this, savedX, savedY, savedWidth, savedHeight),
5509      mustExec: true
5510    });
5511  }
5512  static _round(x) {
5513    return Math.round(x * 10000) / 10000;
5514  }
5515  #resizerPointermove(name, event) {
5516    const [parentWidth, parentHeight] = this.parentDimensions;
5517    const savedX = this.x;
5518    const savedY = this.y;
5519    const savedWidth = this.width;
5520    const savedHeight = this.height;
5521    const minWidth = AnnotationEditor.MIN_SIZE / parentWidth;
5522    const minHeight = AnnotationEditor.MIN_SIZE / parentHeight;
5523    const rotationMatrix = this.#getRotationMatrix(this.rotation);
5524    const transf = (x, y) => [rotationMatrix[0] * x + rotationMatrix[2] * y, rotationMatrix[1] * x + rotationMatrix[3] * y];
5525    const invRotationMatrix = this.#getRotationMatrix(360 - this.rotation);
5526    const invTransf = (x, y) => [invRotationMatrix[0] * x + invRotationMatrix[2] * y, invRotationMatrix[1] * x + invRotationMatrix[3] * y];
5527    let getPoint;
5528    let getOpposite;
5529    let isDiagonal = false;
5530    let isHorizontal = false;
5531    switch (name) {
5532      case "topLeft":
5533        isDiagonal = true;
5534        getPoint = (w, h) => [0, 0];
5535        getOpposite = (w, h) => [w, h];
5536        break;
5537      case "topMiddle":
5538        getPoint = (w, h) => [w / 2, 0];
5539        getOpposite = (w, h) => [w / 2, h];
5540        break;
5541      case "topRight":
5542        isDiagonal = true;
5543        getPoint = (w, h) => [w, 0];
5544        getOpposite = (w, h) => [0, h];
5545        break;
5546      case "middleRight":
5547        isHorizontal = true;
5548        getPoint = (w, h) => [w, h / 2];
5549        getOpposite = (w, h) => [0, h / 2];
5550        break;
5551      case "bottomRight":
5552        isDiagonal = true;
5553        getPoint = (w, h) => [w, h];
5554        getOpposite = (w, h) => [0, 0];
5555        break;
5556      case "bottomMiddle":
5557        getPoint = (w, h) => [w / 2, h];
5558        getOpposite = (w, h) => [w / 2, 0];
5559        break;
5560      case "bottomLeft":
5561        isDiagonal = true;
5562        getPoint = (w, h) => [0, h];
5563        getOpposite = (w, h) => [w, 0];
5564        break;
5565      case "middleLeft":
5566        isHorizontal = true;
5567        getPoint = (w, h) => [0, h / 2];
5568        getOpposite = (w, h) => [w, h / 2];
5569        break;
5570    }
5571    const point = getPoint(savedWidth, savedHeight);
5572    const oppositePoint = getOpposite(savedWidth, savedHeight);
5573    let transfOppositePoint = transf(...oppositePoint);
5574    const oppositeX = AnnotationEditor._round(savedX + transfOppositePoint[0]);
5575    const oppositeY = AnnotationEditor._round(savedY + transfOppositePoint[1]);
5576    let ratioX = 1;
5577    let ratioY = 1;
5578    let deltaX, deltaY;
5579    if (!event.fromKeyboard) {
5580      const {
5581        screenX,
5582        screenY
5583      } = event;
5584      const [lastScreenX, lastScreenY] = this.#lastPointerCoords;
5585      [deltaX, deltaY] = this.screenToPageTranslation(screenX - lastScreenX, screenY - lastScreenY);
5586      this.#lastPointerCoords[0] = screenX;
5587      this.#lastPointerCoords[1] = screenY;
5588    } else {
5589      ({
5590        deltaX,
5591        deltaY
5592      } = event);
5593    }
5594    [deltaX, deltaY] = invTransf(deltaX / parentWidth, deltaY / parentHeight);
5595    if (isDiagonal) {
5596      const oldDiag = Math.hypot(savedWidth, savedHeight);
5597      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);
5598    } else if (isHorizontal) {
5599      ratioX = MathClamp(Math.abs(oppositePoint[0] - point[0] - deltaX), minWidth, 1) / savedWidth;
5600    } else {
5601      ratioY = MathClamp(Math.abs(oppositePoint[1] - point[1] - deltaY), minHeight, 1) / savedHeight;
5602    }
5603    const newWidth = AnnotationEditor._round(savedWidth * ratioX);
5604    const newHeight = AnnotationEditor._round(savedHeight * ratioY);
5605    transfOppositePoint = transf(...getOpposite(newWidth, newHeight));
5606    const newX = oppositeX - transfOppositePoint[0];
5607    const newY = oppositeY - transfOppositePoint[1];
5608    this.#initialRect ||= [this.x, this.y, this.width, this.height];
5609    this.width = newWidth;
5610    this.height = newHeight;
5611    this.x = newX;
5612    this.y = newY;
5613    this.setDims();
5614    this.fixAndSetPosition();
5615    this._onResizing();
5616  }
5617  _onResizing() {}
5618  altTextFinish() {
5619    this.#altText?.finish();
5620  }
5621  get toolbarButtons() {
5622    return null;
5623  }
5624  async addEditToolbar() {
5625    if (this._editToolbar || this.#isInEditMode) {
5626      return this._editToolbar;
5627    }
5628    this._editToolbar = new EditorToolbar(this);
5629    this.div.append(this._editToolbar.render());
5630    const {
5631      toolbarButtons
5632    } = this;
5633    if (toolbarButtons) {
5634      for (const [name, tool] of toolbarButtons) {
5635        await this._editToolbar.addButton(name, tool);
5636      }
5637    }
5638    if (!this.hasComment) {
5639      this._editToolbar.addButton("comment", this.addCommentButton());
5640    }
5641    this._editToolbar.addButton("delete");
5642    return this._editToolbar;
5643  }
5644  addCommentButtonInToolbar() {
5645    this._editToolbar?.addButtonBefore("comment", this.addCommentButton(), ".deleteButton");
5646  }
5647  removeCommentButtonFromToolbar() {
5648    this._editToolbar?.removeButton("comment");
5649  }
5650  removeEditToolbar() {
5651    this._editToolbar?.remove();
5652    this._editToolbar = null;
5653    this.#altText?.destroy();
5654  }
5655  addContainer(container) {
5656    const editToolbarDiv = this._editToolbar?.div;
5657    if (editToolbarDiv) {
5658      editToolbarDiv.before(container);
5659    } else {
5660      this.div.append(container);
5661    }
5662  }
5663  getClientDimensions() {
5664    return this.div.getBoundingClientRect();
5665  }
5666  createAltText() {
5667    if (!this.#altText) {
5668      AltText.initialize(AnnotationEditor._l10n);
5669      this.#altText = new AltText(this);
5670      if (this.#accessibilityData) {
5671        this.#altText.data = this.#accessibilityData;
5672        this.#accessibilityData = null;
5673      }
5674    }
5675    return this.#altText;
5676  }
5677  get altTextData() {
5678    return this.#altText?.data;
5679  }
5680  set altTextData(data) {
5681    if (!this.#altText) {
5682      return;
5683    }
5684    this.#altText.data = data;
5685  }
5686  get guessedAltText() {
5687    return this.#altText?.guessedText;
5688  }
5689  async setGuessedAltText(text) {
5690    await this.#altText?.setGuessedText(text);
5691  }
5692  serializeAltText(isForCopying) {
5693    return this.#altText?.serialize(isForCopying);
5694  }
5695  hasAltText() {
5696    return !!this.#altText && !this.#altText.isEmpty();
5697  }
5698  hasAltTextData() {
5699    return this.#altText?.hasData() ?? false;
5700  }
5701  focusCommentButton() {
5702    this.#comment?.focusButton();
5703  }
5704  addCommentButton() {
5705    return this.canAddComment ? this.#comment ||= new Comment(this) : null;
5706  }
5707  addStandaloneCommentButton() {
5708    if (!this._uiManager.hasCommentManager()) {
5709      return;
5710    }
5711    if (this.#commentStandaloneButton) {
5712      if (this._uiManager.isEditingMode()) {
5713        this.#commentStandaloneButton.classList.remove("hidden");
5714      }
5715      return;
5716    }
5717    if (!this.hasComment) {
5718      return;
5719    }
5720    this.#commentStandaloneButton = this.#comment.renderForStandalone();
5721    this.div.append(this.#commentStandaloneButton);
5722  }
5723  removeStandaloneCommentButton() {
5724    this.#comment.removeStandaloneCommentButton();
5725    this.#commentStandaloneButton = null;
5726  }
5727  hideStandaloneCommentButton() {
5728    this.#commentStandaloneButton?.classList.add("hidden");
5729  }
5730  get comment() {
5731    if (!this.#comment) {
5732      return null;
5733    }
5734    const {
5735      data: {
5736        richText,
5737        text,
5738        date,
5739        deleted
5740      }
5741    } = this.#comment;
5742    return {
5743      text,
5744      richText,
5745      date,
5746      deleted,
5747      color: this.getNonHCMColor(),
5748      opacity: this.opacity ?? 1
5749    };
5750  }
5751  set comment(value) {
5752    this.#comment ||= new Comment(this);
5753    if (typeof value === "object" && value !== null) {
5754      this.#comment.restoreData(value);
5755    } else {
5756      this.#comment.data = value;
5757    }
5758    if (this.hasComment) {
5759      this.removeCommentButtonFromToolbar();
5760      this.addStandaloneCommentButton();
5761      this._uiManager.updateComment(this);
5762    } else {
5763      this.addCommentButtonInToolbar();
5764      this.removeStandaloneCommentButton();
5765      this._uiManager.removeComment(this);
5766    }
5767  }
5768  setCommentData({
5769    comment,
5770    popupRef,
5771    richText
5772  }) {
5773    if (!popupRef) {
5774      return;
5775    }
5776    this.#comment ||= new Comment(this);
5777    this.#comment.setInitialText(comment, richText);
5778    if (!this.annotationElementId) {
5779      return;
5780    }
5781    const storedData = this._uiManager.getAndRemoveDataFromAnnotationStorage(this.annotationElementId);
5782    if (storedData) {
5783      this.updateFromAnnotationLayer(storedData);
5784    }
5785  }
5786  get hasEditedComment() {
5787    return this.#comment?.hasBeenEdited();
5788  }
5789  get hasDeletedComment() {
5790    return this.#comment?.isDeleted();
5791  }
5792  get hasComment() {
5793    return !!this.#comment && !this.#comment.isEmpty() && !this.#comment.isDeleted();
5794  }
5795  async editComment(options) {
5796    this.#comment ||= new Comment(this);
5797    this.#comment.edit(options);
5798  }
5799  toggleComment(isSelected, visibility = undefined) {
5800    if (this.hasComment) {
5801      this._uiManager.toggleComment(this, isSelected, visibility);
5802    }
5803  }
5804  setSelectedCommentButton(selected) {
5805    this.#comment.setSelectedButton(selected);
5806  }
5807  addComment(serialized) {
5808    if (this.hasEditedComment) {
5809      const DEFAULT_POPUP_WIDTH = 180;
5810      const DEFAULT_POPUP_HEIGHT = 100;
5811      const [,,, trY] = serialized.rect;
5812      const [pageWidth] = this.pageDimensions;
5813      const [pageX] = this.pageTranslation;
5814      const blX = pageX + pageWidth + 1;
5815      const blY = trY - DEFAULT_POPUP_HEIGHT;
5816      const trX = blX + DEFAULT_POPUP_WIDTH;
5817      serialized.popup = {
5818        contents: this.comment.text,
5819        deleted: this.comment.deleted,
5820        rect: [blX, blY, trX, trY]
5821      };
5822    }
5823  }
5824  updateFromAnnotationLayer({
5825    popup: {
5826      contents,
5827      deleted
5828    }
5829  }) {
5830    this.#comment.data = deleted ? null : contents;
5831  }
5832  get parentBoundingClientRect() {
5833    return this.parent.boundingClientRect;
5834  }
5835  render() {
5836    const div = this.div = document.createElement("div");
5837    div.setAttribute("data-editor-rotation", (360 - this.rotation) % 360);
5838    div.className = this.name;
5839    div.setAttribute("id", this.id);
5840    div.tabIndex = this.#disabled ? -1 : 0;
5841    div.setAttribute("role", "application");
5842    if (this.defaultL10nId) {
5843      div.setAttribute("data-l10n-id", this.defaultL10nId);
5844    }
5845    if (!this._isVisible) {
5846      div.classList.add("hidden");
5847    }
5848    this.setInForeground();
5849    this.#addFocusListeners();
5850    const [parentWidth, parentHeight] = this.parentDimensions;
5851    if (this.parentRotation % 180 !== 0) {
5852      div.style.maxWidth = `${(100 * parentHeight / parentWidth).toFixed(2)}%`;
5853      div.style.maxHeight = `${(100 * parentWidth / parentHeight).toFixed(2)}%`;
5854    }
5855    const [tx, ty] = this.getInitialTranslation();
5856    this.translate(tx, ty);
5857    bindEvents(this, div, ["keydown", "pointerdown", "dblclick"]);
5858    
vendor: 3,341 bytes, lines 5858-5951
5858if (this.isResizable && this._uiManager._supportsPinchToZoom) {
5859      this.#touchManager ||= new TouchManager({
5860        container: div,
5861        isPinchingDisabled: () => !this.isSelected,
5862        onPinchStart: this.#touchPinchStartCallback.bind(this),
5863        onPinching: this.#touchPinchCallback.bind(this),
5864        onPinchEnd: this.#touchPinchEndCallback.bind(this),
5865        signal: this._uiManager._signal
5866      });
5867    }
5868    this.addStandaloneCommentButton();
5869    this._uiManager._editorUndoBar?.hide();
5870    return div;
5871  }
5872  #touchPinchStartCallback() {
5873    this.#savedDimensions = {
5874      savedX: this.x,
5875      savedY: this.y,
5876      savedWidth: this.width,
5877      savedHeight: this.height
5878    };
5879    this.#altText?.toggle(false);
5880    this.parent.togglePointerEvents(false);
5881  }
5882  #touchPinchCallback(_origin, prevDistance, distance) {
5883    const slowDownFactor = 0.7;
5884    let factor = slowDownFactor * (distance / prevDistance) + 1 - slowDownFactor;
5885    if (factor === 1) {
5886      return;
5887    }
5888    const rotationMatrix = this.#getRotationMatrix(this.rotation);
5889    const transf = (x, y) => [rotationMatrix[0] * x + rotationMatrix[2] * y, rotationMatrix[1] * x + rotationMatrix[3] * y];
5890    const [parentWidth, parentHeight] = this.parentDimensions;
5891    const savedX = this.x;
5892    const savedY = this.y;
5893    const savedWidth = this.width;
5894    const savedHeight = this.height;
5895    const minWidth = AnnotationEditor.MIN_SIZE / parentWidth;
5896    const minHeight = AnnotationEditor.MIN_SIZE / parentHeight;
5897    factor = Math.max(Math.min(factor, 1 / savedWidth, 1 / savedHeight), minWidth / savedWidth, minHeight / savedHeight);
5898    const newWidth = AnnotationEditor._round(savedWidth * factor);
5899    const newHeight = AnnotationEditor._round(savedHeight * factor);
5900    if (newWidth === savedWidth && newHeight === savedHeight) {
5901      return;
5902    }
5903    this.#initialRect ||= [savedX, savedY, savedWidth, savedHeight];
5904    const transfCenterPoint = transf(savedWidth / 2, savedHeight / 2);
5905    const centerX = AnnotationEditor._round(savedX + transfCenterPoint[0]);
5906    const centerY = AnnotationEditor._round(savedY + transfCenterPoint[1]);
5907    const newTransfCenterPoint = transf(newWidth / 2, newHeight / 2);
5908    this.x = centerX - newTransfCenterPoint[0];
5909    this.y = centerY - newTransfCenterPoint[1];
5910    this.width = newWidth;
5911    this.height = newHeight;
5912    this.setDims();
5913    this.fixAndSetPosition();
5914    this._onResizing();
5915  }
5916  #touchPinchEndCallback() {
5917    this.#altText?.toggle(true);
5918    this.parent.togglePointerEvents(true);
5919    this.#addResizeToUndoStack();
5920  }
5921  pointerdown(event) {
5922    const {
5923      isMac
5924    } = FeatureTest.platform;
5925    if (event.button !== 0 || event.ctrlKey && isMac) {
5926      event.preventDefault();
5927      return;
5928    }
5929    this.#hasBeenClicked = true;
5930    if (this._isDraggable) {
5931      this.#setUpDragSession(event);
5932      return;
5933    }
5934    this.#selectOnPointerEvent(event);
5935  }
5936  #selectOnPointerEvent(event) {
5937    const {
5938      isMac
5939    } = FeatureTest.platform;
5940    if (event.ctrlKey && !isMac || event.shiftKey || event.metaKey && isMac) {
5941      this.parent.toggleSelected(this);
5942    } else {
5943      this.parent.setSelected(this);
5944    }
5945  }
5946  #setUpDragSession(event) {
5947    const {
5948      isSelected
5949    } = this;
5950    this._uiManager.setUpDragSession();
5951    let hasDraggingStarted = false;
vendor: 8,204 bytes, lines 5952-6243
5952    const ac = new AbortController();
5953    const signal = this._uiManager.combinedSignal(ac);
5954    const opts = {
5955      capture: true,
5956      passive: false,
5957      signal
5958    };
5959    const cancelDrag = e => {
5960      ac.abort();
5961      this.#dragPointerId = null;
5962      this.#hasBeenClicked = false;
5963      if (!this._uiManager.endDragSession()) {
5964        this.#selectOnPointerEvent(e);
5965      }
5966      if (hasDraggingStarted) {
5967        this._onStopDragging();
5968      }
5969    };
5970    if (isSelected) {
5971      this.#prevDragX = event.clientX;
5972      this.#prevDragY = event.clientY;
5973      this.#dragPointerId = event.pointerId;
5974      this.#dragPointerType = event.pointerType;
5975      window.addEventListener("pointermove", e => {
5976        if (!hasDraggingStarted) {
5977          hasDraggingStarted = true;
5978          this._uiManager.toggleComment(this, true, false);
5979          this._onStartDragging();
5980        }
5981        const {
5982          clientX: x,
5983          clientY: y,
5984          pointerId
5985        } = e;
5986        if (pointerId !== this.#dragPointerId) {
5987          stopEvent(e);
5988          return;
5989        }
5990        const [tx, ty] = this.screenToPageTranslation(x - this.#prevDragX, y - this.#prevDragY);
5991        this.#prevDragX = x;
5992        this.#prevDragY = y;
5993        this._uiManager.dragSelectedEditors(tx, ty);
5994      }, opts);
5995      window.addEventListener("touchmove", stopEvent, opts);
5996      window.addEventListener("pointerdown", e => {
5997        if (e.pointerType === this.#dragPointerType) {
5998          if (this.#touchManager || e.isPrimary) {
5999            cancelDrag(e);
6000          }
6001        }
6002        stopEvent(e);
6003      }, opts);
6004    }
6005    const pointerUpCallback = e => {
6006      if (!this.#dragPointerId || this.#dragPointerId === e.pointerId) {
6007        cancelDrag(e);
6008        return;
6009      }
6010      stopEvent(e);
6011    };
6012    window.addEventListener("pointerup", pointerUpCallback, {
6013      signal
6014    });
6015    window.addEventListener("blur", pointerUpCallback, {
6016      signal
6017    });
6018  }
6019  _onStartDragging() {}
6020  _onStopDragging() {}
6021  moveInDOM() {
6022    if (this.#moveInDOMTimeout) {
6023      clearTimeout(this.#moveInDOMTimeout);
6024    }
6025    this.#moveInDOMTimeout = setTimeout(() => {
6026      this.#moveInDOMTimeout = null;
6027      this.parent?.moveEditorInDOM(this);
6028    }, 0);
6029  }
6030  _setParentAndPosition(parent, x, y) {
6031    parent.changeParent(this);
6032    this.x = x;
6033    this.y = y;
6034    this.fixAndSetPosition();
6035    this._onTranslated();
6036  }
6037  getRect(tx, ty, rotation = this.rotation) {
6038    const scale = this.parentScale;
6039    const [pageWidth, pageHeight] = this.pageDimensions;
6040    const [pageX, pageY] = this.pageTranslation;
6041    const shiftX = tx / scale;
6042    const shiftY = ty / scale;
6043    const x = this.x * pageWidth;
6044    const y = this.y * pageHeight;
6045    const width = this.width * pageWidth;
6046    const height = this.height * pageHeight;
6047    switch (rotation) {
6048      case 0:
6049        return [x + shiftX + pageX, pageHeight - y - shiftY - height + pageY, x + shiftX + width + pageX, pageHeight - y - shiftY + pageY];
6050      case 90:
6051        return [x + shiftY + pageX, pageHeight - y + shiftX + pageY, x + shiftY + height + pageX, pageHeight - y + shiftX + width + pageY];
6052      case 180:
6053        return [x - shiftX - width + pageX, pageHeight - y + shiftY + pageY, x - shiftX + pageX, pageHeight - y + shiftY + height + pageY];
6054      case 270:
6055        return [x - shiftY - height + pageX, pageHeight - y - shiftX - width + pageY, x - shiftY + pageX, pageHeight - y - shiftX + pageY];
6056      default:
6057        throw new Error("Invalid rotation");
6058    }
6059  }
6060  getRectInCurrentCoords(rect, pageHeight) {
6061    const [x1, y1, x2, y2] = rect;
6062    const width = x2 - x1;
6063    const height = y2 - y1;
6064    switch (this.rotation) {
6065      case 0:
6066        return [x1, pageHeight - y2, width, height];
6067      case 90:
6068        return [x1, pageHeight - y1, height, width];
6069      case 180:
6070        return [x2, pageHeight - y1, width, height];
6071      case 270:
6072        return [x2, pageHeight - y2, height, width];
6073      default:
6074        throw new Error("Invalid rotation");
6075    }
6076  }
6077  getPDFRect() {
6078    return this.getRect(0, 0);
6079  }
6080  getNonHCMColor() {
6081    return this.color && AnnotationEditor._colorManager.convert(this._uiManager.getNonHCMColor(this.color));
6082  }
6083  onUpdatedColor() {
6084    this.#comment?.onUpdatedColor();
6085  }
6086  getData() {
6087    const {
6088      comment: {
6089        text: str,
6090        color,
6091        date,
6092        opacity,
6093        deleted,
6094        richText
6095      },
6096      uid: id,
6097      pageIndex,
6098      creationDate,
6099      modificationDate
6100    } = this;
6101    return {
6102      id,
6103      pageIndex,
6104      rect: this.getPDFRect(),
6105      richText,
6106      contentsObj: {
6107        str
6108      },
6109      creationDate,
6110      modificationDate: date || modificationDate,
6111      popupRef: !deleted,
6112      color,
6113      opacity
6114    };
6115  }
6116  onceAdded(focus) {}
6117  isEmpty() {
6118    return false;
6119  }
6120  enableEditMode() {
6121    if (this.isInEditMode()) {
6122      return false;
6123    }
6124    this.parent.setEditingState(false);
6125    this.#isInEditMode = true;
6126    return true;
6127  }
6128  disableEditMode() {
6129    if (!this.isInEditMode()) {
6130      return false;
6131    }
6132    this.parent.setEditingState(true);
6133    this.#isInEditMode = false;
6134    return true;
6135  }
6136  isInEditMode() {
6137    return this.#isInEditMode;
6138  }
6139  shouldGetKeyboardEvents() {
6140    return this.#isResizerEnabledForKeyboard;
6141  }
6142  needsToBeRebuilt() {
6143    return this.div && !this.isAttachedToDOM;
6144  }
6145  get isOnScreen() {
6146    const {
6147      top,
6148      left,
6149      bottom,
6150      right
6151    } = this.getClientDimensions();
6152    const {
6153      innerHeight,
6154      innerWidth
6155    } = window;
6156    return left < innerWidth && right > 0 && top < innerHeight && bottom > 0;
6157  }
6158  #addFocusListeners() {
6159    if (this.#focusAC || !this.div) {
6160      return;
6161    }
6162    this.#focusAC = new AbortController();
6163    const signal = this._uiManager.combinedSignal(this.#focusAC);
6164    this.div.addEventListener("focusin", this.focusin.bind(this), {
6165      signal
6166    });
6167    this.div.addEventListener("focusout", this.focusout.bind(this), {
6168      signal
6169    });
6170  }
6171  rebuild() {
6172    this.#addFocusListeners();
6173  }
6174  rotate(_angle) {}
6175  resize() {}
6176  serializeDeleted() {
6177    return {
6178      id: this.annotationElementId,
6179      deleted: true,
6180      pageIndex: this.pageIndex,
6181      popupRef: this._initialData?.popupRef || ""
6182    };
6183  }
6184  serialize(isForCopying = false, context = null) {
6185    return {
6186      annotationType: this.mode,
6187      pageIndex: this.pageIndex,
6188      rect: this.getPDFRect(),
6189      rotation: this.rotation,
6190      structTreeParentId: this._structTreeParentId,
6191      popupRef: this._initialData?.popupRef || ""
6192    };
6193  }
6194  static async deserialize(data, parent, uiManager) {
6195    const editor = new this.prototype.constructor({
6196      parent,
6197      id: uiManager.getId(),
6198      uiManager,
6199      annotationElementId: data.annotationElementId,
6200      creationDate: data.creationDate,
6201      modificationDate: data.modificationDate
6202    });
6203    editor.rotation = data.rotation;
6204    editor.#accessibilityData = data.accessibilityData;
6205    editor._isCopy = data.isCopy || false;
6206    const [pageWidth, pageHeight] = editor.pageDimensions;
6207    const [x, y, width, height] = editor.getRectInCurrentCoords(data.rect, pageHeight);
6208    editor.x = x / pageWidth;
6209    editor.y = y / pageHeight;
6210    editor.width = width / pageWidth;
6211    editor.height = height / pageHeight;
6212    return editor;
6213  }
6214  get hasBeenModified() {
6215    return !!this.annotationElementId && (this.deleted || this.serialize() !== null);
6216  }
6217  remove() {
6218    this.#focusAC?.abort();
6219    this.#focusAC = null;
6220    if (!this.isEmpty()) {
6221      this.commit();
6222    }
6223    if (this.parent) {
6224      this.parent.remove(this);
6225    } else {
6226      this._uiManager.removeEditor(this);
6227    }
6228    this.hideCommentPopup();
6229    if (this.#moveInDOMTimeout) {
6230      clearTimeout(this.#moveInDOMTimeout);
6231      this.#moveInDOMTimeout = null;
6232    }
6233    this.#stopResizing();
6234    this.removeEditToolbar();
6235    if (this.#telemetryTimeouts) {
6236      for (const timeout of this.#telemetryTimeouts.values()) {
6237        clearTimeout(timeout);
6238      }
6239      this.#telemetryTimeouts = null;
6240    }
6241    this.parent = null;
6242    this.#touchManager?.destroy();
6243    this.#touchManager
vendor: 22,323 bytes, lines 6243-7078
6243 = null;
6244    this.#fakeAnnotation?.remove();
6245    this.#fakeAnnotation = null;
6246  }
6247  get isResizable() {
6248    return false;
6249  }
6250  makeResizable() {
6251    if (this.isResizable) {
6252      this.#createResizers();
6253      this.#resizersDiv.classList.remove("hidden");
6254    }
6255  }
6256  get toolbarPosition() {
6257    return null;
6258  }
6259  get commentButtonPosition() {
6260    return this._uiManager.direction === "ltr" ? [1, 0] : [0, 0];
6261  }
6262  get commentButtonPositionInPage() {
6263    const {
6264      commentButtonPosition: [posX, posY]
6265    } = this;
6266    const [blX, blY, trX, trY] = this.getPDFRect();
6267    return [AnnotationEditor._round(blX + (trX - blX) * posX), AnnotationEditor._round(blY + (trY - blY) * (1 - posY))];
6268  }
6269  get commentButtonColor() {
6270    return this._uiManager.makeCommentColor(this.getNonHCMColor(), this.opacity);
6271  }
6272  get commentPopupPosition() {
6273    return this.#comment.commentPopupPositionInLayer;
6274  }
6275  set commentPopupPosition(pos) {
6276    this.#comment.commentPopupPositionInLayer = pos;
6277  }
6278  hasDefaultPopupPosition() {
6279    return this.#comment.hasDefaultPopupPosition();
6280  }
6281  get commentButtonWidth() {
6282    return this.#comment.commentButtonWidth;
6283  }
6284  get elementBeforePopup() {
6285    return this.div;
6286  }
6287  setCommentButtonStates(options) {
6288    this.#comment?.setCommentButtonStates(options);
6289  }
6290  keydown(event) {
6291    if (!this.isResizable || event.target !== this.div || event.key !== "Enter") {
6292      return;
6293    }
6294    this._uiManager.setSelected(this);
6295    this.#savedDimensions = {
6296      savedX: this.x,
6297      savedY: this.y,
6298      savedWidth: this.width,
6299      savedHeight: this.height
6300    };
6301    const children = this.#resizersDiv.children;
6302    if (!this.#allResizerDivs) {
6303      this.#allResizerDivs = Array.from(children);
6304      const boundResizerKeydown = this.#resizerKeydown.bind(this);
6305      const boundResizerBlur = this.#resizerBlur.bind(this);
6306      const signal = this._uiManager._signal;
6307      for (const div of this.#allResizerDivs) {
6308        const name = div.getAttribute("data-resizer-name");
6309        div.setAttribute("role", "spinbutton");
6310        div.addEventListener("keydown", boundResizerKeydown, {
6311          signal
6312        });
6313        div.addEventListener("blur", boundResizerBlur, {
6314          signal
6315        });
6316        div.addEventListener("focus", this.#resizerFocus.bind(this, name), {
6317          signal
6318        });
6319        div.setAttribute("data-l10n-id", AnnotationEditor._l10nResizer[name]);
6320      }
6321    }
6322    const first = this.#allResizerDivs[0];
6323    let firstPosition = 0;
6324    for (const div of children) {
6325      if (div === first) {
6326        break;
6327      }
6328      firstPosition++;
6329    }
6330    const nextFirstPosition = (360 - this.rotation + this.parentRotation) % 360 / 90 * (this.#allResizerDivs.length / 4);
6331    if (nextFirstPosition !== firstPosition) {
6332      if (nextFirstPosition < firstPosition) {
6333        for (let i = 0; i < firstPosition - nextFirstPosition; i++) {
6334          this.#resizersDiv.append(this.#resizersDiv.firstElementChild);
6335        }
6336      } else if (nextFirstPosition > firstPosition) {
6337        for (let i = 0; i < nextFirstPosition - firstPosition; i++) {
6338          this.#resizersDiv.firstElementChild.before(this.#resizersDiv.lastElementChild);
6339        }
6340      }
6341      let i = 0;
6342      for (const child of children) {
6343        const div = this.#allResizerDivs[i++];
6344        const name = div.getAttribute("data-resizer-name");
6345        child.setAttribute("data-l10n-id", AnnotationEditor._l10nResizer[name]);
6346      }
6347    }
6348    this.#setResizerTabIndex(0);
6349    this.#isResizerEnabledForKeyboard = true;
6350    this.#resizersDiv.firstElementChild.focus({
6351      focusVisible: true
6352    });
6353    event.preventDefault();
6354    event.stopImmediatePropagation();
6355  }
6356  #resizerKeydown(event) {
6357    AnnotationEditor._resizerKeyboardManager.exec(this, event);
6358  }
6359  #resizerBlur(event) {
6360    if (this.#isResizerEnabledForKeyboard && event.relatedTarget?.parentNode !== this.#resizersDiv) {
6361      this.#stopResizing();
6362    }
6363  }
6364  #resizerFocus(name) {
6365    this.#focusedResizerName = this.#isResizerEnabledForKeyboard ? name : "";
6366  }
6367  #setResizerTabIndex(value) {
6368    if (!this.#allResizerDivs) {
6369      return;
6370    }
6371    for (const div of this.#allResizerDivs) {
6372      div.tabIndex = value;
6373    }
6374  }
6375  _resizeWithKeyboard(x, y) {
6376    if (!this.#isResizerEnabledForKeyboard) {
6377      return;
6378    }
6379    this.#resizerPointermove(this.#focusedResizerName, {
6380      deltaX: x,
6381      deltaY: y,
6382      fromKeyboard: true
6383    });
6384  }
6385  #stopResizing() {
6386    this.#isResizerEnabledForKeyboard = false;
6387    this.#setResizerTabIndex(-1);
6388    this.#addResizeToUndoStack();
6389  }
6390  _stopResizingWithKeyboard() {
6391    this.#stopResizing();
6392    this.div.focus();
6393  }
6394  select() {
6395    if (this.isSelected && this._editToolbar) {
6396      this._editToolbar.show();
6397      return;
6398    }
6399    this.isSelected = true;
6400    this.makeResizable();
6401    this.div?.classList.add("selectedEditor");
6402    if (!this._editToolbar) {
6403      this.addEditToolbar().then(() => {
6404        if (this.div?.classList.contains("selectedEditor")) {
6405          this._editToolbar?.show();
6406        }
6407      });
6408      return;
6409    }
6410    this._editToolbar?.show();
6411    this.#altText?.toggleAltTextBadge(false);
6412  }
6413  focus() {
6414    if (this.div && !this.div.contains(document.activeElement)) {
6415      setTimeout(() => this.div?.focus({
6416        preventScroll: true
6417      }), 0);
6418    }
6419  }
6420  unselect() {
6421    if (!this.isSelected) {
6422      return;
6423    }
6424    this.isSelected = false;
6425    this.#resizersDiv?.classList.add("hidden");
6426    this.div?.classList.remove("selectedEditor");
6427    if (this.div?.contains(document.activeElement)) {
6428      this._uiManager.currentLayer.div.focus({
6429        preventScroll: true
6430      });
6431    }
6432    this._editToolbar?.hide();
6433    this.#altText?.toggleAltTextBadge(true);
6434    this.hideCommentPopup();
6435  }
6436  hideCommentPopup() {
6437    if (this.hasComment) {
6438      this._uiManager.toggleComment(null);
6439    }
6440  }
6441  updateParams(type, value) {}
6442  disableEditing() {}
6443  enableEditing() {}
6444  get canChangeContent() {
6445    return false;
6446  }
6447  enterInEditMode() {
6448    if (!this.canChangeContent) {
6449      return;
6450    }
6451    this.enableEditMode();
6452    this.div.focus();
6453  }
6454  dblclick(event) {
6455    if (event.target.nodeName === "BUTTON") {
6456      return;
6457    }
6458    this.enterInEditMode();
6459    this.parent.updateToolbar({
6460      mode: this.constructor._editorType,
6461      editId: this.uid
6462    });
6463  }
6464  getElementForAltText() {
6465    return this.div;
6466  }
6467  get contentDiv() {
6468    return this.div;
6469  }
6470  get isEditing() {
6471    return this.#isEditing;
6472  }
6473  set isEditing(value) {
6474    this.#isEditing = value;
6475    if (!this.parent) {
6476      return;
6477    }
6478    if (value) {
6479      this.parent.setSelected(this);
6480      this.parent.setActiveEditor(this);
6481    } else {
6482      this.parent.setActiveEditor(null);
6483    }
6484  }
6485  static get MIN_SIZE() {
6486    return 16;
6487  }
6488  static canCreateNewEmptyEditor() {
6489    return true;
6490  }
6491  get telemetryInitialData() {
6492    return {
6493      action: "added"
6494    };
6495  }
6496  get telemetryFinalData() {
6497    return null;
6498  }
6499  _reportTelemetry(data, mustWait = false) {
6500    if (mustWait) {
6501      this.#telemetryTimeouts ||= new Map();
6502      const {
6503        action
6504      } = data;
6505      let timeout = this.#telemetryTimeouts.get(action);
6506      if (timeout) {
6507        clearTimeout(timeout);
6508      }
6509      timeout = setTimeout(() => {
6510        this._reportTelemetry(data);
6511        this.#telemetryTimeouts.delete(action);
6512        if (this.#telemetryTimeouts.size === 0) {
6513          this.#telemetryTimeouts = null;
6514        }
6515      }, AnnotationEditor._telemetryTimeout);
6516      this.#telemetryTimeouts.set(action, timeout);
6517      return;
6518    }
6519    data.type ||= this.editorType;
6520    this._uiManager._eventBus.dispatch("reporttelemetry", {
6521      source: this,
6522      details: {
6523        type: "editing",
6524        data
6525      }
6526    });
6527  }
6528  show(visible = this._isVisible) {
6529    this.div.classList.toggle("hidden", !visible);
6530    this._isVisible = visible;
6531  }
6532  enable() {
6533    if (this.div) {
6534      this.div.tabIndex = 0;
6535    }
6536    this.#disabled = false;
6537  }
6538  disable() {
6539    if (this.div) {
6540      this.div.tabIndex = -1;
6541    }
6542    this.#disabled = true;
6543  }
6544  updateFakeAnnotationElement(annotationLayer) {
6545    if (!this.#fakeAnnotation && !this.deleted) {
6546      this.#fakeAnnotation = annotationLayer.addFakeAnnotation(this);
6547      return;
6548    }
6549    if (this.deleted) {
6550      this.#fakeAnnotation.remove();
6551      this.#fakeAnnotation = null;
6552      return;
6553    }
6554    if (this.hasEditedComment || this._hasBeenMoved || this._hasBeenResized) {
6555      this.#fakeAnnotation.updateEdited({
6556        rect: this.getPDFRect(),
6557        popup: this.comment
6558      });
6559    }
6560  }
6561  renderAnnotationElement(annotation) {
6562    if (this.deleted) {
6563      annotation.hide();
6564      return null;
6565    }
6566    let content = annotation.container.querySelector(".annotationContent");
6567    if (!content) {
6568      content = document.createElement("div");
6569      content.classList.add("annotationContent", this.editorType);
6570      annotation.container.prepend(content);
6571    } else if (content.nodeName === "CANVAS") {
6572      const canvas = content;
6573      content = document.createElement("div");
6574      content.classList.add("annotationContent", this.editorType);
6575      canvas.before(content);
6576    }
6577    return content;
6578  }
6579  resetAnnotationElement(annotation) {
6580    const {
6581      firstElementChild
6582    } = annotation.container;
6583    if (firstElementChild?.nodeName === "DIV" && firstElementChild.classList.contains("annotationContent")) {
6584      firstElementChild.remove();
6585    }
6586  }
6587}
6588class FakeEditor extends AnnotationEditor {
6589  constructor(params) {
6590    super(params);
6591    this.annotationElementId = params.annotationElementId;
6592    this.deleted = true;
6593  }
6594  serialize() {
6595    return this.serializeDeleted();
6596  }
6597}
6598
6599;// ./src/shared/murmurhash3.js
6600const SEED = 0xc3d2e1f0;
6601const MASK_HIGH = 0xffff0000;
6602const MASK_LOW = 0xffff;
6603class MurmurHash3_64 {
6604  constructor(seed) {
6605    this.h1 = seed ? seed & 0xffffffff : SEED;
6606    this.h2 = seed ? seed & 0xffffffff : SEED;
6607  }
6608  update(input) {
6609    let data, length;
6610    if (typeof input === "string") {
6611      data = new Uint8Array(input.length * 2);
6612      length = 0;
6613      for (let i = 0, ii = input.length; i < ii; i++) {
6614        const code = input.charCodeAt(i);
6615        if (code <= 0xff) {
6616          data[length++] = code;
6617        } else {
6618          data[length++] = code >>> 8;
6619          data[length++] = code & 0xff;
6620        }
6621      }
6622    } else if (ArrayBuffer.isView(input)) {
6623      data = input.slice();
6624      length = data.byteLength;
6625    } else {
6626      throw new Error("Invalid data format, must be a string or TypedArray.");
6627    }
6628    const blockCounts = length >> 2;
6629    const tailLength = length - blockCounts * 4;
6630    const dataUint32 = new Uint32Array(data.buffer, 0, blockCounts);
6631    let k1 = 0,
6632      k2 = 0;
6633    let h1 = this.h1,
6634      h2 = this.h2;
6635    const C1 = 0xcc9e2d51,
6636      C2 = 0x1b873593;
6637    const C1_LOW = C1 & MASK_LOW,
6638      C2_LOW = C2 & MASK_LOW;
6639    for (let i = 0; i < blockCounts; i++) {
6640      if (i & 1) {
6641        k1 = dataUint32[i];
6642        k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW;
6643        k1 = k1 << 15 | k1 >>> 17;
6644        k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW;
6645        h1 ^= k1;
6646        h1 = h1 << 13 | h1 >>> 19;
6647        h1 = h1 * 5 + 0xe6546b64;
6648      } else {
6649        k2 = dataUint32[i];
6650        k2 = k2 * C1 & MASK_HIGH | k2 * C1_LOW & MASK_LOW;
6651        k2 = k2 << 15 | k2 >>> 17;
6652        k2 = k2 * C2 & MASK_HIGH | k2 * C2_LOW & MASK_LOW;
6653        h2 ^= k2;
6654        h2 = h2 << 13 | h2 >>> 19;
6655        h2 = h2 * 5 + 0xe6546b64;
6656      }
6657    }
6658    k1 = 0;
6659    switch (tailLength) {
6660      case 3:
6661        k1 ^= data[blockCounts * 4 + 2] << 16;
6662      case 2:
6663        k1 ^= data[blockCounts * 4 + 1] << 8;
6664      case 1:
6665        k1 ^= data[blockCounts * 4];
6666        k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW;
6667        k1 = k1 << 15 | k1 >>> 17;
6668        k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW;
6669        if (blockCounts & 1) {
6670          h1 ^= k1;
6671        } else {
6672          h2 ^= k1;
6673        }
6674    }
6675    this.h1 = h1;
6676    this.h2 = h2;
6677  }
6678  hexdigest() {
6679    let h1 = this.h1,
6680      h2 = this.h2;
6681    h1 ^= h2 >>> 1;
6682    h1 = h1 * 0xed558ccd & MASK_HIGH | h1 * 0x8ccd & MASK_LOW;
6683    h2 = h2 * 0xff51afd7 & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16;
6684    h1 ^= h2 >>> 1;
6685    h1 = h1 * 0x1a85ec53 & MASK_HIGH | h1 * 0xec53 & MASK_LOW;
6686    h2 = h2 * 0xc4ceb9fe & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16;
6687    h1 ^= h2 >>> 1;
6688    return (h1 >>> 0).toString(16).padStart(8, "0") + (h2 >>> 0).toString(16).padStart(8, "0");
6689  }
6690}
6691
6692;// ./src/display/annotation_storage.js
6693
6694
6695
6696const SerializableEmpty = Object.freeze({
6697  map: null,
6698  hash: "",
6699  transfer: undefined
6700});
6701class AnnotationStorage {
6702  #modified = false;
6703  #modifiedIds = null;
6704  #editorsMap = null;
6705  #storage = new Map();
6706  onSetModified = null;
6707  onResetModified = null;
6708  onAnnotationEditor = null;
6709  getValue(key, defaultValue) {
6710    const value = this.#storage.get(key);
6711    if (value === undefined) {
6712      return defaultValue;
6713    }
6714    return Object.assign(defaultValue, value);
6715  }
6716  getRawValue(key) {
6717    return this.#storage.get(key);
6718  }
6719  remove(key) {
6720    const storedValue = this.#storage.get(key);
6721    if (storedValue === undefined) {
6722      return;
6723    }
6724    if (storedValue instanceof AnnotationEditor) {
6725      this.#editorsMap.delete(storedValue.annotationElementId);
6726    }
6727    this.#storage.delete(key);
6728    if (this.#storage.size === 0) {
6729      this.resetModified();
6730    }
6731    if (this.#storage.values().some(v => v instanceof AnnotationEditor)) {
6732      return;
6733    }
6734    this.onAnnotationEditor?.(null);
6735  }
6736  setValue(key, value) {
6737    const obj = this.#storage.get(key);
6738    let modified = false;
6739    if (obj !== undefined) {
6740      for (const [entry, val] of Object.entries(value)) {
6741        if (obj[entry] !== val) {
6742          modified = true;
6743          obj[entry] = val;
6744        }
6745      }
6746    } else {
6747      modified = true;
6748      this.#storage.set(key, value);
6749    }
6750    if (modified) {
6751      this.#setModified();
6752    }
6753    if (value instanceof AnnotationEditor) {
6754      (this.#editorsMap ||= new Map()).set(value.annotationElementId, value);
6755      this.onAnnotationEditor?.(value.constructor._type);
6756    }
6757  }
6758  has(key) {
6759    return this.#storage.has(key);
6760  }
6761  get size() {
6762    return this.#storage.size;
6763  }
6764  #setModified() {
6765    if (!this.#modified) {
6766      this.#modified = true;
6767      this.onSetModified?.();
6768    }
6769  }
6770  resetModified() {
6771    if (this.#modified) {
6772      this.#modified = false;
6773      this.onResetModified?.();
6774    }
6775  }
6776  get print() {
6777    return new PrintAnnotationStorage(this);
6778  }
6779  get serializable() {
6780    if (this.#storage.size === 0) {
6781      return SerializableEmpty;
6782    }
6783    const map = new Map(),
6784      hash = new MurmurHash3_64(),
6785      transfer = [];
6786    const context = Object.create(null);
6787    let hasBitmap = false;
6788    for (const [key, val] of this.#storage) {
6789      const serialized = val instanceof AnnotationEditor ? val.serialize(false, context) : val;
6790      if (val.page) {
6791        val.pageIndex = val.page._pageIndex;
6792        delete val.page;
6793      }
6794      if (serialized) {
6795        map.set(key, serialized);
6796        hash.update(`${key}:${JSON.stringify(serialized)}`);
6797        hasBitmap ||= !!serialized.bitmap;
6798      }
6799    }
6800    if (hasBitmap) {
6801      for (const value of map.values()) {
6802        if (value.bitmap) {
6803          transfer.push(value.bitmap);
6804        }
6805      }
6806    }
6807    return map.size > 0 ? {
6808      map,
6809      hash: hash.hexdigest(),
6810      transfer
6811    } : SerializableEmpty;
6812  }
6813  get editorStats() {
6814    let stats = null;
6815    const typeToEditor = new Map();
6816    let numberOfEditedComments = 0;
6817    let numberOfDeletedComments = 0;
6818    for (const value of this.#storage.values()) {
6819      if (!(value instanceof AnnotationEditor)) {
6820        if (value.popup) {
6821          if (value.popup.deleted) {
6822            numberOfDeletedComments += 1;
6823          } else {
6824            numberOfEditedComments += 1;
6825          }
6826        }
6827        continue;
6828      }
6829      if (value.isCommentDeleted) {
6830        numberOfDeletedComments += 1;
6831      } else if (value.hasEditedComment) {
6832        numberOfEditedComments += 1;
6833      }
6834      const editorStats = value.telemetryFinalData;
6835      if (!editorStats) {
6836        continue;
6837      }
6838      const {
6839        type
6840      } = editorStats;
6841      typeToEditor.getOrInsertComputed(type, () => Object.getPrototypeOf(value).constructor);
6842      stats ||= Object.create(null);
6843      const map = stats[type] ||= new Map();
6844      for (const [key, val] of Object.entries(editorStats)) {
6845        if (key === "type") {
6846          continue;
6847        }
6848        const counters = map.getOrInsertComputed(key, makeMap);
6849        counters.set(val, (counters.get(val) ?? 0) + 1);
6850      }
6851    }
6852    if (numberOfDeletedComments > 0 || numberOfEditedComments > 0) {
6853      stats ||= Object.create(null);
6854      stats.comments = {
6855        deleted: numberOfDeletedComments,
6856        edited: numberOfEditedComments
6857      };
6858    }
6859    if (!stats) {
6860      return null;
6861    }
6862    for (const [type, editor] of typeToEditor) {
6863      stats[type] = editor.computeTelemetryFinalData(stats[type]);
6864    }
6865    return stats;
6866  }
6867  resetModifiedIds() {
6868    this.#modifiedIds = null;
6869  }
6870  updateEditor(annotationId, data) {
6871    const value = this.#editorsMap?.get(annotationId);
6872    if (value) {
6873      value.updateFromAnnotationLayer(data);
6874      return true;
6875    }
6876    return false;
6877  }
6878  getEditor(annotationId) {
6879    return this.#editorsMap?.get(annotationId) || null;
6880  }
6881  get modifiedIds() {
6882    if (this.#modifiedIds) {
6883      return this.#modifiedIds;
6884    }
6885    const ids = [];
6886    if (this.#editorsMap) {
6887      for (const value of this.#editorsMap.values()) {
6888        if (!value.serialize()) {
6889          continue;
6890        }
6891        ids.push(value.annotationElementId);
6892      }
6893    }
6894    let hash = "";
6895    if (ids.length) {
6896      const h = new MurmurHash3_64();
6897      h.update(ids.join(","));
6898      hash = h.hexdigest();
6899    }
6900    return this.#modifiedIds = {
6901      ids: new Set(ids),
6902      hash
6903    };
6904  }
6905  [Symbol.iterator]() {
6906    return this.#storage.entries();
6907  }
6908}
6909class PrintAnnotationStorage extends AnnotationStorage {
6910  #serializable = SerializableEmpty;
6911  constructor(parent) {
6912    super();
6913    const {
6914      serializable
6915    } = parent;
6916    if (serializable === SerializableEmpty) {
6917      return;
6918    }
6919    const {
6920      map,
6921      hash,
6922      transfer
6923    } = serializable;
6924    const clone = structuredClone(map, transfer ? {
6925      transfer
6926    } : null);
6927    this.#serializable = {
6928      map: clone,
6929      hash,
6930      transfer: []
6931    };
6932  }
6933  get print() {
6934    unreachable("Should not call PrintAnnotationStorage.print");
6935  }
6936  get serializable() {
6937    return this.#serializable;
6938  }
6939  get modifiedIds() {
6940    return shadow(this, "modifiedIds", {
6941      ids: new Set(),
6942      hash: ""
6943    });
6944  }
6945}
6946
6947;// ./src/display/canvas_dependency_tracker.js
6948
6949
6950
6951const FORCED_DEPENDENCY_LABEL = "__forcedDependency";
6952const {
6953  floor,
6954  ceil
6955} = Math;
6956function expandBBox(array, index, minX, minY, maxX, maxY) {
6957  array[index * 4 + 0] = Math.min(array[index * 4 + 0], minX);
6958  array[index * 4 + 1] = Math.min(array[index * 4 + 1], minY);
6959  array[index * 4 + 2] = Math.max(array[index * 4 + 2], maxX);
6960  array[index * 4 + 3] = Math.max(array[index * 4 + 3], maxY);
6961}
6962function scaleCharBBox(scaleX, scaleY, x, y, bbox) {
6963  let temp;
6964  if (scaleX) {
6965    if (scaleX < 0) {
6966      temp = bbox[0];
6967      bbox[0] = bbox[2];
6968      bbox[2] = temp;
6969    }
6970    bbox[0] *= scaleX;
6971    bbox[2] *= scaleX;
6972    if (scaleY < 0) {
6973      temp = bbox[1];
6974      bbox[1] = bbox[3];
6975      bbox[3] = temp;
6976    }
6977    bbox[1] *= scaleY;
6978    bbox[3] *= scaleY;
6979  } else {
6980    bbox.fill(0);
6981  }
6982  bbox[0] += x;
6983  bbox[1] += y;
6984  bbox[2] += x;
6985  bbox[3] += y;
6986}
6987const EMPTY_BBOX = new Uint32Array(new Uint8Array([255, 255, 0, 0]).buffer)[0];
6988class BBoxReader {
6989  #bboxes;
6990  #coords;
6991  constructor(bboxes, coords) {
6992    this.#bboxes = bboxes;
6993    this.#coords = coords;
6994  }
6995  get length() {
6996    return this.#bboxes.length;
6997  }
6998  isEmpty(i) {
6999    return this.#bboxes[i] === EMPTY_BBOX;
7000  }
7001  minX(i) {
7002    return this.#coords[i * 4 + 0] / 256;
7003  }
7004  minY(i) {
7005    return this.#coords[i * 4 + 1] / 256;
7006  }
7007  maxX(i) {
7008    return (this.#coords[i * 4 + 2] + 1) / 256;
7009  }
7010  maxY(i) {
7011    return (this.#coords[i * 4 + 3] + 1) / 256;
7012  }
7013}
7014const ensureDebugMetadata = (map, key) => map?.getOrInsertComputed(key, () => ({
7015  dependencies: new Set(),
7016  isRenderingOperation: false
7017}));
7018class CanvasBBoxTracker {
7019  #baseTransformStack = [[1, 0, 0, 1, 0, 0]];
7020  #clipBox = [-Infinity, -Infinity, Infinity, Infinity];
7021  #pendingBBox = new Float64Array(BBOX_INIT);
7022  _pendingBBoxIdx = -1;
7023  #canvasWidth;
7024  #canvasHeight;
7025  #bboxesCoords;
7026  #bboxes;
7027  _savesStack = [];
7028  _markedContentStack = [];
7029  constructor(canvas, operationsCount) {
7030    this.#canvasWidth = canvas.width;
7031    this.#canvasHeight = canvas.height;
7032    this.#initializeBBoxes(operationsCount);
7033  }
7034  growOperationsCount(operationsCount) {
7035    if (operationsCount >= this.#bboxes.length) {
7036      this.#initializeBBoxes(operationsCount, this.#bboxes);
7037    }
7038  }
7039  #initializeBBoxes(operationsCount, oldBBoxes) {
7040    const buffer = new ArrayBuffer(operationsCount * 4);
7041    this.#bboxesCoords = new Uint8ClampedArray(buffer);
7042    this.#bboxes = new Uint32Array(buffer);
7043    if (oldBBoxes && oldBBoxes.length > 0) {
7044      this.#bboxes.set(oldBBoxes);
7045      this.#bboxes.fill(EMPTY_BBOX, oldBBoxes.length);
7046    } else {
7047      this.#bboxes.fill(EMPTY_BBOX);
7048    }
7049  }
7050  get clipBox() {
7051    return this.#clipBox;
7052  }
7053  save(opIdx) {
7054    this.#clipBox = {
7055      __proto__: this.#clipBox
7056    };
7057    this._savesStack.push(opIdx);
7058    return this;
7059  }
7060  restore(opIdx, onSavePopped) {
7061    const previous = Object.getPrototypeOf(this.#clipBox);
7062    if (previous === null) {
7063      return this;
7064    }
7065    this.#clipBox = previous;
7066    const lastSave = this._savesStack.pop();
7067    if (lastSave !== undefined) {
7068      onSavePopped?.(lastSave, opIdx);
7069      this.#bboxes[opIdx] = this.#bboxes[lastSave];
7070    }
7071    return this;
7072  }
7073  recordOpenMarker(idx) {
7074    this._savesStack.push(idx);
7075    return this;
7076  }
7077  getOpenMarker() {
7078    
7078if (this._savesStack.length === 0) {
7079      return null;
7080    }
7081    return
vendor: 20,732 bytes, lines 7081-7707
7081 this._savesStack.at(-1);
7082  }
7083  recordCloseMarker(opIdx, onSavePopped) {
7084    const lastSave = this._savesStack.pop();
7085    if (lastSave !== undefined) {
7086      onSavePopped?.(lastSave, opIdx);
7087      this.#bboxes[opIdx] = this.#bboxes[lastSave];
7088    }
7089    return this;
7090  }
7091  beginMarkedContent(opIdx) {
7092    this._markedContentStack.push(opIdx);
7093    return this;
7094  }
7095  endMarkedContent(opIdx, onSavePopped) {
7096    const lastSave = this._markedContentStack.pop();
7097    if (lastSave !== undefined) {
7098      onSavePopped?.(lastSave, opIdx);
7099      this.#bboxes[opIdx] = this.#bboxes[lastSave];
7100    }
7101    return this;
7102  }
7103  pushBaseTransform(ctx) {
7104    this.#baseTransformStack.push(Util.multiplyByDOMMatrix(this.#baseTransformStack.at(-1), ctx.getTransform()));
7105    return this;
7106  }
7107  popBaseTransform() {
7108    if (this.#baseTransformStack.length > 1) {
7109      this.#baseTransformStack.pop();
7110    }
7111    return this;
7112  }
7113  resetBBox(idx) {
7114    if (this._pendingBBoxIdx !== idx) {
7115      this._pendingBBoxIdx = idx;
7116      this.#pendingBBox.set(BBOX_INIT, 0);
7117    }
7118    return this;
7119  }
7120  recordClipBox(idx, ctx, minX, maxX, minY, maxY) {
7121    const transform = Util.multiplyByDOMMatrix(this.#baseTransformStack.at(-1), ctx.getTransform());
7122    const clipBox = BBOX_INIT.slice();
7123    Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, clipBox);
7124    const intersection = Util.intersect(this.#clipBox, clipBox);
7125    if (intersection) {
7126      this.#clipBox[0] = intersection[0];
7127      this.#clipBox[1] = intersection[1];
7128      this.#clipBox[2] = intersection[2];
7129      this.#clipBox[3] = intersection[3];
7130    } else {
7131      this.#clipBox[0] = this.#clipBox[1] = Infinity;
7132      this.#clipBox[2] = this.#clipBox[3] = -Infinity;
7133    }
7134    return this;
7135  }
7136  recordBBox(idx, ctx, minX, maxX, minY, maxY) {
7137    const clipBox = this.#clipBox;
7138    if (clipBox[0] === Infinity) {
7139      return this;
7140    }
7141    const transform = Util.multiplyByDOMMatrix(this.#baseTransformStack.at(-1), ctx.getTransform());
7142    if (clipBox[0] === -Infinity) {
7143      Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, this.#pendingBBox);
7144      return this;
7145    }
7146    const bbox = BBOX_INIT.slice();
7147    Util.axialAlignedBoundingBox([minX, minY, maxX, maxY], transform, bbox);
7148    this.#pendingBBox[0] = MathClamp(bbox[0], clipBox[0], this.#pendingBBox[0]);
7149    this.#pendingBBox[1] = MathClamp(bbox[1], clipBox[1], this.#pendingBBox[1]);
7150    this.#pendingBBox[2] = MathClamp(bbox[2], this.#pendingBBox[2], clipBox[2]);
7151    this.#pendingBBox[3] = MathClamp(bbox[3], this.#pendingBBox[3], clipBox[3]);
7152    return this;
7153  }
7154  recordFullPageBBox(idx) {
7155    this.#pendingBBox[0] = Math.max(0, this.#clipBox[0]);
7156    this.#pendingBBox[1] = Math.max(0, this.#clipBox[1]);
7157    this.#pendingBBox[2] = Math.min(this.#canvasWidth, this.#clipBox[2]);
7158    this.#pendingBBox[3] = Math.min(this.#canvasHeight, this.#clipBox[3]);
7159    return this;
7160  }
7161  recordOperation(idx, preserve = false, dependencyLists) {
7162    if (this._pendingBBoxIdx !== idx) {
7163      return this;
7164    }
7165    const minX = floor(this.#pendingBBox[0] * 256 / this.#canvasWidth);
7166    const minY = floor(this.#pendingBBox[1] * 256 / this.#canvasHeight);
7167    const maxX = ceil(this.#pendingBBox[2] * 256 / this.#canvasWidth);
7168    const maxY = ceil(this.#pendingBBox[3] * 256 / this.#canvasHeight);
7169    expandBBox(this.#bboxesCoords, idx, minX, minY, maxX, maxY);
7170    if (dependencyLists) {
7171      for (const dependencies of dependencyLists) {
7172        for (const depIdx of dependencies) {
7173          if (depIdx !== idx) {
7174            expandBBox(this.#bboxesCoords, depIdx, minX, minY, maxX, maxY);
7175          }
7176        }
7177      }
7178    }
7179    if (!preserve) {
7180      this._pendingBBoxIdx = -1;
7181    }
7182    return this;
7183  }
7184  bboxToClipBoxDropOperation(idx) {
7185    if (this._pendingBBoxIdx === idx) {
7186      this._pendingBBoxIdx = -1;
7187      this.#clipBox[0] = Math.max(this.#clipBox[0], this.#pendingBBox[0]);
7188      this.#clipBox[1] = Math.max(this.#clipBox[1], this.#pendingBBox[1]);
7189      this.#clipBox[2] = Math.min(this.#clipBox[2], this.#pendingBBox[2]);
7190      this.#clipBox[3] = Math.min(this.#clipBox[3], this.#pendingBBox[3]);
7191    }
7192    return this;
7193  }
7194  take() {
7195    return new BBoxReader(this.#bboxes, this.#bboxesCoords);
7196  }
7197  takeDebugMetadata() {
7198    throw new Error("Unreachable");
7199  }
7200  recordSimpleData(name, idx) {
7201    return this;
7202  }
7203  recordIncrementalData(name, idx) {
7204    return this;
7205  }
7206  resetIncrementalData(name, idx) {
7207    return this;
7208  }
7209  recordNamedData(name, idx) {
7210    return this;
7211  }
7212  recordSimpleDataFromNamed(name, depName, fallbackIdx) {
7213    return this;
7214  }
7215  recordFutureForcedDependency(name, idx) {
7216    return this;
7217  }
7218  inheritSimpleDataAsFutureForcedDependencies(names) {
7219    return this;
7220  }
7221  inheritPendingDependenciesAsFutureForcedDependencies() {
7222    return this;
7223  }
7224  recordCharacterBBox(idx, ctx, font, scale = 1, x = 0, y = 0, getMeasure) {
7225    return this;
7226  }
7227  getSimpleIndex(dependencyName) {
7228    return undefined;
7229  }
7230  recordDependencies(idx, dependencyNames) {
7231    return this;
7232  }
7233  recordNamedDependency(idx, name) {
7234    return this;
7235  }
7236  recordShowTextOperation(idx, preserve = false) {
7237    return this;
7238  }
7239}
7240class CanvasDependencyTracker {
7241  #simple = {
7242    __proto__: null
7243  };
7244  #incremental = {
7245    __proto__: null,
7246    transform: [],
7247    moveText: [],
7248    sameLineText: [],
7249    [FORCED_DEPENDENCY_LABEL]: []
7250  };
7251  #namedDependencies = new Map();
7252  #pendingDependencies = new Set();
7253  #fontBBoxTrustworthy = new Map();
7254  #debugMetadata;
7255  #recordDebugMetadataDepenencyAfterRestore;
7256  #bboxTracker;
7257  constructor(bboxTracker, recordDebugMetadata = false) {
7258    this.#bboxTracker = bboxTracker;
7259    if (recordDebugMetadata) {
7260      this.#debugMetadata = new Map();
7261      this.#recordDebugMetadataDepenencyAfterRestore = (lastSave, opIdx) => {
7262        ensureDebugMetadata(this.#debugMetadata, opIdx).dependencies.add(lastSave);
7263      };
7264    }
7265  }
7266  get clipBox() {
7267    return this.#bboxTracker.clipBox;
7268  }
7269  growOperationsCount(operationsCount) {
7270    this.#bboxTracker.growOperationsCount(operationsCount);
7271  }
7272  save(opIdx) {
7273    this.#simple = {
7274      __proto__: this.#simple
7275    };
7276    this.#incremental = {
7277      __proto__: this.#incremental,
7278      transform: {
7279        __proto__: this.#incremental.transform
7280      },
7281      moveText: {
7282        __proto__: this.#incremental.moveText
7283      },
7284      sameLineText: {
7285        __proto__: this.#incremental.sameLineText
7286      },
7287      [FORCED_DEPENDENCY_LABEL]: {
7288        __proto__: this.#incremental[FORCED_DEPENDENCY_LABEL]
7289      }
7290    };
7291    this.#bboxTracker.save(opIdx);
7292    return this;
7293  }
7294  restore(opIdx) {
7295    this.#bboxTracker.restore(opIdx, this.#recordDebugMetadataDepenencyAfterRestore);
7296    const previous = Object.getPrototypeOf(this.#simple);
7297    if (previous === null) {
7298      return this;
7299    }
7300    this.#simple = previous;
7301    this.#incremental = Object.getPrototypeOf(this.#incremental);
7302    return this;
7303  }
7304  recordOpenMarker(opIdx) {
7305    this.#bboxTracker.recordOpenMarker(opIdx, this.#recordDebugMetadataDepenencyAfterRestore);
7306    return this;
7307  }
7308  getOpenMarker() {
7309    return this.#bboxTracker.getOpenMarker();
7310  }
7311  recordCloseMarker(opIdx) {
7312    this.#bboxTracker.recordCloseMarker(opIdx, this.#recordDebugMetadataDepenencyAfterRestore);
7313    return this;
7314  }
7315  beginMarkedContent(opIdx) {
7316    this.#bboxTracker.beginMarkedContent(opIdx);
7317    return this;
7318  }
7319  endMarkedContent(opIdx) {
7320    this.#bboxTracker.endMarkedContent(opIdx, this.#recordDebugMetadataDepenencyAfterRestore);
7321    return this;
7322  }
7323  pushBaseTransform(ctx) {
7324    this.#bboxTracker.pushBaseTransform(ctx);
7325    return this;
7326  }
7327  popBaseTransform() {
7328    this.#bboxTracker.popBaseTransform();
7329    return this;
7330  }
7331  recordSimpleData(name, idx) {
7332    this.#simple[name] = idx;
7333    return this;
7334  }
7335  recordIncrementalData(name, idx) {
7336    this.#incremental[name].push(idx);
7337    return this;
7338  }
7339  resetIncrementalData(name, idx) {
7340    this.#incremental[name].length = 0;
7341    return this;
7342  }
7343  recordNamedData(name, idx) {
7344    this.#namedDependencies.set(name, idx);
7345    return this;
7346  }
7347  recordSimpleDataFromNamed(name, depName, fallbackIdx) {
7348    this.#simple[name] = this.#namedDependencies.get(depName) ?? fallbackIdx;
7349  }
7350  recordFutureForcedDependency(name, idx) {
7351    this.recordIncrementalData(FORCED_DEPENDENCY_LABEL, idx);
7352    return this;
7353  }
7354  inheritSimpleDataAsFutureForcedDependencies(names) {
7355    for (const name of names) {
7356      if (name in this.#simple) {
7357        this.recordFutureForcedDependency(name, this.#simple[name]);
7358      }
7359    }
7360    return this;
7361  }
7362  inheritPendingDependenciesAsFutureForcedDependencies() {
7363    for (const dep of this.#pendingDependencies) {
7364      this.recordFutureForcedDependency(FORCED_DEPENDENCY_LABEL, dep);
7365    }
7366    return this;
7367  }
7368  resetBBox(idx) {
7369    this.#bboxTracker.resetBBox(idx);
7370    return this;
7371  }
7372  recordClipBox(idx, ctx, minX, maxX, minY, maxY) {
7373    this.#bboxTracker.recordClipBox(idx, ctx, minX, maxX, minY, maxY);
7374    return this;
7375  }
7376  recordBBox(idx, ctx, minX, maxX, minY, maxY) {
7377    this.#bboxTracker.recordBBox(idx, ctx, minX, maxX, minY, maxY);
7378    return this;
7379  }
7380  recordCharacterBBox(idx, ctx, font, scale = 1, x = 0, y = 0, getMeasure) {
7381    const fontBBox = font.bbox;
7382    let isBBoxTrustworthy;
7383    let computedBBox;
7384    if (fontBBox) {
7385      isBBoxTrustworthy = fontBBox[2] !== fontBBox[0] && fontBBox[3] !== fontBBox[1] && this.#fontBBoxTrustworthy.get(font);
7386      if (isBBoxTrustworthy !== false) {
7387        computedBBox = [0, 0, 0, 0];
7388        Util.axialAlignedBoundingBox(fontBBox, font.fontMatrix, computedBBox);
7389        if (scale !== 1 || x !== 0 || y !== 0) {
7390          scaleCharBBox(scale, -scale, x, y, computedBBox);
7391        }
7392        if (isBBoxTrustworthy) {
7393          return this.recordBBox(idx, ctx, computedBBox[0], computedBBox[2], computedBBox[1], computedBBox[3]);
7394        }
7395      }
7396    }
7397    if (!getMeasure) {
7398      return this.recordFullPageBBox(idx);
7399    }
7400    const measure = getMeasure();
7401    if (fontBBox && computedBBox && isBBoxTrustworthy === undefined) {
7402      isBBoxTrustworthy = computedBBox[0] <= x - measure.actualBoundingBoxLeft && computedBBox[2] >= x + measure.actualBoundingBoxRight && computedBBox[1] <= y - measure.actualBoundingBoxAscent && computedBBox[3] >= y + measure.actualBoundingBoxDescent;
7403      this.#fontBBoxTrustworthy.set(font, isBBoxTrustworthy);
7404      if (isBBoxTrustworthy) {
7405        return this.recordBBox(idx, ctx, computedBBox[0], computedBBox[2], computedBBox[1], computedBBox[3]);
7406      }
7407    }
7408    return this.recordBBox(idx, ctx, x - measure.actualBoundingBoxLeft, x + measure.actualBoundingBoxRight, y - measure.actualBoundingBoxAscent, y + measure.actualBoundingBoxDescent);
7409  }
7410  recordFullPageBBox(idx) {
7411    this.#bboxTracker.recordFullPageBBox(idx);
7412    return this;
7413  }
7414  getSimpleIndex(dependencyName) {
7415    return this.#simple[dependencyName];
7416  }
7417  recordDependencies(idx, dependencyNames) {
7418    const pendingDependencies = this.#pendingDependencies;
7419    const simple = this.#simple;
7420    const incremental = this.#incremental;
7421    for (const name of dependencyNames) {
7422      if (name in this.#simple) {
7423        pendingDependencies.add(simple[name]);
7424      } else if (name in incremental) {
7425        incremental[name].forEach(pendingDependencies.add, pendingDependencies);
7426      }
7427    }
7428    return this;
7429  }
7430  recordNamedDependency(idx, name) {
7431    if (this.#namedDependencies.has(name)) {
7432      this.#pendingDependencies.add(this.#namedDependencies.get(name));
7433    }
7434    return this;
7435  }
7436  recordOperation(idx, preserve = false) {
7437    this.recordDependencies(idx, [FORCED_DEPENDENCY_LABEL]);
7438    if (this.#debugMetadata) {
7439      const metadata = ensureDebugMetadata(this.#debugMetadata, idx);
7440      const {
7441        dependencies
7442      } = metadata;
7443      this.#pendingDependencies.forEach(dependencies.add, dependencies);
7444      this.#bboxTracker._savesStack.forEach(dependencies.add, dependencies);
7445      this.#bboxTracker._markedContentStack.forEach(dependencies.add, dependencies);
7446      dependencies.delete(idx);
7447      metadata.isRenderingOperation = true;
7448    }
7449    const needsCleanup = !preserve && idx === this.#bboxTracker._pendingBBoxIdx;
7450    this.#bboxTracker.recordOperation(idx, preserve, [this.#pendingDependencies, this.#bboxTracker._savesStack, this.#bboxTracker._markedContentStack]);
7451    if (needsCleanup) {
7452      this.#pendingDependencies.clear();
7453    }
7454    return this;
7455  }
7456  recordShowTextOperation(idx, preserve = false) {
7457    const deps = Array.from(this.#pendingDependencies);
7458    this.recordOperation(idx, preserve);
7459    this.recordIncrementalData("sameLineText", idx);
7460    for (const dep of deps) {
7461      this.recordIncrementalData("sameLineText", dep);
7462    }
7463    return this;
7464  }
7465  bboxToClipBoxDropOperation(idx, preserve = false) {
7466    const needsCleanup = !preserve && idx === this.#bboxTracker._pendingBBoxIdx;
7467    this.#bboxTracker.bboxToClipBoxDropOperation(idx);
7468    if (needsCleanup) {
7469      this.#pendingDependencies.clear();
7470    }
7471    return this;
7472  }
7473  take() {
7474    this.#fontBBoxTrustworthy.clear();
7475    return this.#bboxTracker.take();
7476  }
7477  takeDebugMetadata() {
7478    return this.#debugMetadata;
7479  }
7480}
7481class CanvasNestedDependencyTracker {
7482  #dependencyTracker;
7483  #opIdx;
7484  #ignoreBBoxes;
7485  #nestingLevel = 0;
7486  #savesLevel = 0;
7487  constructor(dependencyTracker, opIdx, ignoreBBoxes) {
7488    if (dependencyTracker instanceof CanvasNestedDependencyTracker && dependencyTracker.#ignoreBBoxes === !!ignoreBBoxes) {
7489      return dependencyTracker;
7490    }
7491    this.#dependencyTracker = dependencyTracker;
7492    this.#opIdx = opIdx;
7493    this.#ignoreBBoxes = !!ignoreBBoxes;
7494  }
7495  get clipBox() {
7496    return this.#dependencyTracker.clipBox;
7497  }
7498  growOperationsCount() {
7499    throw new Error("Unreachable");
7500  }
7501  save(opIdx) {
7502    this.#savesLevel++;
7503    this.#dependencyTracker.save(this.#opIdx);
7504    return this;
7505  }
7506  restore(opIdx) {
7507    if (this.#savesLevel > 0) {
7508      this.#dependencyTracker.restore(this.#opIdx);
7509      this.#savesLevel--;
7510    }
7511    return this;
7512  }
7513  recordOpenMarker(idx) {
7514    this.#nestingLevel++;
7515    return this;
7516  }
7517  getOpenMarker() {
7518    return this.#nestingLevel > 0 ? this.#opIdx : this.#dependencyTracker.getOpenMarker();
7519  }
7520  recordCloseMarker(idx) {
7521    this.#nestingLevel--;
7522    return this;
7523  }
7524  beginMarkedContent(opIdx) {
7525    return this;
7526  }
7527  endMarkedContent(opIdx) {
7528    return this;
7529  }
7530  pushBaseTransform(ctx) {
7531    this.#dependencyTracker.pushBaseTransform(ctx);
7532    return this;
7533  }
7534  popBaseTransform() {
7535    this.#dependencyTracker.popBaseTransform();
7536    return this;
7537  }
7538  recordSimpleData(name, idx) {
7539    this.#dependencyTracker.recordSimpleData(name, this.#opIdx);
7540    return this;
7541  }
7542  recordIncrementalData(name, idx) {
7543    this.#dependencyTracker.recordIncrementalData(name, this.#opIdx);
7544    return this;
7545  }
7546  resetIncrementalData(name, idx) {
7547    this.#dependencyTracker.resetIncrementalData(name, this.#opIdx);
7548    return this;
7549  }
7550  recordNamedData(name, idx) {
7551    return this;
7552  }
7553  recordSimpleDataFromNamed(name, depName, fallbackIdx) {
7554    this.#dependencyTracker.recordSimpleDataFromNamed(name, depName, this.#opIdx);
7555    return this;
7556  }
7557  recordFutureForcedDependency(name, idx) {
7558    this.#dependencyTracker.recordFutureForcedDependency(name, this.#opIdx);
7559    return this;
7560  }
7561  inheritSimpleDataAsFutureForcedDependencies(names) {
7562    this.#dependencyTracker.inheritSimpleDataAsFutureForcedDependencies(names);
7563    return this;
7564  }
7565  inheritPendingDependenciesAsFutureForcedDependencies() {
7566    this.#dependencyTracker.inheritPendingDependenciesAsFutureForcedDependencies();
7567    return this;
7568  }
7569  resetBBox(idx) {
7570    if (!this.#ignoreBBoxes) {
7571      this.#dependencyTracker.resetBBox(this.#opIdx);
7572    }
7573    return this;
7574  }
7575  recordClipBox(idx, ctx, minX, maxX, minY, maxY) {
7576    if (!this.#ignoreBBoxes) {
7577      this.#dependencyTracker.recordClipBox(this.#opIdx, ctx, minX, maxX, minY, maxY);
7578    }
7579    return this;
7580  }
7581  recordBBox(idx, ctx, minX, maxX, minY, maxY) {
7582    if (!this.#ignoreBBoxes) {
7583      this.#dependencyTracker.recordBBox(this.#opIdx, ctx, minX, maxX, minY, maxY);
7584    }
7585    return this;
7586  }
7587  recordCharacterBBox(idx, ctx, font, scale, x, y, getMeasure) {
7588    if (!this.#ignoreBBoxes) {
7589      this.#dependencyTracker.recordCharacterBBox(this.#opIdx, ctx, font, scale, x, y, getMeasure);
7590    }
7591    return this;
7592  }
7593  recordFullPageBBox(idx) {
7594    if (!this.#ignoreBBoxes) {
7595      this.#dependencyTracker.recordFullPageBBox(this.#opIdx);
7596    }
7597    return this;
7598  }
7599  getSimpleIndex(dependencyName) {
7600    return this.#dependencyTracker.getSimpleIndex(dependencyName);
7601  }
7602  recordDependencies(idx, dependencyNames) {
7603    this.#dependencyTracker.recordDependencies(this.#opIdx, dependencyNames);
7604    return this;
7605  }
7606  recordNamedDependency(idx, name) {
7607    this.#dependencyTracker.recordNamedDependency(this.#opIdx, name);
7608    return this;
7609  }
7610  recordOperation(idx) {
7611    this.#dependencyTracker.recordOperation(this.#opIdx, true);
7612    return this;
7613  }
7614  recordShowTextOperation(idx) {
7615    this.#dependencyTracker.recordShowTextOperation(this.#opIdx, true);
7616    return this;
7617  }
7618  bboxToClipBoxDropOperation(idx) {
7619    if (!this.#ignoreBBoxes) {
7620      this.#dependencyTracker.bboxToClipBoxDropOperation(this.#opIdx, true);
7621    }
7622    return this;
7623  }
7624  take() {
7625    throw new Error("Unreachable");
7626  }
7627  takeDebugMetadata() {
7628    throw new Error("Unreachable");
7629  }
7630}
7631const Dependencies = {
7632  stroke: ["path", "transform", "filter", "strokeColor", "strokeAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "dash"],
7633  fill: ["path", "transform", "filter", "fillColor", "fillAlpha", "globalCompositeOperation", "SMask"],
7634  imageXObject: ["transform", "SMask", "filter", "fillAlpha", "strokeAlpha", "globalCompositeOperation"],
7635  rawFillPath: ["filter", "fillColor", "fillAlpha"],
7636  showText: ["transform", "leading", "charSpacing", "wordSpacing", "hScale", "textRise", "moveText", "textMatrix", "font", "fontObj", "filter", "fillColor", "textRenderingMode", "SMask", "fillAlpha", "strokeAlpha", "globalCompositeOperation", "sameLineText"],
7637  transform: ["transform"],
7638  transformAndFill: ["transform", "fillColor"]
7639};
7640class CanvasImagesTracker {
7641  #canvasWidth;
7642  #canvasHeight;
7643  #capacity = 4;
7644  #count = 0;
7645  #coords = new CanvasImagesTracker.#CoordsArray(this.#capacity * 6);
7646  static #CoordsArray = FeatureTest.isFloat16ArraySupported ? Float16Array : Float32Array;
7647  constructor(canvas) {
7648    this.#canvasWidth = canvas.width;
7649    this.#canvasHeight = canvas.height;
7650  }
7651  record(ctx, width, height, clipBox) {
7652    if (this.#count === this.#capacity) {
7653      this.#capacity *= 2;
7654      const newCoords = new CanvasImagesTracker.#CoordsArray(this.#capacity * 6);
7655      newCoords.set(this.#coords);
7656      this.#coords = newCoords;
7657    }
7658    const transform = getCurrentTransform(ctx);
7659    let coords;
7660    if (clipBox[0] !== Infinity) {
7661      const bbox = BBOX_INIT.slice();
7662      Util.axialAlignedBoundingBox([0, -height, width, 0], transform, bbox);
7663      const finalBBox = Util.intersect(clipBox, bbox);
7664      if (!finalBBox) {
7665        return;
7666      }
7667      const [minX, minY, maxX, maxY] = finalBBox;
7668      if (minX !== bbox[0] || minY !== bbox[1] || maxX !== bbox[2] || maxY !== bbox[3]) {
7669        const rotationAngle = Math.atan2(transform[1], transform[0]);
7670        const sin = Math.abs(Math.sin(rotationAngle));
7671        const cos = Math.abs(Math.cos(rotationAngle));
7672        if (sin < 1e-6 || cos < 1e-6 || Math.abs(sin - cos) < 1e-6) {
7673          coords = [minX, minY, minX, maxY, maxX, minY];
7674        } else {
7675          const finalBBoxWidth = maxX - minX;
7676          const finalBBoxHeight = maxY - minY;
7677          const sin2 = sin * sin;
7678          const cos2 = cos * cos;
7679          const cosSin = cos * sin;
7680          const denom = cos2 - sin2;
7681          const a = (finalBBoxHeight * cos2 - finalBBoxWidth * cosSin) / denom;
7682          const b = (finalBBoxHeight * cosSin - finalBBoxWidth * sin2) / denom;
7683          coords = [minX + b, minY, minX, minY + a, maxX, maxY - a];
7684        }
7685      }
7686    }
7687    if (!coords) {
7688      coords = [0, -height, 0, 0, width, -height];
7689      Util.applyTransform(coords, transform, 0);
7690      Util.applyTransform(coords, transform, 2);
7691      Util.applyTransform(coords, transform, 4);
7692    }
7693    coords[0] /= this.#canvasWidth;
7694    coords[1] /= this.#canvasHeight;
7695    coords[2] /= this.#canvasWidth;
7696    coords[3] /= this.#canvasHeight;
7697    coords[4] /= this.#canvasWidth;
7698    coords[5] /= this.#canvasHeight;
7699    this.#coords.set(coords, this.#count * 6);
7700    this.#count++;
7701  }
7702  take() {
7703    return this.#coords.subarray(0, this.#count * 6);
7704  }
7705}
7706
7707;// ./src/
7707display/font_loader.js
vendor: 9,963 bytes, lines 7707-7966
7707
7708
7709
7710class FontLoader {
7711  #systemFonts = new Set();
7712  #styleSheet = null;
7713  constructor({
7714    ownerDocument = globalThis.document,
7715    styleElement = null
7716  }) {
7717    this._document = ownerDocument;
7718    this.nativeFontFaces = new Set();
7719    this.styleElement = null;
7720    this.loadingRequests = [];
7721    this.loadTestFontId = 0;
7722  }
7723  addNativeFontFace(nativeFontFace) {
7724    this.nativeFontFaces.add(nativeFontFace);
7725    this._document.fonts.add(nativeFontFace);
7726  }
7727  removeNativeFontFace(nativeFontFace) {
7728    this.nativeFontFaces.delete(nativeFontFace);
7729    this._document.fonts.delete(nativeFontFace);
7730  }
7731  insertRule(rule) {
7732    const styleSheet = this.#getStyleSheet();
7733    styleSheet.insertRule(rule, styleSheet.cssRules.length);
7734  }
7735  #getStyleSheet() {
7736    if (this.#styleSheet) {
7737      return this.#styleSheet;
7738    }
7739    const StyleSheet = this._document.defaultView?.CSSStyleSheet || globalThis.CSSStyleSheet;
7740    if (!this.styleElement && StyleSheet) {
7741      const {
7742        adoptedStyleSheets
7743      } = this._document;
7744      if (adoptedStyleSheets) {
7745        const styleSheet = new StyleSheet();
7746        adoptedStyleSheets.push(styleSheet);
7747        return this.#styleSheet = styleSheet;
7748      }
7749    }
7750    if (!this.styleElement) {
7751      this.styleElement = this._document.createElement("style");
7752      this._document.documentElement.getElementsByTagName("head")[0].append(this.styleElement);
7753    }
7754    return this.#styleSheet = this.styleElement.sheet;
7755  }
7756  clear() {
7757    for (const nativeFontFace of this.nativeFontFaces) {
7758      this._document.fonts.delete(nativeFontFace);
7759    }
7760    this.nativeFontFaces.clear();
7761    this.#systemFonts.clear();
7762    if (this.#styleSheet) {
7763      const {
7764        adoptedStyleSheets
7765      } = this._document;
7766      if (adoptedStyleSheets?.includes(this.#styleSheet)) {
7767        this._document.adoptedStyleSheets = adoptedStyleSheets.filter(styleSheet => styleSheet !== this.#styleSheet);
7768      }
7769      this.#styleSheet = null;
7770    }
7771    if (this.styleElement) {
7772      this.styleElement.remove();
7773      this.styleElement = null;
7774    }
7775  }
7776  async loadSystemFont({
7777    systemFontInfo: info,
7778    disableFontFace,
7779    _inspectFont
7780  }) {
7781    if (!info || this.#systemFonts.has(info.loadedName)) {
7782      return;
7783    }
7784    assert(!disableFontFace, "loadSystemFont shouldn't be called when `disableFontFace` is set.");
7785    if (this.isFontLoadingAPISupported) {
7786      const {
7787        loadedName,
7788        src,
7789        style
7790      } = info;
7791      const fontFace = new FontFace(loadedName, src, style);
7792      this.addNativeFontFace(fontFace);
7793      try {
7794        await fontFace.load();
7795        this.#systemFonts.add(loadedName);
7796        _inspectFont?.(info);
7797      } catch {
7798        warn(`Cannot load system font: ${info.baseFontName}, installing it could help to improve PDF rendering.`);
7799        this.removeNativeFontFace(fontFace);
7800      }
7801      return;
7802    }
7803    unreachable("Not implemented: loadSystemFont without the Font Loading API.");
7804  }
7805  async bind(font) {
7806    if (font.attached || font.missingFile && !font.systemFontInfo) {
7807      return;
7808    }
7809    font.attached = true;
7810    if (font.systemFontInfo) {
7811      await this.loadSystemFont(font);
7812      return;
7813    }
7814    if (this.isFontLoadingAPISupported) {
7815      const nativeFontFace = font.createNativeFontFace();
7816      if (nativeFontFace) {
7817        this.addNativeFontFace(nativeFontFace);
7818        try {
7819          await nativeFontFace.loaded;
7820        } catch (ex) {
7821          warn(`Failed to load font '${nativeFontFace.family}': '${ex}'.`);
7822          font.disableFontFace = true;
7823          throw ex;
7824        }
7825      }
7826      return;
7827    }
7828    const rule = font.createFontFaceRule();
7829    if (rule) {
7830      this.insertRule(rule);
7831      if (this.isSyncFontLoadingSupported) {
7832        return;
7833      }
7834      await new Promise(resolve => {
7835        const request = this._queueLoadingCallback(resolve);
7836        this._prepareFontLoadEvent(font, request);
7837      });
7838    }
7839  }
7840  get isFontLoadingAPISupported() {
7841    const hasFonts = !!this._document?.fonts;
7842    return shadow(this, "isFontLoadingAPISupported", hasFonts);
7843  }
7844  get isSyncFontLoadingSupported() {
7845    return shadow(this, "isSyncFontLoadingSupported", isNodeJS || FeatureTest.platform.isFirefox);
7846  }
7847  _queueLoadingCallback(callback) {
7848    function completeRequest() {
7849      assert(!request.done, "completeRequest() cannot be called twice.");
7850      request.done = true;
7851      while (loadingRequests.length > 0 && loadingRequests[0].done) {
7852        const otherRequest = loadingRequests.shift();
7853        setTimeout(otherRequest.callback, 0);
7854      }
7855    }
7856    const {
7857      loadingRequests
7858    } = this;
7859    const request = {
7860      done: false,
7861      complete: completeRequest,
7862      callback
7863    };
7864    loadingRequests.push(request);
7865    return request;
7866  }
7867  get _loadTestFont() {
7868    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==");
7869    return shadow(this, "_loadTestFont", testFont);
7870  }
7871  _prepareFontLoadEvent(font, request) {
7872    function int32(data, offset) {
7873      return data.charCodeAt(offset) << 24 | data.charCodeAt(offset + 1) << 16 | data.charCodeAt(offset + 2) << 8 | data.charCodeAt(offset + 3) & 0xff;
7874    }
7875    function string32(value) {
7876      return String.fromCharCode(value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff);
7877    }
7878    function spliceString(s, offset, remove, insert) {
7879      const chunk1 = s.substring(0, offset);
7880      const chunk2 = s.substring(offset + remove);
7881      return chunk1 + insert + chunk2;
7882    }
7883    let i, ii;
7884    const canvas = this._document.createElement("canvas");
7885    canvas.width = 1;
7886    canvas.height = 1;
7887    const ctx = canvas.getContext("2d");
7888    let called = 0;
7889    function isFontReady(name, callback) {
7890      if (++called > 30) {
7891        warn("Load test font never loaded.");
7892        callback();
7893        return;
7894      }
7895      ctx.font = "30px " + name;
7896      ctx.fillText(".", 0, 20);
7897      const imageData = ctx.getImageData(0, 0, 1, 1);
7898      if (imageData.data[3] > 0) {
7899        callback();
7900        return;
7901      }
7902      setTimeout(isFontReady.bind(null, name, callback));
7903    }
7904    const loadTestFontId = `lt${Date.now()}${this.loadTestFontId++}`;
7905    let data = this._loadTestFont;
7906    const COMMENT_OFFSET = 976;
7907    data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length, loadTestFontId);
7908    const CFF_CHECKSUM_OFFSET = 16;
7909    const XXXX_VALUE = 0x58585858;
7910    let checksum = int32(data, CFF_CHECKSUM_OFFSET);
7911    for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) {
7912      checksum = checksum - XXXX_VALUE + int32(loadTestFontId, i) | 0;
7913    }
7914    if (i < loadTestFontId.length) {
7915      checksum = checksum - XXXX_VALUE + int32(loadTestFontId + "XXX", i) | 0;
7916    }
7917    data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum));
7918    const url = `url(data:font/opentype;base64,${btoa(data)});`;
7919    const rule = `@font-face {font-family:"${loadTestFontId}";src:${url}}`;
7920    this.insertRule(rule);
7921    const div = this._document.createElement("div");
7922    div.style.visibility = "hidden";
7923    div.style.width = div.style.height = "10px";
7924    div.style.position = "absolute";
7925    div.style.top = div.style.left = "0px";
7926    for (const name of [font.loadedName, loadTestFontId]) {
7927      const span = this._document.createElement("span");
7928      span.textContent = "Hi";
7929      span.style.fontFamily = name;
7930      div.append(span);
7931    }
7932    this._document.body.append(div);
7933    isFontReady(loadTestFontId, () => {
7934      div.remove();
7935      request.complete();
7936    });
7937  }
7938}
7939class FontFaceObject {
7940  compiledGlyphs = Object.create(null);
7941  #fontData;
7942  constructor(translatedData, inspectFont = null, charProcOperatorList, extra) {
7943    this.#fontData = translatedData;
7944    this._inspectFont = inspectFont;
7945    if (charProcOperatorList) {
7946      this.charProcOperatorList = charProcOperatorList;
7947    }
7948    if (extra) {
7949      Object.assign(this, extra);
7950    }
7951  }
7952  createNativeFontFace() {
7953    if (!this.data || this.disableFontFace) {
7954      return null;
7955    }
7956    let nativeFontFace;
7957    if (!this.cssFontInfo) {
7958      nativeFontFace = new FontFace(this.loadedName, this.data, {});
7959    } else {
7960      const css = {
7961        weight: this.cssFontInfo.fontWeight
7962      };
7963      if (this.cssFontInfo.italicAngle) {
7964        css.style = `oblique ${this.cssFontInfo.italicAngle}deg`;
7965      }
7966      nativeFontFace = new FontFace(
vendor: 8,406 bytes, lines 7966-8281
7966this.cssFontInfo.fontFamily, this.data, css);
7967    }
7968    this._inspectFont?.(this);
7969    return nativeFontFace;
7970  }
7971  createFontFaceRule() {
7972    if (!this.data || this.disableFontFace) {
7973      return null;
7974    }
7975    const url = `url(data:${this.mimetype};base64,${this.data.toBase64()});`;
7976    let rule;
7977    if (!this.cssFontInfo) {
7978      rule = `@font-face {font-family:"${this.loadedName}";src:${url}}`;
7979    } else {
7980      let css = `font-weight: ${this.cssFontInfo.fontWeight};`;
7981      if (this.cssFontInfo.italicAngle) {
7982        css += `font-style: oblique ${this.cssFontInfo.italicAngle}deg;`;
7983      }
7984      rule = `@font-face {font-family:"${this.cssFontInfo.fontFamily}";${css}src:${url}}`;
7985    }
7986    this._inspectFont?.(this, url);
7987    return rule;
7988  }
7989  getPathGenerator(objs, character) {
7990    if (this.compiledGlyphs[character] !== undefined) {
7991      return this.compiledGlyphs[character];
7992    }
7993    const objId = this.loadedName + "_path_" + character;
7994    let cmds;
7995    try {
7996      cmds = objs.get(objId);
7997    } catch (ex) {
7998      warn(`getPathGenerator - ignoring character: "${ex}".`);
7999    }
8000    const path = makePathFromDrawOPS(cmds?.path);
8001    if (!this.fontExtraProperties) {
8002      objs.delete(objId);
8003    }
8004    return this.compiledGlyphs[character] = path;
8005  }
8006  get black() {
8007    return this.#fontData.black;
8008  }
8009  get bold() {
8010    return this.#fontData.bold;
8011  }
8012  get disableFontFace() {
8013    return this.#fontData.disableFontFace;
8014  }
8015  set disableFontFace(value) {
8016    shadow(this, "disableFontFace", !!value);
8017  }
8018  get fontExtraProperties() {
8019    return this.#fontData.fontExtraProperties;
8020  }
8021  get isInvalidPDFjsFont() {
8022    return this.#fontData.isInvalidPDFjsFont;
8023  }
8024  get isType3Font() {
8025    return this.#fontData.isType3Font;
8026  }
8027  get italic() {
8028    return this.#fontData.italic;
8029  }
8030  get missingFile() {
8031    return this.#fontData.missingFile;
8032  }
8033  get remeasure() {
8034    return this.#fontData.remeasure;
8035  }
8036  get vertical() {
8037    return this.#fontData.vertical;
8038  }
8039  get ascent() {
8040    return this.#fontData.ascent;
8041  }
8042  get defaultWidth() {
8043    return this.#fontData.defaultWidth;
8044  }
8045  get descent() {
8046    return this.#fontData.descent;
8047  }
8048  get bbox() {
8049    return this.#fontData.bbox;
8050  }
8051  get fontMatrix() {
8052    return this.#fontData.fontMatrix;
8053  }
8054  get fallbackName() {
8055    return this.#fontData.fallbackName;
8056  }
8057  get loadedName() {
8058    return this.#fontData.loadedName;
8059  }
8060  get mimetype() {
8061    return this.#fontData.mimetype;
8062  }
8063  get name() {
8064    return this.#fontData.name;
8065  }
8066  get data() {
8067    return this.#fontData.data;
8068  }
8069  clearData() {
8070    this.#fontData.clearData();
8071  }
8072  get cssFontInfo() {
8073    return this.#fontData.cssFontInfo;
8074  }
8075  get systemFontInfo() {
8076    return this.#fontData.systemFontInfo;
8077  }
8078  get defaultVMetrics() {
8079    return this.#fontData.defaultVMetrics;
8080  }
8081}
8082
8083;// ./src/shared/obj_bin_transform_utils.js
8084class CSS_FONT_INFO {
8085  static strings = ["fontFamily", "fontWeight", "italicAngle"];
8086}
8087class SYSTEM_FONT_INFO {
8088  static strings = ["css", "loadedName", "baseFontName", "src"];
8089}
8090class FONT_INFO {
8091  static bools = ["black", "bold", "disableFontFace", "fontExtraProperties", "isInvalidPDFjsFont", "isType3Font", "italic", "missingFile", "remeasure", "vertical"];
8092  static numbers = ["ascent", "defaultWidth", "descent"];
8093  static strings = ["fallbackName", "loadedName", "mimetype", "name"];
8094  static OFFSET_NUMBERS = Math.ceil(this.bools.length * 2 / 8);
8095  static OFFSET_BBOX = this.OFFSET_NUMBERS + this.numbers.length * 8;
8096  static OFFSET_FONT_MATRIX = this.OFFSET_BBOX + 1 + 2 * 4;
8097  static OFFSET_DEFAULT_VMETRICS = this.OFFSET_FONT_MATRIX + 1 + 8 * 6;
8098  static OFFSET_STRINGS = this.OFFSET_DEFAULT_VMETRICS + 1 + 2 * 3;
8099}
8100class PATTERN_INFO {
8101  static KIND = 0;
8102  static HAS_BBOX = 1;
8103  static HAS_BACKGROUND = 2;
8104  static SHADING_TYPE = 3;
8105  static N_COORD = 4;
8106  static N_COLOR = 8;
8107  static N_STOP = 12;
8108  static N_FIGURES = 16;
8109}
8110
8111;// ./src/display/obj_bin_transform_display.js
8112
8113
8114class CssFontInfo {
8115  #buffer;
8116  #decoder = new TextDecoder();
8117  #view;
8118  constructor(buffer) {
8119    this.#buffer = buffer;
8120    this.#view = new DataView(buffer);
8121  }
8122  #readString(index) {
8123    assert(index < CSS_FONT_INFO.strings.length, "Invalid string index");
8124    let offset = 0;
8125    for (let i = 0; i < index; i++) {
8126      offset += this.#view.getUint32(offset) + 4;
8127    }
8128    const length = this.#view.getUint32(offset);
8129    return this.#decoder.decode(new Uint8Array(this.#buffer, offset + 4, length));
8130  }
8131  get fontFamily() {
8132    return this.#readString(0);
8133  }
8134  get fontWeight() {
8135    return this.#readString(1);
8136  }
8137  get italicAngle() {
8138    return this.#readString(2);
8139  }
8140}
8141class SystemFontInfo {
8142  #buffer;
8143  #decoder = new TextDecoder();
8144  #view;
8145  constructor(buffer) {
8146    this.#buffer = buffer;
8147    this.#view = new DataView(buffer);
8148  }
8149  get guessFallback() {
8150    return this.#view.getUint8(0) !== 0;
8151  }
8152  #readString(index) {
8153    assert(index < SYSTEM_FONT_INFO.strings.length, "Invalid string index");
8154    let offset = 5;
8155    for (let i = 0; i < index; i++) {
8156      offset += this.#view.getUint32(offset) + 4;
8157    }
8158    const length = this.#view.getUint32(offset);
8159    return this.#decoder.decode(new Uint8Array(this.#buffer, offset + 4, length));
8160  }
8161  get css() {
8162    return this.#readString(0);
8163  }
8164  get loadedName() {
8165    return this.#readString(1);
8166  }
8167  get baseFontName() {
8168    return this.#readString(2);
8169  }
8170  get src() {
8171    return this.#readString(3);
8172  }
8173  get style() {
8174    let offset = 1;
8175    offset += 4 + this.#view.getUint32(offset);
8176    const styleLength = this.#view.getUint32(offset);
8177    const style = this.#decoder.decode(new Uint8Array(this.#buffer, offset + 4, styleLength));
8178    offset += 4 + styleLength;
8179    const weightLength = this.#view.getUint32(offset);
8180    const weight = this.#decoder.decode(new Uint8Array(this.#buffer, offset + 4, weightLength));
8181    return {
8182      style,
8183      weight
8184    };
8185  }
8186}
8187class FontInfo {
8188  #buffer;
8189  #decoder = new TextDecoder();
8190  #view;
8191  constructor({
8192    buffer,
8193    extra
8194  }) {
8195    this.#buffer = buffer;
8196    this.#view = new DataView(buffer);
8197    if (extra) {
8198      Object.assign(this, extra);
8199    }
8200  }
8201  #readBoolean(index) {
8202    assert(index < FONT_INFO.bools.length, "Invalid boolean index");
8203    const byteOffset = Math.floor(index / 4);
8204    const bitOffset = index * 2 % 8;
8205    const value = this.#view.getUint8(byteOffset) >> bitOffset & 0x03;
8206    return value === 0x00 ? undefined : value === 0x02;
8207  }
8208  get black() {
8209    return this.#readBoolean(0);
8210  }
8211  get bold() {
8212    return this.#readBoolean(1);
8213  }
8214  get disableFontFace() {
8215    return this.#readBoolean(2);
8216  }
8217  get fontExtraProperties() {
8218    return this.#readBoolean(3);
8219  }
8220  get isInvalidPDFjsFont() {
8221    return this.#readBoolean(4);
8222  }
8223  get isType3Font() {
8224    return this.#readBoolean(5);
8225  }
8226  get italic() {
8227    return this.#readBoolean(6);
8228  }
8229  get missingFile() {
8230    return this.#readBoolean(7);
8231  }
8232  get remeasure() {
8233    return this.#readBoolean(8);
8234  }
8235  get vertical() {
8236    return this.#readBoolean(9);
8237  }
8238  #readNumber(index) {
8239    assert(index < FONT_INFO.numbers.length, "Invalid number index");
8240    return this.#view.getFloat64(FONT_INFO.OFFSET_NUMBERS + index * 8);
8241  }
8242  get ascent() {
8243    return this.#readNumber(0);
8244  }
8245  get defaultWidth() {
8246    return this.#readNumber(1);
8247  }
8248  get descent() {
8249    return this.#readNumber(2);
8250  }
8251  #readArray(offset, arrLen, lookupName, increment) {
8252    const len = this.#view.getUint8(offset);
8253    if (len === 0) {
8254      return undefined;
8255    }
8256    assert(len === arrLen, "Invalid array length.");
8257    offset += 1;
8258    const arr = new Array(len);
8259    for (let i = 0; i < len; i++) {
8260      arr[i] = this.#view[lookupName](offset, true);
8261      offset += increment;
8262    }
8263    return arr;
8264  }
8265  get bbox() {
8266    return this.#readArray(FONT_INFO.OFFSET_BBOX, 4, "getInt16", 2);
8267  }
8268  get fontMatrix() {
8269    return this.#readArray(FONT_INFO.OFFSET_FONT_MATRIX, 6, "getFloat64", 8);
8270  }
8271  get defaultVMetrics() {
8272    return this.#readArray(FONT_INFO.OFFSET_DEFAULT_VMETRICS, 3, "getInt16", 2);
8273  }
8274  #readString(index) {
8275    assert(index < FONT_INFO.strings.length, "Invalid string index");
8276    let offset = FONT_INFO.OFFSET_STRINGS + 4;
8277    for (let i = 0; i < index; i++) {
8278      offset += this.#view.getUint32(offset) + 4;
8279    }
8280    const length = this.#view.getUint32(offset);
8281    return this.#
vendor: 26,889 bytes, lines 8281-9203
8281decoder.decode(new Uint8Array(this.#buffer, offset + 4, length));
8282  }
8283  get fallbackName() {
8284    return this.#readString(0);
8285  }
8286  get loadedName() {
8287    return this.#readString(1);
8288  }
8289  get mimetype() {
8290    return this.#readString(2);
8291  }
8292  get name() {
8293    return this.#readString(3);
8294  }
8295  #getDataOffsets() {
8296    let offset = FONT_INFO.OFFSET_STRINGS;
8297    const stringsLength = this.#view.getUint32(offset);
8298    offset += 4 + stringsLength;
8299    const systemFontInfoLength = this.#view.getUint32(offset);
8300    offset += 4 + systemFontInfoLength;
8301    const cssFontInfoLength = this.#view.getUint32(offset);
8302    offset += 4 + cssFontInfoLength;
8303    const length = this.#view.getUint32(offset);
8304    return {
8305      offset,
8306      length
8307    };
8308  }
8309  get data() {
8310    const {
8311      offset,
8312      length
8313    } = this.#getDataOffsets();
8314    return length === 0 ? undefined : new Uint8Array(this.#buffer, offset + 4, length);
8315  }
8316  clearData() {
8317    const {
8318      offset,
8319      length
8320    } = this.#getDataOffsets();
8321    if (length === 0) {
8322      return;
8323    }
8324    this.#view.setUint32(offset, 0);
8325    this.#buffer = new Uint8Array(this.#buffer, 0, offset + 4).slice().buffer;
8326    this.#view = new DataView(this.#buffer);
8327  }
8328  get cssFontInfo() {
8329    let offset = FONT_INFO.OFFSET_STRINGS;
8330    const stringsLength = this.#view.getUint32(offset);
8331    offset += 4 + stringsLength;
8332    const systemFontInfoLength = this.#view.getUint32(offset);
8333    offset += 4 + systemFontInfoLength;
8334    const cssFontInfoLength = this.#view.getUint32(offset);
8335    if (cssFontInfoLength === 0) {
8336      return null;
8337    }
8338    const cssFontInfoData = new Uint8Array(cssFontInfoLength);
8339    cssFontInfoData.set(new Uint8Array(this.#buffer, offset + 4, cssFontInfoLength));
8340    return new CssFontInfo(cssFontInfoData.buffer);
8341  }
8342  get systemFontInfo() {
8343    let offset = FONT_INFO.OFFSET_STRINGS;
8344    const stringsLength = this.#view.getUint32(offset);
8345    offset += 4 + stringsLength;
8346    const systemFontInfoLength = this.#view.getUint32(offset);
8347    if (systemFontInfoLength === 0) {
8348      return null;
8349    }
8350    const systemFontInfoData = new Uint8Array(systemFontInfoLength);
8351    systemFontInfoData.set(new Uint8Array(this.#buffer, offset + 4, systemFontInfoLength));
8352    return new SystemFontInfo(systemFontInfoData.buffer);
8353  }
8354}
8355class PatternInfo {
8356  constructor(buffer) {
8357    this.buffer = buffer;
8358    this.view = new DataView(buffer);
8359    this.data = new Uint8Array(buffer);
8360  }
8361  getIR() {
8362    const dataView = this.view;
8363    const kind = this.data[PATTERN_INFO.KIND];
8364    const hasBBox = !!this.data[PATTERN_INFO.HAS_BBOX];
8365    const hasBackground = !!this.data[PATTERN_INFO.HAS_BACKGROUND];
8366    const nCoord = dataView.getUint32(PATTERN_INFO.N_COORD, true);
8367    const nColor = dataView.getUint32(PATTERN_INFO.N_COLOR, true);
8368    const nStop = dataView.getUint32(PATTERN_INFO.N_STOP, true);
8369    let offset = 20;
8370    const coords = new Float32Array(this.buffer, offset, nCoord * 2);
8371    offset += nCoord * 8;
8372    const colors = new Uint8Array(this.buffer, offset, nColor * 4);
8373    offset += nColor * 4;
8374    const stops = [];
8375    for (let i = 0; i < nStop; ++i) {
8376      const p = dataView.getFloat32(offset, true);
8377      offset += 4;
8378      const rgb = dataView.getUint32(offset, true);
8379      offset += 4;
8380      stops.push([p, `#${rgb.toString(16).padStart(6, "0")}`]);
8381    }
8382    let bbox = null;
8383    if (hasBBox) {
8384      bbox = [];
8385      for (let i = 0; i < 4; ++i) {
8386        bbox.push(dataView.getFloat32(offset, true));
8387        offset += 4;
8388      }
8389    }
8390    let background = null;
8391    if (hasBackground) {
8392      background = new Uint8Array(this.buffer, offset, 3);
8393      offset += 3;
8394    }
8395    if (kind === 1) {
8396      return ["RadialAxial", "axial", bbox, stops, Array.from(coords.slice(0, 2)), Array.from(coords.slice(2, 4)), null, null];
8397    }
8398    if (kind === 2) {
8399      return ["RadialAxial", "radial", bbox, stops, [coords[0], coords[1]], [coords[3], coords[4]], coords[2], coords[5]];
8400    }
8401    if (kind === 3) {
8402      const shadingType = this.data[PATTERN_INFO.SHADING_TYPE];
8403      let bounds = null;
8404      if (coords.length > 0) {
8405        bounds = BBOX_INIT.slice();
8406        for (let i = 0, ii = coords.length; i < ii; i += 2) {
8407          Util.pointBoundingBox(coords[i], coords[i + 1], bounds);
8408        }
8409      }
8410      return ["Mesh", shadingType, coords, colors, nCoord, bounds, bbox, background];
8411    }
8412    throw new Error(`Unsupported pattern kind: ${kind}`);
8413  }
8414}
8415class FontPathInfo {
8416  #buffer;
8417  constructor(buffer) {
8418    this.#buffer = buffer;
8419  }
8420  get path() {
8421    if (FeatureTest.isFloat16ArraySupported) {
8422      return new Float16Array(this.#buffer);
8423    }
8424    return new Float32Array(this.#buffer);
8425  }
8426}
8427
8428;// ./src/display/api_utils.js
8429
8430function getUrlProp(val) {
8431  if (val instanceof URL) {
8432    return val;
8433  }
8434  if (typeof val === "string") {
8435    if (isNodeJS) {
8436      if (/^[a-z][a-z0-9\-+.]+:/i.test(val)) {
8437        return new URL(val);
8438      }
8439      const url = process.getBuiltinModule("url");
8440      return new URL(url.pathToFileURL(val));
8441    }
8442    const url = URL.parse(val, window.location);
8443    if (url) {
8444      return url;
8445    }
8446  }
8447  throw new Error("Invalid PDF url data: " + "either string or URL-object is expected in the url property.");
8448}
8449function getDataProp(val) {
8450  if (isNodeJS && typeof Buffer !== "undefined" && val instanceof Buffer) {
8451    throw new Error("Please provide binary data as `Uint8Array`, rather than `Buffer`.");
8452  }
8453  if (val instanceof Uint8Array && val.byteLength === val.buffer.byteLength) {
8454    return val;
8455  }
8456  if (typeof val === "string") {
8457    return stringToBytes(val);
8458  }
8459  if (val instanceof ArrayBuffer || ArrayBuffer.isView(val) || typeof val === "object" && !isNaN(val?.length)) {
8460    return new Uint8Array(val);
8461  }
8462  throw new Error("Invalid PDF binary data: either TypedArray, " + "string, or array-like object is expected in the data property.");
8463}
8464function getFactoryUrlProp(val) {
8465  if (typeof val !== "string") {
8466    return null;
8467  }
8468  if (val.endsWith("/")) {
8469    return val;
8470  }
8471  throw new Error(`Invalid factory url: "${val}" must include trailing slash.`);
8472}
8473const isRefProxy = v => typeof v === "object" && Number.isInteger(v?.num) && v.num >= 0 && Number.isInteger(v?.gen) && v.gen >= 0;
8474const isNameProxy = v => typeof v === "object" && typeof v?.name === "string";
8475const isValidExplicitDest = _isValidExplicitDest.bind(null, isRefProxy, isNameProxy);
8476class LoopbackPort {
8477  #listeners = new Map();
8478  #deferred = Promise.resolve();
8479  postMessage(obj, transfer) {
8480    const event = {
8481      data: structuredClone(obj, transfer ? {
8482        transfer
8483      } : null)
8484    };
8485    this.#deferred.then(() => {
8486      for (const [listener] of this.#listeners) {
8487        listener.call(this, event);
8488      }
8489    });
8490  }
8491  addEventListener(name, listener, options = null) {
8492    let rmAbort = null;
8493    if (options?.signal instanceof AbortSignal) {
8494      const {
8495        signal
8496      } = options;
8497      if (signal.aborted) {
8498        warn("LoopbackPort - cannot use an `aborted` signal.");
8499        return;
8500      }
8501      const onAbort = () => this.removeEventListener(name, listener);
8502      rmAbort = () => signal.removeEventListener("abort", onAbort);
8503      signal.addEventListener("abort", onAbort);
8504    }
8505    this.#listeners.set(listener, rmAbort);
8506  }
8507  removeEventListener(name, listener) {
8508    const rmAbort = this.#listeners.get(listener);
8509    rmAbort?.();
8510    this.#listeners.delete(listener);
8511  }
8512  terminate() {
8513    for (const [, rmAbort] of this.#listeners) {
8514      rmAbort?.();
8515    }
8516    this.#listeners.clear();
8517  }
8518}
8519
8520;// ./src/shared/message_handler.js
8521
8522const CallbackKind = {
8523  DATA: 1,
8524  ERROR: 2
8525};
8526const StreamKind = {
8527  CANCEL: 1,
8528  CANCEL_COMPLETE: 2,
8529  CLOSE: 3,
8530  ENQUEUE: 4,
8531  ERROR: 5,
8532  PULL: 6,
8533  PULL_COMPLETE: 7,
8534  START_COMPLETE: 8
8535};
8536function onFn() {}
8537function wrapReason(ex) {
8538  if (ex instanceof AbortException || ex instanceof InvalidPDFException || ex instanceof PasswordException || ex instanceof ResponseException || ex instanceof UnknownErrorException) {
8539    return ex;
8540  }
8541  if (!(ex instanceof Error || typeof ex === "object" && ex !== null)) {
8542    unreachable('wrapReason: Expected "reason" to be a (possibly cloned) Error.');
8543  }
8544  switch (ex.name) {
8545    case "AbortException":
8546      return new AbortException(ex.message);
8547    case "InvalidPDFException":
8548      return new InvalidPDFException(ex.message);
8549    case "PasswordException":
8550      return new PasswordException(ex.message, ex.code);
8551    case "ResponseException":
8552      return new ResponseException(ex.message, ex.status, ex.missing);
8553    case "UnknownErrorException":
8554      return new UnknownErrorException(ex.message, ex.details);
8555  }
8556  return new UnknownErrorException(ex.message, ex.toString());
8557}
8558class MessageHandler {
8559  #messageAC = new AbortController();
8560  constructor(sourceName, targetName, comObj) {
8561    this.sourceName = sourceName;
8562    this.targetName = targetName;
8563    this.comObj = comObj;
8564    this.callbackId = 1;
8565    this.streamId = 1;
8566    this.streamSinks = Object.create(null);
8567    this.streamControllers = Object.create(null);
8568    this.callbackCapabilities = Object.create(null);
8569    this.actionHandler = Object.create(null);
8570    comObj.addEventListener("message", this.#onMessage.bind(this), {
8571      signal: this.#messageAC.signal
8572    });
8573  }
8574  #onMessage({
8575    data
8576  }) {
8577    if (data.targetName !== this.sourceName) {
8578      return;
8579    }
8580    if (data.stream) {
8581      this.#processStreamMessage(data);
8582      return;
8583    }
8584    if (data.callback) {
8585      const callbackId = data.callbackId;
8586      const capability = this.callbackCapabilities[callbackId];
8587      if (!capability) {
8588        throw new Error(`Cannot resolve callback ${callbackId}`);
8589      }
8590      delete this.callbackCapabilities[callbackId];
8591      if (data.callback === CallbackKind.DATA) {
8592        capability.resolve(data.data);
8593      } else if (data.callback === CallbackKind.ERROR) {
8594        capability.reject(wrapReason(data.reason));
8595      } else {
8596        throw new Error("Unexpected callback case");
8597      }
8598      return;
8599    }
8600    const action = this.actionHandler[data.action];
8601    if (!action) {
8602      throw new Error(`Unknown action from worker: ${data.action}`);
8603    }
8604    if (data.callbackId) {
8605      const sourceName = this.sourceName,
8606        targetName = data.sourceName,
8607        comObj = this.comObj;
8608      Promise.try(action, data.data).then(function (result) {
8609        comObj.postMessage({
8610          sourceName,
8611          targetName,
8612          callback: CallbackKind.DATA,
8613          callbackId: data.callbackId,
8614          data: result
8615        });
8616      }, function (reason) {
8617        comObj.postMessage({
8618          sourceName,
8619          targetName,
8620          callback: CallbackKind.ERROR,
8621          callbackId: data.callbackId,
8622          reason: wrapReason(reason)
8623        });
8624      });
8625      return;
8626    }
8627    if (data.streamId) {
8628      this.#createStreamSink(data);
8629      return;
8630    }
8631    action(data.data);
8632  }
8633  on(actionName, handler) {
8634    const ah = this.actionHandler;
8635    if (ah[actionName]) {
8636      throw new Error(`There is already an actionName called "${actionName}"`);
8637    }
8638    ah[actionName] = handler;
8639  }
8640  send(actionName, data, transfers) {
8641    this.comObj.postMessage({
8642      sourceName: this.sourceName,
8643      targetName: this.targetName,
8644      action: actionName,
8645      data
8646    }, transfers);
8647  }
8648  sendWithPromise(actionName, data, transfers) {
8649    const callbackId = this.callbackId++;
8650    const capability = Promise.withResolvers();
8651    this.callbackCapabilities[callbackId] = capability;
8652    try {
8653      this.comObj.postMessage({
8654        sourceName: this.sourceName,
8655        targetName: this.targetName,
8656        action: actionName,
8657        callbackId,
8658        data
8659      }, transfers);
8660    } catch (ex) {
8661      capability.reject(ex);
8662    }
8663    return capability.promise;
8664  }
8665  sendWithStream(actionName, data, queueingStrategy, transfers) {
8666    const streamId = this.streamId++,
8667      sourceName = this.sourceName,
8668      targetName = this.targetName,
8669      comObj = this.comObj;
8670    return new ReadableStream({
8671      start: controller => {
8672        const startCapability = Promise.withResolvers();
8673        this.streamControllers[streamId] = {
8674          controller,
8675          startCall: startCapability,
8676          pullCall: null,
8677          cancelCall: null,
8678          isClosed: false
8679        };
8680        comObj.postMessage({
8681          sourceName,
8682          targetName,
8683          action: actionName,
8684          streamId,
8685          data,
8686          desiredSize: controller.desiredSize
8687        }, transfers);
8688        return startCapability.promise;
8689      },
8690      pull: controller => {
8691        const pullCapability = Promise.withResolvers();
8692        this.streamControllers[streamId].pullCall = pullCapability;
8693        comObj.postMessage({
8694          sourceName,
8695          targetName,
8696          stream: StreamKind.PULL,
8697          streamId,
8698          desiredSize: controller.desiredSize
8699        });
8700        return pullCapability.promise;
8701      },
8702      cancel: reason => {
8703        assert(reason instanceof Error, "cancel must have a valid reason");
8704        const cancelCapability = Promise.withResolvers();
8705        this.streamControllers[streamId].cancelCall = cancelCapability;
8706        this.streamControllers[streamId].isClosed = true;
8707        comObj.postMessage({
8708          sourceName,
8709          targetName,
8710          stream: StreamKind.CANCEL,
8711          streamId,
8712          reason: wrapReason(reason)
8713        });
8714        return cancelCapability.promise;
8715      }
8716    }, queueingStrategy);
8717  }
8718  #createStreamSink(data) {
8719    const streamId = data.streamId,
8720      sourceName = this.sourceName,
8721      targetName = data.sourceName,
8722      comObj = this.comObj;
8723    const self = this,
8724      action = this.actionHandler[data.action];
8725    const streamSink = {
8726      enqueue(chunk, size = 1, transfers) {
8727        if (this.isCancelled) {
8728          return;
8729        }
8730        const lastDesiredSize = this.desiredSize;
8731        this.desiredSize -= size;
8732        if (lastDesiredSize > 0 && this.desiredSize <= 0) {
8733          this.sinkCapability = Promise.withResolvers();
8734          this.ready = this.sinkCapability.promise;
8735        }
8736        comObj.postMessage({
8737          sourceName,
8738          targetName,
8739          stream: StreamKind.ENQUEUE,
8740          streamId,
8741          chunk
8742        }, transfers);
8743      },
8744      close() {
8745        if (this.isCancelled) {
8746          return;
8747        }
8748        this.isCancelled = true;
8749        comObj.postMessage({
8750          sourceName,
8751          targetName,
8752          stream: StreamKind.CLOSE,
8753          streamId
8754        });
8755        delete self.streamSinks[streamId];
8756      },
8757      error(reason) {
8758        assert(reason instanceof Error, "error must have a valid reason");
8759        if (this.isCancelled) {
8760          return;
8761        }
8762        this.isCancelled = true;
8763        comObj.postMessage({
8764          sourceName,
8765          targetName,
8766          stream: StreamKind.ERROR,
8767          streamId,
8768          reason: wrapReason(reason)
8769        });
8770      },
8771      sinkCapability: Promise.withResolvers(),
8772      onPull: null,
8773      onCancel: null,
8774      isCancelled: false,
8775      desiredSize: data.desiredSize,
8776      ready: null
8777    };
8778    streamSink.sinkCapability.resolve();
8779    streamSink.ready = streamSink.sinkCapability.promise;
8780    this.streamSinks[streamId] = streamSink;
8781    Promise.try(action, data.data, streamSink).then(function () {
8782      comObj.postMessage({
8783        sourceName,
8784        targetName,
8785        stream: StreamKind.START_COMPLETE,
8786        streamId,
8787        success: true
8788      });
8789    }, function (reason) {
8790      comObj.postMessage({
8791        sourceName,
8792        targetName,
8793        stream: StreamKind.START_COMPLETE,
8794        streamId,
8795        reason: wrapReason(reason)
8796      });
8797    });
8798  }
8799  #processStreamMessage(data) {
8800    const streamId = data.streamId,
8801      sourceName = this.sourceName,
8802      targetName = data.sourceName,
8803      comObj = this.comObj;
8804    const streamController = this.streamControllers[streamId],
8805      streamSink = this.streamSinks[streamId];
8806    switch (data.stream) {
8807      case StreamKind.START_COMPLETE:
8808        if (data.success) {
8809          streamController.startCall.resolve();
8810        } else {
8811          streamController.startCall.reject(wrapReason(data.reason));
8812        }
8813        break;
8814      case StreamKind.PULL_COMPLETE:
8815        if (data.success) {
8816          streamController.pullCall.resolve();
8817        } else {
8818          streamController.pullCall.reject(wrapReason(data.reason));
8819        }
8820        break;
8821      case StreamKind.PULL:
8822        if (!streamSink) {
8823          comObj.postMessage({
8824            sourceName,
8825            targetName,
8826            stream: StreamKind.PULL_COMPLETE,
8827            streamId,
8828            success: true
8829          });
8830          break;
8831        }
8832        if (streamSink.desiredSize <= 0 && data.desiredSize > 0) {
8833          streamSink.sinkCapability.resolve();
8834        }
8835        streamSink.desiredSize = data.desiredSize;
8836        Promise.try(streamSink.onPull || onFn).then(function () {
8837          comObj.postMessage({
8838            sourceName,
8839            targetName,
8840            stream: StreamKind.PULL_COMPLETE,
8841            streamId,
8842            success: true
8843          });
8844        }, function (reason) {
8845          comObj.postMessage({
8846            sourceName,
8847            targetName,
8848            stream: StreamKind.PULL_COMPLETE,
8849            streamId,
8850            reason: wrapReason(reason)
8851          });
8852        });
8853        break;
8854      case StreamKind.ENQUEUE:
8855        assert(streamController, "enqueue should have stream controller");
8856        if (streamController.isClosed) {
8857          break;
8858        }
8859        streamController.controller.enqueue(data.chunk);
8860        break;
8861      case StreamKind.CLOSE:
8862        assert(streamController, "close should have stream controller");
8863        if (streamController.isClosed) {
8864          break;
8865        }
8866        streamController.isClosed = true;
8867        streamController.controller.close();
8868        this.#deleteStreamController(streamController, streamId);
8869        break;
8870      case StreamKind.ERROR:
8871        assert(streamController, "error should have stream controller");
8872        streamController.controller.error(wrapReason(data.reason));
8873        this.#deleteStreamController(streamController, streamId);
8874        break;
8875      case StreamKind.CANCEL_COMPLETE:
8876        if (data.success) {
8877          streamController.cancelCall.resolve();
8878        } else {
8879          streamController.cancelCall.reject(wrapReason(data.reason));
8880        }
8881        this.#deleteStreamController(streamController, streamId);
8882        break;
8883      case StreamKind.CANCEL:
8884        if (!streamSink) {
8885          break;
8886        }
8887        const dataReason = wrapReason(data.reason);
8888        Promise.try(streamSink.onCancel || onFn, dataReason).then(function () {
8889          comObj.postMessage({
8890            sourceName,
8891            targetName,
8892            stream: StreamKind.CANCEL_COMPLETE,
8893            streamId,
8894            success: true
8895          });
8896        }, function (reason) {
8897          comObj.postMessage({
8898            sourceName,
8899            targetName,
8900            stream: StreamKind.CANCEL_COMPLETE,
8901            streamId,
8902            reason: wrapReason(reason)
8903          });
8904        });
8905        streamSink.sinkCapability.reject(dataReason);
8906        streamSink.isCancelled = true;
8907        delete this.streamSinks[streamId];
8908        break;
8909      default:
8910        throw new Error("Unexpected stream case");
8911    }
8912  }
8913  async #deleteStreamController(streamController, streamId) {
8914    await Promise.allSettled([streamController.startCall?.promise, streamController.pullCall?.promise, streamController.cancelCall?.promise]);
8915    delete this.streamControllers[streamId];
8916  }
8917  destroy() {
8918    this.#messageAC?.abort();
8919    this.#messageAC = null;
8920  }
8921}
8922
8923;// ./src/display/binary_data_factory.js
8924
8925
8926class BaseBinaryDataFactory {
8927  #errorStr = Object.freeze({
8928    cMapUrl: "CMap",
8929    standardFontDataUrl: "font",
8930    wasmUrl: "wasm"
8931  });
8932  constructor({
8933    cMapUrl = null,
8934    standardFontDataUrl = null,
8935    wasmUrl = null
8936  }) {
8937    this.cMapUrl = cMapUrl;
8938    this.standardFontDataUrl = standardFontDataUrl;
8939    this.wasmUrl = wasmUrl;
8940  }
8941  async fetch({
8942    kind,
8943    filename
8944  }) {
8945    switch (kind) {
8946      case "cMapUrl":
8947      case "standardFontDataUrl":
8948      case "wasmUrl":
8949        break;
8950      default:
8951        unreachable(`Not implemented: ${kind}`);
8952    }
8953    const baseUrl = this[kind];
8954    if (!baseUrl) {
8955      throw new Error(`Ensure that the \`${kind}\` API parameter is provided.`);
8956    }
8957    const url = `${baseUrl}${filename}`;
8958    return this._fetch(url, kind).catch(reason => {
8959      throw new Error(`Unable to load ${this.#errorStr[kind]} data at: ${url}`);
8960    });
8961  }
8962  async _fetch(url, kind) {
8963    unreachable("Abstract method `_fetch` called.");
8964  }
8965}
8966class DOMBinaryDataFactory extends BaseBinaryDataFactory {
8967  async _fetch(url, kind) {
8968    const type = kind === "cMapUrl" && !url.endsWith(".bcmap") ? "text" : "bytes";
8969    const data = await fetchData(url, type);
8970    return data instanceof Uint8Array ? data : stringToBytes(data);
8971  }
8972}
8973
8974;// ./src/display/canvas_factory.js
8975
8976class BaseCanvasFactory {
8977  #enableHWA = false;
8978  constructor({
8979    enableHWA = false
8980  }) {
8981    this.#enableHWA = enableHWA;
8982  }
8983  create(width, height) {
8984    if (width <= 0 || height <= 0) {
8985      throw new Error("Invalid canvas size");
8986    }
8987    const canvas = this._createCanvas(width, height);
8988    return {
8989      canvas,
8990      context: canvas.getContext("2d", {
8991        willReadFrequently: !this.#enableHWA
8992      })
8993    };
8994  }
8995  reset({
8996    canvas
8997  }, width, height) {
8998    if (!canvas) {
8999      throw new Error("Canvas is not specified");
9000    }
9001    if (width <= 0 || height <= 0) {
9002      throw new Error("Invalid canvas size");
9003    }
9004    canvas.width = width;
9005    canvas.height = height;
9006  }
9007  destroy(canvasAndContext) {
9008    const {
9009      canvas
9010    } = canvasAndContext;
9011    if (!canvas) {
9012      throw new Error("Canvas is not specified");
9013    }
9014    canvas.width = canvas.height = 0;
9015    canvasAndContext.canvas = null;
9016    canvasAndContext.context = null;
9017  }
9018  _createCanvas(width, height) {
9019    unreachable("Abstract method `_createCanvas` called.");
9020  }
9021}
9022class DOMCanvasFactory extends BaseCanvasFactory {
9023  constructor({
9024    ownerDocument = globalThis.document,
9025    enableHWA = false
9026  }) {
9027    super({
9028      enableHWA
9029    });
9030    this._document = ownerDocument;
9031  }
9032  _createCanvas(width, height) {
9033    const canvas = this._document.createElement("canvas");
9034    canvas.width = width;
9035    canvas.height = height;
9036    return canvas;
9037  }
9038}
9039
9040;// ./src/display/filter_factory.js
9041
9042
9043class BaseFilterFactory {
9044  addFilter(maps) {
9045    return "none";
9046  }
9047  addHCMFilter(fgColor, bgColor) {
9048    return "none";
9049  }
9050  addAlphaFilter(map) {
9051    return "none";
9052  }
9053  addLuminosityFilter(map) {
9054    return "none";
9055  }
9056  addKnockoutFilter(alpha = 0) {
9057    return "none";
9058  }
9059  addHighlightHCMFilter(filterName, fgColor, bgColor, newFgColor, newBgColor) {
9060    return "none";
9061  }
9062  addSelectionHCMFilter(fgColor, bgColor) {
9063    return "none";
9064  }
9065  addSelectionFilter() {
9066    return "none";
9067  }
9068  createSelectionStyle(pageColors = null) {
9069    return null;
9070  }
9071  destroy(keepHCM = false) {}
9072}
9073class DOMFilterFactory extends BaseFilterFactory {
9074  #baseUrl;
9075  #_cache;
9076  #_defs;
9077  #docId;
9078  #document;
9079  #_hcmCache;
9080  #id = 0;
9081  constructor({
9082    docId,
9083    ownerDocument = globalThis.document
9084  }) {
9085    super();
9086    this.#docId = docId;
9087    this.#document = ownerDocument;
9088  }
9089  get #cache() {
9090    return this.#_cache ||= new Map();
9091  }
9092  get #hcmCache() {
9093    return this.#_hcmCache ||= new Map();
9094  }
9095  get #defs() {
9096    if (!this.#_defs) {
9097      const div = this.#document.createElement("div");
9098      const {
9099        style
9100      } = div;
9101      style.colorScheme = "only light";
9102      style.visibility = "hidden";
9103      style.contain = "strict";
9104      style.width = style.height = 0;
9105      style.position = "absolute";
9106      style.top = style.left = 0;
9107      style.zIndex = -1;
9108      const svg = this.#document.createElementNS(SVG_NS, "svg");
9109      svg.setAttribute("width", 0);
9110      svg.setAttribute("height", 0);
9111      this.#_defs = this.#document.createElementNS(SVG_NS, "defs");
9112      div.append(svg);
9113      svg.append(this.#_defs);
9114      this.#document.body.append(div);
9115    }
9116    return this.#_defs;
9117  }
9118  #createTables(maps) {
9119    if (maps.length === 1) {
9120      const mapR = maps[0];
9121      const buffer = new Array(256);
9122      for (let i = 0; i < 256; i++) {
9123        buffer[i] = mapR[i] / 255;
9124      }
9125      const table = buffer.join(",");
9126      return [table, table, table];
9127    }
9128    const [mapR, mapG, mapB] = maps;
9129    const bufferR = new Array(256);
9130    const bufferG = new Array(256);
9131    const bufferB = new Array(256);
9132    for (let i = 0; i < 256; i++) {
9133      bufferR[i] = mapR[i] / 255;
9134      bufferG[i] = mapG[i] / 255;
9135      bufferB[i] = mapB[i] / 255;
9136    }
9137    return [bufferR.join(","), bufferG.join(","), bufferB.join(",")];
9138  }
9139  #createUrl(id) {
9140    if (this.#baseUrl === undefined) {
9141      this.#baseUrl = "";
9142      const url = this.#document.URL;
9143      if (url !== this.#document.baseURI) {
9144        if (isDataScheme(url)) {
9145          warn('#createUrl: ignore "data:"-URL for performance reasons.');
9146        } else {
9147          this.#baseUrl = updateUrlHash(url, "");
9148        }
9149      }
9150    }
9151    return `url(${this.#baseUrl}#${id})`;
9152  }
9153  addFilter(maps) {
9154    if (!maps) {
9155      return "none";
9156    }
9157    let value = this.#cache.get(maps);
9158    if (value) {
9159      return value;
9160    }
9161    const [tableR, tableG, tableB] = this.#createTables(maps);
9162    const key = maps.length === 1 ? tableR : `${tableR}${tableG}${tableB}`;
9163    value = this.#cache.get(key);
9164    if (value) {
9165      this.#cache.set(maps, value);
9166      return value;
9167    }
9168    const id = `g_${this.#docId}_transfer_map_${this.#id++}`;
9169    const url = this.#createUrl(id);
9170    this.#cache.set(maps, url);
9171    this.#cache.set(key, url);
9172    const filter = this.#createFilter(id);
9173    this.#addTransferMapConversion(tableR, tableG, tableB, filter);
9174    return url;
9175  }
9176  addHCMFilter(fgColor, bgColor) {
9177    const key = `${fgColor}-${bgColor}`;
9178    const filterName = "base";
9179    let info = this.#hcmCache.get(filterName);
9180    if (info?.key === key) {
9181      return info.url;
9182    }
9183    if (info) {
9184      info.filter?.remove();
9185      info.key = key;
9186      info.url = "none";
9187      info.filter = null;
9188    } else {
9189      info = {
9190        key,
9191        url: "none",
9192        filter: null
9193      };
9194      this.#hcmCache.set(filterName, info);
9195    }
9196    if (!fgColor || !bgColor) {
9197      return info.url;
9198    }
9199    const fgRGB = this.#getRGB(fgColor);
9200    fgColor = Util.makeHexColor(...fgRGB);
9201    const bgRGB = this.#getRGB(bgColor);
9202    bgColor = Util.makeHexColor(...bgRGB);
9203    this.#
vendor: 8,088 bytes, lines 9203-9425
9203defs.style.color = "";
9204    if (fgColor === "#000000" && bgColor === "#ffffff" || fgColor === bgColor) {
9205      return info.url;
9206    }
9207    const map = new Array(256);
9208    for (let i = 0; i <= 255; i++) {
9209      const x = i / 255;
9210      map[i] = x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
9211    }
9212    const table = map.join(",");
9213    const id = `g_${this.#docId}_hcm_filter`;
9214    const filter = info.filter = this.#createFilter(id);
9215    this.#addTransferMapConversion(table, table, table, filter);
9216    this.#addGrayConversion(filter);
9217    const getSteps = (c, n) => {
9218      const start = fgRGB[c] / 255;
9219      const end = bgRGB[c] / 255;
9220      const arr = new Array(n + 1);
9221      for (let i = 0; i <= n; i++) {
9222        arr[i] = start + i / n * (end - start);
9223      }
9224      return arr.join(",");
9225    };
9226    this.#addTransferMapConversion(getSteps(0, 5), getSteps(1, 5), getSteps(2, 5), filter);
9227    info.url = this.#createUrl(id);
9228    return info.url;
9229  }
9230  addSelectionHCMFilter(fgColor, bgColor) {
9231    return this.addHighlightHCMFilter("selection", fgColor, bgColor, "HighlightText", "Highlight");
9232  }
9233  addSelectionFilter() {
9234    return this.addHighlightHCMFilter("selection_default", "black", "white", "HighlightText", "Highlight");
9235  }
9236  createSelectionStyle(pageColors = null) {
9237    const filter = pageColors ? this.addSelectionHCMFilter(pageColors.foreground, pageColors.background) : this.addSelectionFilter();
9238    if (filter === "none" || !FeatureTest.platform.isFirefox) {
9239      return null;
9240    }
9241    return {
9242      "backdrop-filter": filter,
9243      "background-color": "transparent"
9244    };
9245  }
9246  addAlphaFilter(map) {
9247    let value = this.#cache.get(map);
9248    if (value) {
9249      return value;
9250    }
9251    const [tableA] = this.#createTables([map]);
9252    const key = `alpha_${tableA}`;
9253    value = this.#cache.get(key);
9254    if (value) {
9255      this.#cache.set(map, value);
9256      return value;
9257    }
9258    const id = `g_${this.#docId}_alpha_map_${this.#id++}`;
9259    const url = this.#createUrl(id);
9260    this.#cache.set(map, url);
9261    this.#cache.set(key, url);
9262    const filter = this.#createFilter(id);
9263    this.#addTransferMapAlphaConversion(tableA, filter);
9264    return url;
9265  }
9266  addLuminosityFilter(map) {
9267    let value = this.#cache.get(map || "luminosity");
9268    if (value) {
9269      return value;
9270    }
9271    let tableA, key;
9272    if (map) {
9273      [tableA] = this.#createTables([map]);
9274      key = `luminosity_${tableA}`;
9275    } else {
9276      key = "luminosity";
9277    }
9278    value = this.#cache.get(key);
9279    if (value) {
9280      this.#cache.set(map, value);
9281      return value;
9282    }
9283    const id = `g_${this.#docId}_luminosity_map_${this.#id++}`;
9284    const url = this.#createUrl(id);
9285    this.#cache.set(map, url);
9286    this.#cache.set(key, url);
9287    const filter = this.#createFilter(id);
9288    this.#addLuminosityConversion(filter);
9289    if (map) {
9290      this.#addTransferMapAlphaConversion(tableA, filter);
9291    }
9292    return url;
9293  }
9294  addKnockoutFilter(alpha = 0) {
9295    const slope = alpha > 0 ? Math.min(1 / alpha, 1e6) : 1e6;
9296    const key = `knockout_${slope}`;
9297    const value = this.#cache.get(key);
9298    if (value) {
9299      return value;
9300    }
9301    const id = `g_${this.#docId}_knockout_filter_${this.#id++}`;
9302    const url = this.#createUrl(id);
9303    this.#cache.set(key, url);
9304    const filter = this.#createFilter(id);
9305    const feComponentTransfer = this.#document.createElementNS(SVG_NS, "feComponentTransfer");
9306    filter.append(feComponentTransfer);
9307    const feFuncA = this.#document.createElementNS(SVG_NS, "feFuncA");
9308    feFuncA.setAttribute("type", "linear");
9309    feFuncA.setAttribute("slope", `${slope}`);
9310    feFuncA.setAttribute("intercept", "0");
9311    feComponentTransfer.append(feFuncA);
9312    return url;
9313  }
9314  addHighlightHCMFilter(filterName, fgColor, bgColor, newFgColor, newBgColor) {
9315    const key = `${fgColor}-${bgColor}-${newFgColor}-${newBgColor}`;
9316    let info = this.#hcmCache.get(filterName);
9317    if (info?.key === key) {
9318      return info.url;
9319    }
9320    if (info) {
9321      info.filter?.remove();
9322      info.key = key;
9323      info.url = "none";
9324      info.filter = null;
9325    } else {
9326      info = {
9327        key,
9328        url: "none",
9329        filter: null
9330      };
9331      this.#hcmCache.set(filterName, info);
9332    }
9333    if (!fgColor || !bgColor) {
9334      return info.url;
9335    }
9336    const [fgRGB, bgRGB] = [fgColor, bgColor].map(this.#getRGB.bind(this));
9337    let fgGray = Math.round(0.2126 * fgRGB[0] + 0.7152 * fgRGB[1] + 0.0722 * fgRGB[2]);
9338    let bgGray = Math.round(0.2126 * bgRGB[0] + 0.7152 * bgRGB[1] + 0.0722 * bgRGB[2]);
9339    let [newFgRGB, newBgRGB] = [newFgColor, newBgColor].map(this.#getOpaqueTextColor.bind(this));
9340    if (bgGray < fgGray) {
9341      [fgGray, bgGray, newFgRGB, newBgRGB] = [bgGray, fgGray, newBgRGB, newFgRGB];
9342    }
9343    this.#defs.style.color = "";
9344    const getSteps = (fg, bg, n) => {
9345      const arr = new Array(256);
9346      const step = (bgGray - fgGray) / n;
9347      const newStart = fg / 255;
9348      const newStep = (bg - fg) / (255 * n);
9349      let prev = 0;
9350      for (let i = 0; i <= n; i++) {
9351        const k = Math.round(fgGray + i * step);
9352        const value = newStart + i * newStep;
9353        for (let j = prev; j <= k; j++) {
9354          arr[j] = value;
9355        }
9356        prev = k + 1;
9357      }
9358      for (let i = prev; i < 256; i++) {
9359        arr[i] = arr[prev - 1];
9360      }
9361      return arr.join(",");
9362    };
9363    const id = `g_${this.#docId}_hcm_${filterName}_filter`;
9364    const filter = info.filter = this.#createFilter(id);
9365    this.#addGrayConversion(filter);
9366    this.#addTransferMapConversion(getSteps(newFgRGB[0], newBgRGB[0], 5), getSteps(newFgRGB[1], newBgRGB[1], 5), getSteps(newFgRGB[2], newBgRGB[2], 5), filter);
9367    info.url = this.#createUrl(id);
9368    return info.url;
9369  }
9370  destroy(keepHCM = false) {
9371    if (keepHCM && this.#_hcmCache?.size) {
9372      return;
9373    }
9374    this.#_defs?.parentNode.parentNode.remove();
9375    this.#_defs = null;
9376    this.#_cache?.clear();
9377    this.#_cache = null;
9378    this.#_hcmCache?.clear();
9379    this.#_hcmCache = null;
9380    this.#id = 0;
9381  }
9382  #addLuminosityConversion(filter) {
9383    const feColorMatrix = this.#document.createElementNS(SVG_NS, "feColorMatrix");
9384    feColorMatrix.setAttribute("type", "matrix");
9385    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");
9386    filter.append(feColorMatrix);
9387  }
9388  #addGrayConversion(filter) {
9389    const feColorMatrix = this.#document.createElementNS(SVG_NS, "feColorMatrix");
9390    feColorMatrix.setAttribute("type", "matrix");
9391    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");
9392    filter.append(feColorMatrix);
9393  }
9394  #createFilter(id) {
9395    const filter = this.#document.createElementNS(SVG_NS, "filter");
9396    filter.setAttribute("color-interpolation-filters", "sRGB");
9397    filter.setAttribute("id", id);
9398    this.#defs.append(filter);
9399    return filter;
9400  }
9401  #appendFeFunc(feComponentTransfer, func, table) {
9402    const feFunc = this.#document.createElementNS(SVG_NS, func);
9403    feFunc.setAttribute("type", "discrete");
9404    feFunc.setAttribute("tableValues", table);
9405    feComponentTransfer.append(feFunc);
9406  }
9407  #addTransferMapConversion(rTable, gTable, bTable, filter) {
9408    const feComponentTransfer = this.#document.createElementNS(SVG_NS, "feComponentTransfer");
9409    filter.append(feComponentTransfer);
9410    this.#appendFeFunc(feComponentTransfer, "feFuncR", rTable);
9411    this.#appendFeFunc(feComponentTransfer, "feFuncG", gTable);
9412    this.#appendFeFunc(feComponentTransfer, "feFuncB", bTable);
9413  }
9414  #addTransferMapAlphaConversion(aTable, filter) {
9415    const feComponentTransfer = this.#document.createElementNS(SVG_NS, "feComponentTransfer");
9416    filter.append(feComponentTransfer);
9417    this.#appendFeFunc(feComponentTransfer, "feFuncA", aTable);
9418  }
9419  #getRGB(color) {
9420    this.#defs.style.color = color;
9421    return getRGB(getComputedStyle(this.#defs).getPropertyValue("color"));
9422  }
9423  #getRGBA(color) {
9424    this.#defs.style.color = color;
9425    return getRGBA(getComputedStyle(this.#defs).getPropertyValue("color"))
vendor: 10,632 bytes, lines 9425-9805
9425;
9426  }
9427  #getOpaqueTextColor(color) {
9428    const [r, g, b, alpha] = this.#getRGBA(color);
9429    if (alpha === 1) {
9430      return [r, g, b];
9431    }
9432    const [canvasR, canvasG, canvasB] = this.#getRGB("Canvas");
9433    return [blend(r, canvasR, alpha), blend(g, canvasG, alpha), blend(b, canvasB, alpha)];
9434  }
9435}
9436function blend(fg, bg, alpha) {
9437  return Math.round(alpha * fg + (1 - alpha) * bg);
9438}
9439
9440;// ./src/display/node_utils.js
9441
9442
9443
9444
9445if (isNodeJS) {
9446  warn("Please use the `legacy` build in Node.js environments.");
9447}
9448async function node_utils_fetchData(url) {
9449  const fs = process.getBuiltinModule("fs/promises");
9450  const data = await fs.readFile(url);
9451  return new Uint8Array(data);
9452}
9453class NodeFilterFactory extends BaseFilterFactory {}
9454class NodeCanvasFactory extends BaseCanvasFactory {
9455  _createCanvas(width, height) {
9456    const require = process.getBuiltinModule("module").createRequire(import.meta.url);
9457    const canvas = require("@napi-rs/canvas");
9458    return canvas.createCanvas(width, height);
9459  }
9460}
9461class NodeBinaryDataFactory extends BaseBinaryDataFactory {
9462  async _fetch(url, kind) {
9463    return node_utils_fetchData(url);
9464  }
9465}
9466
9467;// ./src/shared/image_utils.js
9468/* unused harmony import specifier */ var image_utils_ImageKind;
9469/* unused harmony import specifier */ var image_utils_FeatureTest;
9470
9471function convertToRGBA(params) {
9472  switch (params.kind) {
9473    case image_utils_ImageKind.GRAYSCALE_1BPP:
9474      return convertBlackAndWhiteToRGBA(params);
9475    case image_utils_ImageKind.RGB_24BPP:
9476      return convertRGBToRGBA(params);
9477  }
9478  return null;
9479}
9480function convertBlackAndWhiteToRGBA({
9481  src,
9482  srcPos = 0,
9483  dest,
9484  width,
9485  height,
9486  nonBlackColor = 0xffffffff,
9487  inverseDecode = false
9488}) {
9489  const black = FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff;
9490  const [zeroMapping, oneMapping] = inverseDecode ? [nonBlackColor, black] : [black, nonBlackColor];
9491  const widthInSource = width >> 3;
9492  const widthRemainder = width & 7;
9493  const xorMask = zeroMapping ^ oneMapping;
9494  const srcLength = src.length;
9495  dest = new Uint32Array(dest.buffer);
9496  let destPos = 0;
9497  for (let i = 0; i < height; ++i) {
9498    for (const max = srcPos + widthInSource; srcPos < max; ++srcPos, destPos += 8) {
9499      const elem = src[srcPos];
9500      dest[destPos] = zeroMapping ^ -(elem >> 7 & 1) & xorMask;
9501      dest[destPos + 1] = zeroMapping ^ -(elem >> 6 & 1) & xorMask;
9502      dest[destPos + 2] = zeroMapping ^ -(elem >> 5 & 1) & xorMask;
9503      dest[destPos + 3] = zeroMapping ^ -(elem >> 4 & 1) & xorMask;
9504      dest[destPos + 4] = zeroMapping ^ -(elem >> 3 & 1) & xorMask;
9505      dest[destPos + 5] = zeroMapping ^ -(elem >> 2 & 1) & xorMask;
9506      dest[destPos + 6] = zeroMapping ^ -(elem >> 1 & 1) & xorMask;
9507      dest[destPos + 7] = zeroMapping ^ -(elem & 1) & xorMask;
9508    }
9509    if (widthRemainder === 0) {
9510      continue;
9511    }
9512    const elem = srcPos < srcLength ? src[srcPos++] : 255;
9513    for (let j = 0; j < widthRemainder; ++j, ++destPos) {
9514      dest[destPos] = zeroMapping ^ -(elem >> 7 - j & 1) & xorMask;
9515    }
9516  }
9517  return {
9518    srcPos,
9519    destPos
9520  };
9521}
9522function convertRGBToRGBA({
9523  src,
9524  srcPos = 0,
9525  dest,
9526  destPos = 0,
9527  width,
9528  height
9529}) {
9530  let i = 0;
9531  const len = width * height * 3;
9532  const len32 = len >> 2;
9533  const src32 = new Uint32Array(src.buffer, srcPos, len32);
9534  const alphaMask = FeatureTest.isLittleEndian ? 0xff000000 : 0xff;
9535  if (FeatureTest.isLittleEndian) {
9536    for (; i < len32 - 2; i += 3, destPos += 4) {
9537      const s1 = src32[i],
9538        s2 = src32[i + 1],
9539        s3 = src32[i + 2];
9540      dest[destPos] = s1 | alphaMask;
9541      dest[destPos + 1] = s1 >>> 24 | s2 << 8 | alphaMask;
9542      dest[destPos + 2] = s2 >>> 16 | s3 << 16 | alphaMask;
9543      dest[destPos + 3] = s3 >>> 8 | alphaMask;
9544    }
9545    for (let j = i * 4, jj = srcPos + len; j < jj; j += 3) {
9546      dest[destPos++] = src[j] | src[j + 1] << 8 | src[j + 2] << 16 | alphaMask;
9547    }
9548  } else {
9549    for (; i < len32 - 2; i += 3, destPos += 4) {
9550      const s1 = src32[i],
9551        s2 = src32[i + 1],
9552        s3 = src32[i + 2];
9553      dest[destPos] = s1 | alphaMask;
9554      dest[destPos + 1] = s1 << 24 | s2 >>> 8 | alphaMask;
9555      dest[destPos + 2] = s2 << 16 | s3 >>> 16 | alphaMask;
9556      dest[destPos + 3] = s3 << 8 | alphaMask;
9557    }
9558    for (let j = i * 4, jj = srcPos + len; j < jj; j += 3) {
9559      dest[destPos++] = src[j] << 24 | src[j + 1] << 16 | src[j + 2] << 8 | alphaMask;
9560    }
9561  }
9562  return {
9563    srcPos: srcPos + len,
9564    destPos
9565  };
9566}
9567function grayToRGBA(src, dest) {
9568  if (image_utils_FeatureTest.isLittleEndian) {
9569    for (let i = 0, ii = src.length; i < ii; i++) {
9570      dest[i] = src[i] * 0x10101 | 0xff000000;
9571    }
9572  } else {
9573    for (let i = 0, ii = src.length; i < ii; i++) {
9574      dest[i] = src[i] * 0x1010100 | 0x000000ff;
9575    }
9576  }
9577}
9578
9579;// ./src/display/webgpu.js
9580const MESH_WGSL = `
9581struct Uniforms {
9582  offsetX      : f32,
9583  offsetY      : f32,
9584  scaleX       : f32,
9585  scaleY       : f32,
9586  paddedWidth  : f32,
9587  paddedHeight : f32,
9588  borderSize   : f32,
9589  _pad         : f32,
9590};
9591
9592@group(0) @binding(0) var<uniform> u : Uniforms;
9593
9594struct VertexInput {
9595  @location(0) position : vec2<f32>,
9596  @location(1) color    : vec4<f32>,
9597};
9598
9599struct VertexOutput {
9600  @builtin(position) position : vec4<f32>,
9601  @location(0)       color    : vec3<f32>,
9602};
9603
9604@vertex
9605fn vs_main(in : VertexInput) -> VertexOutput {
9606  var out : VertexOutput;
9607  let cx = (in.position.x + u.offsetX) * u.scaleX;
9608  let cy = (in.position.y + u.offsetY) * u.scaleY;
9609  out.position = vec4<f32>(
9610    ((cx + u.borderSize) / u.paddedWidth) * 2.0 - 1.0,
9611    1.0 - ((cy + u.borderSize) / u.paddedHeight) * 2.0,
9612    0.0,
9613    1.0
9614  );
9615  out.color = in.color.rgb;
9616  return out;
9617}
9618
9619@fragment
9620fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
9621  return vec4<f32>(in.color, 1.0);
9622}
9623`;
9624class WebGPU {
9625  #initPromise = null;
9626  #device = null;
9627  #meshPipeline = null;
9628  #preferredFormat = null;
9629  async #initGPU() {
9630    if (!globalThis.navigator?.gpu) {
9631      return false;
9632    }
9633    try {
9634      const adapter = await navigator.gpu.requestAdapter();
9635      if (!adapter) {
9636        return false;
9637      }
9638      this.#preferredFormat = navigator.gpu.getPreferredCanvasFormat();
9639      this.#device = await adapter.requestDevice();
9640      return true;
9641    } catch {
9642      return false;
9643    }
9644  }
9645  init() {
9646    return this.#initPromise ||= this.#initGPU();
9647  }
9648  get isReady() {
9649    return this.#device !== null;
9650  }
9651  loadMeshShader() {
9652    if (!this.#device || this.#meshPipeline) {
9653      return;
9654    }
9655    const shaderModule = this.#device.createShaderModule({
9656      code: MESH_WGSL
9657    });
9658    this.#meshPipeline = this.#device.createRenderPipeline({
9659      layout: "auto",
9660      vertex: {
9661        module: shaderModule,
9662        entryPoint: "vs_main",
9663        buffers: [{
9664          arrayStride: 2 * 4,
9665          attributes: [{
9666            shaderLocation: 0,
9667            offset: 0,
9668            format: "float32x2"
9669          }]
9670        }, {
9671          arrayStride: 4,
9672          attributes: [{
9673            shaderLocation: 1,
9674            offset: 0,
9675            format: "unorm8x4"
9676          }]
9677        }]
9678      },
9679      fragment: {
9680        module: shaderModule,
9681        entryPoint: "fs_main",
9682        targets: [{
9683          format: this.#preferredFormat
9684        }]
9685      },
9686      primitive: {
9687        topology: "triangle-list"
9688      }
9689    });
9690  }
9691  draw(posData, colData, vertexCount, context, backgroundColor, paddedWidth, paddedHeight, borderSize) {
9692    this.loadMeshShader();
9693    const device = this.#device;
9694    const {
9695      offsetX,
9696      offsetY,
9697      scaleX,
9698      scaleY
9699    } = context;
9700    const posBuffer = device.createBuffer({
9701      size: Math.max(posData.byteLength, 4),
9702      usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
9703    });
9704    if (posData.byteLength > 0) {
9705      device.queue.writeBuffer(posBuffer, 0, posData);
9706    }
9707    const colBuffer = device.createBuffer({
9708      size: Math.max(colData.byteLength, 4),
9709      usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
9710    });
9711    if (colData.byteLength > 0) {
9712      device.queue.writeBuffer(colBuffer, 0, colData);
9713    }
9714    const uniformBuffer = device.createBuffer({
9715      size: 8 * 4,
9716      usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
9717    });
9718    device.queue.writeBuffer(uniformBuffer, 0, new Float32Array([offsetX, offsetY, scaleX, scaleY, paddedWidth, paddedHeight, borderSize, 0]));
9719    const bindGroup = device.createBindGroup({
9720      layout: this.#meshPipeline.getBindGroupLayout(0),
9721      entries: [{
9722        binding: 0,
9723        resource: {
9724          buffer: uniformBuffer
9725        }
9726      }]
9727    });
9728    const offscreen = new OffscreenCanvas(paddedWidth, paddedHeight);
9729    const gpuCtx = offscreen.getContext("webgpu");
9730    gpuCtx.configure({
9731      device,
9732      format: this.#preferredFormat,
9733      alphaMode: backgroundColor ? "opaque" : "premultiplied"
9734    });
9735    const clearValue = backgroundColor ? {
9736      r: backgroundColor[0] / 255,
9737      g: backgroundColor[1] / 255,
9738      b: backgroundColor[2] / 255,
9739      a: 1
9740    } : {
9741      r: 0,
9742      g: 0,
9743      b: 0,
9744      a: 0
9745    };
9746    const commandEncoder = device.createCommandEncoder();
9747    const renderPass = commandEncoder.beginRenderPass({
9748      colorAttachments: [{
9749        view: gpuCtx.getCurrentTexture().createView(),
9750        clearValue,
9751        loadOp: "clear",
9752        storeOp: "store"
9753      }]
9754    });
9755    if (vertexCount > 0) {
9756      renderPass.setPipeline(this.#meshPipeline);
9757      renderPass.setBindGroup(0, bindGroup);
9758      renderPass.setVertexBuffer(0, posBuffer);
9759      renderPass.setVertexBuffer(1, colBuffer);
9760      renderPass.draw(vertexCount);
9761    }
9762    renderPass.end();
9763    device.queue.submit([commandEncoder.finish()]);
9764    posBuffer.destroy();
9765    colBuffer.destroy();
9766    uniformBuffer.destroy();
9767    return offscreen.transferToImageBitmap();
9768  }
9769}
9770const _webGPU = new WebGPU();
9771function initGPU() {
9772  return _webGPU.init();
9773}
9774function isGPUReady() {
9775  return _webGPU.isReady;
9776}
9777function loadMeshShader() {
9778  _webGPU.loadMeshShader();
9779}
9780function drawMeshWithGPU(posData, colData, vertexCount, context, backgroundColor, paddedWidth, paddedHeight, borderSize) {
9781  return _webGPU.draw(posData, colData, vertexCount, context, backgroundColor, paddedWidth, paddedHeight, borderSize);
9782}
9783
9784;// ./src/display/pattern_helper.js
9785
9786
9787
9788
9789const PathType = {
9790  FILL: "Fill",
9791  STROKE: "Stroke",
9792  SHADING: "Shading"
9793};
9794function applyBoundingBox(ctx, bbox) {
9795  if (!bbox) {
9796    return;
9797  }
9798  const width = bbox[2] - bbox[0];
9799  const height = bbox[3] - bbox[1];
9800  const region = new Path2D();
9801  region.rect(bbox[0], bbox[1], width, height);
9802  ctx.clip(region);
9803}
9804class BaseShadingPattern {
9805  
vendor: 8,038 bytes, lines 9805-10061
9805isModifyingCurrentTransform() {
9806    return false;
9807  }
9808  getPattern() {
9809    unreachable("Abstract method `getPattern` called.");
9810  }
9811}
9812class RadialAxialShadingPattern extends BaseShadingPattern {
9813  constructor(IR) {
9814    super();
9815    this._type = IR[1];
9816    this._bbox = IR[2];
9817    this._colorStops = IR[3];
9818    this._p0 = IR[4];
9819    this._p1 = IR[5];
9820    this._r0 = IR[6];
9821    this._r1 = IR[7];
9822    this.matrix = null;
9823  }
9824  isOriginBased() {
9825    return this._p0[0] === 0 && this._p0[1] === 0 && (!this.isRadial() || this._p1[0] === 0 && this._p1[1] === 0);
9826  }
9827  isRadial() {
9828    return this._type === "radial";
9829  }
9830  areConic() {
9831    if (!this.isRadial()) {
9832      return false;
9833    }
9834    const dist = Math.hypot(this._p0[0] - this._p1[0], this._p0[1] - this._p1[1]);
9835    return dist + this._r1 > this._r0 && dist + this._r0 > this._r1;
9836  }
9837  _createGradient(ctx, transform = null) {
9838    let grad;
9839    let firstPoint = this._p0;
9840    let secondPoint = this._p1;
9841    if (transform) {
9842      firstPoint = firstPoint.slice();
9843      secondPoint = secondPoint.slice();
9844      Util.applyTransform(firstPoint, transform);
9845      Util.applyTransform(secondPoint, transform);
9846    }
9847    if (this._type === "axial") {
9848      grad = ctx.createLinearGradient(firstPoint[0], firstPoint[1], secondPoint[0], secondPoint[1]);
9849    } else if (this._type === "radial") {
9850      let r0 = this._r0;
9851      let r1 = this._r1;
9852      if (transform) {
9853        const scale = new Float32Array(2);
9854        Util.singularValueDecompose2dScale(transform, scale);
9855        r0 *= scale[0];
9856        r1 *= scale[0];
9857      }
9858      grad = ctx.createRadialGradient(firstPoint[0], firstPoint[1], r0, secondPoint[0], secondPoint[1], r1);
9859    }
9860    for (const colorStop of this._colorStops) {
9861      grad.addColorStop(colorStop[0], colorStop[1]);
9862    }
9863    return grad;
9864  }
9865  _createReversedGradient(ctx, transform = null) {
9866    let firstPoint = this._p1;
9867    let secondPoint = this._p0;
9868    if (transform) {
9869      firstPoint = firstPoint.slice();
9870      secondPoint = secondPoint.slice();
9871      Util.applyTransform(firstPoint, transform);
9872      Util.applyTransform(secondPoint, transform);
9873    }
9874    let r0 = this._r1;
9875    let r1 = this._r0;
9876    if (transform) {
9877      const scale = new Float32Array(2);
9878      Util.singularValueDecompose2dScale(transform, scale);
9879      r0 *= scale[0];
9880      r1 *= scale[0];
9881    }
9882    const grad = ctx.createRadialGradient(firstPoint[0], firstPoint[1], r0, secondPoint[0], secondPoint[1], r1);
9883    const reversedStops = this._colorStops.map(([t, c]) => [1 - t, c]).reverse();
9884    for (const [t, c] of reversedStops) {
9885      grad.addColorStop(t, c);
9886    }
9887    return grad;
9888  }
9889  getPattern(ctx, owner, inverse, pathType) {
9890    let pattern;
9891    if (pathType === PathType.STROKE || pathType === PathType.FILL) {
9892      if (this.isOriginBased()) {
9893        let transf = Util.transform(inverse, owner.baseTransform);
9894        if (this.matrix) {
9895          transf = Util.transform(transf, this.matrix);
9896        }
9897        const precision = 1e-3;
9898        const n1 = Math.hypot(transf[0], transf[1]);
9899        const n2 = Math.hypot(transf[2], transf[3]);
9900        const ps = (transf[0] * transf[2] + transf[1] * transf[3]) / (n1 * n2);
9901        if (Math.abs(ps) < precision) {
9902          if (this.isRadial()) {
9903            if (Math.abs(n1 - n2) < precision) {
9904              return this._createGradient(ctx, transf);
9905            }
9906          } else {
9907            return this._createGradient(ctx, transf);
9908          }
9909        }
9910      }
9911      const ownerBBox = owner.current.getClippedPathBoundingBox(pathType, getCurrentTransform(ctx)) || [0, 0, 0, 0];
9912      const width = Math.ceil(ownerBBox[2] - ownerBBox[0]) || 1;
9913      const height = Math.ceil(ownerBBox[3] - ownerBBox[1]) || 1;
9914      const tmpCanvas = owner.canvasFactory.create(width, height);
9915      const tmpCtx = tmpCanvas.context;
9916      tmpCtx.clearRect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height);
9917      tmpCtx.beginPath();
9918      tmpCtx.rect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height);
9919      tmpCtx.translate(-ownerBBox[0], -ownerBBox[1]);
9920      inverse = Util.transform(inverse, [1, 0, 0, 1, ownerBBox[0], ownerBBox[1]]);
9921      tmpCtx.transform(...owner.baseTransform);
9922      if (this.matrix) {
9923        tmpCtx.transform(...this.matrix);
9924      }
9925      applyBoundingBox(tmpCtx, this._bbox);
9926      if (this.areConic()) {
9927        tmpCtx.fillStyle = this._createReversedGradient(tmpCtx);
9928        tmpCtx.fill();
9929      }
9930      tmpCtx.fillStyle = this._createGradient(tmpCtx);
9931      tmpCtx.fill();
9932      pattern = ctx.createPattern(tmpCanvas.canvas, "no-repeat");
9933      owner.canvasFactory.destroy(tmpCanvas);
9934      const domMatrix = new DOMMatrix(inverse);
9935      pattern.setTransform(domMatrix);
9936    } else {
9937      if (this.areConic()) {
9938        ctx.save();
9939        applyBoundingBox(ctx, this._bbox);
9940        ctx.fillStyle = this._createReversedGradient(ctx);
9941        ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
9942        ctx.restore();
9943      }
9944      applyBoundingBox(ctx, this._bbox);
9945      pattern = this._createGradient(ctx);
9946    }
9947    return pattern;
9948  }
9949}
9950function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) {
9951  const coords = context.coords,
9952    colors = context.colors;
9953  const bytes = data.data,
9954    rowSize = data.width * 4;
9955  let tmp;
9956  if (coords[p1 * 2 + 1] > coords[p2 * 2 + 1]) {
9957    tmp = p1;
9958    p1 = p2;
9959    p2 = tmp;
9960    tmp = c1;
9961    c1 = c2;
9962    c2 = tmp;
9963  }
9964  if (coords[p2 * 2 + 1] > coords[p3 * 2 + 1]) {
9965    tmp = p2;
9966    p2 = p3;
9967    p3 = tmp;
9968    tmp = c2;
9969    c2 = c3;
9970    c3 = tmp;
9971  }
9972  if (coords[p1 * 2 + 1] > coords[p2 * 2 + 1]) {
9973    tmp = p1;
9974    p1 = p2;
9975    p2 = tmp;
9976    tmp = c1;
9977    c1 = c2;
9978    c2 = tmp;
9979  }
9980  const x1 = (coords[p1 * 2] + context.offsetX) * context.scaleX;
9981  const y1 = (coords[p1 * 2 + 1] + context.offsetY) * context.scaleY;
9982  const x2 = (coords[p2 * 2] + context.offsetX) * context.scaleX;
9983  const y2 = (coords[p2 * 2 + 1] + context.offsetY) * context.scaleY;
9984  const x3 = (coords[p3 * 2] + context.offsetX) * context.scaleX;
9985  const y3 = (coords[p3 * 2 + 1] + context.offsetY) * context.scaleY;
9986  if (y1 >= y3) {
9987    return;
9988  }
9989  const c1r = colors[c1 * 4],
9990    c1g = colors[c1 * 4 + 1],
9991    c1b = colors[c1 * 4 + 2];
9992  const c2r = colors[c2 * 4],
9993    c2g = colors[c2 * 4 + 1],
9994    c2b = colors[c2 * 4 + 2];
9995  const c3r = colors[c3 * 4],
9996    c3g = colors[c3 * 4 + 1],
9997    c3b = colors[c3 * 4 + 2];
9998  const minY = Math.round(y1),
9999    maxY = Math.round(y3);
10000  let xa, car, cag, cab;
10001  let xb, cbr, cbg, cbb;
10002  for (let y = minY; y <= maxY; y++) {
10003    if (y < y2) {
10004      const k = y < y1 ? 0 : (y1 - y) / (y1 - y2);
10005      xa = x1 - (x1 - x2) * k;
10006      car = c1r - (c1r - c2r) * k;
10007      cag = c1g - (c1g - c2g) * k;
10008      cab = c1b - (c1b - c2b) * k;
10009    } else {
10010      let k;
10011      if (y > y3) {
10012        k = 1;
10013      } else if (y2 === y3) {
10014        k = 0;
10015      } else {
10016        k = (y2 - y) / (y2 - y3);
10017      }
10018      xa = x2 - (x2 - x3) * k;
10019      car = c2r - (c2r - c3r) * k;
10020      cag = c2g - (c2g - c3g) * k;
10021      cab = c2b - (c2b - c3b) * k;
10022    }
10023    let k;
10024    if (y < y1) {
10025      k = 0;
10026    } else if (y > y3) {
10027      k = 1;
10028    } else {
10029      k = (y1 - y) / (y1 - y3);
10030    }
10031    xb = x1 - (x1 - x3) * k;
10032    cbr = c1r - (c1r - c3r) * k;
10033    cbg = c1g - (c1g - c3g) * k;
10034    cbb = c1b - (c1b - c3b) * k;
10035    const x1_ = Math.round(Math.min(xa, xb));
10036    const x2_ = Math.round(Math.max(xa, xb));
10037    let j = rowSize * y + x1_ * 4;
10038    for (let x = x1_; x <= x2_; x++) {
10039      k = (xa - x) / (xa - xb);
10040      if (k < 0) {
10041        k = 0;
10042      } else if (k > 1) {
10043        k = 1;
10044      }
10045      bytes[j++] = car - (car - cbr) * k | 0;
10046      bytes[j++] = cag - (cag - cbg) * k | 0;
10047      bytes[j++] = cab - (cab - cbb) * k | 0;
10048      bytes[j++] = 255;
10049    }
10050  }
10051}
10052class MeshShadingPattern extends BaseShadingPattern {
10053  constructor(IR) {
10054    super();
10055    this._posData = IR[2];
10056    this._colData = IR[3];
10057    this._vertexCount = IR[4];
10058    this._bounds = IR[5];
10059    this._bbox = IR[6];
10060    this._background = IR[7];
10061    this.matrix = null
vendor: 13,078 bytes, lines 10061-10407
10061;
10062    loadMeshShader();
10063  }
10064  _createMeshCanvas(combinedScale, backgroundColor, canvasFactory) {
10065    const EXPECTED_SCALE = 1.1;
10066    const MAX_PATTERN_SIZE = 3000;
10067    const BORDER_SIZE = 2;
10068    const offsetX = Math.floor(this._bounds[0]);
10069    const offsetY = Math.floor(this._bounds[1]);
10070    const boundsWidth = Math.ceil(this._bounds[2]) - offsetX;
10071    const boundsHeight = Math.ceil(this._bounds[3]) - offsetY;
10072    const width = Math.min(Math.ceil(Math.abs(boundsWidth * combinedScale[0] * EXPECTED_SCALE)), MAX_PATTERN_SIZE) || 1;
10073    const height = Math.min(Math.ceil(Math.abs(boundsHeight * combinedScale[1] * EXPECTED_SCALE)), MAX_PATTERN_SIZE) || 1;
10074    const scaleX = boundsWidth ? boundsWidth / width : 1;
10075    const scaleY = boundsHeight ? boundsHeight / height : 1;
10076    const context = {
10077      coords: this._posData,
10078      colors: this._colData,
10079      offsetX: -offsetX,
10080      offsetY: -offsetY,
10081      scaleX: 1 / scaleX,
10082      scaleY: 1 / scaleY
10083    };
10084    const paddedWidth = width + BORDER_SIZE * 2;
10085    const paddedHeight = height + BORDER_SIZE * 2;
10086    const tmpCanvas = canvasFactory.create(paddedWidth, paddedHeight);
10087    if (isGPUReady() && this._vertexCount > 48) {
10088      tmpCanvas.context.drawImage(drawMeshWithGPU(this._posData, this._colData, this._vertexCount, context, backgroundColor, paddedWidth, paddedHeight, BORDER_SIZE), 0, 0);
10089    } else {
10090      const data = tmpCanvas.context.createImageData(width, height);
10091      if (backgroundColor) {
10092        const bytes = data.data;
10093        for (let i = 0, ii = bytes.length; i < ii; i += 4) {
10094          bytes[i] = backgroundColor[0];
10095          bytes[i + 1] = backgroundColor[1];
10096          bytes[i + 2] = backgroundColor[2];
10097          bytes[i + 3] = 255;
10098        }
10099      }
10100      for (let i = 0, ii = this._vertexCount; i < ii; i += 3) {
10101        drawTriangle(data, context, i, i + 1, i + 2, i, i + 1, i + 2);
10102      }
10103      tmpCanvas.context.putImageData(data, BORDER_SIZE, BORDER_SIZE);
10104    }
10105    return {
10106      canvas: tmpCanvas.canvas,
10107      offsetX: offsetX - BORDER_SIZE * scaleX,
10108      offsetY: offsetY - BORDER_SIZE * scaleY,
10109      scaleX,
10110      scaleY
10111    };
10112  }
10113  isModifyingCurrentTransform() {
10114    return true;
10115  }
10116  getPattern(ctx, owner, inverse, pathType) {
10117    applyBoundingBox(ctx, this._bbox);
10118    const scale = new Float32Array(2);
10119    if (pathType === PathType.SHADING) {
10120      Util.singularValueDecompose2dScale(getCurrentTransform(ctx), scale);
10121    } else if (this.matrix) {
10122      Util.singularValueDecompose2dScale(this.matrix, scale);
10123      const [matrixScaleX, matrixScaleY] = scale;
10124      Util.singularValueDecompose2dScale(owner.baseTransform, scale);
10125      scale[0] *= matrixScaleX;
10126      scale[1] *= matrixScaleY;
10127    } else {
10128      Util.singularValueDecompose2dScale(owner.baseTransform, scale);
10129    }
10130    const temporaryPatternCanvas = this._createMeshCanvas(scale, pathType === PathType.SHADING ? null : this._background, owner.canvasFactory);
10131    if (pathType !== PathType.SHADING) {
10132      ctx.setTransform(...owner.baseTransform);
10133      if (this.matrix) {
10134        ctx.transform(...this.matrix);
10135      }
10136    }
10137    ctx.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY);
10138    ctx.scale(temporaryPatternCanvas.scaleX, temporaryPatternCanvas.scaleY);
10139    const pattern = ctx.createPattern(temporaryPatternCanvas.canvas, "no-repeat");
10140    owner.canvasFactory.destroy(temporaryPatternCanvas);
10141    return pattern;
10142  }
10143}
10144class DummyShadingPattern extends BaseShadingPattern {
10145  getPattern() {
10146    return "hotpink";
10147  }
10148}
10149function getShadingPattern(IR) {
10150  switch (IR[0]) {
10151    case "RadialAxial":
10152      return new RadialAxialShadingPattern(IR);
10153    case "Mesh":
10154      return new MeshShadingPattern(IR);
10155    case "Dummy":
10156      return new DummyShadingPattern();
10157  }
10158  throw new Error(`Unknown IR type: ${IR[0]}`);
10159}
10160const PaintType = {
10161  COLORED: 1,
10162  UNCOLORED: 2
10163};
10164class TilingPattern {
10165  static MAX_PATTERN_SIZE = 3000;
10166  constructor(IR, ctx, canvasGraphicsFactory, baseTransform) {
10167    this.color = IR[1];
10168    this.operatorList = IR[2];
10169    this.matrix = IR[3];
10170    this.bbox = IR[4];
10171    this.xstep = IR[5];
10172    this.ystep = IR[6];
10173    this.paintType = IR[7];
10174    this.tilingType = IR[8];
10175    this.needsIsolation = IR[9] ?? true;
10176    this.ctx = ctx;
10177    this.canvasGraphicsFactory = canvasGraphicsFactory;
10178    this.baseTransform = baseTransform;
10179    this.patternBaseMatrix = this.matrix ? Util.transform(baseTransform, this.matrix) : baseTransform;
10180  }
10181  canSkipPatternCanvas([width, height, offsetX, offsetY]) {
10182    const [x0, y0, x1, y1] = this.bbox;
10183    const absXStep = Math.abs(this.xstep);
10184    const absYStep = Math.abs(this.ystep);
10185    if (width > absXStep + 1e-6 || height > absYStep + 1e-6) {
10186      return null;
10187    }
10188    const nXFirst = Math.floor((offsetX - x1) / absXStep) + 1;
10189    const nXLast = Math.ceil((offsetX + width - x0) / absXStep) - 1;
10190    const nYFirst = Math.floor((offsetY - y1) / absYStep) + 1;
10191    const nYLast = Math.ceil((offsetY + height - y0) / absYStep) - 1;
10192    return nXLast <= nXFirst && nYLast <= nYFirst ? [nXFirst, nYFirst] : null;
10193  }
10194  updatePatternDims(clippedBBox, dims) {
10195    const inv = Util.inverseTransform(this.patternBaseMatrix);
10196    const c1 = [clippedBBox[0], clippedBBox[1]];
10197    const c2 = [clippedBBox[2], clippedBBox[3]];
10198    Util.applyTransform(c1, inv);
10199    Util.applyTransform(c2, inv);
10200    dims[0] = Math.abs(c2[0] - c1[0]);
10201    dims[1] = Math.abs(c2[1] - c1[1]);
10202    dims[2] = Math.min(c1[0], c2[0]);
10203    dims[3] = Math.min(c1[1], c2[1]);
10204  }
10205  _renderTileCanvas(owner, opIdx, dimx, dimy) {
10206    const [x0, y0, x1, y1] = this.bbox;
10207    const tmpCanvas = owner.canvasFactory.create(dimx.size, dimy.size);
10208    const tmpCtx = tmpCanvas.context;
10209    const graphics = this.canvasGraphicsFactory.createCanvasGraphics(tmpCtx, opIdx);
10210    graphics.groupLevel = owner.groupLevel;
10211    this.setFillAndStrokeStyleToContext(graphics, this.paintType, this.color);
10212    tmpCtx.translate(-dimx.scale * x0, -dimy.scale * y0);
10213    graphics.transform(0, dimx.scale, 0, 0, dimy.scale, 0, 0);
10214    tmpCtx.save();
10215    graphics.dependencyTracker?.save();
10216    this.clipBbox(graphics, x0, y0, x1, y1);
10217    graphics.baseTransform = getCurrentTransform(graphics.ctx);
10218    graphics.executeOperatorList(this.operatorList);
10219    graphics.endDrawing();
10220    graphics.dependencyTracker?.restore();
10221    tmpCtx.restore();
10222    return tmpCanvas;
10223  }
10224  _getCombinedScales() {
10225    const scale = new Float32Array(2);
10226    Util.singularValueDecompose2dScale(this.matrix, scale);
10227    const [matrixScaleX, matrixScaleY] = scale;
10228    Util.singularValueDecompose2dScale(this.baseTransform, scale);
10229    return [matrixScaleX * scale[0], matrixScaleY * scale[1]];
10230  }
10231  drawPattern(owner, path, useEOFill = false, [n, m], opIdx) {
10232    const [x0, y0, x1, y1] = this.bbox;
10233    const dependencyTracker = owner.dependencyTracker;
10234    if (dependencyTracker) {
10235      owner.dependencyTracker = new CanvasNestedDependencyTracker(dependencyTracker, opIdx);
10236    }
10237    owner.save();
10238    if (useEOFill) {
10239      owner.ctx.clip(path, "evenodd");
10240    } else {
10241      owner.ctx.clip(path);
10242    }
10243    owner.ctx.setTransform(...this.patternBaseMatrix);
10244    owner.ctx.translate(n * this.xstep, m * this.ystep);
10245    if (this.needsIsolation || owner.ctx.globalAlpha !== 1 || owner.ctx.globalCompositeOperation !== "source-over" || owner.inSMaskMode) {
10246      const bboxWidth = x1 - x0;
10247      const bboxHeight = y1 - y0;
10248      const [combinedScaleX, combinedScaleY] = this._getCombinedScales();
10249      const dimx = this.getSizeAndScale(bboxWidth, this.ctx.canvas.width, combinedScaleX);
10250      const dimy = this.getSizeAndScale(bboxHeight, this.ctx.canvas.height, combinedScaleY);
10251      const tmpCanvas = this._renderTileCanvas(owner, opIdx, dimx, dimy);
10252      owner.ctx.drawImage(tmpCanvas.canvas, x0, y0, bboxWidth, bboxHeight);
10253      owner.canvasFactory.destroy(tmpCanvas);
10254    } else {
10255      this.setFillAndStrokeStyleToContext(owner, this.paintType, this.color);
10256      this.clipBbox(owner, x0, y0, x1, y1);
10257      owner.baseTransformStack.push(owner.baseTransform);
10258      owner.baseTransform = getCurrentTransform(owner.ctx);
10259      owner.executeOperatorList(this.operatorList);
10260      owner.baseTransform = owner.baseTransformStack.pop();
10261    }
10262    owner.restore();
10263    if (dependencyTracker) {
10264      owner.dependencyTracker = dependencyTracker;
10265    }
10266  }
10267  createPatternCanvas(owner, opIdx) {
10268    const [x0, y0, x1, y1] = this.bbox;
10269    const width = x1 - x0;
10270    const height = y1 - y0;
10271    let {
10272      xstep,
10273      ystep
10274    } = this;
10275    xstep = Math.abs(xstep);
10276    ystep = Math.abs(ystep);
10277    info("TilingType: " + this.tilingType);
10278    const [combinedScaleX, combinedScaleY] = this._getCombinedScales();
10279    let canvasWidth = width,
10280      canvasHeight = height,
10281      redrawHorizontally = false,
10282      redrawVertically = false;
10283    if (Math.ceil(xstep * combinedScaleX) >= Math.ceil(width * combinedScaleX)) {
10284      canvasWidth = xstep;
10285    } else {
10286      redrawHorizontally = true;
10287    }
10288    if (Math.ceil(ystep * combinedScaleY) >= Math.ceil(height * combinedScaleY)) {
10289      canvasHeight = ystep;
10290    } else {
10291      redrawVertically = true;
10292    }
10293    const dimx = this.getSizeAndScale(canvasWidth, this.ctx.canvas.width, combinedScaleX);
10294    const dimy = this.getSizeAndScale(canvasHeight, this.ctx.canvas.height, combinedScaleY);
10295    const tmpCanvas = this._renderTileCanvas(owner, opIdx, dimx, dimy);
10296    if (redrawHorizontally || redrawVertically) {
10297      const image = tmpCanvas.canvas;
10298      if (redrawHorizontally) {
10299        canvasWidth = xstep;
10300      }
10301      if (redrawVertically) {
10302        canvasHeight = ystep;
10303      }
10304      const dimx2 = this.getSizeAndScale(canvasWidth, this.ctx.canvas.width, combinedScaleX);
10305      const dimy2 = this.getSizeAndScale(canvasHeight, this.ctx.canvas.height, combinedScaleY);
10306      const xSize = dimx2.size;
10307      const ySize = dimy2.size;
10308      const tmpCanvas2 = owner.canvasFactory.create(xSize, ySize);
10309      const tmpCtx2 = tmpCanvas2.context;
10310      const ii = redrawHorizontally ? Math.floor(width / xstep) : 0;
10311      const jj = redrawVertically ? Math.floor(height / ystep) : 0;
10312      for (let i = 0; i <= ii; i++) {
10313        for (let j = 0; j <= jj; j++) {
10314          tmpCtx2.drawImage(image, xSize * i, ySize * j, xSize, ySize, 0, 0, xSize, ySize);
10315        }
10316      }
10317      owner.canvasFactory.destroy(tmpCanvas);
10318      return {
10319        canvas: tmpCanvas2.canvas,
10320        canvasEntry: tmpCanvas2,
10321        scaleX: dimx2.scale,
10322        scaleY: dimy2.scale,
10323        offsetX: x0,
10324        offsetY: y0
10325      };
10326    }
10327    return {
10328      canvas: tmpCanvas.canvas,
10329      canvasEntry: tmpCanvas,
10330      scaleX: dimx.scale,
10331      scaleY: dimy.scale,
10332      offsetX: x0,
10333      offsetY: y0
10334    };
10335  }
10336  getSizeAndScale(step, realOutputSize, scale) {
10337    const maxSize = Math.max(TilingPattern.MAX_PATTERN_SIZE, realOutputSize);
10338    let size = Math.ceil(step * scale);
10339    if (size >= maxSize) {
10340      size = maxSize;
10341    } else {
10342      scale = size / step;
10343    }
10344    return {
10345      scale,
10346      size
10347    };
10348  }
10349  clipBbox(graphics, x0, y0, x1, y1) {
10350    const bboxWidth = x1 - x0;
10351    const bboxHeight = y1 - y0;
10352    const clip = new Path2D();
10353    clip.rect(x0, y0, bboxWidth, bboxHeight);
10354    Util.axialAlignedBoundingBox([x0, y0, x1, y1], getCurrentTransform(graphics.ctx), graphics.current.minMax);
10355    graphics.ctx.clip(clip);
10356    graphics.current.updateClipFromPath();
10357  }
10358  setFillAndStrokeStyleToContext(graphics, paintType, color) {
10359    const context = graphics.ctx,
10360      current = graphics.current;
10361    current.patternFill = current.patternStroke = false;
10362    switch (paintType) {
10363      case PaintType.COLORED:
10364        const {
10365          fillStyle,
10366          strokeStyle
10367        } = this.ctx;
10368        context.fillStyle = current.fillColor = fillStyle;
10369        context.strokeStyle = current.strokeColor = strokeStyle;
10370        break;
10371      case PaintType.UNCOLORED:
10372        context.fillStyle = context.strokeStyle = color;
10373        current.fillColor = current.strokeColor = color;
10374        break;
10375      default:
10376        throw new FormatError(`Unsupported paint type: ${paintType}`);
10377    }
10378  }
10379  isModifyingCurrentTransform() {
10380    return false;
10381  }
10382  getPattern(ctx, owner, inverse, pathType, opIdx) {
10383    const matrix = pathType !== PathType.SHADING ? Util.transform(inverse, this.patternBaseMatrix) : inverse;
10384    const temporaryPatternCanvas = this.createPatternCanvas(owner, opIdx);
10385    let domMatrix = new DOMMatrix(matrix);
10386    domMatrix = domMatrix.translate(temporaryPatternCanvas.offsetX, temporaryPatternCanvas.offsetY);
10387    domMatrix = domMatrix.scale(1 / temporaryPatternCanvas.scaleX, 1 / temporaryPatternCanvas.scaleY);
10388    const pattern = ctx.createPattern(temporaryPatternCanvas.canvas, "repeat");
10389    owner.canvasFactory.destroy(temporaryPatternCanvas.canvasEntry);
10390    pattern.setTransform(domMatrix);
10391    return pattern;
10392  }
10393}
10394
10395;// ./src/display/canvas.js
10396
10397
10398
10399
10400
10401
10402const MIN_FONT_SIZE = 16;
10403const MAX_FONT_SIZE = 100;
10404const EXECUTION_TIME = 15;
10405const EXECUTION_STEPS = 10;
10406const FULL_CHUNK_HEIGHT = 16;
10407const 
10407SCALE_MATRIX = new DOMMatrix()
vendor: 64,347 bytes, lines 10407-12169
10407;
10408const XY = new Float32Array(2);
10409function mirrorContextOperations(ctx, destCtx) {
10410  if (ctx._removeMirroring) {
10411    throw new Error("Context is already forwarding operations.");
10412  }
10413  const originalMethods = new Map();
10414  for (const name of ["save", "restore", "rotate", "scale", "translate", "transform", "setTransform", "resetTransform", "clip", "moveTo", "lineTo", "bezierCurveTo", "quadraticCurveTo", "arc", "arcTo", "ellipse", "rect", "roundRect", "closePath", "beginPath"]) {
10415    const original = ctx[name];
10416    if (typeof original !== "function" || typeof destCtx[name] !== "function") {
10417      continue;
10418    }
10419    originalMethods.set(name, original);
10420    ctx[name] = function (...args) {
10421      destCtx[name](...args);
10422      return original.apply(this, args);
10423    };
10424  }
10425  ctx._removeMirroring = () => {
10426    for (const [name, original] of originalMethods) {
10427      ctx[name] = original;
10428    }
10429    delete ctx._removeMirroring;
10430  };
10431}
10432function drawImageAtIntegerCoords(ctx, srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH) {
10433  const [a, b, c, d, tx, ty] = getCurrentTransform(ctx);
10434  if (b === 0 && c === 0) {
10435    const tlX = destX * a + tx;
10436    const rTlX = Math.round(tlX);
10437    const tlY = destY * d + ty;
10438    const rTlY = Math.round(tlY);
10439    const brX = (destX + destW) * a + tx;
10440    const rWidth = Math.abs(Math.round(brX) - rTlX) || 1;
10441    const brY = (destY + destH) * d + ty;
10442    const rHeight = Math.abs(Math.round(brY) - rTlY) || 1;
10443    ctx.setTransform(Math.sign(a), 0, 0, Math.sign(d), rTlX, rTlY);
10444    ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rWidth, rHeight);
10445    ctx.setTransform(a, b, c, d, tx, ty);
10446    return [rWidth, rHeight];
10447  }
10448  if (a === 0 && d === 0) {
10449    const tlX = destY * c + tx;
10450    const rTlX = Math.round(tlX);
10451    const tlY = destX * b + ty;
10452    const rTlY = Math.round(tlY);
10453    const brX = (destY + destH) * c + tx;
10454    const rWidth = Math.abs(Math.round(brX) - rTlX) || 1;
10455    const brY = (destX + destW) * b + ty;
10456    const rHeight = Math.abs(Math.round(brY) - rTlY) || 1;
10457    ctx.setTransform(0, Math.sign(b), Math.sign(c), 0, rTlX, rTlY);
10458    ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, 0, 0, rHeight, rWidth);
10459    ctx.setTransform(a, b, c, d, tx, ty);
10460    return [rHeight, rWidth];
10461  }
10462  ctx.drawImage(srcImg, srcX, srcY, srcW, srcH, destX, destY, destW, destH);
10463  const scaleX = Math.hypot(a, b);
10464  const scaleY = Math.hypot(c, d);
10465  return [scaleX * destW, scaleY * destH];
10466}
10467class CanvasExtraState {
10468  alphaIsShape = false;
10469  fontSize = 0;
10470  fontSizeScale = 1;
10471  textMatrix = null;
10472  textMatrixScale = 1;
10473  fontMatrix = FONT_IDENTITY_MATRIX;
10474  leading = 0;
10475  x = 0;
10476  y = 0;
10477  lineX = 0;
10478  lineY = 0;
10479  charSpacing = 0;
10480  wordSpacing = 0;
10481  textHScale = 1;
10482  textRenderingMode = TextRenderingMode.FILL;
10483  textRise = 0;
10484  fillColor = "#000000";
10485  strokeColor = "#000000";
10486  tilingPatternDims = null;
10487  patternFill = false;
10488  patternStroke = false;
10489  fillAlpha = 1;
10490  strokeAlpha = 1;
10491  lineWidth = 1;
10492  activeSMask = null;
10493  transferMaps = "none";
10494  minMax = F32_BBOX_INIT.slice();
10495  constructor(width, height) {
10496    this.clipBox = new Float32Array([0, 0, width, height]);
10497  }
10498  clone() {
10499    const clone = Object.create(this);
10500    clone.clipBox = this.clipBox.slice();
10501    clone.minMax = this.minMax.slice();
10502    clone.tilingPatternDims = this.tilingPatternDims?.slice();
10503    return clone;
10504  }
10505  getPathBoundingBox(pathType = PathType.FILL, transform = null) {
10506    const box = this.minMax.slice();
10507    if (pathType === PathType.STROKE) {
10508      if (!transform) {
10509        unreachable("Stroke bounding box must include transform.");
10510      }
10511      Util.singularValueDecompose2dScale(transform, XY);
10512      const xStrokePad = XY[0] * this.lineWidth / 2;
10513      const yStrokePad = XY[1] * this.lineWidth / 2;
10514      box[0] -= xStrokePad;
10515      box[1] -= yStrokePad;
10516      box[2] += xStrokePad;
10517      box[3] += yStrokePad;
10518    }
10519    return box;
10520  }
10521  updateClipFromPath() {
10522    const intersect = Util.intersect(this.clipBox, this.getPathBoundingBox());
10523    this.startNewPathAndClipBox(intersect || [0, 0, 0, 0]);
10524  }
10525  isEmptyClip() {
10526    return this.minMax[0] === Infinity;
10527  }
10528  startNewPathAndClipBox(box) {
10529    this.clipBox.set(box, 0);
10530    this.minMax.set(F32_BBOX_INIT, 0);
10531  }
10532  getClippedPathBoundingBox(pathType = PathType.FILL, transform = null) {
10533    return Util.intersect(this.clipBox, this.getPathBoundingBox(pathType, transform));
10534  }
10535}
10536function putBinaryImageData(ctx, imgData) {
10537  const {
10538    width,
10539    height,
10540    kind
10541  } = imgData;
10542  const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
10543  const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
10544  const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
10545  const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
10546  let srcPos = 0;
10547  const src = imgData.data;
10548  const dest = chunkImgData.data;
10549  let i;
10550  if (kind === ImageKind.GRAYSCALE_1BPP) {
10551    for (i = 0; i < totalChunks; i++) {
10552      ({
10553        srcPos
10554      } = convertBlackAndWhiteToRGBA({
10555        src,
10556        srcPos,
10557        dest,
10558        width,
10559        height: i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight
10560      }));
10561      ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
10562    }
10563  } else if (kind === ImageKind.RGBA_32BPP) {
10564    let j = 0;
10565    let elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4;
10566    for (i = 0; i < fullChunks; i++) {
10567      dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
10568      srcPos += elemsInThisChunk;
10569      ctx.putImageData(chunkImgData, 0, j);
10570      j += FULL_CHUNK_HEIGHT;
10571    }
10572    if (i < totalChunks) {
10573      elemsInThisChunk = width * partialChunkHeight * 4;
10574      dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
10575      ctx.putImageData(chunkImgData, 0, j);
10576    }
10577  } else if (kind === ImageKind.RGB_24BPP) {
10578    for (i = 0; i < totalChunks; i++) {
10579      ({
10580        srcPos
10581      } = convertRGBToRGBA({
10582        src,
10583        srcPos,
10584        dest: new Uint32Array(dest.buffer),
10585        width,
10586        height: i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight
10587      }));
10588      ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
10589    }
10590  } else {
10591    throw new Error(`bad image kind: ${kind}`);
10592  }
10593}
10594function putBinaryImageMask(ctx, imgData) {
10595  if (imgData.bitmap) {
10596    ctx.drawImage(imgData.bitmap, 0, 0);
10597    return;
10598  }
10599  const {
10600    width,
10601    height
10602  } = imgData;
10603  const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
10604  const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
10605  const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
10606  const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
10607  let srcPos = 0;
10608  const src = imgData.data;
10609  const dest = chunkImgData.data;
10610  for (let i = 0; i < totalChunks; i++) {
10611    ({
10612      srcPos
10613    } = convertBlackAndWhiteToRGBA({
10614      src,
10615      srcPos,
10616      dest,
10617      width,
10618      height: i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight,
10619      nonBlackColor: 0
10620    }));
10621    ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
10622  }
10623}
10624function copyCtxState(sourceCtx, destCtx) {
10625  const properties = ["strokeStyle", "fillStyle", "fillRule", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "globalCompositeOperation", "font", "filter"];
10626  for (const property of properties) {
10627    if (sourceCtx[property] !== undefined) {
10628      destCtx[property] = sourceCtx[property];
10629    }
10630  }
10631  if (sourceCtx.setLineDash !== undefined) {
10632    destCtx.setLineDash(sourceCtx.getLineDash());
10633    destCtx.lineDashOffset = sourceCtx.lineDashOffset;
10634  }
10635}
10636function resetCtxToDefault(ctx) {
10637  ctx.strokeStyle = ctx.fillStyle = "#000000";
10638  ctx.fillRule = "nonzero";
10639  ctx.globalAlpha = 1;
10640  ctx.lineWidth = 1;
10641  ctx.lineCap = "butt";
10642  ctx.lineJoin = "miter";
10643  ctx.miterLimit = 10;
10644  ctx.globalCompositeOperation = "source-over";
10645  ctx.font = "10px sans-serif";
10646  if (ctx.setLineDash !== undefined) {
10647    ctx.setLineDash([]);
10648    ctx.lineDashOffset = 0;
10649  }
10650  const {
10651    filter
10652  } = ctx;
10653  if (filter !== "none" && filter !== "") {
10654    ctx.filter = "none";
10655  }
10656}
10657function getImageSmoothingEnabled(transform, interpolate) {
10658  if (interpolate) {
10659    return true;
10660  }
10661  Util.singularValueDecompose2dScale(transform, XY);
10662  const actualScale = Math.fround(OutputScale.pixelRatio * PixelsPerInch.PDF_TO_CSS_UNITS);
10663  return XY[0] <= actualScale && XY[1] <= actualScale;
10664}
10665const LINE_CAP_STYLES = ["butt", "round", "square"];
10666const LINE_JOIN_STYLES = ["miter", "round", "bevel"];
10667const NORMAL_CLIP = {};
10668const EO_CLIP = {};
10669class CanvasGraphics {
10670  #knockoutGroupLevel = 0;
10671  #knockoutElementDepth = 0;
10672  #knockoutTempCanvasEntry = null;
10673  #knockoutSavedCtx = null;
10674  #knockoutSavedSMaskCtx = null;
10675  #knockoutSavedGCO = null;
10676  #knockoutElementAlpha = 1;
10677  #knockoutFilterCache;
10678  #knockoutElementGroupMeta = null;
10679  #groupStackMeta = [];
10680  constructor(canvasCtx, commonObjs, objs, canvasFactory, filterFactory, {
10681    optionalContentConfig,
10682    markedContentStack = null
10683  }, annotationCanvasMap, pageColors, dependencyTracker, imagesTracker) {
10684    this.ctx = canvasCtx;
10685    this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height);
10686    this.stateStack = [];
10687    this.pendingClip = null;
10688    this.pendingEOFill = false;
10689    this.commonObjs = commonObjs;
10690    this.objs = objs;
10691    this.canvasFactory = canvasFactory;
10692    this.filterFactory = filterFactory;
10693    this.groupStack = [];
10694    this.baseTransform = null;
10695    this.baseTransformStack = [];
10696    this.groupLevel = 0;
10697    this.smaskStack = [];
10698    this.tempSMask = null;
10699    this.smaskGroupCanvases = [];
10700    this.smaskPreparedEntry = null;
10701    this.smaskPreparedFor = null;
10702    this.smaskPreparedOffsetX = 0;
10703    this.smaskPreparedOffsetY = 0;
10704    this.smaskPreparedOOBAlpha = null;
10705    this.suspendedCtx = null;
10706    this.contentVisible = true;
10707    this.markedContentStack = markedContentStack || [];
10708    this.optionalContentConfig = optionalContentConfig;
10709    this.cachedPatterns = new Map();
10710    this.annotationCanvasMap = annotationCanvasMap;
10711    this.viewportScale = 1;
10712    this.outputScaleX = 1;
10713    this.outputScaleY = 1;
10714    this.pageColors = pageColors;
10715    this._cachedScaleForStroking = [-1, 0];
10716    this._cachedGetSinglePixelWidth = null;
10717    this._cachedBitmapsMap = new Map();
10718    this.dependencyTracker = dependencyTracker ?? null;
10719    this.imagesTracker = imagesTracker ?? null;
10720  }
10721  getObject(opIdx, data, fallback = null) {
10722    if (typeof data === "string") {
10723      this.dependencyTracker?.recordNamedDependency(opIdx, data);
10724      return data.startsWith("g_") ? this.commonObjs.get(data) : this.objs.get(data);
10725    }
10726    return fallback;
10727  }
10728  beginDrawing({
10729    transform,
10730    viewport,
10731    transparency = false,
10732    background = null
10733  }) {
10734    const width = this.ctx.canvas.width;
10735    const height = this.ctx.canvas.height;
10736    const savedFillStyle = this.ctx.fillStyle;
10737    this.ctx.fillStyle = background || "#ffffff";
10738    this.ctx.fillRect(0, 0, width, height);
10739    this.ctx.fillStyle = savedFillStyle;
10740    if (transparency) {
10741      const transparentCanvas = this.transparentCanvasEntry = this.canvasFactory.create(width, height);
10742      this.compositeCtx = this.ctx;
10743      ({
10744        canvas: this.transparentCanvas,
10745        context: this.ctx
10746      } = transparentCanvas);
10747      this.ctx.save();
10748      this.ctx.transform(...getCurrentTransform(this.compositeCtx));
10749    }
10750    this.ctx.save();
10751    resetCtxToDefault(this.ctx);
10752    if (transform) {
10753      this.ctx.transform(...transform);
10754      this.outputScaleX = transform[0];
10755      this.outputScaleY = transform[3];
10756    }
10757    this.ctx.transform(...viewport.transform);
10758    this.viewportScale = viewport.scale;
10759    this.baseTransform = getCurrentTransform(this.ctx);
10760  }
10761  executeOperatorList(operatorList, executionStartIdx, continueCallback, stepper, operationsFilter) {
10762    const argsArray = operatorList.argsArray;
10763    const fnArray = operatorList.fnArray;
10764    let i = executionStartIdx || 0;
10765    const argsArrayLen = argsArray.length;
10766    if (argsArrayLen === i) {
10767      return i;
10768    }
10769    const chunkOperations = argsArrayLen - i > EXECUTION_STEPS && typeof continueCallback === "function";
10770    const endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;
10771    let steps = 0;
10772    const commonObjs = this.commonObjs;
10773    const objs = this.objs;
10774    let fnId, fnArgs;
10775    while (true) {
10776      if (stepper !== undefined) {
10777        if (i === stepper.nextBreakPoint) {
10778          stepper.breakIt(i, continueCallback);
10779          return i;
10780        }
10781        if (stepper.shouldSkip(i)) {
10782          if (++i === argsArrayLen) {
10783            return i;
10784          }
10785          continue;
10786        }
10787      }
10788      if (!operationsFilter || operationsFilter(i)) {
10789        fnId = fnArray[i];
10790        fnArgs = argsArray[i] ?? null;
10791        if (fnId !== OPS.dependency) {
10792          if (fnArgs === null) {
10793            this[fnId](i);
10794          } else {
10795            this[fnId](i, ...fnArgs);
10796          }
10797        } else {
10798          for (const depObjId of fnArgs) {
10799            this.dependencyTracker?.recordNamedData(depObjId, i);
10800            const objsPool = depObjId.startsWith("g_") ? commonObjs : objs;
10801            if (!objsPool.has(depObjId)) {
10802              objsPool.get(depObjId, continueCallback);
10803              return i;
10804            }
10805          }
10806        }
10807      }
10808      i++;
10809      if (i === argsArrayLen) {
10810        return i;
10811      }
10812      if (chunkOperations && ++steps > EXECUTION_STEPS) {
10813        if (Date.now() > endTime) {
10814          continueCallback();
10815          return i;
10816        }
10817        steps = 0;
10818      }
10819    }
10820  }
10821  #restoreInitialState() {
10822    while (this.stateStack.length || this.inSMaskMode) {
10823      this.restore();
10824    }
10825    this.current.activeSMask = null;
10826    this.ctx.restore();
10827    if (this.transparentCanvas) {
10828      this.ctx = this.compositeCtx;
10829      this.ctx.save();
10830      this.ctx.setTransform(1, 0, 0, 1, 0, 0);
10831      this.ctx.drawImage(this.transparentCanvas, 0, 0);
10832      this.ctx.restore();
10833      this.canvasFactory.destroy(this.transparentCanvasEntry);
10834      this.transparentCanvas = null;
10835      this.transparentCanvasEntry = null;
10836    }
10837  }
10838  endDrawing() {
10839    this.#restoreInitialState();
10840    for (const canvas of this.smaskGroupCanvases) {
10841      this.canvasFactory.destroy(canvas);
10842    }
10843    this.smaskGroupCanvases.length = 0;
10844    this._clearPreparedSMask();
10845    this.tempSMask = null;
10846    this.smaskStack.length = 0;
10847    for (const meta of this.#groupStackMeta) {
10848      this.#destroyKnockoutPools(meta);
10849    }
10850    this.#groupStackMeta.length = 0;
10851    this.#knockoutTempCanvasEntry = null;
10852    this.#knockoutSavedCtx = null;
10853    this.#knockoutSavedSMaskCtx = null;
10854    this.#knockoutSavedGCO = null;
10855    this.#knockoutElementAlpha = 1;
10856    this.#knockoutElementGroupMeta = null;
10857    this.#knockoutElementDepth = 0;
10858    this.#knockoutGroupLevel = 0;
10859    this.cachedPatterns.clear();
10860    for (const cache of this._cachedBitmapsMap.values()) {
10861      for (const canvas of cache.values()) {
10862        if (typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement) {
10863          canvas.width = canvas.height = 0;
10864        }
10865      }
10866      cache.clear();
10867    }
10868    this._cachedBitmapsMap.clear();
10869    this.#drawFilter();
10870  }
10871  #drawFilter() {
10872    if (this.pageColors) {
10873      const hcmFilterId = this.filterFactory.addHCMFilter(this.pageColors.foreground, this.pageColors.background);
10874      if (hcmFilterId !== "none") {
10875        const savedFilter = this.ctx.filter;
10876        this.ctx.filter = hcmFilterId;
10877        this.ctx.drawImage(this.ctx.canvas, 0, 0);
10878        this.ctx.filter = savedFilter;
10879      }
10880    }
10881  }
10882  _scaleImage(img, inverseTransform) {
10883    const width = img.width ?? img.displayWidth;
10884    const height = img.height ?? img.displayHeight;
10885    const widthScale = Math.max(Math.hypot(inverseTransform[0], inverseTransform[1]), 1);
10886    const heightScale = Math.max(Math.hypot(inverseTransform[2], inverseTransform[3]), 1);
10887    const scaleSteps = [];
10888    let ws = widthScale,
10889      hs = heightScale,
10890      pw = width,
10891      ph = height;
10892    while (ws > 2 && pw > 1 || hs > 2 && ph > 1) {
10893      let nw = pw,
10894        nh = ph;
10895      if (ws > 2 && pw > 1) {
10896        nw = Math.ceil(pw / 2);
10897        ws /= pw / nw;
10898      }
10899      if (hs > 2 && ph > 1) {
10900        nh = Math.ceil(ph / 2);
10901        hs /= ph / nh;
10902      }
10903      scaleSteps.push({
10904        newWidth: nw,
10905        newHeight: nh
10906      });
10907      pw = nw;
10908      ph = nh;
10909    }
10910    if (scaleSteps.length === 0) {
10911      return {
10912        img,
10913        paintWidth: width,
10914        paintHeight: height,
10915        tmpCanvas: null
10916      };
10917    }
10918    if (scaleSteps.length === 1) {
10919      const {
10920        newWidth,
10921        newHeight
10922      } = scaleSteps[0];
10923      const tmpCanvas = this.canvasFactory.create(newWidth, newHeight);
10924      tmpCanvas.context.drawImage(img, 0, 0, width, height, 0, 0, newWidth, newHeight);
10925      return {
10926        img: tmpCanvas.canvas,
10927        paintWidth: newWidth,
10928        paintHeight: newHeight,
10929        tmpCanvas
10930      };
10931    }
10932    let readEntry = this.canvasFactory.create(1, 1);
10933    let writeEntry = this.canvasFactory.create(1, 1);
10934    let paintWidth = width,
10935      paintHeight = height;
10936    let source = img;
10937    for (const {
10938      newWidth,
10939      newHeight
10940    } of scaleSteps) {
10941      this.canvasFactory.reset(writeEntry, newWidth, newHeight);
10942      writeEntry.context.drawImage(source, 0, 0, paintWidth, paintHeight, 0, 0, newWidth, newHeight);
10943      [readEntry, writeEntry] = [writeEntry, readEntry];
10944      source = readEntry.canvas;
10945      paintWidth = newWidth;
10946      paintHeight = newHeight;
10947    }
10948    this.canvasFactory.destroy(writeEntry);
10949    return {
10950      img: readEntry.canvas,
10951      paintWidth,
10952      paintHeight,
10953      tmpCanvas: readEntry
10954    };
10955  }
10956  _createMaskCanvas(opIdx, img) {
10957    const ctx = this.ctx;
10958    const {
10959      width,
10960      height
10961    } = img;
10962    const fillColor = this.current.fillColor;
10963    const isPatternFill = this.current.patternFill;
10964    const currentTransform = getCurrentTransform(ctx);
10965    let cache, cacheKey, scaled, maskCanvas;
10966    if ((img.bitmap || img.data) && img.count > 1) {
10967      const mainKey = img.bitmap || img.data.buffer;
10968      cacheKey = JSON.stringify(isPatternFill ? currentTransform : [currentTransform.slice(0, 4), fillColor]);
10969      cache = this._cachedBitmapsMap.getOrInsertComputed(mainKey, makeMap);
10970      const cachedImage = cache.get(cacheKey);
10971      if (cachedImage && !isPatternFill) {
10972        const offsetX = Math.round(Math.min(currentTransform[0], currentTransform[2]) + currentTransform[4]);
10973        const offsetY = Math.round(Math.min(currentTransform[1], currentTransform[3]) + currentTransform[5]);
10974        this.dependencyTracker?.recordDependencies(opIdx, Dependencies.transformAndFill);
10975        return {
10976          canvas: cachedImage,
10977          offsetX,
10978          offsetY
10979        };
10980      }
10981      scaled = cachedImage;
10982    }
10983    if (!scaled) {
10984      maskCanvas = this.canvasFactory.create(width, height);
10985      putBinaryImageMask(maskCanvas.context, img);
10986    }
10987    let maskToCanvas = Util.transform(currentTransform, [1 / width, 0, 0, -1 / height, 0, 0]);
10988    maskToCanvas = Util.transform(maskToCanvas, [1, 0, 0, 1, 0, -height]);
10989    const minMax = F32_BBOX_INIT.slice();
10990    Util.axialAlignedBoundingBox([0, 0, width, height], maskToCanvas, minMax);
10991    const [minX, minY, maxX, maxY] = minMax;
10992    const drawnWidth = Math.round(maxX - minX) || 1;
10993    const drawnHeight = Math.round(maxY - minY) || 1;
10994    const fillCanvas = this.canvasFactory.create(drawnWidth, drawnHeight);
10995    const fillCtx = fillCanvas.context;
10996    const offsetX = minX;
10997    const offsetY = minY;
10998    fillCtx.translate(-offsetX, -offsetY);
10999    fillCtx.transform(...maskToCanvas);
11000    let scaledEntry = null;
11001    if (!scaled) {
11002      const scaleResult = this._scaleImage(maskCanvas.canvas, getCurrentTransformInverse(fillCtx));
11003      scaled = scaleResult.img;
11004      scaledEntry = scaleResult.tmpCanvas;
11005      if (scaled !== maskCanvas.canvas) {
11006        this.canvasFactory.destroy(maskCanvas);
11007        maskCanvas = null;
11008      }
11009      if (cache && isPatternFill) {
11010        cache.set(cacheKey, scaled);
11011        scaledEntry = null;
11012        maskCanvas = null;
11013      }
11014    }
11015    fillCtx.imageSmoothingEnabled = getImageSmoothingEnabled(getCurrentTransform(fillCtx), img.interpolate);
11016    drawImageAtIntegerCoords(fillCtx, scaled, 0, 0, scaled.width, scaled.height, 0, 0, width, height);
11017    if (scaledEntry) {
11018      this.canvasFactory.destroy(scaledEntry);
11019    }
11020    if (maskCanvas) {
11021      this.canvasFactory.destroy(maskCanvas);
11022    }
11023    fillCtx.globalCompositeOperation = "source-in";
11024    const inverse = Util.transform(getCurrentTransformInverse(fillCtx), [1, 0, 0, 1, -offsetX, -offsetY]);
11025    fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx, this, inverse, PathType.FILL, opIdx) : fillColor;
11026    fillCtx.fillRect(0, 0, width, height);
11027    if (cache && !isPatternFill) {
11028      cache.set(cacheKey, fillCanvas.canvas);
11029    }
11030    this.dependencyTracker?.recordDependencies(opIdx, Dependencies.transformAndFill);
11031    return {
11032      canvas: fillCanvas.canvas,
11033      canvasEntry: cache && !isPatternFill ? null : fillCanvas,
11034      offsetX: Math.round(offsetX),
11035      offsetY: Math.round(offsetY)
11036    };
11037  }
11038  setLineWidth(opIdx, width) {
11039    this.dependencyTracker?.recordSimpleData("lineWidth", opIdx);
11040    if (width !== this.current.lineWidth) {
11041      this._cachedScaleForStroking[0] = -1;
11042    }
11043    this.current.lineWidth = width;
11044    this.ctx.lineWidth = width;
11045  }
11046  setLineCap(opIdx, style) {
11047    this.dependencyTracker?.recordSimpleData("lineCap", opIdx);
11048    this.ctx.lineCap = LINE_CAP_STYLES[style];
11049  }
11050  setLineJoin(opIdx, style) {
11051    this.dependencyTracker?.recordSimpleData("lineJoin", opIdx);
11052    this.ctx.lineJoin = LINE_JOIN_STYLES[style];
11053  }
11054  setMiterLimit(opIdx, limit) {
11055    this.dependencyTracker?.recordSimpleData("miterLimit", opIdx);
11056    this.ctx.miterLimit = limit;
11057  }
11058  setDash(opIdx, dashArray, dashPhase) {
11059    this.dependencyTracker?.recordSimpleData("dash", opIdx);
11060    const ctx = this.ctx;
11061    if (ctx.setLineDash !== undefined) {
11062      ctx.setLineDash(dashArray);
11063      ctx.lineDashOffset = dashPhase;
11064    }
11065  }
11066  setRenderingIntent(opIdx, intent) {}
11067  setFlatness(opIdx, flatness) {}
11068  setGState(opIdx, states) {
11069    for (const [key, value] of states) {
11070      switch (key) {
11071        case "LW":
11072          this.setLineWidth(opIdx, value);
11073          break;
11074        case "LC":
11075          this.setLineCap(opIdx, value);
11076          break;
11077        case "LJ":
11078          this.setLineJoin(opIdx, value);
11079          break;
11080        case "ML":
11081          this.setMiterLimit(opIdx, value);
11082          break;
11083        case "D":
11084          this.setDash(opIdx, value[0], value[1]);
11085          break;
11086        case "RI":
11087          this.setRenderingIntent(opIdx, value);
11088          break;
11089        case "FL":
11090          this.setFlatness(opIdx, value);
11091          break;
11092        case "Font":
11093          this.setFont(opIdx, value[0], value[1]);
11094          break;
11095        case "CA":
11096          this.dependencyTracker?.recordSimpleData("strokeAlpha", opIdx);
11097          this.current.strokeAlpha = value;
11098          break;
11099        case "ca":
11100          this.dependencyTracker?.recordSimpleData("fillAlpha", opIdx);
11101          this.ctx.globalAlpha = this.current.fillAlpha = value;
11102          break;
11103        case "BM":
11104          this.dependencyTracker?.recordSimpleData("globalCompositeOperation", opIdx);
11105          this.ctx.globalCompositeOperation = value;
11106          break;
11107        case "SMask":
11108          this.dependencyTracker?.recordSimpleData("SMask", opIdx);
11109          this.current.activeSMask = value ? this.tempSMask : null;
11110          if (this.current.activeSMask) {
11111            this.current.activeSMask.blendMode = this.ctx.globalCompositeOperation;
11112          }
11113          this.tempSMask = null;
11114          this.checkSMaskState(opIdx);
11115          break;
11116        case "TR":
11117          this.dependencyTracker?.recordSimpleData("filter", opIdx);
11118          this.ctx.filter = this.current.transferMaps = this.filterFactory.addFilter(value);
11119          break;
11120      }
11121    }
11122  }
11123  get inSMaskMode() {
11124    return !!this.suspendedCtx;
11125  }
11126  _clearPreparedSMask() {
11127    if (this.smaskPreparedEntry) {
11128      this.canvasFactory.destroy(this.smaskPreparedEntry);
11129      this.smaskPreparedEntry = null;
11130    }
11131    this.smaskPreparedFor = null;
11132    this.smaskPreparedOffsetX = 0;
11133    this.smaskPreparedOffsetY = 0;
11134    this.smaskPreparedOOBAlpha = null;
11135  }
11136  _ensurePreparedSMask(smask) {
11137    if (smask === this.smaskPreparedFor) {
11138      return;
11139    }
11140    this._clearPreparedSMask();
11141    this._prepareSMaskCanvas(smask);
11142  }
11143  checkSMaskState(opIdx) {
11144    const inSMaskMode = this.inSMaskMode;
11145    if (this.current.activeSMask && !inSMaskMode) {
11146      this.beginSMaskMode(opIdx);
11147    } else if (!this.current.activeSMask && inSMaskMode) {
11148      this.endSMaskMode();
11149    } else if (this.current.activeSMask && inSMaskMode) {
11150      this._ensurePreparedSMask(this.current.activeSMask);
11151    }
11152  }
11153  _prepareSMaskCanvas(smask) {
11154    const {
11155      canvas: maskCanvas,
11156      subtype,
11157      backdrop,
11158      transferMap
11159    } = smask;
11160    const hasFilter = subtype === "Luminosity" || subtype === "Alpha" && transferMap;
11161    if (!hasFilter && !(subtype === "Luminosity" && backdrop)) {
11162      this.smaskPreparedFor = smask;
11163      return;
11164    }
11165    let filteredOOBAlpha;
11166    if (subtype === "Luminosity" && backdrop) {
11167      const [r, g, b] = getRGBA(backdrop);
11168      const inputAlpha = Math.round(0.3 * r + 0.59 * g + 0.11 * b);
11169      filteredOOBAlpha = transferMap?.[inputAlpha] ?? inputAlpha;
11170    } else {
11171      filteredOOBAlpha = transferMap?.[0] ?? 0;
11172    }
11173    const SMASK_LAYER_TO_MASK_AREA_RATIO = 4;
11174    const {
11175      width: layerW,
11176      height: layerH
11177    } = this.ctx.canvas;
11178    const maskArea = maskCanvas.width * maskCanvas.height;
11179    const useLayerSize = layerW * layerH < SMASK_LAYER_TO_MASK_AREA_RATIO * maskArea;
11180    const filterSpec = hasFilter ? {
11181      url: subtype === "Alpha" ? this.filterFactory.addAlphaFilter(transferMap) : this.filterFactory.addLuminosityFilter(transferMap),
11182      subtype,
11183      transferMap
11184    } : null;
11185    const bakedBackdrop = subtype === "Luminosity" ? backdrop : null;
11186    let preparedEntry, offsetX, offsetY;
11187    if (useLayerSize) {
11188      preparedEntry = this._bakeSMaskCanvas(maskCanvas, smask.offsetX, smask.offsetY, layerW, layerH, bakedBackdrop, filterSpec);
11189      offsetX = 0;
11190      offsetY = 0;
11191    } else {
11192      preparedEntry = this._bakeSMaskCanvas(maskCanvas, 0, 0, maskCanvas.width, maskCanvas.height, bakedBackdrop, filterSpec);
11193      offsetX = smask.offsetX;
11194      offsetY = smask.offsetY;
11195    }
11196    this.smaskPreparedEntry = preparedEntry;
11197    this.smaskPreparedFor = smask;
11198    this.smaskPreparedOffsetX = offsetX;
11199    this.smaskPreparedOffsetY = offsetY;
11200    this.smaskPreparedOOBAlpha = !useLayerSize && filteredOOBAlpha !== 0 ? filteredOOBAlpha : null;
11201  }
11202  _bakeSMaskCanvas(maskCanvas, drawX, drawY, w, h, backdrop, filterSpec) {
11203    if (!backdrop && !filterSpec) {
11204      unreachable("_bakeSMaskCanvas with neither backdrop nor filter");
11205    }
11206    const srcEntry = this.canvasFactory.create(w, h);
11207    const sCtx = srcEntry.context;
11208    sCtx.drawImage(maskCanvas, drawX, drawY);
11209    if (backdrop) {
11210      sCtx.globalCompositeOperation = "destination-atop";
11211      sCtx.fillStyle = backdrop;
11212      sCtx.fillRect(0, 0, w, h);
11213    }
11214    if (!filterSpec) {
11215      return srcEntry;
11216    }
11217    const preparedEntry = this.canvasFactory.create(w, h);
11218    const pCtx = preparedEntry.context;
11219    pCtx.filter = filterSpec.url;
11220    const filterApplied = FeatureTest.isCanvasFilterSupported && pCtx.filter !== "none" && pCtx.filter !== "";
11221    pCtx.drawImage(srcEntry.canvas, 0, 0);
11222    if (FeatureTest.isCanvasFilterSupported) {
11223      pCtx.filter = "none";
11224    }
11225    if (!filterApplied) {
11226      const img = pCtx.getImageData(0, 0, w, h);
11227      const {
11228        data
11229      } = img;
11230      const {
11231        transferMap
11232      } = filterSpec;
11233      if (filterSpec.subtype === "Luminosity") {
11234        for (let i = 0, ii = data.length; i < ii; i += 4) {
11235          const a = 0.3 * data[i] + 0.59 * data[i + 1] + 0.11 * data[i + 2] + 0.5 | 0;
11236          data[i] = data[i + 1] = data[i + 2] = 0;
11237          data[i + 3] = transferMap?.[a] ?? a;
11238        }
11239      } else {
11240        for (let i = 3, ii = data.length; i < ii; i += 4) {
11241          data[i] = transferMap[data[i]];
11242        }
11243      }
11244      pCtx.putImageData(img, 0, 0);
11245    }
11246    this.canvasFactory.destroy(srcEntry);
11247    return preparedEntry;
11248  }
11249  beginSMaskMode(opIdx) {
11250    if (this.inSMaskMode) {
11251      throw new Error("beginSMaskMode called while already in smask mode");
11252    }
11253    const {
11254      width: drawnWidth,
11255      height: drawnHeight
11256    } = this.ctx.canvas;
11257    const scratchCanvas = this.canvasFactory.create(drawnWidth, drawnHeight);
11258    this.smaskScratchCanvas = scratchCanvas;
11259    this.suspendedCtx = this.ctx;
11260    const ctx = this.ctx = scratchCanvas.context;
11261    ctx.setTransform(this.suspendedCtx.getTransform());
11262    copyCtxState(this.suspendedCtx, ctx);
11263    mirrorContextOperations(ctx, this.suspendedCtx);
11264    this._ensurePreparedSMask(this.current.activeSMask);
11265    this.setGState(opIdx, [["BM", "source-over"]]);
11266  }
11267  endSMaskMode() {
11268    if (!this.inSMaskMode) {
11269      throw new Error("endSMaskMode called while not in smask mode");
11270    }
11271    this.ctx._removeMirroring();
11272    copyCtxState(this.ctx, this.suspendedCtx);
11273    this.ctx = this.suspendedCtx;
11274    this.suspendedCtx = null;
11275    this.canvasFactory.destroy(this.smaskScratchCanvas);
11276    this.smaskScratchCanvas = null;
11277    this._clearPreparedSMask();
11278  }
11279  #createKnockoutMaskCanvas(sourceCanvas, reuseEntry = null, alpha = 1) {
11280    const {
11281      width,
11282      height
11283    } = sourceCanvas;
11284    const maskEntry = reuseEntry ?? this.canvasFactory.create(width, height);
11285    const maskCtx = maskEntry.context;
11286    alpha = Math.round(alpha * 255) / 255;
11287    const needsAlphaScaling = alpha < 1;
11288    if (needsAlphaScaling && this.#knockoutFilterCache === undefined) {
11289      this.#knockoutFilterCache = FeatureTest.isCanvasFilterSupported ? new Map() : "none";
11290    }
11291    let knockoutFilter = "none";
11292    if (needsAlphaScaling && this.#knockoutFilterCache instanceof Map) {
11293      knockoutFilter = this.#knockoutFilterCache.getOrInsertComputed(alpha, () => this.filterFactory.addKnockoutFilter(alpha));
11294    }
11295    if (!needsAlphaScaling || knockoutFilter !== "none") {
11296      if (reuseEntry) {
11297        maskCtx.save();
11298        maskCtx.setTransform(1, 0, 0, 1, 0, 0);
11299        maskCtx.clearRect(0, 0, width, height);
11300        maskCtx.restore();
11301      }
11302      maskCtx.filter = knockoutFilter;
11303      maskCtx.drawImage(sourceCanvas, 0, 0);
11304      maskCtx.filter = "none";
11305      return maskEntry;
11306    }
11307    const sourceData = sourceCanvas.getContext("2d", {
11308      willReadFrequently: true
11309    }).getImageData(0, 0, width, height);
11310    const maskData = maskCtx.createImageData(width, height);
11311    const sourcePixels = sourceData.data,
11312      maskPixels = maskData.data;
11313    const alphaScale = alpha > 0 ? 1 / alpha : 1e6;
11314    for (let i = 3, ii = sourcePixels.length; i < ii; i += 4) {
11315      maskPixels[i] = Math.min(Math.round(sourcePixels[i] * alphaScale), 255);
11316    }
11317    maskCtx.putImageData(maskData, 0, 0);
11318    return maskEntry;
11319  }
11320  #getOrCreatePooledEntry(meta, key, width, height) {
11321    let entry = meta?.[key] ?? null;
11322    if (entry && (entry.canvas.width !== width || entry.canvas.height !== height)) {
11323      this.canvasFactory.destroy(entry);
11324      entry = null;
11325    }
11326    if (!entry) {
11327      entry = this.canvasFactory.create(width, height);
11328      if (meta) {
11329        meta[key] = entry;
11330      }
11331      return entry;
11332    }
11333    const ctx = entry.context;
11334    ctx.save();
11335    ctx.setTransform(1, 0, 0, 1, 0, 0);
11336    ctx.clearRect(0, 0, width, height);
11337    ctx.restore();
11338    return entry;
11339  }
11340  #compositeKnockoutSurface(destCtx, surfaceCanvas, options = {}) {
11341    const {
11342      backdropCanvas = null,
11343      destTransform = [1, 0, 0, 1, 0, 0],
11344      backdropOffset = [0, 0],
11345      reuseMaskEntry = null,
11346      poolMeta = null,
11347      sourceAlpha = 1,
11348      sourceFilter = "none",
11349      knockoutAlpha = 1
11350    } = options;
11351    const {
11352      width,
11353      height
11354    } = surfaceCanvas;
11355    const knockoutMaskEntry = this.#createKnockoutMaskCanvas(surfaceCanvas, reuseMaskEntry, knockoutAlpha);
11356    const sourceCompositeOperation = destCtx.globalCompositeOperation;
11357    destCtx.save();
11358    destCtx.setTransform(...destTransform);
11359    destCtx.globalAlpha = 1;
11360    if (FeatureTest.isCanvasFilterSupported) {
11361      destCtx.filter = "none";
11362    }
11363    destCtx.globalCompositeOperation = "destination-out";
11364    destCtx.drawImage(knockoutMaskEntry.canvas, 0, 0);
11365    if (backdropCanvas) {
11366      const [bx, by] = backdropOffset;
11367      const backdropEntry = this.#getOrCreatePooledEntry(poolMeta, "knockoutBackdropEntry", width, height);
11368      const backdropCtx = backdropEntry.context;
11369      backdropCtx.drawImage(backdropCanvas, bx, by, width, height, 0, 0, width, height);
11370      backdropCtx.globalCompositeOperation = "destination-in";
11371      backdropCtx.drawImage(knockoutMaskEntry.canvas, 0, 0);
11372      backdropCtx.globalCompositeOperation = "source-over";
11373      destCtx.globalCompositeOperation = "destination-over";
11374      destCtx.drawImage(backdropEntry.canvas, 0, 0);
11375      if (!poolMeta) {
11376        this.canvasFactory.destroy(backdropEntry);
11377      }
11378    }
11379    destCtx.globalCompositeOperation = sourceCompositeOperation;
11380    destCtx.globalAlpha = sourceAlpha;
11381    if (FeatureTest.isCanvasFilterSupported) {
11382      destCtx.filter = sourceFilter ?? "none";
11383    }
11384    destCtx.drawImage(surfaceCanvas, 0, 0);
11385    destCtx.restore();
11386    if (!reuseMaskEntry) {
11387      this.canvasFactory.destroy(knockoutMaskEntry);
11388    }
11389  }
11390  #beginKnockoutElement(alpha = 1) {
11391    if (this.#knockoutGroupLevel === 0 || this.#knockoutElementDepth > 0 || !this.contentVisible) {
11392      return false;
11393    }
11394    this.#knockoutElementDepth++;
11395    this.#knockoutElementAlpha = alpha;
11396    const groupMeta = this.#groupStackMeta.at(-1);
11397    const {
11398      canvas
11399    } = this.ctx;
11400    const tempEntry = this.#getOrCreatePooledEntry(groupMeta, "knockoutTempEntry", canvas.width, canvas.height);
11401    this.#knockoutTempCanvasEntry = tempEntry;
11402    const tempCtx = tempEntry.context;
11403    tempCtx.save();
11404    tempCtx.setTransform(this.ctx.getTransform());
11405    copyCtxState(this.ctx, tempCtx);
11406    this.#knockoutSavedGCO = tempCtx.globalCompositeOperation;
11407    tempCtx.globalCompositeOperation = "source-over";
11408    mirrorContextOperations(tempCtx, this.ctx);
11409    this.#knockoutElementGroupMeta = groupMeta;
11410    this.#knockoutSavedCtx = this.ctx;
11411    this.#knockoutSavedSMaskCtx = this.suspendedCtx;
11412    this.ctx = tempCtx;
11413    if (this.inSMaskMode) {
11414      this.suspendedCtx = tempCtx;
11415    }
11416    return true;
11417  }
11418  #endKnockoutElement(started) {
11419    if (!started) {
11420      return;
11421    }
11422    const tempEntry = this.#knockoutTempCanvasEntry;
11423    const savedCtx = this.#knockoutSavedCtx;
11424    const savedSMaskCtx = this.#knockoutSavedSMaskCtx;
11425    const tempCtx = tempEntry.context;
11426    this.#knockoutTempCanvasEntry = null;
11427    this.#knockoutSavedCtx = null;
11428    this.#knockoutSavedSMaskCtx = null;
11429    if (this.inSMaskMode && this.suspendedCtx === tempCtx && this.ctx !== tempCtx) {
11430      this.endSMaskMode();
11431    }
11432    if (this.inSMaskMode) {
11433      this.suspendedCtx = savedSMaskCtx;
11434    }
11435    this.ctx._removeMirroring();
11436    this.ctx.globalCompositeOperation = this.#knockoutSavedGCO;
11437    this.#knockoutSavedGCO = null;
11438    copyCtxState(this.ctx, savedCtx);
11439    this.ctx = savedCtx;
11440    const groupMeta = this.#knockoutElementGroupMeta;
11441    this.#knockoutElementGroupMeta = null;
11442    const knockoutAlpha = this.#knockoutElementAlpha;
11443    this.#knockoutElementAlpha = 1;
11444    try {
11445      this.#compositeKnockoutSurface(savedSMaskCtx ?? savedCtx, tempEntry.canvas, {
11446        backdropCanvas: groupMeta?.backdropCtx?.canvas ?? null,
11447        backdropOffset: groupMeta?.backdropCtx ? [groupMeta.offsetX, groupMeta.offsetY] : [0, 0],
11448        reuseMaskEntry: groupMeta?.knockoutMaskEntry ?? null,
11449        poolMeta: groupMeta,
11450        knockoutAlpha
11451      });
11452    } finally {
11453      tempCtx.restore();
11454      this.#knockoutElementDepth--;
11455      if (!groupMeta) {
11456        this.canvasFactory.destroy(tempEntry);
11457      }
11458    }
11459  }
11460  compose(dirtyBox) {
11461    if (!this.current.activeSMask) {
11462      return;
11463    }
11464    dirtyBox = dirtyBox ? [Math.floor(dirtyBox[0]), Math.floor(dirtyBox[1]), Math.ceil(dirtyBox[2]), Math.ceil(dirtyBox[3])] : [0, 0, this.ctx.canvas.width, this.ctx.canvas.height];
11465    const smask = this.current.activeSMask;
11466    const suspendedCtx = this.suspendedCtx;
11467    const applySMaskInPlace = this.#knockoutElementDepth > 0 && suspendedCtx === this.ctx;
11468    this.composeSMask(applySMaskInPlace ? null : suspendedCtx, smask, this.ctx, dirtyBox);
11469    if (applySMaskInPlace) {
11470      return;
11471    }
11472    this.ctx.save();
11473    this.ctx.setTransform(1, 0, 0, 1, 0, 0);
11474    this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
11475    this.ctx.restore();
11476  }
11477  composeSMask(ctx, smask, layerCtx, layerBox) {
11478    const layerOffsetX = layerBox[0];
11479    const layerOffsetY = layerBox[1];
11480    const layerWidth = layerBox[2] - layerOffsetX;
11481    const layerHeight = layerBox[3] - layerOffsetY;
11482    if (layerWidth === 0 || layerHeight === 0) {
11483      return;
11484    }
11485    const preparedEntry = this.smaskPreparedEntry;
11486    if (preparedEntry) {
11487      let clipX = layerOffsetX;
11488      let clipY = layerOffsetY;
11489      let clipW = layerWidth;
11490      let clipH = layerHeight;
11491      const oobAlpha = this.smaskPreparedOOBAlpha;
11492      const hasOOBAlpha = oobAlpha !== null;
11493      if (hasOOBAlpha) {
11494        clipX = Math.max(layerOffsetX, smask.offsetX);
11495        clipY = Math.max(layerOffsetY, smask.offsetY);
11496        const x1 = Math.min(layerOffsetX + layerWidth, smask.offsetX + smask.canvas.width);
11497        const y1 = Math.min(layerOffsetY + layerHeight, smask.offsetY + smask.canvas.height);
11498        clipW = x1 - clipX;
11499        clipH = y1 - clipY;
11500      }
11501      if (clipW > 0 && clipH > 0) {
11502        const srcX = clipX - this.smaskPreparedOffsetX;
11503        const srcY = clipY - this.smaskPreparedOffsetY;
11504        layerCtx.save();
11505        layerCtx.globalAlpha = 1;
11506        layerCtx.setTransform(1, 0, 0, 1, 0, 0);
11507        const clip = new Path2D();
11508        clip.rect(clipX, clipY, clipW, clipH);
11509        layerCtx.clip(clip);
11510        layerCtx.globalCompositeOperation = "destination-in";
11511        layerCtx.drawImage(preparedEntry.canvas, srcX, srcY, clipW, clipH, clipX, clipY, clipW, clipH);
11512        layerCtx.restore();
11513      }
11514      if (hasOOBAlpha && oobAlpha < 255) {
11515        this._applySMaskOOBAlpha(layerCtx, layerOffsetX, layerOffsetY, layerWidth, layerHeight, clipX, clipY, clipX + clipW, clipY + clipH, oobAlpha);
11516      }
11517    } else {
11518      this.genericComposeSMask(smask, layerCtx, layerWidth, layerHeight, layerOffsetX, layerOffsetY);
11519    }
11520    if (!ctx) {
11521      return;
11522    }
11523    ctx.save();
11524    ctx.globalAlpha = 1;
11525    ctx.globalCompositeOperation = smask.blendMode || "source-over";
11526    ctx.setTransform(1, 0, 0, 1, 0, 0);
11527    ctx.drawImage(layerCtx.canvas, layerOffsetX, layerOffsetY, layerWidth, layerHeight, layerOffsetX, layerOffsetY, layerWidth, layerHeight);
11528    ctx.restore();
11529  }
11530  _applySMaskOOBAlpha(layerCtx, layerOffsetX, layerOffsetY, layerWidth, layerHeight, maskX0, maskY0, maskX1, maskY1, alpha) {
11531    const hasInnerCutout = maskX0 < maskX1 && maskY0 < maskY1;
11532    if (hasInnerCutout && maskX0 === layerOffsetX && maskY0 === layerOffsetY && maskX1 === layerOffsetX + layerWidth && maskY1 === layerOffsetY + layerHeight) {
11533      return;
11534    }
11535    const path = new Path2D();
11536    path.rect(layerOffsetX, layerOffsetY, layerWidth, layerHeight);
11537    if (hasInnerCutout) {
11538      path.rect(maskX0, maskY0, maskX1 - maskX0, maskY1 - maskY0);
11539    }
11540    layerCtx.save();
11541    layerCtx.globalAlpha = alpha / 255;
11542    layerCtx.setTransform(1, 0, 0, 1, 0, 0);
11543    layerCtx.clip(path, "evenodd");
11544    layerCtx.globalCompositeOperation = "destination-in";
11545    layerCtx.fillStyle = "#000000";
11546    layerCtx.fillRect(layerOffsetX, layerOffsetY, layerWidth, layerHeight);
11547    layerCtx.restore();
11548  }
11549  genericComposeSMask(smask, layerCtx, width, height, layerOffsetX, layerOffsetY) {
11550    const {
11551      context: maskCtx,
11552      offsetX: maskOffsetX,
11553      offsetY: maskOffsetY
11554    } = smask;
11555    layerCtx.save();
11556    layerCtx.globalAlpha = 1;
11557    layerCtx.setTransform(1, 0, 0, 1, 0, 0);
11558    const clip = new Path2D();
11559    clip.rect(layerOffsetX, layerOffsetY, width, height);
11560    layerCtx.clip(clip);
11561    layerCtx.globalCompositeOperation = "destination-in";
11562    layerCtx.drawImage(maskCtx.canvas, layerOffsetX - maskOffsetX, layerOffsetY - maskOffsetY, width, height, layerOffsetX, layerOffsetY, width, height);
11563    layerCtx.restore();
11564  }
11565  save(opIdx) {
11566    if (this.inSMaskMode) {
11567      copyCtxState(this.ctx, this.suspendedCtx);
11568    }
11569    this.ctx.save();
11570    const old = this.current;
11571    this.stateStack.push(old);
11572    this.current = old.clone();
11573    this.dependencyTracker?.save(opIdx);
11574  }
11575  restore(opIdx) {
11576    this.dependencyTracker?.restore(opIdx);
11577    if (this.stateStack.length === 0) {
11578      if (this.inSMaskMode) {
11579        this.endSMaskMode();
11580      }
11581      return;
11582    }
11583    this.current = this.stateStack.pop();
11584    this.ctx.restore();
11585    if (this.inSMaskMode) {
11586      copyCtxState(this.suspendedCtx, this.ctx);
11587      this.ctx.setTransform(this.suspendedCtx.getTransform());
11588    }
11589    this.checkSMaskState(opIdx);
11590    this.pendingClip = null;
11591    this._cachedScaleForStroking[0] = -1;
11592    this._cachedGetSinglePixelWidth = null;
11593  }
11594  transform(opIdx, a, b, c, d, e, f) {
11595    this.dependencyTracker?.recordIncrementalData("transform", opIdx);
11596    this.ctx.transform(a, b, c, d, e, f);
11597    this._cachedScaleForStroking[0] = -1;
11598    this._cachedGetSinglePixelWidth = null;
11599  }
11600  constructPath(opIdx, op, data, minMax) {
11601    let [path] = data;
11602    if (!minMax) {
11603      path ||= data[0] = new Path2D();
11604      if (op !== OPS.stroke && op !== OPS.closeStroke) {
11605        this.current.tilingPatternDims = null;
11606      }
11607      this[op](opIdx, path);
11608      return;
11609    }
11610    if (this.dependencyTracker !== null) {
11611      const outerExtraSize = op === OPS.stroke ? this.current.lineWidth / 2 : 0;
11612      this.dependencyTracker.resetBBox(opIdx).recordBBox(opIdx, this.ctx, minMax[0] - outerExtraSize, minMax[2] + outerExtraSize, minMax[1] - outerExtraSize, minMax[3] + outerExtraSize).recordDependencies(opIdx, ["transform"]);
11613    }
11614    if (!(path instanceof Path2D)) {
11615      path = data[0] = makePathFromDrawOPS(path);
11616    }
11617    Util.axialAlignedBoundingBox(minMax, getCurrentTransform(this.ctx), this.current.minMax);
11618    const tilingDims = this.current.tilingPatternDims;
11619    if (tilingDims && op !== OPS.stroke && op !== OPS.closeStroke && this.current.fillColor instanceof TilingPattern) {
11620      const clippedBBox = Util.intersect(this.current.clipBox, this.current.minMax);
11621      if (!clippedBBox) {
11622        this.current.tilingPatternDims = null;
11623      } else {
11624        this.current.fillColor.updatePatternDims(clippedBBox, tilingDims);
11625      }
11626    }
11627    this[op](opIdx, path);
11628    this._pathStartIdx = opIdx;
11629  }
11630  closePath(opIdx) {
11631    this.ctx.closePath();
11632  }
11633  stroke(opIdx, path, consumePath = true) {
11634    const started = consumePath && this.#beginKnockoutElement(this.current.strokeAlpha);
11635    const ctx = this.ctx;
11636    const strokeColor = this.current.strokeColor;
11637    ctx.globalAlpha = this.current.strokeAlpha;
11638    if (this.contentVisible) {
11639      if (typeof strokeColor === "object" && strokeColor?.getPattern) {
11640        const baseTransform = strokeColor.isModifyingCurrentTransform() ? ctx.getTransform() : null;
11641        ctx.save();
11642        ctx.strokeStyle = strokeColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.STROKE, opIdx);
11643        if (baseTransform) {
11644          const newPath = new Path2D();
11645          newPath.addPath(path, ctx.getTransform().invertSelf().multiplySelf(baseTransform));
11646          path = newPath;
11647        }
11648        this.rescaleAndStroke(path, false);
11649        ctx.restore();
11650      } else {
11651        this.rescaleAndStroke(path, true);
11652      }
11653    }
11654    this.dependencyTracker?.recordDependencies(opIdx, Dependencies.stroke);
11655    if (consumePath) {
11656      this.consumePath(opIdx, path, this.current.getClippedPathBoundingBox(PathType.STROKE, getCurrentTransform(this.ctx)));
11657    }
11658    ctx.globalAlpha = this.current.fillAlpha;
11659    this.#endKnockoutElement(started);
11660  }
11661  closeStroke(opIdx, path) {
11662    this.stroke(opIdx, path);
11663  }
11664  fill(opIdx, path, consumePath = true) {
11665    const started = consumePath && this.#beginKnockoutElement(this.current.fillAlpha);
11666    const ctx = this.ctx;
11667    const fillColor = this.current.fillColor;
11668    const isPatternFill = this.current.patternFill;
11669    let needRestore = false;
11670    const intersect = this.current.getClippedPathBoundingBox();
11671    this.dependencyTracker?.recordDependencies(opIdx, Dependencies.fill);
11672    if (isPatternFill) {
11673      const dims = this.current.tilingPatternDims;
11674      const tileIdx = dims && fillColor.canSkipPatternCanvas(dims);
11675      if (tileIdx) {
11676        fillColor.drawPattern(this, path, this.pendingEOFill, tileIdx, opIdx);
11677        this.pendingEOFill = false;
11678        if (consumePath) {
11679          this.consumePath(opIdx, path, intersect);
11680        }
11681        this.current.tilingPatternDims = null;
11682        this.#endKnockoutElement(started);
11683        return;
11684      }
11685      const baseTransform = fillColor.isModifyingCurrentTransform() ? ctx.getTransform() : null;
11686      this.dependencyTracker?.save(opIdx);
11687      ctx.save();
11688      ctx.fillStyle = fillColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.FILL, opIdx);
11689      if (baseTransform) {
11690        const newPath = new Path2D();
11691        newPath.addPath(path, ctx.getTransform().invertSelf().multiplySelf(baseTransform));
11692        path = newPath;
11693      }
11694      needRestore = true;
11695    }
11696    if (this.contentVisible && intersect !== null) {
11697      if (this.pendingEOFill) {
11698        ctx.fill(path, "evenodd");
11699        this.pendingEOFill = false;
11700      } else {
11701        ctx.fill(path);
11702      }
11703    }
11704    if (needRestore) {
11705      ctx.restore();
11706      this.dependencyTracker?.restore(opIdx);
11707    }
11708    if (consumePath) {
11709      this.consumePath(opIdx, path, intersect);
11710    }
11711    this.#endKnockoutElement(started);
11712  }
11713  eoFill(opIdx, path) {
11714    this.pendingEOFill = true;
11715    this.fill(opIdx, path);
11716  }
11717  fillStroke(opIdx, path) {
11718    const started = this.#beginKnockoutElement(Math.min(this.current.fillAlpha, this.current.strokeAlpha));
11719    this.fill(opIdx, path, false);
11720    this.stroke(opIdx, path, false);
11721    this.consumePath(opIdx, path);
11722    this.#endKnockoutElement(started);
11723  }
11724  eoFillStroke(opIdx, path) {
11725    this.pendingEOFill = true;
11726    this.fillStroke(opIdx, path);
11727  }
11728  closeFillStroke(opIdx, path) {
11729    this.fillStroke(opIdx, path);
11730  }
11731  closeEOFillStroke(opIdx, path) {
11732    this.pendingEOFill = true;
11733    this.fillStroke(opIdx, path);
11734  }
11735  endPath(opIdx, path) {
11736    this.consumePath(opIdx, path);
11737  }
11738  rawFillPath(opIdx, path) {
11739    const started = this.#beginKnockoutElement(this.current.fillAlpha);
11740    this.ctx.fill(path);
11741    this.dependencyTracker?.recordDependencies(opIdx, Dependencies.rawFillPath).recordOperation(opIdx);
11742    this.#endKnockoutElement(started);
11743  }
11744  clip(opIdx) {
11745    this.dependencyTracker?.recordFutureForcedDependency("clipMode", opIdx);
11746    this.pendingClip = NORMAL_CLIP;
11747  }
11748  eoClip(opIdx) {
11749    this.dependencyTracker?.recordFutureForcedDependency("clipMode", opIdx);
11750    this.pendingClip = EO_CLIP;
11751  }
11752  beginText(opIdx) {
11753    this.current.textMatrix = null;
11754    this.current.textMatrixScale = 1;
11755    this.current.x = this.current.lineX = 0;
11756    this.current.y = this.current.lineY = 0;
11757    this.dependencyTracker?.recordOpenMarker(opIdx).resetIncrementalData("sameLineText").resetIncrementalData("moveText", opIdx);
11758  }
11759  endText(opIdx) {
11760    const paths = this.pendingTextPaths;
11761    const ctx = this.ctx;
11762    if (this.dependencyTracker) {
11763      const {
11764        dependencyTracker
11765      } = this;
11766      if (paths !== undefined) {
11767        dependencyTracker.recordFutureForcedDependency("textClip", dependencyTracker.getOpenMarker()).recordFutureForcedDependency("textClip", opIdx);
11768      }
11769      dependencyTracker.recordCloseMarker(opIdx);
11770    }
11771    if (paths !== undefined) {
11772      const newPath = new Path2D();
11773      const invTransf = ctx.getTransform().invertSelf();
11774      for (const {
11775        transform,
11776        x,
11777        y,
11778        fontSize,
11779        path
11780      } of paths) {
11781        if (!path) {
11782          continue;
11783        }
11784        newPath.addPath(path, new DOMMatrix(transform).preMultiplySelf(invTransf).translate(x, y).scale(fontSize, -fontSize));
11785      }
11786      ctx.clip(newPath);
11787    }
11788    delete this.pendingTextPaths;
11789  }
11790  setCharSpacing(opIdx, spacing) {
11791    this.dependencyTracker?.recordSimpleData("charSpacing", opIdx);
11792    this.current.charSpacing = spacing;
11793  }
11794  setWordSpacing(opIdx, spacing) {
11795    this.dependencyTracker?.recordSimpleData("wordSpacing", opIdx);
11796    this.current.wordSpacing = spacing;
11797  }
11798  setHScale(opIdx, scale) {
11799    this.dependencyTracker?.recordSimpleData("hScale", opIdx);
11800    this.current.textHScale = scale / 100;
11801  }
11802  setLeading(opIdx, leading) {
11803    this.dependencyTracker?.recordSimpleData("leading", opIdx);
11804    this.current.leading = -leading;
11805  }
11806  setFont(opIdx, fontRefName, size) {
11807    this.dependencyTracker?.recordSimpleData("font", opIdx).recordSimpleDataFromNamed("fontObj", fontRefName, opIdx);
11808    const fontObj = this.commonObjs.get(fontRefName);
11809    const current = this.current;
11810    if (!fontObj) {
11811      throw new Error(`Can't find font for ${fontRefName}`);
11812    }
11813    current.fontMatrix = fontObj.fontMatrix || FONT_IDENTITY_MATRIX;
11814    if (current.fontMatrix[0] === 0 || current.fontMatrix[3] === 0) {
11815      warn("Invalid font matrix for font " + fontRefName);
11816    }
11817    if (size < 0) {
11818      size = -size;
11819      current.fontDirection = -1;
11820    } else {
11821      current.fontDirection = 1;
11822    }
11823    this.current.font = fontObj;
11824    this.current.fontSize = size;
11825    if (fontObj.isType3Font) {
11826      return;
11827    }
11828    const name = fontObj.loadedName || "sans-serif";
11829    const typeface = fontObj.systemFontInfo?.css || `"${name}", ${fontObj.fallbackName}`;
11830    let bold = "normal";
11831    if (fontObj.black) {
11832      bold = "900";
11833    } else if (fontObj.bold) {
11834      bold = "bold";
11835    }
11836    const italic = fontObj.italic ? "italic" : "normal";
11837    const browserFontSize = MathClamp(size, MIN_FONT_SIZE, MAX_FONT_SIZE);
11838    this.current.fontSizeScale = size / browserFontSize;
11839    this.ctx.font = `${italic} ${bold} ${browserFontSize}px ${typeface}`;
11840  }
11841  setTextRenderingMode(opIdx, mode) {
11842    this.dependencyTracker?.recordSimpleData("textRenderingMode", opIdx);
11843    this.current.textRenderingMode = mode;
11844  }
11845  setTextRise(opIdx, rise) {
11846    this.dependencyTracker?.recordSimpleData("textRise", opIdx);
11847    this.current.textRise = rise;
11848  }
11849  moveText(opIdx, x, y) {
11850    this.dependencyTracker?.resetIncrementalData("sameLineText").recordIncrementalData("moveText", opIdx);
11851    this.current.x = this.current.lineX += x;
11852    this.current.y = this.current.lineY += y;
11853  }
11854  setLeadingMoveText(opIdx, x, y) {
11855    this.setLeading(opIdx, -y);
11856    this.moveText(opIdx, x, y);
11857  }
11858  setTextMatrix(opIdx, matrix) {
11859    this.dependencyTracker?.resetIncrementalData("sameLineText").recordSimpleData("textMatrix", opIdx);
11860    const {
11861      current
11862    } = this;
11863    current.textMatrix = matrix;
11864    current.textMatrixScale = Math.hypot(matrix[0], matrix[1]);
11865    current.x = current.lineX = 0;
11866    current.y = current.lineY = 0;
11867  }
11868  nextLine(opIdx) {
11869    this.moveText(opIdx, 0, this.current.leading);
11870    this.dependencyTracker?.recordIncrementalData("moveText", this.dependencyTracker.getSimpleIndex("leading") ?? opIdx);
11871  }
11872  #getScaledPath(path, currentTransform, transform) {
11873    const newPath = new Path2D();
11874    newPath.addPath(path, new DOMMatrix(transform).invertSelf().multiplySelf(currentTransform));
11875    return newPath;
11876  }
11877  paintChar(opIdx, character, x, y, patternFillTransform, patternStrokeTransform) {
11878    const ctx = this.ctx;
11879    const current = this.current;
11880    const font = current.font;
11881    const textRenderingMode = current.textRenderingMode;
11882    const fontSize = current.fontSize / current.fontSizeScale;
11883    const fillStrokeMode = textRenderingMode & TextRenderingMode.FILL_STROKE_MASK;
11884    const isAddToPathSet = !!(textRenderingMode & TextRenderingMode.ADD_TO_PATH_FLAG);
11885    const patternFill = current.patternFill && !font.missingFile;
11886    const patternStroke = current.patternStroke && !font.missingFile;
11887    let path;
11888    if ((font.disableFontFace || isAddToPathSet || patternFill || patternStroke) && !font.missingFile) {
11889      path = font.getPathGenerator(this.commonObjs, character);
11890    }
11891    if (path && (font.disableFontFace || patternFill || patternStroke)) {
11892      ctx.save();
11893      ctx.translate(x, y);
11894      ctx.scale(fontSize, -fontSize);
11895      this.dependencyTracker?.recordCharacterBBox(opIdx, ctx, font);
11896      let currentTransform;
11897      if (fillStrokeMode === TextRenderingMode.FILL || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
11898        if (patternFillTransform) {
11899          currentTransform = ctx.getTransform();
11900          ctx.setTransform(...patternFillTransform);
11901          const scaledPath = this.#getScaledPath(path, currentTransform, patternFillTransform);
11902          ctx.fill(scaledPath);
11903        } else {
11904          ctx.fill(path);
11905        }
11906      }
11907      if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
11908        if (patternStrokeTransform) {
11909          currentTransform ||= ctx.getTransform();
11910          ctx.setTransform(...patternStrokeTransform);
11911          const {
11912            a,
11913            b,
11914            c,
11915            d
11916          } = currentTransform;
11917          const invPatternTransform = Util.inverseTransform(patternStrokeTransform);
11918          const transf = Util.transform([a, b, c, d, 0, 0], invPatternTransform);
11919          Util.singularValueDecompose2dScale(transf, XY);
11920          ctx.lineWidth *= Math.max(XY[0], XY[1]) / fontSize;
11921          ctx.stroke(this.#getScaledPath(path, currentTransform, patternStrokeTransform));
11922        } else {
11923          ctx.lineWidth /= fontSize;
11924          ctx.stroke(path);
11925        }
11926      }
11927      ctx.restore();
11928    } else {
11929      if (fillStrokeMode === TextRenderingMode.FILL || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
11930        ctx.fillText(character, x, y);
11931        this.dependencyTracker?.recordCharacterBBox(opIdx, ctx, font, fontSize, x, y, () => ctx.measureText(character));
11932      }
11933      if (fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE) {
11934        if (this.dependencyTracker) {
11935          this.dependencyTracker?.recordCharacterBBox(opIdx, ctx, font, fontSize, x, y, () => ctx.measureText(character)).recordDependencies(opIdx, Dependencies.stroke);
11936        }
11937        ctx.strokeText(character, x, y);
11938      }
11939    }
11940    if (isAddToPathSet) {
11941      const paths = this.pendingTextPaths ||= [];
11942      paths.push({
11943        transform: getCurrentTransform(ctx),
11944        x,
11945        y,
11946        fontSize,
11947        path
11948      });
11949      this.dependencyTracker?.recordCharacterBBox(opIdx, ctx, font, fontSize, x, y);
11950    }
11951  }
11952  get isFontSubpixelAAEnabled() {
11953    const tmpCanvas = this.canvasFactory.create(10, 10);
11954    const ctx = tmpCanvas.context;
11955    ctx.scale(1.5, 1);
11956    ctx.fillText("I", 0, 10);
11957    const data = ctx.getImageData(0, 0, 10, 10).data;
11958    this.canvasFactory.destroy(tmpCanvas);
11959    let enabled = false;
11960    for (let i = 3; i < data.length; i += 4) {
11961      if (data[i] > 0 && data[i] < 255) {
11962        enabled = true;
11963        break;
11964      }
11965    }
11966    return shadow(this, "isFontSubpixelAAEnabled", enabled);
11967  }
11968  showText(opIdx, glyphs) {
11969    if (this.dependencyTracker) {
11970      this.dependencyTracker.recordDependencies(opIdx, Dependencies.showText).resetBBox(opIdx);
11971      if (this.current.textRenderingMode & TextRenderingMode.ADD_TO_PATH_FLAG) {
11972        this.dependencyTracker.recordFutureForcedDependency("textClip", opIdx).inheritPendingDependenciesAsFutureForcedDependencies();
11973      }
11974    }
11975    const current = this.current;
11976    const font = current.font;
11977    if (font.isType3Font) {
11978      const started = this.#beginKnockoutElement(current.fillAlpha);
11979      this.showType3Text(opIdx, glyphs);
11980      this.dependencyTracker?.recordShowTextOperation(opIdx);
11981      this.#endKnockoutElement(started);
11982      return;
11983    }
11984    const fontSize = current.fontSize;
11985    if (fontSize === 0) {
11986      this.dependencyTracker?.recordOperation(opIdx);
11987      return;
11988    }
11989    const started = this.#beginKnockoutElement(current.fillAlpha);
11990    const ctx = this.ctx;
11991    const fontSizeScale = current.fontSizeScale;
11992    const charSpacing = current.charSpacing;
11993    const wordSpacing = current.wordSpacing;
11994    const fontDirection = current.fontDirection;
11995    const textHScale = current.textHScale * fontDirection;
11996    const glyphsLength = glyphs.length;
11997    const vertical = font.vertical;
11998    const spacingDir = vertical ? 1 : -1;
11999    const defaultVMetrics = font.defaultVMetrics;
12000    const widthAdvanceScale = fontSize * current.fontMatrix[0];
12001    const simpleFillText = current.textRenderingMode === TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill;
12002    ctx.save();
12003    if (current.textMatrix) {
12004      ctx.transform(...current.textMatrix);
12005    }
12006    ctx.translate(current.x, current.y + current.textRise);
12007    if (fontDirection > 0) {
12008      ctx.scale(textHScale, -1);
12009    } else {
12010      ctx.scale(textHScale, 1);
12011    }
12012    let patternFillTransform, patternStrokeTransform;
12013    const fillStrokeMode = current.textRenderingMode & TextRenderingMode.FILL_STROKE_MASK;
12014    const needsFill = fillStrokeMode === TextRenderingMode.FILL || fillStrokeMode === TextRenderingMode.FILL_STROKE;
12015    const needsStroke = fillStrokeMode === TextRenderingMode.STROKE || fillStrokeMode === TextRenderingMode.FILL_STROKE;
12016    let lineWidth = current.lineWidth;
12017    const scale = current.textMatrixScale;
12018    if (scale === 0 || lineWidth === 0) {
12019      if (needsStroke) {
12020        lineWidth = this.getSinglePixelWidth();
12021      }
12022    } else {
12023      lineWidth /= scale;
12024    }
12025    if (fontSizeScale !== 1.0) {
12026      ctx.scale(fontSizeScale, fontSizeScale);
12027      lineWidth /= fontSizeScale;
12028    }
12029    ctx.lineWidth = lineWidth;
12030    if (needsFill && current.patternFill) {
12031      ctx.save();
12032      const pattern = current.fillColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.FILL, opIdx);
12033      patternFillTransform = getCurrentTransform(ctx);
12034      ctx.restore();
12035      ctx.fillStyle = pattern;
12036    }
12037    if (needsStroke && current.patternStroke) {
12038      ctx.save();
12039      const pattern = current.strokeColor.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.STROKE, opIdx);
12040      patternStrokeTransform = getCurrentTransform(ctx);
12041      ctx.restore();
12042      ctx.strokeStyle = pattern;
12043    }
12044    if (font.isInvalidPDFjsFont) {
12045      const chars = [];
12046      let width = 0;
12047      for (const glyph of glyphs) {
12048        chars.push(glyph.unicode);
12049        width += glyph.width;
12050      }
12051      const joinedChars = chars.join("");
12052      ctx.fillText(joinedChars, 0, 0);
12053      if (this.dependencyTracker !== null) {
12054        const measure = ctx.measureText(joinedChars);
12055        this.dependencyTracker.recordBBox(opIdx, this.ctx, -measure.actualBoundingBoxLeft, measure.actualBoundingBoxRight, -measure.actualBoundingBoxAscent, measure.actualBoundingBoxDescent).recordShowTextOperation(opIdx);
12056      }
12057      current.x += width * widthAdvanceScale * textHScale;
12058      ctx.restore();
12059      this.compose();
12060      this.#endKnockoutElement(started);
12061      return;
12062    }
12063    let x = 0,
12064      i;
12065    for (i = 0; i < glyphsLength; ++i) {
12066      const glyph = glyphs[i];
12067      if (typeof glyph === "number") {
12068        x += spacingDir * glyph * fontSize / 1000;
12069        continue;
12070      }
12071      let restoreNeeded = false;
12072      const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
12073      const character = glyph.fontChar;
12074      const accent = glyph.accent;
12075      let scaledX, scaledY;
12076      let width = glyph.width;
12077      if (vertical) {
12078        const vmetric = glyph.vmetric || defaultVMetrics;
12079        const vx = -(glyph.vmetric ? vmetric[1] : width * 0.5) * widthAdvanceScale;
12080        const vy = vmetric[2] * widthAdvanceScale;
12081        width = vmetric ? -vmetric[0] : width;
12082        scaledX = vx / fontSizeScale;
12083        scaledY = (x + vy) / fontSizeScale;
12084      } else {
12085        scaledX = x / fontSizeScale;
12086        scaledY = 0;
12087      }
12088      let measure;
12089      if (font.remeasure && width > 0) {
12090        measure = ctx.measureText(character);
12091        const measuredWidth = measure.width * 1000 / fontSize * fontSizeScale;
12092        if (width < measuredWidth && this.isFontSubpixelAAEnabled) {
12093          const characterScaleX = width / measuredWidth;
12094          restoreNeeded = true;
12095          ctx.save();
12096          ctx.scale(characterScaleX, 1);
12097          scaledX /= characterScaleX;
12098        } else if (width !== measuredWidth) {
12099          scaledX += (width - measuredWidth) / 2000 * fontSize / fontSizeScale;
12100        }
12101      }
12102      if (this.contentVisible && (glyph.isInFont || font.missingFile)) {
12103        if (simpleFillText && !accent) {
12104          ctx.fillText(character, scaledX, scaledY);
12105          this.dependencyTracker?.recordCharacterBBox(opIdx, ctx, measure ? {
12106            bbox: null
12107          } : font, fontSize / fontSizeScale, scaledX, scaledY, () => measure ?? ctx.measureText(character));
12108        } else {
12109          this.paintChar(opIdx, character, scaledX, scaledY, patternFillTransform, patternStrokeTransform);
12110          if (accent) {
12111            const scaledAccentX = scaledX + fontSize * accent.offset.x / fontSizeScale;
12112            const scaledAccentY = scaledY - fontSize * accent.offset.y / fontSizeScale;
12113            this.paintChar(opIdx, accent.fontChar, scaledAccentX, scaledAccentY, patternFillTransform, patternStrokeTransform);
12114          }
12115        }
12116      }
12117      const charWidth = vertical ? width * widthAdvanceScale - spacing * fontDirection : width * widthAdvanceScale + spacing * fontDirection;
12118      x += charWidth;
12119      if (restoreNeeded) {
12120        ctx.restore();
12121      }
12122    }
12123    if (vertical) {
12124      current.y -= x;
12125    } else {
12126      current.x += x * textHScale;
12127    }
12128    ctx.restore();
12129    this.compose();
12130    this.dependencyTracker?.recordShowTextOperation(opIdx);
12131    this.#endKnockoutElement(started);
12132  }
12133  showType3Text(opIdx, glyphs) {
12134    const ctx = this.ctx;
12135    const current = this.current;
12136    const font = current.font;
12137    const fontSize = current.fontSize;
12138    const fontDirection = current.fontDirection;
12139    const spacingDir = font.vertical ? 1 : -1;
12140    const charSpacing = current.charSpacing;
12141    const wordSpacing = current.wordSpacing;
12142    const textHScale = current.textHScale * fontDirection;
12143    const fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
12144    const glyphsLength = glyphs.length;
12145    const isTextInvisible = current.textRenderingMode === TextRenderingMode.INVISIBLE;
12146    let i, glyph, width, spacingLength;
12147    if (isTextInvisible || fontSize === 0) {
12148      return;
12149    }
12150    this._cachedScaleForStroking[0] = -1;
12151    this._cachedGetSinglePixelWidth = null;
12152    ctx.save();
12153    if (current.textMatrix) {
12154      ctx.transform(...current.textMatrix);
12155    }
12156    ctx.translate(current.x, current.y + current.textRise);
12157    ctx.scale(textHScale, fontDirection);
12158    const dependencyTracker = this.dependencyTracker;
12159    this.dependencyTracker = dependencyTracker ? new CanvasNestedDependencyTracker(dependencyTracker, opIdx) : null;
12160    for (i = 0; i < glyphsLength; ++i) {
12161      glyph = glyphs[i];
12162      if (typeof glyph === "number") {
12163        spacingLength = spacingDir * glyph * fontSize / 1000;
12164        this.ctx.translate(spacingLength, 0);
12165        current.x += spacingLength * textHScale;
12166        continue;
12167      }
12168      const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
12169      const operatorList = font.charProcOperatorList
vendor: 15,985 bytes, lines 12169-12600
12169[glyph.operatorListId];
12170      if (!operatorList) {
12171        warn(`Type3 character "${glyph.operatorListId}" is not available.`);
12172      } else if (this.contentVisible) {
12173        this.save();
12174        if (operatorList.fnArray[0] === OPS.setCharWidth) {
12175          current.fillAlpha = current.strokeAlpha = 1;
12176          ctx.globalAlpha = 1;
12177        }
12178        ctx.scale(fontSize, fontSize);
12179        ctx.transform(...fontMatrix);
12180        this.executeOperatorList(operatorList);
12181        this.restore();
12182      }
12183      const p = [glyph.width, 0];
12184      Util.applyTransform(p, fontMatrix);
12185      width = p[0] * fontSize + spacing;
12186      ctx.translate(width, 0);
12187      current.x += width * textHScale;
12188    }
12189    ctx.restore();
12190    if (dependencyTracker) {
12191      this.dependencyTracker = dependencyTracker;
12192    }
12193  }
12194  setCharWidth(opIdx, xWidth, yWidth) {}
12195  setCharWidthAndBounds(opIdx, xWidth, yWidth, llx, lly, urx, ury) {
12196    const clip = new Path2D();
12197    clip.rect(llx, lly, urx - llx, ury - lly);
12198    this.ctx.clip(clip);
12199    this.dependencyTracker?.recordBBox(opIdx, this.ctx, llx, urx, lly, ury).recordClipBox(opIdx, this.ctx, llx, urx, lly, ury);
12200    this.endPath(opIdx);
12201  }
12202  getColorN_Pattern(opIdx, IR) {
12203    let pattern;
12204    if (IR[0] === "TilingPattern") {
12205      const baseTransform = this.baseTransform || getCurrentTransform(this.ctx);
12206      const canvasGraphicsFactory = {
12207        createCanvasGraphics: (ctx, renderingOpIdx) => new CanvasGraphics(ctx, this.commonObjs, this.objs, this.canvasFactory, this.filterFactory, {
12208          optionalContentConfig: this.optionalContentConfig,
12209          markedContentStack: this.markedContentStack
12210        }, undefined, undefined, this.dependencyTracker ? new CanvasNestedDependencyTracker(this.dependencyTracker, renderingOpIdx, true) : null)
12211      };
12212      pattern = new TilingPattern(IR, this.ctx, canvasGraphicsFactory, baseTransform);
12213    } else {
12214      pattern = this._getPattern(opIdx, IR[1], IR[2]);
12215    }
12216    return pattern;
12217  }
12218  setStrokeColorN(opIdx, ...args) {
12219    this.dependencyTracker?.recordSimpleData("strokeColor", opIdx);
12220    this.current.strokeColor = this.getColorN_Pattern(opIdx, args);
12221    this.current.patternStroke = true;
12222  }
12223  setFillColorN(opIdx, ...args) {
12224    this.dependencyTracker?.recordSimpleData("fillColor", opIdx);
12225    const pattern = this.current.fillColor = this.getColorN_Pattern(opIdx, args);
12226    this.current.patternFill = true;
12227    this.current.tilingPatternDims = pattern instanceof TilingPattern ? [0, 0, 0, 0] : null;
12228  }
12229  setStrokeRGBColor(opIdx, color) {
12230    this.dependencyTracker?.recordSimpleData("strokeColor", opIdx);
12231    this.ctx.strokeStyle = this.current.strokeColor = color;
12232    this.current.patternStroke = false;
12233  }
12234  setStrokeTransparent(opIdx) {
12235    this.dependencyTracker?.recordSimpleData("strokeColor", opIdx);
12236    this.ctx.strokeStyle = this.current.strokeColor = "transparent";
12237    this.current.patternStroke = false;
12238  }
12239  setFillRGBColor(opIdx, color) {
12240    this.dependencyTracker?.recordSimpleData("fillColor", opIdx);
12241    this.ctx.fillStyle = this.current.fillColor = color;
12242    this.current.patternFill = false;
12243    this.current.tilingPatternDims = null;
12244  }
12245  setFillTransparent(opIdx) {
12246    this.dependencyTracker?.recordSimpleData("fillColor", opIdx);
12247    this.ctx.fillStyle = this.current.fillColor = "transparent";
12248    this.current.patternFill = false;
12249    this.current.tilingPatternDims = null;
12250  }
12251  _getPattern(opIdx, objId, matrix = null) {
12252    let pattern;
12253    if (this.cachedPatterns.has(objId)) {
12254      pattern = this.cachedPatterns.get(objId);
12255    } else {
12256      pattern = getShadingPattern(this.getObject(opIdx, objId));
12257      this.cachedPatterns.set(objId, pattern);
12258    }
12259    if (matrix) {
12260      pattern.matrix = matrix;
12261    }
12262    return pattern;
12263  }
12264  shadingFill(opIdx, objId) {
12265    if (!this.contentVisible) {
12266      return;
12267    }
12268    const started = this.#beginKnockoutElement(this.current.fillAlpha);
12269    const ctx = this.ctx;
12270    this.save(opIdx);
12271    const pattern = this._getPattern(opIdx, objId);
12272    ctx.fillStyle = pattern.getPattern(ctx, this, getCurrentTransformInverse(ctx), PathType.SHADING, opIdx);
12273    const inv = getCurrentTransformInverse(ctx);
12274    if (inv) {
12275      const {
12276        width,
12277        height
12278      } = ctx.canvas;
12279      const minMax = F32_BBOX_INIT.slice();
12280      Util.axialAlignedBoundingBox([0, 0, width, height], inv, minMax);
12281      const [x0, y0, x1, y1] = minMax;
12282      this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
12283    } else {
12284      this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
12285    }
12286    this.dependencyTracker?.resetBBox(opIdx).recordFullPageBBox(opIdx).recordDependencies(opIdx, Dependencies.transform).recordDependencies(opIdx, Dependencies.fill).recordOperation(opIdx);
12287    this.compose(this.current.getClippedPathBoundingBox());
12288    this.restore(opIdx);
12289    this.#endKnockoutElement(started);
12290  }
12291  beginInlineImage() {
12292    unreachable("Should not call beginInlineImage");
12293  }
12294  beginImageData() {
12295    unreachable("Should not call beginImageData");
12296  }
12297  paintFormXObjectBegin(opIdx, matrix, bbox) {
12298    if (!this.contentVisible) {
12299      return;
12300    }
12301    this.save(opIdx);
12302    this.baseTransformStack.push(this.baseTransform);
12303    if (matrix) {
12304      this.transform(opIdx, ...matrix);
12305    }
12306    this.baseTransform = getCurrentTransform(this.ctx);
12307    if (bbox) {
12308      Util.axialAlignedBoundingBox(bbox, this.baseTransform, this.current.minMax);
12309      const [x0, y0, x1, y1] = bbox;
12310      const clip = new Path2D();
12311      clip.rect(x0, y0, x1 - x0, y1 - y0);
12312      this.ctx.clip(clip);
12313      this.dependencyTracker?.recordClipBox(opIdx, this.ctx, x0, x1, y0, y1);
12314      this.endPath(opIdx);
12315    }
12316  }
12317  paintFormXObjectEnd(opIdx) {
12318    if (!this.contentVisible) {
12319      return;
12320    }
12321    this.restore(opIdx);
12322    this.baseTransform = this.baseTransformStack.pop();
12323  }
12324  beginGroup(opIdx, group) {
12325    if (!this.contentVisible) {
12326      return;
12327    }
12328    this.save(opIdx);
12329    const {
12330      inSMaskMode
12331    } = this;
12332    if (inSMaskMode) {
12333      this.endSMaskMode();
12334      this.current.activeSMask = null;
12335    }
12336    const currentCtx = this.ctx;
12337    if ((!group.needsIsolation || !group.isolated && !group.hasSoftMask) && !group.knockout && !group.isGray && this.#knockoutGroupLevel === 0 && currentCtx.globalAlpha === 1 && currentCtx.globalCompositeOperation === "source-over" && !inSMaskMode) {
12338      if (group.bbox) {
12339        let clip = new Path2D();
12340        const [x0, y0, x1, y1] = group.bbox;
12341        clip.rect(x0, y0, x1 - x0, y1 - y0);
12342        if (group.matrix) {
12343          const path = new Path2D();
12344          path.addPath(clip, new DOMMatrix(group.matrix));
12345          clip = path;
12346        }
12347        currentCtx.clip(clip);
12348      }
12349      this.groupStack.push(null);
12350      this.#groupStackMeta.push(null);
12351      this.groupLevel++;
12352      return;
12353    }
12354    if (!group.isolated && !group.knockout && this.#knockoutGroupLevel === 0) {
12355      info("TODO: Fully support non-isolated non-knockout groups.");
12356    }
12357    const currentTransform = getCurrentTransform(currentCtx);
12358    if (group.matrix) {
12359      currentCtx.transform(...group.matrix);
12360    }
12361    const canvasBounds = [0, 0, currentCtx.canvas.width, currentCtx.canvas.height];
12362    let bounds;
12363    if (group.bbox) {
12364      bounds = F32_BBOX_INIT.slice();
12365      Util.axialAlignedBoundingBox(group.bbox, getCurrentTransform(currentCtx), bounds);
12366      bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
12367    } else {
12368      bounds = canvasBounds;
12369    }
12370    const offsetX = Math.floor(bounds[0]);
12371    const offsetY = Math.floor(bounds[1]);
12372    const drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
12373    const drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
12374    this.current.startNewPathAndClipBox([0, 0, drawnWidth, drawnHeight]);
12375    const scratchCanvas = this.canvasFactory.create(drawnWidth, drawnHeight);
12376    if (group.smask) {
12377      this.smaskGroupCanvases.push(scratchCanvas);
12378    }
12379    const groupCtx = scratchCanvas.context;
12380    const backdropCtx = group.knockout && !group.isolated ? currentCtx : null;
12381    const hasInnerBackdrop = !group.isolated && !group.knockout && !group.smask && group.needsIsolation && this.#knockoutGroupLevel > 0;
12382    const knockoutMaskEntry = group.knockout ? this.canvasFactory.create(drawnWidth, drawnHeight) : null;
12383    const savedKnockoutLevel = this.#knockoutGroupLevel;
12384    if (group.knockout) {
12385      this.#knockoutGroupLevel++;
12386    } else {
12387      this.#knockoutGroupLevel = 0;
12388    }
12389    groupCtx.translate(-offsetX, -offsetY);
12390    groupCtx.transform(...currentTransform);
12391    if (!group.isolated && !group.smask && inSMaskMode && group.needsIsolation) {
12392      groupCtx.save();
12393      groupCtx.setTransform(1, 0, 0, 1, 0, 0);
12394      groupCtx.drawImage(currentCtx.canvas, -offsetX, -offsetY);
12395      groupCtx.restore();
12396    }
12397    if (group.bbox) {
12398      let clip = new Path2D();
12399      const [x0, y0, x1, y1] = group.bbox;
12400      clip.rect(x0, y0, x1 - x0, y1 - y0);
12401      if (group.matrix) {
12402        const path = new Path2D();
12403        path.addPath(clip, new DOMMatrix(group.matrix));
12404        clip = path;
12405      }
12406      groupCtx.clip(clip);
12407    }
12408    if (group.smask) {
12409      this.smaskStack.push({
12410        canvas: scratchCanvas.canvas,
12411        context: groupCtx,
12412        offsetX,
12413        offsetY,
12414        subtype: group.smask.subtype,
12415        backdrop: group.smask.backdrop,
12416        transferMap: group.smask.transferMap || null
12417      });
12418    }
12419    if (!group.smask || this.dependencyTracker) {
12420      currentCtx.setTransform(1, 0, 0, 1, 0, 0);
12421      currentCtx.translate(offsetX, offsetY);
12422      currentCtx.save();
12423    }
12424    copyCtxState(currentCtx, groupCtx);
12425    this.ctx = groupCtx;
12426    this.dependencyTracker?.inheritSimpleDataAsFutureForcedDependencies(["fillAlpha", "strokeAlpha", "globalCompositeOperation"]).pushBaseTransform(currentCtx);
12427    this.setGState(opIdx, [["BM", "source-over"], ["ca", 1], ["CA", 1], ["TR", null]]);
12428    this.groupStack.push(currentCtx);
12429    this.#groupStackMeta.push({
12430      backdropCtx,
12431      savedKnockoutLevel,
12432      offsetX,
12433      offsetY,
12434      hasInnerBackdrop,
12435      knockoutMaskEntry,
12436      knockoutTempEntry: null,
12437      knockoutBackdropEntry: null
12438    });
12439    this.groupLevel++;
12440  }
12441  endGroup(opIdx, group) {
12442    if (!this.contentVisible) {
12443      return;
12444    }
12445    this.groupLevel--;
12446    const groupCtx = this.ctx;
12447    const ctx = this.groupStack.pop();
12448    const groupMeta = this.#groupStackMeta.pop();
12449    if (groupMeta) {
12450      this.#knockoutGroupLevel = groupMeta.savedKnockoutLevel;
12451    }
12452    if (ctx === null) {
12453      this.restore(opIdx);
12454      return;
12455    }
12456    if (group.isGray) {
12457      this.#convertGroupToGray(groupCtx);
12458    }
12459    this.ctx = ctx;
12460    this.ctx.imageSmoothingEnabled = false;
12461    this.dependencyTracker?.popBaseTransform();
12462    if (group.smask) {
12463      this.tempSMask = this.smaskStack.pop();
12464      this.restore(opIdx);
12465      if (this.dependencyTracker) {
12466        this.ctx.restore();
12467        if (this.inSMaskMode) {
12468          this.ctx.setTransform(this.suspendedCtx.getTransform());
12469        }
12470      }
12471      this.#destroyKnockoutPools(groupMeta);
12472    } else {
12473      this.ctx.restore();
12474      const currentMtx = getCurrentTransform(this.ctx);
12475      this.restore(opIdx);
12476      this.ctx.save();
12477      this.ctx.setTransform(...currentMtx);
12478      const dirtyBox = F32_BBOX_INIT.slice();
12479      Util.axialAlignedBoundingBox([0, 0, groupCtx.canvas.width, groupCtx.canvas.height], currentMtx, dirtyBox);
12480      const parentGroupMeta = this.#groupStackMeta.at(-1);
12481      if (this.#knockoutGroupLevel > 0) {
12482        if (groupMeta.hasInnerBackdrop) {
12483          const {
12484            width,
12485            height
12486          } = groupCtx.canvas;
12487          const colorEntry = this.canvasFactory.create(width, height);
12488          const colorCtx = colorEntry.context;
12489          colorCtx.drawImage(ctx.canvas, groupMeta.offsetX, groupMeta.offsetY, width, height, 0, 0, width, height);
12490          colorCtx.globalCompositeOperation = "source-over";
12491          colorCtx.drawImage(groupCtx.canvas, 0, 0);
12492          const shapeMaskEntry = this.#createKnockoutMaskCanvas(groupCtx.canvas);
12493          colorCtx.globalCompositeOperation = "destination-in";
12494          colorCtx.drawImage(shapeMaskEntry.canvas, 0, 0);
12495          const sourceCompositeOperation = this.ctx.globalCompositeOperation;
12496          const sourceAlpha = this.ctx.globalAlpha;
12497          const sourceFilter = this.ctx.filter;
12498          this.ctx.save();
12499          this.ctx.setTransform(...currentMtx);
12500          this.ctx.globalAlpha = 1;
12501          if (FeatureTest.isCanvasFilterSupported) {
12502            this.ctx.filter = "none";
12503          }
12504          this.ctx.globalCompositeOperation = "destination-out";
12505          this.ctx.drawImage(shapeMaskEntry.canvas, 0, 0);
12506          this.ctx.globalCompositeOperation = sourceCompositeOperation;
12507          this.ctx.globalAlpha = sourceAlpha;
12508          if (FeatureTest.isCanvasFilterSupported) {
12509            this.ctx.filter = sourceFilter ?? "none";
12510          }
12511          this.ctx.drawImage(colorEntry.canvas, 0, 0);
12512          this.ctx.restore();
12513          this.canvasFactory.destroy(shapeMaskEntry);
12514          this.canvasFactory.destroy(colorEntry);
12515        } else {
12516          const backdropCtx = parentGroupMeta?.backdropCtx ?? null;
12517          this.#compositeKnockoutSurface(this.ctx, groupCtx.canvas, {
12518            backdropCanvas: backdropCtx?.canvas ?? null,
12519            destTransform: currentMtx,
12520            backdropOffset: backdropCtx ? [parentGroupMeta.offsetX + groupMeta.offsetX, parentGroupMeta.offsetY + groupMeta.offsetY] : [0, 0],
12521            sourceAlpha: this.ctx.globalAlpha,
12522            sourceFilter: this.ctx.filter
12523          });
12524        }
12525      } else {
12526        this.ctx.drawImage(groupCtx.canvas, 0, 0);
12527      }
12528      this.ctx.restore();
12529      this.canvasFactory.destroy({
12530        canvas: groupCtx.canvas,
12531        context: groupCtx
12532      });
12533      this.#destroyKnockoutPools(groupMeta);
12534      this.compose(dirtyBox);
12535    }
12536  }
12537  #convertGroupToGray(groupCtx) {
12538    const {
12539      canvas
12540    } = groupCtx;
12541    const {
12542      width,
12543      height
12544    } = canvas;
12545    if (FeatureTest.isCanvasFilterSupported) {
12546      groupCtx.save();
12547      groupCtx.setTransform(1, 0, 0, 1, 0, 0);
12548      groupCtx.filter = "grayscale(1)";
12549      groupCtx.globalAlpha = 1;
12550      groupCtx.globalCompositeOperation = "copy";
12551      groupCtx.drawImage(canvas, 0, 0);
12552      groupCtx.restore();
12553      return;
12554    }
12555    const imageData = groupCtx.getImageData(0, 0, width, height);
12556    const {
12557      data
12558    } = imageData;
12559    for (let i = 0, ii = data.length; i < ii; i += 4) {
12560      const gray = data[i] * 0.2126 + data[i + 1] * 0.7152 + data[i + 2] * 0.0722 + 0.5 | 0;
12561      data[i] = data[i + 1] = data[i + 2] = gray;
12562    }
12563    groupCtx.putImageData(imageData, 0, 0);
12564  }
12565  #destroyKnockoutPools(groupMeta) {
12566    if (!groupMeta) {
12567      return;
12568    }
12569    if (groupMeta.knockoutMaskEntry) {
12570      this.canvasFactory.destroy(groupMeta.knockoutMaskEntry);
12571      groupMeta.knockoutMaskEntry = null;
12572    }
12573    if (groupMeta.knockoutTempEntry) {
12574      this.canvasFactory.destroy(groupMeta.knockoutTempEntry);
12575      groupMeta.knockoutTempEntry = null;
12576    }
12577    if (groupMeta.knockoutBackdropEntry) {
12578      this.canvasFactory.destroy(groupMeta.knockoutBackdropEntry);
12579      groupMeta.knockoutBackdropEntry = null;
12580    }
12581  }
12582  beginAnnotation(opIdx, id, rect, transform, matrix, hasOwnCanvas, canvasName) {
12583    this.#restoreInitialState();
12584    resetCtxToDefault(this.ctx);
12585    this.ctx.save();
12586    this.save(opIdx);
12587    if (this.baseTransform) {
12588      this.ctx.setTransform(...this.baseTransform);
12589    }
12590    if (rect) {
12591      const width = rect[2] - rect[0];
12592      const height = rect[3] - rect[1];
12593      if (hasOwnCanvas && this.annotationCanvasMap) {
12594        transform = transform.slice();
12595        transform[4] -= rect[0];
12596        transform[5] -= rect[1];
12597        rect = rect.slice();
12598        rect[0] = rect[1] = 0;
12599        rect[2] = width;
12600        rect[3] = height
vendor: 14,517 bytes, lines 12600-13019
12600;
12601        Util.singularValueDecompose2dScale(getCurrentTransform(this.ctx), XY);
12602        const {
12603          viewportScale
12604        } = this;
12605        const canvasWidth = Math.ceil(width * this.outputScaleX * viewportScale);
12606        const canvasHeight = Math.ceil(height * this.outputScaleY * viewportScale);
12607        this.annotationCanvas = this.canvasFactory.create(canvasWidth, canvasHeight);
12608        const {
12609          canvas,
12610          context
12611        } = this.annotationCanvas;
12612        if (canvasName) {
12613          const canvases = this.annotationCanvasMap.getOrInsertComputed(id, makeArr);
12614          canvas.setAttribute("data-canvas-name", canvasName);
12615          const index = canvases.findIndex(c => c.getAttribute("data-canvas-name") === canvasName);
12616          if (index === -1) {
12617            canvases.push(canvas);
12618          } else {
12619            canvases[index] = canvas;
12620          }
12621        } else {
12622          this.annotationCanvasMap.set(id, canvas);
12623        }
12624        this.annotationCanvas.savedCtx = this.ctx;
12625        this.ctx = context;
12626        this.ctx.save();
12627        this.ctx.setTransform(XY[0], 0, 0, -XY[1], 0, height * XY[1]);
12628        resetCtxToDefault(this.ctx);
12629      } else {
12630        resetCtxToDefault(this.ctx);
12631        this.endPath(opIdx);
12632        const clip = new Path2D();
12633        clip.rect(rect[0], rect[1], width, height);
12634        this.ctx.clip(clip);
12635      }
12636    }
12637    this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height);
12638    this.baseTransformStack.push(this.baseTransform);
12639    this.transform(opIdx, ...transform);
12640    this.transform(opIdx, ...matrix);
12641    this.baseTransform = getCurrentTransform(this.ctx);
12642  }
12643  endAnnotation(opIdx) {
12644    if (this.annotationCanvas) {
12645      this.ctx.restore();
12646      this.#drawFilter();
12647      this.ctx = this.annotationCanvas.savedCtx;
12648      delete this.annotationCanvas.savedCtx;
12649      delete this.annotationCanvas;
12650    }
12651    this.baseTransform = this.baseTransformStack.pop();
12652  }
12653  paintImageMaskXObject(opIdx, img) {
12654    if (!this.contentVisible) {
12655      return;
12656    }
12657    const count = img.count;
12658    img = this.getObject(opIdx, img.data, img);
12659    img.count = count;
12660    const started = this.#beginKnockoutElement(this.current.fillAlpha);
12661    const ctx = this.ctx;
12662    const mask = this._createMaskCanvas(opIdx, img);
12663    const maskCanvas = mask.canvas;
12664    ctx.save();
12665    ctx.setTransform(1, 0, 0, 1, 0, 0);
12666    ctx.drawImage(maskCanvas, mask.offsetX, mask.offsetY);
12667    this.dependencyTracker?.resetBBox(opIdx).recordBBox(opIdx, this.ctx, mask.offsetX, mask.offsetX + maskCanvas.width, mask.offsetY, mask.offsetY + maskCanvas.height).recordOperation(opIdx);
12668    ctx.restore();
12669    if (mask.canvasEntry) {
12670      this.canvasFactory.destroy(mask.canvasEntry);
12671    }
12672    this.compose();
12673    this.#endKnockoutElement(started);
12674  }
12675  paintImageMaskXObjectRepeat(opIdx, img, scaleX, skewX = 0, skewY = 0, scaleY, positions) {
12676    if (!this.contentVisible) {
12677      return;
12678    }
12679    img = this.getObject(opIdx, img.data, img);
12680    const started = this.#beginKnockoutElement(this.current.fillAlpha);
12681    const ctx = this.ctx;
12682    ctx.save();
12683    const currentTransform = getCurrentTransform(ctx);
12684    ctx.transform(scaleX, skewX, skewY, scaleY, 0, 0);
12685    const mask = this._createMaskCanvas(opIdx, img);
12686    ctx.setTransform(1, 0, 0, 1, mask.offsetX - currentTransform[4], mask.offsetY - currentTransform[5]);
12687    this.dependencyTracker?.resetBBox(opIdx);
12688    for (let i = 0, ii = positions.length; i < ii; i += 2) {
12689      const trans = Util.transform(currentTransform, [scaleX, skewX, skewY, scaleY, positions[i], positions[i + 1]]);
12690      ctx.drawImage(mask.canvas, trans[4], trans[5]);
12691      this.dependencyTracker?.recordBBox(opIdx, this.ctx, trans[4], trans[4] + mask.canvas.width, trans[5], trans[5] + mask.canvas.height);
12692    }
12693    ctx.restore();
12694    if (mask.canvasEntry) {
12695      this.canvasFactory.destroy(mask.canvasEntry);
12696    }
12697    this.compose();
12698    this.dependencyTracker?.recordOperation(opIdx);
12699    this.#endKnockoutElement(started);
12700  }
12701  paintImageMaskXObjectGroup(opIdx, images) {
12702    if (!this.contentVisible) {
12703      return;
12704    }
12705    const started = this.#beginKnockoutElement(this.current.fillAlpha);
12706    const ctx = this.ctx;
12707    const fillColor = this.current.fillColor;
12708    const isPatternFill = this.current.patternFill;
12709    this.dependencyTracker?.resetBBox(opIdx).recordDependencies(opIdx, Dependencies.transformAndFill);
12710    for (const image of images) {
12711      const {
12712        data,
12713        width,
12714        height,
12715        transform
12716      } = image;
12717      const maskCanvas = this.canvasFactory.create(width, height);
12718      const maskCtx = maskCanvas.context;
12719      maskCtx.save();
12720      const img = this.getObject(opIdx, data, image);
12721      putBinaryImageMask(maskCtx, img);
12722      maskCtx.globalCompositeOperation = "source-in";
12723      maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, getCurrentTransformInverse(ctx), PathType.FILL, opIdx) : fillColor;
12724      maskCtx.fillRect(0, 0, width, height);
12725      maskCtx.restore();
12726      ctx.save();
12727      ctx.transform(...transform);
12728      ctx.scale(1, -1);
12729      drawImageAtIntegerCoords(ctx, maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
12730      this.canvasFactory.destroy(maskCanvas);
12731      this.dependencyTracker?.recordBBox(opIdx, ctx, 0, width, 0, height);
12732      ctx.restore();
12733    }
12734    this.compose();
12735    this.dependencyTracker?.recordOperation(opIdx);
12736    this.#endKnockoutElement(started);
12737  }
12738  paintImageXObject(opIdx, objId) {
12739    if (!this.contentVisible) {
12740      return;
12741    }
12742    const imgData = this.getObject(opIdx, objId);
12743    if (!imgData) {
12744      warn("Dependent image isn't ready yet");
12745      return;
12746    }
12747    this.paintInlineImageXObject(opIdx, imgData);
12748  }
12749  paintImageXObjectRepeat(opIdx, objId, scaleX, scaleY, positions) {
12750    if (!this.contentVisible) {
12751      return;
12752    }
12753    const imgData = this.getObject(opIdx, objId);
12754    if (!imgData) {
12755      warn("Dependent image isn't ready yet");
12756      return;
12757    }
12758    const width = imgData.width;
12759    const height = imgData.height;
12760    const map = [];
12761    for (let i = 0, ii = positions.length; i < ii; i += 2) {
12762      map.push({
12763        transform: [scaleX, 0, 0, scaleY, positions[i], positions[i + 1]],
12764        x: 0,
12765        y: 0,
12766        w: width,
12767        h: height
12768      });
12769    }
12770    this.paintInlineImageXObjectGroup(opIdx, imgData, map);
12771  }
12772  applyTransferMapsToCanvas(ctx) {
12773    if (this.current.transferMaps !== "none") {
12774      ctx.filter = this.current.transferMaps;
12775      ctx.drawImage(ctx.canvas, 0, 0);
12776      ctx.filter = "none";
12777    }
12778    return ctx.canvas;
12779  }
12780  applyTransferMapsToBitmap(imgData) {
12781    if (this.current.transferMaps === "none") {
12782      return {
12783        img: imgData.bitmap,
12784        canvasEntry: null
12785      };
12786    }
12787    const {
12788      bitmap,
12789      width,
12790      height
12791    } = imgData;
12792    const tmpCanvas = this.canvasFactory.create(width, height);
12793    const tmpCtx = tmpCanvas.context;
12794    tmpCtx.filter = this.current.transferMaps;
12795    tmpCtx.drawImage(bitmap, 0, 0);
12796    tmpCtx.filter = "none";
12797    return {
12798      img: tmpCanvas.canvas,
12799      canvasEntry: tmpCanvas
12800    };
12801  }
12802  paintInlineImageXObject(opIdx, imgData) {
12803    if (!this.contentVisible) {
12804      return;
12805    }
12806    const width = imgData.width;
12807    const height = imgData.height;
12808    const started = this.#beginKnockoutElement(this.current.fillAlpha);
12809    const ctx = this.ctx;
12810    this.save(opIdx);
12811    const {
12812      filter
12813    } = ctx;
12814    if (filter !== "none" && filter !== "") {
12815      ctx.filter = "none";
12816    }
12817    ctx.scale(1 / width, -1 / height);
12818    let imgToPaint;
12819    let inlineImgCanvas = null;
12820    if (imgData.bitmap) {
12821      const result = this.applyTransferMapsToBitmap(imgData);
12822      imgToPaint = result.img;
12823      inlineImgCanvas = result.canvasEntry;
12824    } else {
12825      const tmpCanvas = this.canvasFactory.create(width, height);
12826      putBinaryImageData(tmpCanvas.context, imgData);
12827      imgToPaint = this.applyTransferMapsToCanvas(tmpCanvas.context);
12828      inlineImgCanvas = tmpCanvas;
12829    }
12830    const scaled = this._scaleImage(imgToPaint, getCurrentTransformInverse(ctx));
12831    ctx.imageSmoothingEnabled = getImageSmoothingEnabled(getCurrentTransform(ctx), imgData.interpolate);
12832    if (this.dependencyTracker) {
12833      this.dependencyTracker.resetBBox(opIdx).recordBBox(opIdx, ctx, 0, width, -height, 0).recordDependencies(opIdx, Dependencies.imageXObject).recordOperation(opIdx);
12834      this.imagesTracker?.record(ctx, width, height, this.dependencyTracker.clipBox);
12835    }
12836    drawImageAtIntegerCoords(ctx, scaled.img, 0, 0, scaled.paintWidth, scaled.paintHeight, 0, -height, width, height);
12837    if (scaled.tmpCanvas) {
12838      this.canvasFactory.destroy(scaled.tmpCanvas);
12839    }
12840    if (inlineImgCanvas) {
12841      this.canvasFactory.destroy(inlineImgCanvas);
12842    }
12843    this.compose();
12844    this.restore(opIdx);
12845    this.#endKnockoutElement(started);
12846  }
12847  paintInlineImageXObjectGroup(opIdx, imgData, map) {
12848    if (!this.contentVisible) {
12849      return;
12850    }
12851    const started = this.#beginKnockoutElement(this.current.fillAlpha);
12852    const ctx = this.ctx;
12853    let imgToPaint;
12854    let inlineImgCanvas = null;
12855    if (imgData.bitmap) {
12856      imgToPaint = imgData.bitmap;
12857    } else {
12858      const w = imgData.width;
12859      const h = imgData.height;
12860      const tmpCanvas = this.canvasFactory.create(w, h);
12861      putBinaryImageData(tmpCanvas.context, imgData);
12862      imgToPaint = this.applyTransferMapsToCanvas(tmpCanvas.context);
12863      inlineImgCanvas = tmpCanvas;
12864    }
12865    this.dependencyTracker?.resetBBox(opIdx);
12866    for (const entry of map) {
12867      ctx.save();
12868      ctx.transform(...entry.transform);
12869      ctx.scale(1, -1);
12870      drawImageAtIntegerCoords(ctx, imgToPaint, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1);
12871      this.dependencyTracker?.recordBBox(opIdx, ctx, 0, 1, -1, 0);
12872      ctx.restore();
12873    }
12874    if (inlineImgCanvas) {
12875      this.canvasFactory.destroy(inlineImgCanvas);
12876    }
12877    this.dependencyTracker?.recordOperation(opIdx);
12878    this.compose();
12879    this.#endKnockoutElement(started);
12880  }
12881  paintSolidColorImageMask(opIdx) {
12882    if (!this.contentVisible) {
12883      return;
12884    }
12885    const started = this.#beginKnockoutElement(this.current.fillAlpha);
12886    this.dependencyTracker?.resetBBox(opIdx).recordBBox(opIdx, this.ctx, 0, 1, 0, 1).recordDependencies(opIdx, Dependencies.fill).recordOperation(opIdx);
12887    this.ctx.fillRect(0, 0, 1, 1);
12888    this.compose();
12889    this.#endKnockoutElement(started);
12890  }
12891  markPoint(opIdx, tag) {}
12892  markPointProps(opIdx, tag, properties) {}
12893  beginMarkedContent(opIdx, tag) {
12894    this.dependencyTracker?.beginMarkedContent(opIdx);
12895    this.markedContentStack.push({
12896      visible: true
12897    });
12898  }
12899  beginMarkedContentProps(opIdx, tag, properties) {
12900    this.dependencyTracker?.beginMarkedContent(opIdx);
12901    if (tag === "OC") {
12902      this.markedContentStack.push({
12903        visible: this.optionalContentConfig.isVisible(properties)
12904      });
12905    } else {
12906      this.markedContentStack.push({
12907        visible: true
12908      });
12909    }
12910    this.contentVisible = this.isContentVisible();
12911  }
12912  endMarkedContent(opIdx) {
12913    this.dependencyTracker?.endMarkedContent(opIdx);
12914    this.markedContentStack.pop();
12915    this.contentVisible = this.isContentVisible();
12916  }
12917  beginCompat(opIdx) {}
12918  endCompat(opIdx) {}
12919  consumePath(opIdx, path, clipBox) {
12920    const isEmpty = this.current.isEmptyClip();
12921    if (this.pendingClip) {
12922      this.current.updateClipFromPath();
12923    }
12924    if (!this.pendingClip) {
12925      this.compose(clipBox);
12926    }
12927    const ctx = this.ctx;
12928    if (this.pendingClip) {
12929      if (!isEmpty) {
12930        if (this.pendingClip === EO_CLIP) {
12931          ctx.clip(path, "evenodd");
12932        } else {
12933          ctx.clip(path);
12934        }
12935      }
12936      this.pendingClip = null;
12937      this.dependencyTracker?.bboxToClipBoxDropOperation(opIdx).recordFutureForcedDependency("clipPath", opIdx);
12938    } else {
12939      this.dependencyTracker?.recordOperation(opIdx);
12940    }
12941    this.current.startNewPathAndClipBox(this.current.clipBox);
12942  }
12943  getSinglePixelWidth() {
12944    if (!this._cachedGetSinglePixelWidth) {
12945      const m = getCurrentTransform(this.ctx);
12946      if (m[1] === 0 && m[2] === 0) {
12947        this._cachedGetSinglePixelWidth = 1 / Math.min(Math.abs(m[0]), Math.abs(m[3]));
12948      } else {
12949        const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]);
12950        const normX = Math.hypot(m[0], m[2]);
12951        const normY = Math.hypot(m[1], m[3]);
12952        this._cachedGetSinglePixelWidth = Math.max(normX, normY) / absDet;
12953      }
12954    }
12955    return this._cachedGetSinglePixelWidth;
12956  }
12957  getScaleForStroking() {
12958    if (this._cachedScaleForStroking[0] === -1) {
12959      const {
12960        lineWidth
12961      } = this.current;
12962      const {
12963        a,
12964        b,
12965        c,
12966        d
12967      } = this.ctx.getTransform();
12968      let scaleX, scaleY;
12969      if (b === 0 && c === 0) {
12970        const normX = Math.abs(a);
12971        const normY = Math.abs(d);
12972        if (normX === normY) {
12973          if (lineWidth === 0) {
12974            scaleX = scaleY = 1 / normX;
12975          } else {
12976            const scaledLineWidth = normX * lineWidth;
12977            scaleX = scaleY = scaledLineWidth < 1 ? 1 / scaledLineWidth : 1;
12978          }
12979        } else if (lineWidth === 0) {
12980          scaleX = 1 / normX;
12981          scaleY = 1 / normY;
12982        } else {
12983          const scaledXLineWidth = normX * lineWidth;
12984          const scaledYLineWidth = normY * lineWidth;
12985          scaleX = scaledXLineWidth < 1 ? 1 / scaledXLineWidth : 1;
12986          scaleY = scaledYLineWidth < 1 ? 1 / scaledYLineWidth : 1;
12987        }
12988      } else {
12989        const absDet = Math.abs(a * d - b * c);
12990        const normX = Math.hypot(a, b);
12991        const normY = Math.hypot(c, d);
12992        if (lineWidth === 0) {
12993          scaleX = normY / absDet;
12994          scaleY = normX / absDet;
12995        } else {
12996          const baseArea = lineWidth * absDet;
12997          scaleX = normY > baseArea ? normY / baseArea : 1;
12998          scaleY = normX > baseArea ? normX / baseArea : 1;
12999        }
13000      }
13001      this._cachedScaleForStroking[0] = scaleX;
13002      this._cachedScaleForStroking[1] = scaleY;
13003    }
13004    return this._cachedScaleForStroking;
13005  }
13006  rescaleAndStroke(path, saveRestore) {
13007    const {
13008      ctx,
13009      current: {
13010        lineWidth
13011      }
13012    } = this;
13013    const [scaleX, scaleY] = this.getScaleForStroking();
13014    if (scaleX === scaleY) {
13015      ctx.lineWidth = (lineWidth || 1) * scaleX;
13016      ctx.stroke(path);
13017      return;
13018    }
13019    const 
vendor: 7,361 bytes, lines 13019-13288
13019dashes = ctx.getLineDash();
13020    if (saveRestore) {
13021      ctx.save();
13022    }
13023    ctx.scale(scaleX, scaleY);
13024    SCALE_MATRIX.a = 1 / scaleX;
13025    SCALE_MATRIX.d = 1 / scaleY;
13026    const newPath = new Path2D();
13027    newPath.addPath(path, SCALE_MATRIX);
13028    if (dashes.length > 0) {
13029      const scale = Math.max(scaleX, scaleY);
13030      ctx.setLineDash(dashes.map(x => x / scale));
13031      ctx.lineDashOffset /= scale;
13032    }
13033    ctx.lineWidth = lineWidth || 1;
13034    ctx.stroke(newPath);
13035    if (saveRestore) {
13036      ctx.restore();
13037    }
13038  }
13039  isContentVisible() {
13040    for (let i = this.markedContentStack.length - 1; i >= 0; i--) {
13041      if (!this.markedContentStack[i].visible) {
13042        return false;
13043      }
13044    }
13045    return true;
13046  }
13047}
13048for (const op in OPS) {
13049  if (CanvasGraphics.prototype[op] !== undefined) {
13050    CanvasGraphics.prototype[OPS[op]] = CanvasGraphics.prototype[op];
13051  }
13052}
13053
13054;// ./src/shared/base_pdf_stream.js
13055
13056class BasePDFStream {
13057  #PDFStreamReader = null;
13058  #PDFStreamRangeReader = null;
13059  _fullReader = null;
13060  _rangeReaders = new Set();
13061  _source = null;
13062  constructor(source, PDFStreamReader, PDFStreamRangeReader) {
13063    this._source = source;
13064    this.#PDFStreamReader = PDFStreamReader;
13065    this.#PDFStreamRangeReader = PDFStreamRangeReader;
13066  }
13067  get _progressiveDataLength() {
13068    return this._fullReader?._loaded ?? 0;
13069  }
13070  getFullReader() {
13071    assert(!this._fullReader, "BasePDFStream.getFullReader can only be called once.");
13072    return this._fullReader = new this.#PDFStreamReader(this);
13073  }
13074  getRangeReader(begin, end) {
13075    if (end <= this._progressiveDataLength) {
13076      return null;
13077    }
13078    const reader = new this.#PDFStreamRangeReader(this, begin, end);
13079    this._rangeReaders.add(reader);
13080    return reader;
13081  }
13082  cancelAllRequests(reason) {
13083    this._fullReader?.cancel(reason);
13084    for (const reader of new Set(this._rangeReaders)) {
13085      reader.cancel(reason);
13086    }
13087  }
13088}
13089class BasePDFStreamReader {
13090  onProgress = null;
13091  _contentLength = 0;
13092  _filename = null;
13093  _headersCapability = Promise.withResolvers();
13094  _isRangeSupported = false;
13095  _isStreamingSupported = false;
13096  _loaded = 0;
13097  _stream = null;
13098  constructor(stream) {
13099    this._stream = stream;
13100  }
13101  _callOnProgress() {
13102    this.onProgress?.({
13103      loaded: this._loaded,
13104      total: this._contentLength
13105    });
13106  }
13107  get headersReady() {
13108    return this._headersCapability.promise;
13109  }
13110  get filename() {
13111    return this._filename;
13112  }
13113  get contentLength() {
13114    return this._contentLength;
13115  }
13116  get isRangeSupported() {
13117    return this._isRangeSupported;
13118  }
13119  get isStreamingSupported() {
13120    return this._isStreamingSupported;
13121  }
13122  async read() {
13123    unreachable("Abstract method `read` called");
13124  }
13125  cancel(reason) {
13126    unreachable("Abstract method `cancel` called");
13127  }
13128}
13129class BasePDFStreamRangeReader {
13130  _stream = null;
13131  constructor(stream, begin, end) {
13132    this._stream = stream;
13133  }
13134  async read() {
13135    unreachable("Abstract method `read` called");
13136  }
13137  cancel(reason) {
13138    unreachable("Abstract method `cancel` called");
13139  }
13140}
13141
13142;// ./src/display/content_disposition.js
13143
13144function getFilenameFromContentDispositionHeader(contentDisposition) {
13145  let needsEncodingFixup = true;
13146  let tmp = toParamRegExp("filename\\*", "i").exec(contentDisposition);
13147  if (tmp) {
13148    tmp = tmp[1];
13149    let filename = rfc2616unquote(tmp);
13150    filename = unescape(filename);
13151    filename = rfc5987decode(filename);
13152    filename = rfc2047decode(filename);
13153    return fixupEncoding(filename);
13154  }
13155  tmp = rfc2231getparam(contentDisposition);
13156  if (tmp) {
13157    const filename = rfc2047decode(tmp);
13158    return fixupEncoding(filename);
13159  }
13160  tmp = toParamRegExp("filename", "i").exec(contentDisposition);
13161  if (tmp) {
13162    tmp = tmp[1];
13163    let filename = rfc2616unquote(tmp);
13164    filename = rfc2047decode(filename);
13165    return fixupEncoding(filename);
13166  }
13167  function toParamRegExp(attributePattern, flags) {
13168    return new RegExp("(?:^|;)\\s*" + attributePattern + "\\s*=\\s*" + "(" + '[^";\\s][^;\\s]*' + "|" + '"(?:[^"\\\\]|\\\\"?)+"?' + ")", flags);
13169  }
13170  function textdecode(encoding, value) {
13171    if (encoding) {
13172      if (!/^[\x00-\xFF]+$/.test(value)) {
13173        return value;
13174      }
13175      try {
13176        const decoder = new TextDecoder(encoding, {
13177          fatal: true
13178        });
13179        const buffer = stringToBytes(value);
13180        value = decoder.decode(buffer);
13181        needsEncodingFixup = false;
13182      } catch {}
13183    }
13184    return value;
13185  }
13186  function fixupEncoding(value) {
13187    if (needsEncodingFixup && /[\x80-\xff]/.test(value)) {
13188      value = textdecode("utf-8", value);
13189      if (needsEncodingFixup) {
13190        value = textdecode("iso-8859-1", value);
13191      }
13192    }
13193    return value;
13194  }
13195  function rfc2231getparam(contentDispositionStr) {
13196    const matches = [];
13197    let match;
13198    const iter = toParamRegExp("filename\\*((?!0\\d)\\d+)(\\*?)", "ig");
13199    while ((match = iter.exec(contentDispositionStr)) !== null) {
13200      let [, n, quot, part] = match;
13201      n = parseInt(n, 10);
13202      if (n in matches) {
13203        if (n === 0) {
13204          break;
13205        }
13206        continue;
13207      }
13208      matches[n] = [quot, part];
13209    }
13210    const parts = [];
13211    for (let n = 0; n < matches.length; ++n) {
13212      if (!(n in matches)) {
13213        break;
13214      }
13215      let [quot, part] = matches[n];
13216      part = rfc2616unquote(part);
13217      if (quot) {
13218        part = unescape(part);
13219        if (n === 0) {
13220          part = rfc5987decode(part);
13221        }
13222      }
13223      parts.push(part);
13224    }
13225    return parts.join("");
13226  }
13227  function rfc2616unquote(value) {
13228    if (value.startsWith('"')) {
13229      const parts = value.slice(1).split('\\"');
13230      for (let i = 0; i < parts.length; ++i) {
13231        const quotindex = parts[i].indexOf('"');
13232        if (quotindex !== -1) {
13233          parts[i] = parts[i].slice(0, quotindex);
13234          parts.length = i + 1;
13235        }
13236        parts[i] = parts[i].replaceAll(/\\(.)/g, "$1");
13237      }
13238      value = parts.join('"');
13239    }
13240    return value;
13241  }
13242  function rfc5987decode(extvalue) {
13243    const encodingend = extvalue.indexOf("'");
13244    if (encodingend === -1) {
13245      return extvalue;
13246    }
13247    const encoding = extvalue.slice(0, encodingend);
13248    const langvalue = extvalue.slice(encodingend + 1);
13249    const value = langvalue.replace(/^[^']*'/, "");
13250    return textdecode(encoding, value);
13251  }
13252  function rfc2047decode(value) {
13253    if (!value.startsWith("=?") || /[\x00-\x19\x80-\xff]/.test(value)) {
13254      return value;
13255    }
13256    return value.replaceAll(/=\?([\w-]*)\?([QB])\?((?:[^?]|\?(?!=))*)\?=/gi, function (matches, charset, encoding, text) {
13257      if (encoding === "q" || encoding === "Q") {
13258        text = text.replaceAll("_", " ");
13259        text = text.replaceAll(/=([0-9a-f]{2})/gi, function (match, hex) {
13260          return String.fromCharCode(parseInt(hex, 16));
13261        });
13262        return textdecode(charset, text);
13263      }
13264      try {
13265        text = atob(text);
13266      } catch {}
13267      return textdecode(charset, text);
13268    });
13269  }
13270  return "";
13271}
13272
13273;// ./src/display/network_utils.js
13274
13275
13276
13277function createHeaders(isHttp, httpHeaders) {
13278  const headers = new Headers();
13279  if (!isHttp || !httpHeaders || typeof httpHeaders !== "object") {
13280    return headers;
13281  }
13282  for (const key in httpHeaders) {
13283    const val = httpHeaders[key];
13284    if (val !== undefined) {
13285      headers.append(key, val);
13286    }
13287  }
13288  return headers
vendor: 15,331 bytes, lines 13288-13838
13288;
13289}
13290function getResponseOrigin(url) {
13291  return URL.parse(url)?.origin ?? null;
13292}
13293function validateRangeRequestCapabilities({
13294  responseHeaders,
13295  isHttp,
13296  rangeChunkSize,
13297  disableRange
13298}) {
13299  const rv = {
13300    contentLength: 0,
13301    isRangeSupported: false
13302  };
13303  const length = parseInt(responseHeaders.get("Content-Length"), 10);
13304  if (!Number.isInteger(length)) {
13305    return rv;
13306  }
13307  rv.contentLength = length;
13308  if (length <= 2 * rangeChunkSize) {
13309    return rv;
13310  }
13311  if (disableRange || !isHttp) {
13312    return rv;
13313  }
13314  if (responseHeaders.get("Accept-Ranges") !== "bytes") {
13315    return rv;
13316  }
13317  const contentEncoding = responseHeaders.get("Content-Encoding") || "identity";
13318  if (contentEncoding === "identity") {
13319    rv.isRangeSupported = true;
13320  }
13321  return rv;
13322}
13323function extractFilenameFromHeader(responseHeaders) {
13324  const contentDisposition = responseHeaders.get("Content-Disposition");
13325  if (contentDisposition) {
13326    let filename = getFilenameFromContentDispositionHeader(contentDisposition);
13327    if (filename.includes("%")) {
13328      try {
13329        filename = decodeURIComponent(filename);
13330      } catch {}
13331    }
13332    if (isPdfFile(filename)) {
13333      return filename;
13334    }
13335  }
13336  return null;
13337}
13338function createResponseError(status, url) {
13339  return new ResponseException(`Unexpected server response (${status}) while retrieving PDF "${url.href}".`, status, status === 404 || status === 0 && url.protocol === "file:");
13340}
13341function ensureResponseOrigin(rangeOrigin, origin) {
13342  if (rangeOrigin !== origin) {
13343    throw new Error(`Expected range response-origin "${rangeOrigin}" to match "${origin}".`);
13344  }
13345}
13346
13347;// ./src/display/fetch_stream.js
13348
13349
13350
13351function fetchUrl(url, headers, withCredentials, abortController) {
13352  return fetch(url, {
13353    method: "GET",
13354    headers,
13355    signal: abortController.signal,
13356    mode: "cors",
13357    credentials: withCredentials ? "include" : "same-origin",
13358    redirect: "follow"
13359  });
13360}
13361function ensureResponseStatus(status, url) {
13362  if (status !== 200 && status !== 206) {
13363    throw createResponseError(status, url);
13364  }
13365}
13366function getArrayBuffer(val) {
13367  if (val instanceof Uint8Array) {
13368    return val.buffer;
13369  }
13370  if (val instanceof ArrayBuffer) {
13371    return val;
13372  }
13373  throw new Error(`getArrayBuffer - unexpected data: ${val}`);
13374}
13375class PDFFetchStream extends BasePDFStream {
13376  _responseOrigin = null;
13377  constructor(source) {
13378    super(source, PDFFetchStreamReader, PDFFetchStreamRangeReader);
13379    const {
13380      httpHeaders,
13381      url
13382    } = source;
13383    assert(/https?:/.test(url.protocol), "PDFFetchStream only supports http(s):// URLs.");
13384    this.headers = createHeaders(true, httpHeaders);
13385  }
13386}
13387class PDFFetchStreamReader extends BasePDFStreamReader {
13388  _abortController = new AbortController();
13389  _reader = null;
13390  constructor(stream) {
13391    super(stream);
13392    const {
13393      disableRange,
13394      disableStream,
13395      rangeChunkSize,
13396      url,
13397      withCredentials
13398    } = stream._source;
13399    this._isStreamingSupported = !disableStream;
13400    const headers = new Headers(stream.headers);
13401    fetchUrl(url, headers, withCredentials, this._abortController).then(response => {
13402      stream._responseOrigin = getResponseOrigin(response.url);
13403      ensureResponseStatus(response.status, url);
13404      this._reader = response.body.getReader();
13405      const responseHeaders = response.headers;
13406      const {
13407        contentLength,
13408        isRangeSupported
13409      } = validateRangeRequestCapabilities({
13410        responseHeaders,
13411        isHttp: true,
13412        rangeChunkSize,
13413        disableRange
13414      });
13415      this._contentLength = contentLength;
13416      this._isRangeSupported = isRangeSupported;
13417      this._filename = extractFilenameFromHeader(responseHeaders);
13418      if (!this._isStreamingSupported && this._isRangeSupported) {
13419        this.cancel(new AbortException("Streaming is disabled."));
13420      }
13421      this._headersCapability.resolve();
13422    }).catch(this._headersCapability.reject);
13423  }
13424  async read() {
13425    await this._headersCapability.promise;
13426    const {
13427      value,
13428      done
13429    } = await this._reader.read();
13430    if (done) {
13431      return {
13432        value,
13433        done
13434      };
13435    }
13436    this._loaded += value.byteLength;
13437    this._callOnProgress();
13438    return {
13439      value: getArrayBuffer(value),
13440      done: false
13441    };
13442  }
13443  cancel(reason) {
13444    this._reader?.cancel(reason);
13445    this._abortController.abort();
13446  }
13447}
13448class PDFFetchStreamRangeReader extends BasePDFStreamRangeReader {
13449  _abortController = new AbortController();
13450  _readCapability = Promise.withResolvers();
13451  _reader = null;
13452  constructor(stream, begin, end) {
13453    super(stream, begin, end);
13454    const {
13455      url,
13456      withCredentials
13457    } = stream._source;
13458    const headers = new Headers(stream.headers);
13459    headers.append("Range", `bytes=${begin}-${end - 1}`);
13460    fetchUrl(url, headers, withCredentials, this._abortController).then(response => {
13461      const responseOrigin = getResponseOrigin(response.url);
13462      ensureResponseOrigin(responseOrigin, stream._responseOrigin);
13463      ensureResponseStatus(response.status, url);
13464      this._reader = response.body.getReader();
13465      this._readCapability.resolve();
13466    }).catch(this._readCapability.reject);
13467  }
13468  async read() {
13469    await this._readCapability.promise;
13470    const {
13471      value,
13472      done
13473    } = await this._reader.read();
13474    if (done) {
13475      return {
13476        value,
13477        done
13478      };
13479    }
13480    return {
13481      value: getArrayBuffer(value),
13482      done: false
13483    };
13484  }
13485  cancel(reason) {
13486    this._reader?.cancel(reason);
13487    this._abortController.abort();
13488  }
13489}
13490
13491;// ./src/display/transport_stream.js
13492
13493
13494
13495function transport_stream_getArrayBuffer(val) {
13496  return val instanceof Uint8Array && val.byteLength === val.buffer.byteLength ? val.buffer : new Uint8Array(val).buffer;
13497}
13498function endRequests() {
13499  for (const capability of this._requests) {
13500    capability.resolve({
13501      value: undefined,
13502      done: true
13503    });
13504  }
13505  this._requests.length = 0;
13506}
13507class PDFDataTransportStream extends BasePDFStream {
13508  _progressiveDone = false;
13509  _queuedChunks = [];
13510  constructor(source) {
13511    super(source, PDFDataTransportStreamReader, PDFDataTransportStreamRangeReader);
13512    const {
13513      pdfDataRangeTransport
13514    } = source;
13515    const {
13516      initialData,
13517      progressiveDone
13518    } = pdfDataRangeTransport;
13519    if (initialData?.length > 0) {
13520      const buffer = transport_stream_getArrayBuffer(initialData);
13521      this._queuedChunks.push(buffer);
13522    }
13523    this._progressiveDone = progressiveDone;
13524    const listener = args => {
13525      switch (args.type) {
13526        case "range":
13527        case "progressiveRead":
13528          this.#onReceiveData(args.begin, args.chunk);
13529          break;
13530        case "progressiveDone":
13531          this._fullReader?.progressiveDone();
13532          this._progressiveDone = true;
13533          break;
13534      }
13535    };
13536    pdfDataRangeTransport.transportReady(listener);
13537  }
13538  #onReceiveData(begin, chunk) {
13539    const buffer = transport_stream_getArrayBuffer(chunk);
13540    if (begin === undefined) {
13541      if (this._fullReader) {
13542        this._fullReader._enqueue(buffer);
13543      } else {
13544        this._queuedChunks.push(buffer);
13545      }
13546    } else {
13547      const rangeReader = this._rangeReaders.keys().find(r => r._begin === begin);
13548      assert(rangeReader, "#onReceiveData - no `PDFDataTransportStreamRangeReader` instance found.");
13549      rangeReader._enqueue(buffer);
13550    }
13551  }
13552  getFullReader() {
13553    const reader = super.getFullReader();
13554    this._queuedChunks = null;
13555    return reader;
13556  }
13557  getRangeReader(begin, end) {
13558    const reader = super.getRangeReader(begin, end);
13559    if (reader) {
13560      reader.onDone = () => this._rangeReaders.delete(reader);
13561      this._source.pdfDataRangeTransport.requestDataRange(begin, end);
13562    }
13563    return reader;
13564  }
13565  cancelAllRequests(reason) {
13566    super.cancelAllRequests(reason);
13567    this._source.pdfDataRangeTransport.abort();
13568  }
13569}
13570class PDFDataTransportStreamReader extends BasePDFStreamReader {
13571  #endRequests = endRequests.bind(this);
13572  _done = false;
13573  _queuedChunks = null;
13574  _requests = [];
13575  constructor(stream) {
13576    super(stream);
13577    const {
13578      pdfDataRangeTransport,
13579      disableRange,
13580      disableStream
13581    } = stream._source;
13582    const {
13583      length,
13584      contentDispositionFilename
13585    } = pdfDataRangeTransport;
13586    this._queuedChunks = stream._queuedChunks || [];
13587    for (const chunk of this._queuedChunks) {
13588      this._loaded += chunk.byteLength;
13589    }
13590    this._done = stream._progressiveDone;
13591    this._contentLength = length;
13592    this._isStreamingSupported = !disableStream;
13593    this._isRangeSupported = !disableRange;
13594    if (isPdfFile(contentDispositionFilename)) {
13595      this._filename = contentDispositionFilename;
13596    }
13597    this._headersCapability.resolve();
13598    const loaded = this._loaded;
13599    Promise.resolve().then(() => {
13600      if (loaded > 0 && this._loaded === loaded) {
13601        this._callOnProgress();
13602      }
13603    });
13604  }
13605  _enqueue(chunk) {
13606    if (this._done) {
13607      return;
13608    }
13609    if (this._requests.length > 0) {
13610      const capability = this._requests.shift();
13611      capability.resolve({
13612        value: chunk,
13613        done: false
13614      });
13615    } else {
13616      this._queuedChunks.push(chunk);
13617    }
13618    this._loaded += chunk.byteLength;
13619    this._callOnProgress();
13620  }
13621  async read() {
13622    if (this._queuedChunks.length > 0) {
13623      const chunk = this._queuedChunks.shift();
13624      return {
13625        value: chunk,
13626        done: false
13627      };
13628    }
13629    if (this._done) {
13630      return {
13631        value: undefined,
13632        done: true
13633      };
13634    }
13635    const capability = Promise.withResolvers();
13636    this._requests.push(capability);
13637    return capability.promise;
13638  }
13639  cancel(reason) {
13640    this._done = true;
13641    this.#endRequests();
13642  }
13643  progressiveDone() {
13644    this._done ||= true;
13645    if (this._queuedChunks.length === 0) {
13646      this.#endRequests();
13647    }
13648  }
13649}
13650class PDFDataTransportStreamRangeReader extends BasePDFStreamRangeReader {
13651  #endRequests = endRequests.bind(this);
13652  onDone = null;
13653  _begin = -1;
13654  _done = false;
13655  _queuedChunk = null;
13656  _requests = [];
13657  constructor(stream, begin, end) {
13658    super(stream, begin, end);
13659    this._begin = begin;
13660  }
13661  _enqueue(chunk) {
13662    if (this._done) {
13663      return;
13664    }
13665    if (this._requests.length === 0) {
13666      this._queuedChunk = chunk;
13667    } else {
13668      const capability = this._requests.shift();
13669      capability.resolve({
13670        value: chunk,
13671        done: false
13672      });
13673      this.#endRequests();
13674    }
13675    this._done = true;
13676    this.onDone?.();
13677  }
13678  async read() {
13679    if (this._queuedChunk) {
13680      const chunk = this._queuedChunk;
13681      this._queuedChunk = null;
13682      return {
13683        value: chunk,
13684        done: false
13685      };
13686    }
13687    if (this._done) {
13688      return {
13689        value: undefined,
13690        done: true
13691      };
13692    }
13693    const capability = Promise.withResolvers();
13694    this._requests.push(capability);
13695    return capability.promise;
13696  }
13697  cancel(reason) {
13698    this._done = true;
13699    this.#endRequests();
13700    this.onDone?.();
13701  }
13702}
13703
13704;// ./src/display/network.js
13705
13706
13707
13708
13709const OK_RESPONSE = 200;
13710const PARTIAL_CONTENT_RESPONSE = 206;
13711function network_getArrayBuffer(val) {
13712  return typeof val !== "string" ? val : stringToBytes(val).buffer;
13713}
13714class PDFNetworkStream extends BasePDFStream {
13715  #pendingRequests = new WeakMap();
13716  _responseOrigin = null;
13717  constructor(source) {
13718    super(source, PDFNetworkStreamReader, PDFNetworkStreamRangeReader);
13719    const {
13720      httpHeaders,
13721      url
13722    } = source;
13723    this.url = url;
13724    this.isHttp = /https?:/.test(url.protocol);
13725    this.headers = createHeaders(this.isHttp, httpHeaders);
13726  }
13727  _request(args) {
13728    const xhr = new XMLHttpRequest();
13729    const pendingRequest = {
13730      validateStatus: null,
13731      onHeadersReceived: args.onHeadersReceived,
13732      onDone: args.onDone,
13733      onError: args.onError,
13734      onProgress: args.onProgress
13735    };
13736    this.#pendingRequests.set(xhr, pendingRequest);
13737    xhr.open("GET", this.url);
13738    xhr.withCredentials = this._source.withCredentials;
13739    for (const [key, val] of this.headers) {
13740      xhr.setRequestHeader(key, val);
13741    }
13742    if (this.isHttp && "begin" in args && "end" in args) {
13743      xhr.setRequestHeader("Range", `bytes=${args.begin}-${args.end - 1}`);
13744      pendingRequest.validateStatus = status => status === PARTIAL_CONTENT_RESPONSE || status === OK_RESPONSE;
13745    } else {
13746      pendingRequest.validateStatus = status => status === OK_RESPONSE;
13747    }
13748    xhr.responseType = "arraybuffer";
13749    assert(args.onError, "Expected `onError` callback to be provided.");
13750    xhr.onerror = () => args.onError(xhr.status);
13751    xhr.onreadystatechange = this.#onStateChange.bind(this, xhr);
13752    xhr.onprogress = this.#onProgress.bind(this, xhr);
13753    xhr.send(null);
13754    return xhr;
13755  }
13756  #onProgress(xhr, evt) {
13757    const pendingRequest = this.#pendingRequests.get(xhr);
13758    pendingRequest?.onProgress?.(evt);
13759  }
13760  #onStateChange(xhr, evt) {
13761    const pendingRequest = this.#pendingRequests.get(xhr);
13762    if (!pendingRequest) {
13763      return;
13764    }
13765    if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {
13766      pendingRequest.onHeadersReceived();
13767      delete pendingRequest.onHeadersReceived;
13768    }
13769    if (xhr.readyState !== 4) {
13770      return;
13771    }
13772    if (!this.#pendingRequests.has(xhr)) {
13773      return;
13774    }
13775    this.#pendingRequests.delete(xhr);
13776    if (xhr.status === 0 && this.isHttp) {
13777      pendingRequest.onError(xhr.status);
13778      return;
13779    }
13780    const xhrStatus = xhr.status || OK_RESPONSE;
13781    if (!pendingRequest.validateStatus(xhrStatus)) {
13782      pendingRequest.onError(xhr.status);
13783      return;
13784    }
13785    const chunk = network_getArrayBuffer(xhr.response);
13786    if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
13787      const rangeHeader = xhr.getResponseHeader("Content-Range");
13788      if (/bytes \d+-\d+\/\d+/.test(rangeHeader)) {
13789        pendingRequest.onDone(chunk);
13790      } else {
13791        warn(`Missing or invalid "Content-Range" header.`);
13792        pendingRequest.onError(0);
13793      }
13794    } else if (chunk) {
13795      pendingRequest.onDone(chunk);
13796    } else {
13797      pendingRequest.onError(xhr.status);
13798    }
13799  }
13800  _abortRequest(xhr) {
13801    if (this.#pendingRequests.has(xhr)) {
13802      this.#pendingRequests.delete(xhr);
13803      xhr.abort();
13804    }
13805  }
13806  getRangeReader(begin, end) {
13807    const reader = super.getRangeReader(begin, end);
13808    if (reader) {
13809      reader.onClosed = () => this._rangeReaders.delete(reader);
13810    }
13811    return reader;
13812  }
13813}
13814class PDFNetworkStreamReader extends BasePDFStreamReader {
13815  #endRequests = endRequests.bind(this);
13816  _cachedChunks = [];
13817  _done = false;
13818  _requests = [];
13819  _storedError = null;
13820  constructor(stream) {
13821    super(stream);
13822    this._fullRequestXhr = stream._request({
13823      onHeadersReceived: this.#onHeadersReceived.bind(this),
13824      onDone: this.#onDone.bind(this),
13825      onError: this.#onError.bind(this),
13826      onProgress: this.#onProgress.bind(this)
13827    });
13828  }
13829  #onHeadersReceived() {
13830    const stream = this._stream;
13831    const {
13832      disableRange,
13833      rangeChunkSize
13834    } = stream._source;
13835    const fullRequestXhr = this._fullRequestXhr;
13836    stream._responseOrigin = getResponseOrigin(fullRequestXhr.responseURL);
13837    const rawResponseHeaders = fullRequestXhr.getAllResponseHeaders();
13838    const responseHeaders = new Headers(rawResponseHeaders ? 
13838rawResponseHeaders.trimStart().replace(/[^\S ]+$/, ""
vendor: 17,038 bytes, lines 13838-14517
13838).split(/[\r\n]+/).map(x => {
13839      const [key, ...val] = x.split(": ");
13840      return [key, val.join(": ")];
13841    }) : []);
13842    const {
13843      contentLength,
13844      isRangeSupported
13845    } = validateRangeRequestCapabilities({
13846      responseHeaders,
13847      isHttp: stream.isHttp,
13848      rangeChunkSize,
13849      disableRange
13850    });
13851    this._contentLength = contentLength;
13852    this._isRangeSupported = isRangeSupported;
13853    this._filename = extractFilenameFromHeader(responseHeaders);
13854    if (this._isRangeSupported) {
13855      stream._abortRequest(fullRequestXhr);
13856    }
13857    this._headersCapability.resolve();
13858  }
13859  #onDone(chunk) {
13860    if (this._requests.length > 0) {
13861      const capability = this._requests.shift();
13862      capability.resolve({
13863        value: chunk,
13864        done: false
13865      });
13866    } else {
13867      this._cachedChunks.push(chunk);
13868    }
13869    this._done = true;
13870    if (this._cachedChunks.length === 0) {
13871      this.#endRequests();
13872    }
13873  }
13874  #onError(status) {
13875    this._storedError = createResponseError(status, this._stream.url);
13876    this._headersCapability.reject(this._storedError);
13877    for (const capability of this._requests) {
13878      capability.reject(this._storedError);
13879    }
13880    this._requests.length = 0;
13881    this._cachedChunks.length = 0;
13882  }
13883  #onProgress(evt) {
13884    this.onProgress?.({
13885      loaded: evt.loaded,
13886      total: evt.lengthComputable ? evt.total : this._contentLength
13887    });
13888  }
13889  async read() {
13890    await this._headersCapability.promise;
13891    if (this._storedError) {
13892      throw this._storedError;
13893    }
13894    if (this._cachedChunks.length > 0) {
13895      const chunk = this._cachedChunks.shift();
13896      return {
13897        value: chunk,
13898        done: false
13899      };
13900    }
13901    if (this._done) {
13902      return {
13903        value: undefined,
13904        done: true
13905      };
13906    }
13907    const capability = Promise.withResolvers();
13908    this._requests.push(capability);
13909    return capability.promise;
13910  }
13911  cancel(reason) {
13912    this._done = true;
13913    this._headersCapability.reject(reason);
13914    this.#endRequests();
13915    this._stream._abortRequest(this._fullRequestXhr);
13916    this._fullRequestXhr = null;
13917  }
13918}
13919class PDFNetworkStreamRangeReader extends BasePDFStreamRangeReader {
13920  #endRequests = endRequests.bind(this);
13921  onClosed = null;
13922  _done = false;
13923  _queuedChunk = null;
13924  _requests = [];
13925  _storedError = null;
13926  constructor(stream, begin, end) {
13927    super(stream, begin, end);
13928    this._requestXhr = stream._request({
13929      begin,
13930      end,
13931      onHeadersReceived: this.#onHeadersReceived.bind(this),
13932      onDone: this.#onDone.bind(this),
13933      onError: this.#onError.bind(this),
13934      onProgress: null
13935    });
13936  }
13937  #onHeadersReceived() {
13938    const responseOrigin = getResponseOrigin(this._requestXhr?.responseURL);
13939    try {
13940      ensureResponseOrigin(responseOrigin, this._stream._responseOrigin);
13941    } catch (ex) {
13942      this._storedError = ex;
13943      this.#onError(0);
13944    }
13945  }
13946  #onDone(chunk) {
13947    if (this._requests.length > 0) {
13948      const capability = this._requests.shift();
13949      capability.resolve({
13950        value: chunk,
13951        done: false
13952      });
13953    } else {
13954      this._queuedChunk = chunk;
13955    }
13956    this._done = true;
13957    this.#endRequests();
13958    this.onClosed?.();
13959  }
13960  #onError(status) {
13961    this._storedError ??= createResponseError(status, this._stream.url);
13962    for (const capability of this._requests) {
13963      capability.reject(this._storedError);
13964    }
13965    this._requests.length = 0;
13966    this._queuedChunk = null;
13967  }
13968  async read() {
13969    if (this._storedError) {
13970      throw this._storedError;
13971    }
13972    if (this._queuedChunk !== null) {
13973      const chunk = this._queuedChunk;
13974      this._queuedChunk = null;
13975      return {
13976        value: chunk,
13977        done: false
13978      };
13979    }
13980    if (this._done) {
13981      return {
13982        value: undefined,
13983        done: true
13984      };
13985    }
13986    const capability = Promise.withResolvers();
13987    this._requests.push(capability);
13988    return capability.promise;
13989  }
13990  cancel(reason) {
13991    this._done = true;
13992    this.#endRequests();
13993    this._stream._abortRequest(this._requestXhr);
13994    this.onClosed?.();
13995  }
13996}
13997
13998;// ./src/display/node_stream.js
13999
14000
14001
14002
14003function getReadableStream(url, opts = null) {
14004  const fs = process.getBuiltinModule("fs");
14005  const {
14006    Readable
14007  } = process.getBuiltinModule("stream");
14008  const readStream = fs.createReadStream(url, opts);
14009  return Readable.toWeb(readStream);
14010}
14011class PDFNodeStream extends BasePDFStream {
14012  constructor(source) {
14013    super(source, PDFNodeStreamReader, PDFNodeStreamRangeReader);
14014    const {
14015      url
14016    } = source;
14017    assert(url.protocol === "file:", "PDFNodeStream only supports file:// URLs.");
14018  }
14019}
14020class PDFNodeStreamReader extends BasePDFStreamReader {
14021  _reader = null;
14022  constructor(stream) {
14023    super(stream);
14024    const {
14025      disableRange,
14026      disableStream,
14027      rangeChunkSize,
14028      url
14029    } = stream._source;
14030    this._isStreamingSupported = !disableStream;
14031    const fs = process.getBuiltinModule("fs/promises");
14032    fs.lstat(url).then(stat => {
14033      const readableStream = getReadableStream(url);
14034      this._reader = readableStream.getReader();
14035      const {
14036        size
14037      } = stat;
14038      this._contentLength = size;
14039      this._isRangeSupported = !disableRange && size > 2 * rangeChunkSize;
14040      if (!this._isStreamingSupported && this._isRangeSupported) {
14041        this.cancel(new AbortException("Streaming is disabled."));
14042      }
14043      this._headersCapability.resolve();
14044    }).catch(error => {
14045      if (error.code === "ENOENT") {
14046        error = createResponseError(0, url);
14047      }
14048      this._headersCapability.reject(error);
14049    });
14050  }
14051  async read() {
14052    await this._headersCapability.promise;
14053    const {
14054      value,
14055      done
14056    } = await this._reader.read();
14057    if (done) {
14058      return {
14059        value,
14060        done
14061      };
14062    }
14063    this._loaded += value.byteLength;
14064    this._callOnProgress();
14065    return {
14066      value: getArrayBuffer(value),
14067      done: false
14068    };
14069  }
14070  cancel(reason) {
14071    this._reader?.cancel(reason);
14072  }
14073}
14074class PDFNodeStreamRangeReader extends BasePDFStreamRangeReader {
14075  _readCapability = Promise.withResolvers();
14076  _reader = null;
14077  constructor(stream, begin, end) {
14078    super(stream, begin, end);
14079    const {
14080      url
14081    } = stream._source;
14082    try {
14083      const readableStream = getReadableStream(url, {
14084        start: begin,
14085        end: end - 1
14086      });
14087      this._reader = readableStream.getReader();
14088      this._readCapability.resolve();
14089    } catch (error) {
14090      this._readCapability.reject(error);
14091    }
14092  }
14093  async read() {
14094    await this._readCapability.promise;
14095    const {
14096      value,
14097      done
14098    } = await this._reader.read();
14099    if (done) {
14100      return {
14101        value,
14102        done
14103      };
14104    }
14105    return {
14106      value: getArrayBuffer(value),
14107      done: false
14108    };
14109  }
14110  cancel(reason) {
14111    this._reader?.cancel(reason);
14112  }
14113}
14114
14115;// ./src/display/network_stream.js
14116
14117
14118
14119
14120
14121function getNetworkStream(url) {
14122  return isValidFetchUrl(url) ? PDFFetchStream : isNodeJS ? PDFNodeStream : PDFNetworkStream;
14123}
14124
14125;// ./src/display/worker_options.js
14126class GlobalWorkerOptions {
14127  static #port = null;
14128  static #src = "";
14129  static get workerPort() {
14130    return this.#port;
14131  }
14132  static set workerPort(val) {
14133    if (!(typeof Worker !== "undefined" && val instanceof Worker) && val !== null) {
14134      throw new Error("Invalid `workerPort` type.");
14135    }
14136    this.#port = val;
14137  }
14138  static get workerSrc() {
14139    return this.#src;
14140  }
14141  static set workerSrc(val) {
14142    if (typeof val !== "string") {
14143      throw new Error("Invalid `workerSrc` type.");
14144    }
14145    this.#src = val;
14146  }
14147}
14148
14149;// ./src/display/metadata.js
14150class Metadata {
14151  #map;
14152  #data;
14153  constructor({
14154    parsedData,
14155    rawData
14156  }) {
14157    this.#map = parsedData;
14158    this.#data = rawData;
14159  }
14160  getRaw() {
14161    return this.#data;
14162  }
14163  get(name) {
14164    return this.#map.get(name) ?? null;
14165  }
14166  [Symbol.iterator]() {
14167    return this.#map.entries();
14168  }
14169}
14170
14171;// ./src/display/optional_content_config.js
14172
14173
14174const INTERNAL = Symbol("INTERNAL");
14175class OptionalContentGroup {
14176  #isDisplay = false;
14177  #isPrint = false;
14178  #userSet = false;
14179  #visible = true;
14180  constructor(renderingIntent, {
14181    name,
14182    intent,
14183    usage,
14184    rbGroups
14185  }) {
14186    this.#isDisplay = !!(renderingIntent & RenderingIntentFlag.DISPLAY);
14187    this.#isPrint = !!(renderingIntent & RenderingIntentFlag.PRINT);
14188    this.name = name;
14189    this.intent = intent;
14190    this.usage = usage;
14191    this.rbGroups = rbGroups;
14192  }
14193  get visible() {
14194    if (this.#userSet) {
14195      return this.#visible;
14196    }
14197    if (!this.#visible) {
14198      return false;
14199    }
14200    const {
14201      print,
14202      view
14203    } = this.usage;
14204    if (this.#isDisplay) {
14205      return view?.viewState !== "OFF";
14206    } else if (this.#isPrint) {
14207      return print?.printState !== "OFF";
14208    }
14209    return true;
14210  }
14211  _setVisible(internal, visible, userSet = false) {
14212    if (internal !== INTERNAL) {
14213      unreachable("Internal method `_setVisible` called.");
14214    }
14215    this.#userSet = userSet;
14216    this.#visible = visible;
14217  }
14218  get serializable() {
14219    return {
14220      userSet: this.#userSet,
14221      visible: this.#visible
14222    };
14223  }
14224}
14225class OptionalContentConfig {
14226  #cachedGetHash = null;
14227  #groups = new Map();
14228  #initialHash = null;
14229  #order = null;
14230  #rawData;
14231  creator = null;
14232  name = null;
14233  constructor(data, renderingIntent = RenderingIntentFlag.DISPLAY, groupState = null) {
14234    this.#rawData = data;
14235    this.renderingIntent = renderingIntent;
14236    if (data === null) {
14237      return;
14238    }
14239    this.name = data.name;
14240    this.creator = data.creator;
14241    this.#order = data.order;
14242    for (const group of data.groups) {
14243      this.#groups.set(group.id, new OptionalContentGroup(renderingIntent, group));
14244    }
14245    if (groupState) {
14246      if (groupState.size !== this.#groups.size) {
14247        unreachable("Incorrect serialized groupState.");
14248      }
14249      for (const [id, group] of groupState) {
14250        this.#groups.get(id)._setVisible(INTERNAL, group.visible, group.userSet);
14251      }
14252    } else {
14253      if (data.baseState === "OFF") {
14254        for (const group of this.#groups.values()) {
14255          group._setVisible(INTERNAL, false);
14256        }
14257      }
14258      for (const on of data.on) {
14259        this.#groups.get(on)._setVisible(INTERNAL, true);
14260      }
14261      for (const off of data.off) {
14262        this.#groups.get(off)._setVisible(INTERNAL, false);
14263      }
14264    }
14265    this.#initialHash = this.getHash();
14266  }
14267  #evaluateVisibilityExpression(array) {
14268    const length = array.length;
14269    if (length < 2) {
14270      return true;
14271    }
14272    const operator = array[0];
14273    for (let i = 1; i < length; i++) {
14274      const element = array[i];
14275      let state;
14276      if (Array.isArray(element)) {
14277        state = this.#evaluateVisibilityExpression(element);
14278      } else if (this.#groups.has(element)) {
14279        state = this.#groups.get(element).visible;
14280      } else {
14281        warn(`Optional content group not found: ${element}`);
14282        return true;
14283      }
14284      switch (operator) {
14285        case "And":
14286          if (!state) {
14287            return false;
14288          }
14289          break;
14290        case "Or":
14291          if (state) {
14292            return true;
14293          }
14294          break;
14295        case "Not":
14296          return !state;
14297        default:
14298          return true;
14299      }
14300    }
14301    return operator === "And";
14302  }
14303  isVisible(group) {
14304    if (this.#groups.size === 0) {
14305      return true;
14306    }
14307    if (!group) {
14308      info("Optional content group not defined.");
14309      return true;
14310    }
14311    if (group.type === "OCG") {
14312      if (!this.#groups.has(group.id)) {
14313        warn(`Optional content group not found: ${group.id}`);
14314        return true;
14315      }
14316      return this.#groups.get(group.id).visible;
14317    } else if (group.type === "OCMD") {
14318      if (group.expression) {
14319        return this.#evaluateVisibilityExpression(group.expression);
14320      }
14321      if (!group.policy || group.policy === "AnyOn") {
14322        for (const id of group.ids) {
14323          if (!this.#groups.has(id)) {
14324            warn(`Optional content group not found: ${id}`);
14325            return true;
14326          }
14327          if (this.#groups.get(id).visible) {
14328            return true;
14329          }
14330        }
14331        return false;
14332      } else if (group.policy === "AllOn") {
14333        for (const id of group.ids) {
14334          if (!this.#groups.has(id)) {
14335            warn(`Optional content group not found: ${id}`);
14336            return true;
14337          }
14338          if (!this.#groups.get(id).visible) {
14339            return false;
14340          }
14341        }
14342        return true;
14343      } else if (group.policy === "AnyOff") {
14344        for (const id of group.ids) {
14345          if (!this.#groups.has(id)) {
14346            warn(`Optional content group not found: ${id}`);
14347            return true;
14348          }
14349          if (!this.#groups.get(id).visible) {
14350            return true;
14351          }
14352        }
14353        return false;
14354      } else if (group.policy === "AllOff") {
14355        for (const id of group.ids) {
14356          if (!this.#groups.has(id)) {
14357            warn(`Optional content group not found: ${id}`);
14358            return true;
14359          }
14360          if (this.#groups.get(id).visible) {
14361            return false;
14362          }
14363        }
14364        return true;
14365      }
14366      warn(`Unknown optional content policy ${group.policy}.`);
14367      return true;
14368    }
14369    warn(`Unknown group type ${group.type}.`);
14370    return true;
14371  }
14372  setVisibility(id, visible = true, preserveRB = true) {
14373    const group = this.#groups.get(id);
14374    if (!group) {
14375      warn(`Optional content group not found: ${id}`);
14376      return;
14377    }
14378    if (preserveRB && visible && group.rbGroups.length) {
14379      for (const rbGroup of group.rbGroups) {
14380        for (const otherId of rbGroup) {
14381          if (otherId !== id) {
14382            this.#groups.get(otherId)?._setVisible(INTERNAL, false, true);
14383          }
14384        }
14385      }
14386    }
14387    group._setVisible(INTERNAL, !!visible, true);
14388    this.#cachedGetHash = null;
14389  }
14390  setOCGState({
14391    state,
14392    preserveRB
14393  }) {
14394    let operator;
14395    for (const elem of state) {
14396      switch (elem) {
14397        case "ON":
14398        case "OFF":
14399        case "Toggle":
14400          operator = elem;
14401          continue;
14402      }
14403      const group = this.#groups.get(elem);
14404      if (!group) {
14405        continue;
14406      }
14407      switch (operator) {
14408        case "ON":
14409          this.setVisibility(elem, true, preserveRB);
14410          break;
14411        case "OFF":
14412          this.setVisibility(elem, false, preserveRB);
14413          break;
14414        case "Toggle":
14415          this.setVisibility(elem, !group.visible, preserveRB);
14416          break;
14417      }
14418    }
14419    this.#cachedGetHash = null;
14420  }
14421  get hasInitialVisibility() {
14422    return this.#initialHash === null || this.getHash() === this.#initialHash;
14423  }
14424  getOrder() {
14425    if (!this.#groups.size) {
14426      return null;
14427    }
14428    if (this.#order) {
14429      return this.#order.slice();
14430    }
14431    return [...this.#groups.keys()];
14432  }
14433  getGroup(id) {
14434    return this.#groups.get(id) || null;
14435  }
14436  getHash() {
14437    if (this.#cachedGetHash !== null) {
14438      return this.#cachedGetHash;
14439    }
14440    const hash = new MurmurHash3_64();
14441    for (const [id, group] of this.#groups) {
14442      hash.update(`${id}:${group.visible}`);
14443    }
14444    return this.#cachedGetHash = hash.hexdigest();
14445  }
14446  [Symbol.iterator]() {
14447    return this.#groups.entries();
14448  }
14449  get serializable() {
14450    const groupState = new Map();
14451    for (const [id, group] of this.#groups) {
14452      groupState.set(id, group.serializable);
14453    }
14454    return {
14455      data: this.#rawData,
14456      renderingIntent: this.renderingIntent,
14457      groupState
14458    };
14459  }
14460  static fromSerializable({
14461    data,
14462    renderingIntent,
14463    groupState
14464  }) {
14465    return new OptionalContentConfig(data, renderingIntent, groupState);
14466  }
14467}
14468
14469;// ./src/display/pages_mapper.js
14470
14471
14472class PagesMapper {
14473  #pageNumberToId = null;
14474  #prevPageNumbers = null;
14475  #pagesNumber = 0;
14476  #clipboard = null;
14477  #savedData = null;
14478  get pagesNumber() {
14479    return this.#pagesNumber;
14480  }
14481  set pagesNumber(n) {
14482    if (this.#pagesNumber === n) {
14483      return;
14484    }
14485    this.#pagesNumber = n;
14486    this.#pageNumberToId = null;
14487    this.#prevPageNumbers = null;
14488  }
14489  #ensureInit() {
14490    if (this.#pageNumberToId) {
14491      return;
14492    }
14493    const n = this.#pagesNumber;
14494    const pageNumberToId = this.#pageNumberToId = new Uint32Array(n);
14495    for (let i = 0; i < n; i++) {
14496      pageNumberToId[i] = i + 1;
14497    }
14498    this.#prevPageNumbers = new Int32Array(pageNumberToId);
14499  }
14500  #buildIdToPageNumber() {
14501    const idToPageNumber = new Map();
14502    const pageNumberToId = this.#pageNumberToId;
14503    for (let i = 0, ii = this.#pagesNumber; i < ii; i++) {
14504      const id = pageNumberToId[i];
14505      const pageNumbers = idToPageNumber.get(id);
14506      if (pageNumbers) {
14507        pageNumbers.push(i + 1);
14508      } else {
14509        idToPageNumber.set(id, [i + 1]);
14510      }
14511    }
14512    return idToPageNumber;
14513  }
14514  movePages(selectedPages, pagesToMove, index) {
14515    this.#ensureInit();
14516    const pageNumberToId = this.#pageNumberToId;
14517    const 
vendor: 12,885 bytes, lines 14517-14923
14517prevIdToPageNumber = this.#buildIdToPageNumber();
14518    const movedCount = pagesToMove.length;
14519    const mappedPagesToMove = new Uint32Array(movedCount);
14520    let removedBeforeTarget = 0;
14521    for (let i = 0; i < movedCount; i++) {
14522      const pageIndex = pagesToMove[i] - 1;
14523      mappedPagesToMove[i] = pageNumberToId[pageIndex];
14524      if (pageIndex < index) {
14525        removedBeforeTarget++;
14526      }
14527    }
14528    const pagesNumber = this.#pagesNumber;
14529    const remainingLen = pagesNumber - movedCount;
14530    const adjustedTarget = MathClamp(index - removedBeforeTarget, 0, remainingLen);
14531    for (let i = 0, r = 0; i < pagesNumber; i++) {
14532      if (!selectedPages.has(i + 1)) {
14533        pageNumberToId[r++] = pageNumberToId[i];
14534      }
14535    }
14536    pageNumberToId.copyWithin(adjustedTarget + movedCount, adjustedTarget, remainingLen);
14537    pageNumberToId.set(mappedPagesToMove, adjustedTarget);
14538    this.#updatePrevPageNumbers(prevIdToPageNumber);
14539    if (pageNumberToId.every((id, i) => id === i + 1)) {
14540      this.#pageNumberToId = null;
14541    }
14542  }
14543  deletePages(pagesToDelete) {
14544    this.#ensureInit();
14545    const pageNumberToId = this.#pageNumberToId;
14546    const prevIdToPageNumber = this.#buildIdToPageNumber();
14547    this.#savedData = {
14548      pageNumberToId: pageNumberToId.slice(),
14549      pagesNumber: this.#pagesNumber,
14550      prevPageNumbers: this.#prevPageNumbers.slice()
14551    };
14552    const newN = this.#pagesNumber - pagesToDelete.length;
14553    this.#pagesNumber = newN;
14554    const newPageNumberToId = this.#pageNumberToId = new Uint32Array(newN);
14555    this.#prevPageNumbers = new Int32Array(newN);
14556    let sourceIndex = 0;
14557    let destIndex = 0;
14558    for (const pageNumber of pagesToDelete) {
14559      const pageIndex = pageNumber - 1;
14560      if (pageIndex !== sourceIndex) {
14561        newPageNumberToId.set(pageNumberToId.subarray(sourceIndex, pageIndex), destIndex);
14562        destIndex += pageIndex - sourceIndex;
14563      }
14564      sourceIndex = pageIndex + 1;
14565    }
14566    if (sourceIndex < pageNumberToId.length) {
14567      newPageNumberToId.set(pageNumberToId.subarray(sourceIndex), destIndex);
14568    }
14569    this.#updatePrevPageNumbers(prevIdToPageNumber, new Set(pagesToDelete));
14570  }
14571  cancelDelete() {
14572    if (this.#savedData) {
14573      this.#pageNumberToId = this.#savedData.pageNumberToId;
14574      this.#pagesNumber = this.#savedData.pagesNumber;
14575      this.#prevPageNumbers = this.#savedData.prevPageNumbers;
14576      this.#savedData = null;
14577    }
14578  }
14579  cleanSavedData() {
14580    this.#savedData = null;
14581  }
14582  copyPages(pagesToCopy) {
14583    this.#ensureInit();
14584    this.#clipboard = {
14585      pageNumbers: pagesToCopy,
14586      pageIds: pagesToCopy.map(n => this.#pageNumberToId[n - 1])
14587    };
14588  }
14589  cancelCopy() {
14590    this.#clipboard = null;
14591  }
14592  pastePages(index) {
14593    this.#ensureInit();
14594    const pageNumberToId = this.#pageNumberToId;
14595    const prevIdToPageNumber = this.#buildIdToPageNumber();
14596    const {
14597      pageNumbers: copiedPageNumbers,
14598      pageIds: copiedPageIds
14599    } = this.#clipboard;
14600    const newN = this.#pagesNumber + copiedPageNumbers.length;
14601    this.#pagesNumber = newN;
14602    const newPageNumberToId = this.#pageNumberToId = new Uint32Array(newN);
14603    this.#prevPageNumbers = new Int32Array(newN);
14604    newPageNumberToId.set(pageNumberToId.subarray(0, index), 0);
14605    newPageNumberToId.set(copiedPageIds, index);
14606    newPageNumberToId.set(pageNumberToId.subarray(index), index + copiedPageNumbers.length);
14607    this.#updatePrevPageNumbers(prevIdToPageNumber, null, index, copiedPageNumbers);
14608    this.#clipboard = null;
14609  }
14610  #updatePrevPageNumbers(prevIdToPageNumber, deletedPageNumbers = null, pasteIndex = -1, copiedPageNumbers = null) {
14611    const prevPageNumbers = this.#prevPageNumbers;
14612    const newPageNumberToId = this.#pageNumberToId;
14613    const pasteEnd = pasteIndex + (copiedPageNumbers?.length ?? 0);
14614    const idsIndices = new Map();
14615    for (let i = 0, ii = this.#pagesNumber; i < ii; i++) {
14616      if (i >= pasteIndex && i < pasteEnd) {
14617        prevPageNumbers[i] = -copiedPageNumbers[i - pasteIndex];
14618        continue;
14619      }
14620      const id = newPageNumberToId[i];
14621      const oldPositions = prevIdToPageNumber.get(id);
14622      let j = idsIndices.get(id) || 0;
14623      if (deletedPageNumbers && oldPositions) {
14624        while (j < oldPositions.length && deletedPageNumbers.has(oldPositions[j])) {
14625          j++;
14626        }
14627      }
14628      prevPageNumbers[i] = oldPositions?.[j];
14629      idsIndices.set(id, j + 1);
14630    }
14631  }
14632  hasBeenAltered() {
14633    return this.#pageNumberToId !== null;
14634  }
14635  getPageMappingForSaving(idToPageNumber = null) {
14636    idToPageNumber ??= this.#buildIdToPageNumber();
14637    let nCopy = 0;
14638    for (const pageNumbers of idToPageNumber.values()) {
14639      nCopy = Math.max(nCopy, pageNumbers.length);
14640    }
14641    const extractParams = new Array(nCopy);
14642    for (let i = 0; i < nCopy; i++) {
14643      extractParams[i] = {
14644        document: null,
14645        pageIndices: [],
14646        includePages: []
14647      };
14648    }
14649    for (const [id, pageNumbers] of idToPageNumber) {
14650      for (let i = 0, ii = pageNumbers.length; i < ii; i++) {
14651        extractParams[i].includePages.push([id - 1, pageNumbers[i] - 1]);
14652      }
14653    }
14654    for (const {
14655      includePages,
14656      pageIndices
14657    } of extractParams) {
14658      includePages.sort((a, b) => a[0] - b[0]);
14659      for (let i = 0, ii = includePages.length; i < ii; i++) {
14660        pageIndices.push(includePages[i][1]);
14661        includePages[i] = includePages[i][0];
14662      }
14663    }
14664    return extractParams;
14665  }
14666  extractPages(extractedPageNumbers) {
14667    extractedPageNumbers = Array.from(extractedPageNumbers).sort((a, b) => a - b);
14668    const usedIds = new Map();
14669    for (let i = 0, ii = extractedPageNumbers.length; i < ii; i++) {
14670      const id = this.getPageId(extractedPageNumbers[i]);
14671      const usedPageNumbers = usedIds.getOrInsertComputed(id, makeArr);
14672      usedPageNumbers.push(i + 1);
14673    }
14674    return this.getPageMappingForSaving(usedIds);
14675  }
14676  getPrevPageNumber(pageNumber) {
14677    return this.#prevPageNumbers?.[pageNumber - 1] ?? 0;
14678  }
14679  getPageNumber(id) {
14680    if (!this.#pageNumberToId) {
14681      return id;
14682    }
14683    const pageNumberToId = this.#pageNumberToId;
14684    for (let i = 0, ii = this.#pagesNumber; i < ii; i++) {
14685      if (pageNumberToId[i] === id) {
14686        return i + 1;
14687      }
14688    }
14689    return 0;
14690  }
14691  getPageId(pageNumber) {
14692    return this.#pageNumberToId?.[pageNumber - 1] ?? pageNumber;
14693  }
14694  getMapping() {
14695    return this.#pageNumberToId?.subarray(0, this.pagesNumber);
14696  }
14697}
14698
14699;// ./src/display/pdf_objects.js
14700const INITIAL_DATA = Symbol("INITIAL_DATA");
14701const dataObj = () => ({
14702  ...Promise.withResolvers(),
14703  data: INITIAL_DATA
14704});
14705class PDFObjects {
14706  #objs = new Map();
14707  get(objId, callback = null) {
14708    if (callback) {
14709      const obj = this.#objs.getOrInsertComputed(objId, dataObj);
14710      obj.promise.then(() => callback(obj.data));
14711      return null;
14712    }
14713    const obj = this.#objs.get(objId);
14714    if (!obj || obj.data === INITIAL_DATA) {
14715      throw new Error(`Requesting object that isn't resolved yet ${objId}.`);
14716    }
14717    return obj.data;
14718  }
14719  has(objId) {
14720    const obj = this.#objs.get(objId);
14721    return !!obj && obj.data !== INITIAL_DATA;
14722  }
14723  delete(objId) {
14724    const obj = this.#objs.get(objId);
14725    if (!obj || obj.data === INITIAL_DATA) {
14726      return false;
14727    }
14728    this.#objs.delete(objId);
14729    return true;
14730  }
14731  resolve(objId, data = null) {
14732    const obj = this.#objs.getOrInsertComputed(objId, dataObj);
14733    if (obj.data !== INITIAL_DATA) {
14734      throw new Error(`Object already resolved ${objId}.`);
14735    }
14736    obj.data = data;
14737    obj.resolve();
14738  }
14739  clear() {
14740    for (const {
14741      data
14742    } of this.#objs.values()) {
14743      data?.bitmap?.close();
14744    }
14745    this.#objs.clear();
14746  }
14747  *[Symbol.iterator]() {
14748    for (const [objId, {
14749      data
14750    }] of this.#objs) {
14751      if (data !== INITIAL_DATA) {
14752        yield [objId, data];
14753      }
14754    }
14755  }
14756}
14757
14758;// ./src/display/text_layer.js
14759
14760
14761const MAX_TEXT_DIVS_TO_RENDER = 100000;
14762const DEFAULT_FONT_SIZE = 30;
14763class TextLayer {
14764  #capability = Promise.withResolvers();
14765  #container = null;
14766  #disableProcessItems = false;
14767  #fontInspectorEnabled = !!globalThis.FontInspector?.enabled;
14768  #imagesHandler = null;
14769  #lang = null;
14770  #layoutTextParams = null;
14771  #pageHeight = 0;
14772  #pageWidth = 0;
14773  #reader = null;
14774  #rootContainer = null;
14775  #rotation = 0;
14776  #scale = 0;
14777  #styleCache = Object.create(null);
14778  #textContentItemsStr = [];
14779  #textContentSource = null;
14780  #textDivs = [];
14781  #textDivProperties = new WeakMap();
14782  #transform = null;
14783  static #ascentCache = new Map();
14784  static #canvasContexts = new Map();
14785  static #canvasCtxFonts = new WeakMap();
14786  static #minFontSize = null;
14787  static #pendingTextLayers = new Set();
14788  constructor({
14789    textContentSource,
14790    images,
14791    container,
14792    viewport
14793  }) {
14794    if (textContentSource instanceof ReadableStream) {
14795      this.#textContentSource = textContentSource;
14796    } else if (typeof textContentSource === "object") {
14797      this.#textContentSource = new ReadableStream({
14798        start(controller) {
14799          controller.enqueue(textContentSource);
14800          controller.close();
14801        }
14802      });
14803    } else {
14804      throw new Error('No "textContentSource" parameter specified.');
14805    }
14806    this.#container = this.#rootContainer = container;
14807    this.#imagesHandler = images;
14808    this.#scale = viewport.scale * OutputScale.pixelRatio;
14809    this.#rotation = viewport.rotation;
14810    this.#layoutTextParams = {
14811      div: null,
14812      properties: null,
14813      ctx: null
14814    };
14815    const {
14816      pageWidth,
14817      pageHeight,
14818      pageX,
14819      pageY
14820    } = viewport.rawDims;
14821    this.#transform = [1, 0, 0, -1, -pageX, pageY + pageHeight];
14822    this.#pageWidth = pageWidth;
14823    this.#pageHeight = pageHeight;
14824    TextLayer.#ensureMinFontSizeComputed();
14825    container.style.setProperty("--min-font-size", TextLayer.#minFontSize);
14826    setLayerDimensions(container, viewport);
14827    this.#capability.promise.finally(() => {
14828      TextLayer.#pendingTextLayers.delete(this);
14829      this.#layoutTextParams = null;
14830      this.#styleCache = null;
14831    }).catch(() => {});
14832  }
14833  static get fontFamilyMap() {
14834    const {
14835      isWindows,
14836      isFirefox
14837    } = FeatureTest.platform;
14838    return shadow(this, "fontFamilyMap", new Map([["sans-serif", `${isWindows && isFirefox ? "Calibri, " : ""}sans-serif`], ["monospace", `${isWindows && isFirefox ? "Lucida Console, " : ""}monospace`]]));
14839  }
14840  render() {
14841    if (this.#imagesHandler) {
14842      this.#container.append(this.#imagesHandler.render());
14843    }
14844    const pump = () => {
14845      this.#reader.read().then(({
14846        value,
14847        done
14848      }) => {
14849        if (done) {
14850          this.#capability.resolve();
14851          return;
14852        }
14853        this.#lang ??= value.lang;
14854        Object.assign(this.#styleCache, value.styles);
14855        this.#processItems(value.items);
14856        pump();
14857      }, this.#capability.reject);
14858    };
14859    this.#reader = this.#textContentSource.getReader();
14860    TextLayer.#pendingTextLayers.add(this);
14861    pump();
14862    return this.#capability.promise;
14863  }
14864  update({
14865    viewport,
14866    onBefore = null
14867  }) {
14868    const scale = viewport.scale * OutputScale.pixelRatio;
14869    const rotation = viewport.rotation;
14870    if (rotation !== this.#rotation) {
14871      onBefore?.();
14872      this.#rotation = rotation;
14873      setLayerDimensions(this.#rootContainer, {
14874        rotation
14875      });
14876    }
14877    if (scale !== this.#scale) {
14878      onBefore?.();
14879      this.#scale = scale;
14880      const params = {
14881        div: null,
14882        properties: null,
14883        ctx: TextLayer.#getCtx(this.#lang)
14884      };
14885      for (const div of this.#textDivs) {
14886        params.properties = this.#textDivProperties.get(div);
14887        params.div = div;
14888        this.#layout(params);
14889      }
14890    }
14891  }
14892  cancel() {
14893    const abortEx = new AbortException("TextLayer task cancelled.");
14894    this.#reader?.cancel(abortEx).catch(() => {});
14895    this.#reader = null;
14896    this.#capability.reject(abortEx);
14897  }
14898  get textDivs() {
14899    return this.#textDivs;
14900  }
14901  get textContentItemsStr() {
14902    return this.#textContentItemsStr;
14903  }
14904  #processItems(items) {
14905    if (this.#disableProcessItems) {
14906      return;
14907    }
14908    this.#layoutTextParams.ctx ??= TextLayer.#getCtx(this.#lang);
14909    const textDivs = this.#textDivs,
14910      textContentItemsStr = this.#textContentItemsStr;
14911    for (const item of items) {
14912      if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER) {
14913        warn("Ignoring additional textDivs for performance reasons.");
14914        this.#disableProcessItems = true;
14915        return;
14916      }
14917      if (item.str === undefined) {
14918        if (item.type === "beginMarkedContentProps" || item.type === "beginMarkedContent") {
14919          const parent = this.#container;
14920          this.#container = document.createElement("span");
14921          this.#container.classList.add("markedContent");
14922          if (item.id) {
14923            this.#container.setAttribute("id", `${item.id}`
vendor: 10,057 bytes, lines 14923-15216
14923);
14924          }
14925          if (item.tag === "Artifact") {
14926            this.#container.ariaHidden = true;
14927          }
14928          parent.append(this.#container);
14929        } else if (item.type === "endMarkedContent") {
14930          this.#container = this.#container.parentNode;
14931        }
14932        continue;
14933      }
14934      textContentItemsStr.push(item.str);
14935      this.#appendText(item);
14936    }
14937  }
14938  #appendText(geom) {
14939    const textDiv = document.createElement("span");
14940    const textDivProperties = {
14941      angle: 0,
14942      canvasWidth: 0,
14943      hasText: geom.str !== "",
14944      hasEOL: geom.hasEOL,
14945      fontSize: 0
14946    };
14947    this.#textDivs.push(textDiv);
14948    const tx = Util.transform(this.#transform, geom.transform);
14949    let angle = Math.atan2(tx[1], tx[0]);
14950    const style = this.#styleCache[geom.fontName];
14951    if (style.vertical) {
14952      angle += Math.PI / 2;
14953    }
14954    let fontFamily = this.#fontInspectorEnabled && style.fontSubstitution || style.fontFamily;
14955    fontFamily = TextLayer.fontFamilyMap.get(fontFamily) || fontFamily;
14956    const fontHeight = Math.hypot(tx[2], tx[3]);
14957    const fontAscent = fontHeight * TextLayer.#getAscent(fontFamily, style, this.#lang);
14958    let left, top;
14959    if (angle === 0) {
14960      left = tx[4];
14961      top = tx[5] - fontAscent;
14962    } else {
14963      left = tx[4] + fontAscent * Math.sin(angle);
14964      top = tx[5] - fontAscent * Math.cos(angle);
14965    }
14966    const divStyle = textDiv.style;
14967    divStyle.left = `${(100 * left / this.#pageWidth).toFixed(2)}%`;
14968    divStyle.top = `${(100 * top / this.#pageHeight).toFixed(2)}%`;
14969    divStyle.setProperty("--font-height", `${fontHeight.toFixed(2)}px`);
14970    divStyle.fontFamily = fontFamily;
14971    textDivProperties.fontSize = fontHeight;
14972    textDiv.setAttribute("role", "presentation");
14973    textDiv.textContent = geom.str;
14974    textDiv.dir = geom.dir;
14975    if (this.#fontInspectorEnabled) {
14976      textDiv.dataset.fontName = style.fontSubstitutionLoadedName || geom.fontName;
14977    }
14978    if (angle !== 0) {
14979      textDivProperties.angle = angle * (180 / Math.PI);
14980    }
14981    let shouldScaleText = false;
14982    if (geom.str.length > 1) {
14983      shouldScaleText = true;
14984    } else if (geom.str !== " " && geom.transform[0] !== geom.transform[3]) {
14985      const absScaleX = Math.abs(geom.transform[0]),
14986        absScaleY = Math.abs(geom.transform[3]);
14987      if (absScaleX !== absScaleY && Math.max(absScaleX, absScaleY) / Math.min(absScaleX, absScaleY) > 1.5) {
14988        shouldScaleText = true;
14989      }
14990    }
14991    if (shouldScaleText) {
14992      textDivProperties.canvasWidth = style.vertical ? geom.height : geom.width;
14993    }
14994    this.#textDivProperties.set(textDiv, textDivProperties);
14995    this.#layoutTextParams.div = textDiv;
14996    this.#layoutTextParams.properties = textDivProperties;
14997    this.#layout(this.#layoutTextParams);
14998    if (textDivProperties.hasText) {
14999      this.#container.append(textDiv);
15000    }
15001    if (textDivProperties.hasEOL) {
15002      const br = document.createElement("br");
15003      br.setAttribute("role", "presentation");
15004      this.#container.append(br);
15005    }
15006  }
15007  #layout(params) {
15008    const {
15009      div,
15010      properties,
15011      ctx
15012    } = params;
15013    const {
15014      style
15015    } = div;
15016    if (properties.canvasWidth !== 0 && properties.hasText) {
15017      const {
15018        fontFamily
15019      } = style;
15020      const {
15021        canvasWidth,
15022        fontSize
15023      } = properties;
15024      TextLayer.#ensureCtxFont(ctx, fontSize * this.#scale, fontFamily);
15025      const {
15026        width
15027      } = ctx.measureText(div.textContent);
15028      if (width > 0) {
15029        style.setProperty("--scale-x", canvasWidth * this.#scale / width);
15030      }
15031    }
15032    if (properties.angle !== 0) {
15033      style.setProperty("--rotate", `${properties.angle}deg`);
15034    }
15035  }
15036  static cleanup() {
15037    if (this.#pendingTextLayers.size > 0) {
15038      return;
15039    }
15040    this.#ascentCache.clear();
15041    for (const {
15042      canvas
15043    } of this.#canvasContexts.values()) {
15044      canvas.remove();
15045    }
15046    this.#canvasContexts.clear();
15047  }
15048  static #getCtx(lang = null) {
15049    let ctx = this.#canvasContexts.get(lang ||= "");
15050    if (!ctx) {
15051      const canvas = document.createElement("canvas");
15052      canvas.style.cssText = "position:absolute;top:0;left:0;width:0;height:0;display:none;" + "letter-spacing:normal;word-spacing:normal";
15053      canvas.lang = lang;
15054      document.body.append(canvas);
15055      ctx = canvas.getContext("2d", {
15056        alpha: false,
15057        willReadFrequently: true
15058      });
15059      this.#canvasContexts.set(lang, ctx);
15060      this.#canvasCtxFonts.set(ctx, {
15061        size: 0,
15062        family: ""
15063      });
15064    }
15065    return ctx;
15066  }
15067  static #ensureCtxFont(ctx, size, family) {
15068    const cached = this.#canvasCtxFonts.get(ctx);
15069    if (size === cached.size && family === cached.family) {
15070      return;
15071    }
15072    ctx.font = `${size}px ${family}`;
15073    cached.size = size;
15074    cached.family = family;
15075  }
15076  static #ensureMinFontSizeComputed() {
15077    if (this.#minFontSize !== null) {
15078      return;
15079    }
15080    const div = document.createElement("div");
15081    div.style.opacity = 0;
15082    div.style.lineHeight = 1;
15083    div.style.fontSize = "1px";
15084    div.style.position = "absolute";
15085    div.textContent = "X";
15086    document.body.append(div);
15087    this.#minFontSize = div.getBoundingClientRect().height;
15088    div.remove();
15089  }
15090  static #getAscent(fontFamily, style, lang) {
15091    const cachedAscent = this.#ascentCache.get(fontFamily);
15092    if (cachedAscent) {
15093      return cachedAscent;
15094    }
15095    const ctx = this.#getCtx(lang);
15096    ctx.canvas.width = ctx.canvas.height = DEFAULT_FONT_SIZE;
15097    this.#ensureCtxFont(ctx, DEFAULT_FONT_SIZE, fontFamily);
15098    const metrics = ctx.measureText("");
15099    const ascent = metrics.fontBoundingBoxAscent;
15100    const descent = Math.abs(metrics.fontBoundingBoxDescent);
15101    ctx.canvas.width = ctx.canvas.height = 0;
15102    let ratio = 0.8;
15103    if (ascent) {
15104      ratio = ascent / (ascent + descent);
15105    } else {
15106      if (FeatureTest.platform.isFirefox) {
15107        warn("Enable the `dom.textMetrics.fontBoundingBox.enabled` preference " + "in `about:config` to improve TextLayer rendering.");
15108      }
15109      if (style.ascent) {
15110        ratio = style.ascent;
15111      } else if (style.descent) {
15112        ratio = 1 + style.descent;
15113      }
15114    }
15115    this.#ascentCache.set(fontFamily, ratio);
15116    return ratio;
15117  }
15118}
15119
15120;// ./src/display/api.js
15121
15122
15123
15124
15125
15126
15127
15128
15129
15130
15131
15132
15133
15134
15135
15136
15137
15138
15139
15140
15141
15142
15143
15144
15145
15146const RENDERING_CANCELLED_TIMEOUT = 100;
15147function getDocument(src = {}) {
15148  const task = new PDFDocumentLoadingTask();
15149  const {
15150    docId
15151  } = task;
15152  const url = src.url ? getUrlProp(src.url) : null;
15153  const data = src.data ? getDataProp(src.data) : null;
15154  const httpHeaders = src.httpHeaders || null;
15155  const withCredentials = src.withCredentials === true;
15156  const password = src.password ?? null;
15157  const rangeTransport = src.range instanceof PDFDataRangeTransport ? src.range : null;
15158  const rangeChunkSize = Number.isInteger(src.rangeChunkSize) && src.rangeChunkSize > 0 ? src.rangeChunkSize : 2 ** 16;
15159  let worker = src.worker instanceof PDFWorker ? src.worker : null;
15160  const verbosity = src.verbosity;
15161  const docBaseUrl = typeof src.docBaseUrl === "string" && !isDataScheme(src.docBaseUrl) ? src.docBaseUrl : null;
15162  const cMapUrl = getFactoryUrlProp(src.cMapUrl);
15163  const cMapPacked = src.cMapPacked !== false;
15164  const iccUrl = getFactoryUrlProp(src.iccUrl);
15165  const standardFontDataUrl = getFactoryUrlProp(src.standardFontDataUrl);
15166  const wasmUrl = getFactoryUrlProp(src.wasmUrl);
15167  const ignoreErrors = src.stopAtErrors !== true;
15168  const maxImageSize = Number.isInteger(src.maxImageSize) && src.maxImageSize > -1 ? src.maxImageSize : -1;
15169  const isOffscreenCanvasSupported = typeof src.isOffscreenCanvasSupported === "boolean" ? src.isOffscreenCanvasSupported : !isNodeJS;
15170  const isImageDecoderSupported = typeof src.isImageDecoderSupported === "boolean" ? src.isImageDecoderSupported : !isNodeJS;
15171  const canvasMaxAreaInBytes = Number.isInteger(src.canvasMaxAreaInBytes) ? src.canvasMaxAreaInBytes : -1;
15172  const disableFontFace = typeof src.disableFontFace === "boolean" ? src.disableFontFace : isNodeJS;
15173  const fontExtraProperties = src.fontExtraProperties === true;
15174  const enableXfa = src.enableXfa === true;
15175  const ownerDocument = src.ownerDocument || globalThis.document;
15176  const disableRange = src.disableRange === true;
15177  const disableStream = src.disableStream === true;
15178  const disableAutoFetch = src.disableAutoFetch === true;
15179  const pdfBug = src.pdfBug === true;
15180  const CanvasFactory = src.CanvasFactory || (isNodeJS ? NodeCanvasFactory : DOMCanvasFactory);
15181  const FilterFactory = src.FilterFactory || (isNodeJS ? NodeFilterFactory : DOMFilterFactory);
15182  const BinaryDataFactory = src.BinaryDataFactory || (isNodeJS ? NodeBinaryDataFactory : DOMBinaryDataFactory);
15183  const enableHWA = src.enableHWA === true;
15184  const enableWebGPU = src.enableWebGPU === true;
15185  const gpuPromise = enableWebGPU ? initGPU() : Promise.resolve(false);
15186  const useWasm = src.useWasm !== false;
15187  const pagesMapper = src.pagesMapper || new PagesMapper();
15188  const useSystemFonts = typeof src.useSystemFonts === "boolean" ? src.useSystemFonts : !isNodeJS && !disableFontFace;
15189  const useWorkerFetch = typeof src.useWorkerFetch === "boolean" ? src.useWorkerFetch : !!(BinaryDataFactory === DOMBinaryDataFactory && cMapUrl && cMapPacked && standardFontDataUrl && wasmUrl && isValidFetchUrl(cMapUrl, document.baseURI) && isValidFetchUrl(standardFontDataUrl, document.baseURI) && isValidFetchUrl(wasmUrl, document.baseURI));
15190  const styleElement = null;
15191  setVerbosityLevel(verbosity);
15192  const transportFactory = {
15193    canvasFactory: new CanvasFactory({
15194      ownerDocument,
15195      enableHWA
15196    }),
15197    filterFactory: new FilterFactory({
15198      docId,
15199      ownerDocument
15200    }),
15201    binaryDataFactory: useWorkerFetch ? null : new BinaryDataFactory({
15202      cMapUrl,
15203      standardFontDataUrl,
15204      wasmUrl
15205    })
15206  };
15207  if (!worker) {
15208    worker = PDFWorker.create({
15209      verbosity,
15210      port: GlobalWorkerOptions.workerPort
15211    });
15212    task._worker = worker;
15213  }
15214  const docParams = {
15215    docId,
15216    apiVersion: "6.
152161.200
vendor: 6,387 bytes, lines 15216-15463
15216",
15217    data,
15218    password,
15219    disableAutoFetch,
15220    rangeChunkSize,
15221    docBaseUrl,
15222    enableXfa,
15223    evaluatorOptions: {
15224      maxImageSize,
15225      disableFontFace,
15226      ignoreErrors,
15227      isOffscreenCanvasSupported,
15228      isImageDecoderSupported,
15229      canvasMaxAreaInBytes,
15230      fontExtraProperties,
15231      useSystemFonts,
15232      useWasm,
15233      useWorkerFetch,
15234      cMapUrl,
15235      cMapPacked,
15236      iccUrl,
15237      standardFontDataUrl,
15238      wasmUrl,
15239      hasGPU: false
15240    }
15241  };
15242  const transportParams = {
15243    ownerDocument,
15244    pdfBug,
15245    styleElement,
15246    enableHWA,
15247    loadingParams: {
15248      disableAutoFetch,
15249      enableXfa
15250    }
15251  };
15252  Promise.all([worker.promise, gpuPromise]).then(function ([, hasGPU]) {
15253    if (worker.destroyed) {
15254      throw new Error("Worker was destroyed");
15255    }
15256    docParams.evaluatorOptions.hasGPU = hasGPU;
15257    const workerIdPromise = worker.messageHandler.sendWithPromise("GetDocRequest", docParams, data ? [data.buffer] : null);
15258    let networkStream;
15259    if (data) {} else if (rangeTransport) {
15260      networkStream = new PDFDataTransportStream({
15261        pdfDataRangeTransport: rangeTransport,
15262        disableRange,
15263        disableStream
15264      });
15265    } else if (url) {
15266      const NetworkStream = getNetworkStream(url);
15267      networkStream = new NetworkStream({
15268        url,
15269        httpHeaders,
15270        withCredentials,
15271        rangeChunkSize,
15272        disableRange,
15273        disableStream
15274      });
15275    } else {
15276      throw new Error("getDocument - expected either `data`, `range`, or `url` parameter.");
15277    }
15278    return workerIdPromise.then(workerId => {
15279      if (worker.destroyed) {
15280        throw new Error("Worker was destroyed");
15281      }
15282      const messageHandler = new MessageHandler(docId, workerId, worker.port);
15283      const transport = new WorkerTransport(messageHandler, task, networkStream, transportParams, transportFactory, pagesMapper);
15284      task._transport = transport;
15285      if (task.destroyed) {
15286        throw new Error("Loading aborted");
15287      }
15288      messageHandler.send("Ready", null);
15289    });
15290  }).catch(task._capability.reject).finally(task._setupCapability.resolve);
15291  return task;
15292}
15293class PDFDocumentLoadingTask {
15294  static #docId = 0;
15295  _capability = Promise.withResolvers();
15296  _setupCapability = Promise.withResolvers();
15297  _transport = null;
15298  _worker = null;
15299  docId = `d${PDFDocumentLoadingTask.#docId++}`;
15300  destroyed = false;
15301  onPassword = null;
15302  onProgress = null;
15303  get promise() {
15304    return this._capability.promise;
15305  }
15306  async destroy() {
15307    this.destroyed = true;
15308    this._capability.promise.catch(() => {});
15309    try {
15310      if (this._worker?.port) {
15311        this._worker._pendingDestroy = true;
15312      }
15313      await this._setupCapability.promise;
15314      await this._transport?.destroy();
15315    } catch (ex) {
15316      if (this._worker?.port) {
15317        delete this._worker._pendingDestroy;
15318      }
15319      throw ex;
15320    }
15321    this._transport = null;
15322    this._worker?.destroy();
15323    this._worker = null;
15324  }
15325  async getData() {
15326    return this._transport.getData();
15327  }
15328}
15329class PDFDataRangeTransport {
15330  #capability = Promise.withResolvers();
15331  #listener = null;
15332  constructor(length, initialData, progressiveDone = false, contentDispositionFilename = null) {
15333    this.length = length;
15334    this.initialData = initialData;
15335    this.progressiveDone = progressiveDone;
15336    this.contentDispositionFilename = contentDispositionFilename;
15337  }
15338  onDataRange(begin, chunk) {
15339    this.#listener({
15340      type: "range",
15341      begin,
15342      chunk
15343    });
15344  }
15345  onDataProgressiveRead(chunk) {
15346    this.#capability.promise.then(() => {
15347      this.#listener({
15348        type: "progressiveRead",
15349        chunk
15350      });
15351    });
15352  }
15353  onDataProgressiveDone() {
15354    this.#capability.promise.then(() => {
15355      this.#listener({
15356        type: "progressiveDone"
15357      });
15358    });
15359  }
15360  transportReady(listener) {
15361    this.#listener = listener;
15362    this.#capability.resolve();
15363  }
15364  requestDataRange(begin, end) {
15365    unreachable("Abstract method PDFDataRangeTransport.requestDataRange");
15366  }
15367  abort() {}
15368}
15369class PDFDocumentProxy {
15370  constructor(pdfInfo, transport) {
15371    this._pdfInfo = pdfInfo;
15372    this._transport = transport;
15373  }
15374  get pagesMapper() {
15375    return this._transport.pagesMapper;
15376  }
15377  get annotationStorage() {
15378    return this._transport.annotationStorage;
15379  }
15380  get canvasFactory() {
15381    return this._transport.canvasFactory;
15382  }
15383  get filterFactory() {
15384    return this._transport.filterFactory;
15385  }
15386  get numPages() {
15387    return this._pdfInfo.numPages;
15388  }
15389  get fingerprints() {
15390    return this._pdfInfo.fingerprints;
15391  }
15392  get isPureXfa() {
15393    return shadow(this, "isPureXfa", !!this._transport._htmlForXfa);
15394  }
15395  get allXfaHtml() {
15396    return this._transport._htmlForXfa;
15397  }
15398  getPage(pageNumber) {
15399    return this._transport.getPage(pageNumber);
15400  }
15401  getPageIndex(ref) {
15402    return this._transport.getPageIndex(ref);
15403  }
15404  getDestinations() {
15405    return this._transport.getDestinations();
15406  }
15407  getDestination(id) {
15408    return this._transport.getDestination(id);
15409  }
15410  getPageLabels() {
15411    return this._transport.getPageLabels();
15412  }
15413  getPageLayout() {
15414    return this._transport.getPageLayout();
15415  }
15416  getPageMode() {
15417    return this._transport.getPageMode();
15418  }
15419  getViewerPreferences() {
15420    return this._transport.getViewerPreferences();
15421  }
15422  getOpenAction() {
15423    return this._transport.getOpenAction();
15424  }
15425  getAttachments() {
15426    return this._transport.getAttachments();
15427  }
15428  getAttachmentContent(id) {
15429    return this._transport.getAttachmentContent(id);
15430  }
15431  getAnnotationsByType(types, pageIndexesToSkip) {
15432    return this._transport.getAnnotationsByType(types, pageIndexesToSkip);
15433  }
15434  getJSActions() {
15435    return this._transport.getDocJSActions();
15436  }
15437  getOutline() {
15438    return this._transport.getOutline();
15439  }
15440  getOptionalContentConfig({
15441    intent = "display"
15442  } = {}) {
15443    const {
15444      renderingIntent
15445    } = this._transport.getRenderingIntent(intent);
15446    return this._transport.getOptionalContentConfig(renderingIntent);
15447  }
15448  getPermissions() {
15449    return this._transport.getPermissions();
15450  }
15451  getMetadata() {
15452    return this._transport.getMetadata();
15453  }
15454  getMarkInfo() {
15455    return this._transport.getMarkInfo();
15456  }
15457  getData() {
15458    return this._transport.getData();
15459  }
15460  saveDocument() {
15461    return this._transport.saveDocument();
15462  }
15463  extractPages(pageInfos
15463) {
15464    return this._transport.extractPages(pageInfos);
15465  }
15466  getDownloadInfo() {
15467    return this._transport.downloadInfoCapability.promise;
15468  }
15469  getRawData(data) {
15470    return this._transport.getRawData(data);
15471  }
15472  cleanup(keepLoadedFonts = false) {
15473    return this._transport.startCleanup(keepLoadedFonts || this.isPureXfa);
15474  }
15475  cachedPageNumber(ref) {
15476    return this._transport.cachedPageNumber(ref);
15477  }
15478  get loadingParams() {
15479    return this._transport.loadingParams;
15480  }
15481  get loadingTask() {
15482    return this._transport.loadingTask;
15483  }
15484  getFieldObjects() {
15485    return this._transport.getFieldObjects(
vendor: 33,108 bytes, lines 15485-16530
15485);
15486  }
15487  hasJSActions() {
15488    return this._transport.hasJSActions();
15489  }
15490  getCalculationOrderIds() {
15491    return this._transport.getCalculationOrderIds();
15492  }
15493}
15494class PDFPageProxy {
15495  #pendingCleanup = false;
15496  #pagesMapper = null;
15497  constructor(pageIndex, pageInfo, transport, pagesMapper, pdfBug = false) {
15498    this._pageIndex = pageIndex;
15499    this._pageInfo = pageInfo;
15500    this._transport = transport;
15501    this._stats = pdfBug ? new StatTimer() : null;
15502    this._pdfBug = pdfBug;
15503    this.commonObjs = transport.commonObjs;
15504    this.objs = new PDFObjects();
15505    this._intentStates = new Map();
15506    this.destroyed = false;
15507    this.recordedBBoxes = null;
15508    this.#pagesMapper = pagesMapper;
15509    this.imageCoordinates = null;
15510  }
15511  clone(id) {
15512    const clone = new PDFPageProxy(id, this._pageInfo, this._transport, this.#pagesMapper, this._pdfBug);
15513    clone.clonedFromIndex = this.clonedFromIndex ?? this._pageIndex;
15514    this._transport.updatePage(clone);
15515    return clone;
15516  }
15517  get pageNumber() {
15518    return this._pageIndex + 1;
15519  }
15520  set pageNumber(value) {
15521    this._pageIndex = value - 1;
15522    this._transport.updatePage(this);
15523  }
15524  get rotate() {
15525    return this._pageInfo.rotate;
15526  }
15527  get ref() {
15528    return this._pageInfo.ref;
15529  }
15530  get userUnit() {
15531    return this._pageInfo.userUnit;
15532  }
15533  get view() {
15534    return this._pageInfo.view;
15535  }
15536  getViewport({
15537    scale,
15538    rotation = this.rotate,
15539    offsetX = 0,
15540    offsetY = 0,
15541    dontFlip = false
15542  } = {}) {
15543    return new PageViewport({
15544      viewBox: this.view,
15545      userUnit: this.userUnit,
15546      scale,
15547      rotation,
15548      offsetX,
15549      offsetY,
15550      dontFlip
15551    });
15552  }
15553  getAnnotations({
15554    intent = "display"
15555  } = {}) {
15556    const {
15557      renderingIntent
15558    } = this._transport.getRenderingIntent(intent);
15559    return this._transport.getAnnotations(this._pageIndex, renderingIntent);
15560  }
15561  getJSActions() {
15562    return this._transport.getPageJSActions(this._pageIndex);
15563  }
15564  get filterFactory() {
15565    return this._transport.filterFactory;
15566  }
15567  get isPureXfa() {
15568    return shadow(this, "isPureXfa", !!this._transport._htmlForXfa);
15569  }
15570  async getXfa() {
15571    return this._transport._htmlForXfa?.children[this._pageIndex] || null;
15572  }
15573  render({
15574    canvasContext,
15575    canvas = canvasContext.canvas,
15576    viewport,
15577    intent = "display",
15578    annotationMode = AnnotationMode.ENABLE,
15579    transform = null,
15580    background = null,
15581    optionalContentConfigPromise = null,
15582    annotationCanvasMap = null,
15583    pageColors = null,
15584    printAnnotationStorage = null,
15585    isEditing = false,
15586    recordImages = false,
15587    recordOperations = false,
15588    operationsFilter = null
15589  }) {
15590    this._stats?.time("Overall");
15591    const intentArgs = this._transport.getRenderingIntent(intent, annotationMode, printAnnotationStorage, isEditing);
15592    const {
15593      renderingIntent,
15594      cacheKey
15595    } = intentArgs;
15596    this.#pendingCleanup = false;
15597    optionalContentConfigPromise ||= this._transport.getOptionalContentConfig(renderingIntent);
15598    const intentState = this._intentStates.getOrInsertComputed(cacheKey, makeObj);
15599    if (intentState.streamReaderCancelTimeout) {
15600      clearTimeout(intentState.streamReaderCancelTimeout);
15601      intentState.streamReaderCancelTimeout = null;
15602    }
15603    const intentPrint = !!(renderingIntent & RenderingIntentFlag.PRINT);
15604    if (!intentState.displayReadyCapability) {
15605      intentState.displayReadyCapability = Promise.withResolvers();
15606      intentState.operatorList = {
15607        fnArray: [],
15608        argsArray: [],
15609        lastChunk: false,
15610        separateAnnots: null
15611      };
15612      this._stats?.time("Page Request");
15613      this._pumpOperatorList(intentArgs);
15614    }
15615    const recordForDebugger = !!(this._pdfBug && globalThis.StepperManager?.enabled);
15616    const shouldRecordOperations = !!canvas && !this.recordedBBoxes && (recordOperations || recordForDebugger);
15617    const shouldRecordImages = !!canvas && !this.imageCoordinates && recordImages;
15618    const complete = error => {
15619      intentState.renderTasks.delete(internalRenderTask);
15620      if (shouldRecordOperations) {
15621        const recordedBBoxes = internalRenderTask.gfx?.dependencyTracker.take();
15622        if (recordedBBoxes) {
15623          internalRenderTask.stepper?.setOperatorBBoxes(recordedBBoxes, internalRenderTask.gfx.dependencyTracker.takeDebugMetadata());
15624          if (recordOperations) {
15625            this.recordedBBoxes = recordedBBoxes;
15626          }
15627        }
15628      }
15629      if (shouldRecordImages && !error) {
15630        this.imageCoordinates = internalRenderTask.gfx?.imagesTracker.take();
15631      }
15632      if (intentPrint) {
15633        this.#pendingCleanup = true;
15634      }
15635      this.#tryCleanup();
15636      if (error) {
15637        internalRenderTask.capability.reject(error);
15638        this._abortOperatorList({
15639          intentState,
15640          reason: error instanceof Error ? error : new Error(error)
15641        });
15642      } else {
15643        internalRenderTask.capability.resolve();
15644      }
15645      if (this._stats) {
15646        this._stats.timeEnd("Rendering");
15647        this._stats.timeEnd("Overall");
15648        if (globalThis.Stats?.enabled) {
15649          globalThis.Stats.add(this.pageNumber, this._stats);
15650        }
15651      }
15652    };
15653    let dependencyTracker = null;
15654    let bboxTracker = null;
15655    if (shouldRecordOperations || shouldRecordImages) {
15656      bboxTracker = new CanvasBBoxTracker(canvas, intentState.operatorList.length);
15657    }
15658    if (shouldRecordOperations) {
15659      dependencyTracker = new CanvasDependencyTracker(bboxTracker, recordForDebugger);
15660    }
15661    const internalRenderTask = new InternalRenderTask({
15662      callback: complete,
15663      params: {
15664        canvas,
15665        canvasContext,
15666        dependencyTracker: dependencyTracker ?? bboxTracker,
15667        imagesTracker: shouldRecordImages ? new CanvasImagesTracker(canvas) : null,
15668        viewport,
15669        transform,
15670        background
15671      },
15672      objs: this.objs,
15673      commonObjs: this.commonObjs,
15674      annotationCanvasMap,
15675      operatorList: intentState.operatorList,
15676      pageIndex: this._pageIndex,
15677      canvasFactory: this._transport.canvasFactory,
15678      filterFactory: this._transport.filterFactory,
15679      useRequestAnimationFrame: !intentPrint,
15680      pdfBug: this._pdfBug,
15681      pageColors,
15682      enableHWA: this._transport.enableHWA,
15683      operationsFilter
15684    });
15685    (intentState.renderTasks ||= new Set()).add(internalRenderTask);
15686    const renderTask = internalRenderTask.task;
15687    Promise.all([intentState.displayReadyCapability.promise, optionalContentConfigPromise]).then(([transparency, optionalContentConfig]) => {
15688      if (this.destroyed) {
15689        complete();
15690        return;
15691      }
15692      this._stats?.time("Rendering");
15693      if (!(optionalContentConfig.renderingIntent & renderingIntent)) {
15694        throw new Error("Must use the same `intent`-argument when calling the `PDFPageProxy.render` " + "and `PDFDocumentProxy.getOptionalContentConfig` methods.");
15695      }
15696      internalRenderTask.initializeGraphics({
15697        transparency,
15698        optionalContentConfig
15699      });
15700      internalRenderTask.operatorListChanged();
15701    }).catch(complete);
15702    return renderTask;
15703  }
15704  getOperatorList({
15705    intent = "display",
15706    annotationMode = AnnotationMode.ENABLE,
15707    printAnnotationStorage = null,
15708    isEditing = false
15709  } = {}) {
15710    function operatorListChanged() {
15711      if (intentState.operatorList.lastChunk) {
15712        intentState.opListReadCapability.resolve(intentState.operatorList);
15713        intentState.renderTasks.delete(opListTask);
15714      }
15715    }
15716    const intentArgs = this._transport.getRenderingIntent(intent, annotationMode, printAnnotationStorage, isEditing, true);
15717    const intentState = this._intentStates.getOrInsertComputed(intentArgs.cacheKey, makeObj);
15718    let opListTask;
15719    if (!intentState.opListReadCapability) {
15720      opListTask = Object.create(null);
15721      opListTask.operatorListChanged = operatorListChanged;
15722      intentState.opListReadCapability = Promise.withResolvers();
15723      (intentState.renderTasks ||= new Set()).add(opListTask);
15724      intentState.operatorList = {
15725        fnArray: [],
15726        argsArray: [],
15727        lastChunk: false,
15728        separateAnnots: null
15729      };
15730      this._stats?.time("Page Request");
15731      this._pumpOperatorList(intentArgs);
15732    }
15733    return intentState.opListReadCapability.promise;
15734  }
15735  streamTextContent({
15736    includeMarkedContent = false,
15737    disableNormalization = false
15738  } = {}) {
15739    const TEXT_CONTENT_CHUNK_SIZE = 100;
15740    return this._transport.messageHandler.sendWithStream("GetTextContent", {
15741      pageId: this.#pagesMapper.getPageId(this._pageIndex + 1) - 1,
15742      pageIndex: this._pageIndex,
15743      includeMarkedContent: includeMarkedContent === true,
15744      disableNormalization: disableNormalization === true
15745    }, {
15746      highWaterMark: TEXT_CONTENT_CHUNK_SIZE,
15747      size(textContent) {
15748        return textContent.items.length;
15749      }
15750    });
15751  }
15752  async getTextContent(params = {}) {
15753    if (this._transport._htmlForXfa) {
15754      return this.getXfa().then(xfa => XfaText.textContent(xfa));
15755    }
15756    const readableStream = this.streamTextContent(params);
15757    const textContent = {
15758      items: [],
15759      styles: Object.create(null),
15760      lang: null
15761    };
15762    for await (const value of readableStream) {
15763      textContent.lang ??= value.lang;
15764      Object.assign(textContent.styles, value.styles);
15765      textContent.items.push(...value.items);
15766    }
15767    return textContent;
15768  }
15769  getStructTree() {
15770    return this._transport.getStructTree(this._pageIndex);
15771  }
15772  _destroy() {
15773    this.destroyed = true;
15774    const waitOn = [];
15775    for (const intentState of this._intentStates.values()) {
15776      this._abortOperatorList({
15777        intentState,
15778        reason: new Error("Page was destroyed."),
15779        force: true
15780      });
15781      if (intentState.opListReadCapability) {
15782        continue;
15783      }
15784      for (const internalRenderTask of intentState.renderTasks) {
15785        waitOn.push(internalRenderTask.completed);
15786        internalRenderTask.cancel();
15787      }
15788    }
15789    this.objs.clear();
15790    this.#pendingCleanup = false;
15791    return Promise.all(waitOn);
15792  }
15793  cleanup(resetStats = false) {
15794    this.#pendingCleanup = true;
15795    const success = this.#tryCleanup();
15796    if (resetStats && success) {
15797      this._stats &&= new StatTimer();
15798    }
15799    return success;
15800  }
15801  #tryCleanup() {
15802    if (!this.#pendingCleanup || this.destroyed) {
15803      return false;
15804    }
15805    for (const {
15806      renderTasks,
15807      operatorList
15808    } of this._intentStates.values()) {
15809      if (renderTasks.size > 0 || !operatorList.lastChunk) {
15810        return false;
15811      }
15812    }
15813    this._intentStates.clear();
15814    this.objs.clear();
15815    this.#pendingCleanup = false;
15816    return true;
15817  }
15818  _startRenderPage(transparency, cacheKey) {
15819    const intentState = this._intentStates.get(cacheKey);
15820    if (!intentState) {
15821      return;
15822    }
15823    this._stats?.timeEnd("Page Request");
15824    intentState.displayReadyCapability?.resolve(transparency);
15825  }
15826  _renderPageChunk(operatorListChunk, intentState) {
15827    for (let i = 0, ii = operatorListChunk.length; i < ii; i++) {
15828      intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
15829      intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]);
15830    }
15831    intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
15832    intentState.operatorList.separateAnnots = operatorListChunk.separateAnnots;
15833    for (const internalRenderTask of intentState.renderTasks) {
15834      internalRenderTask.operatorListChanged();
15835    }
15836    if (operatorListChunk.lastChunk) {
15837      this.#tryCleanup();
15838    }
15839  }
15840  _pumpOperatorList({
15841    renderingIntent,
15842    cacheKey,
15843    annotationStorageSerializable,
15844    modifiedIds
15845  }) {
15846    const {
15847      map,
15848      transfer
15849    } = annotationStorageSerializable;
15850    const readableStream = this._transport.messageHandler.sendWithStream("GetOperatorList", {
15851      pageId: this.#pagesMapper.getPageId(this._pageIndex + 1) - 1,
15852      pageIndex: this._pageIndex,
15853      intent: renderingIntent,
15854      cacheKey,
15855      annotationStorage: map,
15856      modifiedIds
15857    }, undefined, transfer);
15858    const reader = readableStream.getReader();
15859    const intentState = this._intentStates.get(cacheKey);
15860    intentState.streamReader = reader;
15861    const pump = () => {
15862      reader.read().then(({
15863        value,
15864        done
15865      }) => {
15866        if (done) {
15867          intentState.streamReader = null;
15868          return;
15869        }
15870        if (this._transport.destroyed) {
15871          return;
15872        }
15873        this._renderPageChunk(value, intentState);
15874        pump();
15875      }, reason => {
15876        intentState.streamReader = null;
15877        if (this._transport.destroyed) {
15878          return;
15879        }
15880        if (intentState.operatorList) {
15881          intentState.operatorList.lastChunk = true;
15882          for (const internalRenderTask of intentState.renderTasks) {
15883            internalRenderTask.operatorListChanged();
15884          }
15885          this.#tryCleanup();
15886        }
15887        if (intentState.displayReadyCapability) {
15888          intentState.displayReadyCapability.reject(reason);
15889        } else if (intentState.opListReadCapability) {
15890          intentState.opListReadCapability.reject(reason);
15891        } else {
15892          throw reason;
15893        }
15894      });
15895    };
15896    pump();
15897  }
15898  _abortOperatorList({
15899    intentState,
15900    reason,
15901    force = false
15902  }) {
15903    if (!intentState.streamReader) {
15904      return;
15905    }
15906    if (intentState.streamReaderCancelTimeout) {
15907      clearTimeout(intentState.streamReaderCancelTimeout);
15908      intentState.streamReaderCancelTimeout = null;
15909    }
15910    if (!force) {
15911      if (intentState.renderTasks.size > 0) {
15912        return;
15913      }
15914      if (reason instanceof RenderingCancelledException) {
15915        let delay = RENDERING_CANCELLED_TIMEOUT;
15916        if (reason.extraDelay > 0 && reason.extraDelay < 1000) {
15917          delay += reason.extraDelay;
15918        }
15919        intentState.streamReaderCancelTimeout = setTimeout(() => {
15920          intentState.streamReaderCancelTimeout = null;
15921          this._abortOperatorList({
15922            intentState,
15923            reason,
15924            force: true
15925          });
15926        }, delay);
15927        return;
15928      }
15929    }
15930    intentState.streamReader.cancel(new AbortException(reason.message)).catch(() => {});
15931    intentState.streamReader = null;
15932    if (this._transport.destroyed) {
15933      return;
15934    }
15935    for (const [curCacheKey, curIntentState] of this._intentStates) {
15936      if (curIntentState === intentState) {
15937        this._intentStates.delete(curCacheKey);
15938        break;
15939      }
15940    }
15941    this.cleanup();
15942  }
15943  get stats() {
15944    return this._stats;
15945  }
15946}
15947class PDFWorker {
15948  #capability = Promise.withResolvers();
15949  #messageHandler = null;
15950  #port = null;
15951  #webWorker = null;
15952  static #fakeWorkerId = 0;
15953  static #isWorkerDisabled = false;
15954  static #workerPorts = new WeakMap();
15955  static {
15956    if (isNodeJS) {
15957      this.#isWorkerDisabled = true;
15958      GlobalWorkerOptions.workerSrc ||= "./pdf.worker.mjs";
15959    }
15960    this._isSameOrigin = (baseUrl, otherUrl) => {
15961      const base = URL.parse(baseUrl);
15962      if (!base?.origin || base.origin === "null") {
15963        return false;
15964      }
15965      const other = new URL(otherUrl, base);
15966      return base.origin === other.origin;
15967    };
15968    this._createCDNWrapper = url => {
15969      const wrapper = `await import("${url}");`;
15970      return URL.createObjectURL(new Blob([wrapper], {
15971        type: "text/javascript"
15972      }));
15973    };
15974  }
15975  constructor({
15976    name = null,
15977    port = null,
15978    verbosity = getVerbosityLevel()
15979  } = {}) {
15980    this.name = name;
15981    this.destroyed = false;
15982    this.verbosity = verbosity;
15983    if (port) {
15984      if (PDFWorker.#workerPorts.has(port)) {
15985        throw new Error("Cannot use more than one PDFWorker per port.");
15986      }
15987      PDFWorker.#workerPorts.set(port, this);
15988      this.#initializeFromPort(port);
15989    } else {
15990      this.#initialize();
15991    }
15992  }
15993  get promise() {
15994    return this.#capability.promise;
15995  }
15996  #resolve() {
15997    this.#capability.resolve();
15998    this.#messageHandler.send("configure", {
15999      verbosity: this.verbosity
16000    });
16001  }
16002  get port() {
16003    return this.#port;
16004  }
16005  get messageHandler() {
16006    return this.#messageHandler;
16007  }
16008  #initializeFromPort(port) {
16009    this.#port = port;
16010    this.#messageHandler = new MessageHandler("main", "worker", port);
16011    this.#messageHandler.on("ready", () => {});
16012    this.#resolve();
16013  }
16014  #initialize() {
16015    if (PDFWorker.#isWorkerDisabled || PDFWorker.#mainThreadWorkerMessageHandler) {
16016      this.#setupFakeWorker();
16017      return;
16018    }
16019    let {
16020      workerSrc
16021    } = PDFWorker;
16022    try {
16023      if (!PDFWorker._isSameOrigin(window.location, workerSrc)) {
16024        workerSrc = PDFWorker._createCDNWrapper(new URL(workerSrc, window.location).href);
16025      }
16026      const worker = new Worker(workerSrc, {
16027        type: "module"
16028      });
16029      const messageHandler = new MessageHandler("main", "worker", worker);
16030      const terminateEarly = () => {
16031        ac.abort();
16032        messageHandler.destroy();
16033        worker.terminate();
16034        if (this.destroyed) {
16035          this.#capability.reject(new Error("Worker was destroyed"));
16036        } else {
16037          this.#setupFakeWorker();
16038        }
16039      };
16040      const ac = new AbortController();
16041      worker.addEventListener("error", () => {
16042        if (!this.#webWorker) {
16043          terminateEarly();
16044        }
16045      }, {
16046        signal: ac.signal
16047      });
16048      messageHandler.on("test", data => {
16049        ac.abort();
16050        if (this.destroyed || !data) {
16051          terminateEarly();
16052          return;
16053        }
16054        this.#messageHandler = messageHandler;
16055        this.#port = worker;
16056        this.#webWorker = worker;
16057        this.#resolve();
16058      });
16059      messageHandler.on("ready", data => {
16060        ac.abort();
16061        if (this.destroyed) {
16062          terminateEarly();
16063          return;
16064        }
16065        try {
16066          sendTest();
16067        } catch {
16068          this.#setupFakeWorker();
16069        }
16070      });
16071      const sendTest = () => {
16072        const testObj = new Uint8Array();
16073        messageHandler.send("test", testObj, [testObj.buffer]);
16074      };
16075      sendTest();
16076      return;
16077    } catch {
16078      info("The worker has been disabled.");
16079    }
16080    this.#setupFakeWorker();
16081  }
16082  #setupFakeWorker() {
16083    if (!PDFWorker.#isWorkerDisabled) {
16084      warn("Setting up fake worker.");
16085      PDFWorker.#isWorkerDisabled = true;
16086    }
16087    PDFWorker._setupFakeWorkerGlobal.then(WorkerMessageHandler => {
16088      if (this.destroyed) {
16089        this.#capability.reject(new Error("Worker was destroyed"));
16090        return;
16091      }
16092      const port = new LoopbackPort();
16093      this.#port = port;
16094      const id = `fake${PDFWorker.#fakeWorkerId++}`;
16095      const workerHandler = new MessageHandler(id + "_worker", id, port);
16096      WorkerMessageHandler.setup(workerHandler, port);
16097      this.#messageHandler = new MessageHandler(id, id + "_worker", port);
16098      this.#resolve();
16099    }).catch(reason => {
16100      this.#capability.reject(new Error(`Setting up fake worker failed: "${reason.message}".`));
16101    });
16102  }
16103  destroy() {
16104    this.destroyed = true;
16105    this.#webWorker?.terminate();
16106    this.#webWorker = null;
16107    PDFWorker.#workerPorts.delete(this.#port);
16108    this.#port = null;
16109    this.#messageHandler?.destroy();
16110    this.#messageHandler = null;
16111  }
16112  static create(params) {
16113    const cachedPort = this.#workerPorts.get(params?.port);
16114    if (cachedPort) {
16115      if (cachedPort._pendingDestroy) {
16116        throw new Error("PDFWorker.create - the worker is being destroyed.\n" + "Please remember to await `PDFDocumentLoadingTask.destroy()`-calls.");
16117      }
16118      return cachedPort;
16119    }
16120    return new PDFWorker(params);
16121  }
16122  static get workerSrc() {
16123    if (GlobalWorkerOptions.workerSrc) {
16124      return GlobalWorkerOptions.workerSrc;
16125    }
16126    throw new Error('No "GlobalWorkerOptions.workerSrc" specified.');
16127  }
16128  static get #mainThreadWorkerMessageHandler() {
16129    try {
16130      return globalThis.pdfjsWorker?.WorkerMessageHandler || null;
16131    } catch {
16132      return null;
16133    }
16134  }
16135  static get _setupFakeWorkerGlobal() {
16136    const loader = async () => {
16137      if (this.#mainThreadWorkerMessageHandler) {
16138        return this.#mainThreadWorkerMessageHandler;
16139      }
16140      const worker = await import(
16141      /*webpackIgnore: true*/
16142      /*@vite-ignore*/
16143      this.workerSrc);
16144      return worker.WorkerMessageHandler;
16145    };
16146    return shadow(this, "_setupFakeWorkerGlobal", loader());
16147  }
16148}
16149class WorkerTransport {
16150  downloadInfoCapability = Promise.withResolvers();
16151  #fullReader = null;
16152  #methodPromises = new Map();
16153  #networkStream = null;
16154  #pageCache = new Map();
16155  #pagePromises = new Map();
16156  #pageRefCache = new Map();
16157  #passwordCapability = null;
16158  constructor(messageHandler, loadingTask, networkStream, params, factory, pagesMapper) {
16159    this.messageHandler = messageHandler;
16160    this.loadingTask = loadingTask;
16161    this.#networkStream = networkStream;
16162    this.commonObjs = new PDFObjects();
16163    this.fontLoader = new FontLoader({
16164      ownerDocument: params.ownerDocument,
16165      styleElement: params.styleElement
16166    });
16167    this.enableHWA = params.enableHWA;
16168    this.loadingParams = params.loadingParams;
16169    this._params = params;
16170    this.canvasFactory = factory.canvasFactory;
16171    this.filterFactory = factory.filterFactory;
16172    this.binaryDataFactory = factory.binaryDataFactory;
16173    this.pagesMapper = pagesMapper;
16174    this.destroyed = false;
16175    this.destroyCapability = null;
16176    this.setupMessageHandler();
16177  }
16178  updatePage(page) {
16179    const {
16180      _pageIndex
16181    } = page;
16182    this.#pageCache.set(_pageIndex, page);
16183    this.#pagePromises.set(_pageIndex, Promise.resolve(page));
16184  }
16185  #cacheSimpleMethod(name, data = null) {
16186    return this.#methodPromises.getOrInsertComputed(name, () => this.messageHandler.sendWithPromise(name, data));
16187  }
16188  #onProgress({
16189    loaded,
16190    total
16191  }) {
16192    this.loadingTask.onProgress?.({
16193      loaded,
16194      total,
16195      percent: total ? MathClamp(Math.round(loaded / total * 100), 0, 100) : NaN
16196    });
16197  }
16198  get annotationStorage() {
16199    return shadow(this, "annotationStorage", new AnnotationStorage());
16200  }
16201  getRenderingIntent(intent, annotationMode = AnnotationMode.ENABLE, printAnnotationStorage = null, isEditing = false, isOpList = false) {
16202    let renderingIntent = RenderingIntentFlag.DISPLAY;
16203    let annotationStorageSerializable = SerializableEmpty;
16204    switch (intent) {
16205      case "any":
16206        renderingIntent = RenderingIntentFlag.ANY;
16207        break;
16208      case "display":
16209        break;
16210      case "print":
16211        renderingIntent = RenderingIntentFlag.PRINT;
16212        break;
16213      default:
16214        warn(`getRenderingIntent - invalid intent: ${intent}`);
16215    }
16216    const annotationStorage = renderingIntent & RenderingIntentFlag.PRINT && printAnnotationStorage instanceof PrintAnnotationStorage ? printAnnotationStorage : this.annotationStorage;
16217    switch (annotationMode) {
16218      case AnnotationMode.DISABLE:
16219        renderingIntent += RenderingIntentFlag.ANNOTATIONS_DISABLE;
16220        break;
16221      case AnnotationMode.ENABLE:
16222        break;
16223      case AnnotationMode.ENABLE_FORMS:
16224        renderingIntent += RenderingIntentFlag.ANNOTATIONS_FORMS;
16225        break;
16226      case AnnotationMode.ENABLE_STORAGE:
16227        renderingIntent += RenderingIntentFlag.ANNOTATIONS_STORAGE;
16228        annotationStorageSerializable = annotationStorage.serializable;
16229        break;
16230      default:
16231        warn(`getRenderingIntent - invalid annotationMode: ${annotationMode}`);
16232    }
16233    if (isEditing) {
16234      renderingIntent += RenderingIntentFlag.IS_EDITING;
16235    }
16236    if (isOpList) {
16237      renderingIntent += RenderingIntentFlag.OPLIST;
16238    }
16239    const {
16240      ids: modifiedIds,
16241      hash: modifiedIdsHash
16242    } = annotationStorage.modifiedIds;
16243    const cacheKeyBuf = [renderingIntent, annotationStorageSerializable.hash, modifiedIdsHash];
16244    return {
16245      renderingIntent,
16246      cacheKey: cacheKeyBuf.join("_"),
16247      annotationStorageSerializable,
16248      modifiedIds
16249    };
16250  }
16251  destroy() {
16252    if (this.destroyCapability) {
16253      return this.destroyCapability.promise;
16254    }
16255    this.destroyed = true;
16256    this.destroyCapability = Promise.withResolvers();
16257    this.#passwordCapability?.reject(new Error("Worker was destroyed during onPassword callback"));
16258    const waitOn = [];
16259    for (const page of this.#pageCache.values()) {
16260      waitOn.push(page._destroy());
16261    }
16262    this.#pageCache.clear();
16263    this.#pagePromises.clear();
16264    this.#pageRefCache.clear();
16265    if (Object.hasOwn(this, "annotationStorage")) {
16266      this.annotationStorage.resetModified();
16267    }
16268    const terminated = this.messageHandler.sendWithPromise("Terminate", null);
16269    waitOn.push(terminated);
16270    Promise.all(waitOn).then(() => {
16271      this.commonObjs.clear();
16272      this.fontLoader.clear();
16273      this.#methodPromises.clear();
16274      this.filterFactory.destroy();
16275      TextLayer.cleanup();
16276      this.#networkStream?.cancelAllRequests(new AbortException("Worker was terminated."));
16277      this.messageHandler?.destroy();
16278      this.messageHandler = null;
16279      this.destroyCapability.resolve();
16280    }, this.destroyCapability.reject);
16281    return this.destroyCapability.promise;
16282  }
16283  setupMessageHandler() {
16284    const {
16285      messageHandler,
16286      loadingTask
16287    } = this;
16288    messageHandler.on("GetReader", (data, sink) => {
16289      assert(this.#networkStream, "GetReader - no `BasePDFStream` instance available.");
16290      this.#fullReader = this.#networkStream.getFullReader();
16291      this.#fullReader.onProgress = evt => this.#onProgress(evt);
16292      sink.onPull = () => {
16293        this.#fullReader.read().then(function ({
16294          value,
16295          done
16296        }) {
16297          if (done) {
16298            sink.close();
16299            return;
16300          }
16301          assert(value instanceof ArrayBuffer, "GetReader - expected an ArrayBuffer.");
16302          sink.enqueue(new Uint8Array(value), 1, [value]);
16303        }).catch(reason => {
16304          sink.error(reason);
16305        });
16306      };
16307      sink.onCancel = reason => {
16308        this.#fullReader.cancel(reason);
16309        sink.ready.catch(readyReason => {
16310          if (this.destroyed) {
16311            return;
16312          }
16313          throw readyReason;
16314        });
16315      };
16316    });
16317    messageHandler.on("ReaderHeadersReady", async data => {
16318      await this.#fullReader.headersReady;
16319      const {
16320        isStreamingSupported,
16321        isRangeSupported,
16322        contentLength
16323      } = this.#fullReader;
16324      if (isStreamingSupported && isRangeSupported) {
16325        this.#fullReader.onProgress = null;
16326      }
16327      return {
16328        isStreamingSupported,
16329        isRangeSupported,
16330        contentLength
16331      };
16332    });
16333    messageHandler.on("GetRangeReader", (data, sink) => {
16334      assert(this.#networkStream, "GetRangeReader - no `BasePDFStream` instance available.");
16335      const rangeReader = this.#networkStream.getRangeReader(data.begin, data.end);
16336      if (!rangeReader) {
16337        sink.close();
16338        return;
16339      }
16340      sink.onPull = () => {
16341        rangeReader.read().then(function ({
16342          value,
16343          done
16344        }) {
16345          if (done) {
16346            sink.close();
16347            return;
16348          }
16349          assert(value instanceof ArrayBuffer, "GetRangeReader - expected an ArrayBuffer.");
16350          sink.enqueue(new Uint8Array(value), 1, [value]);
16351        }).catch(reason => {
16352          sink.error(reason);
16353        });
16354      };
16355      sink.onCancel = reason => {
16356        rangeReader.cancel(reason);
16357        sink.ready.catch(readyReason => {
16358          if (this.destroyed) {
16359            return;
16360          }
16361          throw readyReason;
16362        });
16363      };
16364    });
16365    messageHandler.on("GetDoc", ({
16366      pdfInfo
16367    }) => {
16368      this.pagesMapper.pagesNumber = pdfInfo.numPages;
16369      this._numPages = pdfInfo.numPages;
16370      this._htmlForXfa = pdfInfo.htmlForXfa;
16371      delete pdfInfo.htmlForXfa;
16372      loadingTask._capability.resolve(new PDFDocumentProxy(pdfInfo, this));
16373    });
16374    messageHandler.on("DocException", ex => {
16375      loadingTask._capability.reject(wrapReason(ex));
16376    });
16377    messageHandler.on("PasswordRequest", ex => {
16378      this.#passwordCapability = Promise.withResolvers();
16379      try {
16380        if (!loadingTask.onPassword) {
16381          throw wrapReason(ex);
16382        }
16383        const updatePassword = password => {
16384          if (password instanceof Error) {
16385            this.#passwordCapability.reject(password);
16386          } else {
16387            this.#passwordCapability.resolve({
16388              password
16389            });
16390          }
16391        };
16392        loadingTask.onPassword(updatePassword, ex.code);
16393      } catch (err) {
16394        this.#passwordCapability.reject(err);
16395      }
16396      return this.#passwordCapability.promise;
16397    });
16398    messageHandler.on("DataLoaded", data => {
16399      this.#onProgress({
16400        loaded: data.length,
16401        total: data.length
16402      });
16403      this.downloadInfoCapability.resolve(data);
16404    });
16405    messageHandler.on("StartRenderPage", data => {
16406      if (this.destroyed) {
16407        return;
16408      }
16409      const page = this.#pageCache.get(data.pageIndex);
16410      page._startRenderPage(data.transparency, data.cacheKey);
16411    });
16412    messageHandler.on("commonobj", ([id, type, exportedData]) => {
16413      if (this.destroyed) {
16414        return null;
16415      }
16416      if (this.commonObjs.has(id)) {
16417        return null;
16418      }
16419      switch (type) {
16420        case "Font":
16421          if ("error" in exportedData) {
16422            const exportedError = exportedData.error;
16423            warn(`Error during font loading: ${exportedError}`);
16424            this.commonObjs.resolve(id, exportedError);
16425            break;
16426          }
16427          const fontData = new FontInfo(exportedData);
16428          const inspectFont = this._params.pdfBug && globalThis.FontInspector?.enabled ? (font, url) => globalThis.FontInspector.fontAdded(font, url) : null;
16429          const font = new FontFaceObject(fontData, inspectFont, exportedData.charProcOperatorList, exportedData.extra);
16430          this.fontLoader.bind(font).catch(() => messageHandler.sendWithPromise("FontFallback", {
16431            id
16432          })).finally(() => {
16433            if (!font.fontExtraProperties) {
16434              font.clearData();
16435            }
16436            this.commonObjs.resolve(id, font);
16437          });
16438          break;
16439        case "CopyLocalImage":
16440          const {
16441            imageRef
16442          } = exportedData;
16443          assert(imageRef, "The imageRef must be defined.");
16444          for (const pageProxy of this.#pageCache.values()) {
16445            for (const [, data] of pageProxy.objs) {
16446              if (data?.ref !== imageRef) {
16447                continue;
16448              }
16449              if (!data.dataLen) {
16450                return null;
16451              }
16452              const copy = structuredClone(data);
16453              this.commonObjs.resolve(id, copy);
16454              return data.dataLen;
16455            }
16456          }
16457          break;
16458        case "FontPath":
16459          this.commonObjs.resolve(id, new FontPathInfo(exportedData));
16460          break;
16461        case "Image":
16462          this.commonObjs.resolve(id, exportedData);
16463          break;
16464        case "Pattern":
16465          const pattern = new PatternInfo(exportedData);
16466          this.commonObjs.resolve(id, pattern.getIR());
16467          break;
16468        default:
16469          throw new Error(`Got unknown common object type ${type}`);
16470      }
16471      return null;
16472    });
16473    messageHandler.on("obj", ([id, pageIndex, type, imageData]) => {
16474      if (this.destroyed) {
16475        return;
16476      }
16477      const pageProxy = this.#pageCache.get(pageIndex);
16478      if (pageProxy.objs.has(id)) {
16479        return;
16480      }
16481      if (pageProxy._intentStates.size === 0) {
16482        imageData?.bitmap?.close();
16483        return;
16484      }
16485      switch (type) {
16486        case "Image":
16487        case "Pattern":
16488          pageProxy.objs.resolve(id, imageData);
16489          break;
16490        default:
16491          throw new Error(`Got unknown object type ${type}`);
16492      }
16493    });
16494    messageHandler.on("DocProgress", data => {
16495      if (this.destroyed) {
16496        return;
16497      }
16498      this.#onProgress(data);
16499    });
16500    messageHandler.on("FetchBinaryData", async data => {
16501      if (this.destroyed) {
16502        throw new Error("Worker was destroyed.");
16503      }
16504      if (!this.binaryDataFactory) {
16505        throw new Error("`BinaryDataFactory` not initialized, see the `useWorkerFetch` parameter.");
16506      }
16507      return this.binaryDataFactory.fetch(data);
16508    });
16509  }
16510  getData() {
16511    return this.messageHandler.sendWithPromise("GetData", null);
16512  }
16513  saveDocument() {
16514    if (this.annotationStorage.size <= 0) {
16515      warn("saveDocument called while `annotationStorage` is empty, " + "please use the getData-method instead.");
16516    }
16517    const {
16518      map,
16519      transfer
16520    } = this.annotationStorage.serializable;
16521    return this.messageHandler.sendWithPromise("SaveDocument", {
16522      isPureXfa: !!this._htmlForXfa,
16523      numPages: this._numPages,
16524      annotationStorage: map,
16525      filename: this.#fullReader?.filename ?? null
16526    }, transfer).finally(() => {
16527      this.annotationStorage.resetModified();
16528    });
16529  }
16530  extractPages(pageInfos
vendor: 28,028 bytes, lines 16530-17416
16530) {
16531    const params = {
16532      pageInfos
16533    };
16534    let transfer;
16535    const ImageBitmapCtor = globalThis.ImageBitmap;
16536    if (typeof ImageBitmapCtor === "function") {
16537      const infos = Array.isArray(pageInfos) ? pageInfos : [pageInfos];
16538      for (const pageInfo of infos) {
16539        if (pageInfo?.image instanceof ImageBitmapCtor) {
16540          (transfer ||= []).push(pageInfo.image);
16541        }
16542      }
16543    }
16544    if (this.annotationStorage.size > 0) {
16545      const serialized = this.annotationStorage.serializable;
16546      let {
16547        map
16548      } = serialized;
16549      if (serialized.transfer?.length) {
16550        if (transfer) {
16551          transfer.push(...serialized.transfer);
16552        } else {
16553          transfer = serialized.transfer;
16554        }
16555      }
16556      const mapping = this.pagesMapper.getMapping();
16557      if (mapping) {
16558        const remapped = new Map();
16559        for (const [k, v] of map) {
16560          if (v?.pageIndex !== undefined && v.pageIndex >= 0 && v.pageIndex < mapping.length) {
16561            const sourceIdx = mapping[v.pageIndex] - 1;
16562            if (sourceIdx !== v.pageIndex) {
16563              remapped.set(k, {
16564                ...v,
16565                pageIndex: sourceIdx
16566              });
16567              continue;
16568            }
16569          }
16570          remapped.set(k, v);
16571        }
16572        map = remapped;
16573      }
16574      params.annotationStorage = map;
16575    }
16576    return this.messageHandler.sendWithPromise("ExtractPages", params, transfer).finally(() => {
16577      this.annotationStorage.resetModified();
16578    });
16579  }
16580  getPage(pageNumber) {
16581    if (!Number.isInteger(pageNumber) || pageNumber <= 0 || pageNumber > this.pagesMapper.pagesNumber) {
16582      return Promise.reject(new Error("Invalid page request."));
16583    }
16584    const pageIndex = pageNumber - 1;
16585    const newPageIndex = this.pagesMapper.getPageId(pageNumber) - 1;
16586    const cachedPromise = this.#pagePromises.get(pageIndex);
16587    if (cachedPromise) {
16588      return cachedPromise;
16589    }
16590    const promise = this.messageHandler.sendWithPromise("GetPage", {
16591      pageIndex: newPageIndex
16592    }).then(pageInfo => {
16593      if (this.destroyed) {
16594        throw new Error("Transport destroyed");
16595      }
16596      if (pageInfo.refStr) {
16597        this.#pageRefCache.set(pageInfo.refStr, newPageIndex);
16598      }
16599      const page = new PDFPageProxy(pageIndex, pageInfo, this, this.pagesMapper, this._params.pdfBug);
16600      this.#pageCache.set(pageIndex, page);
16601      return page;
16602    });
16603    this.#pagePromises.set(pageIndex, promise);
16604    return promise;
16605  }
16606  async getPageIndex(ref) {
16607    if (!isRefProxy(ref)) {
16608      throw new Error("Invalid pageIndex request.");
16609    }
16610    const index = await this.messageHandler.sendWithPromise("GetPageIndex", {
16611      num: ref.num,
16612      gen: ref.gen
16613    });
16614    const pageNumber = this.pagesMapper.getPageNumber(index + 1);
16615    if (pageNumber === 0) {
16616      throw new Error("GetPageIndex: page has been removed.");
16617    }
16618    return pageNumber - 1;
16619  }
16620  getAnnotations(pageIndex, intent) {
16621    return this.messageHandler.sendWithPromise("GetAnnotations", {
16622      pageIndex: this.pagesMapper.getPageId(pageIndex + 1) - 1,
16623      intent
16624    });
16625  }
16626  getFieldObjects() {
16627    return this.#cacheSimpleMethod("GetFieldObjects");
16628  }
16629  hasJSActions() {
16630    return this.#cacheSimpleMethod("HasJSActions");
16631  }
16632  getCalculationOrderIds() {
16633    return this.messageHandler.sendWithPromise("GetCalculationOrderIds", null);
16634  }
16635  getDestinations() {
16636    return this.messageHandler.sendWithPromise("GetDestinations", null);
16637  }
16638  getDestination(id) {
16639    if (typeof id !== "string") {
16640      return Promise.reject(new Error("Invalid destination request."));
16641    }
16642    return this.messageHandler.sendWithPromise("GetDestination", {
16643      id
16644    });
16645  }
16646  getPageLabels() {
16647    return this.messageHandler.sendWithPromise("GetPageLabels", null);
16648  }
16649  getPageLayout() {
16650    return this.messageHandler.sendWithPromise("GetPageLayout", null);
16651  }
16652  getPageMode() {
16653    return this.messageHandler.sendWithPromise("GetPageMode", null);
16654  }
16655  getViewerPreferences() {
16656    return this.messageHandler.sendWithPromise("GetViewerPreferences", null);
16657  }
16658  getOpenAction() {
16659    return this.messageHandler.sendWithPromise("GetOpenAction", null);
16660  }
16661  getAttachments() {
16662    return this.messageHandler.sendWithPromise("GetAttachments", null);
16663  }
16664  getAttachmentContent(id) {
16665    return this.messageHandler.sendWithPromise("GetAttachmentContent", id);
16666  }
16667  getAnnotationsByType(types, pageIndexesToSkip) {
16668    return this.messageHandler.sendWithPromise("GetAnnotationsByType", {
16669      types,
16670      pageIndexesToSkip
16671    });
16672  }
16673  getDocJSActions() {
16674    return this.#cacheSimpleMethod("GetDocJSActions");
16675  }
16676  getPageJSActions(pageIndex) {
16677    return this.messageHandler.sendWithPromise("GetPageJSActions", {
16678      pageIndex: this.pagesMapper.getPageId(pageIndex + 1) - 1
16679    });
16680  }
16681  getStructTree(pageIndex) {
16682    return this.messageHandler.sendWithPromise("GetStructTree", {
16683      pageIndex: this.pagesMapper.getPageId(pageIndex + 1) - 1
16684    });
16685  }
16686  getOutline() {
16687    return this.messageHandler.sendWithPromise("GetOutline", null);
16688  }
16689  getOptionalContentConfig(renderingIntent) {
16690    return this.#cacheSimpleMethod("GetOptionalContentConfig").then(data => new OptionalContentConfig(data, renderingIntent));
16691  }
16692  getPermissions() {
16693    return this.messageHandler.sendWithPromise("GetPermissions", null);
16694  }
16695  getMetadata() {
16696    const name = "GetMetadata";
16697    return this.#methodPromises.getOrInsertComputed(name, () => this.messageHandler.sendWithPromise(name, null).then(results => ({
16698      info: results[0],
16699      metadata: results[1] ? new Metadata(results[1]) : null,
16700      contentDispositionFilename: this.#fullReader?.filename ?? null,
16701      contentLength: this.#fullReader?.contentLength ?? null,
16702      hasStructTree: results[2]
16703    })));
16704  }
16705  getMarkInfo() {
16706    return this.messageHandler.sendWithPromise("GetMarkInfo", null);
16707  }
16708  getRawData(data) {
16709    return this.messageHandler.sendWithPromise("GetRawData", data);
16710  }
16711  async startCleanup(keepLoadedFonts = false) {
16712    if (this.destroyed) {
16713      return;
16714    }
16715    await this.messageHandler.sendWithPromise("Cleanup", null);
16716    for (const page of this.#pageCache.values()) {
16717      const cleanupSuccessful = page.cleanup();
16718      if (!cleanupSuccessful) {
16719        throw new Error(`startCleanup: Page ${page.pageNumber} is currently rendering.`);
16720      }
16721    }
16722    this.commonObjs.clear();
16723    if (!keepLoadedFonts) {
16724      this.fontLoader.clear();
16725    }
16726    this.#methodPromises.clear();
16727    this.filterFactory.destroy(true);
16728    TextLayer.cleanup();
16729  }
16730  cachedPageNumber(ref) {
16731    if (!isRefProxy(ref)) {
16732      return null;
16733    }
16734    const refStr = ref.gen === 0 ? `${ref.num}R` : `${ref.num}R${ref.gen}`;
16735    const pageIndex = this.#pageRefCache.get(refStr);
16736    if (pageIndex >= 0) {
16737      const pageNumber = this.pagesMapper.getPageNumber(pageIndex + 1);
16738      if (pageNumber !== 0) {
16739        return pageNumber;
16740      }
16741    }
16742    return null;
16743  }
16744}
16745class RenderTask {
16746  _internalRenderTask = null;
16747  onContinue = null;
16748  onError = null;
16749  constructor(internalRenderTask) {
16750    this._internalRenderTask = internalRenderTask;
16751  }
16752  get promise() {
16753    return this._internalRenderTask.capability.promise;
16754  }
16755  cancel(extraDelay = 0) {
16756    this._internalRenderTask.cancel(null, extraDelay);
16757  }
16758  get separateAnnots() {
16759    const {
16760      separateAnnots
16761    } = this._internalRenderTask.operatorList;
16762    if (!separateAnnots) {
16763      return false;
16764    }
16765    const {
16766      annotationCanvasMap
16767    } = this._internalRenderTask;
16768    return separateAnnots.form || separateAnnots.canvas && annotationCanvasMap?.size > 0;
16769  }
16770  get imageCoordinates() {
16771    return this._internalRenderTask.imageCoordinates || null;
16772  }
16773}
16774class InternalRenderTask {
16775  #rAF = null;
16776  static #canvasInUse = new WeakSet();
16777  constructor({
16778    callback,
16779    params,
16780    objs,
16781    commonObjs,
16782    annotationCanvasMap,
16783    operatorList,
16784    pageIndex,
16785    canvasFactory,
16786    filterFactory,
16787    useRequestAnimationFrame = false,
16788    pdfBug = false,
16789    pageColors = null,
16790    enableHWA = false,
16791    operationsFilter = null
16792  }) {
16793    this.callback = callback;
16794    this.params = params;
16795    this.objs = objs;
16796    this.commonObjs = commonObjs;
16797    this.annotationCanvasMap = annotationCanvasMap;
16798    this.operatorListIdx = null;
16799    this.operatorList = operatorList;
16800    this._pageIndex = pageIndex;
16801    this.canvasFactory = canvasFactory;
16802    this.filterFactory = filterFactory;
16803    this._pdfBug = pdfBug;
16804    this.pageColors = pageColors;
16805    this.running = false;
16806    this.graphicsReadyCallback = null;
16807    this.graphicsReady = false;
16808    this._useRequestAnimationFrame = useRequestAnimationFrame === true && typeof window !== "undefined";
16809    this.cancelled = false;
16810    this.capability = Promise.withResolvers();
16811    this.task = new RenderTask(this);
16812    this._cancelBound = this.cancel.bind(this);
16813    this._continueBound = this._continue.bind(this);
16814    this._scheduleNextBound = this._scheduleNext.bind(this);
16815    this._nextBound = this._next.bind(this);
16816    this._canvas = params.canvas;
16817    this._canvasContext = params.canvas ? null : params.canvasContext;
16818    this._enableHWA = enableHWA;
16819    this._dependencyTracker = params.dependencyTracker;
16820    this._imagesTracker = params.imagesTracker;
16821    this._operationsFilter = operationsFilter;
16822  }
16823  get completed() {
16824    return this.capability.promise.catch(function () {});
16825  }
16826  initializeGraphics({
16827    transparency = false,
16828    optionalContentConfig
16829  }) {
16830    if (this.cancelled) {
16831      return;
16832    }
16833    if (this._canvas) {
16834      if (InternalRenderTask.#canvasInUse.has(this._canvas)) {
16835        throw new Error("Cannot use the same canvas during multiple render() operations. " + "Use different canvas or ensure previous operations were " + "cancelled or completed.");
16836      }
16837      InternalRenderTask.#canvasInUse.add(this._canvas);
16838    }
16839    if (this._pdfBug && globalThis.StepperManager?.enabled) {
16840      this.stepper = globalThis.StepperManager.create(this._pageIndex);
16841      this.stepper.init(this.operatorList);
16842      this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
16843    }
16844    const {
16845      viewport,
16846      transform,
16847      background,
16848      dependencyTracker,
16849      imagesTracker
16850    } = this.params;
16851    const canvasContext = this._canvasContext || this._canvas.getContext("2d", {
16852      alpha: false,
16853      willReadFrequently: !this._enableHWA
16854    });
16855    this.gfx = new CanvasGraphics(canvasContext, this.commonObjs, this.objs, this.canvasFactory, this.filterFactory, {
16856      optionalContentConfig
16857    }, this.annotationCanvasMap, this.pageColors, dependencyTracker, imagesTracker);
16858    this.gfx.beginDrawing({
16859      transform,
16860      viewport,
16861      transparency,
16862      background
16863    });
16864    this.operatorListIdx = 0;
16865    this.graphicsReady = true;
16866    this.graphicsReadyCallback?.();
16867  }
16868  cancel(error = null, extraDelay = 0) {
16869    this.running = false;
16870    this.cancelled = true;
16871    this.gfx?.endDrawing();
16872    if (this.#rAF) {
16873      window.cancelAnimationFrame(this.#rAF);
16874      this.#rAF = null;
16875    }
16876    InternalRenderTask.#canvasInUse.delete(this._canvas);
16877    error ||= new RenderingCancelledException(`Rendering cancelled, page ${this._pageIndex + 1}`, extraDelay);
16878    this.callback(error);
16879    this.task.onError?.(error);
16880  }
16881  operatorListChanged() {
16882    if (!this.graphicsReady) {
16883      this.graphicsReadyCallback ||= this._continueBound;
16884      return;
16885    }
16886    this.gfx.dependencyTracker?.growOperationsCount(this.operatorList.fnArray.length);
16887    this.stepper?.updateOperatorList(this.operatorList);
16888    if (this.running) {
16889      return;
16890    }
16891    this._continue();
16892  }
16893  _continue() {
16894    this.running = true;
16895    if (this.cancelled) {
16896      return;
16897    }
16898    if (this.task.onContinue) {
16899      this.task.onContinue(this._scheduleNextBound);
16900    } else {
16901      this._scheduleNext();
16902    }
16903  }
16904  _scheduleNext() {
16905    if (this._useRequestAnimationFrame) {
16906      this.#rAF = window.requestAnimationFrame(() => {
16907        this.#rAF = null;
16908        this._nextBound().catch(this._cancelBound);
16909      });
16910    } else {
16911      Promise.resolve().then(this._nextBound).catch(this._cancelBound);
16912    }
16913  }
16914  async _next() {
16915    if (this.cancelled) {
16916      return;
16917    }
16918    this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList, this.operatorListIdx, this._continueBound, this.stepper, this._operationsFilter);
16919    if (this.operatorListIdx === this.operatorList.argsArray.length) {
16920      this.running = false;
16921      if (this.operatorList.lastChunk) {
16922        this.gfx.endDrawing();
16923        InternalRenderTask.#canvasInUse.delete(this._canvas);
16924        this.callback();
16925      }
16926    }
16927  }
16928}
16929const version = "6.1.200";
16930const build = "6353acefe";
16931
16932;// ./src/display/editor/color_picker.js
16933
16934
16935
16936class ColorPicker {
16937  #button = null;
16938  #buttonSwatch = null;
16939  #defaultColor;
16940  #dropdown = null;
16941  #dropdownWasFromKeyboard = false;
16942  #isMainColorPicker = false;
16943  #editor = null;
16944  #eventBus;
16945  #openDropdownAC = null;
16946  #uiManager = null;
16947  static #l10nColor = null;
16948  static get _keyboardManager() {
16949    return shadow(this, "_keyboardManager", new KeyboardManager([[["Escape"], ColorPicker.prototype._hideDropdownFromKeyboard], [["Space"], ColorPicker.prototype._colorSelectFromKeyboard], [["ArrowDown", "ArrowRight"], ColorPicker.prototype._moveToNext], [["ArrowUp", "ArrowLeft"], ColorPicker.prototype._moveToPrevious], [["Home"], ColorPicker.prototype._moveToBeginning], [["End"], ColorPicker.prototype._moveToEnd]]));
16950  }
16951  constructor({
16952    editor = null,
16953    uiManager = null
16954  }) {
16955    if (editor) {
16956      this.#isMainColorPicker = false;
16957      this.#editor = editor;
16958    } else {
16959      this.#isMainColorPicker = true;
16960    }
16961    this.#uiManager = editor?._uiManager || uiManager;
16962    this.#eventBus = this.#uiManager._eventBus;
16963    this.#defaultColor = editor?.color?.toUpperCase() || this.#uiManager?.highlightColors.values().next().value || "#FFFF98";
16964    ColorPicker.#l10nColor ||= Object.freeze({
16965      blue: "pdfjs-editor-colorpicker-blue",
16966      green: "pdfjs-editor-colorpicker-green",
16967      pink: "pdfjs-editor-colorpicker-pink",
16968      red: "pdfjs-editor-colorpicker-red",
16969      yellow: "pdfjs-editor-colorpicker-yellow"
16970    });
16971  }
16972  renderButton() {
16973    const button = this.#button = document.createElement("button");
16974    button.className = "colorPicker";
16975    button.tabIndex = "0";
16976    button.setAttribute("data-l10n-id", "pdfjs-editor-colorpicker-button");
16977    button.ariaHasPopup = "true";
16978    if (this.#editor) {
16979      button.ariaControls = `${this.#editor.id}_colorpicker_dropdown`;
16980    }
16981    const signal = this.#uiManager._signal;
16982    button.addEventListener("click", this.#openDropdown.bind(this), {
16983      signal
16984    });
16985    button.addEventListener("keydown", this.#keyDown.bind(this), {
16986      signal
16987    });
16988    const swatch = this.#buttonSwatch = document.createElement("span");
16989    swatch.className = "swatch";
16990    swatch.ariaHidden = "true";
16991    swatch.style.backgroundColor = this.#defaultColor;
16992    button.append(swatch);
16993    return button;
16994  }
16995  renderMainDropdown() {
16996    const dropdown = this.#dropdown = this.#getDropdownRoot();
16997    dropdown.ariaOrientation = "horizontal";
16998    dropdown.ariaLabelledBy = "highlightColorPickerLabel";
16999    return dropdown;
17000  }
17001  #getDropdownRoot() {
17002    const div = document.createElement("div");
17003    const signal = this.#uiManager._signal;
17004    div.addEventListener("contextmenu", noContextMenu, {
17005      signal
17006    });
17007    div.className = "dropdown";
17008    div.role = "listbox";
17009    div.ariaMultiSelectable = "false";
17010    div.ariaOrientation = "vertical";
17011    div.setAttribute("data-l10n-id", "pdfjs-editor-colorpicker-dropdown");
17012    if (this.#editor) {
17013      div.id = `${this.#editor.id}_colorpicker_dropdown`;
17014    }
17015    for (const [name, color] of this.#uiManager.highlightColors) {
17016      const button = document.createElement("button");
17017      button.tabIndex = "0";
17018      button.role = "option";
17019      button.setAttribute("data-color", color);
17020      button.title = name;
17021      button.setAttribute("data-l10n-id", ColorPicker.#l10nColor[name]);
17022      const swatch = document.createElement("span");
17023      button.append(swatch);
17024      swatch.className = "swatch";
17025      swatch.style.backgroundColor = color;
17026      button.ariaSelected = color === this.#defaultColor;
17027      button.addEventListener("click", this.#colorSelect.bind(this, color), {
17028        signal
17029      });
17030      div.append(button);
17031    }
17032    div.addEventListener("keydown", this.#keyDown.bind(this), {
17033      signal
17034    });
17035    return div;
17036  }
17037  #colorSelect(color, event) {
17038    event.stopPropagation();
17039    this.#eventBus.dispatch("switchannotationeditorparams", {
17040      source: this,
17041      type: AnnotationEditorParamsType.HIGHLIGHT_COLOR,
17042      value: color
17043    });
17044    this.updateColor(color);
17045  }
17046  _colorSelectFromKeyboard(event) {
17047    if (event.target === this.#button) {
17048      this.#openDropdown(event);
17049      return;
17050    }
17051    const color = event.target.getAttribute("data-color");
17052    if (!color) {
17053      return;
17054    }
17055    this.#colorSelect(color, event);
17056  }
17057  _moveToNext(event) {
17058    if (!this.#isDropdownVisible) {
17059      this.#openDropdown(event);
17060      return;
17061    }
17062    if (event.target === this.#button) {
17063      this.#dropdown.firstElementChild?.focus();
17064      return;
17065    }
17066    event.target.nextSibling?.focus();
17067  }
17068  _moveToPrevious(event) {
17069    if (event.target === this.#dropdown?.firstElementChild || event.target === this.#button) {
17070      if (this.#isDropdownVisible) {
17071        this._hideDropdownFromKeyboard();
17072      }
17073      return;
17074    }
17075    if (!this.#isDropdownVisible) {
17076      this.#openDropdown(event);
17077    }
17078    event.target.previousSibling?.focus();
17079  }
17080  _moveToBeginning(event) {
17081    if (!this.#isDropdownVisible) {
17082      this.#openDropdown(event);
17083      return;
17084    }
17085    this.#dropdown.firstElementChild?.focus();
17086  }
17087  _moveToEnd(event) {
17088    if (!this.#isDropdownVisible) {
17089      this.#openDropdown(event);
17090      return;
17091    }
17092    this.#dropdown.lastElementChild?.focus();
17093  }
17094  #keyDown(event) {
17095    ColorPicker._keyboardManager.exec(this, event);
17096  }
17097  #openDropdown(event) {
17098    if (this.#isDropdownVisible) {
17099      this.hideDropdown();
17100      return;
17101    }
17102    this.#dropdownWasFromKeyboard = event.detail === 0;
17103    if (!this.#openDropdownAC) {
17104      this.#openDropdownAC = new AbortController();
17105      window.addEventListener("pointerdown", this.#pointerDown.bind(this), {
17106        signal: this.#uiManager.combinedSignal(this.#openDropdownAC)
17107      });
17108    }
17109    this.#button.ariaExpanded = "true";
17110    if (this.#dropdown) {
17111      this.#dropdown.classList.remove("hidden");
17112      return;
17113    }
17114    const root = this.#dropdown = this.#getDropdownRoot();
17115    this.#button.append(root);
17116  }
17117  #pointerDown(event) {
17118    if (this.#dropdown?.contains(event.target)) {
17119      return;
17120    }
17121    this.hideDropdown();
17122  }
17123  hideDropdown() {
17124    this.#dropdown?.classList.add("hidden");
17125    this.#button.ariaExpanded = "false";
17126    this.#openDropdownAC?.abort();
17127    this.#openDropdownAC = null;
17128  }
17129  get #isDropdownVisible() {
17130    return this.#dropdown && !this.#dropdown.classList.contains("hidden");
17131  }
17132  _hideDropdownFromKeyboard() {
17133    if (this.#isMainColorPicker) {
17134      return;
17135    }
17136    if (!this.#isDropdownVisible) {
17137      this.#editor?.unselect();
17138      return;
17139    }
17140    this.hideDropdown();
17141    this.#button.focus({
17142      preventScroll: true,
17143      focusVisible: this.#dropdownWasFromKeyboard
17144    });
17145  }
17146  updateColor(color) {
17147    if (this.#buttonSwatch) {
17148      this.#buttonSwatch.style.backgroundColor = color;
17149    }
17150    if (!this.#dropdown) {
17151      return;
17152    }
17153    const i = this.#uiManager.highlightColors.values();
17154    for (const child of this.#dropdown.children) {
17155      child.ariaSelected = i.next().value === color.toUpperCase();
17156    }
17157  }
17158  destroy() {
17159    this.#button?.remove();
17160    this.#button = null;
17161    this.#buttonSwatch = null;
17162    this.#dropdown?.remove();
17163    this.#dropdown = null;
17164  }
17165}
17166class BasicColorPicker {
17167  #input = null;
17168  #hasAlpha = false;
17169  #editor = null;
17170  #uiManager = null;
17171  static #l10nColor = null;
17172  constructor(editor) {
17173    this.#editor = editor;
17174    this.#uiManager = editor._uiManager;
17175    BasicColorPicker.#l10nColor ||= Object.freeze({
17176      freetext: "pdfjs-editor-color-picker-free-text-input",
17177      ink: "pdfjs-editor-color-picker-ink-input"
17178    });
17179  }
17180  renderButton() {
17181    if (this.#input) {
17182      return this.#input;
17183    }
17184    const {
17185      editorType,
17186      colorType,
17187      colorAndOpacityType,
17188      opacityType,
17189      color,
17190      opacity
17191    } = this.#editor;
17192    const hasAlpha = this.#hasAlpha = FeatureTest.isAlphaColorInputSupported && opacityType !== undefined;
17193    const input = this.#input = document.createElement("input");
17194    input.type = "color";
17195    if (hasAlpha) {
17196      input.setAttribute("alpha", "");
17197      const alphaHex = Util.hexNums[Math.round((opacity ?? 1) * 255)];
17198      input.value = (color || "#000000") + alphaHex;
17199    } else {
17200      input.value = color || "#000000";
17201    }
17202    input.className = "basicColorPicker";
17203    input.tabIndex = 0;
17204    input.setAttribute("data-l10n-id", BasicColorPicker.#l10nColor[editorType]);
17205    input.addEventListener("input", () => {
17206      if (hasAlpha) {
17207        const rgba = getRGBA(input.value);
17208        if (!rgba) {
17209          return;
17210        }
17211        const [r, g, b, op] = rgba;
17212        const hex = Util.makeHexColor(r, g, b);
17213        if (colorAndOpacityType !== undefined) {
17214          this.#uiManager.updateParams(colorAndOpacityType, {
17215            color: hex,
17216            opacity: op
17217          });
17218        } else {
17219          this.#uiManager.updateParams(colorType, hex);
17220          this.#uiManager.updateParams(opacityType, op);
17221        }
17222      } else {
17223        this.#uiManager.updateParams(colorType, input.value);
17224      }
17225    }, {
17226      signal: this.#uiManager._signal
17227    });
17228    return input;
17229  }
17230  update(value) {
17231    if (!this.#input) {
17232      return;
17233    }
17234    if (this.#hasAlpha) {
17235      const alphaHex = Util.hexNums[Math.round(this.#editor.opacity * 255)];
17236      this.#input.value = value + alphaHex;
17237    } else {
17238      this.#input.value = value;
17239    }
17240  }
17241  updateOpacity(value) {
17242    if (!this.#input || !this.#hasAlpha) {
17243      return;
17244    }
17245    const alphaHex = Util.hexNums[Math.round(value * 255)];
17246    this.#input.value = this.#editor.color + alphaHex;
17247  }
17248  destroy() {
17249    this.#input?.remove();
17250    this.#input = null;
17251  }
17252  hideDropdown() {}
17253}
17254
17255;// ./src/shared/scripting_utils.js
17256
17257function makeColorComp(n) {
17258  return Math.floor(MathClamp(n, 0, 1) * 255).toString(16).padStart(2, "0");
17259}
17260function scaleAndClamp(x) {
17261  return MathClamp(x, 0, 1) * 255;
17262}
17263class ColorConverters {
17264  static CMYK_G([c, y, m, k]) {
17265    return ["G", 1 - Math.min(1, 0.3 * c + 0.59 * m + 0.11 * y + k)];
17266  }
17267  static G_CMYK([g]) {
17268    return ["CMYK", 0, 0, 0, 1 - g];
17269  }
17270  static G_RGB([g]) {
17271    return ["RGB", g, g, g];
17272  }
17273  static G_rgb([g]) {
17274    g = scaleAndClamp(g);
17275    return [g, g, g];
17276  }
17277  static G_HTML([g]) {
17278    const G = makeColorComp(g);
17279    return `#${G}${G}${G}`;
17280  }
17281  static RGB_G([r, g, b]) {
17282    return ["G", 0.3 * r + 0.59 * g + 0.11 * b];
17283  }
17284  static RGB_rgb(color) {
17285    return color.map(scaleAndClamp);
17286  }
17287  static RGB_HTML(color) {
17288    return `#${color.map(makeColorComp).join("")}`;
17289  }
17290  static T_HTML() {
17291    return "#00000000";
17292  }
17293  static T_rgb() {
17294    return [null];
17295  }
17296  static CMYK_RGB([c, y, m, k]) {
17297    return ["RGB", 1 - Math.min(1, c + k), 1 - Math.min(1, m + k), 1 - Math.min(1, y + k)];
17298  }
17299  static CMYK_rgb([c, y, m, k]) {
17300    return [scaleAndClamp(1 - Math.min(1, c + k)), scaleAndClamp(1 - Math.min(1, m + k)), scaleAndClamp(1 - Math.min(1, y + k))];
17301  }
17302  static CMYK_HTML(components) {
17303    const rgb = this.CMYK_RGB(components).slice(1);
17304    return this.RGB_HTML(rgb);
17305  }
17306  static RGB_CMYK([r, g, b]) {
17307    const c = 1 - r;
17308    const m = 1 - g;
17309    const y = 1 - b;
17310    const k = Math.min(c, m, y);
17311    return ["CMYK", c, m, y, k];
17312  }
17313}
17314const DateFormats = (/* unused pure expression or super */ null && (["m/d", "m/d/yy", "mm/dd/yy", "mm/yy", "d-mmm", "d-mmm-yy", "dd-mmm-yy", "yy-mm-dd", "mmm-yy", "mmmm-yy", "mmm d, yyyy", "mmmm d, yyyy", "m/d/yy h:MM tt", "m/d/yy HH:MM"]));
17315const TimeFormats = (/* unused pure expression or super */ null && (["HH:MM", "h:MM tt", "HH:MM:ss", "h:MM:ss tt"]));
17316
17317;// ./src/display/svg_factory.js
17318
17319class BaseSVGFactory {
17320  create(width, height, skipDimensions = false) {
17321    if (width <= 0 || height <= 0) {
17322      throw new Error("Invalid SVG dimensions");
17323    }
17324    const svg = this._createSVG("svg:svg");
17325    svg.setAttribute("version", "1.1");
17326    if (!skipDimensions) {
17327      svg.setAttribute("width", `${width}px`);
17328      svg.setAttribute("height", `${height}px`);
17329    }
17330    svg.setAttribute("preserveAspectRatio", "none");
17331    svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
17332    return svg;
17333  }
17334  createElement(type) {
17335    if (typeof type !== "string") {
17336      throw new Error("Invalid SVG element type");
17337    }
17338    return this._createSVG(type);
17339  }
17340  _createSVG(type) {
17341    unreachable("Abstract method `_createSVG` called.");
17342  }
17343}
17344class DOMSVGFactory extends BaseSVGFactory {
17345  _createSVG(type) {
17346    return document.createElementNS(SVG_NS, type);
17347  }
17348}
17349
17350;// ./src/display/annotation_layer.js
17351
17352
17353
17354
17355
17356const annotation_layer_DEFAULT_FONT_SIZE = 9;
17357const GetElementsByNameSet = new WeakSet();
17358const TIMEZONE_OFFSET = new Date().getTimezoneOffset() * 60 * 1000;
17359class AnnotationElementFactory {
17360  static create(parameters) {
17361    const subtype = parameters.data.annotationType;
17362    switch (subtype) {
17363      case AnnotationType.LINK:
17364        return new LinkAnnotationElement(parameters);
17365      case AnnotationType.TEXT:
17366        return new TextAnnotationElement(parameters);
17367      case AnnotationType.WIDGET:
17368        const fieldType = parameters.data.fieldType;
17369        switch (fieldType) {
17370          case "Tx":
17371            return new TextWidgetAnnotationElement(parameters);
17372          case "Btn":
17373            if (parameters.data.radioButton) {
17374              return new RadioButtonWidgetAnnotationElement(parameters);
17375            } else if (parameters.data.checkBox) {
17376              return new CheckboxWidgetAnnotationElement(parameters);
17377            }
17378            return new PushButtonWidgetAnnotationElement(parameters);
17379          case "Ch":
17380            return new ChoiceWidgetAnnotationElement(parameters);
17381          case "Sig":
17382            return new SignatureWidgetAnnotationElement(parameters);
17383        }
17384        return new WidgetAnnotationElement(parameters);
17385      case AnnotationType.POPUP:
17386        return new PopupAnnotationElement(parameters);
17387      case AnnotationType.FREETEXT:
17388        return new FreeTextAnnotationElement(parameters);
17389      case AnnotationType.LINE:
17390        return new LineAnnotationElement(parameters);
17391      case AnnotationType.SQUARE:
17392        return new SquareAnnotationElement(parameters);
17393      case AnnotationType.CIRCLE:
17394        return new CircleAnnotationElement(parameters);
17395      case AnnotationType.POLYLINE:
17396        return new PolylineAnnotationElement(parameters);
17397      case AnnotationType.CARET:
17398        return new CaretAnnotationElement(parameters);
17399      case AnnotationType.INK:
17400        return new InkAnnotationElement(parameters);
17401      case AnnotationType.POLYGON:
17402        return new PolygonAnnotationElement(parameters);
17403      case AnnotationType.HIGHLIGHT:
17404        return new HighlightAnnotationElement(parameters);
17405      case AnnotationType.UNDERLINE:
17406        return new UnderlineAnnotationElement(parameters);
17407      case AnnotationType.SQUIGGLY:
17408        return new SquigglyAnnotationElement(parameters);
17409      case AnnotationType.STRIKEOUT:
17410        return new StrikeOutAnnotationElement(parameters);
17411      case AnnotationType.STAMP:
17412        return new StampAnnotationElement(parameters);
17413      case AnnotationType.FILEATTACHMENT:
17414        return new FileAttachmentAnnotationElement(parameters);
17415      case AnnotationType.RICHMEDIA:
17416      case AnnotationType.SCREEN
vendor: 12,826 bytes, lines 17416-17873
17416:
17417        return new MediaAnnotationElement(parameters);
17418      default:
17419        return new AnnotationElement(parameters);
17420    }
17421  }
17422}
17423class AnnotationElement {
17424  #updates = null;
17425  #hasBorder = false;
17426  #popupElement = null;
17427  constructor(parameters, {
17428    isRenderable = false,
17429    ignoreBorder = false,
17430    createQuadrilaterals = false
17431  } = {}) {
17432    this.isRenderable = isRenderable;
17433    this.data = parameters.data;
17434    this.layer = parameters.layer;
17435    this.linkService = parameters.linkService;
17436    this.downloadManager = parameters.downloadManager;
17437    this.imageResourcesPath = parameters.imageResourcesPath;
17438    this.renderForms = parameters.renderForms;
17439    this.svgFactory = parameters.svgFactory;
17440    this.annotationStorage = parameters.annotationStorage;
17441    this.enableComment = parameters.enableComment;
17442    this.enableScripting = parameters.enableScripting;
17443    this.hasJSActions = parameters.hasJSActions;
17444    this._fieldObjects = parameters.fieldObjects;
17445    this.parent = parameters.parent;
17446    this.hasOwnCommentButton = false;
17447    if (isRenderable) {
17448      this.contentElement = this.container = this._createContainer(ignoreBorder);
17449    }
17450    if (createQuadrilaterals) {
17451      this._createQuadrilaterals();
17452    }
17453  }
17454  static _hasPopupData({
17455    contentsObj,
17456    richText
17457  }) {
17458    return !!(contentsObj?.str || richText?.str);
17459  }
17460  get _isEditable() {
17461    return this.data.isEditable;
17462  }
17463  get hasPopupData() {
17464    return AnnotationElement._hasPopupData(this.data) || this.enableComment && !!this.commentText;
17465  }
17466  get commentData() {
17467    const {
17468      data
17469    } = this;
17470    const editor = this.annotationStorage?.getEditor(data.id);
17471    if (editor) {
17472      return editor.getData();
17473    }
17474    return data;
17475  }
17476  get hasCommentButton() {
17477    return this.enableComment && this.hasPopupElement;
17478  }
17479  get commentButtonPosition() {
17480    const editor = this.annotationStorage?.getEditor(this.data.id);
17481    if (editor) {
17482      return editor.commentButtonPositionInPage;
17483    }
17484    const {
17485      quadPoints,
17486      inkLists,
17487      rect
17488    } = this.data;
17489    let maxX = -Infinity;
17490    let maxY = -Infinity;
17491    if (quadPoints?.length >= 8) {
17492      for (let i = 0; i < quadPoints.length; i += 8) {
17493        if (quadPoints[i + 1] > maxY) {
17494          maxY = quadPoints[i + 1];
17495          maxX = quadPoints[i + 2];
17496        } else if (quadPoints[i + 1] === maxY) {
17497          maxX = Math.max(maxX, quadPoints[i + 2]);
17498        }
17499      }
17500      return [maxX, maxY];
17501    }
17502    if (inkLists?.length >= 1) {
17503      for (const inkList of inkLists) {
17504        for (let i = 0, ii = inkList.length; i < ii; i += 2) {
17505          if (inkList[i + 1] > maxY) {
17506            maxY = inkList[i + 1];
17507            maxX = inkList[i];
17508          } else if (inkList[i + 1] === maxY) {
17509            maxX = Math.max(maxX, inkList[i]);
17510          }
17511        }
17512      }
17513      if (maxX !== Infinity) {
17514        return [maxX, maxY];
17515      }
17516    }
17517    if (rect) {
17518      return [rect[2], rect[3]];
17519    }
17520    return null;
17521  }
17522  _normalizePoint(point) {
17523    const {
17524      page: {
17525        view
17526      },
17527      viewport: {
17528        rawDims: {
17529          pageWidth,
17530          pageHeight,
17531          pageX,
17532          pageY
17533        }
17534      }
17535    } = this.parent;
17536    point[1] = view[3] - point[1] + view[1];
17537    point[0] = 100 * (point[0] - pageX) / pageWidth;
17538    point[1] = 100 * (point[1] - pageY) / pageHeight;
17539    return point;
17540  }
17541  get commentText() {
17542    const {
17543      data
17544    } = this;
17545    return this.annotationStorage.getRawValue(`${AnnotationEditorPrefix}${data.id}`)?.popup?.contents || data.contentsObj?.str || "";
17546  }
17547  set commentText(text) {
17548    const {
17549      data
17550    } = this;
17551    const popup = {
17552      deleted: !text,
17553      contents: text || ""
17554    };
17555    if (!this.annotationStorage.updateEditor(data.id, {
17556      popup
17557    })) {
17558      this.annotationStorage.setValue(`${AnnotationEditorPrefix}${data.id}`, {
17559        id: data.id,
17560        annotationType: data.annotationType,
17561        page: this.parent.page,
17562        popup,
17563        popupRef: data.popupRef,
17564        modificationDate: new Date()
17565      });
17566    }
17567    if (!text) {
17568      this.removePopup();
17569    }
17570  }
17571  removePopup() {
17572    (this.#popupElement?.popup || this.popup)?.remove();
17573    this.#popupElement = this.popup = null;
17574  }
17575  updateEdited(params) {
17576    if (!this.container) {
17577      return;
17578    }
17579    if (params.rect) {
17580      this.#updates ||= {
17581        rect: this.data.rect.slice(0)
17582      };
17583    }
17584    const {
17585      rect,
17586      popup: newPopup
17587    } = params;
17588    if (rect) {
17589      this.#setRectEdited(rect);
17590    }
17591    let popup = this.#popupElement?.popup || this.popup;
17592    if (!popup && newPopup?.text) {
17593      this._createPopup(newPopup);
17594      popup = this.#popupElement.popup;
17595    }
17596    if (!popup) {
17597      return;
17598    }
17599    popup.updateEdited(params);
17600    if (newPopup?.deleted) {
17601      popup.remove();
17602      this.#popupElement = null;
17603      this.popup = null;
17604    }
17605  }
17606  resetEdited() {
17607    if (!this.#updates) {
17608      return;
17609    }
17610    this.#setRectEdited(this.#updates.rect);
17611    this.#popupElement?.popup.resetEdited();
17612    this.#updates = null;
17613  }
17614  #setRectEdited(rect) {
17615    const {
17616      container: {
17617        style
17618      },
17619      data: {
17620        rect: currentRect,
17621        rotation
17622      },
17623      parent: {
17624        viewport: {
17625          rawDims: {
17626            pageWidth,
17627            pageHeight,
17628            pageX,
17629            pageY
17630          }
17631        }
17632      }
17633    } = this;
17634    currentRect?.splice(0, 4, ...rect);
17635    style.left = `${100 * (rect[0] - pageX) / pageWidth}%`;
17636    style.top = `${100 * (pageHeight - rect[3] + pageY) / pageHeight}%`;
17637    if (rotation === 0) {
17638      style.width = `${100 * (rect[2] - rect[0]) / pageWidth}%`;
17639      style.height = `${100 * (rect[3] - rect[1]) / pageHeight}%`;
17640    } else {
17641      this.setRotation(rotation);
17642    }
17643  }
17644  _createContainer(ignoreBorder) {
17645    const {
17646      data,
17647      parent: {
17648        page,
17649        viewport
17650      }
17651    } = this;
17652    const container = document.createElement("section");
17653    container.setAttribute("data-annotation-id", data.id);
17654    if (!(this instanceof WidgetAnnotationElement) && !(this instanceof LinkAnnotationElement) && !(this instanceof MediaAnnotationElement)) {
17655      container.tabIndex = 0;
17656    }
17657    const {
17658      style
17659    } = container;
17660    style.zIndex = this.parent.zIndex;
17661    this.parent.zIndex += 2;
17662    if (data.alternativeText) {
17663      container.title = data.alternativeText;
17664    }
17665    if (data.noRotate) {
17666      container.classList.add("norotate");
17667    }
17668    if (!data.rect || this instanceof PopupAnnotationElement) {
17669      const {
17670        rotation
17671      } = data;
17672      if (!data.hasOwnCanvas && rotation !== 0) {
17673        this.setRotation(rotation, container);
17674      }
17675      return container;
17676    }
17677    const {
17678      width,
17679      height
17680    } = this;
17681    if (!ignoreBorder && data.borderStyle.width > 0) {
17682      style.borderWidth = `${data.borderStyle.width}px`;
17683      const horizontalRadius = data.borderStyle.horizontalCornerRadius;
17684      const verticalRadius = data.borderStyle.verticalCornerRadius;
17685      if (horizontalRadius > 0 || verticalRadius > 0) {
17686        const radius = `calc(${horizontalRadius}px * var(--total-scale-factor)) / calc(${verticalRadius}px * var(--total-scale-factor))`;
17687        style.borderRadius = radius;
17688      }
17689      switch (data.borderStyle.style) {
17690        case AnnotationBorderStyleType.SOLID:
17691          style.borderStyle = "solid";
17692          break;
17693        case AnnotationBorderStyleType.DASHED:
17694          style.borderStyle = "dashed";
17695          break;
17696        case AnnotationBorderStyleType.BEVELED:
17697          warn("Unimplemented border style: beveled");
17698          break;
17699        case AnnotationBorderStyleType.INSET:
17700          warn("Unimplemented border style: inset");
17701          break;
17702        case AnnotationBorderStyleType.UNDERLINE:
17703          style.borderBottomStyle = "solid";
17704          break;
17705        default:
17706          break;
17707      }
17708      const borderColor = data.borderColor || null;
17709      if (borderColor) {
17710        this.#hasBorder = true;
17711        style.borderColor = Util.makeHexColor(...borderColor);
17712      } else {
17713        style.borderWidth = 0;
17714      }
17715    }
17716    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]]);
17717    const {
17718      pageWidth,
17719      pageHeight,
17720      pageX,
17721      pageY
17722    } = viewport.rawDims;
17723    style.left = `${100 * (rect[0] - pageX) / pageWidth}%`;
17724    style.top = `${100 * (rect[1] - pageY) / pageHeight}%`;
17725    const {
17726      rotation
17727    } = data;
17728    if (data.hasOwnCanvas || rotation === 0) {
17729      style.width = `${100 * width / pageWidth}%`;
17730      style.height = `${100 * height / pageHeight}%`;
17731    } else {
17732      this.setRotation(rotation, container);
17733    }
17734    return container;
17735  }
17736  setRotation(angle, container = this.container) {
17737    if (!this.data.rect) {
17738      return;
17739    }
17740    const {
17741      pageWidth,
17742      pageHeight
17743    } = this.parent.viewport.rawDims;
17744    let {
17745      width,
17746      height
17747    } = this;
17748    if (angle % 180 !== 0) {
17749      [width, height] = [height, width];
17750    }
17751    container.style.width = `${100 * width / pageWidth}%`;
17752    container.style.height = `${100 * height / pageHeight}%`;
17753    container.setAttribute("data-main-rotation", (360 - angle) % 360);
17754  }
17755  get _commonActions() {
17756    const setColor = (jsName, styleName, event) => {
17757      const color = event.detail[jsName];
17758      const colorType = color[0];
17759      const colorArray = color.slice(1);
17760      event.target.style[styleName] = ColorConverters[`${colorType}_HTML`](colorArray);
17761      this.annotationStorage.setValue(this.data.id, {
17762        [styleName]: ColorConverters[`${colorType}_rgb`](colorArray)
17763      });
17764    };
17765    return shadow(this, "_commonActions", {
17766      display: event => {
17767        const {
17768          display
17769        } = event.detail;
17770        const hidden = display % 2 === 1;
17771        this.container.style.visibility = hidden ? "hidden" : "visible";
17772        this.annotationStorage.setValue(this.data.id, {
17773          noView: hidden,
17774          noPrint: display === 1 || display === 2
17775        });
17776      },
17777      print: event => {
17778        this.annotationStorage.setValue(this.data.id, {
17779          noPrint: !event.detail.print
17780        });
17781      },
17782      hidden: event => {
17783        const {
17784          hidden
17785        } = event.detail;
17786        this.container.style.visibility = hidden ? "hidden" : "visible";
17787        this.annotationStorage.setValue(this.data.id, {
17788          noPrint: hidden,
17789          noView: hidden
17790        });
17791      },
17792      focus: event => {
17793        setTimeout(() => event.target.focus({
17794          preventScroll: false
17795        }), 0);
17796      },
17797      userName: event => {
17798        event.target.title = event.detail.userName;
17799      },
17800      readonly: event => {
17801        event.target.disabled = event.detail.readonly;
17802      },
17803      required: event => {
17804        this._setRequired(event.target, event.detail.required);
17805      },
17806      bgColor: event => {
17807        setColor("bgColor", "backgroundColor", event);
17808      },
17809      fillColor: event => {
17810        setColor("fillColor", "backgroundColor", event);
17811      },
17812      fgColor: event => {
17813        setColor("fgColor", "color", event);
17814      },
17815      textColor: event => {
17816        setColor("textColor", "color", event);
17817      },
17818      borderColor: event => {
17819        setColor("borderColor", "borderColor", event);
17820      },
17821      strokeColor: event => {
17822        setColor("strokeColor", "borderColor", event);
17823      },
17824      rotation: event => {
17825        const angle = event.detail.rotation;
17826        this.setRotation(angle);
17827        this.annotationStorage.setValue(this.data.id, {
17828          rotation: angle
17829        });
17830      }
17831    });
17832  }
17833  _dispatchEventFromSandbox(actions, jsEvent) {
17834    const commonActions = this._commonActions;
17835    for (const name of Object.keys(jsEvent.detail)) {
17836      const action = actions[name] || commonActions[name];
17837      action?.(jsEvent);
17838    }
17839  }
17840  _setDefaultPropertiesFromJS(element) {
17841    if (!this.enableScripting) {
17842      return;
17843    }
17844    const storedData = this.annotationStorage.getRawValue(this.data.id);
17845    if (!storedData) {
17846      return;
17847    }
17848    const commonActions = this._commonActions;
17849    for (const [actionName, detail] of Object.entries(storedData)) {
17850      const action = commonActions[actionName];
17851      if (action) {
17852        const eventProxy = {
17853          detail: {
17854            [actionName]: detail
17855          },
17856          target: element
17857        };
17858        action(eventProxy);
17859        delete storedData[actionName];
17860      }
17861    }
17862  }
17863  _createQuadrilaterals() {
17864    if (!this.container) {
17865      return;
17866    }
17867    const {
17868      quadPoints
17869    } = this.data;
17870    if (!quadPoints) {
17871      return;
17872    }
17873    const [rectBlX, rectBlY, rectTrX, rectTrY] = this.data.rect.map(
vendor: 29,427 bytes, lines 17873-18804
17873x => Math.fround(x));
17874    if (quadPoints.length === 8) {
17875      const [trX, trY, blX, blY] = quadPoints.subarray(2, 6);
17876      if (rectTrX === trX && rectTrY === trY && rectBlX === blX && rectBlY === blY) {
17877        return;
17878      }
17879    }
17880    const {
17881      style
17882    } = this.container;
17883    let svgBuffer;
17884    if (this.#hasBorder) {
17885      const {
17886        borderColor,
17887        borderWidth
17888      } = style;
17889      style.borderWidth = 0;
17890      svgBuffer = ["url('data:image/svg+xml;utf8,", `<svg xmlns="${SVG_NS}" preserveAspectRatio="none" viewBox="0 0 1 1">`, `<g fill="transparent" stroke="${borderColor}" stroke-width="${borderWidth}">`];
17891      this.container.classList.add("hasBorder");
17892    }
17893    const width = rectTrX - rectBlX;
17894    const height = rectTrY - rectBlY;
17895    const {
17896      svgFactory
17897    } = this;
17898    const svg = svgFactory.createElement("svg");
17899    svg.classList.add("quadrilateralsContainer");
17900    svg.setAttribute("width", 0);
17901    svg.setAttribute("height", 0);
17902    svg.role = "none";
17903    const defs = svgFactory.createElement("defs");
17904    svg.append(defs);
17905    const clipPath = svgFactory.createElement("clipPath");
17906    const id = `clippath_${this.data.id}`;
17907    clipPath.setAttribute("id", id);
17908    clipPath.setAttribute("clipPathUnits", "objectBoundingBox");
17909    defs.append(clipPath);
17910    for (let i = 2, ii = quadPoints.length; i < ii; i += 8) {
17911      const trX = quadPoints[i];
17912      const trY = quadPoints[i + 1];
17913      const blX = quadPoints[i + 2];
17914      const blY = quadPoints[i + 3];
17915      const rect = svgFactory.createElement("rect");
17916      const x = (blX - rectBlX) / width;
17917      const y = (rectTrY - trY) / height;
17918      const rectWidth = (trX - blX) / width;
17919      const rectHeight = (trY - blY) / height;
17920      rect.setAttribute("x", x);
17921      rect.setAttribute("y", y);
17922      rect.setAttribute("width", rectWidth);
17923      rect.setAttribute("height", rectHeight);
17924      clipPath.append(rect);
17925      svgBuffer?.push(`<rect vector-effect="non-scaling-stroke" x="${x}" y="${y}" width="${rectWidth}" height="${rectHeight}"/>`);
17926    }
17927    if (this.#hasBorder) {
17928      svgBuffer.push(`</g></svg>')`);
17929      style.backgroundImage = svgBuffer.join("");
17930    }
17931    this.container.append(svg);
17932    this.container.style.clipPath = `url(#${id})`;
17933  }
17934  _createPopup(popupData = null) {
17935    const {
17936      data
17937    } = this;
17938    let contentsObj, modificationDate;
17939    if (popupData) {
17940      contentsObj = {
17941        str: popupData.text
17942      };
17943      modificationDate = popupData.date;
17944    } else {
17945      contentsObj = data.contentsObj;
17946      modificationDate = data.modificationDate;
17947    }
17948    this.#popupElement = new PopupAnnotationElement({
17949      data: {
17950        color: data.color,
17951        titleObj: data.titleObj,
17952        modificationDate,
17953        contentsObj,
17954        richText: data.richText,
17955        parentRect: data.rect,
17956        borderStyle: 0,
17957        id: `popup_${data.id}`,
17958        rotation: data.rotation,
17959        noRotate: true
17960      },
17961      linkService: this.linkService,
17962      parent: this.parent,
17963      elements: [this]
17964    });
17965  }
17966  get hasPopupElement() {
17967    return !!(this.#popupElement || this.popup || this.data.popupRef);
17968  }
17969  get extraPopupElement() {
17970    return this.#popupElement;
17971  }
17972  render() {
17973    unreachable("Abstract method `AnnotationElement.render` called");
17974  }
17975  _getElementsByName(name, skipId = null) {
17976    const fields = [];
17977    if (this._fieldObjects) {
17978      const fieldObj = this._fieldObjects[name];
17979      if (fieldObj) {
17980        for (const {
17981          page,
17982          id,
17983          exportValues
17984        } of fieldObj) {
17985          if (page === -1) {
17986            continue;
17987          }
17988          if (id === skipId) {
17989            continue;
17990          }
17991          const exportValue = typeof exportValues === "string" ? exportValues : null;
17992          const domElement = document.querySelector(`[data-element-id="${id}"]`);
17993          if (domElement && !GetElementsByNameSet.has(domElement)) {
17994            warn(`_getElementsByName - element not allowed: ${id}`);
17995            continue;
17996          }
17997          fields.push({
17998            id,
17999            exportValue,
18000            domElement
18001          });
18002        }
18003      }
18004      return fields;
18005    }
18006    for (const domElement of document.getElementsByName(name)) {
18007      const {
18008        exportValue
18009      } = domElement;
18010      const id = domElement.getAttribute("data-element-id");
18011      if (id === skipId) {
18012        continue;
18013      }
18014      if (!GetElementsByNameSet.has(domElement)) {
18015        continue;
18016      }
18017      fields.push({
18018        id,
18019        exportValue,
18020        domElement
18021      });
18022    }
18023    return fields;
18024  }
18025  show() {
18026    if (this.container) {
18027      this.container.hidden = false;
18028    }
18029    this.popup?.maybeShow();
18030  }
18031  hide() {
18032    if (this.container) {
18033      this.container.hidden = true;
18034    }
18035    this.popup?.forceHide();
18036  }
18037  getElementsToTriggerPopup() {
18038    return this.container;
18039  }
18040  addHighlightArea() {
18041    const triggers = this.getElementsToTriggerPopup();
18042    if (Array.isArray(triggers)) {
18043      for (const element of triggers) {
18044        element.classList.add("highlightArea");
18045      }
18046    } else {
18047      triggers.classList.add("highlightArea");
18048    }
18049  }
18050  _editOnDoubleClick() {
18051    if (!this._isEditable) {
18052      return;
18053    }
18054    const {
18055      annotationEditorType: mode,
18056      data: {
18057        id: editId
18058      }
18059    } = this;
18060    this.container.addEventListener("dblclick", () => {
18061      this.linkService.eventBus?.dispatch("switchannotationeditormode", {
18062        source: this,
18063        mode,
18064        editId,
18065        mustEnterInEditMode: true
18066      });
18067    });
18068  }
18069  updateOC(optionalContentConfig) {
18070    if (!this.data.oc || !optionalContentConfig) {
18071      return;
18072    }
18073    const isVisible = optionalContentConfig.isVisible(this.data.oc);
18074    if (isVisible) {
18075      this.show();
18076    } else {
18077      this.hide();
18078    }
18079  }
18080  get width() {
18081    return this.data.rect[2] - this.data.rect[0];
18082  }
18083  get height() {
18084    return this.data.rect[3] - this.data.rect[1];
18085  }
18086  _setBackgroundColor(element) {
18087    const color = this.data.backgroundColor || null;
18088    element.style.backgroundColor = color === null ? "transparent" : Util.makeHexColor(...color);
18089  }
18090}
18091class EditorAnnotationElement extends AnnotationElement {
18092  constructor(parameters) {
18093    super(parameters, {
18094      isRenderable: true,
18095      ignoreBorder: true
18096    });
18097    this.editor = parameters.editor;
18098  }
18099  render() {
18100    this.container.className = "editorAnnotation";
18101    return this.container;
18102  }
18103  createOrUpdatePopup() {
18104    const {
18105      editor
18106    } = this;
18107    if (!editor.hasComment) {
18108      return;
18109    }
18110    this._createPopup(editor.comment);
18111  }
18112  get hasCommentButton() {
18113    return this.enableComment && this.editor.hasComment;
18114  }
18115  get commentButtonPosition() {
18116    return this.editor.commentButtonPositionInPage;
18117  }
18118  get commentText() {
18119    return this.editor.comment.text;
18120  }
18121  set commentText(text) {
18122    this.editor.comment = text;
18123    if (!text) {
18124      this.removePopup();
18125    }
18126  }
18127  get commentData() {
18128    return this.editor.getData();
18129  }
18130  remove() {
18131    this.parent.removeAnnotation(this.data.id);
18132    this.container.remove();
18133    this.container = null;
18134    this.removePopup();
18135  }
18136}
18137class LinkAnnotationElement extends AnnotationElement {
18138  constructor(parameters, options = null) {
18139    super(parameters, {
18140      isRenderable: true,
18141      ignoreBorder: !!options?.ignoreBorder,
18142      createQuadrilaterals: true
18143    });
18144    this.isTooltipOnly = parameters.data.isTooltipOnly;
18145  }
18146  render() {
18147    const {
18148      data,
18149      linkService
18150    } = this;
18151    const link = document.createElement("a");
18152    link.setAttribute("data-element-id", data.id);
18153    let isBound = false;
18154    if (data.url) {
18155      linkService.addLinkAttributes(link, data.url, data.newWindow);
18156      isBound = true;
18157    } else if (data.action) {
18158      this._bindNamedAction(link, data.action, data.overlaidText);
18159      isBound = true;
18160    } else if (data.attachment) {
18161      this.#bindAttachment(link, data.attachmentId, data.attachment, data.overlaidText, data.attachmentDest);
18162      isBound = true;
18163    } else if (data.setOCGState) {
18164      this.#bindSetOCGState(link, data.setOCGState, data.overlaidText);
18165      isBound = true;
18166    } else if (data.dest) {
18167      this._bindLink(link, data.dest, data.overlaidText);
18168      isBound = true;
18169    } else {
18170      if (data.actions && (data.actions.Action || data.actions["Mouse Up"] || data.actions["Mouse Down"]) && this.enableScripting && this.hasJSActions) {
18171        this._bindJSAction(link, data);
18172        isBound = true;
18173      }
18174      if (data.resetForm) {
18175        this._bindResetFormAction(link, data.resetForm);
18176        isBound = true;
18177      } else if (this.isTooltipOnly && !isBound) {
18178        this._bindLink(link, "");
18179        isBound = true;
18180      }
18181    }
18182    this.container.classList.add("linkAnnotation");
18183    if (isBound) {
18184      this.contentElement = link;
18185      this.container.append(link);
18186    }
18187    return this.container;
18188  }
18189  #setInternalLink() {
18190    this.container.setAttribute("data-internal-link", "");
18191  }
18192  _bindLink(link, destination, overlaidText = "") {
18193    link.href = this.linkService.getDestinationHash(destination);
18194    link.onclick = () => {
18195      if (destination) {
18196        this.linkService.goToDestination(destination);
18197      }
18198      return false;
18199    };
18200    if (destination || destination === "") {
18201      this.#setInternalLink();
18202    }
18203    if (overlaidText) {
18204      link.title = overlaidText;
18205    }
18206  }
18207  _bindNamedAction(link, action, overlaidText = "") {
18208    link.href = this.linkService.getAnchorUrl("");
18209    link.onclick = () => {
18210      this.linkService.executeNamedAction(action);
18211      return false;
18212    };
18213    if (overlaidText) {
18214      link.title = overlaidText;
18215    }
18216    this.#setInternalLink();
18217  }
18218  #bindAttachment(link, attachmentId, attachment, overlaidText = "", dest = null) {
18219    link.href = this.linkService.getAnchorUrl("");
18220    if (attachment.description) {
18221      link.title = attachment.description;
18222    } else if (overlaidText) {
18223      link.title = overlaidText;
18224    }
18225    const openAttachment = async () => {
18226      const content = await this.linkService.getAttachmentContent(attachmentId);
18227      if (content) {
18228        this.downloadManager?.openOrDownloadData(content, attachment.filename, dest);
18229      }
18230    };
18231    link.onclick = () => {
18232      openAttachment();
18233      return false;
18234    };
18235    this.#setInternalLink();
18236  }
18237  #bindSetOCGState(link, action, overlaidText = "") {
18238    link.href = this.linkService.getAnchorUrl("");
18239    link.onclick = () => {
18240      this.linkService.executeSetOCGState(action);
18241      return false;
18242    };
18243    if (overlaidText) {
18244      link.title = overlaidText;
18245    }
18246    this.#setInternalLink();
18247  }
18248  _bindJSAction(link, data) {
18249    link.href = this.linkService.getAnchorUrl("");
18250    const map = new Map([["Action", "onclick"], ["Mouse Up", "onmouseup"], ["Mouse Down", "onmousedown"]]);
18251    for (const name of Object.keys(data.actions)) {
18252      const jsName = map.get(name);
18253      if (!jsName) {
18254        continue;
18255      }
18256      link[jsName] = () => {
18257        this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
18258          source: this,
18259          detail: {
18260            id: data.id,
18261            name
18262          }
18263        });
18264        return false;
18265      };
18266    }
18267    if (data.overlaidText) {
18268      link.title = data.overlaidText;
18269    }
18270    if (!link.onclick) {
18271      link.onclick = () => false;
18272    }
18273    this.#setInternalLink();
18274  }
18275  _bindResetFormAction(link, resetForm) {
18276    const otherClickAction = link.onclick;
18277    if (!otherClickAction) {
18278      link.href = this.linkService.getAnchorUrl("");
18279    }
18280    this.#setInternalLink();
18281    if (!this._fieldObjects) {
18282      warn(`_bindResetFormAction - "resetForm" action not supported, ` + "ensure that the `fieldObjects` parameter is provided.");
18283      if (!otherClickAction) {
18284        link.onclick = () => false;
18285      }
18286      return;
18287    }
18288    link.onclick = () => {
18289      otherClickAction?.();
18290      const {
18291        fields: resetFormFields,
18292        refs: resetFormRefs,
18293        include
18294      } = resetForm;
18295      const allFields = [];
18296      if (resetFormFields.length !== 0 || resetFormRefs.length !== 0) {
18297        const fieldIds = new Set(resetFormRefs);
18298        for (const fieldName of resetFormFields) {
18299          const fields = this._fieldObjects[fieldName] || [];
18300          for (const {
18301            id
18302          } of fields) {
18303            fieldIds.add(id);
18304          }
18305        }
18306        for (const fields of Object.values(this._fieldObjects)) {
18307          for (const field of fields) {
18308            if (fieldIds.has(field.id) === include) {
18309              allFields.push(field);
18310            }
18311          }
18312        }
18313      } else {
18314        for (const fields of Object.values(this._fieldObjects)) {
18315          allFields.push(...fields);
18316        }
18317      }
18318      const storage = this.annotationStorage;
18319      const allIds = [];
18320      for (const field of allFields) {
18321        const {
18322          id
18323        } = field;
18324        allIds.push(id);
18325        switch (field.type) {
18326          case "text":
18327            {
18328              const value = field.defaultValue || "";
18329              storage.setValue(id, {
18330                value
18331              });
18332              break;
18333            }
18334          case "checkbox":
18335          case "radiobutton":
18336            {
18337              const value = field.defaultValue === field.exportValues;
18338              storage.setValue(id, {
18339                value
18340              });
18341              break;
18342            }
18343          case "combobox":
18344          case "listbox":
18345            {
18346              const value = field.defaultValue || "";
18347              storage.setValue(id, {
18348                value
18349              });
18350              break;
18351            }
18352          default:
18353            continue;
18354        }
18355        const domElement = document.querySelector(`[data-element-id="${id}"]`);
18356        if (!domElement) {
18357          continue;
18358        } else if (!GetElementsByNameSet.has(domElement)) {
18359          warn(`_bindResetFormAction - element not allowed: ${id}`);
18360          continue;
18361        }
18362        domElement.dispatchEvent(new Event("resetform"));
18363      }
18364      if (this.enableScripting) {
18365        this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
18366          source: this,
18367          detail: {
18368            id: "app",
18369            ids: allIds,
18370            name: "ResetForm"
18371          }
18372        });
18373      }
18374      return false;
18375    };
18376  }
18377}
18378class TextAnnotationElement extends AnnotationElement {
18379  constructor(parameters) {
18380    super(parameters, {
18381      isRenderable: true
18382    });
18383  }
18384  render() {
18385    this.container.classList.add("textAnnotation");
18386    const image = document.createElement("img");
18387    image.src = this.imageResourcesPath + "annotation-" + this.data.name.toLowerCase() + ".svg";
18388    image.setAttribute("data-l10n-id", "pdfjs-text-annotation-type");
18389    image.setAttribute("data-l10n-args", JSON.stringify({
18390      type: this.data.name
18391    }));
18392    if (!this.data.popupRef && this.hasPopupData) {
18393      this.hasOwnCommentButton = true;
18394      this._createPopup();
18395    }
18396    this.container.append(image);
18397    return this.container;
18398  }
18399}
18400class WidgetAnnotationElement extends AnnotationElement {
18401  render() {
18402    return this.container;
18403  }
18404  _getKeyModifier(event) {
18405    return FeatureTest.platform.isMac ? event.metaKey : event.ctrlKey;
18406  }
18407  _setEventListener(element, elementData, baseName, eventName, valueGetter) {
18408    if (baseName.includes("mouse")) {
18409      element.addEventListener(baseName, event => {
18410        this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
18411          source: this,
18412          detail: {
18413            id: this.data.id,
18414            name: eventName,
18415            value: valueGetter(event),
18416            shift: event.shiftKey,
18417            modifier: this._getKeyModifier(event)
18418          }
18419        });
18420      });
18421    } else {
18422      element.addEventListener(baseName, event => {
18423        if (baseName === "blur") {
18424          if (!elementData.focused || !event.relatedTarget) {
18425            return;
18426          }
18427          elementData.focused = false;
18428        } else if (baseName === "focus") {
18429          if (elementData.focused) {
18430            return;
18431          }
18432          elementData.focused = true;
18433        }
18434        if (!valueGetter) {
18435          return;
18436        }
18437        this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
18438          source: this,
18439          detail: {
18440            id: this.data.id,
18441            name: eventName,
18442            value: valueGetter(event)
18443          }
18444        });
18445      });
18446    }
18447  }
18448  _setEventListeners(element, elementData, names, getter) {
18449    for (const [baseName, eventName] of names) {
18450      if (eventName === "Action" || this.data.actions?.[eventName]) {
18451        if (eventName === "Focus" || eventName === "Blur") {
18452          elementData ||= {
18453            focused: false
18454          };
18455        }
18456        this._setEventListener(element, elementData, baseName, eventName, getter);
18457        if (eventName === "Focus" && !this.data.actions?.Blur) {
18458          this._setEventListener(element, elementData, "blur", "Blur", null);
18459        } else if (eventName === "Blur" && !this.data.actions?.Focus) {
18460          this._setEventListener(element, elementData, "focus", "Focus", null);
18461        }
18462      }
18463    }
18464  }
18465  _setTextStyle(element) {
18466    const TEXT_ALIGNMENT = ["left", "center", "right"];
18467    const {
18468      fontColor
18469    } = this.data.defaultAppearanceData;
18470    const fontSize = this.data.defaultAppearanceData.fontSize || annotation_layer_DEFAULT_FONT_SIZE;
18471    const style = element.style;
18472    let computedFontSize;
18473    const BORDER_SIZE = 2;
18474    const roundToOneDecimal = x => Math.round(10 * x) / 10;
18475    if (this.data.multiLine) {
18476      const height = Math.abs(this.data.rect[3] - this.data.rect[1] - BORDER_SIZE);
18477      const numberOfLines = Math.round(height / (LINE_FACTOR * fontSize)) || 1;
18478      const lineHeight = height / numberOfLines;
18479      computedFontSize = Math.min(fontSize, roundToOneDecimal(lineHeight / LINE_FACTOR));
18480    } else {
18481      const height = Math.abs(this.data.rect[3] - this.data.rect[1] - BORDER_SIZE);
18482      computedFontSize = Math.min(fontSize, roundToOneDecimal(height / LINE_FACTOR));
18483    }
18484    style.fontSize = `calc(${computedFontSize}px * var(--total-scale-factor))`;
18485    style.color = Util.makeHexColor(...fontColor);
18486    if (this.data.textAlignment !== null && !this.data.comb) {
18487      style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment];
18488    }
18489  }
18490  _setRequired(element, isRequired) {
18491    if (isRequired) {
18492      element.setAttribute("required", true);
18493    } else {
18494      element.removeAttribute("required");
18495    }
18496    element.setAttribute("aria-required", isRequired);
18497  }
18498}
18499class TextWidgetAnnotationElement extends WidgetAnnotationElement {
18500  constructor(parameters) {
18501    const isRenderable = parameters.renderForms || parameters.data.hasOwnCanvas || !parameters.data.hasAppearance && !!parameters.data.fieldValue;
18502    super(parameters, {
18503      isRenderable
18504    });
18505  }
18506  setPropertyOnSiblings(base, key, value, keyInStorage) {
18507    const storage = this.annotationStorage;
18508    for (const element of this._getElementsByName(base.name, base.id)) {
18509      if (element.domElement) {
18510        element.domElement[key] = value;
18511      }
18512      storage.setValue(element.id, {
18513        [keyInStorage]: value
18514      });
18515    }
18516  }
18517  render() {
18518    const storage = this.annotationStorage;
18519    const id = this.data.id;
18520    this.container.classList.add("textWidgetAnnotation");
18521    let element = null;
18522    if (this.renderForms) {
18523      const storedData = storage.getValue(id, {
18524        value: this.data.fieldValue
18525      });
18526      let textContent = storedData.value || "";
18527      const maxLen = storage.getValue(id, {
18528        charLimit: this.data.maxLen
18529      }).charLimit;
18530      if (maxLen && textContent.length > maxLen) {
18531        textContent = textContent.slice(0, maxLen);
18532      }
18533      let fieldFormattedValues = storedData.formattedValue || this.data.textContent?.join("\n") || null;
18534      if (fieldFormattedValues && this.data.comb) {
18535        fieldFormattedValues = fieldFormattedValues.replaceAll(/\s+/g, "");
18536      }
18537      const elementData = {
18538        userValue: textContent,
18539        formattedValue: fieldFormattedValues,
18540        lastCommittedValue: null,
18541        commitKey: 1,
18542        focused: false
18543      };
18544      if (this.data.multiLine) {
18545        element = document.createElement("textarea");
18546        element.textContent = fieldFormattedValues ?? textContent;
18547        if (this.data.doNotScroll) {
18548          element.style.overflowY = "hidden";
18549        }
18550      } else {
18551        element = document.createElement("input");
18552        element.type = this.data.password ? "password" : "text";
18553        element.setAttribute("value", fieldFormattedValues ?? textContent);
18554        if (this.data.doNotScroll) {
18555          element.style.overflowX = "hidden";
18556        }
18557      }
18558      if (this.data.hasOwnCanvas) {
18559        this.container.classList.add("hasOwnCanvas");
18560        if (storage.has(id)) {
18561          this.container.classList.add("sandboxModified");
18562        }
18563      }
18564      GetElementsByNameSet.add(element);
18565      this.contentElement = element;
18566      element.setAttribute("data-element-id", id);
18567      element.disabled = this.data.readOnly;
18568      element.name = this.data.fieldName;
18569      element.tabIndex = 0;
18570      const {
18571        datetimeFormat,
18572        datetimeType,
18573        timeStep
18574      } = this.data;
18575      const hasDateOrTime = !!datetimeType && this.enableScripting;
18576      if (datetimeFormat) {
18577        element.title = datetimeFormat;
18578      }
18579      this._setRequired(element, this.data.required);
18580      if (maxLen) {
18581        element.maxLength = maxLen;
18582      }
18583      element.addEventListener("input", event => {
18584        storage.setValue(id, {
18585          value: event.target.value
18586        });
18587        this.setPropertyOnSiblings(element, "value", event.target.value, "value");
18588        elementData.formattedValue = null;
18589      });
18590      element.addEventListener("resetform", event => {
18591        const defaultValue = this.data.defaultFieldValue ?? "";
18592        element.value = elementData.userValue = defaultValue;
18593        elementData.formattedValue = null;
18594      });
18595      let blurListener = event => {
18596        const {
18597          formattedValue
18598        } = elementData;
18599        if (formattedValue !== null && formattedValue !== undefined) {
18600          event.target.value = formattedValue;
18601        }
18602        event.target.scrollLeft = 0;
18603      };
18604      if (this.enableScripting && this.hasJSActions) {
18605        element.addEventListener("focus", event => {
18606          if (elementData.focused) {
18607            return;
18608          }
18609          const {
18610            target
18611          } = event;
18612          if (hasDateOrTime) {
18613            target.type = datetimeType;
18614            if (timeStep) {
18615              target.step = timeStep;
18616            }
18617          }
18618          if (elementData.userValue) {
18619            const value = elementData.userValue;
18620            if (hasDateOrTime) {
18621              if (datetimeType === "time") {
18622                const date = new Date(value);
18623                const parts = [date.getHours(), date.getMinutes(), date.getSeconds()];
18624                target.value = parts.map(v => v.toString().padStart(2, "0")).join(":");
18625              } else {
18626                target.value = new Date(value - TIMEZONE_OFFSET).toISOString().split(datetimeType === "date" ? "T" : ".", 1)[0];
18627              }
18628            } else {
18629              target.value = value;
18630            }
18631          }
18632          elementData.lastCommittedValue = target.value;
18633          elementData.commitKey = 1;
18634          if (!this.data.actions?.Focus) {
18635            elementData.focused = true;
18636          }
18637        });
18638        element.addEventListener("updatefromsandbox", jsEvent => {
18639          this.container.classList.add("sandboxModified");
18640          const actions = {
18641            value(event) {
18642              elementData.userValue = event.detail.value ?? "";
18643              if (!hasDateOrTime) {
18644                storage.setValue(id, {
18645                  value: elementData.userValue.toString()
18646                });
18647              }
18648              event.target.value = elementData.userValue;
18649            },
18650            formattedValue(event) {
18651              const {
18652                formattedValue
18653              } = event.detail;
18654              elementData.formattedValue = formattedValue;
18655              if (formattedValue !== null && formattedValue !== undefined && event.target !== document.activeElement) {
18656                event.target.value = formattedValue;
18657              }
18658              const data = {
18659                formattedValue
18660              };
18661              if (hasDateOrTime) {
18662                data.value = formattedValue;
18663              }
18664              storage.setValue(id, data);
18665            },
18666            selRange(event) {
18667              event.target.setSelectionRange(...event.detail.selRange);
18668            },
18669            charLimit: event => {
18670              const {
18671                charLimit
18672              } = event.detail;
18673              const {
18674                target
18675              } = event;
18676              if (charLimit === 0) {
18677                target.removeAttribute("maxLength");
18678                return;
18679              }
18680              target.setAttribute("maxLength", charLimit);
18681              let value = elementData.userValue;
18682              if (!value || value.length <= charLimit) {
18683                return;
18684              }
18685              value = value.slice(0, charLimit);
18686              target.value = elementData.userValue = value;
18687              storage.setValue(id, {
18688                value
18689              });
18690              this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
18691                source: this,
18692                detail: {
18693                  id,
18694                  name: "Keystroke",
18695                  value,
18696                  willCommit: true,
18697                  commitKey: 1,
18698                  selStart: target.selectionStart,
18699                  selEnd: target.selectionEnd
18700                }
18701              });
18702            }
18703          };
18704          this._dispatchEventFromSandbox(actions, jsEvent);
18705        });
18706        element.addEventListener("keydown", event => {
18707          elementData.commitKey = 1;
18708          let commitKey = -1;
18709          if (event.key === "Escape") {
18710            commitKey = 0;
18711          } else if (event.key === "Enter" && !this.data.multiLine) {
18712            commitKey = 2;
18713          } else if (event.key === "Tab") {
18714            elementData.commitKey = 3;
18715          }
18716          if (commitKey === -1) {
18717            return;
18718          }
18719          const {
18720            value
18721          } = event.target;
18722          if (elementData.lastCommittedValue === value) {
18723            return;
18724          }
18725          elementData.lastCommittedValue = value;
18726          elementData.userValue = value;
18727          this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
18728            source: this,
18729            detail: {
18730              id,
18731              name: "Keystroke",
18732              value,
18733              willCommit: true,
18734              commitKey,
18735              selStart: event.target.selectionStart,
18736              selEnd: event.target.selectionEnd
18737            }
18738          });
18739        });
18740        const _blurListener = blurListener;
18741        blurListener = null;
18742        element.addEventListener("blur", event => {
18743          if (!elementData.focused || !event.relatedTarget) {
18744            return;
18745          }
18746          if (!this.data.actions?.Blur) {
18747            elementData.focused = false;
18748          }
18749          const {
18750            target
18751          } = event;
18752          let {
18753            value
18754          } = target;
18755          if (hasDateOrTime) {
18756            if (value && datetimeType === "time") {
18757              const parts = value.split(":").map(v => parseInt(v, 10));
18758              value = new Date(2000, 0, 1, parts[0], parts[1], parts[2] || 0).valueOf();
18759              target.step = "";
18760            } else {
18761              if (!value.includes("T")) {
18762                value = `${value}T00:00`;
18763              }
18764              value = new Date(value).valueOf();
18765            }
18766            target.type = "text";
18767          }
18768          elementData.userValue = value;
18769          if (elementData.lastCommittedValue !== value) {
18770            this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
18771              source: this,
18772              detail: {
18773                id,
18774                name: "Keystroke",
18775                value,
18776                willCommit: true,
18777                commitKey: elementData.commitKey,
18778                selStart: event.target.selectionStart,
18779                selEnd: event.target.selectionEnd
18780              }
18781            });
18782          }
18783          _blurListener(event);
18784        });
18785        if (this.data.actions?.Keystroke) {
18786          element.addEventListener("beforeinput", event => {
18787            elementData.lastCommittedValue = null;
18788            const {
18789              data,
18790              target
18791            } = event;
18792            const {
18793              value,
18794              selectionStart,
18795              selectionEnd
18796            } = target;
18797            let selStart = selectionStart,
18798              selEnd = selectionEnd;
18799            switch (event.inputType) {
18800              case "deleteWordBackward":
18801                {
18802                  const match = value.substring(0, selectionStart).match(/\w*\W*$/);
18803                  if (match) {
18804                    selStart -= match[0].length
vendor: 34,318 bytes, lines 18804-19902
18804;
18805                  }
18806                  break;
18807                }
18808              case "deleteWordForward":
18809                {
18810                  const match = value.substring(selectionStart).match(/^\W*\w*/);
18811                  if (match) {
18812                    selEnd += match[0].length;
18813                  }
18814                  break;
18815                }
18816              case "deleteContentBackward":
18817                if (selectionStart === selectionEnd) {
18818                  selStart -= 1;
18819                }
18820                break;
18821              case "deleteContentForward":
18822                if (selectionStart === selectionEnd) {
18823                  selEnd += 1;
18824                }
18825                break;
18826            }
18827            event.preventDefault();
18828            this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
18829              source: this,
18830              detail: {
18831                id,
18832                name: "Keystroke",
18833                value,
18834                change: data || "",
18835                willCommit: false,
18836                selStart,
18837                selEnd
18838              }
18839            });
18840          });
18841        }
18842        this._setEventListeners(element, elementData, [["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.value);
18843      }
18844      if (blurListener) {
18845        element.addEventListener("blur", blurListener);
18846      }
18847      if (this.data.comb) {
18848        const fieldWidth = this.data.rect[2] - this.data.rect[0];
18849        const combWidth = fieldWidth / maxLen;
18850        element.classList.add("comb");
18851        element.style.setProperty("--comb-width", `calc(${combWidth}px * var(--total-scale-factor))`);
18852        const alignment = this.data.textAlignment;
18853        if (alignment === 1 || alignment === 2) {
18854          const setCombOffset = () => {
18855            const free = maxLen - element.value.length;
18856            element.style.setProperty("--comb-offset", `${alignment === 1 ? free >> 1 : free}`);
18857          };
18858          setCombOffset();
18859          for (const evt of ["input", "blur", "resetform", "updatefromsandbox"]) {
18860            element.addEventListener(evt, setCombOffset);
18861          }
18862        }
18863      }
18864    } else {
18865      element = document.createElement("div");
18866      element.textContent = this.data.fieldValue;
18867      element.style.verticalAlign = "middle";
18868      element.style.display = "table-cell";
18869      if (this.data.hasOwnCanvas) {
18870        element.hidden = true;
18871      }
18872    }
18873    this._setTextStyle(element);
18874    this._setBackgroundColor(element);
18875    this._setDefaultPropertiesFromJS(element);
18876    this.container.append(element);
18877    return this.container;
18878  }
18879}
18880class SignatureWidgetAnnotationElement extends WidgetAnnotationElement {
18881  constructor(parameters) {
18882    super(parameters, {
18883      isRenderable: !!parameters.data.hasOwnCanvas
18884    });
18885  }
18886}
18887class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
18888  constructor(parameters) {
18889    super(parameters, {
18890      isRenderable: parameters.renderForms
18891    });
18892  }
18893  render() {
18894    const storage = this.annotationStorage;
18895    const data = this.data;
18896    const id = data.id;
18897    let value = storage.getValue(id, {
18898      value: data.exportValue === data.fieldValue
18899    }).value;
18900    if (typeof value === "string") {
18901      value = value !== "Off";
18902      storage.setValue(id, {
18903        value
18904      });
18905    }
18906    this.container.classList.add("buttonWidgetAnnotation", "checkBox");
18907    const element = document.createElement("input");
18908    GetElementsByNameSet.add(element);
18909    element.setAttribute("data-element-id", id);
18910    element.disabled = data.readOnly;
18911    this._setRequired(element, this.data.required);
18912    element.type = "checkbox";
18913    element.name = data.fieldName;
18914    if (value) {
18915      element.setAttribute("checked", true);
18916    }
18917    element.setAttribute("exportValue", data.exportValue);
18918    element.tabIndex = 0;
18919    element.addEventListener("change", event => {
18920      const {
18921        name,
18922        checked
18923      } = event.target;
18924      for (const checkbox of this._getElementsByName(name, id)) {
18925        const curChecked = checked && checkbox.exportValue === data.exportValue;
18926        if (checkbox.domElement) {
18927          checkbox.domElement.checked = curChecked;
18928        }
18929        storage.setValue(checkbox.id, {
18930          value: curChecked
18931        });
18932      }
18933      storage.setValue(id, {
18934        value: checked
18935      });
18936    });
18937    element.addEventListener("resetform", event => {
18938      const defaultValue = data.defaultFieldValue || "Off";
18939      event.target.checked = defaultValue === data.exportValue;
18940    });
18941    if (this.enableScripting && this.hasJSActions) {
18942      element.addEventListener("updatefromsandbox", jsEvent => {
18943        const actions = {
18944          value(event) {
18945            event.target.checked = event.detail.value !== "Off";
18946            storage.setValue(id, {
18947              value: event.target.checked
18948            });
18949          }
18950        };
18951        this._dispatchEventFromSandbox(actions, jsEvent);
18952      });
18953      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);
18954    }
18955    this._setDefaultPropertiesFromJS(element);
18956    this.container.append(element);
18957    return this.container;
18958  }
18959}
18960class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
18961  constructor(parameters) {
18962    super(parameters, {
18963      isRenderable: parameters.renderForms
18964    });
18965  }
18966  render() {
18967    this.container.classList.add("buttonWidgetAnnotation", "radioButton");
18968    const storage = this.annotationStorage;
18969    const data = this.data;
18970    const id = data.id;
18971    let value = storage.getValue(id, {
18972      value: data.buttonValue !== null && data.fieldValue === data.buttonValue
18973    }).value;
18974    if (typeof value === "string") {
18975      value = value !== data.buttonValue;
18976      storage.setValue(id, {
18977        value
18978      });
18979    }
18980    if (value) {
18981      for (const radio of this._getElementsByName(data.fieldName, id)) {
18982        storage.setValue(radio.id, {
18983          value: false
18984        });
18985      }
18986    }
18987    const element = document.createElement("input");
18988    GetElementsByNameSet.add(element);
18989    element.setAttribute("data-element-id", id);
18990    element.disabled = data.readOnly;
18991    this._setRequired(element, this.data.required);
18992    element.type = "radio";
18993    element.name = data.fieldName;
18994    if (value) {
18995      element.setAttribute("checked", true);
18996    }
18997    element.tabIndex = 0;
18998    element.addEventListener("change", event => {
18999      const {
19000        name,
19001        checked
19002      } = event.target;
19003      for (const radio of this._getElementsByName(name, id)) {
19004        storage.setValue(radio.id, {
19005          value: false
19006        });
19007      }
19008      storage.setValue(id, {
19009        value: checked
19010      });
19011    });
19012    element.addEventListener("resetform", event => {
19013      const defaultValue = data.defaultFieldValue;
19014      event.target.checked = defaultValue !== null && defaultValue !== undefined && defaultValue === data.buttonValue;
19015    });
19016    if (this.enableScripting && this.hasJSActions) {
19017      const pdfButtonValue = data.buttonValue;
19018      element.addEventListener("updatefromsandbox", jsEvent => {
19019        const actions = {
19020          value: event => {
19021            const checked = pdfButtonValue === event.detail.value;
19022            for (const radio of this._getElementsByName(event.target.name)) {
19023              const curChecked = checked && radio.id === id;
19024              if (radio.domElement) {
19025                radio.domElement.checked = curChecked;
19026              }
19027              storage.setValue(radio.id, {
19028                value: curChecked
19029              });
19030            }
19031          }
19032        };
19033        this._dispatchEventFromSandbox(actions, jsEvent);
19034      });
19035      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);
19036    }
19037    this._setDefaultPropertiesFromJS(element);
19038    this.container.append(element);
19039    return this.container;
19040  }
19041}
19042class PushButtonWidgetAnnotationElement extends LinkAnnotationElement {
19043  constructor(parameters) {
19044    super(parameters, {
19045      ignoreBorder: parameters.data.hasAppearance
19046    });
19047  }
19048  render() {
19049    const container = super.render();
19050    container.classList.add("buttonWidgetAnnotation", "pushButton");
19051    const linkElement = container.lastChild;
19052    if (this.enableScripting && this.hasJSActions && linkElement) {
19053      this._setDefaultPropertiesFromJS(linkElement);
19054      linkElement.addEventListener("updatefromsandbox", jsEvent => {
19055        this._dispatchEventFromSandbox({}, jsEvent);
19056      });
19057    }
19058    return container;
19059  }
19060}
19061class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
19062  constructor(parameters) {
19063    super(parameters, {
19064      isRenderable: parameters.renderForms
19065    });
19066  }
19067  render() {
19068    this.container.classList.add("choiceWidgetAnnotation");
19069    const storage = this.annotationStorage;
19070    const id = this.data.id;
19071    const storedData = storage.getValue(id, {
19072      value: this.data.fieldValue
19073    });
19074    const selectElement = document.createElement("select");
19075    GetElementsByNameSet.add(selectElement);
19076    selectElement.setAttribute("data-element-id", id);
19077    selectElement.disabled = this.data.readOnly;
19078    this._setRequired(selectElement, this.data.required);
19079    selectElement.name = this.data.fieldName;
19080    selectElement.tabIndex = 0;
19081    let addAnEmptyEntry = this.data.combo && this.data.options.length > 0;
19082    if (!this.data.combo) {
19083      selectElement.size = this.data.options.length;
19084      if (this.data.multiSelect) {
19085        selectElement.multiple = true;
19086      }
19087    }
19088    selectElement.addEventListener("resetform", event => {
19089      const defaultValue = this.data.defaultFieldValue;
19090      for (const option of selectElement.options) {
19091        option.selected = option.value === defaultValue;
19092      }
19093    });
19094    const fixDisplayValue = (option, value) => {
19095      const newValue = value.replaceAll(" ", "\u00A0");
19096      option.textContent = newValue;
19097      if (newValue !== value) {
19098        option.setAttribute("display-value", value);
19099      }
19100    };
19101    for (const option of this.data.options) {
19102      const optionElement = document.createElement("option");
19103      fixDisplayValue(optionElement, option.displayValue);
19104      optionElement.value = option.exportValue;
19105      if (storedData.value.includes(option.exportValue)) {
19106        optionElement.setAttribute("selected", true);
19107        addAnEmptyEntry = false;
19108      }
19109      selectElement.append(optionElement);
19110    }
19111    let removeEmptyEntry = null;
19112    if (addAnEmptyEntry) {
19113      const noneOptionElement = document.createElement("option");
19114      noneOptionElement.value = " ";
19115      noneOptionElement.setAttribute("hidden", true);
19116      noneOptionElement.setAttribute("selected", true);
19117      selectElement.prepend(noneOptionElement);
19118      removeEmptyEntry = () => {
19119        noneOptionElement.remove();
19120        selectElement.removeEventListener("input", removeEmptyEntry);
19121        removeEmptyEntry = null;
19122      };
19123      selectElement.addEventListener("input", removeEmptyEntry);
19124    }
19125    const getValue = isExport => {
19126      const name = isExport ? "value" : "textContent";
19127      const {
19128        options,
19129        multiple
19130      } = selectElement;
19131      if (!multiple) {
19132        return options.selectedIndex === -1 ? null : options[options.selectedIndex][name];
19133      }
19134      return Array.prototype.filter.call(options, option => option.selected).map(option => option[name]);
19135    };
19136    let selectedValues = getValue(false);
19137    const getItems = event => {
19138      const options = event.target.options;
19139      return Array.prototype.map.call(options, option => ({
19140        displayValue: option.getAttribute("display-value") || option.textContent,
19141        exportValue: option.value
19142      }));
19143    };
19144    if (this.enableScripting && this.hasJSActions) {
19145      selectElement.addEventListener("updatefromsandbox", jsEvent => {
19146        const actions = {
19147          value(event) {
19148            removeEmptyEntry?.();
19149            const value = event.detail.value;
19150            const values = new Set(Array.isArray(value) ? value : [value]);
19151            for (const option of selectElement.options) {
19152              option.selected = values.has(option.value);
19153            }
19154            storage.setValue(id, {
19155              value: getValue(true)
19156            });
19157            selectedValues = getValue(false);
19158          },
19159          multipleSelection(event) {
19160            selectElement.multiple = true;
19161          },
19162          remove(event) {
19163            const options = selectElement.options;
19164            const index = event.detail.remove;
19165            options[index].selected = false;
19166            selectElement.remove(index);
19167            if (options.length > 0) {
19168              const i = Array.prototype.findIndex.call(options, option => option.selected);
19169              if (i === -1) {
19170                options[0].selected = true;
19171              }
19172            }
19173            storage.setValue(id, {
19174              value: getValue(true),
19175              items: getItems(event)
19176            });
19177            selectedValues = getValue(false);
19178          },
19179          clear(event) {
19180            while (selectElement.length !== 0) {
19181              selectElement.remove(0);
19182            }
19183            storage.setValue(id, {
19184              value: null,
19185              items: []
19186            });
19187            selectedValues = getValue(false);
19188          },
19189          insert(event) {
19190            const {
19191              index,
19192              displayValue,
19193              exportValue
19194            } = event.detail.insert;
19195            const selectChild = selectElement.children[index];
19196            const optionElement = document.createElement("option");
19197            fixDisplayValue(optionElement, displayValue);
19198            optionElement.value = exportValue;
19199            if (selectChild) {
19200              selectChild.before(optionElement);
19201            } else {
19202              selectElement.append(optionElement);
19203            }
19204            storage.setValue(id, {
19205              value: getValue(true),
19206              items: getItems(event)
19207            });
19208            selectedValues = getValue(false);
19209          },
19210          items(event) {
19211            const {
19212              items
19213            } = event.detail;
19214            while (selectElement.length !== 0) {
19215              selectElement.remove(0);
19216            }
19217            for (const item of items) {
19218              const {
19219                displayValue,
19220                exportValue
19221              } = item;
19222              const optionElement = document.createElement("option");
19223              fixDisplayValue(optionElement, displayValue);
19224              optionElement.value = exportValue;
19225              selectElement.append(optionElement);
19226            }
19227            if (selectElement.options.length > 0) {
19228              selectElement.options[0].selected = true;
19229            }
19230            storage.setValue(id, {
19231              value: getValue(true),
19232              items: getItems(event)
19233            });
19234            selectedValues = getValue(false);
19235          },
19236          indices(event) {
19237            const indices = new Set(event.detail.indices);
19238            for (const option of event.target.options) {
19239              option.selected = indices.has(option.index);
19240            }
19241            storage.setValue(id, {
19242              value: getValue(true)
19243            });
19244            selectedValues = getValue(false);
19245          },
19246          editable(event) {
19247            event.target.disabled = !event.detail.editable;
19248          }
19249        };
19250        this._dispatchEventFromSandbox(actions, jsEvent);
19251      });
19252      selectElement.addEventListener("input", event => {
19253        const exportValue = getValue(true);
19254        const change = getValue(false);
19255        storage.setValue(id, {
19256          value: exportValue
19257        });
19258        event.preventDefault();
19259        this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
19260          source: this,
19261          detail: {
19262            id,
19263            name: "Keystroke",
19264            value: selectedValues,
19265            change,
19266            changeEx: exportValue,
19267            willCommit: false,
19268            commitKey: 1,
19269            keyDown: false
19270          }
19271        });
19272      });
19273      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);
19274    } else {
19275      selectElement.addEventListener("input", function (event) {
19276        storage.setValue(id, {
19277          value: getValue(true)
19278        });
19279      });
19280    }
19281    if (this.data.combo) {
19282      this._setTextStyle(selectElement);
19283    } else {}
19284    this._setBackgroundColor(selectElement);
19285    this._setDefaultPropertiesFromJS(selectElement);
19286    this.container.append(selectElement);
19287    return this.container;
19288  }
19289}
19290class PopupAnnotationElement extends AnnotationElement {
19291  constructor(parameters) {
19292    const {
19293      data,
19294      elements,
19295      parent
19296    } = parameters;
19297    const hasCommentManager = !!parent._commentManager;
19298    super(parameters, {
19299      isRenderable: !hasCommentManager && AnnotationElement._hasPopupData(data)
19300    });
19301    this.elements = elements;
19302    if (hasCommentManager && AnnotationElement._hasPopupData(data)) {
19303      const popup = this.popup = this.#createPopup();
19304      for (const element of elements) {
19305        element.popup = popup;
19306      }
19307    } else {
19308      this.popup = null;
19309    }
19310  }
19311  #createPopup() {
19312    return new PopupElement({
19313      container: this.container,
19314      color: this.data.color,
19315      titleObj: this.data.titleObj,
19316      modificationDate: this.data.modificationDate || this.data.creationDate,
19317      contentsObj: this.data.contentsObj,
19318      richText: this.data.richText,
19319      rect: this.data.rect,
19320      parentRect: this.data.parentRect || null,
19321      parent: this.parent,
19322      elements: this.elements,
19323      open: this.data.open,
19324      commentManager: this.parent._commentManager
19325    });
19326  }
19327  render() {
19328    const {
19329      container
19330    } = this;
19331    container.classList.add("popupAnnotation");
19332    container.role = "comment";
19333    const popup = this.popup = this.#createPopup();
19334    const elementIds = [];
19335    for (const element of this.elements) {
19336      element.popup = popup;
19337      element.container.ariaHasPopup = "dialog";
19338      elementIds.push(element.data.id);
19339      element.addHighlightArea();
19340    }
19341    this.container.setAttribute("aria-controls", elementIds.map(id => `${AnnotationPrefix}${id}`).join(","));
19342    return this.container;
19343  }
19344}
19345class PopupElement {
19346  #commentManager = null;
19347  #boundKeyDown = this.#keyDown.bind(this);
19348  #boundHide = this.#hide.bind(this);
19349  #boundShow = this.#show.bind(this);
19350  #boundToggle = this.#toggle.bind(this);
19351  #color = null;
19352  #container = null;
19353  #contentsObj = null;
19354  #dateObj = null;
19355  #elements = null;
19356  #parent = null;
19357  #parentRect = null;
19358  #pinned = false;
19359  #popup = null;
19360  #popupAbortController = null;
19361  #position = null;
19362  #commentButton = null;
19363  #commentButtonPosition = null;
19364  #popupPosition = null;
19365  #rect = null;
19366  #richText = null;
19367  #titleObj = null;
19368  #updates = null;
19369  #wasVisible = false;
19370  #firstElement = null;
19371  #commentText = null;
19372  constructor({
19373    container,
19374    color,
19375    elements,
19376    titleObj,
19377    modificationDate,
19378    contentsObj,
19379    richText,
19380    parent,
19381    rect,
19382    parentRect,
19383    open,
19384    commentManager = null
19385  }) {
19386    this.#container = container;
19387    this.#titleObj = titleObj;
19388    this.#contentsObj = contentsObj;
19389    this.#richText = richText;
19390    this.#parent = parent;
19391    this.#color = color;
19392    this.#rect = rect;
19393    this.#parentRect = parentRect;
19394    this.#elements = elements;
19395    this.#commentManager = commentManager;
19396    this.#firstElement = elements[0];
19397    this.#dateObj = PDFDateString.toDateObject(modificationDate);
19398    this.trigger = elements.flatMap(e => e.getElementsToTriggerPopup());
19399    if (!commentManager) {
19400      this.#addEventListeners();
19401      this.#container.hidden = true;
19402      if (open) {
19403        this.#toggle();
19404      }
19405    }
19406  }
19407  #addEventListeners() {
19408    if (this.#popupAbortController) {
19409      return;
19410    }
19411    this.#popupAbortController = new AbortController();
19412    const {
19413      signal
19414    } = this.#popupAbortController;
19415    for (const element of this.trigger) {
19416      element.addEventListener("click", this.#boundToggle, {
19417        signal
19418      });
19419      element.addEventListener("pointerenter", this.#boundShow, {
19420        signal
19421      });
19422      element.addEventListener("pointerleave", this.#boundHide, {
19423        signal
19424      });
19425      element.classList.add("popupTriggerArea");
19426    }
19427    for (const element of this.#elements) {
19428      element.container?.addEventListener("keydown", this.#boundKeyDown, {
19429        signal
19430      });
19431    }
19432  }
19433  #setCommentButtonPosition() {
19434    const element = this.#elements.find(e => e.hasCommentButton);
19435    if (!element) {
19436      return;
19437    }
19438    this.#commentButtonPosition = element._normalizePoint(element.commentButtonPosition);
19439  }
19440  renderCommentButton() {
19441    if (this.#commentButton) {
19442      if (!this.#commentButton.parentNode) {
19443        this.#firstElement.container.after(this.#commentButton);
19444      }
19445      return;
19446    }
19447    if (!this.#commentButtonPosition) {
19448      this.#setCommentButtonPosition();
19449    }
19450    if (!this.#commentButtonPosition) {
19451      return;
19452    }
19453    const {
19454      signal
19455    } = this.#popupAbortController = new AbortController();
19456    const hasOwnButton = this.#firstElement.hasOwnCommentButton;
19457    const togglePopup = () => {
19458      this.#commentManager.toggleCommentPopup(this, true, undefined, !hasOwnButton);
19459    };
19460    const showPopup = () => {
19461      this.#commentManager.toggleCommentPopup(this, false, true, !hasOwnButton);
19462    };
19463    const hidePopup = () => {
19464      this.#commentManager.toggleCommentPopup(this, false, false);
19465    };
19466    if (!hasOwnButton) {
19467      const button = this.#commentButton = document.createElement("button");
19468      button.className = "annotationCommentButton";
19469      const parentContainer = this.#firstElement.container;
19470      button.style.zIndex = parseInt(parentContainer.style.zIndex, 10) + 1;
19471      button.tabIndex = 0;
19472      button.ariaHasPopup = "dialog";
19473      button.ariaControls = "commentPopup";
19474      button.setAttribute("data-l10n-id", "pdfjs-show-comment-button");
19475      this.#updateColor();
19476      this.#updateCommentButtonPosition();
19477      button.addEventListener("keydown", this.#boundKeyDown, {
19478        signal
19479      });
19480      button.addEventListener("click", togglePopup, {
19481        signal
19482      });
19483      button.addEventListener("pointerenter", showPopup, {
19484        signal
19485      });
19486      button.addEventListener("pointerleave", hidePopup, {
19487        signal
19488      });
19489      parentContainer.after(button);
19490    } else {
19491      this.#commentButton = this.#firstElement.container;
19492      for (const element of this.trigger) {
19493        element.ariaHasPopup = "dialog";
19494        element.ariaControls = "commentPopup";
19495        element.addEventListener("keydown", this.#boundKeyDown, {
19496          signal
19497        });
19498        element.addEventListener("click", togglePopup, {
19499          signal
19500        });
19501        element.addEventListener("pointerenter", showPopup, {
19502          signal
19503        });
19504        element.addEventListener("pointerleave", hidePopup, {
19505          signal
19506        });
19507        element.classList.add("popupTriggerArea");
19508      }
19509    }
19510  }
19511  #updateCommentButtonPosition() {
19512    if (this.#firstElement.extraPopupElement && !this.#firstElement.editor) {
19513      return;
19514    }
19515    if (!this.#commentButton) {
19516      this.renderCommentButton();
19517    }
19518    const [x, y] = this.#commentButtonPosition;
19519    const {
19520      style
19521    } = this.#commentButton;
19522    style.left = `calc(${x}%)`;
19523    style.top = `calc(${y}% - var(--comment-button-dim))`;
19524  }
19525  #updateColor() {
19526    if (this.#firstElement.extraPopupElement) {
19527      return;
19528    }
19529    if (!this.#commentButton) {
19530      this.renderCommentButton();
19531    }
19532    this.#commentButton.style.backgroundColor = this.commentButtonColor || "";
19533  }
19534  get commentButtonColor() {
19535    const {
19536      color,
19537      opacity
19538    } = this.#firstElement.commentData;
19539    if (!color) {
19540      return null;
19541    }
19542    return this.#parent._commentManager.makeCommentColor(color, opacity);
19543  }
19544  focusCommentButton() {
19545    setTimeout(() => {
19546      this.#commentButton?.focus();
19547    }, 0);
19548  }
19549  getData() {
19550    const {
19551      richText,
19552      color,
19553      opacity,
19554      creationDate,
19555      modificationDate
19556    } = this.#firstElement.commentData;
19557    return {
19558      contentsObj: {
19559        str: this.comment
19560      },
19561      richText,
19562      color,
19563      opacity,
19564      creationDate,
19565      modificationDate
19566    };
19567  }
19568  get elementBeforePopup() {
19569    return this.#commentButton;
19570  }
19571  get comment() {
19572    this.#commentText ||= this.#firstElement.commentText;
19573    return this.#commentText;
19574  }
19575  set comment(text) {
19576    if (text === this.comment) {
19577      return;
19578    }
19579    this.#firstElement.commentText = this.#commentText = text;
19580  }
19581  focus() {
19582    this.#firstElement.container?.focus();
19583  }
19584  get parentBoundingClientRect() {
19585    return this.#firstElement.layer.getBoundingClientRect();
19586  }
19587  setCommentButtonStates({
19588    selected,
19589    hasPopup
19590  }) {
19591    if (!this.#commentButton) {
19592      return;
19593    }
19594    this.#commentButton.classList.toggle("selected", selected);
19595    this.#commentButton.ariaExpanded = hasPopup;
19596  }
19597  setSelectedCommentButton(selected) {
19598    this.#commentButton.classList.toggle("selected", selected);
19599  }
19600  get commentPopupPosition() {
19601    if (this.#popupPosition) {
19602      return this.#popupPosition;
19603    }
19604    const {
19605      x,
19606      y,
19607      height
19608    } = this.#commentButton.getBoundingClientRect();
19609    const {
19610      x: parentX,
19611      y: parentY,
19612      width: parentWidth,
19613      height: parentHeight
19614    } = this.#firstElement.layer.getBoundingClientRect();
19615    return [(x - parentX) / parentWidth, (y + height - parentY) / parentHeight];
19616  }
19617  set commentPopupPosition(pos) {
19618    this.#popupPosition = pos;
19619  }
19620  hasDefaultPopupPosition() {
19621    return this.#popupPosition === null;
19622  }
19623  get commentButtonPosition() {
19624    return this.#commentButtonPosition;
19625  }
19626  get commentButtonWidth() {
19627    return this.#commentButton.getBoundingClientRect().width / this.parentBoundingClientRect.width;
19628  }
19629  editComment(options) {
19630    const [posX, posY] = this.#popupPosition || this.commentButtonPosition.map(x => x / 100);
19631    const parentDimensions = this.parentBoundingClientRect;
19632    const {
19633      x: parentX,
19634      y: parentY,
19635      width: parentWidth,
19636      height: parentHeight
19637    } = parentDimensions;
19638    this.#commentManager.showDialog(null, this, parentX + posX * parentWidth, parentY + posY * parentHeight, {
19639      ...options,
19640      parentDimensions
19641    });
19642  }
19643  render() {
19644    if (this.#popup) {
19645      return;
19646    }
19647    const popup = this.#popup = document.createElement("div");
19648    popup.className = "popup";
19649    if (this.#color) {
19650      const baseColor = popup.style.outlineColor = Util.makeHexColor(...this.#color);
19651      popup.style.backgroundColor = `color-mix(in srgb, ${baseColor} 30%, white)`;
19652    }
19653    const header = document.createElement("span");
19654    header.className = "header";
19655    if (this.#titleObj?.str) {
19656      const title = document.createElement("span");
19657      title.className = "title";
19658      header.append(title);
19659      ({
19660        dir: title.dir,
19661        str: title.textContent
19662      } = this.#titleObj);
19663    }
19664    popup.append(header);
19665    if (this.#dateObj) {
19666      const modificationDate = document.createElement("time");
19667      modificationDate.className = "popupDate";
19668      modificationDate.setAttribute("data-l10n-id", "pdfjs-annotation-date-time-string");
19669      modificationDate.setAttribute("data-l10n-args", JSON.stringify({
19670        dateObj: this.#dateObj.valueOf()
19671      }));
19672      modificationDate.dateTime = this.#dateObj.toISOString();
19673      header.append(modificationDate);
19674    }
19675    renderRichText({
19676      html: this.#html || this.#contentsObj.str,
19677      dir: this.#contentsObj?.dir,
19678      className: "popupContent"
19679    }, popup);
19680    this.#container.append(popup);
19681  }
19682  get #html() {
19683    const richText = this.#richText;
19684    const contentsObj = this.#contentsObj;
19685    if (richText?.str && (!contentsObj?.str || contentsObj.str === richText.str)) {
19686      return this.#richText.html || null;
19687    }
19688    return null;
19689  }
19690  get #fontSize() {
19691    return this.#html?.attributes?.style?.fontSize || 0;
19692  }
19693  get #fontColor() {
19694    return this.#html?.attributes?.style?.color || null;
19695  }
19696  #makePopupContent(text) {
19697    const popupLines = [];
19698    const popupContent = {
19699      str: text,
19700      html: {
19701        name: "div",
19702        attributes: {
19703          dir: "auto"
19704        },
19705        children: [{
19706          name: "p",
19707          children: popupLines
19708        }]
19709      }
19710    };
19711    const lineAttributes = {
19712      style: {
19713        color: this.#fontColor,
19714        fontSize: this.#fontSize ? `calc(${this.#fontSize}px * var(--total-scale-factor))` : ""
19715      }
19716    };
19717    for (const line of text.split("\n")) {
19718      popupLines.push({
19719        name: "span",
19720        value: line,
19721        attributes: lineAttributes
19722      });
19723    }
19724    return popupContent;
19725  }
19726  #keyDown(event) {
19727    if (event.altKey || event.shiftKey || event.ctrlKey || event.metaKey) {
19728      return;
19729    }
19730    if (event.key === "Enter" || event.key === "Escape" && this.#pinned) {
19731      this.#toggle();
19732    }
19733  }
19734  updateEdited({
19735    rect,
19736    popup,
19737    deleted
19738  }) {
19739    if (this.#commentManager) {
19740      if (deleted) {
19741        this.remove();
19742        this.#commentText = null;
19743      } else if (popup) {
19744        if (popup.deleted) {
19745          this.remove();
19746        } else {
19747          this.#updateColor();
19748          this.#commentText = popup.text;
19749        }
19750      }
19751      if (rect) {
19752        this.#commentButtonPosition = null;
19753        this.#setCommentButtonPosition();
19754        this.#updateCommentButtonPosition();
19755      }
19756      return;
19757    }
19758    if (deleted || popup?.deleted) {
19759      this.remove();
19760      return;
19761    }
19762    this.#addEventListeners();
19763    this.#updates ||= {
19764      contentsObj: this.#contentsObj,
19765      richText: this.#richText
19766    };
19767    if (rect) {
19768      this.#position = null;
19769    }
19770    if (popup && popup.text) {
19771      this.#richText = this.#makePopupContent(popup.text);
19772      this.#dateObj = PDFDateString.toDateObject(popup.date);
19773      this.#contentsObj = null;
19774    }
19775    this.#popup?.remove();
19776    this.#popup = null;
19777  }
19778  resetEdited() {
19779    if (!this.#updates) {
19780      return;
19781    }
19782    ({
19783      contentsObj: this.#contentsObj,
19784      richText: this.#richText
19785    } = this.#updates);
19786    this.#updates = null;
19787    this.#popup?.remove();
19788    this.#popup = null;
19789    this.#position = null;
19790  }
19791  remove() {
19792    this.#popupAbortController?.abort();
19793    this.#popupAbortController = null;
19794    this.#popup?.remove();
19795    this.#popup = null;
19796    this.#wasVisible = false;
19797    this.#pinned = false;
19798    this.#commentButton?.remove();
19799    this.#commentButton = null;
19800    if (this.trigger) {
19801      for (const element of this.trigger) {
19802        element.classList.remove("popupTriggerArea");
19803      }
19804    }
19805  }
19806  #setPosition() {
19807    if (this.#position !== null) {
19808      return;
19809    }
19810    const {
19811      page: {
19812        view
19813      },
19814      viewport: {
19815        rawDims: {
19816          pageWidth,
19817          pageHeight,
19818          pageX,
19819          pageY
19820        }
19821      }
19822    } = this.#parent;
19823    let useParentRect = !!this.#parentRect;
19824    let rect = useParentRect ? this.#parentRect : this.#rect;
19825    for (const element of this.#elements) {
19826      if (!rect || Util.intersect(element.data.rect, rect) !== null) {
19827        rect = element.data.rect;
19828        useParentRect = true;
19829        break;
19830      }
19831    }
19832    const normalizedRect = Util.normalizeRect([rect[0], view[3] - rect[1] + view[1], rect[2], view[3] - rect[3] + view[1]]);
19833    const HORIZONTAL_SPACE_AFTER_ANNOTATION = 5;
19834    const parentWidth = useParentRect ? rect[2] - rect[0] + HORIZONTAL_SPACE_AFTER_ANNOTATION : 0;
19835    const popupLeft = normalizedRect[0] + parentWidth;
19836    const popupTop = normalizedRect[1];
19837    this.#position = [100 * (popupLeft - pageX) / pageWidth, 100 * (popupTop - pageY) / pageHeight];
19838    const {
19839      style
19840    } = this.#container;
19841    style.left = `${this.#position[0]}%`;
19842    style.top = `${this.#position[1]}%`;
19843  }
19844  #toggle() {
19845    if (this.#commentManager) {
19846      this.#commentManager.toggleCommentPopup(this, false);
19847      return;
19848    }
19849    this.#pinned = !this.#pinned;
19850    if (this.#pinned) {
19851      this.#show();
19852      this.#container.addEventListener("click", this.#boundToggle);
19853      this.#container.addEventListener("keydown", this.#boundKeyDown);
19854    } else {
19855      this.#hide();
19856      this.#container.removeEventListener("click", this.#boundToggle);
19857      this.#container.removeEventListener("keydown", this.#boundKeyDown);
19858    }
19859  }
19860  #show() {
19861    if (!this.#popup) {
19862      this.render();
19863    }
19864    if (!this.isVisible) {
19865      this.#setPosition();
19866      this.#container.hidden = false;
19867      this.#container.style.zIndex = parseInt(this.#container.style.zIndex, 10) + 1000;
19868    } else if (this.#pinned) {
19869      this.#container.classList.add("focused");
19870    }
19871  }
19872  #hide() {
19873    this.#container.classList.remove("focused");
19874    if (this.#pinned || !this.isVisible) {
19875      return;
19876    }
19877    this.#container.hidden = true;
19878    this.#container.style.zIndex = parseInt(this.#container.style.zIndex, 10) - 1000;
19879  }
19880  forceHide() {
19881    this.#wasVisible = this.isVisible;
19882    if (!this.#wasVisible) {
19883      return;
19884    }
19885    this.#container.hidden = true;
19886  }
19887  maybeShow() {
19888    if (this.#commentManager) {
19889      return;
19890    }
19891    this.#addEventListeners();
19892    if (!this.#wasVisible) {
19893      return;
19894    }
19895    if (!this.#popup) {
19896      this.#show();
19897    }
19898    this.#wasVisible = false;
19899    this.#container.hidden = false;
19900  }
19901  get isVisible() {
19902    
vendor: 9,224 bytes, lines 19902-20203
19902if (this.#commentManager) {
19903      return false;
19904    }
19905    return this.#container.hidden === false;
19906  }
19907}
19908class FreeTextAnnotationElement extends AnnotationElement {
19909  constructor(parameters) {
19910    super(parameters, {
19911      isRenderable: true,
19912      ignoreBorder: true
19913    });
19914    this.textContent = parameters.data.textContent;
19915    this.textPosition = parameters.data.textPosition;
19916    this.annotationEditorType = AnnotationEditorType.FREETEXT;
19917  }
19918  render() {
19919    this.container.classList.add("freeTextAnnotation");
19920    if (this.textContent) {
19921      const content = this.contentElement = document.createElement("div");
19922      content.classList.add("annotationTextContent");
19923      content.setAttribute("role", "comment");
19924      for (const line of this.textContent) {
19925        const lineSpan = document.createElement("span");
19926        lineSpan.textContent = line;
19927        content.append(lineSpan);
19928      }
19929      this.container.append(content);
19930    }
19931    if (!this.data.popupRef && this.hasPopupData) {
19932      this.hasOwnCommentButton = true;
19933      this._createPopup();
19934    }
19935    this._editOnDoubleClick();
19936    return this.container;
19937  }
19938}
19939class LineAnnotationElement extends AnnotationElement {
19940  #line = null;
19941  constructor(parameters) {
19942    super(parameters, {
19943      isRenderable: true,
19944      ignoreBorder: true
19945    });
19946  }
19947  render() {
19948    this.container.classList.add("lineAnnotation");
19949    const {
19950      data,
19951      width,
19952      height
19953    } = this;
19954    const svg = this.svgFactory.create(width, height, true);
19955    const line = this.#line = this.svgFactory.createElement("svg:line");
19956    line.setAttribute("x1", data.rect[2] - data.lineCoordinates[0]);
19957    line.setAttribute("y1", data.rect[3] - data.lineCoordinates[1]);
19958    line.setAttribute("x2", data.rect[2] - data.lineCoordinates[2]);
19959    line.setAttribute("y2", data.rect[3] - data.lineCoordinates[3]);
19960    line.setAttribute("stroke-width", data.borderStyle.width || 1);
19961    line.setAttribute("stroke", "transparent");
19962    line.setAttribute("fill", "transparent");
19963    svg.append(line);
19964    this.container.append(svg);
19965    if (!data.popupRef && this.hasPopupData) {
19966      this.hasOwnCommentButton = true;
19967      this._createPopup();
19968    }
19969    return this.container;
19970  }
19971  getElementsToTriggerPopup() {
19972    return this.#line;
19973  }
19974  addHighlightArea() {
19975    this.container.classList.add("highlightArea");
19976  }
19977}
19978class SquareAnnotationElement extends AnnotationElement {
19979  #square = null;
19980  constructor(parameters) {
19981    super(parameters, {
19982      isRenderable: true,
19983      ignoreBorder: true
19984    });
19985  }
19986  render() {
19987    this.container.classList.add("squareAnnotation");
19988    const {
19989      data,
19990      width,
19991      height
19992    } = this;
19993    const svg = this.svgFactory.create(width, height, true);
19994    const borderWidth = data.borderStyle.width;
19995    const square = this.#square = this.svgFactory.createElement("svg:rect");
19996    square.setAttribute("x", borderWidth / 2);
19997    square.setAttribute("y", borderWidth / 2);
19998    square.setAttribute("width", width - borderWidth);
19999    square.setAttribute("height", height - borderWidth);
20000    square.setAttribute("stroke-width", borderWidth || 1);
20001    square.setAttribute("stroke", "transparent");
20002    square.setAttribute("fill", "transparent");
20003    svg.append(square);
20004    this.container.append(svg);
20005    if (!data.popupRef && this.hasPopupData) {
20006      this.hasOwnCommentButton = true;
20007      this._createPopup();
20008    }
20009    return this.container;
20010  }
20011  getElementsToTriggerPopup() {
20012    return this.#square;
20013  }
20014  addHighlightArea() {
20015    this.container.classList.add("highlightArea");
20016  }
20017}
20018class CircleAnnotationElement extends AnnotationElement {
20019  #circle = null;
20020  constructor(parameters) {
20021    super(parameters, {
20022      isRenderable: true,
20023      ignoreBorder: true
20024    });
20025  }
20026  render() {
20027    this.container.classList.add("circleAnnotation");
20028    const {
20029      data,
20030      width,
20031      height
20032    } = this;
20033    const svg = this.svgFactory.create(width, height, true);
20034    const borderWidth = data.borderStyle.width;
20035    const circle = this.#circle = this.svgFactory.createElement("svg:ellipse");
20036    circle.setAttribute("cx", width / 2);
20037    circle.setAttribute("cy", height / 2);
20038    circle.setAttribute("rx", width / 2 - borderWidth / 2);
20039    circle.setAttribute("ry", height / 2 - borderWidth / 2);
20040    circle.setAttribute("stroke-width", borderWidth || 1);
20041    circle.setAttribute("stroke", "transparent");
20042    circle.setAttribute("fill", "transparent");
20043    svg.append(circle);
20044    this.container.append(svg);
20045    if (!data.popupRef && this.hasPopupData) {
20046      this.hasOwnCommentButton = true;
20047      this._createPopup();
20048    }
20049    return this.container;
20050  }
20051  getElementsToTriggerPopup() {
20052    return this.#circle;
20053  }
20054  addHighlightArea() {
20055    this.container.classList.add("highlightArea");
20056  }
20057}
20058class PolylineAnnotationElement extends AnnotationElement {
20059  #polyline = null;
20060  constructor(parameters) {
20061    super(parameters, {
20062      isRenderable: true,
20063      ignoreBorder: true
20064    });
20065    this.containerClassName = "polylineAnnotation";
20066    this.svgElementName = "svg:polyline";
20067  }
20068  render() {
20069    this.container.classList.add(this.containerClassName);
20070    const {
20071      data: {
20072        rect,
20073        vertices,
20074        borderStyle,
20075        popupRef
20076      },
20077      width,
20078      height
20079    } = this;
20080    if (!vertices) {
20081      return this.container;
20082    }
20083    const svg = this.svgFactory.create(width, height, true);
20084    let points = [];
20085    for (let i = 0, ii = vertices.length; i < ii; i += 2) {
20086      const x = vertices[i] - rect[0];
20087      const y = rect[3] - vertices[i + 1];
20088      points.push(`${x},${y}`);
20089    }
20090    points = points.join(" ");
20091    const polyline = this.#polyline = this.svgFactory.createElement(this.svgElementName);
20092    polyline.setAttribute("points", points);
20093    polyline.setAttribute("stroke-width", borderStyle.width || 1);
20094    polyline.setAttribute("stroke", "transparent");
20095    polyline.setAttribute("fill", "transparent");
20096    svg.append(polyline);
20097    this.container.append(svg);
20098    if (!popupRef && this.hasPopupData) {
20099      this.hasOwnCommentButton = true;
20100      this._createPopup();
20101    }
20102    return this.container;
20103  }
20104  getElementsToTriggerPopup() {
20105    return this.#polyline;
20106  }
20107  addHighlightArea() {
20108    this.container.classList.add("highlightArea");
20109  }
20110}
20111class PolygonAnnotationElement extends PolylineAnnotationElement {
20112  constructor(parameters) {
20113    super(parameters);
20114    this.containerClassName = "polygonAnnotation";
20115    this.svgElementName = "svg:polygon";
20116  }
20117}
20118class CaretAnnotationElement extends AnnotationElement {
20119  constructor(parameters) {
20120    super(parameters, {
20121      isRenderable: true,
20122      ignoreBorder: true
20123    });
20124  }
20125  render() {
20126    this.container.classList.add("caretAnnotation");
20127    if (!this.data.popupRef && this.hasPopupData) {
20128      this.hasOwnCommentButton = true;
20129      this._createPopup();
20130    }
20131    return this.container;
20132  }
20133}
20134class InkAnnotationElement extends AnnotationElement {
20135  #polylinesGroupElement = null;
20136  #polylines = [];
20137  constructor(parameters) {
20138    super(parameters, {
20139      isRenderable: true,
20140      ignoreBorder: true
20141    });
20142    this.containerClassName = "inkAnnotation";
20143    this.svgElementName = "svg:polyline";
20144    this.annotationEditorType = this.data.it === "InkHighlight" ? AnnotationEditorType.HIGHLIGHT : AnnotationEditorType.INK;
20145  }
20146  #getTransform(rotation, rect) {
20147    switch (rotation) {
20148      case 90:
20149        return {
20150          transform: `rotate(90) translate(${-rect[0]},${rect[1]}) scale(1,-1)`,
20151          width: rect[3] - rect[1],
20152          height: rect[2] - rect[0]
20153        };
20154      case 180:
20155        return {
20156          transform: `rotate(180) translate(${-rect[2]},${rect[1]}) scale(1,-1)`,
20157          width: rect[2] - rect[0],
20158          height: rect[3] - rect[1]
20159        };
20160      case 270:
20161        return {
20162          transform: `rotate(270) translate(${-rect[2]},${rect[3]}) scale(1,-1)`,
20163          width: rect[3] - rect[1],
20164          height: rect[2] - rect[0]
20165        };
20166      default:
20167        return {
20168          transform: `translate(${-rect[0]},${rect[3]}) scale(1,-1)`,
20169          width: rect[2] - rect[0],
20170          height: rect[3] - rect[1]
20171        };
20172    }
20173  }
20174  render() {
20175    this.container.classList.add(this.containerClassName);
20176    const {
20177      data: {
20178        rect,
20179        rotation,
20180        inkLists,
20181        borderStyle,
20182        popupRef
20183      }
20184    } = this;
20185    const {
20186      transform,
20187      width,
20188      height
20189    } = this.#getTransform(rotation, rect);
20190    const svg = this.svgFactory.create(width, height, true);
20191    const g = this.#polylinesGroupElement = this.svgFactory.createElement("svg:g");
20192    svg.append(g);
20193    g.setAttribute("stroke-width", borderStyle.width || 1);
20194    g.setAttribute("stroke-linecap", "round");
20195    g.setAttribute("stroke-linejoin", "round");
20196    g.setAttribute("stroke-miterlimit", 10);
20197    g.setAttribute("stroke", "transparent");
20198    g.setAttribute("fill", "transparent");
20199    g.setAttribute("transform", transform);
20200    for (let i = 0, ii = inkLists.length; i < ii; i++) {
20201      const polyline = this.svgFactory.createElement(this.svgElementName);
20202      this.#polylines.push(polyline);
20203      polyline.setAttribute("points", inkLists[i]
vendor: 13,748 bytes, lines 20203-20701
20203.join(","));
20204      g.append(polyline);
20205    }
20206    if (!popupRef && this.hasPopupData) {
20207      this.hasOwnCommentButton = true;
20208      this._createPopup();
20209    }
20210    this.container.append(svg);
20211    this._editOnDoubleClick();
20212    return this.container;
20213  }
20214  updateEdited(params) {
20215    super.updateEdited(params);
20216    const {
20217      thickness,
20218      points,
20219      rect
20220    } = params;
20221    const g = this.#polylinesGroupElement;
20222    if (thickness >= 0) {
20223      g.setAttribute("stroke-width", thickness || 1);
20224    }
20225    if (points) {
20226      for (let i = 0, ii = this.#polylines.length; i < ii; i++) {
20227        this.#polylines[i].setAttribute("points", points[i].join(","));
20228      }
20229    }
20230    if (rect) {
20231      const {
20232        transform,
20233        width,
20234        height
20235      } = this.#getTransform(this.data.rotation, rect);
20236      const root = g.parentElement;
20237      root.setAttribute("viewBox", `0 0 ${width} ${height}`);
20238      g.setAttribute("transform", transform);
20239    }
20240  }
20241  getElementsToTriggerPopup() {
20242    return this.#polylines;
20243  }
20244  addHighlightArea() {
20245    this.container.classList.add("highlightArea");
20246  }
20247}
20248class HighlightAnnotationElement extends AnnotationElement {
20249  constructor(parameters) {
20250    super(parameters, {
20251      isRenderable: true,
20252      ignoreBorder: true,
20253      createQuadrilaterals: true
20254    });
20255    this.annotationEditorType = AnnotationEditorType.HIGHLIGHT;
20256  }
20257  render() {
20258    const {
20259      data: {
20260        overlaidText,
20261        popupRef
20262      }
20263    } = this;
20264    if (!popupRef && this.hasPopupData) {
20265      this.hasOwnCommentButton = true;
20266      this._createPopup();
20267    }
20268    this.container.classList.add("highlightAnnotation");
20269    this._editOnDoubleClick();
20270    if (overlaidText) {
20271      const mark = document.createElement("mark");
20272      mark.classList.add("overlaidText");
20273      mark.textContent = overlaidText;
20274      this.container.append(mark);
20275    }
20276    return this.container;
20277  }
20278}
20279class UnderlineAnnotationElement extends AnnotationElement {
20280  constructor(parameters) {
20281    super(parameters, {
20282      isRenderable: true,
20283      ignoreBorder: true,
20284      createQuadrilaterals: true
20285    });
20286  }
20287  render() {
20288    const {
20289      data: {
20290        overlaidText,
20291        popupRef
20292      }
20293    } = this;
20294    if (!popupRef && this.hasPopupData) {
20295      this.hasOwnCommentButton = true;
20296      this._createPopup();
20297    }
20298    this.container.classList.add("underlineAnnotation");
20299    if (overlaidText) {
20300      const underline = document.createElement("u");
20301      underline.classList.add("overlaidText");
20302      underline.textContent = overlaidText;
20303      this.container.append(underline);
20304    }
20305    return this.container;
20306  }
20307}
20308class SquigglyAnnotationElement extends AnnotationElement {
20309  constructor(parameters) {
20310    super(parameters, {
20311      isRenderable: true,
20312      ignoreBorder: true,
20313      createQuadrilaterals: true
20314    });
20315  }
20316  render() {
20317    const {
20318      data: {
20319        overlaidText,
20320        popupRef
20321      }
20322    } = this;
20323    if (!popupRef && this.hasPopupData) {
20324      this.hasOwnCommentButton = true;
20325      this._createPopup();
20326    }
20327    this.container.classList.add("squigglyAnnotation");
20328    if (overlaidText) {
20329      const underline = document.createElement("u");
20330      underline.classList.add("overlaidText");
20331      underline.textContent = overlaidText;
20332      this.container.append(underline);
20333    }
20334    return this.container;
20335  }
20336}
20337class StrikeOutAnnotationElement extends AnnotationElement {
20338  constructor(parameters) {
20339    super(parameters, {
20340      isRenderable: true,
20341      ignoreBorder: true,
20342      createQuadrilaterals: true
20343    });
20344  }
20345  render() {
20346    const {
20347      data: {
20348        overlaidText,
20349        popupRef
20350      }
20351    } = this;
20352    if (!popupRef && this.hasPopupData) {
20353      this.hasOwnCommentButton = true;
20354      this._createPopup();
20355    }
20356    this.container.classList.add("strikeoutAnnotation");
20357    if (overlaidText) {
20358      const strikeout = document.createElement("s");
20359      strikeout.classList.add("overlaidText");
20360      strikeout.textContent = overlaidText;
20361      this.container.append(strikeout);
20362    }
20363    return this.container;
20364  }
20365}
20366class StampAnnotationElement extends AnnotationElement {
20367  constructor(parameters) {
20368    super(parameters, {
20369      isRenderable: true,
20370      ignoreBorder: true
20371    });
20372    this.annotationEditorType = AnnotationEditorType.STAMP;
20373  }
20374  render() {
20375    this.container.classList.add("stampAnnotation");
20376    this.container.setAttribute("role", "img");
20377    if (!this.data.popupRef && this.hasPopupData) {
20378      this.hasOwnCommentButton = true;
20379      this._createPopup();
20380    }
20381    this._editOnDoubleClick();
20382    return this.container;
20383  }
20384}
20385class FileAttachmentAnnotationElement extends AnnotationElement {
20386  #trigger = null;
20387  constructor(parameters) {
20388    super(parameters, {
20389      isRenderable: true
20390    });
20391    const {
20392      fileId,
20393      file
20394    } = this.data;
20395    this.filename = file.filename;
20396    this.content = file.content;
20397    this.fileId = fileId;
20398    this.linkService.eventBus?.dispatch("fileattachmentannotation", {
20399      source: this,
20400      attachmentId: this.fileId,
20401      ...file
20402    });
20403  }
20404  render() {
20405    this.container.classList.add("fileAttachmentAnnotation");
20406    const {
20407      container,
20408      data
20409    } = this;
20410    let trigger;
20411    if (data.hasAppearance || data.fillAlpha === 0) {
20412      trigger = document.createElement("div");
20413    } else {
20414      trigger = document.createElement("img");
20415      trigger.src = `${this.imageResourcesPath}annotation-${/paperclip/i.test(data.name) ? "paperclip" : "pushpin"}.svg`;
20416      if (data.fillAlpha && data.fillAlpha < 1) {
20417        trigger.style = `filter: opacity(${Math.round(data.fillAlpha * 100)}%);`;
20418      }
20419    }
20420    trigger.addEventListener("dblclick", this.#download.bind(this));
20421    this.#trigger = trigger;
20422    const {
20423      isMac
20424    } = FeatureTest.platform;
20425    container.addEventListener("keydown", evt => {
20426      if (evt.key === "Enter" && (isMac ? evt.metaKey : evt.ctrlKey)) {
20427        this.#download();
20428      }
20429    });
20430    if (!data.popupRef && this.hasPopupData) {
20431      this.hasOwnCommentButton = true;
20432      this._createPopup();
20433    } else {
20434      trigger.classList.add("popupTriggerArea");
20435    }
20436    container.append(trigger);
20437    return container;
20438  }
20439  getElementsToTriggerPopup() {
20440    return this.#trigger;
20441  }
20442  addHighlightArea() {
20443    this.container.classList.add("highlightArea");
20444  }
20445  async #download() {
20446    const {
20447      fileId,
20448      filename,
20449      content: fallbackContent
20450    } = this;
20451    const content = (await this.linkService.getAttachmentContent(fileId)) || fallbackContent;
20452    if (content) {
20453      this.downloadManager?.openOrDownloadData(content, filename);
20454    }
20455  }
20456}
20457class MediaAnnotationElement extends AnnotationElement {
20458  #abortController = new AbortController();
20459  #contentUrl = null;
20460  #media = null;
20461  constructor(parameters) {
20462    super(parameters, {
20463      isRenderable: !!parameters.data.richMedia
20464    });
20465  }
20466  render() {
20467    this.container.classList.add("mediaAnnotation");
20468    const {
20469      filename
20470    } = this.data.richMedia;
20471    const button = document.createElement("button");
20472    button.className = "mediaPlayButton";
20473    button.type = "button";
20474    button.title = button.ariaLabel = filename;
20475    button.addEventListener("click", () => this.#load(button), {
20476      signal: this.#abortController.signal
20477    });
20478    this.container.append(button);
20479    return this.container;
20480  }
20481  async #load(button) {
20482    const {
20483      fileId,
20484      filename,
20485      contentType
20486    } = this.data.richMedia;
20487    button.disabled = true;
20488    let content;
20489    try {
20490      content = await this.linkService.getAttachmentContent(fileId);
20491    } catch {
20492      return;
20493    } finally {
20494      button.disabled = false;
20495    }
20496    if (!content || !button.isConnected) {
20497      return;
20498    }
20499    const {
20500      signal
20501    } = this.#abortController;
20502    const url = URL.createObjectURL(new Blob([content], {
20503      type: contentType
20504    }));
20505    this.#contentUrl = url;
20506    const isAudio = contentType.startsWith("audio/");
20507    const media = document.createElement(isAudio ? "audio" : "video");
20508    this.#media = media;
20509    media.className = "mediaContent";
20510    this._setBackgroundColor(media);
20511    media.src = url;
20512    media.title = filename;
20513    media.controls = true;
20514    media.autoplay = true;
20515    media.tabIndex = 0;
20516    if (isAudio) {
20517      let hovered = false;
20518      let focused = false;
20519      const updateControls = () => {
20520        media.controls = hovered || focused;
20521      };
20522      this.container.addEventListener("pointerenter", () => {
20523        hovered = true;
20524        updateControls();
20525      }, {
20526        signal
20527      });
20528      this.container.addEventListener("pointerleave", () => {
20529        hovered = false;
20530        updateControls();
20531      }, {
20532        signal
20533      });
20534      this.container.addEventListener("focusin", () => {
20535        focused = true;
20536        updateControls();
20537      }, {
20538        signal
20539      });
20540      this.container.addEventListener("focusout", () => {
20541        focused = false;
20542        updateControls();
20543      }, {
20544        signal
20545      });
20546    }
20547    media.addEventListener("emptied", () => this.#revokeContentUrl(url), {
20548      once: true,
20549      signal
20550    });
20551    button.replaceWith(media);
20552    media.play().catch(() => {});
20553  }
20554  #revokeContentUrl(url = this.#contentUrl) {
20555    if (url && url === this.#contentUrl) {
20556      URL.revokeObjectURL(url);
20557      this.#contentUrl = null;
20558    }
20559  }
20560  destroy() {
20561    this.#abortController.abort();
20562    if (this.#media) {
20563      this.#media.pause();
20564      this.#media.removeAttribute("src");
20565      this.#media.load();
20566      this.#media = null;
20567    }
20568    this.#revokeContentUrl();
20569  }
20570}
20571class AnnotationLayer {
20572  #accessibilityManager = null;
20573  #annotationCanvasMap = null;
20574  #annotationStorage = null;
20575  #editableAnnotations = new Map();
20576  #structTreeLayer = null;
20577  #linkService = null;
20578  #elements = [];
20579  #hasAriaAttributesFromStructTree = false;
20580  zIndex = 0;
20581  constructor({
20582    div,
20583    accessibilityManager,
20584    annotationCanvasMap,
20585    annotationEditorUIManager,
20586    page,
20587    viewport,
20588    structTreeLayer,
20589    commentManager,
20590    linkService,
20591    annotationStorage
20592  }) {
20593    this.div = div;
20594    this.#accessibilityManager = accessibilityManager;
20595    this.#annotationCanvasMap = annotationCanvasMap;
20596    this.#structTreeLayer = structTreeLayer || null;
20597    this.#linkService = linkService || null;
20598    this.#annotationStorage = annotationStorage || new AnnotationStorage();
20599    this.page = page;
20600    this.viewport = viewport;
20601    this._annotationEditorUIManager = annotationEditorUIManager;
20602    this._commentManager = commentManager || null;
20603  }
20604  hasEditableAnnotations() {
20605    return this.#editableAnnotations.size > 0;
20606  }
20607  async render(params) {
20608    const {
20609      annotations,
20610      optionalContentConfig
20611    } = params;
20612    const layer = this.div;
20613    setLayerDimensions(layer, this.viewport);
20614    const popupToElements = new Map();
20615    const popupAnnotations = [];
20616    const elementParams = {
20617      data: null,
20618      layer,
20619      linkService: this.#linkService,
20620      downloadManager: params.downloadManager,
20621      imageResourcesPath: params.imageResourcesPath || "",
20622      renderForms: params.renderForms !== false,
20623      svgFactory: new DOMSVGFactory(),
20624      annotationStorage: this.#annotationStorage,
20625      enableComment: params.enableComment === true,
20626      enableScripting: params.enableScripting === true,
20627      hasJSActions: params.hasJSActions,
20628      fieldObjects: params.fieldObjects,
20629      parent: this,
20630      elements: null
20631    };
20632    for (const data of annotations) {
20633      if (data.noHTML) {
20634        continue;
20635      }
20636      const isPopupAnnotation = data.annotationType === AnnotationType.POPUP;
20637      if (!isPopupAnnotation) {
20638        if (data.rect[2] === data.rect[0] || data.rect[3] === data.rect[1]) {
20639          continue;
20640        }
20641      } else {
20642        const elements = popupToElements.get(data.id);
20643        if (!elements) {
20644          continue;
20645        }
20646        if (!this._commentManager) {
20647          popupAnnotations.push(data);
20648          continue;
20649        }
20650        elementParams.elements = elements;
20651      }
20652      elementParams.data = data;
20653      const element = AnnotationElementFactory.create(elementParams);
20654      if (!element.isRenderable) {
20655        continue;
20656      }
20657      if (!isPopupAnnotation) {
20658        this.#elements.push(element);
20659        if (data.popupRef) {
20660          popupToElements.getOrInsertComputed(data.popupRef, makeArr).push(element);
20661        }
20662      }
20663      const rendered = element.render();
20664      if (data.hidden) {
20665        rendered.style.visibility = "hidden";
20666      }
20667      element.updateOC(optionalContentConfig);
20668      if (element._isEditable) {
20669        this.#editableAnnotations.set(element.data.id, element);
20670        this._annotationEditorUIManager?.renderAnnotationElement(element);
20671      }
20672    }
20673    await this.#addElementsToDOM();
20674    for (const data of popupAnnotations) {
20675      const elements = elementParams.elements = popupToElements.get(data.id);
20676      elementParams.data = data;
20677      const element = AnnotationElementFactory.create(elementParams);
20678      if (!element.isRenderable) {
20679        continue;
20680      }
20681      const rendered = element.render();
20682      element.contentElement.id = `${AnnotationPrefix}${data.id}`;
20683      if (data.hidden) {
20684        rendered.style.visibility = "hidden";
20685      }
20686      elements.at(-1).container.after(rendered);
20687    }
20688    this.#setAnnotationCanvasMap();
20689  }
20690  async #addElementsToDOM() {
20691    if (this.#elements.length === 0) {
20692      return;
20693    }
20694    this.div.replaceChildren();
20695    const promises = [];
20696    if (!this.#hasAriaAttributesFromStructTree) {
20697      this.#hasAriaAttributesFromStructTree = true;
20698      for (const {
20699        contentElement,
20700        data: {
20701          
vendor: 1,708 bytes, lines 20701-20758
20701id
20702        }
20703      } of this.#elements) {
20704        const annotationId = contentElement.id = `${AnnotationPrefix}${id}`;
20705        promises.push(this.#structTreeLayer?.getAriaAttributes(annotationId).then(ariaAttributes => {
20706          if (ariaAttributes) {
20707            for (const [key, value] of ariaAttributes) {
20708              contentElement.setAttribute(key, value);
20709            }
20710          }
20711        }));
20712      }
20713    }
20714    this.#elements.sort(({
20715      data: {
20716        rect: [a0, a1, a2, a3]
20717      }
20718    }, {
20719      data: {
20720        rect: [b0, b1, b2, b3]
20721      }
20722    }) => {
20723      if (a0 === a2 && a1 === a3) {
20724        return +1;
20725      }
20726      if (b0 === b2 && b1 === b3) {
20727        return -1;
20728      }
20729      const top1 = a3;
20730      const bot1 = a1;
20731      const mid1 = (a1 + a3) / 2;
20732      const top2 = b3;
20733      const bot2 = b1;
20734      const mid2 = (b1 + b3) / 2;
20735      if (mid1 >= top2 && mid2 <= bot1) {
20736        return -1;
20737      }
20738      if (mid2 >= top1 && mid1 <= bot2) {
20739        return +1;
20740      }
20741      const centerX1 = (a0 + a2) / 2;
20742      const centerX2 = (b0 + b2) / 2;
20743      return centerX1 - centerX2;
20744    });
20745    const fragment = document.createDocumentFragment();
20746    for (const element of this.#elements) {
20747      fragment.append(element.container);
20748      if (this._commentManager) {
20749        (element.extraPopupElement?.popup || element.popup)?.renderCommentButton();
20750      } else if (element.extraPopupElement) {
20751        fragment.append(element.extraPopupElement.render());
20752      }
20753    }
20754    this.div.append(fragment);
20755    await Promise.all(promises);
20756    if (this.#accessibilityManager) {
20757      for (const element of this.#elements) {
20758        this.#accessibilityManager.addPointerInTextLayer(element.
vendor: 24,856 bytes, lines 20758-21576
20758contentElement, false);
20759      }
20760    }
20761  }
20762  async addLinkAnnotations(annotations) {
20763    const elementParams = {
20764      data: null,
20765      layer: this.div,
20766      linkService: this.#linkService,
20767      svgFactory: new DOMSVGFactory(),
20768      parent: this
20769    };
20770    for (const data of annotations) {
20771      data.borderStyle ||= AnnotationLayer._defaultBorderStyle;
20772      elementParams.data = data;
20773      const element = AnnotationElementFactory.create(elementParams);
20774      if (!element.isRenderable) {
20775        continue;
20776      }
20777      element.render();
20778      element.contentElement.id = `${AnnotationPrefix}${data.id}`;
20779      this.#elements.push(element);
20780    }
20781    await this.#addElementsToDOM();
20782  }
20783  update({
20784    viewport,
20785    optionalContentConfig
20786  }) {
20787    const layer = this.div;
20788    this.viewport = viewport;
20789    setLayerDimensions(layer, {
20790      rotation: viewport.rotation
20791    });
20792    for (const element of this.#elements) {
20793      element.updateOC(optionalContentConfig);
20794    }
20795    this.#setAnnotationCanvasMap();
20796    layer.hidden = false;
20797  }
20798  destroy() {
20799    for (const element of this.#elements) {
20800      element.destroy?.();
20801      this.#accessibilityManager?.removePointerInTextLayer(element.contentElement);
20802    }
20803    this.#elements.length = 0;
20804    this.#editableAnnotations.clear();
20805    this.div.replaceChildren();
20806  }
20807  #setAnnotationCanvasMap() {
20808    if (!this.#annotationCanvasMap) {
20809      return;
20810    }
20811    const layer = this.div;
20812    for (const [id, canvas] of this.#annotationCanvasMap) {
20813      const element = layer.querySelector(`[data-annotation-id="${id}"]`);
20814      if (!element) {
20815        continue;
20816      }
20817      if (Array.isArray(canvas)) {
20818        for (const cvs of canvas) {
20819          cvs.className = "annotationContent";
20820          cvs.ariaHidden = true;
20821        }
20822      } else {
20823        canvas.className = "annotationContent";
20824        canvas.ariaHidden = true;
20825      }
20826      const toRemove = [];
20827      for (const child of element.children) {
20828        if (child.nodeName === "CANVAS") {
20829          toRemove.push(child);
20830        }
20831      }
20832      for (const child of toRemove) {
20833        child.remove();
20834      }
20835      const firstCanvas = Array.isArray(canvas) ? canvas[0] : canvas;
20836      const {
20837        firstChild
20838      } = element;
20839      if (!firstChild) {
20840        element.append(firstCanvas);
20841      } else if (!firstChild.classList.contains("annotationContent")) {
20842        firstChild.before(firstCanvas);
20843      } else {
20844        firstChild.after(firstCanvas);
20845      }
20846      if (Array.isArray(canvas)) {
20847        let lastCanvas = firstCanvas;
20848        for (let i = 1, ii = canvas.length; i < ii; i++) {
20849          lastCanvas.after(canvas[i]);
20850          lastCanvas = canvas[i];
20851        }
20852      }
20853      this.#annotationCanvasMap.delete(id);
20854      const editableAnnotation = this.#editableAnnotations.get(id);
20855      if (!editableAnnotation) {
20856        continue;
20857      }
20858      if (editableAnnotation._hasNoCanvas) {
20859        this._annotationEditorUIManager?.setMissingCanvas(id, element.id, canvas);
20860        editableAnnotation._hasNoCanvas = false;
20861      } else {
20862        editableAnnotation.canvas = canvas;
20863      }
20864    }
20865  }
20866  refreshCanvases() {
20867    this.#setAnnotationCanvasMap();
20868  }
20869  getEditableAnnotations() {
20870    return this.#editableAnnotations.values();
20871  }
20872  getEditableAnnotation(id) {
20873    return this.#editableAnnotations.get(id);
20874  }
20875  addFakeAnnotation(editor) {
20876    const {
20877      div
20878    } = this;
20879    const {
20880      id,
20881      rotation
20882    } = editor;
20883    const element = new EditorAnnotationElement({
20884      data: {
20885        id,
20886        rect: editor.getPDFRect(),
20887        rotation
20888      },
20889      editor,
20890      layer: div,
20891      parent: this,
20892      enableComment: !!this._commentManager,
20893      linkService: this.#linkService,
20894      annotationStorage: this.#annotationStorage
20895    });
20896    element.render();
20897    element.contentElement.id = `${AnnotationPrefix}${id}`;
20898    element.createOrUpdatePopup();
20899    this.#elements.push(element);
20900    return element;
20901  }
20902  removeAnnotation(id) {
20903    const index = this.#elements.findIndex(el => el.data.id === id);
20904    if (index < 0) {
20905      return;
20906    }
20907    const [element] = this.#elements.splice(index, 1);
20908    this.#accessibilityManager?.removePointerInTextLayer(element.contentElement);
20909  }
20910  updateFakeAnnotations(editors) {
20911    if (editors.length === 0) {
20912      return;
20913    }
20914    for (const editor of editors) {
20915      editor.updateFakeAnnotationElement(this);
20916    }
20917    this.#addElementsToDOM();
20918  }
20919  togglePointerEvents(enabled = false) {
20920    this.div.classList.toggle("disabled", !enabled);
20921  }
20922  static get _defaultBorderStyle() {
20923    return shadow(this, "_defaultBorderStyle", Object.freeze({
20924      width: 1,
20925      rawWidth: 1,
20926      style: AnnotationBorderStyleType.SOLID,
20927      dashArray: [3],
20928      horizontalCornerRadius: 0,
20929      verticalCornerRadius: 0
20930    }));
20931  }
20932}
20933
20934;// ./src/display/editor/freetext.js
20935
20936
20937
20938
20939
20940const EOL_PATTERN = /\r\n?|\n/g;
20941class FreeTextEditor extends AnnotationEditor {
20942  #content = "";
20943  #editorDivId = `${this.id}-editor`;
20944  #editModeAC = null;
20945  #fontSize;
20946  _colorPicker = null;
20947  static _freeTextDefaultContent = "";
20948  static _internalPadding = 0;
20949  static _defaultColor = null;
20950  static _defaultFontSize = 10;
20951  static get _keyboardManager() {
20952    const proto = FreeTextEditor.prototype;
20953    const arrowChecker = self => self.isEmpty();
20954    const small = AnnotationEditorUIManager.TRANSLATE_SMALL;
20955    const big = AnnotationEditorUIManager.TRANSLATE_BIG;
20956    return shadow(this, "_keyboardManager", new KeyboardManager([[["ctrl+s", "mac+meta+s", "ctrl+p", "mac+meta+p"], proto.commitOrRemove, {
20957      bubbles: true
20958    }], [["ctrl+Enter", "mac+meta+Enter"], proto.commitOrRemove], [["Escape"], proto.commitOrRemove], [["ArrowLeft"], proto._translateEmpty, {
20959      args: [-small, 0],
20960      checker: arrowChecker
20961    }], [["ctrl+ArrowLeft", "mac+shift+ArrowLeft"], proto._translateEmpty, {
20962      args: [-big, 0],
20963      checker: arrowChecker
20964    }], [["ArrowRight"], proto._translateEmpty, {
20965      args: [small, 0],
20966      checker: arrowChecker
20967    }], [["ctrl+ArrowRight", "mac+shift+ArrowRight"], proto._translateEmpty, {
20968      args: [big, 0],
20969      checker: arrowChecker
20970    }], [["ArrowUp"], proto._translateEmpty, {
20971      args: [0, -small],
20972      checker: arrowChecker
20973    }], [["ctrl+ArrowUp", "mac+shift+ArrowUp"], proto._translateEmpty, {
20974      args: [0, -big],
20975      checker: arrowChecker
20976    }], [["ArrowDown"], proto._translateEmpty, {
20977      args: [0, small],
20978      checker: arrowChecker
20979    }], [["ctrl+ArrowDown", "mac+shift+ArrowDown"], proto._translateEmpty, {
20980      args: [0, big],
20981      checker: arrowChecker
20982    }]]));
20983  }
20984  static _type = "freetext";
20985  static _editorType = AnnotationEditorType.FREETEXT;
20986  constructor(params) {
20987    super({
20988      ...params,
20989      name: "freeTextEditor"
20990    });
20991    this.color = params.color || FreeTextEditor._defaultColor || AnnotationEditor._defaultLineColor;
20992    this.#fontSize = params.fontSize || FreeTextEditor._defaultFontSize;
20993    if (!this.annotationElementId) {
20994      this._uiManager.a11yAlert(AnnotationEditor._l10nAlert.freetext);
20995    }
20996    this.canAddComment = false;
20997  }
20998  static initialize(l10n, uiManager) {
20999    AnnotationEditor.initialize(l10n, uiManager);
21000    const style = getComputedStyle(document.documentElement);
21001    this._internalPadding = parseFloat(style.getPropertyValue("--freetext-padding"));
21002  }
21003  static updateDefaultParams(type, value) {
21004    switch (type) {
21005      case AnnotationEditorParamsType.FREETEXT_SIZE:
21006        FreeTextEditor._defaultFontSize = value;
21007        break;
21008      case AnnotationEditorParamsType.FREETEXT_COLOR:
21009        FreeTextEditor._defaultColor = value;
21010        break;
21011    }
21012  }
21013  updateParams(type, value) {
21014    switch (type) {
21015      case AnnotationEditorParamsType.FREETEXT_SIZE:
21016        this.#updateFontSize(value);
21017        break;
21018      case AnnotationEditorParamsType.FREETEXT_COLOR:
21019        this.#updateColor(value);
21020        break;
21021    }
21022  }
21023  static get defaultPropertiesToUpdate() {
21024    return [[AnnotationEditorParamsType.FREETEXT_SIZE, FreeTextEditor._defaultFontSize], [AnnotationEditorParamsType.FREETEXT_COLOR, FreeTextEditor._defaultColor || AnnotationEditor._defaultLineColor]];
21025  }
21026  get propertiesToUpdate() {
21027    return [[AnnotationEditorParamsType.FREETEXT_SIZE, this.#fontSize], [AnnotationEditorParamsType.FREETEXT_COLOR, this.color]];
21028  }
21029  get toolbarButtons() {
21030    this._colorPicker ||= new BasicColorPicker(this);
21031    return [["colorPicker", this._colorPicker]];
21032  }
21033  get colorType() {
21034    return AnnotationEditorParamsType.FREETEXT_COLOR;
21035  }
21036  #updateFontSize(fontSize) {
21037    const setFontsize = size => {
21038      this.editorDiv.style.fontSize = `calc(${size}px * var(--total-scale-factor))`;
21039      this.translate(0, -(size - this.#fontSize) * this.parentScale);
21040      this.#fontSize = size;
21041      this.#setEditorDimensions();
21042    };
21043    const savedFontsize = this.#fontSize;
21044    this.addCommands({
21045      cmd: setFontsize.bind(this, fontSize),
21046      undo: setFontsize.bind(this, savedFontsize),
21047      post: this._uiManager.updateUI.bind(this._uiManager, this),
21048      mustExec: true,
21049      type: AnnotationEditorParamsType.FREETEXT_SIZE,
21050      overwriteIfSameType: true,
21051      keepUndo: true
21052    });
21053  }
21054  onUpdatedColor() {
21055    this.editorDiv.style.color = this.color;
21056    this._colorPicker?.update(this.color);
21057    super.onUpdatedColor();
21058  }
21059  #updateColor(color) {
21060    const setColor = col => {
21061      this.color = col;
21062      this.onUpdatedColor();
21063    };
21064    const savedColor = this.color;
21065    this.addCommands({
21066      cmd: setColor.bind(this, color),
21067      undo: setColor.bind(this, savedColor),
21068      post: this._uiManager.updateUI.bind(this._uiManager, this),
21069      mustExec: true,
21070      type: AnnotationEditorParamsType.FREETEXT_COLOR,
21071      overwriteIfSameType: true,
21072      keepUndo: true
21073    });
21074  }
21075  _translateEmpty(x, y) {
21076    this._uiManager.translateSelectedEditors(x, y, true);
21077  }
21078  getInitialTranslation() {
21079    const scale = this.parentScale;
21080    return [-FreeTextEditor._internalPadding * scale, -(FreeTextEditor._internalPadding + this.#fontSize) * scale];
21081  }
21082  rebuild() {
21083    if (!this.parent) {
21084      return;
21085    }
21086    super.rebuild();
21087    if (this.div === null) {
21088      return;
21089    }
21090    if (!this.isAttachedToDOM) {
21091      this.parent.add(this);
21092    }
21093  }
21094  enableEditMode() {
21095    if (!super.enableEditMode()) {
21096      return false;
21097    }
21098    this.overlayDiv.classList.remove("enabled");
21099    this.editorDiv.contentEditable = true;
21100    this._isDraggable = false;
21101    this.div.removeAttribute("aria-activedescendant");
21102    this.#editModeAC = new AbortController();
21103    const signal = this._uiManager.combinedSignal(this.#editModeAC);
21104    this.editorDiv.addEventListener("keydown", this.editorDivKeydown.bind(this), {
21105      signal
21106    });
21107    this.editorDiv.addEventListener("focus", this.editorDivFocus.bind(this), {
21108      signal
21109    });
21110    this.editorDiv.addEventListener("blur", this.editorDivBlur.bind(this), {
21111      signal
21112    });
21113    this.editorDiv.addEventListener("input", this.editorDivInput.bind(this), {
21114      signal
21115    });
21116    this.editorDiv.addEventListener("paste", this.editorDivPaste.bind(this), {
21117      signal
21118    });
21119    return true;
21120  }
21121  disableEditMode() {
21122    if (!super.disableEditMode()) {
21123      return false;
21124    }
21125    this.overlayDiv.classList.add("enabled");
21126    this.editorDiv.contentEditable = false;
21127    this.div.setAttribute("aria-activedescendant", this.#editorDivId);
21128    this._isDraggable = true;
21129    this.#editModeAC?.abort();
21130    this.#editModeAC = null;
21131    this.div.focus({
21132      preventScroll: true
21133    });
21134    this.isEditing = false;
21135    this.parent.div.classList.add("freetextEditing");
21136    return true;
21137  }
21138  focusin(event) {
21139    if (!this._focusEventsAllowed) {
21140      return;
21141    }
21142    super.focusin(event);
21143    if (event.target !== this.editorDiv) {
21144      this.editorDiv.focus();
21145    }
21146  }
21147  onceAdded(focus) {
21148    if (this.width) {
21149      return;
21150    }
21151    this.enableEditMode();
21152    if (focus) {
21153      this.editorDiv.focus();
21154    }
21155    if (this._initialOptions?.isCentered) {
21156      this.center();
21157    }
21158    this._initialOptions = null;
21159  }
21160  isEmpty() {
21161    return !this.editorDiv || this.editorDiv.innerText.trim() === "";
21162  }
21163  remove() {
21164    this.isEditing = false;
21165    if (this.parent) {
21166      this.parent.setEditingState(true);
21167      this.parent.div.classList.add("freetextEditing");
21168    }
21169    super.remove();
21170  }
21171  #extractText() {
21172    const buffer = [];
21173    this.editorDiv.normalize();
21174    let prevChild = null;
21175    for (const child of this.editorDiv.childNodes) {
21176      if (prevChild?.nodeType === Node.TEXT_NODE && child.nodeName === "BR") {
21177        continue;
21178      }
21179      buffer.push(FreeTextEditor.#getNodeContent(child));
21180      prevChild = child;
21181    }
21182    return buffer.join("\n");
21183  }
21184  #setEditorDimensions() {
21185    const [parentWidth, parentHeight] = this.parentDimensions;
21186    let rect;
21187    if (this.isAttachedToDOM) {
21188      rect = this.div.getBoundingClientRect();
21189    } else {
21190      const {
21191        currentLayer,
21192        div
21193      } = this;
21194      const savedDisplay = div.style.display;
21195      const savedVisibility = div.classList.contains("hidden");
21196      div.classList.remove("hidden");
21197      div.style.display = "hidden";
21198      currentLayer.div.append(this.div);
21199      rect = div.getBoundingClientRect();
21200      div.remove();
21201      div.style.display = savedDisplay;
21202      div.classList.toggle("hidden", savedVisibility);
21203    }
21204    if (this.rotation % 180 === this.parentRotation % 180) {
21205      this.width = rect.width / parentWidth;
21206      this.height = rect.height / parentHeight;
21207    } else {
21208      this.width = rect.height / parentWidth;
21209      this.height = rect.width / parentHeight;
21210    }
21211    this.fixAndSetPosition();
21212  }
21213  commit() {
21214    if (!this.isInEditMode()) {
21215      return;
21216    }
21217    super.commit();
21218    this.disableEditMode();
21219    const savedText = this.#content;
21220    const newText = this.#content = this.#extractText().trimEnd();
21221    if (savedText === newText) {
21222      return;
21223    }
21224    const setText = text => {
21225      this.#content = text;
21226      if (!text) {
21227        this.remove();
21228        return;
21229      }
21230      this.#setContent();
21231      this._uiManager.rebuild(this);
21232      this.#setEditorDimensions();
21233    };
21234    this.addCommands({
21235      cmd: () => {
21236        setText(newText);
21237      },
21238      undo: () => {
21239        setText(savedText);
21240      },
21241      mustExec: false
21242    });
21243    this.#setEditorDimensions();
21244  }
21245  shouldGetKeyboardEvents() {
21246    return this.isInEditMode();
21247  }
21248  enterInEditMode() {
21249    this.enableEditMode();
21250    this.editorDiv.focus();
21251  }
21252  keydown(event) {
21253    if (event.target === this.div && event.key === "Enter") {
21254      this.enterInEditMode();
21255      event.preventDefault();
21256    }
21257  }
21258  editorDivKeydown(event) {
21259    FreeTextEditor._keyboardManager.exec(this, event);
21260  }
21261  editorDivFocus(event) {
21262    this.isEditing = true;
21263  }
21264  editorDivBlur(event) {
21265    this.isEditing = false;
21266  }
21267  editorDivInput(event) {
21268    this.parent.div.classList.toggle("freetextEditing", this.isEmpty());
21269  }
21270  disableEditing() {
21271    this.editorDiv.setAttribute("role", "comment");
21272    this.editorDiv.removeAttribute("aria-multiline");
21273  }
21274  enableEditing() {
21275    this.editorDiv.setAttribute("role", "textbox");
21276    this.editorDiv.setAttribute("aria-multiline", true);
21277  }
21278  get canChangeContent() {
21279    return true;
21280  }
21281  render() {
21282    if (this.div) {
21283      return this.div;
21284    }
21285    let baseX, baseY;
21286    if (this._isCopy || this.annotationElementId) {
21287      baseX = this.x;
21288      baseY = this.y;
21289    }
21290    super.render();
21291    this.editorDiv = document.createElement("div");
21292    this.editorDiv.className = "internal";
21293    this.editorDiv.setAttribute("id", this.#editorDivId);
21294    this.editorDiv.setAttribute("data-l10n-id", "pdfjs-free-text2");
21295    this.editorDiv.setAttribute("data-l10n-attrs", "default-content");
21296    this.enableEditing();
21297    this.editorDiv.contentEditable = true;
21298    const {
21299      style
21300    } = this.editorDiv;
21301    style.fontSize = `calc(${this.#fontSize}px * var(--total-scale-factor))`;
21302    style.color = this.color;
21303    this.div.append(this.editorDiv);
21304    this.overlayDiv = document.createElement("div");
21305    this.overlayDiv.classList.add("overlay", "enabled");
21306    this.div.append(this.overlayDiv);
21307    if (this._isCopy || this.annotationElementId) {
21308      const [parentWidth, parentHeight] = this.parentDimensions;
21309      if (this.annotationElementId) {
21310        const {
21311          position
21312        } = this._initialData;
21313        let [tx, ty] = this.getInitialTranslation();
21314        [tx, ty] = this.pageTranslationToScreen(tx, ty);
21315        const [pageWidth, pageHeight] = this.pageDimensions;
21316        const [pageX, pageY] = this.pageTranslation;
21317        let posX, posY;
21318        switch (this.rotation) {
21319          case 0:
21320            posX = baseX + (position[0] - pageX) / pageWidth;
21321            posY = baseY + this.height - (position[1] - pageY) / pageHeight;
21322            break;
21323          case 90:
21324            posX = baseX + (position[0] - pageX) / pageWidth;
21325            posY = baseY - (position[1] - pageY) / pageHeight;
21326            [tx, ty] = [ty, -tx];
21327            break;
21328          case 180:
21329            posX = baseX - this.width + (position[0] - pageX) / pageWidth;
21330            posY = baseY - (position[1] - pageY) / pageHeight;
21331            [tx, ty] = [-tx, -ty];
21332            break;
21333          case 270:
21334            posX = baseX + (position[0] - pageX - this.height * pageHeight) / pageWidth;
21335            posY = baseY + (position[1] - pageY - this.width * pageWidth) / pageHeight;
21336            [tx, ty] = [-ty, tx];
21337            break;
21338        }
21339        this.setAt(posX * parentWidth, posY * parentHeight, tx, ty);
21340      } else {
21341        this._moveAfterPaste(baseX, baseY);
21342      }
21343      this.#setContent();
21344      this._isDraggable = true;
21345      this.editorDiv.contentEditable = false;
21346    } else {
21347      this._isDraggable = false;
21348      this.editorDiv.contentEditable = true;
21349    }
21350    return this.div;
21351  }
21352  static #getNodeContent(node) {
21353    return (node.nodeType === Node.TEXT_NODE ? node.nodeValue : node.innerText).replaceAll(EOL_PATTERN, "");
21354  }
21355  editorDivPaste(event) {
21356    const clipboardData = event.clipboardData || window.clipboardData;
21357    const {
21358      types
21359    } = clipboardData;
21360    if (types.length === 1 && types[0] === "text/plain") {
21361      return;
21362    }
21363    event.preventDefault();
21364    const paste = FreeTextEditor.#deserializeContent(clipboardData.getData("text") || "").replaceAll(EOL_PATTERN, "\n");
21365    if (!paste) {
21366      return;
21367    }
21368    const selection = window.getSelection();
21369    if (!selection.rangeCount) {
21370      return;
21371    }
21372    this.editorDiv.normalize();
21373    selection.deleteFromDocument();
21374    const range = selection.getRangeAt(0);
21375    if (!paste.includes("\n")) {
21376      range.insertNode(document.createTextNode(paste));
21377      this.editorDiv.normalize();
21378      selection.collapseToStart();
21379      return;
21380    }
21381    const {
21382      startContainer,
21383      startOffset
21384    } = range;
21385    const bufferBefore = [];
21386    const bufferAfter = [];
21387    if (startContainer.nodeType === Node.TEXT_NODE) {
21388      const parent = startContainer.parentElement;
21389      bufferAfter.push(startContainer.nodeValue.slice(startOffset).replaceAll(EOL_PATTERN, ""));
21390      if (parent !== this.editorDiv) {
21391        let buffer = bufferBefore;
21392        for (const child of this.editorDiv.childNodes) {
21393          if (child === parent) {
21394            buffer = bufferAfter;
21395            continue;
21396          }
21397          buffer.push(FreeTextEditor.#getNodeContent(child));
21398        }
21399      }
21400      bufferBefore.push(startContainer.nodeValue.slice(0, startOffset).replaceAll(EOL_PATTERN, ""));
21401    } else if (startContainer === this.editorDiv) {
21402      let buffer = bufferBefore;
21403      let i = 0;
21404      for (const child of this.editorDiv.childNodes) {
21405        if (i++ === startOffset) {
21406          buffer = bufferAfter;
21407        }
21408        buffer.push(FreeTextEditor.#getNodeContent(child));
21409      }
21410    }
21411    this.#content = `${bufferBefore.join("\n")}${paste}${bufferAfter.join("\n")}`;
21412    this.#setContent();
21413    const newRange = new Range();
21414    let beforeLength = Math.sumPrecise(bufferBefore.map(line => line.length));
21415    for (const {
21416      firstChild
21417    } of this.editorDiv.childNodes) {
21418      if (firstChild.nodeType === Node.TEXT_NODE) {
21419        const length = firstChild.nodeValue.length;
21420        if (beforeLength <= length) {
21421          newRange.setStart(firstChild, beforeLength);
21422          newRange.setEnd(firstChild, beforeLength);
21423          break;
21424        }
21425        beforeLength -= length;
21426      }
21427    }
21428    selection.removeAllRanges();
21429    selection.addRange(newRange);
21430  }
21431  #setContent() {
21432    this.editorDiv.replaceChildren();
21433    if (!this.#content) {
21434      return;
21435    }
21436    for (const line of this.#content.split("\n")) {
21437      const div = document.createElement("div");
21438      div.append(line ? document.createTextNode(line) : document.createElement("br"));
21439      this.editorDiv.append(div);
21440    }
21441  }
21442  #serializeContent() {
21443    return this.#content.replaceAll("\xa0", " ");
21444  }
21445  static #deserializeContent(content) {
21446    return content.replaceAll(" ", "\xa0");
21447  }
21448  get contentDiv() {
21449    return this.editorDiv;
21450  }
21451  getPDFRect() {
21452    const padding = FreeTextEditor._internalPadding * this.parentScale;
21453    return this.getRect(padding, padding);
21454  }
21455  static async deserialize(data, parent, uiManager) {
21456    let initialData = null;
21457    if (data instanceof FreeTextAnnotationElement) {
21458      const {
21459        data: {
21460          defaultAppearanceData: {
21461            fontSize,
21462            fontColor
21463          },
21464          rect,
21465          rotation,
21466          id,
21467          popupRef,
21468          richText,
21469          contentsObj,
21470          creationDate,
21471          modificationDate
21472        },
21473        textContent,
21474        textPosition,
21475        parent: {
21476          page: {
21477            pageNumber
21478          }
21479        }
21480      } = data;
21481      if (!textContent?.length) {
21482        return null;
21483      }
21484      initialData = data = {
21485        annotationType: AnnotationEditorType.FREETEXT,
21486        color: Array.from(fontColor),
21487        fontSize,
21488        value: textContent.join("\n"),
21489        position: textPosition,
21490        pageIndex: pageNumber - 1,
21491        rect: rect.slice(0),
21492        rotation,
21493        annotationElementId: id,
21494        id,
21495        deleted: false,
21496        popupRef,
21497        comment: contentsObj?.str || null,
21498        richText,
21499        creationDate,
21500        modificationDate
21501      };
21502    }
21503    const editor = await super.deserialize(data, parent, uiManager);
21504    editor.#fontSize = data.fontSize;
21505    editor.color = Util.makeHexColor(...data.color);
21506    editor.#content = FreeTextEditor.#deserializeContent(data.value);
21507    editor._initialData = initialData;
21508    if (data.comment) {
21509      editor.setCommentData(data);
21510    }
21511    return editor;
21512  }
21513  serialize(isForCopying = false) {
21514    if (this.isEmpty()) {
21515      return null;
21516    }
21517    if (this.deleted) {
21518      return this.serializeDeleted();
21519    }
21520    const color = AnnotationEditor._colorManager.convert(this.isAttachedToDOM ? getComputedStyle(this.editorDiv).color : this.color);
21521    const serialized = Object.assign(super.serialize(isForCopying), {
21522      color,
21523      fontSize: this.#fontSize,
21524      value: this.#serializeContent()
21525    });
21526    this.addComment(serialized);
21527    if (isForCopying) {
21528      serialized.isCopy = true;
21529      return serialized;
21530    }
21531    if (this.annotationElementId && !this.#hasElementChanged(serialized)) {
21532      return null;
21533    }
21534    serialized.id = this.annotationElementId;
21535    return serialized;
21536  }
21537  #hasElementChanged(serialized) {
21538    const {
21539      value,
21540      fontSize,
21541      color,
21542      pageIndex
21543    } = this._initialData;
21544    return this.hasEditedComment || this._hasBeenMoved || serialized.value !== value || serialized.fontSize !== fontSize || serialized.color.some((c, i) => c !== color[i]) || serialized.pageIndex !== pageIndex;
21545  }
21546  renderAnnotationElement(annotation) {
21547    const content = super.renderAnnotationElement(annotation);
21548    if (!content) {
21549      return null;
21550    }
21551    const {
21552      style
21553    } = content;
21554    style.fontSize = `calc(${this.#fontSize}px * var(--total-scale-factor))`;
21555    style.color = this.color;
21556    content.replaceChildren();
21557    for (const line of this.#content.split("\n")) {
21558      const div = document.createElement("div");
21559      div.append(line ? document.createTextNode(line) : document.createElement("br"));
21560      content.append(div);
21561    }
21562    annotation.updateEdited({
21563      rect: this.getPDFRect(),
21564      popup: this._uiManager.hasCommentManager() || this.hasEditedComment ? this.comment : {
21565        text: this.#content
21566      }
21567    });
21568    return content;
21569  }
21570  resetAnnotationElement(annotation) {
21571    super.resetAnnotationElement(annotation);
21572    annotation.resetEdited();
21573  }
21574}
21575
21576;// ./src/display/editor/draw
vendor: 3,038 bytes, lines 21576-21679
21576ers/outline.js
21577
21578class Outline {
21579  static PRECISION = 1e-4;
21580  toSVGPath() {
21581    unreachable("Abstract method `toSVGPath` must be implemented.");
21582  }
21583  get box() {
21584    unreachable("Abstract getter `box` must be implemented.");
21585  }
21586  serialize(_bbox, _rotation) {
21587    unreachable("Abstract method `serialize` must be implemented.");
21588  }
21589  static _rescale(src, tx, ty, sx, sy, dest) {
21590    dest ||= new Float32Array(src.length);
21591    for (let i = 0, ii = src.length; i < ii; i += 2) {
21592      dest[i] = tx + src[i] * sx;
21593      dest[i + 1] = ty + src[i + 1] * sy;
21594    }
21595    return dest;
21596  }
21597  static _rescaleAndSwap(src, tx, ty, sx, sy, dest) {
21598    dest ||= new Float32Array(src.length);
21599    for (let i = 0, ii = src.length; i < ii; i += 2) {
21600      dest[i] = tx + src[i + 1] * sx;
21601      dest[i + 1] = ty + src[i] * sy;
21602    }
21603    return dest;
21604  }
21605  static _translate(src, tx, ty, dest) {
21606    dest ||= new Float32Array(src.length);
21607    for (let i = 0, ii = src.length; i < ii; i += 2) {
21608      dest[i] = tx + src[i];
21609      dest[i + 1] = ty + src[i + 1];
21610    }
21611    return dest;
21612  }
21613  static svgRound(x) {
21614    return Math.round(x * 10000);
21615  }
21616  static _normalizePoint(x, y, parentWidth, parentHeight, rotation) {
21617    switch (rotation) {
21618      case 90:
21619        return [1 - y / parentWidth, x / parentHeight];
21620      case 180:
21621        return [1 - x / parentWidth, 1 - y / parentHeight];
21622      case 270:
21623        return [y / parentWidth, 1 - x / parentHeight];
21624      default:
21625        return [x / parentWidth, y / parentHeight];
21626    }
21627  }
21628  static createBezierPoints(x1, y1, x2, y2, x3, y3) {
21629    return [(x1 + 5 * x2) / 6, (y1 + 5 * y2) / 6, (5 * x2 + x3) / 6, (5 * y2 + y3) / 6, (x2 + x3) / 2, (y2 + y3) / 2];
21630  }
21631}
21632
21633;// ./src/display/editor/drawers/freedraw.js
21634
21635
21636class FreeDrawOutliner {
21637  #box;
21638  #bottom = [];
21639  #innerMargin;
21640  #isLTR;
21641  #top = [];
21642  #last = new Float32Array(18);
21643  #lastX;
21644  #lastY;
21645  #min;
21646  #min_dist;
21647  #scaleFactor;
21648  #thickness;
21649  #points = [];
21650  static #MIN_DIST = 8;
21651  static #MIN_DIFF = 2;
21652  static #MIN = FreeDrawOutliner.#MIN_DIST + FreeDrawOutliner.#MIN_DIFF;
21653  constructor({
21654    x,
21655    y
21656  }, box, scaleFactor, thickness, isLTR, innerMargin = 0) {
21657    this.#box = box;
21658    this.#thickness = thickness * scaleFactor;
21659    this.#isLTR = isLTR;
21660    this.#last.set([NaN, NaN, NaN, NaN, x, y], 6);
21661    this.#innerMargin = innerMargin;
21662    this.#min_dist = FreeDrawOutliner.#MIN_DIST * scaleFactor;
21663    this.#min = FreeDrawOutliner.#MIN * scaleFactor;
21664    this.#scaleFactor = scaleFactor;
21665    this.#points.push(x, y);
21666  }
21667  isEmpty() {
21668    return isNaN(this.#last[8]);
21669  }
21670  #getLastCoords() {
21671    const lastTop = this.#last.subarray(4, 6);
21672    const lastBottom = this.#last.subarray(16, 18);
21673    const [x, y, width, height] = this.#box;
21674    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];
21675  }
21676  add({
21677    x,
21678    y
21679  }
vendor: 12,363 bytes, lines 21679-21973
21679) {
21680    this.#lastX = x;
21681    this.#lastY = y;
21682    const [layerX, layerY, layerWidth, layerHeight] = this.#box;
21683    let [x1, y1, x2, y2] = this.#last.subarray(8, 12);
21684    const diffX = x - x2;
21685    const diffY = y - y2;
21686    const d = Math.hypot(diffX, diffY);
21687    if (d < this.#min) {
21688      return false;
21689    }
21690    const diffD = d - this.#min_dist;
21691    const K = diffD / d;
21692    const shiftX = K * diffX;
21693    const shiftY = K * diffY;
21694    let x0 = x1;
21695    let y0 = y1;
21696    x1 = x2;
21697    y1 = y2;
21698    x2 += shiftX;
21699    y2 += shiftY;
21700    this.#points?.push(x, y);
21701    const nX = -shiftY / diffD;
21702    const nY = shiftX / diffD;
21703    const thX = nX * this.#thickness;
21704    const thY = nY * this.#thickness;
21705    this.#last.set(this.#last.subarray(2, 8), 0);
21706    this.#last.set([x2 + thX, y2 + thY], 4);
21707    this.#last.set(this.#last.subarray(14, 18), 12);
21708    this.#last.set([x2 - thX, y2 - thY], 16);
21709    if (isNaN(this.#last[6])) {
21710      if (this.#top.length === 0) {
21711        this.#last.set([x1 + thX, y1 + thY], 2);
21712        this.#top.push(NaN, NaN, NaN, NaN, (x1 + thX - layerX) / layerWidth, (y1 + thY - layerY) / layerHeight);
21713        this.#last.set([x1 - thX, y1 - thY], 14);
21714        this.#bottom.push(NaN, NaN, NaN, NaN, (x1 - thX - layerX) / layerWidth, (y1 - thY - layerY) / layerHeight);
21715      }
21716      this.#last.set([x0, y0, x1, y1, x2, y2], 6);
21717      return !this.isEmpty();
21718    }
21719    this.#last.set([x0, y0, x1, y1, x2, y2], 6);
21720    const angle = Math.abs(Math.atan2(y0 - y1, x0 - x1) - Math.atan2(shiftY, shiftX));
21721    if (angle < Math.PI / 2) {
21722      [x1, y1, x2, y2] = this.#last.subarray(2, 6);
21723      this.#top.push(NaN, NaN, NaN, NaN, ((x1 + x2) / 2 - layerX) / layerWidth, ((y1 + y2) / 2 - layerY) / layerHeight);
21724      [x1, y1, x0, y0] = this.#last.subarray(14, 18);
21725      this.#bottom.push(NaN, NaN, NaN, NaN, ((x0 + x1) / 2 - layerX) / layerWidth, ((y0 + y1) / 2 - layerY) / layerHeight);
21726      return true;
21727    }
21728    [x0, y0, x1, y1, x2, y2] = this.#last.subarray(0, 6);
21729    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);
21730    [x2, y2, x1, y1, x0, y0] = this.#last.subarray(12, 18);
21731    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);
21732    return true;
21733  }
21734  toSVGPath() {
21735    if (this.isEmpty()) {
21736      return "";
21737    }
21738    const top = this.#top;
21739    const bottom = this.#bottom;
21740    if (isNaN(this.#last[6]) && !this.isEmpty()) {
21741      return this.#toSVGPathTwoPoints();
21742    }
21743    const buffer = [];
21744    buffer.push(`M${top[4]} ${top[5]}`);
21745    for (let i = 6; i < top.length; i += 6) {
21746      if (isNaN(top[i])) {
21747        buffer.push(`L${top[i + 4]} ${top[i + 5]}`);
21748      } else {
21749        buffer.push(`C${top[i]} ${top[i + 1]} ${top[i + 2]} ${top[i + 3]} ${top[i + 4]} ${top[i + 5]}`);
21750      }
21751    }
21752    this.#toSVGPathEnd(buffer);
21753    for (let i = bottom.length - 6; i >= 6; i -= 6) {
21754      if (isNaN(bottom[i])) {
21755        buffer.push(`L${bottom[i + 4]} ${bottom[i + 5]}`);
21756      } else {
21757        buffer.push(`C${bottom[i]} ${bottom[i + 1]} ${bottom[i + 2]} ${bottom[i + 3]} ${bottom[i + 4]} ${bottom[i + 5]}`);
21758      }
21759    }
21760    this.#toSVGPathStart(buffer);
21761    return buffer.join(" ");
21762  }
21763  #toSVGPathTwoPoints() {
21764    const [x, y, width, height] = this.#box;
21765    const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
21766    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`;
21767  }
21768  #toSVGPathStart(buffer) {
21769    const bottom = this.#bottom;
21770    buffer.push(`L${bottom[4]} ${bottom[5]} Z`);
21771  }
21772  #toSVGPathEnd(buffer) {
21773    const [x, y, width, height] = this.#box;
21774    const lastTop = this.#last.subarray(4, 6);
21775    const lastBottom = this.#last.subarray(16, 18);
21776    const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
21777    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}`);
21778  }
21779  newFreeDrawOutline(outline, points, box, scaleFactor, innerMargin, isLTR) {
21780    return new FreeDrawOutline(outline, points, box, scaleFactor, innerMargin, isLTR);
21781  }
21782  getOutlines() {
21783    const top = this.#top;
21784    const bottom = this.#bottom;
21785    const last = this.#last;
21786    const [layerX, layerY, layerWidth, layerHeight] = this.#box;
21787    const points = new Float32Array((this.#points?.length ?? 0) + 2);
21788    for (let i = 0, ii = points.length - 2; i < ii; i += 2) {
21789      points[i] = (this.#points[i] - layerX) / layerWidth;
21790      points[i + 1] = (this.#points[i + 1] - layerY) / layerHeight;
21791    }
21792    points[points.length - 2] = (this.#lastX - layerX) / layerWidth;
21793    points[points.length - 1] = (this.#lastY - layerY) / layerHeight;
21794    if (isNaN(last[6]) && !this.isEmpty()) {
21795      return this.#getOutlineTwoPoints(points);
21796    }
21797    const outline = new Float32Array(this.#top.length + 24 + this.#bottom.length);
21798    let N = top.length;
21799    for (let i = 0; i < N; i += 2) {
21800      if (isNaN(top[i])) {
21801        outline[i] = outline[i + 1] = NaN;
21802        continue;
21803      }
21804      outline[i] = top[i];
21805      outline[i + 1] = top[i + 1];
21806    }
21807    N = this.#getOutlineEnd(outline, N);
21808    for (let i = bottom.length - 6; i >= 6; i -= 6) {
21809      for (let j = 0; j < 6; j += 2) {
21810        if (isNaN(bottom[i + j])) {
21811          outline[N] = outline[N + 1] = NaN;
21812          N += 2;
21813          continue;
21814        }
21815        outline[N] = bottom[i + j];
21816        outline[N + 1] = bottom[i + j + 1];
21817        N += 2;
21818      }
21819    }
21820    this.#getOutlineStart(outline, N);
21821    return this.newFreeDrawOutline(outline, points, this.#box, this.#scaleFactor, this.#innerMargin, this.#isLTR);
21822  }
21823  #getOutlineTwoPoints(points) {
21824    const last = this.#last;
21825    const [layerX, layerY, layerWidth, layerHeight] = this.#box;
21826    const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
21827    const outline = new Float32Array(36);
21828    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);
21829    return this.newFreeDrawOutline(outline, points, this.#box, this.#scaleFactor, this.#innerMargin, this.#isLTR);
21830  }
21831  #getOutlineStart(outline, pos) {
21832    const bottom = this.#bottom;
21833    outline.set([NaN, NaN, NaN, NaN, bottom[4], bottom[5]], pos);
21834    return pos += 6;
21835  }
21836  #getOutlineEnd(outline, pos) {
21837    const lastTop = this.#last.subarray(4, 6);
21838    const lastBottom = this.#last.subarray(16, 18);
21839    const [layerX, layerY, layerWidth, layerHeight] = this.#box;
21840    const [lastTopX, lastTopY, lastBottomX, lastBottomY] = this.#getLastCoords();
21841    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);
21842    return pos += 24;
21843  }
21844}
21845class FreeDrawOutline extends Outline {
21846  #box;
21847  #bbox = new Float32Array(4);
21848  #innerMargin;
21849  #isLTR;
21850  #points;
21851  #scaleFactor;
21852  #outline;
21853  constructor(outline, points, box, scaleFactor, innerMargin, isLTR) {
21854    super();
21855    this.#outline = outline;
21856    this.#points = points;
21857    this.#box = box;
21858    this.#scaleFactor = scaleFactor;
21859    this.#innerMargin = innerMargin;
21860    this.#isLTR = isLTR;
21861    this.firstPoint = [NaN, NaN];
21862    this.lastPoint = [NaN, NaN];
21863    this.#computeMinMax(isLTR);
21864    const [x, y, width, height] = this.#bbox;
21865    for (let i = 0, ii = outline.length; i < ii; i += 2) {
21866      outline[i] = (outline[i] - x) / width;
21867      outline[i + 1] = (outline[i + 1] - y) / height;
21868    }
21869    for (let i = 0, ii = points.length; i < ii; i += 2) {
21870      points[i] = (points[i] - x) / width;
21871      points[i + 1] = (points[i + 1] - y) / height;
21872    }
21873  }
21874  toSVGPath() {
21875    const buffer = [`M${this.#outline[4]} ${this.#outline[5]}`];
21876    for (let i = 6, ii = this.#outline.length; i < ii; i += 6) {
21877      if (isNaN(this.#outline[i])) {
21878        buffer.push(`L${this.#outline[i + 4]} ${this.#outline[i + 5]}`);
21879        continue;
21880      }
21881      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]}`);
21882    }
21883    buffer.push("Z");
21884    return buffer.join(" ");
21885  }
21886  serialize([blX, blY, trX, trY], rotation) {
21887    const width = trX - blX;
21888    const height = trY - blY;
21889    let outline;
21890    let points;
21891    switch (rotation) {
21892      case 0:
21893        outline = Outline._rescale(this.#outline, blX, trY, width, -height);
21894        points = Outline._rescale(this.#points, blX, trY, width, -height);
21895        break;
21896      case 90:
21897        outline = Outline._rescaleAndSwap(this.#outline, blX, blY, width, height);
21898        points = Outline._rescaleAndSwap(this.#points, blX, blY, width, height);
21899        break;
21900      case 180:
21901        outline = Outline._rescale(this.#outline, trX, blY, -width, height);
21902        points = Outline._rescale(this.#points, trX, blY, -width, height);
21903        break;
21904      case 270:
21905        outline = Outline._rescaleAndSwap(this.#outline, trX, trY, -width, -height);
21906        points = Outline._rescaleAndSwap(this.#points, trX, trY, -width, -height);
21907        break;
21908    }
21909    return {
21910      outline: Array.from(outline),
21911      points: [Array.from(points)]
21912    };
21913  }
21914  #computeMinMax(isLTR) {
21915    const outline = this.#outline;
21916    let lastX = outline[4];
21917    let lastY = outline[5];
21918    const minMax = [lastX, lastY, lastX, lastY];
21919    let firstPointX = lastX;
21920    let firstPointY = lastY;
21921    let lastPointX = lastX;
21922    let lastPointY = lastY;
21923    const ltrCallback = isLTR ? Math.max : Math.min;
21924    const bezierBbox = new Float32Array(4);
21925    for (let i = 6, ii = outline.length; i < ii; i += 6) {
21926      const x = outline[i + 4],
21927        y = outline[i + 5];
21928      if (isNaN(outline[i])) {
21929        Util.pointBoundingBox(x, y, minMax);
21930        if (firstPointY > y) {
21931          firstPointX = x;
21932          firstPointY = y;
21933        } else if (firstPointY === y) {
21934          firstPointX = ltrCallback(firstPointX, x);
21935        }
21936        if (lastPointY < y) {
21937          lastPointX = x;
21938          lastPointY = y;
21939        } else if (lastPointY === y) {
21940          lastPointX = ltrCallback(lastPointX, x);
21941        }
21942      } else {
21943        bezierBbox.set(BBOX_INIT, 0);
21944        Util.bezierBoundingBox(lastX, lastY, ...outline.slice(i, i + 6), bezierBbox);
21945        Util.rectBoundingBox(...bezierBbox, minMax);
21946        if (firstPointY > bezierBbox[1]) {
21947          firstPointX = bezierBbox[0];
21948          firstPointY = bezierBbox[1];
21949        } else if (firstPointY === bezierBbox[1]) {
21950          firstPointX = ltrCallback(firstPointX, bezierBbox[0]);
21951        }
21952        if (lastPointY < bezierBbox[3]) {
21953          lastPointX = bezierBbox[2];
21954          lastPointY = bezierBbox[3];
21955        } else if (lastPointY === bezierBbox[3]) {
21956          lastPointX = ltrCallback(lastPointX, bezierBbox[2]);
21957        }
21958      }
21959      lastX = x;
21960      lastY = y;
21961    }
21962    const bbox = this.#bbox;
21963    bbox[0] = minMax[0] - this.#innerMargin;
21964    bbox[1] = minMax[1] - this.#innerMargin;
21965    bbox[2] = minMax[2] - minMax[0] + 2 * this.#innerMargin;
21966    bbox[3] = minMax[3] - minMax[1] + 2 * this.#innerMargin;
21967    this.firstPoint = [firstPointX, firstPointY];
21968    this.lastPoint = [lastPointX, lastPointY];
21969  }
21970  get box() {
21971    return this.#bbox;
21972  }
21973  newOutliner(
vendor: 35,838 bytes, lines 21973-23243
21973point, box, scaleFactor, thickness, isLTR, innerMargin = 0) {
21974    return new FreeDrawOutliner(point, box, scaleFactor, thickness, isLTR, innerMargin);
21975  }
21976  getNewOutline(thickness, innerMargin) {
21977    const [x, y, width, height] = this.#bbox;
21978    const [layerX, layerY, layerWidth, layerHeight] = this.#box;
21979    const sx = width * layerWidth;
21980    const sy = height * layerHeight;
21981    const tx = x * layerWidth + layerX;
21982    const ty = y * layerHeight + layerY;
21983    const outliner = this.newOutliner({
21984      x: this.#points[0] * sx + tx,
21985      y: this.#points[1] * sy + ty
21986    }, this.#box, this.#scaleFactor, thickness, this.#isLTR, innerMargin ?? this.#innerMargin);
21987    for (let i = 2; i < this.#points.length; i += 2) {
21988      outliner.add({
21989        x: this.#points[i] * sx + tx,
21990        y: this.#points[i + 1] * sy + ty
21991      });
21992    }
21993    return outliner.getOutlines();
21994  }
21995}
21996
21997;// ./src/display/editor/drawers/highlight.js
21998
21999
22000
22001class HighlightOutliner {
22002  #box;
22003  #firstPoint;
22004  #lastPoint;
22005  #verticalEdges = [];
22006  #intervals = [];
22007  constructor(boxes, borderWidth = 0, innerMargin = 0, isLTR = true) {
22008    const minMax = BBOX_INIT.slice();
22009    const NUMBER_OF_DIGITS = 4;
22010    const EPSILON = 10 ** -NUMBER_OF_DIGITS;
22011    for (const {
22012      x,
22013      y,
22014      width,
22015      height
22016    } of boxes) {
22017      const x1 = Math.floor((x - borderWidth) / EPSILON) * EPSILON;
22018      const x2 = Math.ceil((x + width + borderWidth) / EPSILON) * EPSILON;
22019      const y1 = Math.floor((y - borderWidth) / EPSILON) * EPSILON;
22020      const y2 = Math.ceil((y + height + borderWidth) / EPSILON) * EPSILON;
22021      const left = [x1, y1, y2, true];
22022      const right = [x2, y1, y2, false];
22023      this.#verticalEdges.push(left, right);
22024      Util.rectBoundingBox(x1, y1, x2, y2, minMax);
22025    }
22026    const bboxWidth = minMax[2] - minMax[0] + 2 * innerMargin;
22027    const bboxHeight = minMax[3] - minMax[1] + 2 * innerMargin;
22028    const shiftedMinX = minMax[0] - innerMargin;
22029    const shiftedMinY = minMax[1] - innerMargin;
22030    let firstPointX = isLTR ? -Infinity : Infinity;
22031    let firstPointY = Infinity;
22032    const lastEdge = this.#verticalEdges.at(isLTR ? -1 : -2);
22033    const lastPoint = [lastEdge[0], lastEdge[2]];
22034    for (const edge of this.#verticalEdges) {
22035      const [x, y1, y2, left] = edge;
22036      if (!left && isLTR) {
22037        if (y1 < firstPointY) {
22038          firstPointY = y1;
22039          firstPointX = x;
22040        } else if (y1 === firstPointY) {
22041          firstPointX = Math.max(firstPointX, x);
22042        }
22043      } else if (left && !isLTR) {
22044        if (y1 < firstPointY) {
22045          firstPointY = y1;
22046          firstPointX = x;
22047        } else if (y1 === firstPointY) {
22048          firstPointX = Math.min(firstPointX, x);
22049        }
22050      }
22051      edge[0] = (x - shiftedMinX) / bboxWidth;
22052      edge[1] = (y1 - shiftedMinY) / bboxHeight;
22053      edge[2] = (y2 - shiftedMinY) / bboxHeight;
22054    }
22055    this.#box = new Float32Array([shiftedMinX, shiftedMinY, bboxWidth, bboxHeight]);
22056    this.#firstPoint = [firstPointX, firstPointY];
22057    this.#lastPoint = lastPoint;
22058  }
22059  getOutlines() {
22060    this.#verticalEdges.sort((a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2]);
22061    const outlineVerticalEdges = [];
22062    for (const edge of this.#verticalEdges) {
22063      if (edge[3]) {
22064        outlineVerticalEdges.push(...this.#breakEdge(edge));
22065        this.#insert(edge);
22066      } else {
22067        this.#remove(edge);
22068        outlineVerticalEdges.push(...this.#breakEdge(edge));
22069      }
22070    }
22071    return this.#getOutlines(outlineVerticalEdges);
22072  }
22073  #getOutlines(outlineVerticalEdges) {
22074    const edges = [];
22075    const allEdges = new Set();
22076    for (const edge of outlineVerticalEdges) {
22077      const [x, y1, y2] = edge;
22078      edges.push([x, y1, edge], [x, y2, edge]);
22079    }
22080    edges.sort((a, b) => a[1] - b[1] || a[0] - b[0]);
22081    for (let i = 0, ii = edges.length; i < ii; i += 2) {
22082      const edge1 = edges[i][2];
22083      const edge2 = edges[i + 1][2];
22084      edge1.push(edge2);
22085      edge2.push(edge1);
22086      allEdges.add(edge1);
22087      allEdges.add(edge2);
22088    }
22089    const outlines = [];
22090    let outline;
22091    while (allEdges.size > 0) {
22092      const edge = allEdges.values().next().value;
22093      let [x, y1, y2, edge1, edge2] = edge;
22094      allEdges.delete(edge);
22095      let lastPointX = x;
22096      let lastPointY = y1;
22097      outline = [x, y2];
22098      outlines.push(outline);
22099      while (true) {
22100        let e;
22101        if (allEdges.has(edge1)) {
22102          e = edge1;
22103        } else if (allEdges.has(edge2)) {
22104          e = edge2;
22105        } else {
22106          break;
22107        }
22108        allEdges.delete(e);
22109        [x, y1, y2, edge1, edge2] = e;
22110        if (lastPointX !== x) {
22111          outline.push(lastPointX, lastPointY, x, lastPointY === y1 ? y1 : y2);
22112          lastPointX = x;
22113        }
22114        lastPointY = lastPointY === y1 ? y2 : y1;
22115      }
22116      outline.push(lastPointX, lastPointY);
22117    }
22118    return new HighlightOutline(outlines, this.#box, this.#firstPoint, this.#lastPoint);
22119  }
22120  #binarySearch(y) {
22121    const array = this.#intervals;
22122    let start = 0;
22123    let end = array.length - 1;
22124    while (start <= end) {
22125      const middle = start + end >> 1;
22126      const y1 = array[middle][0];
22127      if (y1 === y) {
22128        return middle;
22129      }
22130      if (y1 < y) {
22131        start = middle + 1;
22132      } else {
22133        end = middle - 1;
22134      }
22135    }
22136    return end + 1;
22137  }
22138  #insert([, y1, y2]) {
22139    const index = this.#binarySearch(y1);
22140    this.#intervals.splice(index, 0, [y1, y2]);
22141  }
22142  #remove([, y1, y2]) {
22143    const index = this.#binarySearch(y1);
22144    for (let i = index; i < this.#intervals.length; i++) {
22145      const [start, end] = this.#intervals[i];
22146      if (start !== y1) {
22147        break;
22148      }
22149      if (start === y1 && end === y2) {
22150        this.#intervals.splice(i, 1);
22151        return;
22152      }
22153    }
22154    for (let i = index - 1; i >= 0; i--) {
22155      const [start, end] = this.#intervals[i];
22156      if (start !== y1) {
22157        break;
22158      }
22159      if (start === y1 && end === y2) {
22160        this.#intervals.splice(i, 1);
22161        return;
22162      }
22163    }
22164  }
22165  #breakEdge(edge) {
22166    const [x, y1, y2] = edge;
22167    const results = [[x, y1, y2]];
22168    const index = this.#binarySearch(y2);
22169    for (let i = 0; i < index; i++) {
22170      const [start, end] = this.#intervals[i];
22171      for (let j = 0, jj = results.length; j < jj; j++) {
22172        const [, y3, y4] = results[j];
22173        if (end <= y3 || y4 <= start) {
22174          continue;
22175        }
22176        if (y3 >= start) {
22177          if (y4 > end) {
22178            results[j][1] = end;
22179          } else {
22180            if (jj === 1) {
22181              return [];
22182            }
22183            results.splice(j, 1);
22184            j--;
22185            jj--;
22186          }
22187          continue;
22188        }
22189        results[j][2] = start;
22190        if (y4 > end) {
22191          results.push([x, end, y4]);
22192        }
22193      }
22194    }
22195    return results;
22196  }
22197}
22198class HighlightOutline extends Outline {
22199  #box;
22200  #outlines;
22201  constructor(outlines, box, firstPoint, lastPoint) {
22202    super();
22203    this.#outlines = outlines;
22204    this.#box = box;
22205    this.firstPoint = firstPoint;
22206    this.lastPoint = lastPoint;
22207  }
22208  toSVGPath() {
22209    const buffer = [];
22210    for (const polygon of this.#outlines) {
22211      let [prevX, prevY] = polygon;
22212      buffer.push(`M${prevX} ${prevY}`);
22213      for (let i = 2; i < polygon.length; i += 2) {
22214        const x = polygon[i];
22215        const y = polygon[i + 1];
22216        if (x === prevX) {
22217          buffer.push(`V${y}`);
22218          prevY = y;
22219        } else if (y === prevY) {
22220          buffer.push(`H${x}`);
22221          prevX = x;
22222        }
22223      }
22224      buffer.push("Z");
22225    }
22226    return buffer.join(" ");
22227  }
22228  serialize([blX, blY, trX, trY], _rotation) {
22229    const outlines = [];
22230    const width = trX - blX;
22231    const height = trY - blY;
22232    for (const outline of this.#outlines) {
22233      const points = new Array(outline.length);
22234      for (let i = 0; i < outline.length; i += 2) {
22235        points[i] = blX + outline[i] * width;
22236        points[i + 1] = trY - outline[i + 1] * height;
22237      }
22238      outlines.push(points);
22239    }
22240    return outlines;
22241  }
22242  get box() {
22243    return this.#box;
22244  }
22245}
22246class FreeHighlightOutliner extends FreeDrawOutliner {
22247  newFreeDrawOutline(outline, points, box, scaleFactor, innerMargin, isLTR) {
22248    return new FreeHighlightOutline(outline, points, box, scaleFactor, innerMargin, isLTR);
22249  }
22250}
22251class FreeHighlightOutline extends FreeDrawOutline {
22252  newOutliner(point, box, scaleFactor, thickness, isLTR, innerMargin = 0) {
22253    return new FreeHighlightOutliner(point, box, scaleFactor, thickness, isLTR, innerMargin);
22254  }
22255}
22256
22257;// ./src/display/editor/highlight.js
22258
22259
22260
22261
22262
22263
22264
22265class HighlightEditor extends AnnotationEditor {
22266  #anchorNode = null;
22267  #anchorOffset = 0;
22268  #boxes;
22269  #clipPathId = null;
22270  #colorPicker = null;
22271  #focusOutlines = null;
22272  #focusNode = null;
22273  #focusOffset = 0;
22274  #highlightDiv = null;
22275  #highlightOutlines = null;
22276  #id = null;
22277  #isFreeHighlight = false;
22278  #firstPoint = null;
22279  #lastPoint = null;
22280  #outlineId = null;
22281  #text = "";
22282  #thickness;
22283  #methodOfCreation = "";
22284  static _defaultColor = null;
22285  static _defaultOpacity = 1;
22286  static _defaultThickness = 12;
22287  static _type = "highlight";
22288  static _editorType = AnnotationEditorType.HIGHLIGHT;
22289  static _freeHighlightId = -1;
22290  static _freeHighlight = null;
22291  static _freeHighlightClipId = "";
22292  static get _keyboardManager() {
22293    const proto = HighlightEditor.prototype;
22294    return shadow(this, "_keyboardManager", new KeyboardManager([[["ArrowLeft"], proto._moveCaret, {
22295      args: [0]
22296    }], [["ArrowRight"], proto._moveCaret, {
22297      args: [1]
22298    }], [["ArrowUp"], proto._moveCaret, {
22299      args: [2]
22300    }], [["ArrowDown"], proto._moveCaret, {
22301      args: [3]
22302    }]]));
22303  }
22304  constructor(params) {
22305    super({
22306      ...params,
22307      name: "highlightEditor"
22308    });
22309    this.color = params.color || HighlightEditor._defaultColor;
22310    this.#thickness = params.thickness || HighlightEditor._defaultThickness;
22311    this.opacity = params.opacity || HighlightEditor._defaultOpacity;
22312    this.#boxes = params.boxes || null;
22313    this.#methodOfCreation = params.methodOfCreation || "";
22314    this.#text = params.text || "";
22315    this._isDraggable = false;
22316    this.defaultL10nId = "pdfjs-editor-highlight-editor";
22317    if (params.highlightId > -1) {
22318      this.#isFreeHighlight = true;
22319      this.#createFreeOutlines(params);
22320      this.#addToDrawLayer();
22321    } else if (this.#boxes) {
22322      this.#anchorNode = params.anchorNode;
22323      this.#anchorOffset = params.anchorOffset;
22324      this.#focusNode = params.focusNode;
22325      this.#focusOffset = params.focusOffset;
22326      this.#createOutlines();
22327      this.#addToDrawLayer();
22328      this.rotate(this.rotation);
22329    }
22330    if (!this.annotationElementId) {
22331      this._uiManager.a11yAlert(AnnotationEditor._l10nAlert.highlight);
22332    }
22333  }
22334  get telemetryInitialData() {
22335    return {
22336      action: "added",
22337      type: this.#isFreeHighlight ? "free_highlight" : "highlight",
22338      color: this._uiManager.getNonHCMColorName(this.color),
22339      thickness: this.#thickness,
22340      methodOfCreation: this.#methodOfCreation
22341    };
22342  }
22343  get telemetryFinalData() {
22344    return {
22345      type: "highlight",
22346      color: this._uiManager.getNonHCMColorName(this.color)
22347    };
22348  }
22349  static computeTelemetryFinalData(data) {
22350    return {
22351      numberOfColors: data.get("color").size
22352    };
22353  }
22354  #createOutlines() {
22355    const outliner = new HighlightOutliner(this.#boxes, 0.001);
22356    this.#highlightOutlines = outliner.getOutlines();
22357    [this.x, this.y, this.width, this.height] = this.#highlightOutlines.box;
22358    const outlinerForOutline = new HighlightOutliner(this.#boxes, 0.0025, 0.001, this._uiManager.direction === "ltr");
22359    this.#focusOutlines = outlinerForOutline.getOutlines();
22360    const {
22361      firstPoint
22362    } = this.#highlightOutlines;
22363    this.#firstPoint = [(firstPoint[0] - this.x) / this.width, (firstPoint[1] - this.y) / this.height];
22364    const {
22365      lastPoint
22366    } = this.#focusOutlines;
22367    this.#lastPoint = [(lastPoint[0] - this.x) / this.width, (lastPoint[1] - this.y) / this.height];
22368  }
22369  #createFreeOutlines({
22370    highlightOutlines,
22371    highlightId,
22372    clipPathId
22373  }) {
22374    this.#highlightOutlines = highlightOutlines;
22375    const extraThickness = 1.5;
22376    this.#focusOutlines = highlightOutlines.getNewOutline(this.#thickness / 2 + extraThickness, 0.0025);
22377    if (highlightId >= 0) {
22378      this.#id = highlightId;
22379      this.#clipPathId = clipPathId;
22380      this.parent.drawLayer.finalizeDraw(highlightId, {
22381        bbox: highlightOutlines.box,
22382        path: {
22383          d: highlightOutlines.toSVGPath()
22384        }
22385      });
22386      this.#outlineId = this.parent.drawLayer.drawOutline({
22387        rootClass: {
22388          highlightOutline: true,
22389          free: true
22390        },
22391        bbox: this.#focusOutlines.box,
22392        path: {
22393          d: this.#focusOutlines.toSVGPath()
22394        }
22395      }, true);
22396    } else if (this.parent) {
22397      const angle = this.parent.viewport.rotation;
22398      this.parent.drawLayer.updateProperties(this.#id, {
22399        bbox: HighlightEditor.#rotateBbox(this.#highlightOutlines.box, (angle - this.rotation + 360) % 360),
22400        path: {
22401          d: highlightOutlines.toSVGPath()
22402        }
22403      });
22404      this.parent.drawLayer.updateProperties(this.#outlineId, {
22405        bbox: HighlightEditor.#rotateBbox(this.#focusOutlines.box, angle),
22406        path: {
22407          d: this.#focusOutlines.toSVGPath()
22408        }
22409      });
22410    }
22411    const [x, y, width, height] = highlightOutlines.box;
22412    switch (this.rotation) {
22413      case 0:
22414        this.x = x;
22415        this.y = y;
22416        this.width = width;
22417        this.height = height;
22418        break;
22419      case 90:
22420        {
22421          const [pageWidth, pageHeight] = this.parentDimensions;
22422          this.x = y;
22423          this.y = 1 - x;
22424          this.width = width * pageHeight / pageWidth;
22425          this.height = height * pageWidth / pageHeight;
22426          break;
22427        }
22428      case 180:
22429        this.x = 1 - x;
22430        this.y = 1 - y;
22431        this.width = width;
22432        this.height = height;
22433        break;
22434      case 270:
22435        {
22436          const [pageWidth, pageHeight] = this.parentDimensions;
22437          this.x = 1 - y;
22438          this.y = x;
22439          this.width = width * pageHeight / pageWidth;
22440          this.height = height * pageWidth / pageHeight;
22441          break;
22442        }
22443    }
22444    const {
22445      firstPoint
22446    } = highlightOutlines;
22447    this.#firstPoint = [(firstPoint[0] - x) / width, (firstPoint[1] - y) / height];
22448    const {
22449      lastPoint
22450    } = this.#focusOutlines;
22451    this.#lastPoint = [(lastPoint[0] - x) / width, (lastPoint[1] - y) / height];
22452  }
22453  static initialize(l10n, uiManager) {
22454    AnnotationEditor.initialize(l10n, uiManager);
22455    HighlightEditor._defaultColor ||= uiManager.highlightColors?.values().next().value || "#fff066";
22456  }
22457  static updateDefaultParams(type, value) {
22458    switch (type) {
22459      case AnnotationEditorParamsType.HIGHLIGHT_COLOR:
22460        HighlightEditor._defaultColor = value;
22461        break;
22462      case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS:
22463        HighlightEditor._defaultThickness = value;
22464        break;
22465    }
22466  }
22467  translateInPage(x, y) {}
22468  get toolbarPosition() {
22469    return this.#lastPoint;
22470  }
22471  get commentButtonPosition() {
22472    return this.#firstPoint;
22473  }
22474  updateParams(type, value) {
22475    switch (type) {
22476      case AnnotationEditorParamsType.HIGHLIGHT_COLOR:
22477        this.#updateColor(value);
22478        break;
22479      case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS:
22480        this.#updateThickness(value);
22481        break;
22482    }
22483  }
22484  static get defaultPropertiesToUpdate() {
22485    return [[AnnotationEditorParamsType.HIGHLIGHT_COLOR, HighlightEditor._defaultColor], [AnnotationEditorParamsType.HIGHLIGHT_THICKNESS, HighlightEditor._defaultThickness]];
22486  }
22487  get propertiesToUpdate() {
22488    return [[AnnotationEditorParamsType.HIGHLIGHT_COLOR, this.color || HighlightEditor._defaultColor], [AnnotationEditorParamsType.HIGHLIGHT_THICKNESS, this.#thickness || HighlightEditor._defaultThickness], [AnnotationEditorParamsType.HIGHLIGHT_FREE, this.#isFreeHighlight]];
22489  }
22490  onUpdatedColor() {
22491    this.parent?.drawLayer.updateProperties(this.#id, {
22492      root: {
22493        fill: this.color,
22494        "fill-opacity": this.opacity
22495      }
22496    });
22497    this.#colorPicker?.updateColor(this.color);
22498    super.onUpdatedColor();
22499  }
22500  #updateColor(color) {
22501    const setColorAndOpacity = (col, opa) => {
22502      this.color = col;
22503      this.opacity = opa;
22504      this.onUpdatedColor();
22505    };
22506    const savedColor = this.color;
22507    const savedOpacity = this.opacity;
22508    this.addCommands({
22509      cmd: setColorAndOpacity.bind(this, color, HighlightEditor._defaultOpacity),
22510      undo: setColorAndOpacity.bind(this, savedColor, savedOpacity),
22511      post: this._uiManager.updateUI.bind(this._uiManager, this),
22512      mustExec: true,
22513      type: AnnotationEditorParamsType.HIGHLIGHT_COLOR,
22514      overwriteIfSameType: true,
22515      keepUndo: true
22516    });
22517    this._reportTelemetry({
22518      action: "color_changed",
22519      color: this._uiManager.getNonHCMColorName(color)
22520    }, true);
22521  }
22522  #updateThickness(thickness) {
22523    const savedThickness = this.#thickness;
22524    const setThickness = th => {
22525      this.#thickness = th;
22526      this.#changeThickness(th);
22527    };
22528    this.addCommands({
22529      cmd: setThickness.bind(this, thickness),
22530      undo: setThickness.bind(this, savedThickness),
22531      post: this._uiManager.updateUI.bind(this._uiManager, this),
22532      mustExec: true,
22533      type: AnnotationEditorParamsType.INK_THICKNESS,
22534      overwriteIfSameType: true,
22535      keepUndo: true
22536    });
22537    this._reportTelemetry({
22538      action: "thickness_changed",
22539      thickness
22540    }, true);
22541  }
22542  get toolbarButtons() {
22543    if (this._uiManager.highlightColors) {
22544      const colorPicker = this.#colorPicker = new ColorPicker({
22545        editor: this
22546      });
22547      return [["colorPicker", colorPicker]];
22548    }
22549    return super.toolbarButtons;
22550  }
22551  disableEditing() {
22552    super.disableEditing();
22553    this.div.classList.toggle("disabled", true);
22554  }
22555  enableEditing() {
22556    super.enableEditing();
22557    this.div.classList.toggle("disabled", false);
22558  }
22559  fixAndSetPosition() {
22560    return super.fixAndSetPosition(this.#getRotation());
22561  }
22562  getBaseTranslation() {
22563    return [0, 0];
22564  }
22565  getRect(tx, ty) {
22566    return super.getRect(tx, ty, this.#getRotation());
22567  }
22568  onceAdded(focus) {
22569    if (!this.annotationElementId) {
22570      this.parent.addUndoableEditor(this);
22571    }
22572    if (focus) {
22573      this.div.focus();
22574    }
22575  }
22576  remove() {
22577    this.#cleanDrawLayer();
22578    this._reportTelemetry({
22579      action: "deleted"
22580    });
22581    super.remove();
22582  }
22583  rebuild() {
22584    if (!this.parent) {
22585      return;
22586    }
22587    super.rebuild();
22588    if (this.div === null) {
22589      return;
22590    }
22591    this.#addToDrawLayer();
22592    if (!this.isAttachedToDOM) {
22593      this.parent.add(this);
22594    }
22595  }
22596  setParent(parent) {
22597    let mustBeSelected = false;
22598    if (this.parent && !parent) {
22599      this.#cleanDrawLayer();
22600    } else if (parent) {
22601      this.#addToDrawLayer(parent);
22602      mustBeSelected = !this.parent && this.div?.classList.contains("selectedEditor");
22603    }
22604    super.setParent(parent);
22605    this.show(this._isVisible);
22606    if (mustBeSelected) {
22607      this.select();
22608    }
22609  }
22610  #changeThickness(thickness) {
22611    if (!this.#isFreeHighlight) {
22612      return;
22613    }
22614    this.#createFreeOutlines({
22615      highlightOutlines: this.#highlightOutlines.getNewOutline(thickness / 2)
22616    });
22617    this.fixAndSetPosition();
22618    this.setDims();
22619  }
22620  #cleanDrawLayer() {
22621    if (this.#id === null || !this.parent) {
22622      return;
22623    }
22624    this.parent.drawLayer.remove(this.#id);
22625    this.#id = null;
22626    this.parent.drawLayer.remove(this.#outlineId);
22627    this.#outlineId = null;
22628  }
22629  #addToDrawLayer(parent = this.parent) {
22630    if (this.#id !== null) {
22631      return;
22632    }
22633    ({
22634      id: this.#id,
22635      clipPathId: this.#clipPathId
22636    } = parent.drawLayer.draw({
22637      bbox: this.#highlightOutlines.box,
22638      root: {
22639        viewBox: "0 0 1 1",
22640        fill: this.color,
22641        "fill-opacity": this.opacity
22642      },
22643      rootClass: {
22644        highlight: true,
22645        free: this.#isFreeHighlight
22646      },
22647      path: {
22648        d: this.#highlightOutlines.toSVGPath()
22649      }
22650    }, false, true));
22651    this.#outlineId = parent.drawLayer.drawOutline({
22652      rootClass: {
22653        highlightOutline: true,
22654        free: this.#isFreeHighlight
22655      },
22656      bbox: this.#focusOutlines.box,
22657      path: {
22658        d: this.#focusOutlines.toSVGPath()
22659      }
22660    }, this.#isFreeHighlight);
22661    if (this.#highlightDiv) {
22662      this.#highlightDiv.style.clipPath = this.#clipPathId;
22663    }
22664  }
22665  static #rotateBbox([x, y, width, height], angle) {
22666    switch (angle) {
22667      case 90:
22668        return [1 - y - height, x, height, width];
22669      case 180:
22670        return [1 - x - width, 1 - y - height, width, height];
22671      case 270:
22672        return [y, 1 - x - width, height, width];
22673    }
22674    return [x, y, width, height];
22675  }
22676  rotate(angle) {
22677    const {
22678      drawLayer
22679    } = this.parent;
22680    let box;
22681    if (this.#isFreeHighlight) {
22682      angle = (angle - this.rotation + 360) % 360;
22683      box = HighlightEditor.#rotateBbox(this.#highlightOutlines.box, angle);
22684    } else {
22685      box = HighlightEditor.#rotateBbox([this.x, this.y, this.width, this.height], angle);
22686    }
22687    drawLayer.updateProperties(this.#id, {
22688      bbox: box,
22689      root: {
22690        "data-main-rotation": angle
22691      }
22692    });
22693    drawLayer.updateProperties(this.#outlineId, {
22694      bbox: HighlightEditor.#rotateBbox(this.#focusOutlines.box, angle),
22695      root: {
22696        "data-main-rotation": angle
22697      }
22698    });
22699  }
22700  render() {
22701    if (this.div) {
22702      return this.div;
22703    }
22704    const div = super.render();
22705    if (this.#text) {
22706      div.setAttribute("aria-label", this.#text);
22707      div.setAttribute("role", "mark");
22708    }
22709    if (this.#isFreeHighlight) {
22710      div.classList.add("free");
22711    } else {
22712      this.div.addEventListener("keydown", this.#keydown.bind(this), {
22713        signal: this._uiManager._signal
22714      });
22715    }
22716    const highlightDiv = this.#highlightDiv = document.createElement("div");
22717    div.append(highlightDiv);
22718    highlightDiv.setAttribute("aria-hidden", "true");
22719    highlightDiv.className = "internal";
22720    highlightDiv.style.clipPath = this.#clipPathId;
22721    this.setDims();
22722    bindEvents(this, this.#highlightDiv, ["pointerover", "pointerleave"]);
22723    this.enableEditing();
22724    return div;
22725  }
22726  pointerover() {
22727    if (!this.isSelected) {
22728      this.parent?.drawLayer.updateProperties(this.#outlineId, {
22729        rootClass: {
22730          hovered: true
22731        }
22732      });
22733    }
22734  }
22735  pointerleave() {
22736    if (!this.isSelected) {
22737      this.parent?.drawLayer.updateProperties(this.#outlineId, {
22738        rootClass: {
22739          hovered: false
22740        }
22741      });
22742    }
22743  }
22744  #keydown(event) {
22745    HighlightEditor._keyboardManager.exec(this, event);
22746  }
22747  _moveCaret(direction) {
22748    this.parent.unselect(this);
22749    switch (direction) {
22750      case 0:
22751      case 2:
22752        this.#setCaret(true);
22753        break;
22754      case 1:
22755      case 3:
22756        this.#setCaret(false);
22757        break;
22758    }
22759  }
22760  #setCaret(start) {
22761    if (!this.#anchorNode) {
22762      return;
22763    }
22764    const selection = window.getSelection();
22765    if (start) {
22766      selection.setPosition(this.#anchorNode, this.#anchorOffset);
22767    } else {
22768      selection.setPosition(this.#focusNode, this.#focusOffset);
22769    }
22770  }
22771  select() {
22772    super.select();
22773    if (!this.#outlineId) {
22774      return;
22775    }
22776    this.parent?.drawLayer.updateProperties(this.#outlineId, {
22777      rootClass: {
22778        hovered: false,
22779        selected: true
22780      }
22781    });
22782  }
22783  unselect() {
22784    super.unselect();
22785    if (!this.#outlineId) {
22786      return;
22787    }
22788    this.parent?.drawLayer.updateProperties(this.#outlineId, {
22789      rootClass: {
22790        selected: false
22791      }
22792    });
22793    if (!this.#isFreeHighlight) {
22794      this.#setCaret(false);
22795    }
22796  }
22797  get _mustFixPosition() {
22798    return !this.#isFreeHighlight;
22799  }
22800  show(visible = this._isVisible) {
22801    super.show(visible);
22802    if (this.parent) {
22803      this.parent.drawLayer.updateProperties(this.#id, {
22804        rootClass: {
22805          hidden: !visible
22806        }
22807      });
22808      this.parent.drawLayer.updateProperties(this.#outlineId, {
22809        rootClass: {
22810          hidden: !visible
22811        }
22812      });
22813    }
22814  }
22815  #getRotation() {
22816    return this.#isFreeHighlight ? this.rotation : 0;
22817  }
22818  #serializeBoxes() {
22819    if (this.#isFreeHighlight) {
22820      return null;
22821    }
22822    const [pageWidth, pageHeight] = this.pageDimensions;
22823    const [pageX, pageY] = this.pageTranslation;
22824    const boxes = this.#boxes;
22825    const quadPoints = new Float32Array(boxes.length * 8);
22826    let i = 0;
22827    for (const {
22828      x,
22829      y,
22830      width,
22831      height
22832    } of boxes) {
22833      const sx = x * pageWidth + pageX;
22834      const sy = (1 - y) * pageHeight + pageY;
22835      quadPoints[i] = quadPoints[i + 4] = sx;
22836      quadPoints[i + 1] = quadPoints[i + 3] = sy;
22837      quadPoints[i + 2] = quadPoints[i + 6] = sx + width * pageWidth;
22838      quadPoints[i + 5] = quadPoints[i + 7] = sy - height * pageHeight;
22839      i += 8;
22840    }
22841    return quadPoints;
22842  }
22843  #serializeOutlines(rect) {
22844    return this.#highlightOutlines.serialize(rect, this.#getRotation());
22845  }
22846  static startHighlighting(parent, isLTR, {
22847    target: textLayer,
22848    x,
22849    y
22850  }) {
22851    const {
22852      x: layerX,
22853      y: layerY,
22854      width: parentWidth,
22855      height: parentHeight
22856    } = textLayer.getBoundingClientRect();
22857    const ac = new AbortController();
22858    const signal = parent.combinedSignal(ac);
22859    const pointerUpCallback = e => {
22860      ac.abort();
22861      this.#endHighlight(parent, e);
22862    };
22863    window.addEventListener("blur", pointerUpCallback, {
22864      signal
22865    });
22866    window.addEventListener("pointerup", pointerUpCallback, {
22867      signal
22868    });
22869    window.addEventListener("pointerdown", stopEvent, {
22870      capture: true,
22871      passive: false,
22872      signal
22873    });
22874    window.addEventListener("contextmenu", noContextMenu, {
22875      signal
22876    });
22877    textLayer.addEventListener("pointermove", this.#highlightMove.bind(this, parent), {
22878      signal
22879    });
22880    this._freeHighlight = new FreeHighlightOutliner({
22881      x,
22882      y
22883    }, [layerX, layerY, parentWidth, parentHeight], parent.scale, this._defaultThickness / 2, isLTR, 0.001);
22884    ({
22885      id: this._freeHighlightId,
22886      clipPathId: this._freeHighlightClipId
22887    } = parent.drawLayer.draw({
22888      bbox: [0, 0, 1, 1],
22889      root: {
22890        viewBox: "0 0 1 1",
22891        fill: this._defaultColor,
22892        "fill-opacity": this._defaultOpacity
22893      },
22894      rootClass: {
22895        highlight: true,
22896        free: true
22897      },
22898      path: {
22899        d: this._freeHighlight.toSVGPath()
22900      }
22901    }, true, true));
22902  }
22903  static #highlightMove(parent, event) {
22904    if (this._freeHighlight.add(event)) {
22905      parent.drawLayer.updateProperties(this._freeHighlightId, {
22906        path: {
22907          d: this._freeHighlight.toSVGPath()
22908        }
22909      });
22910    }
22911  }
22912  static #endHighlight(parent, event) {
22913    if (!this._freeHighlight.isEmpty()) {
22914      parent.createAndAddNewEditor(event, false, {
22915        highlightId: this._freeHighlightId,
22916        highlightOutlines: this._freeHighlight.getOutlines(),
22917        clipPathId: this._freeHighlightClipId,
22918        methodOfCreation: "main_toolbar"
22919      });
22920    } else {
22921      parent.drawLayer.remove(this._freeHighlightId);
22922    }
22923    this._freeHighlightId = -1;
22924    this._freeHighlight = null;
22925    this._freeHighlightClipId = "";
22926  }
22927  static async deserialize(data, parent, uiManager) {
22928    let initialData = null;
22929    if (data instanceof HighlightAnnotationElement) {
22930      const {
22931        data: {
22932          quadPoints,
22933          rect,
22934          rotation,
22935          id,
22936          color,
22937          opacity,
22938          popupRef,
22939          richText,
22940          contentsObj,
22941          creationDate,
22942          modificationDate
22943        },
22944        parent: {
22945          page: {
22946            pageNumber
22947          }
22948        }
22949      } = data;
22950      initialData = data = {
22951        annotationType: AnnotationEditorType.HIGHLIGHT,
22952        color: Array.from(color),
22953        opacity,
22954        quadPoints,
22955        boxes: null,
22956        pageIndex: pageNumber - 1,
22957        rect: rect.slice(0),
22958        rotation,
22959        annotationElementId: id,
22960        id,
22961        deleted: false,
22962        popupRef,
22963        richText,
22964        comment: contentsObj?.str || null,
22965        creationDate,
22966        modificationDate
22967      };
22968    } else if (data instanceof InkAnnotationElement) {
22969      const {
22970        data: {
22971          inkLists,
22972          rect,
22973          rotation,
22974          id,
22975          color,
22976          borderStyle: {
22977            rawWidth: thickness
22978          },
22979          popupRef,
22980          richText,
22981          contentsObj,
22982          creationDate,
22983          modificationDate
22984        },
22985        parent: {
22986          page: {
22987            pageNumber
22988          }
22989        }
22990      } = data;
22991      initialData = data = {
22992        annotationType: AnnotationEditorType.HIGHLIGHT,
22993        color: Array.from(color),
22994        thickness,
22995        inkLists,
22996        boxes: null,
22997        pageIndex: pageNumber - 1,
22998        rect: rect.slice(0),
22999        rotation,
23000        annotationElementId: id,
23001        id,
23002        deleted: false,
23003        popupRef,
23004        richText,
23005        comment: contentsObj?.str || null,
23006        creationDate,
23007        modificationDate
23008      };
23009    }
23010    const {
23011      color,
23012      quadPoints,
23013      inkLists,
23014      outlines,
23015      opacity
23016    } = data;
23017    const editor = await super.deserialize(data, parent, uiManager);
23018    editor.color = Util.makeHexColor(...color);
23019    editor.opacity = opacity || 1;
23020    if (inkLists) {
23021      editor.#thickness = data.thickness;
23022    }
23023    editor._initialData = initialData;
23024    if (data.comment) {
23025      editor.setCommentData(data);
23026    }
23027    const [pageWidth, pageHeight] = editor.pageDimensions;
23028    const [pageX, pageY] = editor.pageTranslation;
23029    if (quadPoints) {
23030      const boxes = editor.#boxes = [];
23031      for (let i = 0; i < quadPoints.length; i += 8) {
23032        boxes.push({
23033          x: (quadPoints[i] - pageX) / pageWidth,
23034          y: 1 - (quadPoints[i + 1] - pageY) / pageHeight,
23035          width: (quadPoints[i + 2] - quadPoints[i]) / pageWidth,
23036          height: (quadPoints[i + 1] - quadPoints[i + 5]) / pageHeight
23037        });
23038      }
23039      editor.#createOutlines();
23040      editor.#addToDrawLayer();
23041      editor.rotate(editor.rotation);
23042    } else if (inkLists || outlines) {
23043      editor.#isFreeHighlight = true;
23044      const points = (inkLists || outlines.points)[0];
23045      const point = {
23046        x: points[0] - pageX,
23047        y: pageHeight - (points[1] - pageY)
23048      };
23049      const outliner = new FreeHighlightOutliner(point, [0, 0, pageWidth, pageHeight], 1, editor.#thickness / 2, true, 0.001);
23050      for (let i = 0, ii = points.length; i < ii; i += 2) {
23051        point.x = points[i] - pageX;
23052        point.y = pageHeight - (points[i + 1] - pageY);
23053        outliner.add(point);
23054      }
23055      const {
23056        id,
23057        clipPathId
23058      } = parent.drawLayer.draw({
23059        bbox: [0, 0, 1, 1],
23060        root: {
23061          viewBox: "0 0 1 1",
23062          fill: editor.color,
23063          "fill-opacity": editor._defaultOpacity
23064        },
23065        rootClass: {
23066          highlight: true,
23067          free: true
23068        },
23069        path: {
23070          d: outliner.toSVGPath()
23071        }
23072      }, true, true);
23073      editor.#createFreeOutlines({
23074        highlightOutlines: outliner.getOutlines(),
23075        highlightId: id,
23076        clipPathId
23077      });
23078      editor.#addToDrawLayer();
23079      editor.rotate(editor.parentRotation);
23080    }
23081    return editor;
23082  }
23083  serialize(isForCopying = false) {
23084    if (this.isEmpty() || isForCopying) {
23085      return null;
23086    }
23087    if (this.deleted) {
23088      return this.serializeDeleted();
23089    }
23090    const color = AnnotationEditor._colorManager.convert(this._uiManager.getNonHCMColor(this.color));
23091    const serialized = super.serialize(isForCopying);
23092    Object.assign(serialized, {
23093      color,
23094      opacity: this.opacity,
23095      thickness: this.#thickness,
23096      quadPoints: this.#serializeBoxes(),
23097      outlines: this.#serializeOutlines(serialized.rect)
23098    });
23099    this.addComment(serialized);
23100    if (this.annotationElementId && !this.#hasElementChanged(serialized)) {
23101      return null;
23102    }
23103    serialized.id = this.annotationElementId;
23104    return serialized;
23105  }
23106  #hasElementChanged(serialized) {
23107    const {
23108      color
23109    } = this._initialData;
23110    return this.hasEditedComment || serialized.color.some((c, i) => c !== color[i]);
23111  }
23112  renderAnnotationElement(annotation) {
23113    if (this.deleted) {
23114      annotation.hide();
23115      return null;
23116    }
23117    annotation.updateEdited({
23118      rect: this.getPDFRect(),
23119      popup: this.comment
23120    });
23121    return null;
23122  }
23123  static canCreateNewEmptyEditor() {
23124    return false;
23125  }
23126}
23127
23128;// ./src/display/editor/draw.js
23129
23130
23131
23132
23133class DrawingOptions {
23134  #svgProperties = Object.create(null);
23135  updateProperty(name, value) {
23136    this[name] = value;
23137    this.updateSVGProperty(name, value);
23138  }
23139  updateProperties(properties) {
23140    if (!properties) {
23141      return;
23142    }
23143    for (const [name, value] of Object.entries(properties)) {
23144      if (!name.startsWith("_")) {
23145        this.updateProperty(name, value);
23146      }
23147    }
23148  }
23149  updateSVGProperty(name, value) {
23150    this.#svgProperties[name] = value;
23151  }
23152  toSVGProperties() {
23153    const root = this.#svgProperties;
23154    this.#svgProperties = Object.create(null);
23155    return {
23156      root
23157    };
23158  }
23159  reset() {
23160    this.#svgProperties = Object.create(null);
23161  }
23162  updateAll(options = this) {
23163    this.updateProperties(options);
23164  }
23165  clone() {
23166    unreachable("Not implemented");
23167  }
23168}
23169class DrawingEditor extends AnnotationEditor {
23170  #drawOutlines = null;
23171  #mustBeCommitted;
23172  _colorPicker = null;
23173  _drawId = null;
23174  static _currentDrawId = -1;
23175  static _currentParent = null;
23176  static #currentDraw = null;
23177  static #currentDrawingAC = null;
23178  static #currentDrawingOptions = null;
23179  static _INNER_MARGIN = 3;
23180  constructor(params) {
23181    super(params);
23182    this.#mustBeCommitted = params.mustBeCommitted || false;
23183    this._addOutlines(params);
23184  }
23185  onUpdatedColor() {
23186    this._colorPicker?.update(this.color);
23187    super.onUpdatedColor();
23188  }
23189  onUpdatedOpacity() {
23190    this._colorPicker?.updateOpacity?.(this.opacity);
23191  }
23192  _addOutlines(params) {
23193    if (params.drawOutlines) {
23194      this.#createDrawOutlines(params);
23195      this.#addToDrawLayer();
23196    }
23197  }
23198  #createDrawOutlines({
23199    drawOutlines,
23200    drawId,
23201    drawingOptions
23202  }) {
23203    this.#drawOutlines = drawOutlines;
23204    this._drawingOptions ||= drawingOptions;
23205    if (!this.annotationElementId) {
23206      this._uiManager.a11yAlert(AnnotationEditor._l10nAlert[this.editorType]);
23207    }
23208    if (drawId >= 0) {
23209      this._drawId = drawId;
23210      this.parent.drawLayer.finalizeDraw(drawId, drawOutlines.defaultProperties);
23211    } else {
23212      this._drawId = this.#createDrawing(drawOutlines, this.parent);
23213    }
23214    this.#updateBbox(drawOutlines.box);
23215  }
23216  #createDrawing(drawOutlines, parent) {
23217    const {
23218      id
23219    } = parent.drawLayer.draw(DrawingEditor._mergeSVGProperties(this._drawingOptions.toSVGProperties(), drawOutlines.defaultSVGProperties), false, false);
23220    return id;
23221  }
23222  static _mergeSVGProperties(p1, p2) {
23223    const p1Keys = new Set(Object.keys(p1));
23224    for (const [key, value] of Object.entries(p2)) {
23225      if (p1Keys.has(key)) {
23226        Object.assign(p1[key], value);
23227      } else {
23228        p1[key] = value;
23229      }
23230    }
23231    return p1;
23232  }
23233  static getDefaultDrawingOptions(_options) {
23234    unreachable("Not implemented");
23235  }
23236  static get typesMap() {
23237    unreachable("Not implemented");
23238  }
23239  static get isDrawer() {
23240    return true;
23241  }
23242  static get supportMultipleDrawings() {
23243    return false;
vendor: 4,719 bytes, lines 23244-23389
23244  }
23245  static updateDefaultParams(type, value) {
23246    const propertyName = this.typesMap.get(type);
23247    if (propertyName) {
23248      this._defaultDrawingOptions.updateProperty(propertyName, value);
23249    }
23250    if (this._currentParent) {
23251      DrawingEditor.#currentDraw.updateProperty(propertyName, value);
23252      this._currentParent.drawLayer.updateProperties(this._currentDrawId, this._defaultDrawingOptions.toSVGProperties());
23253    }
23254  }
23255  updateParams(type, value) {
23256    const propertyName = this.constructor.typesMap.get(type);
23257    if (propertyName) {
23258      this._updateProperty(type, propertyName, value);
23259    }
23260  }
23261  static get defaultPropertiesToUpdate() {
23262    const properties = [];
23263    const options = this._defaultDrawingOptions;
23264    for (const [type, name] of this.typesMap) {
23265      properties.push([type, options[name]]);
23266    }
23267    return properties;
23268  }
23269  get propertiesToUpdate() {
23270    const properties = [];
23271    const {
23272      _drawingOptions
23273    } = this;
23274    for (const [type, name] of this.constructor.typesMap) {
23275      properties.push([type, _drawingOptions[name]]);
23276    }
23277    return properties;
23278  }
23279  _updateProperty(type, name, value) {
23280    const options = this._drawingOptions;
23281    const savedValue = options[name];
23282    const setter = val => {
23283      options.updateProperty(name, val);
23284      const bbox = this.#drawOutlines.updateProperty(name, val);
23285      if (bbox) {
23286        this.#updateBbox(bbox);
23287      }
23288      this.parent?.drawLayer.updateProperties(this._drawId, options.toSVGProperties());
23289      if (type === this.colorType) {
23290        this.onUpdatedColor();
23291      } else if (type === this.opacityType) {
23292        this.onUpdatedOpacity();
23293      }
23294    };
23295    this.addCommands({
23296      cmd: setter.bind(this, value),
23297      undo: setter.bind(this, savedValue),
23298      post: this._uiManager.updateUI.bind(this._uiManager, this),
23299      mustExec: true,
23300      type,
23301      overwriteIfSameType: true,
23302      keepUndo: true
23303    });
23304  }
23305  _updateColorAndOpacity(color, opacity) {
23306    const colorName = this.constructor.typesMap.get(this.colorType);
23307    const opacityName = this.constructor.typesMap.get(this.opacityType);
23308    const options = this._drawingOptions;
23309    const savedColor = options[colorName];
23310    const savedOpacity = options[opacityName];
23311    const setter = (c, op) => {
23312      options.updateProperty(colorName, c);
23313      options.updateProperty(opacityName, op);
23314      this.#drawOutlines.updateProperty(colorName, c);
23315      this.#drawOutlines.updateProperty(opacityName, op);
23316      this.parent?.drawLayer.updateProperties(this._drawId, options.toSVGProperties());
23317      this.onUpdatedColor();
23318      this.onUpdatedOpacity();
23319    };
23320    this.addCommands({
23321      cmd: setter.bind(this, color, opacity),
23322      undo: setter.bind(this, savedColor, savedOpacity),
23323      post: this._uiManager.updateUI.bind(this._uiManager, this),
23324      mustExec: true,
23325      type: AnnotationEditorParamsType.INK_COLOR_AND_OPACITY,
23326      overwriteIfSameType: true,
23327      keepUndo: true
23328    });
23329  }
23330  _onResizing() {
23331    this.parent?.drawLayer.updateProperties(this._drawId, DrawingEditor._mergeSVGProperties(this.#drawOutlines.getPathResizingSVGProperties(this.#convertToDrawSpace()), {
23332      bbox: this.#rotateBox()
23333    }));
23334  }
23335  _onResized() {
23336    this.parent?.drawLayer.updateProperties(this._drawId, DrawingEditor._mergeSVGProperties(this.#drawOutlines.getPathResizedSVGProperties(this.#convertToDrawSpace()), {
23337      bbox: this.#rotateBox()
23338    }));
23339  }
23340  _onTranslating(_x, _y) {
23341    this.parent?.drawLayer.updateProperties(this._drawId, {
23342      bbox: this.#rotateBox()
23343    });
23344  }
23345  _onTranslated() {
23346    this.parent?.drawLayer.updateProperties(this._drawId, DrawingEditor._mergeSVGProperties(this.#drawOutlines.getPathTranslatedSVGProperties(this.#convertToDrawSpace(), this.parentDimensions), {
23347      bbox: this.#rotateBox()
23348    }));
23349  }
23350  _onStartDragging() {
23351    this.parent?.drawLayer.updateProperties(this._drawId, {
23352      rootClass: {
23353        moving: true
23354      }
23355    });
23356  }
23357  _onStopDragging() {
23358    this.parent?.drawLayer.updateProperties(this._drawId, {
23359      rootClass: {
23360        moving: false
23361      }
23362    });
23363  }
23364  commit() {
23365    super.commit();
23366    this.disableEditMode();
23367    this.disableEditing();
23368  }
23369  disableEditing() {
23370    super.disableEditing();
23371    this.div.classList.toggle("disabled", true);
23372  }
23373  enableEditing() {
23374    super.enableEditing();
23375    this.div.classList.toggle("disabled", false);
23376  }
23377  getBaseTranslation() {
23378    return [0, 0];
23379  }
23380  get isResizable() {
23381    return true;
23382  }
23383  onceAdded(focus) {
23384    if (!this.annotationElementId) {
23385      this.parent.addUndoableEditor(this);
23386    }
23387    this._isDraggable = true;
23388    if (this.#mustBeCommitted) {
23389      this.#mustBeCommitted = false;
vendor: 6,101 bytes, lines 23390-23606
23390      this.commit();
23391      this.parent.setSelected(this);
23392      if (focus && this.isOnScreen) {
23393        this.div.focus();
23394      }
23395    }
23396  }
23397  remove() {
23398    this.#cleanDrawLayer();
23399    super.remove();
23400  }
23401  rebuild() {
23402    if (!this.parent) {
23403      return;
23404    }
23405    super.rebuild();
23406    if (this.div === null) {
23407      return;
23408    }
23409    this.#addToDrawLayer();
23410    this.#updateBbox(this.#drawOutlines.box);
23411    if (!this.isAttachedToDOM) {
23412      this.parent.add(this);
23413    }
23414  }
23415  setParent(parent) {
23416    let mustBeSelected = false;
23417    if (this.parent && !parent) {
23418      this._uiManager.removeShouldRescale(this);
23419      this.#cleanDrawLayer();
23420    } else if (parent) {
23421      this._uiManager.addShouldRescale(this);
23422      this.#addToDrawLayer(parent);
23423      mustBeSelected = !this.parent && this.div?.classList.contains("selectedEditor");
23424    }
23425    super.setParent(parent);
23426    if (mustBeSelected) {
23427      this.select();
23428    }
23429  }
23430  #cleanDrawLayer() {
23431    if (this._drawId === null || !this.parent) {
23432      return;
23433    }
23434    this.parent.drawLayer.remove(this._drawId);
23435    this._drawId = null;
23436    this._drawingOptions.reset();
23437  }
23438  #addToDrawLayer(parent = this.parent) {
23439    if (this._drawId !== null && this.parent === parent) {
23440      return;
23441    }
23442    if (this._drawId !== null) {
23443      this.parent.drawLayer.updateParent(this._drawId, parent.drawLayer);
23444      return;
23445    }
23446    this._drawingOptions.updateAll();
23447    this._drawId = this.#createDrawing(this.#drawOutlines, parent);
23448  }
23449  #convertToParentSpace([x, y, width, height]) {
23450    const {
23451      parentDimensions: [pW, pH],
23452      rotation
23453    } = this;
23454    switch (rotation) {
23455      case 90:
23456        return [y, 1 - x, width * (pH / pW), height * (pW / pH)];
23457      case 180:
23458        return [1 - x, 1 - y, width, height];
23459      case 270:
23460        return [1 - y, x, width * (pH / pW), height * (pW / pH)];
23461      default:
23462        return [x, y, width, height];
23463    }
23464  }
23465  #convertToDrawSpace() {
23466    const {
23467      x,
23468      y,
23469      width,
23470      height,
23471      parentDimensions: [pW, pH],
23472      rotation
23473    } = this;
23474    switch (rotation) {
23475      case 90:
23476        return [1 - y, x, width * (pW / pH), height * (pH / pW)];
23477      case 180:
23478        return [1 - x, 1 - y, width, height];
23479      case 270:
23480        return [y, 1 - x, width * (pW / pH), height * (pH / pW)];
23481      default:
23482        return [x, y, width, height];
23483    }
23484  }
23485  #updateBbox(bbox) {
23486    [this.x, this.y, this.width, this.height] = this.#convertToParentSpace(bbox);
23487    if (this.div) {
23488      this.fixAndSetPosition();
23489      this.setDims();
23490    }
23491    this._onResized();
23492  }
23493  #rotateBox() {
23494    const {
23495      x,
23496      y,
23497      width,
23498      height,
23499      rotation,
23500      parentRotation,
23501      parentDimensions: [pW, pH]
23502    } = this;
23503    switch ((rotation * 4 + parentRotation) / 90) {
23504      case 1:
23505        return [1 - y - height, x, height, width];
23506      case 2:
23507        return [1 - x - width, 1 - y - height, width, height];
23508      case 3:
23509        return [y, 1 - x - width, height, width];
23510      case 4:
23511        return [x, y - width * (pW / pH), height * (pH / pW), width * (pW / pH)];
23512      case 5:
23513        return [1 - y, x, width * (pW / pH), height * (pH / pW)];
23514      case 6:
23515        return [1 - x - height * (pH / pW), 1 - y, height * (pH / pW), width * (pW / pH)];
23516      case 7:
23517        return [y - width * (pW / pH), 1 - x - height * (pH / pW), width * (pW / pH), height * (pH / pW)];
23518      case 8:
23519        return [x - width, y - height, width, height];
23520      case 9:
23521        return [1 - y, x - width, height, width];
23522      case 10:
23523        return [1 - x, 1 - y, width, height];
23524      case 11:
23525        return [y - height, 1 - x, height, width];
23526      case 12:
23527        return [x - height * (pH / pW), y, height * (pH / pW), width * (pW / pH)];
23528      case 13:
23529        return [1 - y - width * (pW / pH), x - height * (pH / pW), width * (pW / pH), height * (pH / pW)];
23530      case 14:
23531        return [1 - x, 1 - y - width * (pW / pH), height * (pH / pW), width * (pW / pH)];
23532      case 15:
23533        return [y, 1 - x, width * (pW / pH), height * (pH / pW)];
23534      default:
23535        return [x, y, width, height];
23536    }
23537  }
23538  rotate() {
23539    if (!this.parent) {
23540      return;
23541    }
23542    this.parent.drawLayer.updateProperties(this._drawId, DrawingEditor._mergeSVGProperties({
23543      bbox: this.#rotateBox()
23544    }, this.#drawOutlines.updateRotation((this.parentRotation - this.rotation + 360) % 360)));
23545  }
23546  onScaleChanging() {
23547    if (!this.parent) {
23548      return;
23549    }
23550    this.#updateBbox(this.#drawOutlines.updateParentDimensions(this.parentDimensions, this.parent.scale));
23551  }
23552  static onScaleChangingWhenDrawing() {}
23553  render() {
23554    if (this.div) {
23555      return this.div;
23556    }
23557    let baseX, baseY;
23558    if (this._isCopy) {
23559      baseX = this.x;
23560      baseY = this.y;
23561    }
23562    const div = super.render();
23563    div.classList.add("draw");
23564    const drawDiv = document.createElement("div");
23565    div.append(drawDiv);
23566    drawDiv.setAttribute("aria-hidden", "true");
23567    drawDiv.className = "internal";
23568    this.setDims();
23569    this._uiManager.addShouldRescale(this);
23570    this.disableEditing();
23571    if (this._isCopy) {
23572      this._moveAfterPaste(baseX, baseY);
23573    }
23574    return div;
23575  }
23576  static createDrawerInstance(_x, _y, _parentWidth, _parentHeight, _rotation) {
23577    unreachable("Not implemented");
23578  }
23579  static startDrawing(parent, uiManager, _isLTR, event) {
23580    const {
23581      target,
23582      offsetX: x,
23583      offsetY: y,
23584      pointerId,
23585      pointerType
23586    } = event;
23587    if (CurrentPointers.isInitializedAndDifferentPointerType(pointerType)) {
23588      return;
23589    }
23590    const {
23591      viewport: {
23592        rotation
23593      }
23594    } = parent;
23595    const {
23596      width: parentWidth,
23597      height: parentHeight
23598    } = target.getBoundingClientRect();
23599    const ac = DrawingEditor.#currentDrawingAC = new AbortController();
23600    const signal = parent.combinedSignal(ac);
23601    CurrentPointers.setPointer(pointerType, pointerId);
23602    window.addEventListener("pointerup", e => {
23603      if (CurrentPointers.isSamePointerIdOrRemove(e.pointerId)) {
23604        this._endDraw(e);
23605      }
23606    }, {
vendor: 6,826 bytes, lines 23607-23831
23607      signal
23608    });
23609    window.addEventListener("pointercancel", e => {
23610      if (CurrentPointers.isSamePointerIdOrRemove(e.pointerId)) {
23611        this._currentParent.endDrawingSession();
23612      }
23613    }, {
23614      signal
23615    });
23616    window.addEventListener("pointerdown", e => {
23617      if (!CurrentPointers.isSamePointerType(e.pointerType)) {
23618        return;
23619      }
23620      CurrentPointers.initializeAndAddPointerId(e.pointerId);
23621      if (DrawingEditor.#currentDraw.isCancellable()) {
23622        DrawingEditor.#currentDraw.removeLastElement();
23623        if (DrawingEditor.#currentDraw.isEmpty()) {
23624          this._currentParent.endDrawingSession(true);
23625        } else {
23626          this._endDraw(null);
23627        }
23628      }
23629    }, {
23630      capture: true,
23631      passive: false,
23632      signal
23633    });
23634    window.addEventListener("contextmenu", noContextMenu, {
23635      signal
23636    });
23637    target.addEventListener("pointermove", this._drawMove.bind(this), {
23638      signal
23639    });
23640    target.addEventListener("touchmove", e => {
23641      if (CurrentPointers.isSameTimeStamp(e.timeStamp)) {
23642        stopEvent(e);
23643      }
23644    }, {
23645      signal
23646    });
23647    parent.toggleDrawing();
23648    uiManager._editorUndoBar?.hide();
23649    if (DrawingEditor.#currentDraw) {
23650      parent.drawLayer.updateProperties(this._currentDrawId, DrawingEditor.#currentDraw.startNew(x, y, parentWidth, parentHeight, rotation));
23651      return;
23652    }
23653    uiManager.updateUIForDefaultProperties(this);
23654    DrawingEditor.#currentDraw = this.createDrawerInstance(x, y, parentWidth, parentHeight, rotation);
23655    DrawingEditor.#currentDrawingOptions = this.getDefaultDrawingOptions();
23656    this._currentParent = parent;
23657    ({
23658      id: this._currentDrawId
23659    } = parent.drawLayer.draw(this._mergeSVGProperties(DrawingEditor.#currentDrawingOptions.toSVGProperties(), DrawingEditor.#currentDraw.defaultSVGProperties), true, false));
23660  }
23661  static _drawMove(event) {
23662    CurrentPointers.isSameTimeStamp(event.timeStamp);
23663    if (!DrawingEditor.#currentDraw) {
23664      return;
23665    }
23666    const {
23667      offsetX,
23668      offsetY,
23669      pointerId
23670    } = event;
23671    if (!CurrentPointers.isSamePointerId(pointerId)) {
23672      return;
23673    }
23674    if (CurrentPointers.isUsingMultiplePointers()) {
23675      this._endDraw(event);
23676      return;
23677    }
23678    this._currentParent.drawLayer.updateProperties(this._currentDrawId, DrawingEditor.#currentDraw.add(offsetX, offsetY));
23679    CurrentPointers.setTimeStamp(event.timeStamp);
23680    stopEvent(event);
23681  }
23682  static _cleanup(all) {
23683    if (all) {
23684      this._currentDrawId = -1;
23685      this._currentParent = null;
23686      DrawingEditor.#currentDraw = null;
23687      DrawingEditor.#currentDrawingOptions = null;
23688      CurrentPointers.clearTimeStamp();
23689    }
23690    if (DrawingEditor.#currentDrawingAC) {
23691      DrawingEditor.#currentDrawingAC.abort();
23692      DrawingEditor.#currentDrawingAC = null;
23693      CurrentPointers.clearPointerIds();
23694    }
23695  }
23696  static _endDraw(event) {
23697    const parent = this._currentParent;
23698    if (!parent) {
23699      return;
23700    }
23701    parent.toggleDrawing(true);
23702    this._cleanup(false);
23703    if (event?.target === parent.div) {
23704      parent.drawLayer.updateProperties(this._currentDrawId, DrawingEditor.#currentDraw.end(event.offsetX, event.offsetY));
23705    }
23706    if (this.supportMultipleDrawings) {
23707      const draw = DrawingEditor.#currentDraw;
23708      const drawId = this._currentDrawId;
23709      const lastElement = draw.getLastElement();
23710      parent.addCommands({
23711        cmd: () => {
23712          parent.drawLayer.updateProperties(drawId, draw.setLastElement(lastElement));
23713        },
23714        undo: () => {
23715          parent.drawLayer.updateProperties(drawId, draw.removeLastElement());
23716        },
23717        mustExec: false,
23718        type: AnnotationEditorParamsType.DRAW_STEP
23719      });
23720      return;
23721    }
23722    this.endDrawing(false);
23723  }
23724  static endDrawing(isAborted) {
23725    const parent = this._currentParent;
23726    if (!parent) {
23727      return null;
23728    }
23729    parent.toggleDrawing(true);
23730    parent.cleanUndoStack(AnnotationEditorParamsType.DRAW_STEP);
23731    if (!DrawingEditor.#currentDraw.isEmpty()) {
23732      const {
23733        pageDimensions: [pageWidth, pageHeight],
23734        scale
23735      } = parent;
23736      const editor = parent.createAndAddNewEditor({
23737        offsetX: 0,
23738        offsetY: 0
23739      }, false, {
23740        drawId: this._currentDrawId,
23741        drawOutlines: DrawingEditor.#currentDraw.getOutlines(pageWidth * scale, pageHeight * scale, scale, this._INNER_MARGIN),
23742        drawingOptions: DrawingEditor.#currentDrawingOptions,
23743        mustBeCommitted: !isAborted
23744      });
23745      this._cleanup(true);
23746      return editor;
23747    }
23748    parent.drawLayer.remove(this._currentDrawId);
23749    this._cleanup(true);
23750    return null;
23751  }
23752  createDrawingOptions(_data) {}
23753  static deserializeDraw(_pageX, _pageY, _pageWidth, _pageHeight, _innerWidth, _data) {
23754    unreachable("Not implemented");
23755  }
23756  static async deserialize(data, parent, uiManager) {
23757    const {
23758      rawDims: {
23759        pageWidth,
23760        pageHeight,
23761        pageX,
23762        pageY
23763      }
23764    } = parent.viewport;
23765    const drawOutlines = this.deserializeDraw(pageX, pageY, pageWidth, pageHeight, this._INNER_MARGIN, data);
23766    const editor = await super.deserialize(data, parent, uiManager);
23767    editor.createDrawingOptions(data);
23768    editor.#createDrawOutlines({
23769      drawOutlines
23770    });
23771    editor.#addToDrawLayer();
23772    editor.onScaleChanging();
23773    editor.rotate();
23774    return editor;
23775  }
23776  serializeDraw(isForCopying) {
23777    const [pageX, pageY] = this.pageTranslation;
23778    const [pageWidth, pageHeight] = this.pageDimensions;
23779    return this.#drawOutlines.serialize([pageX, pageY, pageWidth, pageHeight], isForCopying);
23780  }
23781  renderAnnotationElement(annotation) {
23782    annotation.updateEdited({
23783      rect: this.getPDFRect()
23784    });
23785    return null;
23786  }
23787  static canCreateNewEmptyEditor() {
23788    return false;
23789  }
23790}
23791
23792;// ./src/display/editor/drawers/inkdraw.js
23793
23794
23795
23796class InkDrawOutliner {
23797  #last = new Float64Array(6);
23798  #line;
23799  #lines;
23800  #rotation;
23801  #thickness;
23802  #points;
23803  #lastSVGPath = "";
23804  #lastIndex = 0;
23805  #outlines = new InkDrawOutline();
23806  #parentWidth;
23807  #parentHeight;
23808  constructor(x, y, parentWidth, parentHeight, rotation, thickness) {
23809    this.#parentWidth = parentWidth;
23810    this.#parentHeight = parentHeight;
23811    this.#rotation = rotation;
23812    this.#thickness = thickness;
23813    [x, y] = this.#normalizePoint(x, y);
23814    const line = this.#line = [NaN, NaN, NaN, NaN, x, y];
23815    this.#points = [x, y];
23816    this.#lines = [{
23817      line,
23818      points: this.#points
23819    }];
23820    this.#last.set(line, 0);
23821  }
23822  updateProperty(name, value) {
23823    if (name === "stroke-width") {
23824      this.#thickness = value;
23825    }
23826  }
23827  #normalizePoint(x, y) {
23828    return Outline._normalizePoint(x, y, this.#parentWidth, this.#parentHeight, this.#rotation);
23829  }
23830  isEmpty() {
23831    return !this.#lines?.length
vendor: 10,036 bytes, lines 23831-24185
23831;
23832  }
23833  isCancellable() {
23834    return this.#points.length <= 10;
23835  }
23836  add(x, y) {
23837    [x, y] = this.#normalizePoint(x, y);
23838    const [x1, y1, x2, y2] = this.#last.subarray(2, 6);
23839    const diffX = x - x2;
23840    const diffY = y - y2;
23841    const d = Math.hypot(this.#parentWidth * diffX, this.#parentHeight * diffY);
23842    if (d <= 2) {
23843      return null;
23844    }
23845    this.#points.push(x, y);
23846    if (isNaN(x1)) {
23847      this.#last.set([x2, y2, x, y], 2);
23848      this.#line.push(NaN, NaN, NaN, NaN, x, y);
23849      return {
23850        path: {
23851          d: this.toSVGPath()
23852        }
23853      };
23854    }
23855    if (isNaN(this.#last[0])) {
23856      this.#line.splice(6, 6);
23857    }
23858    this.#last.set([x1, y1, x2, y2, x, y], 0);
23859    this.#line.push(...Outline.createBezierPoints(x1, y1, x2, y2, x, y));
23860    return {
23861      path: {
23862        d: this.toSVGPath()
23863      }
23864    };
23865  }
23866  end(x, y) {
23867    const change = this.add(x, y);
23868    if (change) {
23869      return change;
23870    }
23871    if (this.#points.length === 2) {
23872      return {
23873        path: {
23874          d: this.toSVGPath()
23875        }
23876      };
23877    }
23878    return null;
23879  }
23880  startNew(x, y, parentWidth, parentHeight, rotation) {
23881    this.#parentWidth = parentWidth;
23882    this.#parentHeight = parentHeight;
23883    this.#rotation = rotation;
23884    [x, y] = this.#normalizePoint(x, y);
23885    const line = this.#line = [NaN, NaN, NaN, NaN, x, y];
23886    this.#points = [x, y];
23887    const last = this.#lines.at(-1);
23888    if (last) {
23889      last.line = new Float32Array(last.line);
23890      last.points = new Float32Array(last.points);
23891    }
23892    this.#lines.push({
23893      line,
23894      points: this.#points
23895    });
23896    this.#last.set(line, 0);
23897    this.#lastIndex = 0;
23898    this.toSVGPath();
23899    return null;
23900  }
23901  getLastElement() {
23902    return this.#lines.at(-1);
23903  }
23904  setLastElement(element) {
23905    if (!this.#lines) {
23906      return this.#outlines.setLastElement(element);
23907    }
23908    this.#lines.push(element);
23909    this.#line = element.line;
23910    this.#points = element.points;
23911    this.#lastIndex = 0;
23912    return {
23913      path: {
23914        d: this.toSVGPath()
23915      }
23916    };
23917  }
23918  removeLastElement() {
23919    if (!this.#lines) {
23920      return this.#outlines.removeLastElement();
23921    }
23922    this.#lines.pop();
23923    this.#lastSVGPath = "";
23924    for (let i = 0, ii = this.#lines.length; i < ii; i++) {
23925      const {
23926        line,
23927        points
23928      } = this.#lines[i];
23929      this.#line = line;
23930      this.#points = points;
23931      this.#lastIndex = 0;
23932      this.toSVGPath();
23933    }
23934    return {
23935      path: {
23936        d: this.#lastSVGPath
23937      }
23938    };
23939  }
23940  toSVGPath() {
23941    const firstX = Outline.svgRound(this.#line[4]);
23942    const firstY = Outline.svgRound(this.#line[5]);
23943    if (this.#points.length === 2) {
23944      this.#lastSVGPath = `${this.#lastSVGPath} M ${firstX} ${firstY} Z`;
23945      return this.#lastSVGPath;
23946    }
23947    if (this.#points.length <= 6) {
23948      const i = this.#lastSVGPath.lastIndexOf("M");
23949      this.#lastSVGPath = `${this.#lastSVGPath.slice(0, i)} M ${firstX} ${firstY}`;
23950      this.#lastIndex = 6;
23951    }
23952    if (this.#points.length === 4) {
23953      const secondX = Outline.svgRound(this.#line[10]);
23954      const secondY = Outline.svgRound(this.#line[11]);
23955      this.#lastSVGPath = `${this.#lastSVGPath} L ${secondX} ${secondY}`;
23956      this.#lastIndex = 12;
23957      return this.#lastSVGPath;
23958    }
23959    const buffer = [];
23960    if (this.#lastIndex === 0) {
23961      buffer.push(`M ${firstX} ${firstY}`);
23962      this.#lastIndex = 6;
23963    }
23964    for (let i = this.#lastIndex, ii = this.#line.length; i < ii; i += 6) {
23965      const [c1x, c1y, c2x, c2y, x, y] = this.#line.slice(i, i + 6).map(Outline.svgRound);
23966      buffer.push(`C${c1x} ${c1y} ${c2x} ${c2y} ${x} ${y}`);
23967    }
23968    this.#lastSVGPath += buffer.join(" ");
23969    this.#lastIndex = this.#line.length;
23970    return this.#lastSVGPath;
23971  }
23972  getOutlines(parentWidth, parentHeight, scale, innerMargin) {
23973    const last = this.#lines.at(-1);
23974    last.line = new Float32Array(last.line);
23975    last.points = new Float32Array(last.points);
23976    this.#outlines.build(this.#lines, parentWidth, parentHeight, scale, this.#rotation, this.#thickness, innerMargin);
23977    this.#last = null;
23978    this.#line = null;
23979    this.#lines = null;
23980    this.#lastSVGPath = null;
23981    return this.#outlines;
23982  }
23983  get defaultSVGProperties() {
23984    return {
23985      root: {
23986        viewBox: "0 0 10000 10000"
23987      },
23988      rootClass: {
23989        draw: true
23990      },
23991      bbox: [0, 0, 1, 1]
23992    };
23993  }
23994}
23995class InkDrawOutline extends Outline {
23996  #bbox;
23997  #currentRotation = 0;
23998  #innerMargin;
23999  #lines;
24000  #parentWidth;
24001  #parentHeight;
24002  #parentScale;
24003  #rotation;
24004  #thickness;
24005  build(lines, parentWidth, parentHeight, parentScale, rotation, thickness, innerMargin) {
24006    this.#parentWidth = parentWidth;
24007    this.#parentHeight = parentHeight;
24008    this.#parentScale = parentScale;
24009    this.#rotation = rotation;
24010    this.#thickness = thickness;
24011    this.#innerMargin = innerMargin ?? 0;
24012    this.#lines = lines;
24013    this.#computeBbox();
24014  }
24015  get thickness() {
24016    return this.#thickness;
24017  }
24018  setLastElement(element) {
24019    this.#lines.push(element);
24020    return {
24021      path: {
24022        d: this.toSVGPath()
24023      }
24024    };
24025  }
24026  removeLastElement() {
24027    this.#lines.pop();
24028    return {
24029      path: {
24030        d: this.toSVGPath()
24031      }
24032    };
24033  }
24034  toSVGPath() {
24035    const buffer = [];
24036    for (const {
24037      line
24038    } of this.#lines) {
24039      buffer.push(`M${Outline.svgRound(line[4])} ${Outline.svgRound(line[5])}`);
24040      if (line.length === 6) {
24041        buffer.push("Z");
24042        continue;
24043      }
24044      if (line.length === 12 && isNaN(line[6])) {
24045        buffer.push(`L${Outline.svgRound(line[10])} ${Outline.svgRound(line[11])}`);
24046        continue;
24047      }
24048      for (let i = 6, ii = line.length; i < ii; i += 6) {
24049        const [c1x, c1y, c2x, c2y, x, y] = line.subarray(i, i + 6).map(Outline.svgRound);
24050        buffer.push(`C${c1x} ${c1y} ${c2x} ${c2y} ${x} ${y}`);
24051      }
24052    }
24053    return buffer.join("");
24054  }
24055  serialize([pageX, pageY, pageWidth, pageHeight], isForCopying) {
24056    const serializedLines = [];
24057    const serializedPoints = [];
24058    const [x, y, width, height] = this.#getBBoxWithNoMargin();
24059    let tx, ty, sx, sy, x1, y1, x2, y2, rescaleFn;
24060    switch (this.#rotation) {
24061      case 0:
24062        rescaleFn = Outline._rescale;
24063        tx = pageX;
24064        ty = pageY + pageHeight;
24065        sx = pageWidth;
24066        sy = -pageHeight;
24067        x1 = pageX + x * pageWidth;
24068        y1 = pageY + (1 - y - height) * pageHeight;
24069        x2 = pageX + (x + width) * pageWidth;
24070        y2 = pageY + (1 - y) * pageHeight;
24071        break;
24072      case 90:
24073        rescaleFn = Outline._rescaleAndSwap;
24074        tx = pageX;
24075        ty = pageY;
24076        sx = pageWidth;
24077        sy = pageHeight;
24078        x1 = pageX + y * pageWidth;
24079        y1 = pageY + x * pageHeight;
24080        x2 = pageX + (y + height) * pageWidth;
24081        y2 = pageY + (x + width) * pageHeight;
24082        break;
24083      case 180:
24084        rescaleFn = Outline._rescale;
24085        tx = pageX + pageWidth;
24086        ty = pageY;
24087        sx = -pageWidth;
24088        sy = pageHeight;
24089        x1 = pageX + (1 - x - width) * pageWidth;
24090        y1 = pageY + y * pageHeight;
24091        x2 = pageX + (1 - x) * pageWidth;
24092        y2 = pageY + (y + height) * pageHeight;
24093        break;
24094      case 270:
24095        rescaleFn = Outline._rescaleAndSwap;
24096        tx = pageX + pageWidth;
24097        ty = pageY + pageHeight;
24098        sx = -pageWidth;
24099        sy = -pageHeight;
24100        x1 = pageX + (1 - y - height) * pageWidth;
24101        y1 = pageY + (1 - x - width) * pageHeight;
24102        x2 = pageX + (1 - y) * pageWidth;
24103        y2 = pageY + (1 - x) * pageHeight;
24104        break;
24105    }
24106    for (const {
24107      line,
24108      points
24109    } of this.#lines) {
24110      serializedLines.push(rescaleFn(line, tx, ty, sx, sy, isForCopying ? new Array(line.length) : null));
24111      serializedPoints.push(rescaleFn(points, tx, ty, sx, sy, isForCopying ? new Array(points.length) : null));
24112    }
24113    return {
24114      lines: serializedLines,
24115      points: serializedPoints,
24116      rect: [x1, y1, x2, y2]
24117    };
24118  }
24119  static deserialize(pageX, pageY, pageWidth, pageHeight, innerMargin, {
24120    paths: {
24121      lines,
24122      points
24123    },
24124    rotation,
24125    thickness
24126  }) {
24127    const newLines = [];
24128    let tx, ty, sx, sy, rescaleFn;
24129    switch (rotation) {
24130      case 0:
24131        rescaleFn = Outline._rescale;
24132        tx = -pageX / pageWidth;
24133        ty = pageY / pageHeight + 1;
24134        sx = 1 / pageWidth;
24135        sy = -1 / pageHeight;
24136        break;
24137      case 90:
24138        rescaleFn = Outline._rescaleAndSwap;
24139        tx = -pageY / pageHeight;
24140        ty = -pageX / pageWidth;
24141        sx = 1 / pageHeight;
24142        sy = 1 / pageWidth;
24143        break;
24144      case 180:
24145        rescaleFn = Outline._rescale;
24146        tx = pageX / pageWidth + 1;
24147        ty = -pageY / pageHeight;
24148        sx = -1 / pageWidth;
24149        sy = 1 / pageHeight;
24150        break;
24151      case 270:
24152        rescaleFn = Outline._rescaleAndSwap;
24153        tx = pageY / pageHeight + 1;
24154        ty = pageX / pageWidth + 1;
24155        sx = -1 / pageHeight;
24156        sy = -1 / pageWidth;
24157        break;
24158    }
24159    if (!lines) {
24160      lines = [];
24161      for (const point of points) {
24162        const len = point.length;
24163        if (len === 2) {
24164          lines.push(new Float32Array([NaN, NaN, NaN, NaN, point[0], point[1]]));
24165          continue;
24166        }
24167        if (len === 4) {
24168          lines.push(new Float32Array([NaN, NaN, NaN, NaN, point[0], point[1], NaN, NaN, NaN, NaN, point[2], point[3]]));
24169          continue;
24170        }
24171        const line = new Float32Array(3 * (len - 2));
24172        lines.push(line);
24173        let [x1, y1, x2, y2] = point.subarray(0, 4);
24174        line.set([NaN, NaN, NaN, NaN, x1, y1], 0);
24175        for (let i = 4; i < len; i += 2) {
24176          const x = point[i];
24177          const y = point[i + 1];
24178          line.set(Outline.createBezierPoints(x1, y1, x2, y2, x, y), (i - 2) * 3);
24179          [x1, y1, x2, y2] = [x2, y2, x, y];
24180        }
24181      }
24182    }
24183    for (let i = 0, ii = lines.length; i < ii; i++) {
24184      newLines.push({
24185        line: rescaleFn(lines[i].map(
vendor: 1,901 bytes, lines 24185-24237
24185x => x ?? NaN), tx, ty, sx, sy),
24186        points: rescaleFn(points[i].map(x => x ?? NaN), tx, ty, sx, sy)
24187      });
24188    }
24189    const outlines = new this.prototype.constructor();
24190    outlines.build(newLines, pageWidth, pageHeight, 1, rotation, thickness, innerMargin);
24191    return outlines;
24192  }
24193  #getMarginComponents(thickness = this.#thickness) {
24194    const margin = this.#innerMargin + thickness / 2 * this.#parentScale;
24195    return this.#rotation % 180 === 0 ? [margin / this.#parentWidth, margin / this.#parentHeight] : [margin / this.#parentHeight, margin / this.#parentWidth];
24196  }
24197  #getBBoxWithNoMargin() {
24198    const [x, y, width, height] = this.#bbox;
24199    const [marginX, marginY] = this.#getMarginComponents(0);
24200    return [x + marginX, y + marginY, width - 2 * marginX, height - 2 * marginY];
24201  }
24202  #computeBbox() {
24203    const bbox = this.#bbox = F32_BBOX_INIT.slice();
24204    for (const {
24205      line
24206    } of this.#lines) {
24207      if (line.length <= 12) {
24208        for (let i = 4, ii = line.length; i < ii; i += 6) {
24209          Util.pointBoundingBox(line[i], line[i + 1], bbox);
24210        }
24211        continue;
24212      }
24213      let lastX = line[4],
24214        lastY = line[5];
24215      for (let i = 6, ii = line.length; i < ii; i += 6) {
24216        const [c1x, c1y, c2x, c2y, x, y] = line.subarray(i, i + 6);
24217        Util.bezierBoundingBox(lastX, lastY, c1x, c1y, c2x, c2y, x, y, bbox);
24218        lastX = x;
24219        lastY = y;
24220      }
24221    }
24222    const [marginX, marginY] = this.#getMarginComponents();
24223    bbox[0] = MathClamp(bbox[0] - marginX, 0, 1);
24224    bbox[1] = MathClamp(bbox[1] - marginY, 0, 1);
24225    bbox[2] = MathClamp(bbox[2] + marginX, 0, 1);
24226    bbox[3] = MathClamp(bbox[3] + marginY, 0, 1);
24227    bbox[2] -= bbox[0];
24228    bbox[3] -= bbox[1];
24229  }
24230  get box() {
24231    return this.#bbox;
24232  }
24233  updateProperty(name, value) {
24234    if (name === "stroke-width") {
24235      return this.#updateThickness(value);
24236    }
24237    return
vendor: 8,392 bytes, lines 24237-24515
24237 null;
24238  }
24239  #updateThickness(thickness) {
24240    const [oldMarginX, oldMarginY] = this.#getMarginComponents();
24241    this.#thickness = thickness;
24242    const [newMarginX, newMarginY] = this.#getMarginComponents();
24243    const [diffMarginX, diffMarginY] = [newMarginX - oldMarginX, newMarginY - oldMarginY];
24244    const bbox = this.#bbox;
24245    bbox[0] -= diffMarginX;
24246    bbox[1] -= diffMarginY;
24247    bbox[2] += 2 * diffMarginX;
24248    bbox[3] += 2 * diffMarginY;
24249    return bbox;
24250  }
24251  updateParentDimensions([width, height], scale) {
24252    const [oldMarginX, oldMarginY] = this.#getMarginComponents();
24253    this.#parentWidth = width;
24254    this.#parentHeight = height;
24255    this.#parentScale = scale;
24256    const [newMarginX, newMarginY] = this.#getMarginComponents();
24257    const diffMarginX = newMarginX - oldMarginX;
24258    const diffMarginY = newMarginY - oldMarginY;
24259    const bbox = this.#bbox;
24260    bbox[0] -= diffMarginX;
24261    bbox[1] -= diffMarginY;
24262    bbox[2] += 2 * diffMarginX;
24263    bbox[3] += 2 * diffMarginY;
24264    return bbox;
24265  }
24266  updateRotation(rotation) {
24267    this.#currentRotation = rotation;
24268    return {
24269      path: {
24270        transform: this.rotationTransform
24271      }
24272    };
24273  }
24274  get viewBox() {
24275    return this.#bbox.map(Outline.svgRound).join(" ");
24276  }
24277  get defaultProperties() {
24278    const [x, y] = this.#bbox;
24279    return {
24280      root: {
24281        viewBox: this.viewBox
24282      },
24283      path: {
24284        "transform-origin": `${Outline.svgRound(x)} ${Outline.svgRound(y)}`
24285      }
24286    };
24287  }
24288  get rotationTransform() {
24289    const [,, width, height] = this.#bbox;
24290    let a = 0,
24291      b = 0,
24292      c = 0,
24293      d = 0,
24294      e = 0,
24295      f = 0;
24296    switch (this.#currentRotation) {
24297      case 90:
24298        b = height / width;
24299        c = -width / height;
24300        e = width;
24301        break;
24302      case 180:
24303        a = -1;
24304        d = -1;
24305        e = width;
24306        f = height;
24307        break;
24308      case 270:
24309        b = -height / width;
24310        c = width / height;
24311        f = height;
24312        break;
24313      default:
24314        return "";
24315    }
24316    return `matrix(${a} ${b} ${c} ${d} ${Outline.svgRound(e)} ${Outline.svgRound(f)})`;
24317  }
24318  getPathResizingSVGProperties([newX, newY, newWidth, newHeight]) {
24319    const [marginX, marginY] = this.#getMarginComponents();
24320    const [x, y, width, height] = this.#bbox;
24321    if (Math.abs(width - marginX) <= Outline.PRECISION || Math.abs(height - marginY) <= Outline.PRECISION) {
24322      const tx = newX + newWidth / 2 - (x + width / 2);
24323      const ty = newY + newHeight / 2 - (y + height / 2);
24324      return {
24325        path: {
24326          "transform-origin": `${Outline.svgRound(newX)} ${Outline.svgRound(newY)}`,
24327          transform: `${this.rotationTransform} translate(${tx} ${ty})`
24328        }
24329      };
24330    }
24331    const s1x = (newWidth - 2 * marginX) / (width - 2 * marginX);
24332    const s1y = (newHeight - 2 * marginY) / (height - 2 * marginY);
24333    const s2x = width / newWidth;
24334    const s2y = height / newHeight;
24335    return {
24336      path: {
24337        "transform-origin": `${Outline.svgRound(x)} ${Outline.svgRound(y)}`,
24338        transform: `${this.rotationTransform} scale(${s2x} ${s2y}) ` + `translate(${Outline.svgRound(marginX)} ${Outline.svgRound(marginY)}) scale(${s1x} ${s1y}) ` + `translate(${Outline.svgRound(-marginX)} ${Outline.svgRound(-marginY)})`
24339      }
24340    };
24341  }
24342  getPathResizedSVGProperties([newX, newY, newWidth, newHeight]) {
24343    const [marginX, marginY] = this.#getMarginComponents();
24344    const bbox = this.#bbox;
24345    const [x, y, width, height] = bbox;
24346    bbox[0] = newX;
24347    bbox[1] = newY;
24348    bbox[2] = newWidth;
24349    bbox[3] = newHeight;
24350    if (Math.abs(width - marginX) <= Outline.PRECISION || Math.abs(height - marginY) <= Outline.PRECISION) {
24351      const tx = newX + newWidth / 2 - (x + width / 2);
24352      const ty = newY + newHeight / 2 - (y + height / 2);
24353      for (const {
24354        line,
24355        points
24356      } of this.#lines) {
24357        Outline._translate(line, tx, ty, line);
24358        Outline._translate(points, tx, ty, points);
24359      }
24360      return {
24361        root: {
24362          viewBox: this.viewBox
24363        },
24364        path: {
24365          "transform-origin": `${Outline.svgRound(newX)} ${Outline.svgRound(newY)}`,
24366          transform: this.rotationTransform || null,
24367          d: this.toSVGPath()
24368        }
24369      };
24370    }
24371    const s1x = (newWidth - 2 * marginX) / (width - 2 * marginX);
24372    const s1y = (newHeight - 2 * marginY) / (height - 2 * marginY);
24373    const tx = -s1x * (x + marginX) + newX + marginX;
24374    const ty = -s1y * (y + marginY) + newY + marginY;
24375    if (s1x !== 1 || s1y !== 1 || tx !== 0 || ty !== 0) {
24376      for (const {
24377        line,
24378        points
24379      } of this.#lines) {
24380        Outline._rescale(line, tx, ty, s1x, s1y, line);
24381        Outline._rescale(points, tx, ty, s1x, s1y, points);
24382      }
24383    }
24384    return {
24385      root: {
24386        viewBox: this.viewBox
24387      },
24388      path: {
24389        "transform-origin": `${Outline.svgRound(newX)} ${Outline.svgRound(newY)}`,
24390        transform: this.rotationTransform || null,
24391        d: this.toSVGPath()
24392      }
24393    };
24394  }
24395  getPathTranslatedSVGProperties([newX, newY], parentDimensions) {
24396    const [newParentWidth, newParentHeight] = parentDimensions;
24397    const bbox = this.#bbox;
24398    const tx = newX - bbox[0];
24399    const ty = newY - bbox[1];
24400    if (this.#parentWidth === newParentWidth && this.#parentHeight === newParentHeight) {
24401      for (const {
24402        line,
24403        points
24404      } of this.#lines) {
24405        Outline._translate(line, tx, ty, line);
24406        Outline._translate(points, tx, ty, points);
24407      }
24408    } else {
24409      const sx = this.#parentWidth / newParentWidth;
24410      const sy = this.#parentHeight / newParentHeight;
24411      this.#parentWidth = newParentWidth;
24412      this.#parentHeight = newParentHeight;
24413      for (const {
24414        line,
24415        points
24416      } of this.#lines) {
24417        Outline._rescale(line, tx, ty, sx, sy, line);
24418        Outline._rescale(points, tx, ty, sx, sy, points);
24419      }
24420      bbox[2] *= sx;
24421      bbox[3] *= sy;
24422    }
24423    bbox[0] = newX;
24424    bbox[1] = newY;
24425    return {
24426      root: {
24427        viewBox: this.viewBox
24428      },
24429      path: {
24430        d: this.toSVGPath(),
24431        "transform-origin": `${Outline.svgRound(newX)} ${Outline.svgRound(newY)}`
24432      }
24433    };
24434  }
24435  get defaultSVGProperties() {
24436    const bbox = this.#bbox;
24437    return {
24438      root: {
24439        viewBox: this.viewBox
24440      },
24441      rootClass: {
24442        draw: true
24443      },
24444      path: {
24445        d: this.toSVGPath(),
24446        "transform-origin": `${Outline.svgRound(bbox[0])} ${Outline.svgRound(bbox[1])}`,
24447        transform: this.rotationTransform || null
24448      },
24449      bbox
24450    };
24451  }
24452}
24453
24454;// ./src/display/editor/ink.js
24455
24456
24457
24458
24459
24460
24461class InkDrawingOptions extends DrawingOptions {
24462  constructor(viewerParameters) {
24463    super();
24464    this._viewParameters = viewerParameters;
24465    super.updateProperties({
24466      fill: "none",
24467      stroke: AnnotationEditor._defaultLineColor,
24468      "stroke-opacity": 1,
24469      "stroke-width": 1,
24470      "stroke-linecap": "round",
24471      "stroke-linejoin": "round",
24472      "stroke-miterlimit": 10
24473    });
24474  }
24475  updateSVGProperty(name, value) {
24476    if (name === "stroke-width") {
24477      value ??= this["stroke-width"];
24478      value *= this._viewParameters.realScale;
24479    }
24480    super.updateSVGProperty(name, value);
24481  }
24482  clone() {
24483    const clone = new InkDrawingOptions(this._viewParameters);
24484    clone.updateAll(this);
24485    return clone;
24486  }
24487}
24488class InkEditor extends DrawingEditor {
24489  static _type = "ink";
24490  static _editorType = AnnotationEditorType.INK;
24491  static _defaultDrawingOptions = null;
24492  constructor(params) {
24493    super({
24494      ...params,
24495      name: "inkEditor"
24496    });
24497    this._willKeepAspectRatio = true;
24498    this.defaultL10nId = "pdfjs-editor-ink-editor";
24499  }
24500  static initialize(l10n, uiManager) {
24501    AnnotationEditor.initialize(l10n, uiManager);
24502    this._defaultDrawingOptions = new InkDrawingOptions(uiManager.viewParameters);
24503  }
24504  static getDefaultDrawingOptions(options) {
24505    const clone = this._defaultDrawingOptions.clone();
24506    clone.updateProperties(options);
24507    return clone;
24508  }
24509  static get supportMultipleDrawings() {
24510    return true;
24511  }
24512  static get typesMap() {
24513    return shadow(this, "typesMap", new Map([[AnnotationEditorParamsType.INK_THICKNESS, "stroke-width"], [AnnotationEditorParamsType.INK_COLOR, "stroke"], [AnnotationEditorParamsType.INK_OPACITY, "stroke-opacity"]]));
24514  }
24515  static createDrawerInstance(
24515x, y, parentWidth, parentHeight, rotation) {
24516    return new InkDrawOutliner(x, y, parentWidth, parentH
vendor: 29,877 bytes, lines 24516-25546
24516eight, rotation, this._defaultDrawingOptions["stroke-width"]);
24517  }
24518  static deserializeDraw(pageX, pageY, pageWidth, pageHeight, innerMargin, data) {
24519    return InkDrawOutline.deserialize(pageX, pageY, pageWidth, pageHeight, innerMargin, data);
24520  }
24521  static async deserialize(data, parent, uiManager) {
24522    let initialData = null;
24523    if (data instanceof InkAnnotationElement) {
24524      const {
24525        data: {
24526          inkLists,
24527          rect,
24528          rotation,
24529          id,
24530          color,
24531          opacity,
24532          borderStyle: {
24533            rawWidth: thickness
24534          },
24535          popupRef,
24536          richText,
24537          contentsObj,
24538          creationDate,
24539          modificationDate
24540        },
24541        parent: {
24542          page: {
24543            pageNumber
24544          }
24545        }
24546      } = data;
24547      initialData = data = {
24548        annotationType: AnnotationEditorType.INK,
24549        color: Array.from(color),
24550        thickness,
24551        opacity,
24552        paths: {
24553          points: inkLists
24554        },
24555        boxes: null,
24556        pageIndex: pageNumber - 1,
24557        rect: rect.slice(0),
24558        rotation,
24559        annotationElementId: id,
24560        id,
24561        deleted: false,
24562        popupRef,
24563        richText,
24564        comment: contentsObj?.str || null,
24565        creationDate,
24566        modificationDate
24567      };
24568    }
24569    const editor = await super.deserialize(data, parent, uiManager);
24570    editor._initialData = initialData;
24571    if (data.comment) {
24572      editor.setCommentData(data);
24573    }
24574    return editor;
24575  }
24576  get toolbarButtons() {
24577    this._colorPicker ||= new BasicColorPicker(this);
24578    return [["colorPicker", this._colorPicker]];
24579  }
24580  get colorType() {
24581    return AnnotationEditorParamsType.INK_COLOR;
24582  }
24583  get colorAndOpacityType() {
24584    return AnnotationEditorParamsType.INK_COLOR_AND_OPACITY;
24585  }
24586  get opacityType() {
24587    return AnnotationEditorParamsType.INK_OPACITY;
24588  }
24589  updateParams(type, value) {
24590    if (type === AnnotationEditorParamsType.INK_COLOR_AND_OPACITY) {
24591      this._updateColorAndOpacity(value.color, value.opacity);
24592      return;
24593    }
24594    super.updateParams(type, value);
24595  }
24596  static updateDefaultParams(type, value) {
24597    if (type === AnnotationEditorParamsType.INK_COLOR_AND_OPACITY) {
24598      super.updateDefaultParams(AnnotationEditorParamsType.INK_COLOR, value.color);
24599      super.updateDefaultParams(AnnotationEditorParamsType.INK_OPACITY, value.opacity);
24600      return;
24601    }
24602    super.updateDefaultParams(type, value);
24603  }
24604  get color() {
24605    return this._drawingOptions.stroke;
24606  }
24607  get opacity() {
24608    return this._drawingOptions["stroke-opacity"];
24609  }
24610  onScaleChanging() {
24611    if (!this.parent) {
24612      return;
24613    }
24614    super.onScaleChanging();
24615    const {
24616      _drawId,
24617      _drawingOptions,
24618      parent
24619    } = this;
24620    _drawingOptions.updateSVGProperty("stroke-width");
24621    parent.drawLayer.updateProperties(_drawId, _drawingOptions.toSVGProperties());
24622  }
24623  static onScaleChangingWhenDrawing() {
24624    const parent = this._currentParent;
24625    if (!parent) {
24626      return;
24627    }
24628    super.onScaleChangingWhenDrawing();
24629    this._defaultDrawingOptions.updateSVGProperty("stroke-width");
24630    parent.drawLayer.updateProperties(this._currentDrawId, this._defaultDrawingOptions.toSVGProperties());
24631  }
24632  createDrawingOptions({
24633    color,
24634    thickness,
24635    opacity
24636  }) {
24637    this._drawingOptions = InkEditor.getDefaultDrawingOptions({
24638      stroke: Util.makeHexColor(...color),
24639      "stroke-width": thickness,
24640      "stroke-opacity": opacity
24641    });
24642  }
24643  serialize(isForCopying = false) {
24644    if (this.isEmpty()) {
24645      return null;
24646    }
24647    if (this.deleted) {
24648      return this.serializeDeleted();
24649    }
24650    const {
24651      lines,
24652      points
24653    } = this.serializeDraw(isForCopying);
24654    const {
24655      _drawingOptions: {
24656        stroke,
24657        "stroke-opacity": opacity,
24658        "stroke-width": thickness
24659      }
24660    } = this;
24661    const serialized = Object.assign(super.serialize(isForCopying), {
24662      color: AnnotationEditor._colorManager.convert(stroke),
24663      opacity,
24664      thickness,
24665      paths: {
24666        lines,
24667        points
24668      }
24669    });
24670    this.addComment(serialized);
24671    if (isForCopying) {
24672      serialized.isCopy = true;
24673      return serialized;
24674    }
24675    if (this.annotationElementId && !this.#hasElementChanged(serialized)) {
24676      return null;
24677    }
24678    serialized.id = this.annotationElementId;
24679    return serialized;
24680  }
24681  #hasElementChanged(serialized) {
24682    const {
24683      color,
24684      thickness,
24685      opacity,
24686      pageIndex
24687    } = this._initialData;
24688    return this.hasEditedComment || this._hasBeenMoved || this._hasBeenResized || serialized.color.some((c, i) => c !== color[i]) || serialized.thickness !== thickness || serialized.opacity !== opacity || serialized.pageIndex !== pageIndex;
24689  }
24690  renderAnnotationElement(annotation) {
24691    if (this.deleted) {
24692      annotation.hide();
24693      return null;
24694    }
24695    const {
24696      points,
24697      rect
24698    } = this.serializeDraw(false);
24699    annotation.updateEdited({
24700      rect,
24701      thickness: this._drawingOptions["stroke-width"],
24702      points,
24703      popup: this.comment
24704    });
24705    return null;
24706  }
24707}
24708
24709;// ./src/display/editor/drawers/contour.js
24710
24711class ContourDrawOutline extends InkDrawOutline {
24712  toSVGPath() {
24713    let path = super.toSVGPath();
24714    if (!path.endsWith("Z")) {
24715      path += "Z";
24716    }
24717    return path;
24718  }
24719}
24720
24721;// ./src/display/editor/drawers/signaturedraw.js
24722
24723
24724
24725
24726const BASE_HEADER_LENGTH = 8;
24727const POINTS_PROPERTIES_NUMBER = 3;
24728class SignatureExtractor {
24729  static #PARAMETERS = {
24730    maxDim: 512,
24731    sigmaSFactor: 0.02,
24732    sigmaR: 25,
24733    kernelSize: 16
24734  };
24735  static #neighborIndexToId(i0, j0, i, j) {
24736    i -= i0;
24737    j -= j0;
24738    if (i === 0) {
24739      return j > 0 ? 0 : 4;
24740    }
24741    if (i === 1) {
24742      return j + 6;
24743    }
24744    return 2 - j;
24745  }
24746  static #neighborIdToIndex = new Int32Array([0, 1, -1, 1, -1, 0, -1, -1, 0, -1, 1, -1, 1, 0, 1, 1]);
24747  static #clockwiseNonZero(buf, width, i0, j0, i, j, offset) {
24748    const id = this.#neighborIndexToId(i0, j0, i, j);
24749    for (let k = 0; k < 8; k++) {
24750      const kk = (-k + id - offset + 16) % 8;
24751      const shiftI = this.#neighborIdToIndex[2 * kk];
24752      const shiftJ = this.#neighborIdToIndex[2 * kk + 1];
24753      if (buf[(i0 + shiftI) * width + (j0 + shiftJ)] !== 0) {
24754        return kk;
24755      }
24756    }
24757    return -1;
24758  }
24759  static #counterClockwiseNonZero(buf, width, i0, j0, i, j, offset) {
24760    const id = this.#neighborIndexToId(i0, j0, i, j);
24761    for (let k = 0; k < 8; k++) {
24762      const kk = (k + id + offset + 16) % 8;
24763      const shiftI = this.#neighborIdToIndex[2 * kk];
24764      const shiftJ = this.#neighborIdToIndex[2 * kk + 1];
24765      if (buf[(i0 + shiftI) * width + (j0 + shiftJ)] !== 0) {
24766        return kk;
24767      }
24768    }
24769    return -1;
24770  }
24771  static #findContours(buf, width, height, threshold) {
24772    const N = buf.length;
24773    const types = new Int32Array(N);
24774    for (let i = 0; i < N; i++) {
24775      types[i] = buf[i] <= threshold ? 1 : 0;
24776    }
24777    for (let i = 1; i < height - 1; i++) {
24778      types[i * width] = types[i * width + width - 1] = 0;
24779    }
24780    for (let i = 0; i < width; i++) {
24781      types[i] = types[width * height - 1 - i] = 0;
24782    }
24783    let nbd = 1;
24784    let lnbd;
24785    const contours = [];
24786    for (let i = 1; i < height - 1; i++) {
24787      lnbd = 1;
24788      for (let j = 1; j < width - 1; j++) {
24789        const ij = i * width + j;
24790        const pix = types[ij];
24791        if (pix === 0) {
24792          continue;
24793        }
24794        let i2 = i;
24795        let j2 = j;
24796        if (pix === 1 && types[ij - 1] === 0) {
24797          nbd += 1;
24798          j2 -= 1;
24799        } else if (pix >= 1 && types[ij + 1] === 0) {
24800          nbd += 1;
24801          j2 += 1;
24802          if (pix > 1) {
24803            lnbd = pix;
24804          }
24805        } else {
24806          if (pix !== 1) {
24807            lnbd = Math.abs(pix);
24808          }
24809          continue;
24810        }
24811        const points = [j, i];
24812        const isHole = j2 === j + 1;
24813        const contour = {
24814          isHole,
24815          points,
24816          id: nbd,
24817          parent: 0
24818        };
24819        contours.push(contour);
24820        let contour0;
24821        for (const c of contours) {
24822          if (c.id === lnbd) {
24823            contour0 = c;
24824            break;
24825          }
24826        }
24827        if (!contour0) {
24828          contour.parent = isHole ? lnbd : 0;
24829        } else if (contour0.isHole) {
24830          contour.parent = isHole ? contour0.parent : lnbd;
24831        } else {
24832          contour.parent = isHole ? lnbd : contour0.parent;
24833        }
24834        const k = this.#clockwiseNonZero(types, width, i, j, i2, j2, 0);
24835        if (k === -1) {
24836          types[ij] = -nbd;
24837          if (types[ij] !== 1) {
24838            lnbd = Math.abs(types[ij]);
24839          }
24840          continue;
24841        }
24842        let shiftI = this.#neighborIdToIndex[2 * k];
24843        let shiftJ = this.#neighborIdToIndex[2 * k + 1];
24844        const i1 = i + shiftI;
24845        const j1 = j + shiftJ;
24846        i2 = i1;
24847        j2 = j1;
24848        let i3 = i;
24849        let j3 = j;
24850        while (true) {
24851          const kk = this.#counterClockwiseNonZero(types, width, i3, j3, i2, j2, 1);
24852          shiftI = this.#neighborIdToIndex[2 * kk];
24853          shiftJ = this.#neighborIdToIndex[2 * kk + 1];
24854          const i4 = i3 + shiftI;
24855          const j4 = j3 + shiftJ;
24856          points.push(j4, i4);
24857          const ij3 = i3 * width + j3;
24858          if (types[ij3 + 1] === 0) {
24859            types[ij3] = -nbd;
24860          } else if (types[ij3] === 1) {
24861            types[ij3] = nbd;
24862          }
24863          if (i4 === i && j4 === j && i3 === i1 && j3 === j1) {
24864            if (types[ij] !== 1) {
24865              lnbd = Math.abs(types[ij]);
24866            }
24867            break;
24868          } else {
24869            i2 = i3;
24870            j2 = j3;
24871            i3 = i4;
24872            j3 = j4;
24873          }
24874        }
24875      }
24876    }
24877    return contours;
24878  }
24879  static #douglasPeuckerHelper(points, start, end, output) {
24880    if (end - start <= 4) {
24881      for (let i = start; i < end - 2; i += 2) {
24882        output.push(points[i], points[i + 1]);
24883      }
24884      return;
24885    }
24886    const ax = points[start];
24887    const ay = points[start + 1];
24888    const abx = points[end - 4] - ax;
24889    const aby = points[end - 3] - ay;
24890    const dist = Math.hypot(abx, aby);
24891    const nabx = abx / dist;
24892    const naby = aby / dist;
24893    const aa = nabx * ay - naby * ax;
24894    const m = aby / abx;
24895    const invS = 1 / dist;
24896    const phi = Math.atan(m);
24897    const cosPhi = Math.cos(phi);
24898    const sinPhi = Math.sin(phi);
24899    const tmax = invS * (Math.abs(cosPhi) + Math.abs(sinPhi));
24900    const poly = invS * (1 - tmax + tmax ** 2);
24901    const partialPhi = Math.max(Math.atan(Math.abs(sinPhi + cosPhi) * poly), Math.atan(Math.abs(sinPhi - cosPhi) * poly));
24902    let dmax = 0;
24903    let index = start;
24904    for (let i = start + 2; i < end - 2; i += 2) {
24905      const d = Math.abs(aa - nabx * points[i + 1] + naby * points[i]);
24906      if (d > dmax) {
24907        index = i;
24908        dmax = d;
24909      }
24910    }
24911    if (dmax > (dist * partialPhi) ** 2) {
24912      this.#douglasPeuckerHelper(points, start, index + 2, output);
24913      this.#douglasPeuckerHelper(points, index, end, output);
24914    } else {
24915      output.push(ax, ay);
24916    }
24917  }
24918  static #douglasPeucker(points) {
24919    const output = [];
24920    const len = points.length;
24921    this.#douglasPeuckerHelper(points, 0, len, output);
24922    output.push(points[len - 2], points[len - 1]);
24923    return output.length <= 4 ? null : output;
24924  }
24925  static #bilateralFilter(buf, width, height, sigmaS, sigmaR, kernelSize) {
24926    const kernel = new Float32Array(kernelSize ** 2);
24927    const sigmaS2 = -2 * sigmaS ** 2;
24928    const halfSize = kernelSize >> 1;
24929    for (let i = 0; i < kernelSize; i++) {
24930      const x = (i - halfSize) ** 2;
24931      for (let j = 0; j < kernelSize; j++) {
24932        kernel[i * kernelSize + j] = Math.exp((x + (j - halfSize) ** 2) / sigmaS2);
24933      }
24934    }
24935    const rangeValues = new Float32Array(256);
24936    const sigmaR2 = -2 * sigmaR ** 2;
24937    for (let i = 0; i < 256; i++) {
24938      rangeValues[i] = Math.exp(i ** 2 / sigmaR2);
24939    }
24940    const N = buf.length;
24941    const out = new Uint8Array(N);
24942    const histogram = new Uint32Array(256);
24943    for (let i = 0; i < height; i++) {
24944      for (let j = 0; j < width; j++) {
24945        const ij = i * width + j;
24946        const center = buf[ij];
24947        let sum = 0;
24948        let norm = 0;
24949        for (let k = 0; k < kernelSize; k++) {
24950          const y = i + k - halfSize;
24951          if (y < 0 || y >= height) {
24952            continue;
24953          }
24954          for (let l = 0; l < kernelSize; l++) {
24955            const x = j + l - halfSize;
24956            if (x < 0 || x >= width) {
24957              continue;
24958            }
24959            const neighbour = buf[y * width + x];
24960            const w = kernel[k * kernelSize + l] * rangeValues[Math.abs(neighbour - center)];
24961            sum += neighbour * w;
24962            norm += w;
24963          }
24964        }
24965        const pix = out[ij] = Math.round(sum / norm);
24966        histogram[pix]++;
24967      }
24968    }
24969    return [out, histogram];
24970  }
24971  static #getHistogram(buf) {
24972    const histogram = new Uint32Array(256);
24973    for (const g of buf) {
24974      histogram[g]++;
24975    }
24976    return histogram;
24977  }
24978  static #toUint8(buf) {
24979    const N = buf.length;
24980    const out = new Uint8ClampedArray(N >> 2);
24981    let max = -Infinity;
24982    let min = Infinity;
24983    for (let i = 0, ii = out.length; i < ii; i++) {
24984      const pix = out[i] = buf[i << 2];
24985      max = Math.max(max, pix);
24986      min = Math.min(min, pix);
24987    }
24988    const ratio = 255 / (max - min);
24989    for (let i = 0, ii = out.length; i < ii; i++) {
24990      out[i] = (out[i] - min) * ratio;
24991    }
24992    return out;
24993  }
24994  static #guessThreshold(histogram) {
24995    let i;
24996    let M = -Infinity;
24997    let L = -Infinity;
24998    const min = histogram.findIndex(v => v !== 0);
24999    let pos = min;
25000    let spos = min;
25001    for (i = min; i < 256; i++) {
25002      const v = histogram[i];
25003      if (v > M) {
25004        if (i - pos > L) {
25005          L = i - pos;
25006          spos = i - 1;
25007        }
25008        M = v;
25009        pos = i;
25010      }
25011    }
25012    for (i = spos - 1; i >= 0; i--) {
25013      if (histogram[i] > histogram[i + 1]) {
25014        break;
25015      }
25016    }
25017    return i;
25018  }
25019  static #getGrayPixels(bitmap) {
25020    const originalBitmap = bitmap;
25021    const {
25022      width,
25023      height
25024    } = bitmap;
25025    const {
25026      maxDim
25027    } = this.#PARAMETERS;
25028    let newWidth = width;
25029    let newHeight = height;
25030    if (width > maxDim || height > maxDim) {
25031      let prevWidth = width;
25032      let prevHeight = height;
25033      let steps = Math.log2(Math.max(width, height) / maxDim);
25034      const isteps = Math.floor(steps);
25035      steps = steps === isteps ? isteps - 1 : isteps;
25036      for (let i = 0; i < steps; i++) {
25037        newWidth = Math.ceil(prevWidth / 2);
25038        newHeight = Math.ceil(prevHeight / 2);
25039        const offscreen = new OffscreenCanvas(newWidth, newHeight);
25040        const ctx = offscreen.getContext("2d");
25041        ctx.drawImage(bitmap, 0, 0, prevWidth, prevHeight, 0, 0, newWidth, newHeight);
25042        prevWidth = newWidth;
25043        prevHeight = newHeight;
25044        if (bitmap !== originalBitmap) {
25045          bitmap.close();
25046        }
25047        bitmap = offscreen.transferToImageBitmap();
25048      }
25049      const ratio = Math.min(maxDim / newWidth, maxDim / newHeight);
25050      newWidth = Math.round(newWidth * ratio);
25051      newHeight = Math.round(newHeight * ratio);
25052    }
25053    const offscreen = new OffscreenCanvas(newWidth, newHeight);
25054    const ctx = offscreen.getContext("2d", {
25055      willReadFrequently: true
25056    });
25057    ctx.fillStyle = "white";
25058    ctx.fillRect(0, 0, newWidth, newHeight);
25059    ctx.filter = "grayscale(1)";
25060    ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, newWidth, newHeight);
25061    const grayImage = ctx.getImageData(0, 0, newWidth, newHeight).data;
25062    const uint8Buf = this.#toUint8(grayImage);
25063    return [uint8Buf, newWidth, newHeight];
25064  }
25065  static extractContoursFromText(text, {
25066    fontFamily,
25067    fontStyle,
25068    fontWeight
25069  }, pageWidth, pageHeight, rotation, innerMargin) {
25070    let canvas = new OffscreenCanvas(1, 1);
25071    let ctx = canvas.getContext("2d", {
25072      alpha: false
25073    });
25074    const fontSize = 200;
25075    const font = ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
25076    const {
25077      actualBoundingBoxLeft,
25078      actualBoundingBoxRight,
25079      actualBoundingBoxAscent,
25080      actualBoundingBoxDescent,
25081      fontBoundingBoxAscent,
25082      fontBoundingBoxDescent,
25083      width
25084    } = ctx.measureText(text);
25085    const SCALE = 1.5;
25086    const canvasWidth = Math.ceil(Math.max(Math.abs(actualBoundingBoxLeft) + Math.abs(actualBoundingBoxRight) || 0, width) * SCALE);
25087    const canvasHeight = Math.ceil(Math.max(Math.abs(actualBoundingBoxAscent) + Math.abs(actualBoundingBoxDescent) || fontSize, Math.abs(fontBoundingBoxAscent) + Math.abs(fontBoundingBoxDescent) || fontSize) * SCALE);
25088    canvas = new OffscreenCanvas(canvasWidth, canvasHeight);
25089    ctx = canvas.getContext("2d", {
25090      alpha: true,
25091      willReadFrequently: true
25092    });
25093    ctx.font = font;
25094    ctx.filter = "grayscale(1)";
25095    ctx.fillStyle = "white";
25096    ctx.fillRect(0, 0, canvasWidth, canvasHeight);
25097    ctx.fillStyle = "black";
25098    ctx.fillText(text, canvasWidth * (SCALE - 1) / 2, canvasHeight * (3 - SCALE) / 2);
25099    const uint8Buf = this.#toUint8(ctx.getImageData(0, 0, canvasWidth, canvasHeight).data);
25100    const histogram = this.#getHistogram(uint8Buf);
25101    const threshold = this.#guessThreshold(histogram);
25102    const contourList = this.#findContours(uint8Buf, canvasWidth, canvasHeight, threshold);
25103    return this.processDrawnLines({
25104      lines: {
25105        curves: contourList,
25106        width: canvasWidth,
25107        height: canvasHeight
25108      },
25109      pageWidth,
25110      pageHeight,
25111      rotation,
25112      innerMargin,
25113      mustSmooth: true,
25114      areContours: true
25115    });
25116  }
25117  static process(bitmap, pageWidth, pageHeight, rotation, innerMargin) {
25118    const [uint8Buf, width, height] = this.#getGrayPixels(bitmap);
25119    const [buffer, histogram] = this.#bilateralFilter(uint8Buf, width, height, Math.hypot(width, height) * this.#PARAMETERS.sigmaSFactor, this.#PARAMETERS.sigmaR, this.#PARAMETERS.kernelSize);
25120    const threshold = this.#guessThreshold(histogram);
25121    const contourList = this.#findContours(buffer, width, height, threshold);
25122    return this.processDrawnLines({
25123      lines: {
25124        curves: contourList,
25125        width,
25126        height
25127      },
25128      pageWidth,
25129      pageHeight,
25130      rotation,
25131      innerMargin,
25132      mustSmooth: true,
25133      areContours: true
25134    });
25135  }
25136  static processDrawnLines({
25137    lines,
25138    pageWidth,
25139    pageHeight,
25140    rotation,
25141    innerMargin,
25142    mustSmooth,
25143    areContours
25144  }) {
25145    if (rotation % 180 !== 0) {
25146      [pageWidth, pageHeight] = [pageHeight, pageWidth];
25147    }
25148    const {
25149      curves,
25150      width,
25151      height
25152    } = lines;
25153    const thickness = lines.thickness ?? 0;
25154    const linesAndPoints = [];
25155    const ratio = Math.min(pageWidth / width, pageHeight / height);
25156    const xScale = ratio / pageWidth;
25157    const yScale = ratio / pageHeight;
25158    const newCurves = [];
25159    for (const {
25160      points
25161    } of curves) {
25162      const reducedPoints = mustSmooth ? this.#douglasPeucker(points) : points;
25163      if (!reducedPoints) {
25164        continue;
25165      }
25166      newCurves.push(reducedPoints);
25167      const len = reducedPoints.length;
25168      const newPoints = new Float32Array(len);
25169      const line = new Float32Array(3 * (len === 2 ? 2 : len - 2));
25170      linesAndPoints.push({
25171        line,
25172        points: newPoints
25173      });
25174      if (len === 2) {
25175        newPoints[0] = reducedPoints[0] * xScale;
25176        newPoints[1] = reducedPoints[1] * yScale;
25177        line.set([NaN, NaN, NaN, NaN, newPoints[0], newPoints[1]], 0);
25178        continue;
25179      }
25180      let [x1, y1, x2, y2] = reducedPoints;
25181      x1 *= xScale;
25182      y1 *= yScale;
25183      x2 *= xScale;
25184      y2 *= yScale;
25185      newPoints.set([x1, y1, x2, y2], 0);
25186      line.set([NaN, NaN, NaN, NaN, x1, y1], 0);
25187      for (let i = 4; i < len; i += 2) {
25188        const x = newPoints[i] = reducedPoints[i] * xScale;
25189        const y = newPoints[i + 1] = reducedPoints[i + 1] * yScale;
25190        line.set(Outline.createBezierPoints(x1, y1, x2, y2, x, y), (i - 2) * 3);
25191        [x1, y1, x2, y2] = [x2, y2, x, y];
25192      }
25193    }
25194    if (linesAndPoints.length === 0) {
25195      return null;
25196    }
25197    const outline = areContours ? new ContourDrawOutline() : new InkDrawOutline();
25198    outline.build(linesAndPoints, pageWidth, pageHeight, 1, rotation, areContours ? 0 : thickness, innerMargin);
25199    return {
25200      outline,
25201      newCurves,
25202      areContours,
25203      thickness,
25204      width,
25205      height
25206    };
25207  }
25208  static async compressSignature({
25209    outlines,
25210    areContours,
25211    thickness,
25212    width,
25213    height
25214  }) {
25215    let minDiff = Infinity;
25216    let maxDiff = -Infinity;
25217    let outlinesLength = 0;
25218    for (const points of outlines) {
25219      outlinesLength += points.length;
25220      for (let i = 2, ii = points.length; i < ii; i++) {
25221        const dx = points[i] - points[i - 2];
25222        minDiff = Math.min(minDiff, dx);
25223        maxDiff = Math.max(maxDiff, dx);
25224      }
25225    }
25226    let bufferType;
25227    if (minDiff >= -128 && maxDiff <= 127) {
25228      bufferType = Int8Array;
25229    } else if (minDiff >= -32768 && maxDiff <= 32767) {
25230      bufferType = Int16Array;
25231    } else {
25232      bufferType = Int32Array;
25233    }
25234    const len = outlines.length;
25235    const headerLength = BASE_HEADER_LENGTH + POINTS_PROPERTIES_NUMBER * len;
25236    const header = new Uint32Array(headerLength);
25237    let offset = 0;
25238    header[offset++] = headerLength * Uint32Array.BYTES_PER_ELEMENT + (outlinesLength - 2 * len) * bufferType.BYTES_PER_ELEMENT;
25239    header[offset++] = 0;
25240    header[offset++] = width;
25241    header[offset++] = height;
25242    header[offset++] = areContours ? 0 : 1;
25243    header[offset++] = Math.max(0, Math.floor(thickness ?? 0));
25244    header[offset++] = len;
25245    header[offset++] = bufferType.BYTES_PER_ELEMENT;
25246    for (const points of outlines) {
25247      header[offset++] = points.length - 2;
25248      header[offset++] = points[0];
25249      header[offset++] = points[1];
25250    }
25251    const cs = new CompressionStream("deflate-raw");
25252    const writer = cs.writable.getWriter();
25253    await writer.ready;
25254    writer.write(header);
25255    const BufferCtor = bufferType.prototype.constructor;
25256    for (const points of outlines) {
25257      const diffs = new BufferCtor(points.length - 2);
25258      for (let i = 2, ii = points.length; i < ii; i++) {
25259        diffs[i - 2] = points[i] - points[i - 2];
25260      }
25261      writer.write(diffs);
25262    }
25263    writer.close();
25264    const bytes = await new Response(cs.readable).bytes();
25265    return bytes.toBase64();
25266  }
25267  static async decompressSignature(signatureData) {
25268    try {
25269      const bytes = Uint8Array.fromBase64(signatureData);
25270      const {
25271        readable,
25272        writable
25273      } = new DecompressionStream("deflate-raw");
25274      const writer = writable.getWriter();
25275      await writer.ready;
25276      writer.write(bytes).then(async () => {
25277        await writer.ready;
25278        await writer.close();
25279      }).catch(() => {});
25280      let data = null;
25281      let offset = 0;
25282      for await (const chunk of readable) {
25283        data ||= new Uint8Array(new Uint32Array(chunk.buffer, 0, 4)[0]);
25284        data.set(chunk, offset);
25285        offset += chunk.length;
25286      }
25287      const header = new Uint32Array(data.buffer, 0, data.length >> 2);
25288      const version = header[1];
25289      if (version !== 0) {
25290        throw new Error(`Invalid version: ${version}`);
25291      }
25292      const width = header[2];
25293      const height = header[3];
25294      const areContours = header[4] === 0;
25295      const thickness = header[5];
25296      const numberOfDrawings = header[6];
25297      const bufferType = header[7];
25298      const outlines = [];
25299      const diffsOffset = (BASE_HEADER_LENGTH + POINTS_PROPERTIES_NUMBER * numberOfDrawings) * Uint32Array.BYTES_PER_ELEMENT;
25300      let diffs;
25301      switch (bufferType) {
25302        case Int8Array.BYTES_PER_ELEMENT:
25303          diffs = new Int8Array(data.buffer, diffsOffset);
25304          break;
25305        case Int16Array.BYTES_PER_ELEMENT:
25306          diffs = new Int16Array(data.buffer, diffsOffset);
25307          break;
25308        case Int32Array.BYTES_PER_ELEMENT:
25309          diffs = new Int32Array(data.buffer, diffsOffset);
25310          break;
25311      }
25312      offset = 0;
25313      for (let i = 0; i < numberOfDrawings; i++) {
25314        const len = header[POINTS_PROPERTIES_NUMBER * i + BASE_HEADER_LENGTH];
25315        const points = new Float32Array(len + 2);
25316        outlines.push(points);
25317        for (let j = 0; j < POINTS_PROPERTIES_NUMBER - 1; j++) {
25318          points[j] = header[POINTS_PROPERTIES_NUMBER * i + BASE_HEADER_LENGTH + j + 1];
25319        }
25320        for (let j = 0; j < len; j++) {
25321          points[j + 2] = points[j] + diffs[offset++];
25322        }
25323      }
25324      return {
25325        areContours,
25326        thickness,
25327        outlines,
25328        width,
25329        height
25330      };
25331    } catch (e) {
25332      warn(`decompressSignature: ${e}`);
25333      return null;
25334    }
25335  }
25336}
25337
25338;// ./src/display/editor/signature.js
25339
25340
25341
25342
25343
25344
25345
25346class SignatureOptions extends DrawingOptions {
25347  constructor() {
25348    super();
25349    super.updateProperties({
25350      fill: AnnotationEditor._defaultLineColor,
25351      "stroke-width": 0
25352    });
25353  }
25354  clone() {
25355    const clone = new SignatureOptions();
25356    clone.updateAll(this);
25357    return clone;
25358  }
25359}
25360class DrawnSignatureOptions extends InkDrawingOptions {
25361  constructor(viewerParameters) {
25362    super(viewerParameters);
25363    super.updateProperties({
25364      stroke: AnnotationEditor._defaultLineColor,
25365      "stroke-width": 1
25366    });
25367  }
25368  clone() {
25369    const clone = new DrawnSignatureOptions(this._viewParameters);
25370    clone.updateAll(this);
25371    return clone;
25372  }
25373}
25374class SignatureEditor extends DrawingEditor {
25375  #isExtracted = false;
25376  #description = null;
25377  #signatureData = null;
25378  #signatureUUID = null;
25379  static _type = "signature";
25380  static _editorType = AnnotationEditorType.SIGNATURE;
25381  static _defaultDrawingOptions = null;
25382  constructor(params) {
25383    super({
25384      ...params,
25385      mustBeCommitted: true,
25386      name: "signatureEditor"
25387    });
25388    this._willKeepAspectRatio = true;
25389    this.#signatureData = params.signatureData || null;
25390    this.#description = null;
25391    this.defaultL10nId = "pdfjs-editor-signature-editor1";
25392  }
25393  static initialize(l10n, uiManager) {
25394    AnnotationEditor.initialize(l10n, uiManager);
25395    this._defaultDrawingOptions = new SignatureOptions();
25396    this._defaultDrawnSignatureOptions = new DrawnSignatureOptions(uiManager.viewParameters);
25397  }
25398  static getDefaultDrawingOptions(options) {
25399    const clone = this._defaultDrawingOptions.clone();
25400    clone.updateProperties(options);
25401    return clone;
25402  }
25403  static get supportMultipleDrawings() {
25404    return false;
25405  }
25406  static get typesMap() {
25407    return shadow(this, "typesMap", new Map());
25408  }
25409  static get isDrawer() {
25410    return false;
25411  }
25412  get telemetryFinalData() {
25413    return {
25414      type: "signature",
25415      hasDescription: !!this.#description
25416    };
25417  }
25418  static computeTelemetryFinalData(data) {
25419    const hasDescriptionStats = data.get("hasDescription");
25420    return {
25421      hasAltText: hasDescriptionStats.get(true) ?? 0,
25422      hasNoAltText: hasDescriptionStats.get(false) ?? 0
25423    };
25424  }
25425  get isResizable() {
25426    return true;
25427  }
25428  onScaleChanging() {
25429    if (this._drawId === null) {
25430      return;
25431    }
25432    super.onScaleChanging();
25433  }
25434  render() {
25435    if (this.div) {
25436      return this.div;
25437    }
25438    let baseX, baseY;
25439    const {
25440      _isCopy
25441    } = this;
25442    if (_isCopy) {
25443      this._isCopy = false;
25444      baseX = this.x;
25445      baseY = this.y;
25446    }
25447    super.render();
25448    if (this._drawId === null) {
25449      if (this.#signatureData) {
25450        const {
25451          lines,
25452          mustSmooth,
25453          areContours,
25454          description,
25455          uuid,
25456          heightInPage
25457        } = this.#signatureData;
25458        const {
25459          rawDims: {
25460            pageWidth,
25461            pageHeight
25462          },
25463          rotation
25464        } = this.parent.viewport;
25465        const outline = SignatureExtractor.processDrawnLines({
25466          lines,
25467          pageWidth,
25468          pageHeight,
25469          rotation,
25470          innerMargin: SignatureEditor._INNER_MARGIN,
25471          mustSmooth,
25472          areContours
25473        });
25474        this.addSignature(outline, heightInPage, description, uuid);
25475      } else {
25476        this.div.setAttribute("data-l10n-args", JSON.stringify({
25477          description: ""
25478        }));
25479        this.div.hidden = true;
25480        this._uiManager.getSignature(this);
25481      }
25482    } else {
25483      this.div.setAttribute("data-l10n-args", JSON.stringify({
25484        description: this.#description || ""
25485      }));
25486    }
25487    if (_isCopy) {
25488      this._isCopy = true;
25489      this._moveAfterPaste(baseX, baseY);
25490    }
25491    return this.div;
25492  }
25493  setUuid(uuid) {
25494    this.#signatureUUID = uuid;
25495    this.addEditToolbar();
25496  }
25497  getUuid() {
25498    return this.#signatureUUID;
25499  }
25500  get description() {
25501    return this.#description;
25502  }
25503  set description(description) {
25504    this.#description = description;
25505    if (!this.div) {
25506      return;
25507    }
25508    this.div.setAttribute("data-l10n-args", JSON.stringify({
25509      description
25510    }));
25511    super.addEditToolbar().then(toolbar => {
25512      toolbar?.updateEditSignatureButton(description);
25513    });
25514  }
25515  getSignaturePreview() {
25516    const {
25517      newCurves,
25518      areContours,
25519      thickness,
25520      width,
25521      height
25522    } = this.#signatureData;
25523    const maxDim = Math.max(width, height);
25524    const outlineData = SignatureExtractor.processDrawnLines({
25525      lines: {
25526        curves: newCurves.map(points => ({
25527          points
25528        })),
25529        thickness,
25530        width,
25531        height
25532      },
25533      pageWidth: maxDim,
25534      pageHeight: maxDim,
25535      rotation: 0,
25536      innerMargin: 0,
25537      mustSmooth: false,
25538      areContours
25539    });
25540    return {
25541      areContours,
25542      outline: outlineData.outline
25543    };
25544  }
25545  get toolbarButtons() {
25546    
25546if (this._uiManager.signatureManager) {
25547      return [["editSignature", this._uiManager.signatureManager]];
25548    }
25549    return
vendor: 13,925 bytes, lines 25549-26060
25549 super.toolbarButtons;
25550  }
25551  addSignature(data, heightInPage, description, uuid) {
25552    const {
25553      x: savedX,
25554      y: savedY
25555    } = this;
25556    const {
25557      outline
25558    } = this.#signatureData = data;
25559    this.#isExtracted = outline instanceof ContourDrawOutline;
25560    this.description = description;
25561    let drawingOptions;
25562    if (this.#isExtracted) {
25563      drawingOptions = SignatureEditor.getDefaultDrawingOptions();
25564    } else {
25565      drawingOptions = SignatureEditor._defaultDrawnSignatureOptions.clone();
25566      drawingOptions.updateProperties({
25567        "stroke-width": outline.thickness
25568      });
25569    }
25570    this._addOutlines({
25571      drawOutlines: outline,
25572      drawingOptions
25573    });
25574    const [, pageHeight] = this.pageDimensions;
25575    let newHeight = heightInPage / pageHeight;
25576    newHeight = newHeight >= 1 ? 0.5 : newHeight;
25577    this.width *= newHeight / this.height;
25578    if (this.width >= 1) {
25579      newHeight *= 0.9 / this.width;
25580      this.width = 0.9;
25581    }
25582    this.height = newHeight;
25583    this.setDims();
25584    this.x = savedX;
25585    this.y = savedY;
25586    this.center();
25587    this._onResized();
25588    this.onScaleChanging();
25589    this.rotate();
25590    this._uiManager.addToAnnotationStorage(this);
25591    this.setUuid(uuid);
25592    this._reportTelemetry({
25593      action: "pdfjs.signature.inserted",
25594      data: {
25595        hasBeenSaved: !!uuid,
25596        hasDescription: !!description
25597      }
25598    });
25599    this.div.hidden = false;
25600  }
25601  getFromImage(bitmap) {
25602    const {
25603      rawDims: {
25604        pageWidth,
25605        pageHeight
25606      },
25607      rotation
25608    } = this.parent.viewport;
25609    return SignatureExtractor.process(bitmap, pageWidth, pageHeight, rotation, SignatureEditor._INNER_MARGIN);
25610  }
25611  getFromText(text, fontInfo) {
25612    const {
25613      rawDims: {
25614        pageWidth,
25615        pageHeight
25616      },
25617      rotation
25618    } = this.parent.viewport;
25619    return SignatureExtractor.extractContoursFromText(text, fontInfo, pageWidth, pageHeight, rotation, SignatureEditor._INNER_MARGIN);
25620  }
25621  getDrawnSignature(curves) {
25622    const {
25623      rawDims: {
25624        pageWidth,
25625        pageHeight
25626      },
25627      rotation
25628    } = this.parent.viewport;
25629    return SignatureExtractor.processDrawnLines({
25630      lines: curves,
25631      pageWidth,
25632      pageHeight,
25633      rotation,
25634      innerMargin: SignatureEditor._INNER_MARGIN,
25635      mustSmooth: false,
25636      areContours: false
25637    });
25638  }
25639  createDrawingOptions({
25640    areContours,
25641    thickness
25642  }) {
25643    if (areContours) {
25644      this._drawingOptions = SignatureEditor.getDefaultDrawingOptions();
25645    } else {
25646      this._drawingOptions = SignatureEditor._defaultDrawnSignatureOptions.clone();
25647      this._drawingOptions.updateProperties({
25648        "stroke-width": thickness
25649      });
25650    }
25651  }
25652  serialize(isForCopying = false) {
25653    if (this.isEmpty()) {
25654      return null;
25655    }
25656    const {
25657      lines,
25658      points
25659    } = this.serializeDraw(isForCopying);
25660    const {
25661      _drawingOptions: {
25662        "stroke-width": thickness
25663      }
25664    } = this;
25665    const serialized = Object.assign(super.serialize(isForCopying), {
25666      isSignature: true,
25667      areContours: this.#isExtracted,
25668      color: [0, 0, 0],
25669      thickness: this.#isExtracted ? 0 : thickness
25670    });
25671    this.addComment(serialized);
25672    if (isForCopying) {
25673      serialized.paths = {
25674        lines,
25675        points
25676      };
25677      serialized.uuid = this.#signatureUUID;
25678      serialized.isCopy = true;
25679    } else {
25680      serialized.lines = lines;
25681    }
25682    if (this.#description) {
25683      serialized.accessibilityData = {
25684        type: "Figure",
25685        alt: this.#description
25686      };
25687    }
25688    return serialized;
25689  }
25690  static deserializeDraw(pageX, pageY, pageWidth, pageHeight, innerMargin, data) {
25691    if (data.areContours) {
25692      return ContourDrawOutline.deserialize(pageX, pageY, pageWidth, pageHeight, innerMargin, data);
25693    }
25694    return InkDrawOutline.deserialize(pageX, pageY, pageWidth, pageHeight, innerMargin, data);
25695  }
25696  static async deserialize(data, parent, uiManager) {
25697    const editor = await super.deserialize(data, parent, uiManager);
25698    editor.#isExtracted = data.areContours;
25699    editor.description = data.accessibilityData?.alt || "";
25700    editor.#signatureUUID = data.uuid;
25701    return editor;
25702  }
25703}
25704
25705;// ./src/display/editor/stamp.js
25706
25707
25708
25709
25710class StampEditor extends AnnotationEditor {
25711  #bitmap = null;
25712  #bitmapId = null;
25713  #bitmapPromise = null;
25714  #bitmapUrl = null;
25715  #bitmapFile = null;
25716  #bitmapFileName = "";
25717  #canvas = null;
25718  #missingCanvas = false;
25719  #resizeTimeoutId = null;
25720  #isSvg = false;
25721  #hasBeenAddedInUndoStack = false;
25722  static _type = "stamp";
25723  static _editorType = AnnotationEditorType.STAMP;
25724  constructor(params) {
25725    super({
25726      ...params,
25727      name: "stampEditor"
25728    });
25729    this.#bitmapUrl = params.bitmapUrl;
25730    this.#bitmapFile = params.bitmapFile;
25731    this.defaultL10nId = "pdfjs-editor-stamp-editor";
25732  }
25733  static initialize(l10n, uiManager) {
25734    AnnotationEditor.initialize(l10n, uiManager);
25735  }
25736  static isHandlingMimeForPasting(mime) {
25737    return SupportedImageMimeTypes.includes(mime);
25738  }
25739  static paste(item, parent) {
25740    parent.pasteEditor({
25741      mode: AnnotationEditorType.STAMP
25742    }, {
25743      bitmapFile: item.getAsFile()
25744    });
25745  }
25746  altTextFinish() {
25747    if (this._uiManager.useNewAltTextFlow) {
25748      this.div.hidden = false;
25749    }
25750    super.altTextFinish();
25751  }
25752  get telemetryFinalData() {
25753    return {
25754      type: "stamp",
25755      hasAltText: !!this.altTextData?.altText
25756    };
25757  }
25758  static computeTelemetryFinalData(data) {
25759    const hasAltTextStats = data.get("hasAltText");
25760    return {
25761      hasAltText: hasAltTextStats.get(true) ?? 0,
25762      hasNoAltText: hasAltTextStats.get(false) ?? 0
25763    };
25764  }
25765  #getBitmapFetched(data, fromId = false) {
25766    if (!data) {
25767      this.remove();
25768      return;
25769    }
25770    this.#bitmap = data.bitmap;
25771    if (!fromId) {
25772      this.#bitmapId = data.id;
25773      this.#isSvg = data.isSvg;
25774    }
25775    if (data.file) {
25776      this.#bitmapFileName = data.file.name;
25777    }
25778    this.#createCanvas();
25779  }
25780  #getBitmapDone() {
25781    this.#bitmapPromise = null;
25782    this._uiManager.enableWaiting(false);
25783    if (!this.#canvas) {
25784      return;
25785    }
25786    if (this._uiManager.useNewAltTextWhenAddingImage && this._uiManager.useNewAltTextFlow && this.#bitmap) {
25787      this.addEditToolbar().then(() => {
25788        this._editToolbar.hide();
25789        this._uiManager.editAltText(this, true);
25790      });
25791      return;
25792    }
25793    if (!this._uiManager.useNewAltTextWhenAddingImage && this._uiManager.useNewAltTextFlow && this.#bitmap) {
25794      this._reportTelemetry({
25795        action: "pdfjs.image.image_added",
25796        data: {
25797          alt_text_modal: false,
25798          alt_text_type: "empty"
25799        }
25800      });
25801      try {
25802        this.mlGuessAltText();
25803      } catch {}
25804    }
25805    this.div.focus();
25806  }
25807  async mlGuessAltText(imageData = null, updateAltTextData = true) {
25808    if (this.hasAltTextData()) {
25809      return null;
25810    }
25811    const {
25812      mlManager
25813    } = this._uiManager;
25814    if (!mlManager) {
25815      throw new Error("No ML.");
25816    }
25817    if (!(await mlManager.isEnabledFor("altText"))) {
25818      throw new Error("ML isn't enabled for alt text.");
25819    }
25820    const {
25821      data,
25822      width,
25823      height
25824    } = imageData || this.copyCanvas(null, null, true).imageData;
25825    const response = await mlManager.guess({
25826      name: "altText",
25827      request: {
25828        data,
25829        width,
25830        height,
25831        channels: data.length / (width * height)
25832      }
25833    });
25834    if (!response) {
25835      throw new Error("No response from the AI service.");
25836    }
25837    if (response.error) {
25838      throw new Error("Error from the AI service.");
25839    }
25840    if (response.cancel) {
25841      return null;
25842    }
25843    if (!response.output) {
25844      throw new Error("No valid response from the AI service.");
25845    }
25846    const altText = response.output;
25847    await this.setGuessedAltText(altText);
25848    if (updateAltTextData && !this.hasAltTextData()) {
25849      this.altTextData = {
25850        alt: altText,
25851        decorative: false
25852      };
25853    }
25854    return altText;
25855  }
25856  #getBitmap() {
25857    if (this.#bitmapId) {
25858      this._uiManager.enableWaiting(true);
25859      this._uiManager.imageManager.getFromId(this.#bitmapId).then(data => this.#getBitmapFetched(data, true)).finally(() => this.#getBitmapDone());
25860      return;
25861    }
25862    if (this.#bitmapUrl) {
25863      const url = this.#bitmapUrl;
25864      this.#bitmapUrl = null;
25865      this._uiManager.enableWaiting(true);
25866      this.#bitmapPromise = this._uiManager.imageManager.getFromUrl(url).then(data => this.#getBitmapFetched(data)).finally(() => this.#getBitmapDone());
25867      return;
25868    }
25869    if (this.#bitmapFile) {
25870      const file = this.#bitmapFile;
25871      this.#bitmapFile = null;
25872      this._uiManager.enableWaiting(true);
25873      this.#bitmapPromise = this._uiManager.imageManager.getFromFile(file).then(data => this.#getBitmapFetched(data)).finally(() => this.#getBitmapDone());
25874      return;
25875    }
25876    const input = document.createElement("input");
25877    input.type = "file";
25878    input.accept = SupportedImageMimeTypes.join(",");
25879    const signal = this._uiManager._signal;
25880    this.#bitmapPromise = new Promise(resolve => {
25881      input.addEventListener("change", async () => {
25882        if (!input.files || input.files.length === 0) {
25883          this.remove();
25884        } else {
25885          this._uiManager.enableWaiting(true);
25886          const data = await this._uiManager.imageManager.getFromFile(input.files[0]);
25887          this._reportTelemetry({
25888            action: "pdfjs.image.image_selected",
25889            data: {
25890              alt_text_modal: this._uiManager.useNewAltTextFlow
25891            }
25892          });
25893          this.#getBitmapFetched(data);
25894        }
25895        resolve();
25896      }, {
25897        signal
25898      });
25899      input.addEventListener("cancel", () => {
25900        this.remove();
25901        resolve();
25902      }, {
25903        signal
25904      });
25905    }).finally(() => this.#getBitmapDone());
25906    input.click();
25907  }
25908  remove() {
25909    if (this.#bitmapId) {
25910      this.#bitmap = null;
25911      this._uiManager.imageManager.deleteId(this.#bitmapId);
25912      this.#canvas?.remove();
25913      this.#canvas = null;
25914      if (this.#resizeTimeoutId) {
25915        clearTimeout(this.#resizeTimeoutId);
25916        this.#resizeTimeoutId = null;
25917      }
25918    }
25919    super.remove();
25920  }
25921  rebuild() {
25922    if (!this.parent) {
25923      if (this.#bitmapId) {
25924        this.#getBitmap();
25925      }
25926      return;
25927    }
25928    super.rebuild();
25929    if (this.div === null) {
25930      return;
25931    }
25932    if (this.#bitmapId && this.#canvas === null) {
25933      this.#getBitmap();
25934    }
25935    if (!this.isAttachedToDOM) {
25936      this.parent.add(this);
25937    }
25938  }
25939  onceAdded(focus) {
25940    this._isDraggable = true;
25941    if (focus) {
25942      this.div.focus();
25943    }
25944  }
25945  isEmpty() {
25946    return !(this.#bitmapPromise || this.#bitmap || this.#bitmapUrl || this.#bitmapFile || this.#bitmapId || this.#missingCanvas);
25947  }
25948  get toolbarButtons() {
25949    return [["altText", this.createAltText()]];
25950  }
25951  get isResizable() {
25952    return true;
25953  }
25954  render() {
25955    if (this.div) {
25956      return this.div;
25957    }
25958    let baseX, baseY;
25959    if (this._isCopy) {
25960      baseX = this.x;
25961      baseY = this.y;
25962    }
25963    super.render();
25964    this.div.hidden = true;
25965    this.createAltText();
25966    if (!this.#missingCanvas) {
25967      if (this.#bitmap) {
25968        this.#createCanvas();
25969      } else {
25970        this.#getBitmap();
25971      }
25972    }
25973    if (this._isCopy) {
25974      this._moveAfterPaste(baseX, baseY);
25975    }
25976    this._uiManager.addShouldRescale(this);
25977    return this.div;
25978  }
25979  setCanvas(annotationElementId, canvas) {
25980    const {
25981      id: bitmapId,
25982      bitmap
25983    } = this._uiManager.imageManager.getFromCanvas(annotationElementId, canvas);
25984    canvas.remove();
25985    if (bitmapId && this._uiManager.imageManager.isValidId(bitmapId)) {
25986      this.#bitmapId = bitmapId;
25987      if (bitmap) {
25988        this.#bitmap = bitmap;
25989      }
25990      this.#missingCanvas = false;
25991      this.#createCanvas();
25992    }
25993  }
25994  _onResized() {
25995    this.onScaleChanging();
25996  }
25997  onScaleChanging() {
25998    if (!this.parent) {
25999      return;
26000    }
26001    if (this.#resizeTimeoutId !== null) {
26002      clearTimeout(this.#resizeTimeoutId);
26003    }
26004    const TIME_TO_WAIT = 200;
26005    this.#resizeTimeoutId = setTimeout(() => {
26006      this.#resizeTimeoutId = null;
26007      this.#drawBitmap();
26008    }, TIME_TO_WAIT);
26009  }
26010  #createCanvas() {
26011    const {
26012      div
26013    } = this;
26014    let {
26015      width,
26016      height
26017    } = this.#bitmap;
26018    const [pageWidth, pageHeight] = this.pageDimensions;
26019    const MAX_RATIO = 0.75;
26020    if (this.width) {
26021      width = this.width * pageWidth;
26022      height = this.height * pageHeight;
26023    } else if (width > MAX_RATIO * pageWidth || height > MAX_RATIO * pageHeight) {
26024      const factor = Math.min(MAX_RATIO * pageWidth / width, MAX_RATIO * pageHeight / height);
26025      width *= factor;
26026      height *= factor;
26027    }
26028    this._uiManager.enableWaiting(false);
26029    const canvas = this.#canvas = document.createElement("canvas");
26030    canvas.setAttribute("role", "img");
26031    this.addContainer(canvas);
26032    this.width = width / pageWidth;
26033    this.height = height / pageHeight;
26034    this.setDims();
26035    if (this._initialOptions?.isCentered) {
26036      this.center();
26037    } else {
26038      this.fixAndSetPosition();
26039    }
26040    this._initialOptions = null;
26041    if (!this._uiManager.useNewAltTextWhenAddingImage || !this._uiManager.useNewAltTextFlow || this.annotationElementId) {
26042      div.hidden = false;
26043    }
26044    this.#drawBitmap();
26045    if (!this.#hasBeenAddedInUndoStack) {
26046      this.parent.addUndoableEditor(this);
26047      this.#hasBeenAddedInUndoStack = true;
26048    }
26049    this._reportTelemetry({
26050      action: "inserted_image"
26051    });
26052    if (this.#bitmapFileName) {
26053      this.div.setAttribute("aria-description", this.#bitmapFileName);
26054    }
26055    if (!this.annotationElementId) {
26056      this._uiManager.a11yAlert(AnnotationEditor._l10nAlert.stamp);
26057    }
26058  }
26059  copyCanvas(maxDataDimension, maxPreviewDimension, createImageData = false) {
26060    
26060if (!maxDataDimension) {
26061      maxDataDimension = 224;
26062    }
vendor: 21,259 bytes, lines 26062-26726
26062
26063    const {
26064      width: bitmapWidth,
26065      height: bitmapHeight
26066    } = this.#bitmap;
26067    const outputScale = new OutputScale();
26068    let bitmap = this.#bitmap;
26069    let width = bitmapWidth,
26070      height = bitmapHeight;
26071    let canvas = null;
26072    if (maxPreviewDimension) {
26073      if (bitmapWidth > maxPreviewDimension || bitmapHeight > maxPreviewDimension) {
26074        const ratio = Math.min(maxPreviewDimension / bitmapWidth, maxPreviewDimension / bitmapHeight);
26075        width = Math.floor(bitmapWidth * ratio);
26076        height = Math.floor(bitmapHeight * ratio);
26077      }
26078      canvas = document.createElement("canvas");
26079      const scaledWidth = canvas.width = Math.ceil(width * outputScale.sx);
26080      const scaledHeight = canvas.height = Math.ceil(height * outputScale.sy);
26081      if (!this.#isSvg) {
26082        bitmap = this.#scaleBitmap(scaledWidth, scaledHeight);
26083      }
26084      const ctx = canvas.getContext("2d");
26085      ctx.filter = this._uiManager.hcmFilter;
26086      let white = "white",
26087        black = "#cfcfd8";
26088      if (this._uiManager.hcmFilter !== "none") {
26089        black = "black";
26090      } else if (ColorScheme.isDarkMode) {
26091        white = "#8f8f9d";
26092        black = "#42414d";
26093      }
26094      const boxDim = 15;
26095      const boxDimWidth = boxDim * outputScale.sx;
26096      const boxDimHeight = boxDim * outputScale.sy;
26097      const pattern = new OffscreenCanvas(boxDimWidth * 2, boxDimHeight * 2);
26098      const patternCtx = pattern.getContext("2d");
26099      patternCtx.fillStyle = white;
26100      patternCtx.fillRect(0, 0, boxDimWidth * 2, boxDimHeight * 2);
26101      patternCtx.fillStyle = black;
26102      patternCtx.fillRect(0, 0, boxDimWidth, boxDimHeight);
26103      patternCtx.fillRect(boxDimWidth, boxDimHeight, boxDimWidth, boxDimHeight);
26104      ctx.fillStyle = ctx.createPattern(pattern, "repeat");
26105      ctx.fillRect(0, 0, scaledWidth, scaledHeight);
26106      ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, scaledWidth, scaledHeight);
26107    }
26108    let imageData = null;
26109    if (createImageData) {
26110      let dataWidth, dataHeight;
26111      if (outputScale.symmetric && bitmap.width < maxDataDimension && bitmap.height < maxDataDimension) {
26112        dataWidth = bitmap.width;
26113        dataHeight = bitmap.height;
26114      } else {
26115        bitmap = this.#bitmap;
26116        if (bitmapWidth > maxDataDimension || bitmapHeight > maxDataDimension) {
26117          const ratio = Math.min(maxDataDimension / bitmapWidth, maxDataDimension / bitmapHeight);
26118          dataWidth = Math.floor(bitmapWidth * ratio);
26119          dataHeight = Math.floor(bitmapHeight * ratio);
26120          if (!this.#isSvg) {
26121            bitmap = this.#scaleBitmap(dataWidth, dataHeight);
26122          }
26123        }
26124      }
26125      const offscreen = new OffscreenCanvas(dataWidth, dataHeight);
26126      const offscreenCtx = offscreen.getContext("2d", {
26127        willReadFrequently: true
26128      });
26129      offscreenCtx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, dataWidth, dataHeight);
26130      imageData = {
26131        width: dataWidth,
26132        height: dataHeight,
26133        data: offscreenCtx.getImageData(0, 0, dataWidth, dataHeight).data
26134      };
26135    }
26136    return {
26137      canvas,
26138      width,
26139      height,
26140      imageData
26141    };
26142  }
26143  #scaleBitmap(width, height) {
26144    const {
26145      width: bitmapWidth,
26146      height: bitmapHeight
26147    } = this.#bitmap;
26148    let newWidth = bitmapWidth;
26149    let newHeight = bitmapHeight;
26150    let bitmap = this.#bitmap;
26151    while (newWidth > 2 * width || newHeight > 2 * height) {
26152      const prevWidth = newWidth;
26153      const prevHeight = newHeight;
26154      if (newWidth > 2 * width) {
26155        newWidth = Math.ceil(newWidth / 2);
26156      }
26157      if (newHeight > 2 * height) {
26158        newHeight = Math.ceil(newHeight / 2);
26159      }
26160      const offscreen = new OffscreenCanvas(newWidth, newHeight);
26161      const ctx = offscreen.getContext("2d");
26162      ctx.drawImage(bitmap, 0, 0, prevWidth, prevHeight, 0, 0, newWidth, newHeight);
26163      bitmap = offscreen.transferToImageBitmap();
26164    }
26165    return bitmap;
26166  }
26167  #drawBitmap() {
26168    const [parentWidth, parentHeight] = this.parentDimensions;
26169    const {
26170      width,
26171      height
26172    } = this;
26173    const outputScale = new OutputScale();
26174    const scaledWidth = Math.ceil(width * parentWidth * outputScale.sx);
26175    const scaledHeight = Math.ceil(height * parentHeight * outputScale.sy);
26176    const canvas = this.#canvas;
26177    if (!canvas || canvas.width === scaledWidth && canvas.height === scaledHeight) {
26178      return;
26179    }
26180    canvas.width = scaledWidth;
26181    canvas.height = scaledHeight;
26182    const bitmap = this.#isSvg ? this.#bitmap : this.#scaleBitmap(scaledWidth, scaledHeight);
26183    const ctx = canvas.getContext("2d");
26184    ctx.filter = this._uiManager.hcmFilter;
26185    ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, scaledWidth, scaledHeight);
26186  }
26187  #serializeBitmap(toUrl) {
26188    if (toUrl) {
26189      if (this.#isSvg) {
26190        const url = this._uiManager.imageManager.getSvgUrl(this.#bitmapId);
26191        if (url) {
26192          return url;
26193        }
26194      }
26195      const canvas = document.createElement("canvas");
26196      ({
26197        width: canvas.width,
26198        height: canvas.height
26199      } = this.#bitmap);
26200      const ctx = canvas.getContext("2d");
26201      ctx.drawImage(this.#bitmap, 0, 0);
26202      return canvas.toDataURL();
26203    }
26204    if (this.#isSvg) {
26205      const [pageWidth, pageHeight] = this.pageDimensions;
26206      const width = Math.round(this.width * pageWidth * PixelsPerInch.PDF_TO_CSS_UNITS);
26207      const height = Math.round(this.height * pageHeight * PixelsPerInch.PDF_TO_CSS_UNITS);
26208      const offscreen = new OffscreenCanvas(width, height);
26209      const ctx = offscreen.getContext("2d");
26210      ctx.drawImage(this.#bitmap, 0, 0, this.#bitmap.width, this.#bitmap.height, 0, 0, width, height);
26211      return offscreen.transferToImageBitmap();
26212    }
26213    return structuredClone(this.#bitmap);
26214  }
26215  static async deserialize(data, parent, uiManager) {
26216    let initialData = null;
26217    let missingCanvas = false;
26218    if (data instanceof StampAnnotationElement) {
26219      const {
26220        data: {
26221          rect,
26222          rotation,
26223          id,
26224          structParent,
26225          popupRef,
26226          richText,
26227          contentsObj,
26228          creationDate,
26229          modificationDate
26230        },
26231        container,
26232        parent: {
26233          page: {
26234            pageNumber
26235          }
26236        },
26237        canvas
26238      } = data;
26239      let bitmapId, bitmap;
26240      if (canvas) {
26241        delete data.canvas;
26242        ({
26243          id: bitmapId,
26244          bitmap
26245        } = uiManager.imageManager.getFromCanvas(container.id, canvas));
26246        canvas.remove();
26247      } else {
26248        missingCanvas = true;
26249        data._hasNoCanvas = true;
26250      }
26251      const altText = (await parent._structTree.getAriaAttributes(`${AnnotationPrefix}${id}`))?.get("aria-label") || "";
26252      initialData = data = {
26253        annotationType: AnnotationEditorType.STAMP,
26254        bitmapId,
26255        bitmap,
26256        pageIndex: pageNumber - 1,
26257        rect: rect.slice(0),
26258        rotation,
26259        annotationElementId: id,
26260        id,
26261        deleted: false,
26262        accessibilityData: {
26263          decorative: false,
26264          altText
26265        },
26266        isSvg: false,
26267        structParent,
26268        popupRef,
26269        richText,
26270        comment: contentsObj?.str || null,
26271        creationDate,
26272        modificationDate
26273      };
26274    }
26275    const editor = await super.deserialize(data, parent, uiManager);
26276    const {
26277      rect,
26278      bitmap,
26279      bitmapUrl,
26280      bitmapId,
26281      isSvg,
26282      accessibilityData
26283    } = data;
26284    if (missingCanvas) {
26285      uiManager.addMissingCanvas(data.id, editor);
26286      editor.#missingCanvas = true;
26287    } else if (bitmapId && uiManager.imageManager.isValidId(bitmapId)) {
26288      editor.#bitmapId = bitmapId;
26289      if (bitmap) {
26290        editor.#bitmap = bitmap;
26291      }
26292    } else {
26293      editor.#bitmapUrl = bitmapUrl;
26294    }
26295    editor.#isSvg = isSvg;
26296    const [parentWidth, parentHeight] = editor.pageDimensions;
26297    editor.width = (rect[2] - rect[0]) / parentWidth;
26298    editor.height = (rect[3] - rect[1]) / parentHeight;
26299    if (accessibilityData) {
26300      editor.altTextData = accessibilityData;
26301    }
26302    editor._initialData = initialData;
26303    if (data.comment) {
26304      editor.setCommentData(data);
26305    }
26306    editor.#hasBeenAddedInUndoStack = !!initialData;
26307    return editor;
26308  }
26309  serialize(isForCopying = false, context = null) {
26310    if (this.isEmpty()) {
26311      return null;
26312    }
26313    if (this.deleted) {
26314      return this.serializeDeleted();
26315    }
26316    const serialized = Object.assign(super.serialize(isForCopying), {
26317      bitmapId: this.#bitmapId,
26318      isSvg: this.#isSvg
26319    });
26320    this.addComment(serialized);
26321    if (isForCopying) {
26322      serialized.bitmapUrl = this.#serializeBitmap(true);
26323      serialized.accessibilityData = this.serializeAltText(true);
26324      serialized.isCopy = true;
26325      return serialized;
26326    }
26327    const {
26328      decorative,
26329      altText
26330    } = this.serializeAltText(false);
26331    if (!decorative && altText) {
26332      serialized.accessibilityData = {
26333        type: "Figure",
26334        alt: altText
26335      };
26336    }
26337    if (this.annotationElementId) {
26338      const changes = this.#hasElementChanged(serialized);
26339      if (changes.isSame) {
26340        return null;
26341      }
26342      if (changes.isSameAltText) {
26343        delete serialized.accessibilityData;
26344      } else {
26345        serialized.accessibilityData.structParent = this._initialData.structParent ?? -1;
26346      }
26347      serialized.id = this.annotationElementId;
26348      delete serialized.bitmapId;
26349      return serialized;
26350    }
26351    if (context === null) {
26352      return serialized;
26353    }
26354    context.stamps ||= new Map();
26355    const area = this.#isSvg ? (serialized.rect[2] - serialized.rect[0]) * (serialized.rect[3] - serialized.rect[1]) : null;
26356    if (!context.stamps.has(this.#bitmapId)) {
26357      context.stamps.set(this.#bitmapId, {
26358        area,
26359        serialized
26360      });
26361      serialized.bitmap = this.#serializeBitmap(false);
26362    } else if (this.#isSvg) {
26363      const prevData = context.stamps.get(this.#bitmapId);
26364      if (area > prevData.area) {
26365        prevData.area = area;
26366        prevData.serialized.bitmap.close();
26367        prevData.serialized.bitmap = this.#serializeBitmap(false);
26368      }
26369    }
26370    return serialized;
26371  }
26372  #hasElementChanged(serialized) {
26373    const {
26374      pageIndex,
26375      accessibilityData: {
26376        altText
26377      }
26378    } = this._initialData;
26379    const isSamePageIndex = serialized.pageIndex === pageIndex;
26380    const isSameAltText = (serialized.accessibilityData?.alt || "") === altText;
26381    return {
26382      isSame: !this.hasEditedComment && !this._hasBeenMoved && !this._hasBeenResized && isSamePageIndex && isSameAltText,
26383      isSameAltText
26384    };
26385  }
26386  renderAnnotationElement(annotation) {
26387    if (this.deleted) {
26388      annotation.hide();
26389      return null;
26390    }
26391    annotation.updateEdited({
26392      rect: this.getPDFRect(),
26393      popup: this.comment
26394    });
26395    return null;
26396  }
26397}
26398
26399;// ./src/display/editor/annotation_editor_layer.js
26400
26401
26402
26403
26404
26405
26406
26407
26408class AnnotationEditorLayer {
26409  #accessibilityManager;
26410  #allowClick = false;
26411  #annotationLayer = null;
26412  #clickAC = null;
26413  #editorFocusTimeoutId = null;
26414  #editors = new Map();
26415  #hadPointerDown = false;
26416  #isDisabling = false;
26417  #isEnabling = false;
26418  #drawingAC = null;
26419  #focusedElement = null;
26420  #textLayer = null;
26421  #textSelectionAC = null;
26422  #textLayerDblClickAC = null;
26423  #lastPointerDownTimestamp = -1;
26424  #uiManager;
26425  static _initialized = false;
26426  static #editorTypes = new Map([FreeTextEditor, InkEditor, StampEditor, HighlightEditor, SignatureEditor].map(type => [type._editorType, type]));
26427  constructor({
26428    uiManager,
26429    pageIndex,
26430    div,
26431    structTreeLayer,
26432    accessibilityManager,
26433    annotationLayer,
26434    drawLayer,
26435    textLayer,
26436    viewport,
26437    l10n
26438  }) {
26439    const editorTypes = [...AnnotationEditorLayer.#editorTypes.values()];
26440    if (!AnnotationEditorLayer._initialized) {
26441      AnnotationEditorLayer._initialized = true;
26442      for (const editorType of editorTypes) {
26443        editorType.initialize(l10n, uiManager);
26444      }
26445    }
26446    uiManager.registerEditorTypes(editorTypes);
26447    this.#uiManager = uiManager;
26448    this.pageIndex = pageIndex;
26449    this.div = div;
26450    this.#accessibilityManager = accessibilityManager;
26451    this.#annotationLayer = annotationLayer;
26452    this.viewport = viewport;
26453    this.#textLayer = textLayer;
26454    this.drawLayer = drawLayer;
26455    this._structTree = structTreeLayer;
26456    this.#uiManager.addLayer(this);
26457  }
26458  get isEmpty() {
26459    return this.#editors.size === 0;
26460  }
26461  get isInvisible() {
26462    return this.isEmpty && this.#uiManager.getMode() === AnnotationEditorType.NONE;
26463  }
26464  updateToolbar(options) {
26465    this.#uiManager.updateToolbar(options);
26466  }
26467  updateMode(mode = this.#uiManager.getMode()) {
26468    this.#cleanup();
26469    switch (mode) {
26470      case AnnotationEditorType.NONE:
26471        this.div.classList.toggle("nonEditing", true);
26472        this.disableTextSelection();
26473        this.togglePointerEvents(false);
26474        this.toggleAnnotationLayerPointerEvents(true);
26475        this.disableClick();
26476        return;
26477      case AnnotationEditorType.INK:
26478        this.disableTextSelection();
26479        this.togglePointerEvents(true);
26480        this.enableClick();
26481        break;
26482      case AnnotationEditorType.HIGHLIGHT:
26483        this.enableTextSelection();
26484        this.togglePointerEvents(false);
26485        this.disableClick();
26486        break;
26487      default:
26488        this.disableTextSelection();
26489        this.togglePointerEvents(true);
26490        this.enableClick();
26491    }
26492    this.toggleAnnotationLayerPointerEvents(false);
26493    const {
26494      classList
26495    } = this.div;
26496    classList.toggle("nonEditing", false);
26497    if (mode === AnnotationEditorType.POPUP) {
26498      classList.toggle("commentEditing", true);
26499    } else {
26500      classList.toggle("commentEditing", false);
26501      for (const editorType of AnnotationEditorLayer.#editorTypes.values()) {
26502        classList.toggle(`${editorType._type}Editing`, mode === editorType._editorType);
26503      }
26504    }
26505    this.div.hidden = false;
26506  }
26507  hasTextLayer(textLayer) {
26508    return textLayer === this.#textLayer?.div;
26509  }
26510  setEditingState(isEditing) {
26511    this.#uiManager.setEditingState(isEditing);
26512  }
26513  addCommands(params) {
26514    this.#uiManager.addCommands(params);
26515  }
26516  cleanUndoStack(type) {
26517    this.#uiManager.cleanUndoStack(type);
26518  }
26519  toggleDrawing(enabled = false) {
26520    this.div.classList.toggle("drawing", !enabled);
26521  }
26522  togglePointerEvents(enabled = false) {
26523    this.div.classList.toggle("disabled", !enabled);
26524  }
26525  toggleAnnotationLayerPointerEvents(enabled = false) {
26526    this.#annotationLayer?.togglePointerEvents(enabled);
26527  }
26528  get #allEditorsIterator() {
26529    return this.#editors.size !== 0 ? this.#editors.values() : this.#uiManager.getEditors(this.pageIndex);
26530  }
26531  async enable() {
26532    this.#isEnabling = true;
26533    this.div.tabIndex = 0;
26534    this.togglePointerEvents(true);
26535    this.div.classList.toggle("nonEditing", false);
26536    this.#textLayerDblClickAC?.abort();
26537    this.#textLayerDblClickAC = null;
26538    const annotationElementIds = new Set();
26539    for (const editor of this.#allEditorsIterator) {
26540      editor.enableEditing();
26541      editor.show(true);
26542      if (editor.annotationElementId) {
26543        this.#uiManager.removeChangedExistingAnnotation(editor);
26544        annotationElementIds.add(editor.annotationElementId);
26545      }
26546    }
26547    const annotationLayer = this.#annotationLayer;
26548    if (annotationLayer) {
26549      for (const editable of annotationLayer.getEditableAnnotations()) {
26550        editable.hide();
26551        if (this.#uiManager.isDeletedAnnotationElement(editable.data.id)) {
26552          continue;
26553        }
26554        if (annotationElementIds.has(editable.data.id)) {
26555          continue;
26556        }
26557        const editor = await this.deserialize(editable);
26558        if (!editor) {
26559          continue;
26560        }
26561        this.addOrRebuild(editor);
26562        editor.enableEditing();
26563      }
26564    }
26565    this.#isEnabling = false;
26566    this.#uiManager._eventBus.dispatch("editorsrendered", {
26567      source: this,
26568      pageNumber: this.pageIndex + 1
26569    });
26570  }
26571  disable() {
26572    this.#isDisabling = true;
26573    this.div.tabIndex = -1;
26574    this.togglePointerEvents(false);
26575    this.div.classList.toggle("nonEditing", true);
26576    if (this.#textLayer && !this.#textLayerDblClickAC) {
26577      this.#textLayerDblClickAC = new AbortController();
26578      const signal = this.#uiManager.combinedSignal(this.#textLayerDblClickAC);
26579      this.#textLayer.div.addEventListener("pointerdown", e => {
26580        const DBL_CLICK_THRESHOLD = 500;
26581        const {
26582          clientX,
26583          clientY,
26584          timeStamp
26585        } = e;
26586        const lastPointerDownTimestamp = this.#lastPointerDownTimestamp;
26587        if (timeStamp - lastPointerDownTimestamp > DBL_CLICK_THRESHOLD) {
26588          this.#lastPointerDownTimestamp = timeStamp;
26589          return;
26590        }
26591        this.#lastPointerDownTimestamp = -1;
26592        const {
26593          classList
26594        } = this.div;
26595        classList.toggle("getElements", true);
26596        const elements = document.elementsFromPoint(clientX, clientY);
26597        classList.toggle("getElements", false);
26598        if (!this.div.contains(elements[0])) {
26599          return;
26600        }
26601        let id;
26602        const regex = new RegExp(`^${AnnotationEditorPrefix}[0-9]+$`);
26603        for (const element of elements) {
26604          if (regex.test(element.id)) {
26605            id = element.id;
26606            break;
26607          }
26608        }
26609        if (!id) {
26610          return;
26611        }
26612        const editor = this.#editors.get(id);
26613        if (editor?.annotationElementId === null) {
26614          stopEvent(e);
26615          editor.dblclick(e);
26616        }
26617      }, {
26618        signal,
26619        capture: true
26620      });
26621    }
26622    const annotationLayer = this.#annotationLayer;
26623    const needFakeAnnotation = [];
26624    if (annotationLayer) {
26625      const changedAnnotations = new Map();
26626      const resetAnnotations = new Map();
26627      for (const editor of this.#allEditorsIterator) {
26628        editor.disableEditing();
26629        if (!editor.annotationElementId) {
26630          needFakeAnnotation.push(editor);
26631          continue;
26632        }
26633        if (editor.serialize() !== null) {
26634          changedAnnotations.set(editor.annotationElementId, editor);
26635          continue;
26636        } else {
26637          resetAnnotations.set(editor.annotationElementId, editor);
26638        }
26639        this.getEditableAnnotation(editor.annotationElementId)?.show();
26640        editor.remove();
26641      }
26642      for (const editable of annotationLayer.getEditableAnnotations()) {
26643        const {
26644          id
26645        } = editable.data;
26646        if (this.#uiManager.isDeletedAnnotationElement(id)) {
26647          editable.updateEdited({
26648            deleted: true
26649          });
26650          continue;
26651        }
26652        let editor = resetAnnotations.get(id);
26653        if (editor) {
26654          editor.resetAnnotationElement(editable);
26655          editor.show(false);
26656          editable.show();
26657          continue;
26658        }
26659        editor = changedAnnotations.get(id);
26660        if (editor) {
26661          this.#uiManager.addChangedExistingAnnotation(editor);
26662          if (editor.renderAnnotationElement(editable)) {
26663            editor.show(false);
26664          }
26665        }
26666        editable.show();
26667      }
26668    }
26669    this.#cleanup();
26670    if (this.isEmpty) {
26671      this.div.hidden = true;
26672    }
26673    const {
26674      classList
26675    } = this.div;
26676    for (const editorType of AnnotationEditorLayer.#editorTypes.values()) {
26677      classList.remove(`${editorType._type}Editing`);
26678    }
26679    this.disableTextSelection();
26680    this.toggleAnnotationLayerPointerEvents(true);
26681    annotationLayer?.updateFakeAnnotations(needFakeAnnotation);
26682    this.#isDisabling = false;
26683  }
26684  getEditableAnnotation(id) {
26685    return this.#annotationLayer?.getEditableAnnotation(id) || null;
26686  }
26687  setActiveEditor(editor) {
26688    const currentActive = this.#uiManager.getActive();
26689    if (currentActive === editor) {
26690      return;
26691    }
26692    this.#uiManager.setActiveEditor(editor);
26693  }
26694  enableTextSelection() {
26695    this.div.tabIndex = -1;
26696    if (this.#textLayer?.div && !this.#textSelectionAC) {
26697      this.#textSelectionAC = new AbortController();
26698      const signal = this.#uiManager.combinedSignal(this.#textSelectionAC);
26699      this.#textLayer.div.addEventListener("pointerdown", this.#textLayerPointerDown.bind(this), {
26700        signal
26701      });
26702      this.#textLayer.div.classList.add("highlighting");
26703    }
26704  }
26705  disableTextSelection() {
26706    this.div.tabIndex = 0;
26707    if (this.#textLayer?.div && this.#textSelectionAC) {
26708      this.#textSelectionAC.abort();
26709      this.#textSelectionAC = null;
26710      this.#textLayer.div.classList.remove("highlighting");
26711    }
26712  }
26713  #textLayerPointerDown(event) {
26714    this.#uiManager.unselectAll();
26715    const {
26716      target
26717    } = event;
26718    if (target === this.#textLayer.div || (target.getAttribute("role") === "img" || target.classList.contains("endOfContent") || target.classList.contains("textLayerImages") || target.classList.contains("textLayerImagePlaceholder")) && this.#textLayer.div.contains(target)) {
26719      const {
26720        isMac
26721      } = FeatureTest.platform;
26722      if (event.button !== 0 || event.ctrlKey && isMac) {
26723        return;
26724      }
26725      this.#uiManager.showAllEditors("highlight", true, true);
26726      
26726this.#textLayer.div.classList.add("free");
26727      this.toggleDrawing();
26728      HighlightEditor.startHighlighting(this, this.#uiManager.direction === "ltr", {
26729        target: this.#textLayer.div,
26730        x: event.x,
26731        y: event.y
26732      });
26733      this.#textLayer.div.addEventListener("pointerup", () => {
26734        this.#textLayer.div.classList.remove("free");
26735        this.toggleDrawing(true);
26736      }, {
26737        once: true,
26738        signal: this.#uiManager._signal
26739      }
vendor: 15,980 bytes, lines 26739-27322
26739);
26740      event.preventDefault();
26741    }
26742  }
26743  enableClick() {
26744    if (this.#clickAC) {
26745      return;
26746    }
26747    this.#clickAC = new AbortController();
26748    const signal = this.#uiManager.combinedSignal(this.#clickAC);
26749    this.div.addEventListener("pointerdown", this.pointerdown.bind(this), {
26750      signal
26751    });
26752    const pointerup = this.pointerup.bind(this);
26753    this.div.addEventListener("pointerup", pointerup, {
26754      signal
26755    });
26756    this.div.addEventListener("pointercancel", pointerup, {
26757      signal
26758    });
26759  }
26760  disableClick() {
26761    this.#clickAC?.abort();
26762    this.#clickAC = null;
26763  }
26764  attach(editor) {
26765    this.#editors.set(editor.id, editor);
26766    const {
26767      annotationElementId
26768    } = editor;
26769    if (annotationElementId && this.#uiManager.isDeletedAnnotationElement(annotationElementId)) {
26770      this.#uiManager.removeDeletedAnnotationElement(editor);
26771    }
26772  }
26773  detach(editor) {
26774    this.#editors.delete(editor.id);
26775    this.#accessibilityManager?.removePointerInTextLayer(editor.contentDiv);
26776    if (!this.#isDisabling && editor.annotationElementId) {
26777      this.#uiManager.addDeletedAnnotationElement(editor);
26778    }
26779  }
26780  remove(editor) {
26781    this.detach(editor);
26782    this.#uiManager.removeEditor(editor);
26783    editor.div.remove();
26784    editor.isAttachedToDOM = false;
26785  }
26786  changeParent(editor) {
26787    if (editor.parent === this) {
26788      return;
26789    }
26790    if (editor.parent && editor.annotationElementId) {
26791      this.#uiManager.addDeletedAnnotationElement(editor);
26792      AnnotationEditor.deleteAnnotationElement(editor);
26793      editor.annotationElementId = null;
26794    }
26795    this.attach(editor);
26796    editor.parent?.detach(editor);
26797    editor.setParent(this);
26798    if (editor.div && editor.isAttachedToDOM) {
26799      editor.div.remove();
26800      this.div.append(editor.div);
26801    }
26802  }
26803  add(editor) {
26804    if (editor.parent === this && editor.isAttachedToDOM) {
26805      return;
26806    }
26807    this.changeParent(editor);
26808    this.#uiManager.addEditor(editor);
26809    this.attach(editor);
26810    if (!editor.isAttachedToDOM) {
26811      const div = editor.render();
26812      this.div.append(div);
26813      editor.isAttachedToDOM = true;
26814    }
26815    editor.fixAndSetPosition();
26816    editor.onceAdded(!this.#isEnabling);
26817    this.#uiManager.addToAnnotationStorage(editor);
26818    editor._reportTelemetry(editor.telemetryInitialData);
26819  }
26820  moveEditorInDOM(editor) {
26821    if (!editor.isAttachedToDOM) {
26822      return;
26823    }
26824    const {
26825      activeElement
26826    } = document;
26827    if (editor.div.contains(activeElement) && !this.#editorFocusTimeoutId) {
26828      editor._focusEventsAllowed = false;
26829      this.#editorFocusTimeoutId = setTimeout(() => {
26830        this.#editorFocusTimeoutId = null;
26831        if (!editor.div.contains(document.activeElement)) {
26832          editor.div.addEventListener("focusin", () => {
26833            editor._focusEventsAllowed = true;
26834          }, {
26835            once: true,
26836            signal: this.#uiManager._signal
26837          });
26838          activeElement.focus();
26839        } else {
26840          editor._focusEventsAllowed = true;
26841        }
26842      }, 0);
26843    }
26844    editor._structTreeParentId = this.#accessibilityManager?.moveElementInDOM(this.div, editor.div, editor.contentDiv, true);
26845  }
26846  addOrRebuild(editor) {
26847    if (editor.needsToBeRebuilt()) {
26848      editor.parent ||= this;
26849      editor.rebuild();
26850      editor.show();
26851    } else {
26852      this.add(editor);
26853    }
26854  }
26855  addUndoableEditor(editor) {
26856    const cmd = () => editor._uiManager.rebuild(editor);
26857    const undo = () => {
26858      editor.remove();
26859    };
26860    this.addCommands({
26861      cmd,
26862      undo,
26863      mustExec: false
26864    });
26865  }
26866  getEditorByUID(uid) {
26867    for (const editor of this.#editors.values()) {
26868      if (editor.uid === uid) {
26869        return editor;
26870      }
26871    }
26872    return null;
26873  }
26874  get #currentEditorType() {
26875    return AnnotationEditorLayer.#editorTypes.get(this.#uiManager.getMode());
26876  }
26877  combinedSignal(ac) {
26878    return this.#uiManager.combinedSignal(ac);
26879  }
26880  #createNewEditor(params) {
26881    const editorType = this.#currentEditorType;
26882    return editorType ? new editorType.prototype.constructor(params) : null;
26883  }
26884  canCreateNewEmptyEditor() {
26885    return this.#currentEditorType?.canCreateNewEmptyEditor();
26886  }
26887  async pasteEditor(options, params) {
26888    this.updateToolbar(options);
26889    await this.#uiManager.updateMode(options.mode);
26890    const {
26891      offsetX,
26892      offsetY
26893    } = this.#getCenterPoint();
26894    const id = this.#uiManager.getId();
26895    const editor = this.#createNewEditor({
26896      parent: this,
26897      id,
26898      x: offsetX,
26899      y: offsetY,
26900      uiManager: this.#uiManager,
26901      isCentered: true,
26902      ...params
26903    });
26904    if (editor) {
26905      this.add(editor);
26906    }
26907  }
26908  async deserialize(data) {
26909    return (await AnnotationEditorLayer.#editorTypes.get(data.annotationType ?? data.annotationEditorType)?.deserialize(data, this, this.#uiManager)) || null;
26910  }
26911  createAndAddNewEditor(event, isCentered, data = {}) {
26912    const id = this.#uiManager.getId();
26913    const editor = this.#createNewEditor({
26914      parent: this,
26915      id,
26916      x: event.offsetX,
26917      y: event.offsetY,
26918      uiManager: this.#uiManager,
26919      isCentered,
26920      ...data
26921    });
26922    if (editor) {
26923      this.add(editor);
26924    }
26925    return editor;
26926  }
26927  get boundingClientRect() {
26928    return this.div.getBoundingClientRect();
26929  }
26930  #getCenterPoint() {
26931    const {
26932      x,
26933      y,
26934      width,
26935      height
26936    } = this.boundingClientRect;
26937    const tlX = Math.max(0, x);
26938    const tlY = Math.max(0, y);
26939    const brX = Math.min(window.innerWidth, x + width);
26940    const brY = Math.min(window.innerHeight, y + height);
26941    const centerX = (tlX + brX) / 2 - x;
26942    const centerY = (tlY + brY) / 2 - y;
26943    const [offsetX, offsetY] = this.viewport.rotation % 180 === 0 ? [centerX, centerY] : [centerY, centerX];
26944    return {
26945      offsetX,
26946      offsetY
26947    };
26948  }
26949  addNewEditor(data = {}) {
26950    this.createAndAddNewEditor(this.#getCenterPoint(), true, data);
26951  }
26952  setSelected(editor) {
26953    this.#uiManager.setSelected(editor);
26954  }
26955  toggleSelected(editor) {
26956    this.#uiManager.toggleSelected(editor);
26957  }
26958  unselect(editor) {
26959    this.#uiManager.unselect(editor);
26960  }
26961  pointerup(event) {
26962    const {
26963      isMac
26964    } = FeatureTest.platform;
26965    if (event.button !== 0 || event.ctrlKey && isMac) {
26966      return;
26967    }
26968    if (event.target !== this.div) {
26969      return;
26970    }
26971    if (!this.#hadPointerDown) {
26972      return;
26973    }
26974    this.#hadPointerDown = false;
26975    if (this.#currentEditorType?.isDrawer && this.#currentEditorType.supportMultipleDrawings) {
26976      return;
26977    }
26978    if (!this.#allowClick) {
26979      this.#allowClick = true;
26980      return;
26981    }
26982    const currentMode = this.#uiManager.getMode();
26983    if (currentMode === AnnotationEditorType.STAMP || currentMode === AnnotationEditorType.POPUP || currentMode === AnnotationEditorType.SIGNATURE) {
26984      this.#uiManager.unselectAll();
26985      return;
26986    }
26987    this.createAndAddNewEditor(event, false);
26988  }
26989  pointerdown(event) {
26990    if (this.#uiManager.getMode() === AnnotationEditorType.HIGHLIGHT) {
26991      this.enableTextSelection();
26992    }
26993    if (this.#hadPointerDown) {
26994      this.#hadPointerDown = false;
26995      return;
26996    }
26997    const {
26998      isMac
26999    } = FeatureTest.platform;
27000    if (event.button !== 0 || event.ctrlKey && isMac) {
27001      return;
27002    }
27003    if (event.target !== this.div) {
27004      return;
27005    }
27006    this.#hadPointerDown = true;
27007    if (this.#currentEditorType?.isDrawer) {
27008      this.startDrawingSession(event);
27009      return;
27010    }
27011    const editor = this.#uiManager.getActive();
27012    this.#allowClick = !editor || editor.isEmpty();
27013  }
27014  startDrawingSession(event) {
27015    this.div.focus({
27016      preventScroll: true
27017    });
27018    if (this.#drawingAC) {
27019      this.#currentEditorType.startDrawing(this, this.#uiManager, false, event);
27020      return;
27021    }
27022    this.#uiManager.setCurrentDrawingSession(this);
27023    this.#drawingAC = new AbortController();
27024    const signal = this.#uiManager.combinedSignal(this.#drawingAC);
27025    this.div.addEventListener("blur", ({
27026      relatedTarget
27027    }) => {
27028      if (relatedTarget && !this.div.contains(relatedTarget)) {
27029        this.#focusedElement = null;
27030        this.commitOrRemove();
27031      }
27032    }, {
27033      signal
27034    });
27035    this.#currentEditorType.startDrawing(this, this.#uiManager, false, event);
27036  }
27037  pause(on) {
27038    if (on) {
27039      const {
27040        activeElement
27041      } = document;
27042      if (this.div.contains(activeElement)) {
27043        this.#focusedElement = activeElement;
27044      }
27045      return;
27046    }
27047    if (this.#focusedElement) {
27048      setTimeout(() => {
27049        this.#focusedElement?.focus();
27050        this.#focusedElement = null;
27051      }, 0);
27052    }
27053  }
27054  endDrawingSession(isAborted = false) {
27055    if (!this.#drawingAC) {
27056      return null;
27057    }
27058    this.#uiManager.setCurrentDrawingSession(null);
27059    this.#drawingAC.abort();
27060    this.#drawingAC = null;
27061    this.#focusedElement = null;
27062    return this.#currentEditorType.endDrawing(isAborted);
27063  }
27064  findNewParent(editor, x, y) {
27065    const layer = this.#uiManager.findParent(x, y);
27066    if (layer === null || layer === this) {
27067      return false;
27068    }
27069    layer.changeParent(editor);
27070    return true;
27071  }
27072  commitOrRemove() {
27073    if (this.#drawingAC) {
27074      this.endDrawingSession();
27075      return true;
27076    }
27077    return false;
27078  }
27079  onScaleChanging() {
27080    if (!this.#drawingAC) {
27081      return;
27082    }
27083    this.#currentEditorType.onScaleChangingWhenDrawing(this);
27084  }
27085  destroy() {
27086    this.commitOrRemove();
27087    if (this.#uiManager.getActive()?.parent === this) {
27088      this.#uiManager.commitOrRemove();
27089      this.#uiManager.setActiveEditor(null);
27090    }
27091    if (this.#editorFocusTimeoutId) {
27092      clearTimeout(this.#editorFocusTimeoutId);
27093      this.#editorFocusTimeoutId = null;
27094    }
27095    for (const editor of this.#editors.values()) {
27096      this.#accessibilityManager?.removePointerInTextLayer(editor.contentDiv);
27097      editor.setParent(null);
27098      editor.isAttachedToDOM = false;
27099      editor.div.remove();
27100    }
27101    this.div = null;
27102    this.#editors.clear();
27103    this.#uiManager.removeLayer(this);
27104  }
27105  #cleanup() {
27106    for (const editor of this.#editors.values()) {
27107      if (editor.isEmpty()) {
27108        editor.remove();
27109      }
27110    }
27111  }
27112  async render({
27113    viewport
27114  }) {
27115    this.viewport = viewport;
27116    setLayerDimensions(this.div, viewport);
27117    for (const editor of this.#uiManager.getEditors(this.pageIndex)) {
27118      this.add(editor);
27119      editor.rebuild();
27120    }
27121    await this.#uiManager.findClonesForPage(this);
27122    this.div.hidden = this.isEmpty;
27123    this.updateMode();
27124  }
27125  update({
27126    viewport
27127  }) {
27128    this.#uiManager.commitOrRemove();
27129    this.#cleanup();
27130    const oldRotation = this.viewport.rotation;
27131    const rotation = viewport.rotation;
27132    this.viewport = viewport;
27133    setLayerDimensions(this.div, {
27134      rotation
27135    });
27136    if (oldRotation !== rotation) {
27137      for (const editor of this.#editors.values()) {
27138        editor.rotate(rotation);
27139      }
27140    }
27141  }
27142  get pageDimensions() {
27143    const {
27144      pageWidth,
27145      pageHeight
27146    } = this.viewport.rawDims;
27147    return [pageWidth, pageHeight];
27148  }
27149  get scale() {
27150    return this.#uiManager.viewParameters.realScale;
27151  }
27152}
27153
27154;// ./src/display/draw_layer.js
27155
27156
27157function compareTextLayers(a, b) {
27158  if (a === b) {
27159    return 0;
27160  }
27161  return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
27162}
27163function getTextLayer(node) {
27164  if (!node) {
27165    return null;
27166  }
27167  if (node.nodeType === Node.ELEMENT_NODE) {
27168    return node.closest(".textLayer");
27169  }
27170  return node.parentElement?.closest(".textLayer") || null;
27171}
27172function isPointBefore(nodeA, offsetA, nodeB, offsetB) {
27173  if (nodeA === nodeB) {
27174    return offsetA <= offsetB;
27175  }
27176  const relation = nodeA.compareDocumentPosition(nodeB);
27177  if (relation & Node.DOCUMENT_POSITION_FOLLOWING) {
27178    return true;
27179  }
27180  if (relation & Node.DOCUMENT_POSITION_PRECEDING) {
27181    return false;
27182  }
27183  return null;
27184}
27185function normalizeEdgeBoundary(container, offset, textLayer) {
27186  if (container.nodeType !== Node.ELEMENT_NODE || !container.classList.contains("textLayer") || offset !== container.childNodes.length) {
27187    return {
27188      container,
27189      offset
27190    };
27191  }
27192  let lastNode = container.lastChild;
27193  if (lastNode?.nodeType === Node.ELEMENT_NODE && lastNode.classList.contains("endOfContent")) {
27194    lastNode = lastNode.previousSibling;
27195  }
27196  if (!lastNode || !textLayer.contains(lastNode)) {
27197    return null;
27198  }
27199  if (lastNode.nodeType === Node.TEXT_NODE) {
27200    return {
27201      container: lastNode,
27202      offset: lastNode.textContent.length
27203    };
27204  }
27205  return {
27206    container: lastNode,
27207    offset: lastNode.childNodes.length
27208  };
27209}
27210class DrawLayer {
27211  #parent = null;
27212  #mapping = new Map();
27213  #textLayer = null;
27214  #filterFactory = null;
27215  #pageColors = null;
27216  #textLayerObserver = null;
27217  #toUpdate = new Map();
27218  static #id = 0;
27219  static #selectionId = 0;
27220  static #selectionChangeAC = null;
27221  static #selections = new Set();
27222  static #isSelecting = false;
27223  static #textLayerSet = new Set();
27224  static #textLayers = new WeakMap();
27225  constructor({
27226    filterFactory = null,
27227    pageColors = null,
27228    pageIndex,
27229    textLayer = null
27230  }) {
27231    this.pageIndex = pageIndex;
27232    this.#filterFactory = filterFactory;
27233    this.#pageColors = pageColors;
27234    if (textLayer) {
27235      const previousData = DrawLayer.#textLayers.get(textLayer);
27236      if (previousData?.selectionDiv) {
27237        previousData.selectionDiv.remove();
27238        DrawLayer.#selections.delete(previousData.selectionDiv);
27239      }
27240      DrawLayer.#textLayers.set(textLayer, {
27241        drawLayer: this
27242      });
27243      DrawLayer.#textLayerSet.add(textLayer);
27244      this.#textLayer = textLayer;
27245      this.#textLayerObserver = new MutationObserver(records => {
27246        if (!this.#parent || !this.#textLayer?.isConnected || !DrawLayer.#hasSelection()) {
27247          return;
27248        }
27249        for (const {
27250          addedNodes
27251        } of records) {
27252          for (const node of addedNodes) {
27253            if (node.nodeType === Node.ELEMENT_NODE && node.classList.contains("endOfContent")) {
27254              DrawLayer.#selectionChange();
27255              return;
27256            }
27257          }
27258        }
27259      });
27260      this.#textLayerObserver.observe(textLayer, {
27261        childList: true
27262      });
27263      if (DrawLayer.#selectionChangeAC === null) {
27264        DrawLayer.#selectionChangeAC = new AbortController();
27265        const {
27266          signal
27267        } = DrawLayer.#selectionChangeAC;
27268        document.addEventListener("selectionchange", DrawLayer.#selectionChange.bind(DrawLayer), {
27269          signal
27270        });
27271        document.addEventListener("pointerdown", () => {
27272          DrawLayer.#isSelecting = true;
27273        }, {
27274          signal
27275        });
27276        document.addEventListener("pointerup", () => {
27277          DrawLayer.#isSelecting = false;
27278        }, {
27279          signal
27280        });
27281        window.addEventListener("blur", () => {
27282          DrawLayer.#isSelecting = false;
27283        }, {
27284          signal
27285        });
27286      }
27287    }
27288  }
27289  setParent(parent) {
27290    if (!this.#parent) {
27291      this.#parent = parent;
27292      if (this.#textLayer?.isConnected && DrawLayer.#hasSelection()) {
27293        DrawLayer.#selectionChange();
27294      }
27295      return;
27296    }
27297    if (this.#parent !== parent) {
27298      if (this.#mapping.size > 0) {
27299        for (const root of this.#mapping.values()) {
27300          root.remove();
27301          parent.append(root);
27302        }
27303      }
27304      this.#parent = parent;
27305    }
27306  }
27307  static #cleanupTextLayerSelection(textLayer) {
27308    const textLayerData = this.#textLayers.get(textLayer);
27309    if (!textLayerData?.selectionDiv) {
27310      return;
27311    }
27312    textLayerData.selectionDiv.remove();
27313    this.#selections.delete(textLayerData.selectionDiv);
27314    textLayerData.selectionDiv = null;
27315    textLayerData.path = null;
27316  }
27317  static #hasSelection() {
27318    const selection = document.getSelection();
27319    return !!selection && !selection.isCollapsed;
27320  }
27321  static #getOrderedTextLayers() {
27322    return 
27322[...this.#textLayerSet].filter(textLayer => textLayer.isConnected
vendor: 7,564 bytes, lines 27322-27535
27322).sort(compareTextLayers);
27323  }
27324  static #selectionChange() {
27325    const selection = document.getSelection();
27326    if (!selection || selection.isCollapsed) {
27327      for (const root of this.#selections) {
27328        root.remove();
27329      }
27330      this.#selections.clear();
27331      return;
27332    }
27333    const rotators = new WeakMap();
27334    const orderedTextLayers = this.#getOrderedTextLayers();
27335    const ranges = [];
27336    for (let i = 0, ii = selection.rangeCount; i < ii; i++) {
27337      const range = selection.getRangeAt(i);
27338      if (range.collapsed) {
27339        continue;
27340      }
27341      let {
27342        startContainer,
27343        startOffset,
27344        endContainer,
27345        endOffset
27346      } = range;
27347      let startTextLayer = getTextLayer(startContainer);
27348      let endTextLayer = getTextLayer(endContainer);
27349      const startMissing = startTextLayer === null;
27350      const endMissing = endTextLayer === null;
27351      if (this.#isSelecting && startMissing !== endMissing) {
27352        return;
27353      }
27354      if (selection.rangeCount === 1) {
27355        const {
27356          anchorNode,
27357          anchorOffset,
27358          focusNode,
27359          focusOffset
27360        } = selection;
27361        const anchorLayer = getTextLayer(anchorNode);
27362        const focusLayer = getTextLayer(focusNode);
27363        const anchorBeforeFocus = isPointBefore(anchorNode, anchorOffset, focusNode, focusOffset);
27364        if (anchorLayer && focusLayer && anchorBeforeFocus !== null) {
27365          if (anchorBeforeFocus) {
27366            startContainer = anchorNode;
27367            startOffset = anchorOffset;
27368            startTextLayer = anchorLayer;
27369            endContainer = focusNode;
27370            endOffset = focusOffset;
27371            endTextLayer = focusLayer;
27372          } else {
27373            startContainer = focusNode;
27374            startOffset = focusOffset;
27375            startTextLayer = focusLayer;
27376            endContainer = anchorNode;
27377            endOffset = anchorOffset;
27378            endTextLayer = anchorLayer;
27379          }
27380        }
27381      }
27382      const activeTextLayers = orderedTextLayers.filter(textLayer => range.intersectsNode(textLayer));
27383      if (activeTextLayers.length === 0) {
27384        continue;
27385      }
27386      let boundarySubstituted = false;
27387      if (!startTextLayer) {
27388        startTextLayer = activeTextLayers[0];
27389        startContainer = startTextLayer;
27390        startOffset = 0;
27391        boundarySubstituted = true;
27392      }
27393      if (!endTextLayer) {
27394        endTextLayer = activeTextLayers.at(-1);
27395        endContainer = endTextLayer;
27396        endOffset = endTextLayer.childNodes.length;
27397        boundarySubstituted = true;
27398      }
27399      if (endContainer.nodeType === Node.ELEMENT_NODE) {
27400        if (endContainer.classList.contains("endOfContent")) {
27401          const previousNode = endContainer.previousSibling;
27402          if (!previousNode) {
27403            continue;
27404          }
27405          endContainer = previousNode;
27406          endOffset = previousNode.nodeType === Node.TEXT_NODE ? previousNode.textContent.length : previousNode.childNodes.length;
27407        } else if (endContainer.classList.contains("textLayer") && endContainer.childNodes.length === endOffset) {
27408          const normalizedEnd = normalizeEdgeBoundary(endContainer, endOffset, endTextLayer);
27409          if (!normalizedEnd) {
27410            continue;
27411          }
27412          endContainer = normalizedEnd.container;
27413          endOffset = normalizedEnd.offset;
27414        }
27415      }
27416      if (startContainer.nodeType === Node.ELEMENT_NODE) {
27417        const normalizedStart = normalizeEdgeBoundary(startContainer, startOffset, startTextLayer);
27418        if (!normalizedStart) {
27419          continue;
27420        }
27421        startContainer = normalizedStart.container;
27422        startOffset = normalizedStart.offset;
27423      }
27424      if (startTextLayer === endTextLayer && !boundarySubstituted && activeTextLayers.includes(startTextLayer)) {
27425        ranges.push([range, startTextLayer]);
27426        continue;
27427      }
27428      for (const textLayer of activeTextLayers) {
27429        const firstNode = textLayer.firstChild;
27430        if (!firstNode) {
27431          continue;
27432        }
27433        const subRange = document.createRange();
27434        if (textLayer === startTextLayer) {
27435          subRange.setStart(startContainer, startOffset);
27436        } else {
27437          subRange.setStartBefore(firstNode);
27438        }
27439        if (textLayer === endTextLayer) {
27440          subRange.setEnd(endContainer, endOffset);
27441        } else {
27442          const lastNode = textLayer.lastChild;
27443          if (!lastNode) {
27444            continue;
27445          }
27446          if (lastNode.nodeType === Node.ELEMENT_NODE && lastNode.classList.contains("endOfContent")) {
27447            const lastTextNode = lastNode.previousSibling;
27448            if (!lastTextNode) {
27449              continue;
27450            }
27451            subRange.setEndAfter(lastTextNode);
27452          } else {
27453            subRange.setEndAfter(lastNode);
27454          }
27455        }
27456        if (!subRange.collapsed) {
27457          ranges.push([subRange, textLayer]);
27458        }
27459      }
27460    }
27461    const selectedTextLayers = new Set(ranges.map(range => range[1]));
27462    for (const textLayer of this.#textLayerSet) {
27463      if (!selectedTextLayers.has(textLayer)) {
27464        this.#cleanupTextLayerSelection(textLayer);
27465      }
27466    }
27467    for (const [range, textLayer] of ranges) {
27468      const textLayerData = DrawLayer.#textLayers.get(textLayer);
27469      if (!textLayerData) {
27470        continue;
27471      }
27472      let rotator = rotators.get(textLayer);
27473      if (!rotator) {
27474        const clientRect = textLayer.getBoundingClientRect();
27475        rotator = (x, y, w, h) => ({
27476          x: (x - clientRect.x) / clientRect.width,
27477          y: (y - clientRect.y) / clientRect.height,
27478          width: w / clientRect.width,
27479          height: h / clientRect.height
27480        });
27481        rotators.set(textLayer, rotator);
27482      }
27483      const boxes = [];
27484      for (let {
27485        x,
27486        y,
27487        width,
27488        height
27489      } of range.getClientRects()) {
27490        if (width === 0 || height === 0) {
27491          continue;
27492        }
27493        ({
27494          x,
27495          y,
27496          width,
27497          height
27498        } = rotator(x, y, width, height));
27499        if (width === 1 && height === 1) {
27500          continue;
27501        }
27502        boxes.push(`M${x} ${y} h${width} v${height} h-${width} Z`);
27503      }
27504      if (boxes.length === 0) {
27505        continue;
27506      }
27507      const drawLayer = textLayerData.drawLayer;
27508      let div = textLayerData.selectionDiv;
27509      let path = textLayerData.path;
27510      if (!div) {
27511        const clipPathId = `clip_selection_${DrawLayer.#selectionId++}`;
27512        div = document.createElement("div");
27513        div.className = "selection";
27514        div.style.clipPath = `url(#${clipPathId})`;
27515        const selectionStyle = drawLayer.#filterFactory?.createSelectionStyle(drawLayer.#pageColors);
27516        if (selectionStyle) {
27517          for (const [name, value] of Object.entries(selectionStyle)) {
27518            div.style.setProperty(name, value);
27519          }
27520        }
27521        const svg = DrawLayer._svgFactory.create(1, 1, true);
27522        svg.setAttribute("aria-hidden", "true");
27523        svg.setAttribute("width", "100%");
27524        svg.setAttribute("height", "100%");
27525        const clipPath = DrawLayer._svgFactory.createElement("clipPath");
27526        clipPath.setAttribute("id", clipPathId);
27527        clipPath.setAttribute("clipPathUnits", "objectBoundingBox");
27528        path = DrawLayer._svgFactory.createElement("path");
27529        clipPath.append(path);
27530        svg.append(clipPath);
27531        div.append(svg);
27532        textLayerData.path = path;
27533        textLayerData.selectionDiv = div;
27534      }
27535      if (
27535!div.parentNode &&
vendor: 10,727 bytes, lines 27535-27892
27535 drawLayer.#parent) {
27536        drawLayer.#parent.append(div);
27537        this.#selections.add(div);
27538      }
27539      path.setAttribute("d", boxes.join(" "));
27540    }
27541  }
27542  static get _svgFactory() {
27543    return shadow(this, "_svgFactory", new DOMSVGFactory());
27544  }
27545  static #setBox(element, [x, y, width, height]) {
27546    const {
27547      style
27548    } = element;
27549    style.top = `${100 * y}%`;
27550    style.left = `${100 * x}%`;
27551    style.width = `${100 * width}%`;
27552    style.height = `${100 * height}%`;
27553  }
27554  #createSVG() {
27555    const svg = DrawLayer._svgFactory.create(1, 1, true);
27556    this.#parent.append(svg);
27557    svg.setAttribute("aria-hidden", "true");
27558    return svg;
27559  }
27560  #createClipPath(defs, pathId) {
27561    const clipPath = DrawLayer._svgFactory.createElement("clipPath");
27562    defs.append(clipPath);
27563    const clipPathId = `clip_${pathId}`;
27564    clipPath.setAttribute("id", clipPathId);
27565    clipPath.setAttribute("clipPathUnits", "objectBoundingBox");
27566    const clipPathUse = DrawLayer._svgFactory.createElement("use");
27567    clipPath.append(clipPathUse);
27568    clipPathUse.setAttribute("href", `#${pathId}`);
27569    clipPathUse.classList.add("clip");
27570    return clipPathId;
27571  }
27572  #updateProperties(element, properties) {
27573    for (const [key, value] of Object.entries(properties)) {
27574      if (value === null) {
27575        element.removeAttribute(key);
27576      } else {
27577        element.setAttribute(key, value);
27578      }
27579    }
27580  }
27581  draw(properties, isPathUpdatable = false, hasClip = false) {
27582    const id = DrawLayer.#id++;
27583    const root = this.#createSVG();
27584    const defs = DrawLayer._svgFactory.createElement("defs");
27585    root.append(defs);
27586    const path = DrawLayer._svgFactory.createElement("path");
27587    defs.append(path);
27588    const pathId = `path_${id}`;
27589    path.setAttribute("id", pathId);
27590    path.setAttribute("vector-effect", "non-scaling-stroke");
27591    if (isPathUpdatable) {
27592      this.#toUpdate.set(id, path);
27593    }
27594    const clipPathId = hasClip ? this.#createClipPath(defs, pathId) : null;
27595    const use = DrawLayer._svgFactory.createElement("use");
27596    root.append(use);
27597    use.setAttribute("href", `#${pathId}`);
27598    this.updateProperties(root, properties);
27599    this.#mapping.set(id, root);
27600    return {
27601      id,
27602      clipPathId: `url(#${clipPathId})`
27603    };
27604  }
27605  drawOutline(properties, mustRemoveSelfIntersections) {
27606    const id = DrawLayer.#id++;
27607    const root = this.#createSVG();
27608    const defs = DrawLayer._svgFactory.createElement("defs");
27609    root.append(defs);
27610    const path = DrawLayer._svgFactory.createElement("path");
27611    defs.append(path);
27612    const pathId = `path_${id}`;
27613    path.setAttribute("id", pathId);
27614    path.setAttribute("vector-effect", "non-scaling-stroke");
27615    let maskId;
27616    if (mustRemoveSelfIntersections) {
27617      const mask = DrawLayer._svgFactory.createElement("mask");
27618      defs.append(mask);
27619      maskId = `mask_${id}`;
27620      mask.setAttribute("id", maskId);
27621      mask.setAttribute("maskUnits", "objectBoundingBox");
27622      const rect = DrawLayer._svgFactory.createElement("rect");
27623      mask.append(rect);
27624      rect.setAttribute("width", "1");
27625      rect.setAttribute("height", "1");
27626      rect.setAttribute("fill", "white");
27627      const use = DrawLayer._svgFactory.createElement("use");
27628      mask.append(use);
27629      use.setAttribute("href", `#${pathId}`);
27630      use.setAttribute("stroke", "none");
27631      use.setAttribute("fill", "black");
27632      use.setAttribute("fill-rule", "nonzero");
27633      use.classList.add("mask");
27634    }
27635    const use1 = DrawLayer._svgFactory.createElement("use");
27636    root.append(use1);
27637    use1.setAttribute("href", `#${pathId}`);
27638    if (maskId) {
27639      use1.setAttribute("mask", `url(#${maskId})`);
27640    }
27641    const use2 = use1.cloneNode();
27642    root.append(use2);
27643    use1.classList.add("mainOutline");
27644    use2.classList.add("secondaryOutline");
27645    this.updateProperties(root, properties);
27646    this.#mapping.set(id, root);
27647    return id;
27648  }
27649  finalizeDraw(id, properties) {
27650    this.#toUpdate.delete(id);
27651    this.updateProperties(id, properties);
27652  }
27653  updateProperties(elementOrId, properties) {
27654    if (!properties) {
27655      return;
27656    }
27657    const {
27658      root,
27659      bbox,
27660      rootClass,
27661      path
27662    } = properties;
27663    const element = typeof elementOrId === "number" ? this.#mapping.get(elementOrId) : elementOrId;
27664    if (!element) {
27665      return;
27666    }
27667    if (root) {
27668      this.#updateProperties(element, root);
27669    }
27670    if (bbox) {
27671      DrawLayer.#setBox(element, bbox);
27672    }
27673    if (rootClass) {
27674      const {
27675        classList
27676      } = element;
27677      for (const [className, value] of Object.entries(rootClass)) {
27678        classList.toggle(className, value);
27679      }
27680    }
27681    if (path) {
27682      const defs = element.firstElementChild;
27683      const pathElement = defs.firstElementChild;
27684      this.#updateProperties(pathElement, path);
27685    }
27686  }
27687  updateParent(id, layer) {
27688    if (layer === this) {
27689      return;
27690    }
27691    const root = this.#mapping.get(id);
27692    if (!root) {
27693      return;
27694    }
27695    layer.#parent.append(root);
27696    this.#mapping.delete(id);
27697    layer.#mapping.set(id, root);
27698  }
27699  remove(id) {
27700    this.#toUpdate.delete(id);
27701    if (this.#parent === null) {
27702      return;
27703    }
27704    this.#mapping.get(id).remove();
27705    this.#mapping.delete(id);
27706  }
27707  destroy() {
27708    this.#parent = null;
27709    for (const root of this.#mapping.values()) {
27710      root.remove();
27711    }
27712    this.#mapping.clear();
27713    this.#toUpdate.clear();
27714    this.#textLayerObserver?.disconnect();
27715    this.#textLayerObserver = null;
27716    if (this.#textLayer) {
27717      const data = DrawLayer.#textLayers.get(this.#textLayer);
27718      if (data?.drawLayer === this) {
27719        DrawLayer.#cleanupTextLayerSelection(this.#textLayer);
27720        DrawLayer.#textLayers.delete(this.#textLayer);
27721        DrawLayer.#textLayerSet.delete(this.#textLayer);
27722        if (DrawLayer.#textLayerSet.size === 0) {
27723          DrawLayer.#selectionChangeAC?.abort();
27724          DrawLayer.#selectionChangeAC = null;
27725          DrawLayer.#isSelecting = false;
27726        }
27727      }
27728      this.#textLayer = null;
27729    }
27730  }
27731}
27732
27733;// ./src/display/text_layer_images.js
27734
27735function percentage(value) {
27736  return `${(value * 100).toFixed(2)}%`;
27737}
27738class TextLayerImages {
27739  #coordinates = [];
27740  #coordinatesByElement = new Map();
27741  #getPageCanvas = null;
27742  #minSize = 0;
27743  #pageWidth = 0;
27744  #pageHeight = 0;
27745  static #activeImage = null;
27746  constructor(minSize, coordinates, viewport, getPageCanvas) {
27747    this.#minSize = minSize;
27748    this.#coordinates = coordinates;
27749    this.#pageWidth = viewport.rawDims.pageWidth;
27750    this.#pageHeight = viewport.rawDims.pageHeight;
27751    this.#getPageCanvas = getPageCanvas;
27752  }
27753  render() {
27754    const container = document.createElement("div");
27755    container.className = "textLayerImages";
27756    for (let i = 0; i < this.#coordinates.length; i += 6) {
27757      const el = this.#createImagePlaceholder(this.#coordinates.subarray(i, i + 6));
27758      if (el) {
27759        container.append(el);
27760      }
27761    }
27762    container.addEventListener("contextmenu", event => {
27763      if (!(event.target instanceof HTMLCanvasElement)) {
27764        return;
27765      }
27766      const imgElement = event.target;
27767      const coords = this.#coordinatesByElement.get(imgElement);
27768      if (!coords) {
27769        return;
27770      }
27771      const activeImage = TextLayerImages.#activeImage?.deref();
27772      if (activeImage === imgElement) {
27773        return;
27774      }
27775      if (activeImage) {
27776        activeImage.width = 0;
27777        activeImage.height = 0;
27778      }
27779      TextLayerImages.#activeImage = new WeakRef(imgElement);
27780      const {
27781        inverseTransform,
27782        x1,
27783        y1,
27784        width,
27785        height
27786      } = coords;
27787      const pageCanvas = this.#getPageCanvas();
27788      const imageX1 = Math.ceil(x1 * pageCanvas.width);
27789      const imageY1 = Math.ceil(y1 * pageCanvas.height);
27790      const imageX2 = Math.floor((x1 + width / this.#pageWidth) * pageCanvas.width);
27791      const imageY2 = Math.floor((y1 + height / this.#pageHeight) * pageCanvas.height);
27792      imgElement.width = imageX2 - imageX1;
27793      imgElement.height = imageY2 - imageY1;
27794      const ctx = imgElement.getContext("2d");
27795      ctx.setTransform(...inverseTransform);
27796      ctx.translate(-imageX1, -imageY1);
27797      ctx.drawImage(pageCanvas, 0, 0);
27798    });
27799    return container;
27800  }
27801  #createImagePlaceholder([x1, y1, x2, y2, x3, y3]) {
27802    const width = Math.hypot((x3 - x1) * this.#pageWidth, (y3 - y1) * this.#pageHeight);
27803    const height = Math.hypot((x2 - x1) * this.#pageWidth, (y2 - y1) * this.#pageHeight);
27804    if (width < this.#minSize || height < this.#minSize) {
27805      return null;
27806    }
27807    const transform = [(x3 - x1) * this.#pageWidth / width, (y3 - y1) * this.#pageHeight / width, (x2 - x1) * this.#pageWidth / height, (y2 - y1) * this.#pageHeight / height, 0, 0];
27808    const inverseTransform = Util.inverseTransform(transform);
27809    const imgElement = document.createElement("canvas");
27810    imgElement.className = "textLayerImagePlaceholder";
27811    imgElement.width = 0;
27812    imgElement.height = 0;
27813    Object.assign(imgElement.style, {
27814      opacity: 0,
27815      position: "absolute",
27816      left: percentage(x1),
27817      top: percentage(y1),
27818      width: percentage(width / this.#pageWidth),
27819      height: percentage(height / this.#pageHeight),
27820      transformOrigin: "0% 0%",
27821      transform: `matrix(${transform.join(",")})`
27822    });
27823    this.#coordinatesByElement.set(imgElement, {
27824      inverseTransform,
27825      width,
27826      height,
27827      x1,
27828      y1
27829    });
27830    return imgElement;
27831  }
27832}
27833
27834;// ./src/pdf.js
27835
27836
27837
27838
27839
27840
27841
27842
27843
27844
27845
27846
27847
27848
27849
27850
27851
27852
27853{
27854  globalThis._pdfjsTestingUtils = {
27855    HighlightOutliner: HighlightOutliner
27856  };
27857}
27858globalThis.pdfjsLib = {
27859  AbortException: AbortException,
27860  AnnotationEditorLayer: AnnotationEditorLayer,
27861  AnnotationEditorParamsType: AnnotationEditorParamsType,
27862  AnnotationEditorType: AnnotationEditorType,
27863  AnnotationEditorUIManager: AnnotationEditorUIManager,
27864  AnnotationLayer: AnnotationLayer,
27865  AnnotationMode: AnnotationMode,
27866  AnnotationType: AnnotationType,
27867  applyOpacity: applyOpacity,
27868  build: build,
27869  ColorPicker: ColorPicker,
27870  createValidAbsoluteUrl: createValidAbsoluteUrl,
27871  CSSConstants: CSSConstants,
27872  DOMSVGFactory: DOMSVGFactory,
27873  DrawLayer: DrawLayer,
27874  FeatureTest: FeatureTest,
27875  fetchData: fetchData,
27876  findContrastColor: findContrastColor,
27877  getDocument: getDocument,
27878  getFilenameFromUrl: getFilenameFromUrl,
27879  getPdfFilenameFromUrl: getPdfFilenameFromUrl,
27880  getRGB: getRGB,
27881  getRGBA: getRGBA,
27882  getUuid: getUuid,
27883  GlobalWorkerOptions: GlobalWorkerOptions,
27884  ImageKind: ImageKind,
27885  InvalidPDFException: InvalidPDFException,
27886  isDataScheme: isDataScheme,
27887  isPdfFile: isPdfFile,
27888  isValidExplicitDest: isValidExplicitDest,
27889  makeArr: makeArr,
27890  makeMap: makeMap,
27891  makeObj: makeObj,
27892  
27892MathClamp: MathClamp,
27893  noContextMenu: noContextMenu,
27894  normalizeUnicode: normalizeUnicode,
27895  OPS: OPS,
27896  OutputScale: OutputScale,
27897  PasswordException: PasswordException,
27898  PasswordResponses: PasswordResponses,
27899  PDFDataRangeTransport: PDFDataRangeTransport,
27900  PDFDateString: PDFDateString,
27901  PDFWorker: PDFWorker,
27902  PermissionFlag: PermissionFlag,
27903  PixelsPerInch: PixelsPerInch,
27904  RenderingCancelledException: RenderingCancelledException,
27905  renderRichText: renderRichText,
27906  ResponseException: ResponseException,
27907  setLayerDimensions: setLayerDimensions,
27908  shadow: shadow,
27909  SignatureExtractor: SignatureExtractor,
27910  stopEvent: stopEvent,
27911  SupportedImageMimeTypes: SupportedImageMimeTypes,
27912  TextLayer: TextLayer,
27913  TextLayerImages: TextLayerImages,
27914  TouchManager: TouchManager,
27915  updateUrlHash: updateUrlHash,
27916  Util: Util,
27917  VerbosityLevel: VerbosityLevel,
27918  version: version,
27919  XfaLayer: XfaLayer
27920};
27921
27922export { AbortException, AnnotationEditorLayer, AnnotationEditorParamsType, AnnotationEditorType, AnnotationEditorUIManager, AnnotationLayer, AnnotationMode, AnnotationType, CSSConstants, ColorPicker, DOMSVGFactory, DrawLayer, FeatureTest, GlobalWorkerOptions, ImageKind, InvalidPDFException, MathClamp, OPS, OutputScale, PDFDataRangeTransport, PDFDateString, PDFWorker, PasswordException, PasswordResponses, PermissionFlag, PixelsPerInch, RenderingCancelledException, ResponseException, SignatureExtractor, SupportedImageMimeTypes, TextLayer, TextLayerImages, TouchManager, Util, VerbosityLevel, XfaLayer, applyOpacity, build, createValidAbsoluteUrl, fetchData, findContrastColor, getDocument, getFilenameFromUrl, getPdfFilenameFromUrl, getRGB, getRGBA, getUuid, isDataScheme, isPdfFile, isValidExplicitDest, makeArr, makeMap, makeObj, noContextMenu, normalizeUnicode, renderRichText, setLayerDimensions, shadow, stopEvent, updateUrlHash, version };
27923
27924//# 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.