Compare commits
	
		
			16 Commits
		
	
	
		
			b14f696071
			...
			2a68724b53
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2a68724b53 | ||
| 
						 | 
					65d618635c | ||
| 
						 | 
					30e69956db | ||
| 
						 | 
					e650b95253 | ||
| 
						 | 
					a7d47af474 | ||
| 
						 | 
					b54887cfab | ||
| 
						 | 
					b4267cd294 | ||
| 
						 | 
					eb160726ee | ||
| 
						 | 
					70b6ddc5d9 | ||
| 
						 | 
					3c78ff5fb0 | ||
| 
						 | 
					e647311a89 | ||
| 
						 | 
					f676c2c0c8 | ||
| 
						 | 
					dab8a2eaa4 | ||
| 
						 | 
					db2849cc17 | ||
| 
						 | 
					38004b65b1 | ||
| 
						 | 
					90b2664622 | 
@ -72,6 +72,10 @@
 | 
				
			|||||||
      "type": "boolean",
 | 
					      "type": "boolean",
 | 
				
			||||||
      "default": false
 | 
					      "default": false
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "enableHighlightFloatingButton": {
 | 
				
			||||||
 | 
					      "type": "boolean",
 | 
				
			||||||
 | 
					      "default": false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "highlightEditorColors": {
 | 
					    "highlightEditorColors": {
 | 
				
			||||||
      "type": "string",
 | 
					      "type": "string",
 | 
				
			||||||
      "default": "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F"
 | 
					      "default": "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										28
									
								
								gulpfile.mjs
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								gulpfile.mjs
									
									
									
									
									
								
							@ -863,11 +863,17 @@ async function parseDefaultPreferences(dir) {
 | 
				
			|||||||
    "./" + DEFAULT_PREFERENCES_DIR + dir + "app_options.mjs"
 | 
					    "./" + DEFAULT_PREFERENCES_DIR + dir + "app_options.mjs"
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const browserPrefs = AppOptions.getAll(OptionKind.BROWSER);
 | 
					  const browserPrefs = AppOptions.getAll(
 | 
				
			||||||
 | 
					    OptionKind.BROWSER,
 | 
				
			||||||
 | 
					    /* defaultOnly = */ true
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
  if (Object.keys(browserPrefs).length === 0) {
 | 
					  if (Object.keys(browserPrefs).length === 0) {
 | 
				
			||||||
    throw new Error("No browser preferences found.");
 | 
					    throw new Error("No browser preferences found.");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  const prefs = AppOptions.getAll(OptionKind.PREFERENCE);
 | 
					  const prefs = AppOptions.getAll(
 | 
				
			||||||
 | 
					    OptionKind.PREFERENCE,
 | 
				
			||||||
 | 
					    /* defaultOnly = */ true
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
  if (Object.keys(prefs).length === 0) {
 | 
					  if (Object.keys(prefs).length === 0) {
 | 
				
			||||||
    throw new Error("No default preferences found.");
 | 
					    throw new Error("No default preferences found.");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -2222,25 +2228,15 @@ gulp.task(
 | 
				
			|||||||
          ])
 | 
					          ])
 | 
				
			||||||
          .pipe(gulp.dest(DIST_DIR + "legacy/build/")),
 | 
					          .pipe(gulp.dest(DIST_DIR + "legacy/build/")),
 | 
				
			||||||
        gulp
 | 
					        gulp
 | 
				
			||||||
          .src(MINIFIED_DIR + "build/pdf.min.mjs")
 | 
					          .src(MINIFIED_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.min.mjs")
 | 
				
			||||||
          .pipe(gulp.dest(DIST_DIR + "build/")),
 | 
					 | 
				
			||||||
        gulp
 | 
					 | 
				
			||||||
          .src(MINIFIED_DIR + "build/pdf.worker.min.mjs")
 | 
					 | 
				
			||||||
          .pipe(gulp.dest(DIST_DIR + "build/")),
 | 
					 | 
				
			||||||
        gulp
 | 
					 | 
				
			||||||
          .src(MINIFIED_DIR + "build/pdf.sandbox.min.mjs")
 | 
					 | 
				
			||||||
          .pipe(gulp.dest(DIST_DIR + "build/")),
 | 
					          .pipe(gulp.dest(DIST_DIR + "build/")),
 | 
				
			||||||
        gulp
 | 
					        gulp
 | 
				
			||||||
          .src(MINIFIED_DIR + "image_decoders/pdf.image_decoders.min.mjs")
 | 
					          .src(MINIFIED_DIR + "image_decoders/pdf.image_decoders.min.mjs")
 | 
				
			||||||
          .pipe(gulp.dest(DIST_DIR + "image_decoders/")),
 | 
					          .pipe(gulp.dest(DIST_DIR + "image_decoders/")),
 | 
				
			||||||
        gulp
 | 
					        gulp
 | 
				
			||||||
          .src(MINIFIED_LEGACY_DIR + "build/pdf.min.mjs")
 | 
					          .src(
 | 
				
			||||||
          .pipe(gulp.dest(DIST_DIR + "legacy/build/")),
 | 
					            MINIFIED_LEGACY_DIR + "build/{pdf,pdf.worker,pdf.sandbox}.min.mjs"
 | 
				
			||||||
        gulp
 | 
					          )
 | 
				
			||||||
          .src(MINIFIED_LEGACY_DIR + "build/pdf.worker.min.mjs")
 | 
					 | 
				
			||||||
          .pipe(gulp.dest(DIST_DIR + "legacy/build/")),
 | 
					 | 
				
			||||||
        gulp
 | 
					 | 
				
			||||||
          .src(MINIFIED_LEGACY_DIR + "build/pdf.sandbox.min.mjs")
 | 
					 | 
				
			||||||
          .pipe(gulp.dest(DIST_DIR + "legacy/build/")),
 | 
					          .pipe(gulp.dest(DIST_DIR + "legacy/build/")),
 | 
				
			||||||
        gulp
 | 
					        gulp
 | 
				
			||||||
          .src(
 | 
					          .src(
 | 
				
			||||||
 | 
				
			|||||||
@ -318,6 +318,8 @@ pdfjs-editor-stamp-button-label = Add or edit images
 | 
				
			|||||||
pdfjs-editor-highlight-button =
 | 
					pdfjs-editor-highlight-button =
 | 
				
			||||||
    .title = Highlight
 | 
					    .title = Highlight
 | 
				
			||||||
pdfjs-editor-highlight-button-label = Highlight
 | 
					pdfjs-editor-highlight-button-label = Highlight
 | 
				
			||||||
 | 
					pdfjs-highlight-floating-button =
 | 
				
			||||||
 | 
					    .title = Highlight
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Remove button for the various kind of editor.
 | 
					## Remove button for the various kind of editor.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -445,20 +445,10 @@ class Catalog {
 | 
				
			|||||||
          continue;
 | 
					          continue;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        groupRefs.put(groupRef);
 | 
					        groupRefs.put(groupRef);
 | 
				
			||||||
        const group = this.xref.fetch(groupRef);
 | 
					
 | 
				
			||||||
        groups.push({
 | 
					        groups.push(this.#readOptionalContentGroup(groupRef));
 | 
				
			||||||
          id: groupRef.toString(),
 | 
					 | 
				
			||||||
          name:
 | 
					 | 
				
			||||||
            typeof group.get("Name") === "string"
 | 
					 | 
				
			||||||
              ? stringToPDFString(group.get("Name"))
 | 
					 | 
				
			||||||
              : null,
 | 
					 | 
				
			||||||
          intent:
 | 
					 | 
				
			||||||
            typeof group.get("Intent") === "string"
 | 
					 | 
				
			||||||
              ? stringToPDFString(group.get("Intent"))
 | 
					 | 
				
			||||||
              : null,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      config = this._readOptionalContentConfig(defaultConfig, groupRefs);
 | 
					      config = this.#readOptionalContentConfig(defaultConfig, groupRefs);
 | 
				
			||||||
      config.groups = groups;
 | 
					      config.groups = groups;
 | 
				
			||||||
    } catch (ex) {
 | 
					    } catch (ex) {
 | 
				
			||||||
      if (ex instanceof MissingDataException) {
 | 
					      if (ex instanceof MissingDataException) {
 | 
				
			||||||
@ -469,7 +459,65 @@ class Catalog {
 | 
				
			|||||||
    return shadow(this, "optionalContentConfig", config);
 | 
					    return shadow(this, "optionalContentConfig", config);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _readOptionalContentConfig(config, contentGroupRefs) {
 | 
					  #readOptionalContentGroup(groupRef) {
 | 
				
			||||||
 | 
					    const group = this.xref.fetch(groupRef);
 | 
				
			||||||
 | 
					    const obj = {
 | 
				
			||||||
 | 
					      id: groupRef.toString(),
 | 
				
			||||||
 | 
					      name: null,
 | 
				
			||||||
 | 
					      intent: null,
 | 
				
			||||||
 | 
					      usage: {
 | 
				
			||||||
 | 
					        print: null,
 | 
				
			||||||
 | 
					        view: null,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const name = group.get("Name");
 | 
				
			||||||
 | 
					    if (typeof name === "string") {
 | 
				
			||||||
 | 
					      obj.name = stringToPDFString(name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let intent = group.getArray("Intent");
 | 
				
			||||||
 | 
					    if (!Array.isArray(intent)) {
 | 
				
			||||||
 | 
					      intent = [intent];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (intent.every(i => i instanceof Name)) {
 | 
				
			||||||
 | 
					      obj.intent = intent.map(i => i.name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const usage = group.get("Usage");
 | 
				
			||||||
 | 
					    if (!(usage instanceof Dict)) {
 | 
				
			||||||
 | 
					      return obj;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const usageObj = obj.usage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const print = usage.get("Print");
 | 
				
			||||||
 | 
					    if (print instanceof Dict) {
 | 
				
			||||||
 | 
					      const printState = print.get("PrintState");
 | 
				
			||||||
 | 
					      if (printState instanceof Name) {
 | 
				
			||||||
 | 
					        switch (printState.name) {
 | 
				
			||||||
 | 
					          case "ON":
 | 
				
			||||||
 | 
					          case "OFF":
 | 
				
			||||||
 | 
					            usageObj.print = { printState: printState.name };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const view = usage.get("View");
 | 
				
			||||||
 | 
					    if (view instanceof Dict) {
 | 
				
			||||||
 | 
					      const viewState = view.get("ViewState");
 | 
				
			||||||
 | 
					      if (viewState instanceof Name) {
 | 
				
			||||||
 | 
					        switch (viewState.name) {
 | 
				
			||||||
 | 
					          case "ON":
 | 
				
			||||||
 | 
					          case "OFF":
 | 
				
			||||||
 | 
					            usageObj.view = { viewState: viewState.name };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return obj;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #readOptionalContentConfig(config, contentGroupRefs) {
 | 
				
			||||||
    function parseOnOff(refs) {
 | 
					    function parseOnOff(refs) {
 | 
				
			||||||
      const onParsed = [];
 | 
					      const onParsed = [];
 | 
				
			||||||
      if (Array.isArray(refs)) {
 | 
					      if (Array.isArray(refs)) {
 | 
				
			||||||
 | 
				
			|||||||
@ -949,12 +949,26 @@ class PDFDocumentProxy {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
 | 
					   * @typedef {Object} GetOptionalContentConfigParameters
 | 
				
			||||||
 | 
					   * @property {string} [intent] - Determines the optional content groups that
 | 
				
			||||||
 | 
					   *   are visible by default; valid values are:
 | 
				
			||||||
 | 
					   *    - 'display' (viewable groups).
 | 
				
			||||||
 | 
					   *    - 'print' (printable groups).
 | 
				
			||||||
 | 
					   *    - 'any' (all groups).
 | 
				
			||||||
 | 
					   *   The default value is 'display'.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * @param {GetOptionalContentConfigParameters} [params] - Optional content
 | 
				
			||||||
 | 
					   *   config parameters.
 | 
				
			||||||
   * @returns {Promise<OptionalContentConfig>} A promise that is resolved with
 | 
					   * @returns {Promise<OptionalContentConfig>} A promise that is resolved with
 | 
				
			||||||
   *   an {@link OptionalContentConfig} that contains all the optional content
 | 
					   *   an {@link OptionalContentConfig} that contains all the optional content
 | 
				
			||||||
   *   groups (assuming that the document has any).
 | 
					   *   groups (assuming that the document has any).
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  getOptionalContentConfig() {
 | 
					  getOptionalContentConfig({ intent = "display" } = {}) {
 | 
				
			||||||
    return this._transport.getOptionalContentConfig();
 | 
					    const { renderingIntent } = this._transport.getRenderingIntent(intent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return this._transport.getOptionalContentConfig(renderingIntent);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@ -1340,17 +1354,14 @@ class PDFPageProxy {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * @param {GetAnnotationsParameters} params - Annotation parameters.
 | 
					   * @param {GetAnnotationsParameters} [params] - Annotation parameters.
 | 
				
			||||||
   * @returns {Promise<Array<any>>} A promise that is resolved with an
 | 
					   * @returns {Promise<Array<any>>} A promise that is resolved with an
 | 
				
			||||||
   *   {Array} of the annotation objects.
 | 
					   *   {Array} of the annotation objects.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  getAnnotations({ intent = "display" } = {}) {
 | 
					  getAnnotations({ intent = "display" } = {}) {
 | 
				
			||||||
    const intentArgs = this._transport.getRenderingIntent(intent);
 | 
					    const { renderingIntent } = this._transport.getRenderingIntent(intent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return this._transport.getAnnotations(
 | 
					    return this._transport.getAnnotations(this._pageIndex, renderingIntent);
 | 
				
			||||||
      this._pageIndex,
 | 
					 | 
				
			||||||
      intentArgs.renderingIntent
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@ -1411,20 +1422,20 @@ class PDFPageProxy {
 | 
				
			|||||||
      annotationMode,
 | 
					      annotationMode,
 | 
				
			||||||
      printAnnotationStorage
 | 
					      printAnnotationStorage
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    const { renderingIntent, cacheKey } = intentArgs;
 | 
				
			||||||
    // If there was a pending destroy, cancel it so no cleanup happens during
 | 
					    // If there was a pending destroy, cancel it so no cleanup happens during
 | 
				
			||||||
    // this call to render...
 | 
					    // this call to render...
 | 
				
			||||||
    this.#pendingCleanup = false;
 | 
					    this.#pendingCleanup = false;
 | 
				
			||||||
    // ... and ensure that a delayed cleanup is always aborted.
 | 
					    // ... and ensure that a delayed cleanup is always aborted.
 | 
				
			||||||
    this.#abortDelayedCleanup();
 | 
					    this.#abortDelayedCleanup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!optionalContentConfigPromise) {
 | 
					    optionalContentConfigPromise ||=
 | 
				
			||||||
      optionalContentConfigPromise = this._transport.getOptionalContentConfig();
 | 
					      this._transport.getOptionalContentConfig(renderingIntent);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let intentState = this._intentStates.get(intentArgs.cacheKey);
 | 
					    let intentState = this._intentStates.get(cacheKey);
 | 
				
			||||||
    if (!intentState) {
 | 
					    if (!intentState) {
 | 
				
			||||||
      intentState = Object.create(null);
 | 
					      intentState = Object.create(null);
 | 
				
			||||||
      this._intentStates.set(intentArgs.cacheKey, intentState);
 | 
					      this._intentStates.set(cacheKey, intentState);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Ensure that a pending `streamReader` cancel timeout is always aborted.
 | 
					    // Ensure that a pending `streamReader` cancel timeout is always aborted.
 | 
				
			||||||
@ -1433,9 +1444,7 @@ class PDFPageProxy {
 | 
				
			|||||||
      intentState.streamReaderCancelTimeout = null;
 | 
					      intentState.streamReaderCancelTimeout = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const intentPrint = !!(
 | 
					    const intentPrint = !!(renderingIntent & RenderingIntentFlag.PRINT);
 | 
				
			||||||
      intentArgs.renderingIntent & RenderingIntentFlag.PRINT
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // If there's no displayReadyCapability yet, then the operatorList
 | 
					    // If there's no displayReadyCapability yet, then the operatorList
 | 
				
			||||||
    // was never requested before. Make the request and create the promise.
 | 
					    // was never requested before. Make the request and create the promise.
 | 
				
			||||||
@ -1512,6 +1521,12 @@ class PDFPageProxy {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        this._stats?.time("Rendering");
 | 
					        this._stats?.time("Rendering");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!(optionalContentConfig.renderingIntent & renderingIntent)) {
 | 
				
			||||||
 | 
					          throw new Error(
 | 
				
			||||||
 | 
					            "Must use the same `intent`-argument when calling the `PDFPageProxy.render` " +
 | 
				
			||||||
 | 
					              "and `PDFDocumentProxy.getOptionalContentConfig` methods."
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        internalRenderTask.initializeGraphics({
 | 
					        internalRenderTask.initializeGraphics({
 | 
				
			||||||
          transparency,
 | 
					          transparency,
 | 
				
			||||||
          optionalContentConfig,
 | 
					          optionalContentConfig,
 | 
				
			||||||
@ -2994,10 +3009,10 @@ class WorkerTransport {
 | 
				
			|||||||
    return this.messageHandler.sendWithPromise("GetOutline", null);
 | 
					    return this.messageHandler.sendWithPromise("GetOutline", null);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getOptionalContentConfig() {
 | 
					  getOptionalContentConfig(renderingIntent) {
 | 
				
			||||||
    return this.messageHandler
 | 
					    return this.#cacheSimpleMethod("GetOptionalContentConfig").then(
 | 
				
			||||||
      .sendWithPromise("GetOptionalContentConfig", null)
 | 
					      data => new OptionalContentConfig(data, renderingIntent)
 | 
				
			||||||
      .then(results => new OptionalContentConfig(results));
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getPermissions() {
 | 
					  getPermissions() {
 | 
				
			||||||
 | 
				
			|||||||
@ -66,6 +66,7 @@ class DrawLayer {
 | 
				
			|||||||
  #createSVG(box) {
 | 
					  #createSVG(box) {
 | 
				
			||||||
    const svg = DrawLayer._svgFactory.create(1, 1, /* skipDimensions = */ true);
 | 
					    const svg = DrawLayer._svgFactory.create(1, 1, /* skipDimensions = */ true);
 | 
				
			||||||
    this.#parent.append(svg);
 | 
					    this.#parent.append(svg);
 | 
				
			||||||
 | 
					    svg.setAttribute("aria-hidden", true);
 | 
				
			||||||
    DrawLayer.#setBox(svg, box);
 | 
					    DrawLayer.#setBox(svg, box);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return svg;
 | 
					    return svg;
 | 
				
			||||||
 | 
				
			|||||||
@ -93,6 +93,7 @@ class ColorPicker {
 | 
				
			|||||||
    button.addEventListener("keydown", this.#boundKeyDown);
 | 
					    button.addEventListener("keydown", this.#boundKeyDown);
 | 
				
			||||||
    const swatch = (this.#buttonSwatch = document.createElement("span"));
 | 
					    const swatch = (this.#buttonSwatch = document.createElement("span"));
 | 
				
			||||||
    swatch.className = "swatch";
 | 
					    swatch.className = "swatch";
 | 
				
			||||||
 | 
					    swatch.setAttribute("aria-hidden", true);
 | 
				
			||||||
    swatch.style.backgroundColor = this.#defaultColor;
 | 
					    swatch.style.backgroundColor = this.#defaultColor;
 | 
				
			||||||
    button.append(swatch);
 | 
					    button.append(swatch);
 | 
				
			||||||
    return button;
 | 
					    return button;
 | 
				
			||||||
 | 
				
			|||||||
@ -61,6 +61,8 @@ class HighlightEditor extends AnnotationEditor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  #outlineId = null;
 | 
					  #outlineId = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #text = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #thickness;
 | 
					  #thickness;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #methodOfCreation = "";
 | 
					  #methodOfCreation = "";
 | 
				
			||||||
@ -104,6 +106,7 @@ class HighlightEditor extends AnnotationEditor {
 | 
				
			|||||||
    this.#opacity = params.opacity || HighlightEditor._defaultOpacity;
 | 
					    this.#opacity = params.opacity || HighlightEditor._defaultOpacity;
 | 
				
			||||||
    this.#boxes = params.boxes || null;
 | 
					    this.#boxes = params.boxes || null;
 | 
				
			||||||
    this.#methodOfCreation = params.methodOfCreation || "";
 | 
					    this.#methodOfCreation = params.methodOfCreation || "";
 | 
				
			||||||
 | 
					    this.#text = params.text || "";
 | 
				
			||||||
    this._isDraggable = false;
 | 
					    this._isDraggable = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (params.highlightId > -1) {
 | 
					    if (params.highlightId > -1) {
 | 
				
			||||||
@ -558,6 +561,13 @@ class HighlightEditor extends AnnotationEditor {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const div = super.render();
 | 
					    const div = super.render();
 | 
				
			||||||
 | 
					    if (this.#text) {
 | 
				
			||||||
 | 
					      const mark = document.createElement("mark");
 | 
				
			||||||
 | 
					      div.append(mark);
 | 
				
			||||||
 | 
					      mark.append(document.createTextNode(this.#text));
 | 
				
			||||||
 | 
					      // The text is invisible but it's still visible by a screen reader.
 | 
				
			||||||
 | 
					      mark.className = "visuallyHidden";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (this.#isFreeHighlight) {
 | 
					    if (this.#isFreeHighlight) {
 | 
				
			||||||
      div.classList.add("free");
 | 
					      div.classList.add("free");
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@ -565,6 +575,7 @@ class HighlightEditor extends AnnotationEditor {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    const highlightDiv = (this.#highlightDiv = document.createElement("div"));
 | 
					    const highlightDiv = (this.#highlightDiv = document.createElement("div"));
 | 
				
			||||||
    div.append(highlightDiv);
 | 
					    div.append(highlightDiv);
 | 
				
			||||||
 | 
					    highlightDiv.setAttribute("aria-hidden", "true");
 | 
				
			||||||
    highlightDiv.className = "internal";
 | 
					    highlightDiv.className = "internal";
 | 
				
			||||||
    highlightDiv.style.clipPath = this.#clipPathId;
 | 
					    highlightDiv.style.clipPath = this.#clipPathId;
 | 
				
			||||||
    const [parentWidth, parentHeight] = this.parentDimensions;
 | 
					    const [parentWidth, parentHeight] = this.parentDimensions;
 | 
				
			||||||
 | 
				
			|||||||
@ -31,6 +31,7 @@ class EditorToolbar {
 | 
				
			|||||||
  render() {
 | 
					  render() {
 | 
				
			||||||
    const editToolbar = (this.#toolbar = document.createElement("div"));
 | 
					    const editToolbar = (this.#toolbar = document.createElement("div"));
 | 
				
			||||||
    editToolbar.className = "editToolbar";
 | 
					    editToolbar.className = "editToolbar";
 | 
				
			||||||
 | 
					    editToolbar.setAttribute("role", "toolbar");
 | 
				
			||||||
    editToolbar.addEventListener("contextmenu", noContextMenu);
 | 
					    editToolbar.addEventListener("contextmenu", noContextMenu);
 | 
				
			||||||
    editToolbar.addEventListener("pointerdown", EditorToolbar.#pointerDown);
 | 
					    editToolbar.addEventListener("pointerdown", EditorToolbar.#pointerDown);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -134,4 +135,80 @@ class EditorToolbar {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export { EditorToolbar };
 | 
					class HighlightToolbar {
 | 
				
			||||||
 | 
					  #buttons = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #toolbar = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #uiManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(uiManager) {
 | 
				
			||||||
 | 
					    this.#uiManager = uiManager;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #render() {
 | 
				
			||||||
 | 
					    const editToolbar = (this.#toolbar = document.createElement("div"));
 | 
				
			||||||
 | 
					    editToolbar.className = "editToolbar";
 | 
				
			||||||
 | 
					    editToolbar.setAttribute("role", "toolbar");
 | 
				
			||||||
 | 
					    editToolbar.addEventListener("contextmenu", noContextMenu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const buttons = (this.#buttons = document.createElement("div"));
 | 
				
			||||||
 | 
					    buttons.className = "buttons";
 | 
				
			||||||
 | 
					    editToolbar.append(buttons);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.#addHighlightButton();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return editToolbar;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #getLastPoint(boxes, isLTR) {
 | 
				
			||||||
 | 
					    let lastY = 0;
 | 
				
			||||||
 | 
					    let lastX = 0;
 | 
				
			||||||
 | 
					    for (const box of boxes) {
 | 
				
			||||||
 | 
					      const y = box.y + box.height;
 | 
				
			||||||
 | 
					      if (y < lastY) {
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const x = box.x + (isLTR ? box.width : 0);
 | 
				
			||||||
 | 
					      if (y > lastY) {
 | 
				
			||||||
 | 
					        lastX = x;
 | 
				
			||||||
 | 
					        lastY = y;
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (isLTR) {
 | 
				
			||||||
 | 
					        if (x > lastX) {
 | 
				
			||||||
 | 
					          lastX = x;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else if (x < lastX) {
 | 
				
			||||||
 | 
					        lastX = x;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return [isLTR ? 1 - lastX : lastX, lastY];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  show(parent, boxes, isLTR) {
 | 
				
			||||||
 | 
					    const [x, y] = this.#getLastPoint(boxes, isLTR);
 | 
				
			||||||
 | 
					    const { style } = (this.#toolbar ||= this.#render());
 | 
				
			||||||
 | 
					    parent.append(this.#toolbar);
 | 
				
			||||||
 | 
					    style.insetInlineEnd = `${100 * x}%`;
 | 
				
			||||||
 | 
					    style.top = `calc(${100 * y}% + var(--editor-toolbar-vert-offset))`;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hide() {
 | 
				
			||||||
 | 
					    this.#toolbar.remove();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #addHighlightButton() {
 | 
				
			||||||
 | 
					    const button = document.createElement("button");
 | 
				
			||||||
 | 
					    button.className = "highlightButton";
 | 
				
			||||||
 | 
					    button.tabIndex = 0;
 | 
				
			||||||
 | 
					    button.setAttribute("data-l10n-id", `pdfjs-highlight-floating-button`);
 | 
				
			||||||
 | 
					    button.addEventListener("contextmenu", noContextMenu);
 | 
				
			||||||
 | 
					    button.addEventListener("click", () => {
 | 
				
			||||||
 | 
					      this.#uiManager.highlightSelection("floating_button");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.#buttons.append(button);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { EditorToolbar, HighlightToolbar };
 | 
				
			||||||
 | 
				
			|||||||
@ -33,6 +33,7 @@ import {
 | 
				
			|||||||
  getRGB,
 | 
					  getRGB,
 | 
				
			||||||
  PixelsPerInch,
 | 
					  PixelsPerInch,
 | 
				
			||||||
} from "../display_utils.js";
 | 
					} from "../display_utils.js";
 | 
				
			||||||
 | 
					import { HighlightToolbar } from "./toolbar.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function bindEvents(obj, element, names) {
 | 
					function bindEvents(obj, element, names) {
 | 
				
			||||||
  for (const name of names) {
 | 
					  for (const name of names) {
 | 
				
			||||||
@ -555,6 +556,8 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  #editorsToRescale = new Set();
 | 
					  #editorsToRescale = new Set();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #enableHighlightFloatingButton = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #filterFactory = null;
 | 
					  #filterFactory = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #focusMainContainerTimeoutId = null;
 | 
					  #focusMainContainerTimeoutId = null;
 | 
				
			||||||
@ -563,6 +566,8 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  #highlightWhenShiftUp = false;
 | 
					  #highlightWhenShiftUp = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #highlightToolbar = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #idManager = new IdManager();
 | 
					  #idManager = new IdManager();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #isEnabled = false;
 | 
					  #isEnabled = false;
 | 
				
			||||||
@ -771,6 +776,7 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
    pdfDocument,
 | 
					    pdfDocument,
 | 
				
			||||||
    pageColors,
 | 
					    pageColors,
 | 
				
			||||||
    highlightColors,
 | 
					    highlightColors,
 | 
				
			||||||
 | 
					    enableHighlightFloatingButton,
 | 
				
			||||||
    mlManager
 | 
					    mlManager
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    this.#container = container;
 | 
					    this.#container = container;
 | 
				
			||||||
@ -782,10 +788,12 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
    this._eventBus._on("scalechanging", this.#boundOnScaleChanging);
 | 
					    this._eventBus._on("scalechanging", this.#boundOnScaleChanging);
 | 
				
			||||||
    this._eventBus._on("rotationchanging", this.#boundOnRotationChanging);
 | 
					    this._eventBus._on("rotationchanging", this.#boundOnRotationChanging);
 | 
				
			||||||
    this.#addSelectionListener();
 | 
					    this.#addSelectionListener();
 | 
				
			||||||
 | 
					    this.#addKeyboardManager();
 | 
				
			||||||
    this.#annotationStorage = pdfDocument.annotationStorage;
 | 
					    this.#annotationStorage = pdfDocument.annotationStorage;
 | 
				
			||||||
    this.#filterFactory = pdfDocument.filterFactory;
 | 
					    this.#filterFactory = pdfDocument.filterFactory;
 | 
				
			||||||
    this.#pageColors = pageColors;
 | 
					    this.#pageColors = pageColors;
 | 
				
			||||||
    this.#highlightColors = highlightColors || null;
 | 
					    this.#highlightColors = highlightColors || null;
 | 
				
			||||||
 | 
					    this.#enableHighlightFloatingButton = enableHighlightFloatingButton;
 | 
				
			||||||
    this.#mlManager = mlManager || null;
 | 
					    this.#mlManager = mlManager || null;
 | 
				
			||||||
    this.viewParameters = {
 | 
					    this.viewParameters = {
 | 
				
			||||||
      realScale: PixelsPerInch.PDF_TO_CSS_UNITS,
 | 
					      realScale: PixelsPerInch.PDF_TO_CSS_UNITS,
 | 
				
			||||||
@ -821,6 +829,8 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
    this.#selectedEditors.clear();
 | 
					    this.#selectedEditors.clear();
 | 
				
			||||||
    this.#commandManager.destroy();
 | 
					    this.#commandManager.destroy();
 | 
				
			||||||
    this.#altTextManager?.destroy();
 | 
					    this.#altTextManager?.destroy();
 | 
				
			||||||
 | 
					    this.#highlightToolbar?.hide();
 | 
				
			||||||
 | 
					    this.#highlightToolbar = null;
 | 
				
			||||||
    if (this.#focusMainContainerTimeoutId) {
 | 
					    if (this.#focusMainContainerTimeoutId) {
 | 
				
			||||||
      clearTimeout(this.#focusMainContainerTimeoutId);
 | 
					      clearTimeout(this.#focusMainContainerTimeoutId);
 | 
				
			||||||
      this.#focusMainContainerTimeoutId = null;
 | 
					      this.#focusMainContainerTimeoutId = null;
 | 
				
			||||||
@ -946,24 +956,32 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
    this.viewParameters.rotation = pagesRotation;
 | 
					    this.viewParameters.rotation = pagesRotation;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #getAnchorElementForSelection({ anchorNode }) {
 | 
				
			||||||
 | 
					    return anchorNode.nodeType === Node.TEXT_NODE
 | 
				
			||||||
 | 
					      ? anchorNode.parentElement
 | 
				
			||||||
 | 
					      : anchorNode;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  highlightSelection(methodOfCreation = "") {
 | 
					  highlightSelection(methodOfCreation = "") {
 | 
				
			||||||
    const selection = document.getSelection();
 | 
					    const selection = document.getSelection();
 | 
				
			||||||
    if (!selection || selection.isCollapsed) {
 | 
					    if (!selection || selection.isCollapsed) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const { anchorNode, anchorOffset, focusNode, focusOffset } = selection;
 | 
					    const { anchorNode, anchorOffset, focusNode, focusOffset } = selection;
 | 
				
			||||||
    const anchorElement =
 | 
					    const text = selection.toString();
 | 
				
			||||||
      anchorNode.nodeType === Node.TEXT_NODE
 | 
					    const anchorElement = this.#getAnchorElementForSelection(selection);
 | 
				
			||||||
        ? anchorNode.parentElement
 | 
					 | 
				
			||||||
        : anchorNode;
 | 
					 | 
				
			||||||
    const textLayer = anchorElement.closest(".textLayer");
 | 
					    const textLayer = anchorElement.closest(".textLayer");
 | 
				
			||||||
    const boxes = this.getSelectionBoxes(textLayer);
 | 
					    const boxes = this.getSelectionBoxes(textLayer);
 | 
				
			||||||
 | 
					    if (!boxes) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    selection.empty();
 | 
					    selection.empty();
 | 
				
			||||||
    if (this.#mode === AnnotationEditorType.NONE) {
 | 
					    if (this.#mode === AnnotationEditorType.NONE) {
 | 
				
			||||||
      this._eventBus.dispatch("showannotationeditorui", {
 | 
					      this._eventBus.dispatch("showannotationeditorui", {
 | 
				
			||||||
        source: this,
 | 
					        source: this,
 | 
				
			||||||
        mode: AnnotationEditorType.HIGHLIGHT,
 | 
					        mode: AnnotationEditorType.HIGHLIGHT,
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					      this.showAllEditors("highlight", true, /* updateButton = */ true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    for (const layer of this.#allLayers.values()) {
 | 
					    for (const layer of this.#allLayers.values()) {
 | 
				
			||||||
      if (layer.hasTextLayer(textLayer)) {
 | 
					      if (layer.hasTextLayer(textLayer)) {
 | 
				
			||||||
@ -974,12 +992,28 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
          anchorOffset,
 | 
					          anchorOffset,
 | 
				
			||||||
          focusNode,
 | 
					          focusNode,
 | 
				
			||||||
          focusOffset,
 | 
					          focusOffset,
 | 
				
			||||||
 | 
					          text,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #displayHighlightToolbar() {
 | 
				
			||||||
 | 
					    const selection = document.getSelection();
 | 
				
			||||||
 | 
					    if (!selection || selection.isCollapsed) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const anchorElement = this.#getAnchorElementForSelection(selection);
 | 
				
			||||||
 | 
					    const textLayer = anchorElement.closest(".textLayer");
 | 
				
			||||||
 | 
					    const boxes = this.getSelectionBoxes(textLayer);
 | 
				
			||||||
 | 
					    if (!boxes) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.#highlightToolbar ||= new HighlightToolbar(this);
 | 
				
			||||||
 | 
					    this.#highlightToolbar.show(textLayer, boxes, this.direction === "ltr");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Add an editor in the annotation storage.
 | 
					   * Add an editor in the annotation storage.
 | 
				
			||||||
   * @param {AnnotationEditor} editor
 | 
					   * @param {AnnotationEditor} editor
 | 
				
			||||||
@ -998,6 +1032,7 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
    const selection = document.getSelection();
 | 
					    const selection = document.getSelection();
 | 
				
			||||||
    if (!selection || selection.isCollapsed) {
 | 
					    if (!selection || selection.isCollapsed) {
 | 
				
			||||||
      if (this.#selectedTextNode) {
 | 
					      if (this.#selectedTextNode) {
 | 
				
			||||||
 | 
					        this.#highlightToolbar?.hide();
 | 
				
			||||||
        this.#selectedTextNode = null;
 | 
					        this.#selectedTextNode = null;
 | 
				
			||||||
        this.#dispatchUpdateStates({
 | 
					        this.#dispatchUpdateStates({
 | 
				
			||||||
          hasSelectedText: false,
 | 
					          hasSelectedText: false,
 | 
				
			||||||
@ -1010,12 +1045,11 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const anchorElement =
 | 
					    const anchorElement = this.#getAnchorElementForSelection(selection);
 | 
				
			||||||
      anchorNode.nodeType === Node.TEXT_NODE
 | 
					    const textLayer = anchorElement.closest(".textLayer");
 | 
				
			||||||
        ? anchorNode.parentElement
 | 
					    if (!textLayer) {
 | 
				
			||||||
        : anchorNode;
 | 
					 | 
				
			||||||
    if (!anchorElement.closest(".textLayer")) {
 | 
					 | 
				
			||||||
      if (this.#selectedTextNode) {
 | 
					      if (this.#selectedTextNode) {
 | 
				
			||||||
 | 
					        this.#highlightToolbar?.hide();
 | 
				
			||||||
        this.#selectedTextNode = null;
 | 
					        this.#selectedTextNode = null;
 | 
				
			||||||
        this.#dispatchUpdateStates({
 | 
					        this.#dispatchUpdateStates({
 | 
				
			||||||
          hasSelectedText: false,
 | 
					          hasSelectedText: false,
 | 
				
			||||||
@ -1023,16 +1057,22 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    this.#highlightToolbar?.hide();
 | 
				
			||||||
    this.#selectedTextNode = anchorNode;
 | 
					    this.#selectedTextNode = anchorNode;
 | 
				
			||||||
    this.#dispatchUpdateStates({
 | 
					    this.#dispatchUpdateStates({
 | 
				
			||||||
      hasSelectedText: true,
 | 
					      hasSelectedText: true,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (this.#mode !== AnnotationEditorType.HIGHLIGHT) {
 | 
					    if (
 | 
				
			||||||
 | 
					      this.#mode !== AnnotationEditorType.HIGHLIGHT &&
 | 
				
			||||||
 | 
					      this.#mode !== AnnotationEditorType.NONE
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.showAllEditors("highlight", true, /* updateButton = */ true);
 | 
					    if (this.#mode === AnnotationEditorType.HIGHLIGHT) {
 | 
				
			||||||
 | 
					      this.showAllEditors("highlight", true, /* updateButton = */ true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.#highlightWhenShiftUp = this.isShiftKeyDown;
 | 
					    this.#highlightWhenShiftUp = this.isShiftKeyDown;
 | 
				
			||||||
    if (!this.isShiftKeyDown) {
 | 
					    if (!this.isShiftKeyDown) {
 | 
				
			||||||
@ -1044,7 +1084,7 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
        window.removeEventListener("pointerup", pointerup);
 | 
					        window.removeEventListener("pointerup", pointerup);
 | 
				
			||||||
        window.removeEventListener("blur", pointerup);
 | 
					        window.removeEventListener("blur", pointerup);
 | 
				
			||||||
        if (e.type === "pointerup") {
 | 
					        if (e.type === "pointerup") {
 | 
				
			||||||
          this.highlightSelection("main_toolbar");
 | 
					          this.#onSelectEnd("main_toolbar");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
      window.addEventListener("pointerup", pointerup);
 | 
					      window.addEventListener("pointerup", pointerup);
 | 
				
			||||||
@ -1052,6 +1092,14 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #onSelectEnd(methodOfCreation = "") {
 | 
				
			||||||
 | 
					    if (this.#mode === AnnotationEditorType.HIGHLIGHT) {
 | 
				
			||||||
 | 
					      this.highlightSelection(methodOfCreation);
 | 
				
			||||||
 | 
					    } else if (this.#enableHighlightFloatingButton) {
 | 
				
			||||||
 | 
					      this.#displayHighlightToolbar();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #addSelectionListener() {
 | 
					  #addSelectionListener() {
 | 
				
			||||||
    document.addEventListener("selectionchange", this.#boundSelectionChange);
 | 
					    document.addEventListener("selectionchange", this.#boundSelectionChange);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -1074,7 +1122,7 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
    this.isShiftKeyDown = false;
 | 
					    this.isShiftKeyDown = false;
 | 
				
			||||||
    if (this.#highlightWhenShiftUp) {
 | 
					    if (this.#highlightWhenShiftUp) {
 | 
				
			||||||
      this.#highlightWhenShiftUp = false;
 | 
					      this.#highlightWhenShiftUp = false;
 | 
				
			||||||
      this.highlightSelection("main_toolbar");
 | 
					      this.#onSelectEnd("main_toolbar");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!this.hasSelection) {
 | 
					    if (!this.hasSelection) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
@ -1250,7 +1298,10 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
    if (!this.isShiftKeyDown && event.key === "Shift") {
 | 
					    if (!this.isShiftKeyDown && event.key === "Shift") {
 | 
				
			||||||
      this.isShiftKeyDown = true;
 | 
					      this.isShiftKeyDown = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!this.isEditorHandlingKeyboard) {
 | 
					    if (
 | 
				
			||||||
 | 
					      this.#mode !== AnnotationEditorType.NONE &&
 | 
				
			||||||
 | 
					      !this.isEditorHandlingKeyboard
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
      AnnotationEditorUIManager._keyboardManager.exec(this, event);
 | 
					      AnnotationEditorUIManager._keyboardManager.exec(this, event);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -1264,7 +1315,7 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
      this.isShiftKeyDown = false;
 | 
					      this.isShiftKeyDown = false;
 | 
				
			||||||
      if (this.#highlightWhenShiftUp) {
 | 
					      if (this.#highlightWhenShiftUp) {
 | 
				
			||||||
        this.#highlightWhenShiftUp = false;
 | 
					        this.#highlightWhenShiftUp = false;
 | 
				
			||||||
        this.highlightSelection("main_toolbar");
 | 
					        this.#onSelectEnd("main_toolbar");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -1333,7 +1384,6 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
  setEditingState(isEditing) {
 | 
					  setEditingState(isEditing) {
 | 
				
			||||||
    if (isEditing) {
 | 
					    if (isEditing) {
 | 
				
			||||||
      this.#addFocusManager();
 | 
					      this.#addFocusManager();
 | 
				
			||||||
      this.#addKeyboardManager();
 | 
					 | 
				
			||||||
      this.#addCopyPasteListeners();
 | 
					      this.#addCopyPasteListeners();
 | 
				
			||||||
      this.#dispatchUpdateStates({
 | 
					      this.#dispatchUpdateStates({
 | 
				
			||||||
        isEditing: this.#mode !== AnnotationEditorType.NONE,
 | 
					        isEditing: this.#mode !== AnnotationEditorType.NONE,
 | 
				
			||||||
@ -1344,7 +1394,6 @@ class AnnotationEditorUIManager {
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      this.#removeFocusManager();
 | 
					      this.#removeFocusManager();
 | 
				
			||||||
      this.#removeKeyboardManager();
 | 
					 | 
				
			||||||
      this.#removeCopyPasteListeners();
 | 
					      this.#removeCopyPasteListeners();
 | 
				
			||||||
      this.#dispatchUpdateStates({
 | 
					      this.#dispatchUpdateStates({
 | 
				
			||||||
        isEditing: false,
 | 
					        isEditing: false,
 | 
				
			||||||
 | 
				
			|||||||
@ -424,21 +424,22 @@ class PDFNodeStreamFsFullReader extends BaseFullReader {
 | 
				
			|||||||
      path = path.replace(/^\//, "");
 | 
					      path = path.replace(/^\//, "");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fs.lstat(path, (error, stat) => {
 | 
					    fs.promises.lstat(path).then(
 | 
				
			||||||
      if (error) {
 | 
					      stat => {
 | 
				
			||||||
 | 
					        // Setting right content length.
 | 
				
			||||||
 | 
					        this._contentLength = stat.size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._setReadableStream(fs.createReadStream(path));
 | 
				
			||||||
 | 
					        this._headersCapability.resolve();
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      error => {
 | 
				
			||||||
        if (error.code === "ENOENT") {
 | 
					        if (error.code === "ENOENT") {
 | 
				
			||||||
          error = new MissingPDFException(`Missing PDF "${path}".`);
 | 
					          error = new MissingPDFException(`Missing PDF "${path}".`);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        this._storedError = error;
 | 
					        this._storedError = error;
 | 
				
			||||||
        this._headersCapability.reject(error);
 | 
					        this._headersCapability.reject(error);
 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      // Setting right content length.
 | 
					    );
 | 
				
			||||||
      this._contentLength = stat.size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      this._setReadableStream(fs.createReadStream(path));
 | 
					 | 
				
			||||||
      this._headersCapability.resolve();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -71,15 +71,7 @@ if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("SKIP_BABEL")) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const fetchData = function (url) {
 | 
					const fetchData = function (url) {
 | 
				
			||||||
  return new Promise((resolve, reject) => {
 | 
					  return fs.promises.readFile(url).then(data => new Uint8Array(data));
 | 
				
			||||||
    fs.readFile(url, (error, data) => {
 | 
					 | 
				
			||||||
      if (error || !data) {
 | 
					 | 
				
			||||||
        reject(new Error(error));
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      resolve(new Uint8Array(data));
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NodeFilterFactory extends BaseFilterFactory {}
 | 
					class NodeFilterFactory extends BaseFilterFactory {}
 | 
				
			||||||
 | 
				
			|||||||
@ -13,33 +13,63 @@
 | 
				
			|||||||
 * limitations under the License.
 | 
					 * limitations under the License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { info, objectFromMap, unreachable, warn } from "../shared/util.js";
 | 
					import {
 | 
				
			||||||
 | 
					  info,
 | 
				
			||||||
 | 
					  objectFromMap,
 | 
				
			||||||
 | 
					  RenderingIntentFlag,
 | 
				
			||||||
 | 
					  unreachable,
 | 
				
			||||||
 | 
					  warn,
 | 
				
			||||||
 | 
					} from "../shared/util.js";
 | 
				
			||||||
import { MurmurHash3_64 } from "../shared/murmurhash3.js";
 | 
					import { MurmurHash3_64 } from "../shared/murmurhash3.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const INTERNAL = Symbol("INTERNAL");
 | 
					const INTERNAL = Symbol("INTERNAL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class OptionalContentGroup {
 | 
					class OptionalContentGroup {
 | 
				
			||||||
 | 
					  #isDisplay = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #isPrint = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #userSet = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #visible = true;
 | 
					  #visible = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(name, intent) {
 | 
					  constructor(renderingIntent, { name, intent, usage }) {
 | 
				
			||||||
 | 
					    this.#isDisplay = !!(renderingIntent & RenderingIntentFlag.DISPLAY);
 | 
				
			||||||
 | 
					    this.#isPrint = !!(renderingIntent & RenderingIntentFlag.PRINT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.name = name;
 | 
					    this.name = name;
 | 
				
			||||||
    this.intent = intent;
 | 
					    this.intent = intent;
 | 
				
			||||||
 | 
					    this.usage = usage;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * @type {boolean}
 | 
					   * @type {boolean}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  get visible() {
 | 
					  get visible() {
 | 
				
			||||||
    return this.#visible;
 | 
					    if (this.#userSet) {
 | 
				
			||||||
 | 
					      return this.#visible;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!this.#visible) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const { print, view } = this.usage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (this.#isDisplay) {
 | 
				
			||||||
 | 
					      return view?.viewState !== "OFF";
 | 
				
			||||||
 | 
					    } else if (this.#isPrint) {
 | 
				
			||||||
 | 
					      return print?.printState !== "OFF";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * @ignore
 | 
					   * @ignore
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  _setVisible(internal, visible) {
 | 
					  _setVisible(internal, visible, userSet = false) {
 | 
				
			||||||
    if (internal !== INTERNAL) {
 | 
					    if (internal !== INTERNAL) {
 | 
				
			||||||
      unreachable("Internal method `_setVisible` called.");
 | 
					      unreachable("Internal method `_setVisible` called.");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    this.#userSet = userSet;
 | 
				
			||||||
    this.#visible = visible;
 | 
					    this.#visible = visible;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -53,7 +83,9 @@ class OptionalContentConfig {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  #order = null;
 | 
					  #order = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(data) {
 | 
					  constructor(data, renderingIntent = RenderingIntentFlag.DISPLAY) {
 | 
				
			||||||
 | 
					    this.renderingIntent = renderingIntent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.name = null;
 | 
					    this.name = null;
 | 
				
			||||||
    this.creator = null;
 | 
					    this.creator = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -66,7 +98,7 @@ class OptionalContentConfig {
 | 
				
			|||||||
    for (const group of data.groups) {
 | 
					    for (const group of data.groups) {
 | 
				
			||||||
      this.#groups.set(
 | 
					      this.#groups.set(
 | 
				
			||||||
        group.id,
 | 
					        group.id,
 | 
				
			||||||
        new OptionalContentGroup(group.name, group.intent)
 | 
					        new OptionalContentGroup(renderingIntent, group)
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -198,11 +230,44 @@ class OptionalContentConfig {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setVisibility(id, visible = true) {
 | 
					  setVisibility(id, visible = true) {
 | 
				
			||||||
    if (!this.#groups.has(id)) {
 | 
					    const group = this.#groups.get(id);
 | 
				
			||||||
 | 
					    if (!group) {
 | 
				
			||||||
      warn(`Optional content group not found: ${id}`);
 | 
					      warn(`Optional content group not found: ${id}`);
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.#groups.get(id)._setVisible(INTERNAL, !!visible);
 | 
					    group._setVisible(INTERNAL, !!visible, /* userSet = */ true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.#cachedGetHash = null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  setOCGState({ state, preserveRB }) {
 | 
				
			||||||
 | 
					    let operator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const elem of state) {
 | 
				
			||||||
 | 
					      switch (elem) {
 | 
				
			||||||
 | 
					        case "ON":
 | 
				
			||||||
 | 
					        case "OFF":
 | 
				
			||||||
 | 
					        case "Toggle":
 | 
				
			||||||
 | 
					          operator = elem;
 | 
				
			||||||
 | 
					          continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const group = this.#groups.get(elem);
 | 
				
			||||||
 | 
					      if (!group) {
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      switch (operator) {
 | 
				
			||||||
 | 
					        case "ON":
 | 
				
			||||||
 | 
					          group._setVisible(INTERNAL, true);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case "OFF":
 | 
				
			||||||
 | 
					          group._setVisible(INTERNAL, false);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case "Toggle":
 | 
				
			||||||
 | 
					          group._setVisible(INTERNAL, !group.visible);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.#cachedGetHash = null;
 | 
					    this.#cachedGetHash = null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -684,7 +684,9 @@ class Driver {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            task.pdfDoc = doc;
 | 
					            task.pdfDoc = doc;
 | 
				
			||||||
            task.optionalContentConfigPromise = doc.getOptionalContentConfig();
 | 
					            task.optionalContentConfigPromise = doc.getOptionalContentConfig({
 | 
				
			||||||
 | 
					              intent: task.print ? "print" : "display",
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (task.optionalContent) {
 | 
					            if (task.optionalContent) {
 | 
				
			||||||
              const entries = Object.entries(task.optionalContent),
 | 
					              const entries = Object.entries(task.optionalContent),
 | 
				
			||||||
 | 
				
			|||||||
@ -35,6 +35,7 @@ async function runTests(results) {
 | 
				
			|||||||
      "scripting_spec.mjs",
 | 
					      "scripting_spec.mjs",
 | 
				
			||||||
      "stamp_editor_spec.mjs",
 | 
					      "stamp_editor_spec.mjs",
 | 
				
			||||||
      "text_field_spec.mjs",
 | 
					      "text_field_spec.mjs",
 | 
				
			||||||
 | 
					      "viewer_spec.mjs",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -46,8 +46,11 @@ const getXY = (page, selector) =>
 | 
				
			|||||||
    return `${bbox.x}::${bbox.y}`;
 | 
					    return `${bbox.x}::${bbox.y}`;
 | 
				
			||||||
  }, selector);
 | 
					  }, selector);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getSpanRectFromText = (page, pageNumber, text) =>
 | 
					const getSpanRectFromText = async (page, pageNumber, text) => {
 | 
				
			||||||
  page.evaluate(
 | 
					  await page.waitForSelector(
 | 
				
			||||||
 | 
					    `.page[data-page-number="${pageNumber}"] > .textLayer .endOfContent`
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  return page.evaluate(
 | 
				
			||||||
    (number, content) => {
 | 
					    (number, content) => {
 | 
				
			||||||
      for (const el of document.querySelectorAll(
 | 
					      for (const el of document.querySelectorAll(
 | 
				
			||||||
        `.page[data-page-number="${number}"] > .textLayer > span`
 | 
					        `.page[data-page-number="${number}"] > .textLayer > span`
 | 
				
			||||||
@ -62,6 +65,7 @@ const getSpanRectFromText = (page, pageNumber, text) =>
 | 
				
			|||||||
    pageNumber,
 | 
					    pageNumber,
 | 
				
			||||||
    text
 | 
					    text
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("Highlight Editor", () => {
 | 
					describe("Highlight Editor", () => {
 | 
				
			||||||
  describe("Editor must be removed without exception", () => {
 | 
					  describe("Editor must be removed without exception", () => {
 | 
				
			||||||
@ -1510,4 +1514,46 @@ describe("Highlight Editor", () => {
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe("Highlight from floating highlight button", () => {
 | 
				
			||||||
 | 
					    let pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    beforeAll(async () => {
 | 
				
			||||||
 | 
					      pages = await loadAndWait(
 | 
				
			||||||
 | 
					        "tracemonkey.pdf",
 | 
				
			||||||
 | 
					        ".annotationEditorLayer",
 | 
				
			||||||
 | 
					        null,
 | 
				
			||||||
 | 
					        null,
 | 
				
			||||||
 | 
					        { highlightEditorColors: "red=#AB0000" }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    afterAll(async () => {
 | 
				
			||||||
 | 
					      await closePages(pages);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it("must check that clicking on the highlight floating button triggers an highlight", async () => {
 | 
				
			||||||
 | 
					      await Promise.all(
 | 
				
			||||||
 | 
					        pages.map(async ([browserName, page]) => {
 | 
				
			||||||
 | 
					          const rect = await getSpanRectFromText(page, 1, "Abstract");
 | 
				
			||||||
 | 
					          const x = rect.x + rect.width / 2;
 | 
				
			||||||
 | 
					          const y = rect.y + rect.height / 2;
 | 
				
			||||||
 | 
					          await page.mouse.click(x, y, { count: 2, delay: 100 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          await page.waitForSelector(".textLayer .highlightButton");
 | 
				
			||||||
 | 
					          await page.click(".textLayer .highlightButton");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          await page.waitForSelector(getEditorSelector(0));
 | 
				
			||||||
 | 
					          const usedColor = await page.evaluate(() => {
 | 
				
			||||||
 | 
					            const highlight = document.querySelector(
 | 
				
			||||||
 | 
					              `.page[data-page-number = "1"] .canvasWrapper > svg.highlight`
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            return highlight.getAttribute("fill");
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          expect(usedColor).withContext(`In ${browserName}`).toEqual("#AB0000");
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										58
									
								
								test/integration/viewer_spec.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								test/integration/viewer_spec.mjs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					/* Copyright 2024 Mozilla Foundation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { closePages, loadAndWait } from "./test_utils.mjs";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe("PDF viewer", () => {
 | 
				
			||||||
 | 
					  describe("Zoom with the mouse wheel", () => {
 | 
				
			||||||
 | 
					    let pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    beforeAll(async () => {
 | 
				
			||||||
 | 
					      pages = await loadAndWait("empty.pdf", ".textLayer .endOfContent", 1000);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    afterAll(async () => {
 | 
				
			||||||
 | 
					      await closePages(pages);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it("must check that we can zoom with the mouse wheel and pressed control key", async () => {
 | 
				
			||||||
 | 
					      await Promise.all(
 | 
				
			||||||
 | 
					        pages.map(async ([browserName, page]) => {
 | 
				
			||||||
 | 
					          if (browserName === "firefox") {
 | 
				
			||||||
 | 
					            // Skip this test for Firefox, as it's not working correctly.
 | 
				
			||||||
 | 
					            // See https://github.com/puppeteer/puppeteer/issues/12093.
 | 
				
			||||||
 | 
					            // TODO: Remove this check once the issue is resolved.
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          await page.keyboard.down("Control");
 | 
				
			||||||
 | 
					          let zoom = 10;
 | 
				
			||||||
 | 
					          const zoomGetter = () =>
 | 
				
			||||||
 | 
					            page.evaluate(
 | 
				
			||||||
 | 
					              () => window.PDFViewerApplication.pdfViewer.currentScale
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          while (zoom > 0.1) {
 | 
				
			||||||
 | 
					            await page.mouse.wheel({ deltaY: 100 });
 | 
				
			||||||
 | 
					            zoom = await zoomGetter();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          while (zoom < 10) {
 | 
				
			||||||
 | 
					            await page.mouse.wheel({ deltaY: -100 });
 | 
				
			||||||
 | 
					            zoom = await zoomGetter();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          await page.keyboard.up("Control");
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										1
									
								
								test/pdfs/bug1826783.pdf.link
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/pdfs/bug1826783.pdf.link
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					https://bugzilla.mozilla.org/attachment.cgi?id=9327375
 | 
				
			||||||
@ -4016,6 +4016,23 @@
 | 
				
			|||||||
    "lastPage": 5,
 | 
					    "lastPage": 5,
 | 
				
			||||||
    "type": "eq"
 | 
					    "type": "eq"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "id": "bug1826783-display",
 | 
				
			||||||
 | 
					    "file": "pdfs/bug1826783.pdf",
 | 
				
			||||||
 | 
					    "md5": "93e706efee15dd7b32d32d66f15a3ea2",
 | 
				
			||||||
 | 
					    "rounds": 1,
 | 
				
			||||||
 | 
					    "link": true,
 | 
				
			||||||
 | 
					    "type": "eq"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "id": "bug1826783-print",
 | 
				
			||||||
 | 
					    "file": "pdfs/bug1826783.pdf",
 | 
				
			||||||
 | 
					    "md5": "93e706efee15dd7b32d32d66f15a3ea2",
 | 
				
			||||||
 | 
					    "rounds": 1,
 | 
				
			||||||
 | 
					    "link": true,
 | 
				
			||||||
 | 
					    "type": "eq",
 | 
				
			||||||
 | 
					    "print": true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "id": "issue8586",
 | 
					    "id": "issue8586",
 | 
				
			||||||
    "file": "pdfs/issue8586.pdf",
 | 
					    "file": "pdfs/issue8586.pdf",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										41
									
								
								test/unit/app_options_spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								test/unit/app_options_spec.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					/* Copyright 2024 Mozilla Foundation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { AppOptions, OptionKind } from "../../web/app_options.js";
 | 
				
			||||||
 | 
					import { objectSize } from "../../src/shared/util.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe("AppOptions", function () {
 | 
				
			||||||
 | 
					  it("checks that getAll returns data, for every OptionKind", function () {
 | 
				
			||||||
 | 
					    const KIND_NAMES = ["BROWSER", "VIEWER", "API", "WORKER", "PREFERENCE"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const name of KIND_NAMES) {
 | 
				
			||||||
 | 
					      const kind = OptionKind[name];
 | 
				
			||||||
 | 
					      expect(typeof kind).toEqual("number");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const options = AppOptions.getAll(kind);
 | 
				
			||||||
 | 
					      expect(objectSize(options)).toBeGreaterThan(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('checks that the number of "PREFERENCE" options does *not* exceed the maximum in mozilla-central', function () {
 | 
				
			||||||
 | 
					    // If the following constant is updated then you *MUST* make the same change
 | 
				
			||||||
 | 
					    // in mozilla-central as well to ensure that preference-fetching works; see
 | 
				
			||||||
 | 
					    // https://searchfox.org/mozilla-central/source/toolkit/components/pdfjs/content/PdfStreamConverter.sys.mjs
 | 
				
			||||||
 | 
					    const MAX_NUMBER_OF_PREFS = 50;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const options = AppOptions.getAll(OptionKind.PREFERENCE);
 | 
				
			||||||
 | 
					    expect(objectSize(options)).toBeLessThanOrEqual(MAX_NUMBER_OF_PREFS);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -7,6 +7,7 @@
 | 
				
			|||||||
    "annotation_spec.js",
 | 
					    "annotation_spec.js",
 | 
				
			||||||
    "annotation_storage_spec.js",
 | 
					    "annotation_storage_spec.js",
 | 
				
			||||||
    "api_spec.js",
 | 
					    "api_spec.js",
 | 
				
			||||||
 | 
					    "app_options_spec.js",
 | 
				
			||||||
    "bidi_spec.js",
 | 
					    "bidi_spec.js",
 | 
				
			||||||
    "cff_parser_spec.js",
 | 
					    "cff_parser_spec.js",
 | 
				
			||||||
    "cmap_spec.js",
 | 
					    "cmap_spec.js",
 | 
				
			||||||
 | 
				
			|||||||
@ -50,6 +50,7 @@ async function initializePDFJS(callback) {
 | 
				
			|||||||
      "pdfjs-test/unit/annotation_spec.js",
 | 
					      "pdfjs-test/unit/annotation_spec.js",
 | 
				
			||||||
      "pdfjs-test/unit/annotation_storage_spec.js",
 | 
					      "pdfjs-test/unit/annotation_storage_spec.js",
 | 
				
			||||||
      "pdfjs-test/unit/api_spec.js",
 | 
					      "pdfjs-test/unit/api_spec.js",
 | 
				
			||||||
 | 
					      "pdfjs-test/unit/app_options_spec.js",
 | 
				
			||||||
      "pdfjs-test/unit/bidi_spec.js",
 | 
					      "pdfjs-test/unit/bidi_spec.js",
 | 
				
			||||||
      "pdfjs-test/unit/cff_parser_spec.js",
 | 
					      "pdfjs-test/unit/cff_parser_spec.js",
 | 
				
			||||||
      "pdfjs-test/unit/cmap_spec.js",
 | 
					      "pdfjs-test/unit/cmap_spec.js",
 | 
				
			||||||
 | 
				
			|||||||
@ -48,6 +48,19 @@
 | 
				
			|||||||
    pointer;
 | 
					    pointer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The following class is used to hide an element but keep it available to
 | 
				
			||||||
 | 
					 * for screen readers. */
 | 
				
			||||||
 | 
					.visuallyHidden {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  border: 0;
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					  width: 0;
 | 
				
			||||||
 | 
					  height: 0;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  white-space: nowrap;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.textLayer.highlighting {
 | 
					.textLayer.highlighting {
 | 
				
			||||||
  cursor: var(--editorFreeHighlight-editing-cursor);
 | 
					  cursor: var(--editorFreeHighlight-editing-cursor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -182,10 +195,12 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.annotationEditorLayer
 | 
					.annotationEditorLayer
 | 
				
			||||||
  :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor) {
 | 
					  :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor),
 | 
				
			||||||
 | 
					.textLayer {
 | 
				
			||||||
  .editToolbar {
 | 
					  .editToolbar {
 | 
				
			||||||
    --editor-toolbar-delete-image: url(images/editor-toolbar-delete.svg);
 | 
					    --editor-toolbar-delete-image: url(images/editor-toolbar-delete.svg);
 | 
				
			||||||
    --editor-toolbar-bg-color: #f0f0f4;
 | 
					    --editor-toolbar-bg-color: #f0f0f4;
 | 
				
			||||||
 | 
					    --editor-toolbar-highlight-image: url(images/toolbarButton-editorHighlight.svg);
 | 
				
			||||||
    --editor-toolbar-fg-color: #2e2e56;
 | 
					    --editor-toolbar-fg-color: #2e2e56;
 | 
				
			||||||
    --editor-toolbar-border-color: #8f8f9d;
 | 
					    --editor-toolbar-border-color: #8f8f9d;
 | 
				
			||||||
    --editor-toolbar-hover-border-color: var(--editor-toolbar-border-color);
 | 
					    --editor-toolbar-hover-border-color: var(--editor-toolbar-border-color);
 | 
				
			||||||
@ -271,6 +286,25 @@
 | 
				
			|||||||
        margin-inline: 2px;
 | 
					        margin-inline: 2px;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .highlightButton {
 | 
				
			||||||
 | 
					        width: var(--editor-toolbar-height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        &::before {
 | 
				
			||||||
 | 
					          content: "";
 | 
				
			||||||
 | 
					          mask-image: var(--editor-toolbar-highlight-image);
 | 
				
			||||||
 | 
					          mask-repeat: no-repeat;
 | 
				
			||||||
 | 
					          mask-position: center;
 | 
				
			||||||
 | 
					          display: inline-block;
 | 
				
			||||||
 | 
					          background-color: var(--editor-toolbar-fg-color);
 | 
				
			||||||
 | 
					          width: 100%;
 | 
				
			||||||
 | 
					          height: 100%;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        &:hover::before {
 | 
				
			||||||
 | 
					          background-color: var(--editor-toolbar-hover-fg-color);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      .delete {
 | 
					      .delete {
 | 
				
			||||||
        width: var(--editor-toolbar-height);
 | 
					        width: var(--editor-toolbar-height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -424,6 +424,9 @@ const PDFViewerApplication = {
 | 
				
			|||||||
      annotationMode: AppOptions.get("annotationMode"),
 | 
					      annotationMode: AppOptions.get("annotationMode"),
 | 
				
			||||||
      annotationEditorMode,
 | 
					      annotationEditorMode,
 | 
				
			||||||
      annotationEditorHighlightColors: AppOptions.get("highlightEditorColors"),
 | 
					      annotationEditorHighlightColors: AppOptions.get("highlightEditorColors"),
 | 
				
			||||||
 | 
					      enableHighlightFloatingButton: AppOptions.get(
 | 
				
			||||||
 | 
					        "enableHighlightFloatingButton"
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
      imageResourcesPath: AppOptions.get("imageResourcesPath"),
 | 
					      imageResourcesPath: AppOptions.get("imageResourcesPath"),
 | 
				
			||||||
      enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
 | 
					      enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
 | 
				
			||||||
      maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
 | 
					      maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
 | 
				
			||||||
@ -1796,7 +1799,6 @@ const PDFViewerApplication = {
 | 
				
			|||||||
      pagesOverview: this.pdfViewer.getPagesOverview(),
 | 
					      pagesOverview: this.pdfViewer.getPagesOverview(),
 | 
				
			||||||
      printContainer: this.appConfig.printContainer,
 | 
					      printContainer: this.appConfig.printContainer,
 | 
				
			||||||
      printResolution: AppOptions.get("printResolution"),
 | 
					      printResolution: AppOptions.get("printResolution"),
 | 
				
			||||||
      optionalContentConfigPromise: this.pdfViewer.optionalContentConfigPromise,
 | 
					 | 
				
			||||||
      printAnnotationStoragePromise: this._printAnnotationStoragePromise,
 | 
					      printAnnotationStoragePromise: this._printAnnotationStoragePromise,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    this.forceRendering();
 | 
					    this.forceRendering();
 | 
				
			||||||
@ -2022,8 +2024,9 @@ const PDFViewerApplication = {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
    const scroll = (_boundEvents.mainContainerScroll = () => {
 | 
					    const scroll = (_boundEvents.mainContainerScroll = () => {
 | 
				
			||||||
      if (
 | 
					      if (
 | 
				
			||||||
        this._lastScrollTop === mainContainer.scrollTop &&
 | 
					        this._isCtrlKeyDown ||
 | 
				
			||||||
        this._lastScrollLeft === mainContainer.scrollLeft
 | 
					        (this._lastScrollTop === mainContainer.scrollTop &&
 | 
				
			||||||
 | 
					          this._lastScrollLeft === mainContainer.scrollLeft)
 | 
				
			||||||
      ) {
 | 
					      ) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -143,6 +143,14 @@ const defaultOptions = {
 | 
				
			|||||||
    value: typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING"),
 | 
					    value: typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING"),
 | 
				
			||||||
    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
 | 
					    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  enableHighlightFloatingButton: {
 | 
				
			||||||
 | 
					    // We'll probably want to make some experiments before enabling this
 | 
				
			||||||
 | 
					    // in Firefox release, but it has to be temporary.
 | 
				
			||||||
 | 
					    // TODO: remove it when unnecessary.
 | 
				
			||||||
 | 
					    /** @type {boolean} */
 | 
				
			||||||
 | 
					    value: typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING"),
 | 
				
			||||||
 | 
					    kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  enableML: {
 | 
					  enableML: {
 | 
				
			||||||
    /** @type {boolean} */
 | 
					    /** @type {boolean} */
 | 
				
			||||||
    value: false,
 | 
					    value: false,
 | 
				
			||||||
@ -409,57 +417,64 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const userOptions = Object.create(null);
 | 
					const userOptions = Object.create(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING || LIB")) {
 | 
				
			||||||
 | 
					  // Ensure that the `defaultOptions` are correctly specified.
 | 
				
			||||||
 | 
					  for (const name in defaultOptions) {
 | 
				
			||||||
 | 
					    const { value, kind } = defaultOptions[name];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (kind & OptionKind.PREFERENCE) {
 | 
				
			||||||
 | 
					      if (kind === OptionKind.PREFERENCE) {
 | 
				
			||||||
 | 
					        throw new Error(`Cannot use only "PREFERENCE" kind: ${name}`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (kind & OptionKind.BROWSER) {
 | 
				
			||||||
 | 
					        throw new Error(`Cannot mix "PREFERENCE" and "BROWSER" kind: ${name}`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (compatibilityParams[name] !== undefined) {
 | 
				
			||||||
 | 
					        throw new Error(
 | 
				
			||||||
 | 
					          `Should not have compatibility-value for "PREFERENCE" kind: ${name}`
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // Only "simple" preference-values are allowed.
 | 
				
			||||||
 | 
					      if (
 | 
				
			||||||
 | 
					        typeof value !== "boolean" &&
 | 
				
			||||||
 | 
					        typeof value !== "string" &&
 | 
				
			||||||
 | 
					        !Number.isInteger(value)
 | 
				
			||||||
 | 
					      ) {
 | 
				
			||||||
 | 
					        throw new Error(`Invalid value for "PREFERENCE" kind: ${name}`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AppOptions {
 | 
					class AppOptions {
 | 
				
			||||||
  constructor() {
 | 
					  constructor() {
 | 
				
			||||||
    throw new Error("Cannot initialize AppOptions.");
 | 
					    throw new Error("Cannot initialize AppOptions.");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static get(name) {
 | 
					  static getCompat(name) {
 | 
				
			||||||
    const userOption = userOptions[name];
 | 
					    return compatibilityParams[name] ?? undefined;
 | 
				
			||||||
    if (userOption !== undefined) {
 | 
					 | 
				
			||||||
      return userOption;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    const defaultOption = defaultOptions[name];
 | 
					 | 
				
			||||||
    if (defaultOption !== undefined) {
 | 
					 | 
				
			||||||
      return compatibilityParams[name] ?? defaultOption.value;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return undefined;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static getAll(kind = null) {
 | 
					  static get(name) {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      userOptions[name] ??
 | 
				
			||||||
 | 
					      compatibilityParams[name] ??
 | 
				
			||||||
 | 
					      defaultOptions[name]?.value ??
 | 
				
			||||||
 | 
					      undefined
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static getAll(kind = null, defaultOnly = false) {
 | 
				
			||||||
    const options = Object.create(null);
 | 
					    const options = Object.create(null);
 | 
				
			||||||
    for (const name in defaultOptions) {
 | 
					    for (const name in defaultOptions) {
 | 
				
			||||||
      const defaultOption = defaultOptions[name];
 | 
					      const defaultOption = defaultOptions[name];
 | 
				
			||||||
      if (kind) {
 | 
					 | 
				
			||||||
        if (!(kind & defaultOption.kind)) {
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (
 | 
					 | 
				
			||||||
          (typeof PDFJSDev === "undefined" || PDFJSDev.test("LIB")) &&
 | 
					 | 
				
			||||||
          kind === OptionKind.PREFERENCE
 | 
					 | 
				
			||||||
        ) {
 | 
					 | 
				
			||||||
          if (defaultOption.kind & OptionKind.BROWSER) {
 | 
					 | 
				
			||||||
            throw new Error(`Invalid kind for preference: ${name}`);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          const value = defaultOption.value,
 | 
					 | 
				
			||||||
            valueType = typeof value;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (
 | 
					      if (kind && !(kind & defaultOption.kind)) {
 | 
				
			||||||
            valueType === "boolean" ||
 | 
					        continue;
 | 
				
			||||||
            valueType === "string" ||
 | 
					 | 
				
			||||||
            (valueType === "number" && Number.isInteger(value))
 | 
					 | 
				
			||||||
          ) {
 | 
					 | 
				
			||||||
            options[name] = value;
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          throw new Error(`Invalid type for preference: ${name}`);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      const userOption = userOptions[name];
 | 
					      options[name] = defaultOnly
 | 
				
			||||||
      options[name] =
 | 
					        ? defaultOption.value
 | 
				
			||||||
        userOption !== undefined
 | 
					        : userOptions[name] ?? compatibilityParams[name] ?? defaultOption.value;
 | 
				
			||||||
          ? userOption
 | 
					 | 
				
			||||||
          : compatibilityParams[name] ?? defaultOption.value;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return options;
 | 
					    return options;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -493,4 +508,4 @@ class AppOptions {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export { AppOptions, compatibilityParams, OptionKind };
 | 
					export { AppOptions, OptionKind };
 | 
				
			||||||
 | 
				
			|||||||
@ -119,15 +119,15 @@ class FirefoxPrintService {
 | 
				
			|||||||
    pagesOverview,
 | 
					    pagesOverview,
 | 
				
			||||||
    printContainer,
 | 
					    printContainer,
 | 
				
			||||||
    printResolution,
 | 
					    printResolution,
 | 
				
			||||||
    optionalContentConfigPromise = null,
 | 
					 | 
				
			||||||
    printAnnotationStoragePromise = null,
 | 
					    printAnnotationStoragePromise = null,
 | 
				
			||||||
  }) {
 | 
					  }) {
 | 
				
			||||||
    this.pdfDocument = pdfDocument;
 | 
					    this.pdfDocument = pdfDocument;
 | 
				
			||||||
    this.pagesOverview = pagesOverview;
 | 
					    this.pagesOverview = pagesOverview;
 | 
				
			||||||
    this.printContainer = printContainer;
 | 
					    this.printContainer = printContainer;
 | 
				
			||||||
    this._printResolution = printResolution || 150;
 | 
					    this._printResolution = printResolution || 150;
 | 
				
			||||||
    this._optionalContentConfigPromise =
 | 
					    this._optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
 | 
				
			||||||
      optionalContentConfigPromise || pdfDocument.getOptionalContentConfig();
 | 
					      intent: "print",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    this._printAnnotationStoragePromise =
 | 
					    this._printAnnotationStoragePromise =
 | 
				
			||||||
      printAnnotationStoragePromise || Promise.resolve();
 | 
					      printAnnotationStoragePromise || Promise.resolve();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -258,14 +258,8 @@ if (PDFJSDev.test("GECKOVIEW")) {
 | 
				
			|||||||
            const hasWillPrint =
 | 
					            const hasWillPrint =
 | 
				
			||||||
              pdfViewer.enableScripting &&
 | 
					              pdfViewer.enableScripting &&
 | 
				
			||||||
              !!(await pdfDocument.getJSActions())?.WillPrint;
 | 
					              !!(await pdfDocument.getJSActions())?.WillPrint;
 | 
				
			||||||
            const hasUnchangedOptionalContent = (
 | 
					 | 
				
			||||||
              await pdfViewer.optionalContentConfigPromise
 | 
					 | 
				
			||||||
            ).hasInitialVisibility;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            result =
 | 
					            result = hasUnchangedAnnotations && !hasWillPrint;
 | 
				
			||||||
              hasUnchangedAnnotations &&
 | 
					 | 
				
			||||||
              !hasWillPrint &&
 | 
					 | 
				
			||||||
              hasUnchangedOptionalContent;
 | 
					 | 
				
			||||||
          } catch {
 | 
					          } catch {
 | 
				
			||||||
            console.warn("Unable to check if the document can be downloaded.");
 | 
					            console.warn("Unable to check if the document can be downloaded.");
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
				
			|||||||
@ -182,7 +182,7 @@ class PDFLayerViewer extends BaseTreeViewer {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    const pdfDocument = this._pdfDocument;
 | 
					    const pdfDocument = this._pdfDocument;
 | 
				
			||||||
    const optionalContentConfig = await (promise ||
 | 
					    const optionalContentConfig = await (promise ||
 | 
				
			||||||
      pdfDocument.getOptionalContentConfig());
 | 
					      pdfDocument.getOptionalContentConfig({ intent: "display" }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pdfDocument !== this._pdfDocument) {
 | 
					    if (pdfDocument !== this._pdfDocument) {
 | 
				
			||||||
      return; // The document was closed while the optional content resolved.
 | 
					      return; // The document was closed while the optional content resolved.
 | 
				
			||||||
 | 
				
			|||||||
@ -517,31 +517,7 @@ class PDFLinkService {
 | 
				
			|||||||
    if (pdfDocument !== this.pdfDocument) {
 | 
					    if (pdfDocument !== this.pdfDocument) {
 | 
				
			||||||
      return; // The document was closed while the optional content resolved.
 | 
					      return; // The document was closed while the optional content resolved.
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let operator;
 | 
					    optionalContentConfig.setOCGState(action);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (const elem of action.state) {
 | 
					 | 
				
			||||||
      switch (elem) {
 | 
					 | 
				
			||||||
        case "ON":
 | 
					 | 
				
			||||||
        case "OFF":
 | 
					 | 
				
			||||||
        case "Toggle":
 | 
					 | 
				
			||||||
          operator = elem;
 | 
					 | 
				
			||||||
          continue;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      switch (operator) {
 | 
					 | 
				
			||||||
        case "ON":
 | 
					 | 
				
			||||||
          optionalContentConfig.setVisibility(elem, true);
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
        case "OFF":
 | 
					 | 
				
			||||||
          optionalContentConfig.setVisibility(elem, false);
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
        case "Toggle":
 | 
					 | 
				
			||||||
          const group = optionalContentConfig.getGroup(elem);
 | 
					 | 
				
			||||||
          if (group) {
 | 
					 | 
				
			||||||
            optionalContentConfig.setVisibility(elem, !group.visible);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.pdfViewer.optionalContentConfigPromise = Promise.resolve(
 | 
					    this.pdfViewer.optionalContentConfigPromise = Promise.resolve(
 | 
				
			||||||
      optionalContentConfig
 | 
					      optionalContentConfig
 | 
				
			||||||
 | 
				
			|||||||
@ -41,7 +41,7 @@ import {
 | 
				
			|||||||
} from "./ui_utils.js";
 | 
					} from "./ui_utils.js";
 | 
				
			||||||
import { AnnotationEditorLayerBuilder } from "./annotation_editor_layer_builder.js";
 | 
					import { AnnotationEditorLayerBuilder } from "./annotation_editor_layer_builder.js";
 | 
				
			||||||
import { AnnotationLayerBuilder } from "./annotation_layer_builder.js";
 | 
					import { AnnotationLayerBuilder } from "./annotation_layer_builder.js";
 | 
				
			||||||
import { compatibilityParams } from "./app_options.js";
 | 
					import { AppOptions } from "./app_options.js";
 | 
				
			||||||
import { DrawLayerBuilder } from "./draw_layer_builder.js";
 | 
					import { DrawLayerBuilder } from "./draw_layer_builder.js";
 | 
				
			||||||
import { GenericL10n } from "web-null_l10n";
 | 
					import { GenericL10n } from "web-null_l10n";
 | 
				
			||||||
import { SimpleLinkService } from "./pdf_link_service.js";
 | 
					import { SimpleLinkService } from "./pdf_link_service.js";
 | 
				
			||||||
@ -83,8 +83,6 @@ import { XfaLayerBuilder } from "./xfa_layer_builder.js";
 | 
				
			|||||||
 *   the necessary layer-properties.
 | 
					 *   the necessary layer-properties.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MAX_CANVAS_PIXELS = compatibilityParams.maxCanvasPixels || 16777216;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const DEFAULT_LAYER_PROPERTIES =
 | 
					const DEFAULT_LAYER_PROPERTIES =
 | 
				
			||||||
  typeof PDFJSDev === "undefined" || !PDFJSDev.test("COMPONENTS")
 | 
					  typeof PDFJSDev === "undefined" || !PDFJSDev.test("COMPONENTS")
 | 
				
			||||||
    ? null
 | 
					    ? null
 | 
				
			||||||
@ -152,7 +150,9 @@ class PDFPageView {
 | 
				
			|||||||
    this.#annotationMode =
 | 
					    this.#annotationMode =
 | 
				
			||||||
      options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
 | 
					      options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
 | 
				
			||||||
    this.imageResourcesPath = options.imageResourcesPath || "";
 | 
					    this.imageResourcesPath = options.imageResourcesPath || "";
 | 
				
			||||||
    this.maxCanvasPixels = options.maxCanvasPixels ?? MAX_CANVAS_PIXELS;
 | 
					    this.maxCanvasPixels =
 | 
				
			||||||
 | 
					      options.maxCanvasPixels ??
 | 
				
			||||||
 | 
					      (AppOptions.getCompat("maxCanvasPixels") || 16777216);
 | 
				
			||||||
    this.pageColors = options.pageColors || null;
 | 
					    this.pageColors = options.pageColors || null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.eventBus = options.eventBus;
 | 
					    this.eventBus = options.eventBus;
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,12 @@
 | 
				
			|||||||
 * limitations under the License.
 | 
					 * limitations under the License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { AnnotationMode, PixelsPerInch, shadow } from "pdfjs-lib";
 | 
					import {
 | 
				
			||||||
 | 
					  AnnotationMode,
 | 
				
			||||||
 | 
					  PixelsPerInch,
 | 
				
			||||||
 | 
					  RenderingCancelledException,
 | 
				
			||||||
 | 
					  shadow,
 | 
				
			||||||
 | 
					} from "pdfjs-lib";
 | 
				
			||||||
import { getXfaHtmlForPrinting } from "./print_utils.js";
 | 
					import { getXfaHtmlForPrinting } from "./print_utils.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let activeService = null;
 | 
					let activeService = null;
 | 
				
			||||||
@ -58,7 +63,14 @@ function renderPage(
 | 
				
			|||||||
      optionalContentConfigPromise,
 | 
					      optionalContentConfigPromise,
 | 
				
			||||||
      printAnnotationStorage,
 | 
					      printAnnotationStorage,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    return pdfPage.render(renderContext).promise;
 | 
					    const renderTask = pdfPage.render(renderContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return renderTask.promise.catch(reason => {
 | 
				
			||||||
 | 
					      if (!(reason instanceof RenderingCancelledException)) {
 | 
				
			||||||
 | 
					        console.error(reason);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      throw reason;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -68,15 +80,15 @@ class PDFPrintService {
 | 
				
			|||||||
    pagesOverview,
 | 
					    pagesOverview,
 | 
				
			||||||
    printContainer,
 | 
					    printContainer,
 | 
				
			||||||
    printResolution,
 | 
					    printResolution,
 | 
				
			||||||
    optionalContentConfigPromise = null,
 | 
					 | 
				
			||||||
    printAnnotationStoragePromise = null,
 | 
					    printAnnotationStoragePromise = null,
 | 
				
			||||||
  }) {
 | 
					  }) {
 | 
				
			||||||
    this.pdfDocument = pdfDocument;
 | 
					    this.pdfDocument = pdfDocument;
 | 
				
			||||||
    this.pagesOverview = pagesOverview;
 | 
					    this.pagesOverview = pagesOverview;
 | 
				
			||||||
    this.printContainer = printContainer;
 | 
					    this.printContainer = printContainer;
 | 
				
			||||||
    this._printResolution = printResolution || 150;
 | 
					    this._printResolution = printResolution || 150;
 | 
				
			||||||
    this._optionalContentConfigPromise =
 | 
					    this._optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
 | 
				
			||||||
      optionalContentConfigPromise || pdfDocument.getOptionalContentConfig();
 | 
					      intent: "print",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    this._printAnnotationStoragePromise =
 | 
					    this._printAnnotationStoragePromise =
 | 
				
			||||||
      printAnnotationStoragePromise || Promise.resolve();
 | 
					      printAnnotationStoragePromise || Promise.resolve();
 | 
				
			||||||
    this.currentPage = -1;
 | 
					    this.currentPage = -1;
 | 
				
			||||||
 | 
				
			|||||||
@ -189,7 +189,9 @@ class PDFThumbnailViewer {
 | 
				
			|||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const firstPagePromise = pdfDocument.getPage(1);
 | 
					    const firstPagePromise = pdfDocument.getPage(1);
 | 
				
			||||||
    const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig();
 | 
					    const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
 | 
				
			||||||
 | 
					      intent: "display",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    firstPagePromise
 | 
					    firstPagePromise
 | 
				
			||||||
      .then(firstPdfPage => {
 | 
					      .then(firstPdfPage => {
 | 
				
			||||||
 | 
				
			|||||||
@ -214,6 +214,8 @@ class PDFViewer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  #copyCallbackBound = null;
 | 
					  #copyCallbackBound = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #enableHighlightFloatingButton = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #enablePermissions = false;
 | 
					  #enablePermissions = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #mlManager = null;
 | 
					  #mlManager = null;
 | 
				
			||||||
@ -282,6 +284,8 @@ class PDFViewer {
 | 
				
			|||||||
      options.annotationEditorMode ?? AnnotationEditorType.NONE;
 | 
					      options.annotationEditorMode ?? AnnotationEditorType.NONE;
 | 
				
			||||||
    this.#annotationEditorHighlightColors =
 | 
					    this.#annotationEditorHighlightColors =
 | 
				
			||||||
      options.annotationEditorHighlightColors || null;
 | 
					      options.annotationEditorHighlightColors || null;
 | 
				
			||||||
 | 
					    this.#enableHighlightFloatingButton =
 | 
				
			||||||
 | 
					      options.enableHighlightFloatingButton === true;
 | 
				
			||||||
    this.imageResourcesPath = options.imageResourcesPath || "";
 | 
					    this.imageResourcesPath = options.imageResourcesPath || "";
 | 
				
			||||||
    this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
 | 
					    this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
 | 
				
			||||||
    if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
 | 
					    if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
 | 
				
			||||||
@ -781,7 +785,9 @@ class PDFViewer {
 | 
				
			|||||||
    const pagesCount = pdfDocument.numPages;
 | 
					    const pagesCount = pdfDocument.numPages;
 | 
				
			||||||
    const firstPagePromise = pdfDocument.getPage(1);
 | 
					    const firstPagePromise = pdfDocument.getPage(1);
 | 
				
			||||||
    // Rendering (potentially) depends on this, hence fetching it immediately.
 | 
					    // Rendering (potentially) depends on this, hence fetching it immediately.
 | 
				
			||||||
    const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig();
 | 
					    const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
 | 
				
			||||||
 | 
					      intent: "display",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    const permissionsPromise = this.#enablePermissions
 | 
					    const permissionsPromise = this.#enablePermissions
 | 
				
			||||||
      ? pdfDocument.getPermissions()
 | 
					      ? pdfDocument.getPermissions()
 | 
				
			||||||
      : Promise.resolve();
 | 
					      : Promise.resolve();
 | 
				
			||||||
@ -861,6 +867,7 @@ class PDFViewer {
 | 
				
			|||||||
              pdfDocument,
 | 
					              pdfDocument,
 | 
				
			||||||
              this.pageColors,
 | 
					              this.pageColors,
 | 
				
			||||||
              this.#annotationEditorHighlightColors,
 | 
					              this.#annotationEditorHighlightColors,
 | 
				
			||||||
 | 
					              this.#enableHighlightFloatingButton,
 | 
				
			||||||
              this.#mlManager
 | 
					              this.#mlManager
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            this.eventBus.dispatch("annotationeditoruimanager", {
 | 
					            this.eventBus.dispatch("annotationeditoruimanager", {
 | 
				
			||||||
@ -1822,7 +1829,7 @@ class PDFViewer {
 | 
				
			|||||||
      console.error("optionalContentConfigPromise: Not initialized yet.");
 | 
					      console.error("optionalContentConfigPromise: Not initialized yet.");
 | 
				
			||||||
      // Prevent issues if the getter is accessed *before* the `onePageRendered`
 | 
					      // Prevent issues if the getter is accessed *before* the `onePageRendered`
 | 
				
			||||||
      // promise has resolved; won't (normally) happen in the default viewer.
 | 
					      // promise has resolved; won't (normally) happen in the default viewer.
 | 
				
			||||||
      return this.pdfDocument.getOptionalContentConfig();
 | 
					      return this.pdfDocument.getOptionalContentConfig({ intent: "display" });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return this._optionalContentConfigPromise;
 | 
					    return this._optionalContentConfigPromise;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ import { AppOptions, OptionKind } from "./app_options.js";
 | 
				
			|||||||
class BasePreferences {
 | 
					class BasePreferences {
 | 
				
			||||||
  #defaults = Object.freeze(
 | 
					  #defaults = Object.freeze(
 | 
				
			||||||
    typeof PDFJSDev === "undefined"
 | 
					    typeof PDFJSDev === "undefined"
 | 
				
			||||||
      ? AppOptions.getAll(OptionKind.PREFERENCE)
 | 
					      ? AppOptions.getAll(OptionKind.PREFERENCE, /* defaultOnly = */ true)
 | 
				
			||||||
      : PDFJSDev.eval("DEFAULT_PREFERENCES")
 | 
					      : PDFJSDev.eval("DEFAULT_PREFERENCES")
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -48,7 +48,7 @@ class BasePreferences {
 | 
				
			|||||||
      ({ browserPrefs, prefs }) => {
 | 
					      ({ browserPrefs, prefs }) => {
 | 
				
			||||||
        const BROWSER_PREFS =
 | 
					        const BROWSER_PREFS =
 | 
				
			||||||
          typeof PDFJSDev === "undefined"
 | 
					          typeof PDFJSDev === "undefined"
 | 
				
			||||||
            ? AppOptions.getAll(OptionKind.BROWSER)
 | 
					            ? AppOptions.getAll(OptionKind.BROWSER, /* defaultOnly = */ true)
 | 
				
			||||||
            : PDFJSDev.eval("BROWSER_PREFERENCES");
 | 
					            : PDFJSDev.eval("BROWSER_PREFERENCES");
 | 
				
			||||||
        const options = Object.create(null);
 | 
					        const options = Object.create(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user