Bläddra i källkod

PDF.js version 2.13.216 - See https://github.com/mozilla/pdf.js/releases/tag/v2.13.216

pdfjsbot 3 år sedan
förälder
incheckning
070a365be5
100 ändrade filer med 5633 tillägg och 7133 borttagningar
  1. 2 3
      README.md
  2. 1 1
      bower.json
  3. 2803 2974
      build/pdf.js
  4. 0 0
      build/pdf.js.map
  5. 1 1
      build/pdf.min.js
  6. 1 1
      build/pdf.sandbox.js
  7. 0 0
      build/pdf.sandbox.js.map
  8. 1 1
      build/pdf.sandbox.min.js
  9. 1 1
      build/pdf.worker.entry.js
  10. 304 278
      build/pdf.worker.js
  11. 0 0
      build/pdf.worker.js.map
  12. 1 1
      build/pdf.worker.min.js
  13. 55 98
      image_decoders/pdf.image_decoders.js
  14. 0 0
      image_decoders/pdf.image_decoders.js.map
  15. 1 1
      image_decoders/pdf.image_decoders.min.js
  16. 60 1414
      legacy/build/pdf.js
  17. 0 0
      legacy/build/pdf.js.map
  18. 1 1
      legacy/build/pdf.min.js
  19. 1 1
      legacy/build/pdf.sandbox.js
  20. 0 0
      legacy/build/pdf.sandbox.js.map
  21. 1 1
      legacy/build/pdf.sandbox.min.js
  22. 1 1
      legacy/build/pdf.worker.entry.js
  23. 921 319
      legacy/build/pdf.worker.js
  24. 0 0
      legacy/build/pdf.worker.js.map
  25. 1 1
      legacy/build/pdf.worker.min.js
  26. 103 1134
      legacy/image_decoders/pdf.image_decoders.js
  27. 0 0
      legacy/image_decoders/pdf.image_decoders.js.map
  28. 1 1
      legacy/image_decoders/pdf.image_decoders.min.js
  29. 318 169
      legacy/web/pdf_viewer.js
  30. 0 0
      legacy/web/pdf_viewer.js.map
  31. 105 63
      lib/core/annotation.js
  32. 1 1
      lib/core/arithmetic_decoder.js
  33. 1 1
      lib/core/ascii_85_stream.js
  34. 1 1
      lib/core/ascii_hex_stream.js
  35. 1 1
      lib/core/base_stream.js
  36. 1 1
      lib/core/bidi.js
  37. 1 1
      lib/core/calibri_factors.js
  38. 236 249
      lib/core/catalog.js
  39. 1 1
      lib/core/ccitt.js
  40. 4 4
      lib/core/ccitt_stream.js
  41. 1 1
      lib/core/cff_font.js
  42. 1 1
      lib/core/cff_parser.js
  43. 1 1
      lib/core/charsets.js
  44. 1 1
      lib/core/chunked_stream.js
  45. 36 0
      lib/core/cleanup_helper.js
  46. 13 11
      lib/core/cmap.js
  47. 8 6
      lib/core/colorspace.js
  48. 8 6
      lib/core/core_utils.js
  49. 4 4
      lib/core/crypto.js
  50. 1 1
      lib/core/decode_stream.js
  51. 1 1
      lib/core/decrypt_stream.js
  52. 1 1
      lib/core/default_appearance.js
  53. 97 53
      lib/core/document.js
  54. 1 1
      lib/core/encodings.js
  55. 156 127
      lib/core/evaluator.js
  56. 7 5
      lib/core/file_spec.js
  57. 1 1
      lib/core/flate_stream.js
  58. 69 48
      lib/core/font_renderer.js
  59. 31 4
      lib/core/fonts.js
  60. 1 1
      lib/core/fonts_utils.js
  61. 11 9
      lib/core/function.js
  62. 6 8
      lib/core/glyf.js
  63. 1 1
      lib/core/glyphlist.js
  64. 1 1
      lib/core/helvetica_factors.js
  65. 7 5
      lib/core/image.js
  66. 1 1
      lib/core/image_utils.js
  67. 1 1
      lib/core/jbig2.js
  68. 6 4
      lib/core/jbig2_stream.js
  69. 2 2
      lib/core/jpeg_stream.js
  70. 1 1
      lib/core/jpg.js
  71. 8 7
      lib/core/jpx.js
  72. 1 1
      lib/core/jpx_stream.js
  73. 1 1
      lib/core/liberationsans_widths.js
  74. 1 1
      lib/core/lzw_stream.js
  75. 1 1
      lib/core/metadata_parser.js
  76. 90 3
      lib/core/metrics.js
  77. 2 2
      lib/core/murmurhash3.js
  78. 1 1
      lib/core/myriadpro_factors.js
  79. 4 4
      lib/core/name_number_tree.js
  80. 6 4
      lib/core/object_loader.js
  81. 1 1
      lib/core/opentype_file_builder.js
  82. 1 1
      lib/core/operator_list.js
  83. 18 11
      lib/core/parser.js
  84. 5 5
      lib/core/pattern.js
  85. 1 1
      lib/core/pdf_manager.js
  86. 4 4
      lib/core/predictor_stream.js
  87. 1 13
      lib/core/primitives.js
  88. 1 1
      lib/core/ps_parser.js
  89. 1 1
      lib/core/run_length_stream.js
  90. 1 1
      lib/core/segoeui_factors.js
  91. 1 1
      lib/core/standard_fonts.js
  92. 1 1
      lib/core/stream.js
  93. 15 15
      lib/core/struct_tree.js
  94. 1 1
      lib/core/to_unicode_map.js
  95. 1 1
      lib/core/type1_font.js
  96. 8 1
      lib/core/type1_parser.js
  97. 27 1
      lib/core/unicode.js
  98. 15 10
      lib/core/worker.js
  99. 1 1
      lib/core/worker_stream.js
  100. 7 5
      lib/core/writer.js

+ 2 - 3
README.md

@@ -8,8 +8,7 @@ This is a pre-built version of the PDF.js source code. It is automatically
 generated by the build scripts.
 
 For usage with older browsers or environments, without support for modern
-features such as e.g. `async`/`await`, `ReadableStream`, optional chaining,
-nullish coalescing, and private `class` fields/methods; please see the `legacy`
-folder.
+features such as `async`/`await`, optional chaining, nullish coalescing,
+and private `class` fields/methods; please see the `legacy/` folder.
 
 See https://github.com/mozilla/pdf.js for learning and contributing.

+ 1 - 1
bower.json

@@ -1,6 +1,6 @@
 {
   "name": "pdfjs-dist",
-  "version": "2.12.313",
+  "version": "2.13.216",
   "main": [
     "build/pdf.js",
     "build/pdf.worker.js"

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2803 - 2974
build/pdf.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
build/pdf.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
build/pdf.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
build/pdf.sandbox.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
build/pdf.sandbox.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
build/pdf.sandbox.min.js


+ 1 - 1
build/pdf.worker.entry.js

@@ -1,4 +1,4 @@
-/* Copyright 2021 Mozilla Foundation
+/* Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 304 - 278
build/pdf.worker.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
build/pdf.worker.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
build/pdf.worker.min.js


+ 55 - 98
image_decoders/pdf.image_decoders.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -47,7 +47,6 @@ exports.arrayByteLength = arrayByteLength;
 exports.arraysToBytes = arraysToBytes;
 exports.assert = assert;
 exports.bytesToString = bytesToString;
-exports.createObjectURL = createObjectURL;
 exports.createPromiseCapability = createPromiseCapability;
 exports.createValidAbsoluteUrl = createValidAbsoluteUrl;
 exports.escapeString = escapeString;
@@ -57,13 +56,9 @@ exports.info = info;
 exports.isArrayBuffer = isArrayBuffer;
 exports.isArrayEqual = isArrayEqual;
 exports.isAscii = isAscii;
-exports.isBool = isBool;
-exports.isNum = isNum;
 exports.isSameOrigin = isSameOrigin;
-exports.isString = isString;
 exports.objectFromMap = objectFromMap;
 exports.objectSize = objectSize;
-exports.removeNullCharacters = removeNullCharacters;
 exports.setVerbosityLevel = setVerbosityLevel;
 exports.shadow = shadow;
 exports.string32 = string32;
@@ -610,24 +605,12 @@ class AbortException extends BaseException {
 }
 
 exports.AbortException = AbortException;
-const NullCharactersRegExp = /\x00+/g;
-const InvisibleCharactersRegExp = /[\x01-\x1F]/g;
 
-function removeNullCharacters(str, replaceInvisible = false) {
-  if (typeof str !== "string") {
-    warn("The argument for removeNullCharacters must be a string.");
-    return str;
-  }
-
-  if (replaceInvisible) {
-    str = str.replace(InvisibleCharactersRegExp, " ");
+function bytesToString(bytes) {
+  if (typeof bytes !== "object" || bytes === null || bytes.length === undefined) {
+    unreachable("Invalid argument for bytesToString");
   }
 
-  return str.replace(NullCharactersRegExp, "");
-}
-
-function bytesToString(bytes) {
-  assert(bytes !== null && typeof bytes === "object" && bytes.length !== undefined, "Invalid argument for bytesToString");
   const length = bytes.length;
   const MAX_ARGUMENT_COUNT = 8192;
 
@@ -647,7 +630,10 @@ function bytesToString(bytes) {
 }
 
 function stringToBytes(str) {
-  assert(typeof str === "string", "Invalid argument for stringToBytes");
+  if (typeof str !== "string") {
+    unreachable("Invalid argument for stringToBytes");
+  }
+
   const length = str.length;
   const bytes = new Uint8Array(length);
 
@@ -663,8 +649,11 @@ function arrayByteLength(arr) {
     return arr.length;
   }
 
-  assert(arr.byteLength !== undefined, "arrayByteLength - invalid argument.");
-  return arr.byteLength;
+  if (arr.byteLength !== undefined) {
+    return arr.byteLength;
+  }
+
+  unreachable("Invalid argument for arrayByteLength");
 }
 
 function arraysToBytes(arr) {
@@ -924,24 +913,37 @@ exports.Util = Util;
 const PDFStringTranslateTable = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2d8, 0x2c7, 0x2c6, 0x2d9, 0x2dd, 0x2db, 0x2da, 0x2dc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x192, 0x2044, 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x141, 0x152, 0x160, 0x178, 0x17d, 0x131, 0x142, 0x153, 0x161, 0x17e, 0, 0x20ac];
 
 function stringToPDFString(str) {
-  const length = str.length,
-        strBuf = [];
+  if (str[0] >= "\xEF") {
+    let encoding;
 
-  if (str[0] === "\xFE" && str[1] === "\xFF") {
-    for (let i = 2; i < length; i += 2) {
-      strBuf.push(String.fromCharCode(str.charCodeAt(i) << 8 | str.charCodeAt(i + 1)));
+    if (str[0] === "\xFE" && str[1] === "\xFF") {
+      encoding = "utf-16be";
+    } else if (str[0] === "\xFF" && str[1] === "\xFE") {
+      encoding = "utf-16le";
+    } else if (str[0] === "\xEF" && str[1] === "\xBB" && str[2] === "\xBF") {
+      encoding = "utf-8";
     }
-  } else if (str[0] === "\xFF" && str[1] === "\xFE") {
-    for (let i = 2; i < length; i += 2) {
-      strBuf.push(String.fromCharCode(str.charCodeAt(i + 1) << 8 | str.charCodeAt(i)));
-    }
-  } else {
-    for (let i = 0; i < length; ++i) {
-      const code = PDFStringTranslateTable[str.charCodeAt(i)];
-      strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
+
+    if (encoding) {
+      try {
+        const decoder = new TextDecoder(encoding, {
+          fatal: true
+        });
+        const buffer = stringToBytes(str);
+        return decoder.decode(buffer);
+      } catch (ex) {
+        warn(`stringToPDFString: "${ex}".`);
+      }
     }
   }
 
+  const strBuf = [];
+
+  for (let i = 0, ii = str.length; i < ii; i++) {
+    const code = PDFStringTranslateTable[str.charCodeAt(i)];
+    strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
+  }
+
   return strBuf.join("");
 }
 
@@ -980,18 +982,6 @@ function utf8StringToString(str) {
   return unescape(encodeURIComponent(str));
 }
 
-function isBool(v) {
-  return typeof v === "boolean";
-}
-
-function isNum(v) {
-  return typeof v === "number";
-}
-
-function isString(v) {
-  return typeof v === "string";
-}
-
 function isArrayBuffer(v) {
   return typeof v === "object" && v !== null && v.byteLength !== undefined;
 }
@@ -1038,30 +1028,6 @@ function createPromiseCapability() {
   return capability;
 }
 
-function createObjectURL(data, contentType = "", forceDataSchema = false) {
-  if (URL.createObjectURL && typeof Blob !== "undefined" && !forceDataSchema) {
-    return URL.createObjectURL(new Blob([data], {
-      type: contentType
-    }));
-  }
-
-  const digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
-  let buffer = `data:${contentType};base64,`;
-
-  for (let i = 0, ii = data.length; i < ii; i += 3) {
-    const b1 = data[i] & 0xff;
-    const b2 = data[i + 1] & 0xff;
-    const b3 = data[i + 2] & 0xff;
-    const d1 = b1 >> 2,
-          d2 = (b1 & 3) << 4 | b2 >> 4;
-    const d3 = i + 1 < ii ? (b2 & 0xf) << 2 | b3 >> 6 : 64;
-    const d4 = i + 2 < ii ? b3 & 0x3f : 64;
-    buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
-  }
-
-  return buffer;
-}
-
 /***/ }),
 /* 2 */
 /***/ ((__unused_webpack_module, __unused_webpack_exports, __w_pdfjs_require__) => {
@@ -3314,6 +3280,8 @@ var _util = __w_pdfjs_require__(1);
 
 var _primitives = __w_pdfjs_require__(6);
 
+var _base_stream = __w_pdfjs_require__(7);
+
 function getLookupTableFactory(initializer) {
   let lookup;
   return function () {
@@ -3568,7 +3536,7 @@ function _collectJS(entry, xref, list, parents) {
 
   let parent = null;
 
-  if ((0, _primitives.isRef)(entry)) {
+  if (entry instanceof _primitives.Ref) {
     if (parents.has(entry)) {
       return;
     }
@@ -3583,17 +3551,17 @@ function _collectJS(entry, xref, list, parents) {
       _collectJS(element, xref, list, parents);
     }
   } else if (entry instanceof _primitives.Dict) {
-    if ((0, _primitives.isName)(entry.get("S"), "JavaScript") && entry.has("JS")) {
+    if ((0, _primitives.isName)(entry.get("S"), "JavaScript")) {
       const js = entry.get("JS");
       let code;
 
-      if ((0, _primitives.isStream)(js)) {
+      if (js instanceof _base_stream.BaseStream) {
         code = js.getString();
-      } else {
+      } else if (typeof js === "string") {
         code = js;
       }
 
-      code = (0, _util.stringToPDFString)(code);
+      code = code && (0, _util.stringToPDFString)(code);
 
       if (code) {
         list.push(code);
@@ -3783,14 +3751,10 @@ exports.clearPrimitiveCaches = clearPrimitiveCaches;
 exports.isCmd = isCmd;
 exports.isDict = isDict;
 exports.isName = isName;
-exports.isRef = isRef;
 exports.isRefsEqual = isRefsEqual;
-exports.isStream = isStream;
 
 var _util = __w_pdfjs_require__(1);
 
-var _base_stream = __w_pdfjs_require__(7);
-
 const CIRCULAR_REF = Symbol("CIRCULAR_REF");
 exports.CIRCULAR_REF = CIRCULAR_REF;
 const EOF = Symbol("EOF");
@@ -4137,18 +4101,10 @@ function isDict(v, type) {
   return v instanceof Dict && (type === undefined || isName(v.get("Type"), type));
 }
 
-function isRef(v) {
-  return v instanceof Ref;
-}
-
 function isRefsEqual(v1, v2) {
   return v1.num === v2.num && v1.gen === v2.gen;
 }
 
-function isStream(v) {
-  return v instanceof _base_stream.BaseStream;
-}
-
 function clearPrimitiveCaches() {
   Cmd._clearCache();
 
@@ -6950,10 +6906,6 @@ class JpxImage {
               unsupported.push("selectiveArithmeticCodingBypass");
             }
 
-            if (cod.resetContextProbabilities) {
-              unsupported.push("resetContextProbabilities");
-            }
-
             if (cod.terminationOnEachCodingPass) {
               unsupported.push("terminationOnEachCodingPass");
             }
@@ -7898,7 +7850,7 @@ function parseTilePackets(context, data, offset, dataLength) {
   return position;
 }
 
-function copyCoefficients(coefficients, levelWidth, levelHeight, subband, delta, mb, reversible, segmentationSymbolUsed) {
+function copyCoefficients(coefficients, levelWidth, levelHeight, subband, delta, mb, reversible, segmentationSymbolUsed, resetContextProbabilities) {
   const x0 = subband.tbx0;
   const y0 = subband.tby0;
   const width = subband.tbx1 - subband.tbx0;
@@ -7965,6 +7917,10 @@ function copyCoefficients(coefficients, levelWidth, levelHeight, subband, delta,
           break;
       }
 
+      if (resetContextProbabilities) {
+        bitModel.reset();
+      }
+
       currentCodingpassType = (currentCodingpassType + 1) % 3;
     }
 
@@ -8019,6 +7975,7 @@ function transformTile(context, tile, c) {
   const scalarExpounded = quantizationParameters.scalarExpounded;
   const guardBits = quantizationParameters.guardBits;
   const segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed;
+  const resetContextProbabilities = codingStyleParameters.resetContextProbabilities;
   const precision = context.components[c].precision;
   const reversible = codingStyleParameters.reversibleTransformation;
   const transform = reversible ? new ReversibleTransform() : new IrreversibleTransform();
@@ -8047,7 +8004,7 @@ function transformTile(context, tile, c) {
       const gainLog2 = SubbandsGainLog2[subband.type];
       const delta = reversible ? 1 : 2 ** (precision + gainLog2 - epsilon) * (1 + mu / 2048);
       const mb = guardBits + epsilon - 1;
-      copyCoefficients(coefficients, width, height, subband, delta, mb, reversible, segmentationSymbolUsed);
+      copyCoefficients(coefficients, width, height, subband, delta, mb, reversible, segmentationSymbolUsed, resetContextProbabilities);
     }
 
     subbandCoefficients.push({
@@ -8986,8 +8943,8 @@ var _jpg = __w_pdfjs_require__(10);
 
 var _jpx = __w_pdfjs_require__(11);
 
-const pdfjsVersion = '2.12.313';
-const pdfjsBuild = 'a2ae56f39';
+const pdfjsVersion = '2.13.216';
+const pdfjsBuild = '399a0ec60';
 })();
 
 /******/ 	return __webpack_exports__;

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
image_decoders/pdf.image_decoders.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
image_decoders/pdf.image_decoders.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 60 - 1414
legacy/build/pdf.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
legacy/build/pdf.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
legacy/build/pdf.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
legacy/build/pdf.sandbox.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
legacy/build/pdf.sandbox.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
legacy/build/pdf.sandbox.min.js


+ 1 - 1
legacy/build/pdf.worker.entry.js

@@ -1,4 +1,4 @@
-/* Copyright 2021 Mozilla Foundation
+/* Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 921 - 319
legacy/build/pdf.worker.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
legacy/build/pdf.worker.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
legacy/build/pdf.worker.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 103 - 1134
legacy/image_decoders/pdf.image_decoders.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
legacy/image_decoders/pdf.image_decoders.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
legacy/image_decoders/pdf.image_decoders.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 318 - 169
legacy/web/pdf_viewer.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
legacy/web/pdf_viewer.js.map


+ 105 - 63
lib/core/annotation.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,6 +35,8 @@ var _default_appearance = require("./default_appearance.js");
 
 var _primitives = require("./primitives.js");
 
+var _base_stream = require("./base_stream.js");
+
 var _bidi = require("./bidi.js");
 
 var _catalog = require("./catalog.js");
@@ -61,13 +63,13 @@ class AnnotationFactory {
   static _create(xref, ref, pdfManager, idFactory, acroForm, collectFields, pageIndex = -1) {
     const dict = xref.fetchIfRef(ref);
 
-    if (!(0, _primitives.isDict)(dict)) {
+    if (!(dict instanceof _primitives.Dict)) {
       return undefined;
     }
 
-    const id = (0, _primitives.isRef)(ref) ? ref.toString() : `annot_${idFactory.createObjId()}`;
+    const id = ref instanceof _primitives.Ref ? ref.toString() : `annot_${idFactory.createObjId()}`;
     let subtype = dict.get("Subtype");
-    subtype = (0, _primitives.isName)(subtype) ? subtype.name : null;
+    subtype = subtype instanceof _primitives.Name ? subtype.name : null;
     const parameters = {
       xref,
       ref,
@@ -92,7 +94,7 @@ class AnnotationFactory {
           dict,
           key: "FT"
         });
-        fieldType = (0, _primitives.isName)(fieldType) ? fieldType.name : null;
+        fieldType = fieldType instanceof _primitives.Name ? fieldType.name : null;
 
         switch (fieldType) {
           case "Tx":
@@ -173,13 +175,13 @@ class AnnotationFactory {
     try {
       const annotDict = await xref.fetchIfRefAsync(ref);
 
-      if (!(0, _primitives.isDict)(annotDict)) {
+      if (!(annotDict instanceof _primitives.Dict)) {
         return -1;
       }
 
       const pageRef = annotDict.getRaw("P");
 
-      if (!(0, _primitives.isRef)(pageRef)) {
+      if (!(pageRef instanceof _primitives.Ref)) {
         return -1;
       }
 
@@ -327,7 +329,7 @@ class Annotation {
         const kidIds = [];
 
         for (const kid of kids) {
-          if ((0, _primitives.isRef)(kid)) {
+          if (kid instanceof _primitives.Ref) {
             kidIds.push(kid.toString());
           }
         }
@@ -419,7 +421,7 @@ class Annotation {
   }
 
   setModificationDate(modificationDate) {
-    this.modificationDate = (0, _util.isString)(modificationDate) ? modificationDate : null;
+    this.modificationDate = typeof modificationDate === "string" ? modificationDate : null;
   }
 
   setFlags(flags) {
@@ -454,7 +456,7 @@ class Annotation {
   setBorderStyle(borderStyle) {
     this.borderStyle = new AnnotationBorderStyle();
 
-    if (!(0, _primitives.isDict)(borderStyle)) {
+    if (!(borderStyle instanceof _primitives.Dict)) {
       return;
     }
 
@@ -488,24 +490,24 @@ class Annotation {
     this.appearance = null;
     const appearanceStates = dict.get("AP");
 
-    if (!(0, _primitives.isDict)(appearanceStates)) {
+    if (!(appearanceStates instanceof _primitives.Dict)) {
       return;
     }
 
     const normalAppearanceState = appearanceStates.get("N");
 
-    if ((0, _primitives.isStream)(normalAppearanceState)) {
+    if (normalAppearanceState instanceof _base_stream.BaseStream) {
       this.appearance = normalAppearanceState;
       return;
     }
 
-    if (!(0, _primitives.isDict)(normalAppearanceState)) {
+    if (!(normalAppearanceState instanceof _primitives.Dict)) {
       return;
     }
 
     const as = dict.get("AS");
 
-    if (!(0, _primitives.isName)(as) || !normalAppearanceState.has(as.name)) {
+    if (!(as instanceof _primitives.Name) || !normalAppearanceState.has(as.name)) {
       return;
     }
 
@@ -644,12 +646,12 @@ class AnnotationBorderStyle {
   }
 
   setWidth(width, rect = [0, 0, 0, 0]) {
-    if ((0, _primitives.isName)(width)) {
+    if (width instanceof _primitives.Name) {
       this.width = 0;
       return;
     }
 
-    if (Number.isInteger(width)) {
+    if (typeof width === "number") {
       if (width > 0) {
         const maxWidth = (rect[2] - rect[0]) / 2;
         const maxHeight = (rect[3] - rect[1]) / 2;
@@ -665,7 +667,7 @@ class AnnotationBorderStyle {
   }
 
   setStyle(style) {
-    if (!(0, _primitives.isName)(style)) {
+    if (!(style instanceof _primitives.Name)) {
       return;
     }
 
@@ -748,9 +750,9 @@ class MarkupAnnotation extends Annotation {
 
     if (dict.has("IRT")) {
       const rawIRT = dict.getRaw("IRT");
-      this.data.inReplyTo = (0, _primitives.isRef)(rawIRT) ? rawIRT.toString() : null;
+      this.data.inReplyTo = rawIRT instanceof _primitives.Ref ? rawIRT.toString() : null;
       const rt = dict.get("RT");
-      this.data.replyType = (0, _primitives.isName)(rt) ? rt.name : _util.AnnotationReplyType.REPLY;
+      this.data.replyType = rt instanceof _primitives.Name ? rt.name : _util.AnnotationReplyType.REPLY;
     }
 
     if (this.data.replyType === _util.AnnotationReplyType.GROUP) {
@@ -799,7 +801,7 @@ class MarkupAnnotation extends Annotation {
   }
 
   setCreationDate(creationDate) {
-    this.creationDate = (0, _util.isString)(creationDate) ? creationDate : null;
+    this.creationDate = typeof creationDate === "string" ? creationDate : null;
   }
 
   _setDefaultAppearance({
@@ -934,13 +936,13 @@ class WidgetAnnotation extends Annotation {
       dict,
       key: "DA"
     }) || params.acroForm.get("DA");
-    this._defaultAppearance = (0, _util.isString)(defaultAppearance) ? defaultAppearance : "";
+    this._defaultAppearance = typeof defaultAppearance === "string" ? defaultAppearance : "";
     data.defaultAppearanceData = (0, _default_appearance.parseDefaultAppearance)(this._defaultAppearance);
     const fieldType = (0, _core_utils.getInheritableProperty)({
       dict,
       key: "FT"
     });
-    data.fieldType = (0, _primitives.isName)(fieldType) ? fieldType.name : null;
+    data.fieldType = fieldType instanceof _primitives.Name ? fieldType.name : null;
     const localResources = (0, _core_utils.getInheritableProperty)({
       dict,
       key: "DR"
@@ -972,10 +974,10 @@ class WidgetAnnotation extends Annotation {
 
   _decodeFormValue(formValue) {
     if (Array.isArray(formValue)) {
-      return formValue.filter(item => (0, _util.isString)(item)).map(item => (0, _util.stringToPDFString)(item));
-    } else if ((0, _primitives.isName)(formValue)) {
+      return formValue.filter(item => typeof item === "string").map(item => (0, _util.stringToPDFString)(item));
+    } else if (formValue instanceof _primitives.Name) {
       return (0, _util.stringToPDFString)(formValue.name);
-    } else if ((0, _util.isString)(formValue)) {
+    } else if (typeof formValue === "string") {
       return (0, _util.stringToPDFString)(formValue);
     }
 
@@ -1046,7 +1048,7 @@ class WidgetAnnotation extends Annotation {
     } = evaluator;
     const dict = xref.fetchIfRef(this.ref);
 
-    if (!(0, _primitives.isDict)(dict)) {
+    if (!(dict instanceof _primitives.Dict)) {
       return null;
     }
 
@@ -1128,9 +1130,10 @@ class WidgetAnnotation extends Annotation {
       this.data.defaultAppearanceData = (0, _default_appearance.parseDefaultAppearance)(this._defaultAppearance = "/Helvetica 0 Tf 0 g");
     }
 
-    const [defaultAppearance, fontSize] = this._computeFontSize(totalHeight, lineCount);
-
     const font = await this._getFontData(evaluator, task);
+
+    const [defaultAppearance, fontSize] = this._computeFontSize(totalHeight - defaultPadding, totalWidth - 2 * hPadding, value, font, lineCount);
+
     let descent = font.descent;
 
     if (isNaN(descent)) {
@@ -1177,25 +1180,71 @@ class WidgetAnnotation extends Annotation {
     return initialState.font;
   }
 
-  _computeFontSize(height, lineCount) {
+  _getTextWidth(text, font) {
+    return font.charsToGlyphs(text).reduce((width, glyph) => width + glyph.width, 0) / 1000;
+  }
+
+  _computeFontSize(height, width, text, font, lineCount) {
     let {
       fontSize
     } = this.data.defaultAppearanceData;
 
     if (!fontSize) {
-      const roundWithOneDigit = x => Math.round(x * 10) / 10;
+      const roundWithTwoDigits = x => Math.floor(x * 100) / 100;
 
-      const FONT_FACTOR = 0.8;
+      const LINE_FACTOR = 1.35;
 
       if (lineCount === -1) {
-        fontSize = roundWithOneDigit(FONT_FACTOR * height);
+        const textWidth = this._getTextWidth(text, font);
+
+        fontSize = roundWithTwoDigits(Math.min(height / LINE_FACTOR, width / textWidth));
       } else {
-        fontSize = 10;
-        let lineHeight = fontSize / FONT_FACTOR;
+        const lines = text.split(/\r\n?|\n/);
+        const cachedLines = [];
+
+        for (const line of lines) {
+          const encoded = font.encodeString(line).join("");
+          const glyphs = font.charsToGlyphs(encoded);
+          const positions = font.getCharPositions(encoded);
+          cachedLines.push({
+            line: encoded,
+            glyphs,
+            positions
+          });
+        }
+
+        const isTooBig = fsize => {
+          let totalHeight = 0;
+
+          for (const cache of cachedLines) {
+            const chunks = this._splitLine(null, font, fsize, width, cache);
+
+            totalHeight += chunks.length * fsize;
+
+            if (totalHeight > height) {
+              return true;
+            }
+          }
+
+          return false;
+        };
+
+        fontSize = 12;
+        let lineHeight = fontSize * LINE_FACTOR;
         let numberOfLines = Math.round(height / lineHeight);
         numberOfLines = Math.max(numberOfLines, lineCount);
-        lineHeight = height / numberOfLines;
-        fontSize = roundWithOneDigit(FONT_FACTOR * lineHeight);
+
+        while (true) {
+          lineHeight = height / numberOfLines;
+          fontSize = roundWithTwoDigits(lineHeight / LINE_FACTOR);
+
+          if (isTooBig(fontSize)) {
+            numberOfLines++;
+            continue;
+          }
+
+          break;
+        }
       }
 
       const {
@@ -1213,14 +1262,7 @@ class WidgetAnnotation extends Annotation {
   }
 
   _renderText(text, font, fontSize, totalWidth, alignment, hPadding, vPadding) {
-    const glyphs = font.charsToGlyphs(text);
-    const scale = fontSize / 1000;
-    let width = 0;
-
-    for (const glyph of glyphs) {
-      width += glyph.width * scale;
-    }
-
+    const width = this._getTextWidth(text, font) * fontSize;
     let shift;
 
     if (alignment === 1) {
@@ -1289,7 +1331,7 @@ class TextWidgetAnnotation extends WidgetAnnotation {
     this._hasText = true;
     const dict = params.dict;
 
-    if (!(0, _util.isString)(this.data.fieldValue)) {
+    if (typeof this.data.fieldValue !== "string") {
       this.data.fieldValue = "";
     }
 
@@ -1331,7 +1373,7 @@ class TextWidgetAnnotation extends WidgetAnnotation {
   }
 
   _getMultilineAppearance(defaultAppearance, text, font, fontSize, width, height, alignment, hPadding, vPadding) {
-    const lines = text.split(/\r\n|\r|\n/);
+    const lines = text.split(/\r\n?|\n/);
     const buf = [];
     const totalWidth = width - 2 * hPadding;
 
@@ -1348,15 +1390,15 @@ class TextWidgetAnnotation extends WidgetAnnotation {
     return "/Tx BMC q BT " + defaultAppearance + ` 1 0 0 1 0 ${height} Tm ${renderedText}` + " ET Q EMC";
   }
 
-  _splitLine(line, font, fontSize, width) {
-    line = font.encodeString(line).join("");
-    const glyphs = font.charsToGlyphs(line);
+  _splitLine(line, font, fontSize, width, cache = {}) {
+    line = cache.line || font.encodeString(line).join("");
+    const glyphs = cache.glyphs || font.charsToGlyphs(line);
 
     if (glyphs.length <= 1) {
       return [line];
     }
 
-    const positions = font.getCharPositions(line);
+    const positions = cache.positions || font.getCharPositions(line);
     const scale = fontSize / 1000;
     const chunks = [];
     let lastSpacePosInStringStart = -1,
@@ -1524,7 +1566,7 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
 
     const dict = evaluator.xref.fetchIfRef(this.ref);
 
-    if (!(0, _primitives.isDict)(dict)) {
+    if (!(dict instanceof _primitives.Dict)) {
       return null;
     }
 
@@ -1575,7 +1617,7 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
 
     const dict = evaluator.xref.fetchIfRef(this.ref);
 
-    if (!(0, _primitives.isDict)(dict)) {
+    if (!(dict instanceof _primitives.Dict)) {
       return null;
     }
 
@@ -1590,7 +1632,7 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
     const encrypt = evaluator.xref.encrypt;
 
     if (value) {
-      if ((0, _primitives.isRef)(this.parent)) {
+      if (this.parent instanceof _primitives.Ref) {
         const parent = evaluator.xref.fetch(this.parent);
         let parentTransform = null;
 
@@ -1602,7 +1644,7 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
         parentBuffer = [`${this.parent.num} ${this.parent.gen} obj\n`];
         (0, _writer.writeDict)(parent, parentBuffer, parentTransform);
         parentBuffer.push("\nendobj\n");
-      } else if ((0, _primitives.isDict)(this.parent)) {
+      } else if (this.parent instanceof _primitives.Dict) {
         this.parent.set("V", name);
       }
     }
@@ -1683,13 +1725,13 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
   _processCheckBox(params) {
     const customAppearance = params.dict.get("AP");
 
-    if (!(0, _primitives.isDict)(customAppearance)) {
+    if (!(customAppearance instanceof _primitives.Dict)) {
       return;
     }
 
     const normalAppearance = customAppearance.get("N");
 
-    if (!(0, _primitives.isDict)(normalAppearance)) {
+    if (!(normalAppearance instanceof _primitives.Dict)) {
       return;
     }
 
@@ -1744,24 +1786,24 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
     this.data.fieldValue = this.data.buttonValue = null;
     const fieldParent = params.dict.get("Parent");
 
-    if ((0, _primitives.isDict)(fieldParent)) {
+    if (fieldParent instanceof _primitives.Dict) {
       this.parent = params.dict.getRaw("Parent");
       const fieldParentValue = fieldParent.get("V");
 
-      if ((0, _primitives.isName)(fieldParentValue)) {
+      if (fieldParentValue instanceof _primitives.Name) {
         this.data.fieldValue = this._decodeFormValue(fieldParentValue);
       }
     }
 
     const appearanceStates = params.dict.get("AP");
 
-    if (!(0, _primitives.isDict)(appearanceStates)) {
+    if (!(appearanceStates instanceof _primitives.Dict)) {
       return;
     }
 
     const normalAppearance = appearanceStates.get("N");
 
-    if (!(0, _primitives.isDict)(normalAppearance)) {
+    if (!(normalAppearance instanceof _primitives.Dict)) {
       return;
     }
 
@@ -1865,7 +1907,7 @@ class ChoiceWidgetAnnotation extends WidgetAnnotation {
       }
     }
 
-    if ((0, _util.isString)(this.data.fieldValue)) {
+    if (typeof this.data.fieldValue === "string") {
       this.data.fieldValue = [this.data.fieldValue];
     } else if (!this.data.fieldValue) {
       this.data.fieldValue = [];
@@ -1974,9 +2016,9 @@ class PopupAnnotation extends Annotation {
     }
 
     const parentSubtype = parentItem.get("Subtype");
-    this.data.parentType = (0, _primitives.isName)(parentSubtype) ? parentSubtype.name : null;
+    this.data.parentType = parentSubtype instanceof _primitives.Name ? parentSubtype.name : null;
     const rawParent = parameters.dict.getRaw("Parent");
-    this.data.parentId = (0, _primitives.isRef)(rawParent) ? rawParent.toString() : null;
+    this.data.parentId = rawParent instanceof _primitives.Ref ? rawParent.toString() : null;
     const parentRect = parentItem.getArray("Rect");
 
     if (Array.isArray(parentRect) && parentRect.length === 4) {

+ 1 - 1
lib/core/arithmetic_decoder.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/ascii_85_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/ascii_hex_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/base_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/bidi.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/calibri_factors.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 236 - 249
lib/core/catalog.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,16 +26,18 @@ Object.defineProperty(exports, "__esModule", {
 });
 exports.Catalog = void 0;
 
-var _primitives = require("./primitives.js");
-
 var _core_utils = require("./core_utils.js");
 
 var _util = require("../shared/util.js");
 
+var _primitives = require("./primitives.js");
+
 var _name_number_tree = require("./name_number_tree.js");
 
 var _base_stream = require("./base_stream.js");
 
+var _cleanup_helper = require("./cleanup_helper.js");
+
 var _colorspace = require("./colorspace.js");
 
 var _file_spec = require("./file_spec.js");
@@ -99,7 +101,7 @@ class Catalog {
     try {
       const obj = this._catDict.get("Collection");
 
-      if ((0, _primitives.isDict)(obj) && obj.size > 0) {
+      if (obj instanceof _primitives.Dict && obj.size > 0) {
         collection = obj;
       }
     } catch (ex) {
@@ -119,7 +121,7 @@ class Catalog {
     try {
       const obj = this._catDict.get("AcroForm");
 
-      if ((0, _primitives.isDict)(obj) && obj.size > 0) {
+      if (obj instanceof _primitives.Dict && obj.size > 0) {
         acroForm = obj;
       }
     } catch (ex) {
@@ -136,7 +138,7 @@ class Catalog {
   get acroFormRef() {
     const value = this._catDict.getRaw("AcroForm");
 
-    return (0, _util.shadow)(this, "acroFormRef", (0, _primitives.isRef)(value) ? value : null);
+    return (0, _util.shadow)(this, "acroFormRef", value instanceof _primitives.Ref ? value : null);
   }
 
   get metadata() {
@@ -194,7 +196,7 @@ class Catalog {
   _readMarkInfo() {
     const obj = this._catDict.get("MarkInfo");
 
-    if (!(0, _primitives.isDict)(obj)) {
+    if (!(obj instanceof _primitives.Dict)) {
       return null;
     }
 
@@ -211,7 +213,7 @@ class Catalog {
 
       const value = obj.get(key);
 
-      if (!(0, _util.isBool)(value)) {
+      if (typeof value !== "boolean") {
         continue;
       }
 
@@ -240,7 +242,7 @@ class Catalog {
   _readStructTreeRoot() {
     const obj = this._catDict.get("StructTreeRoot");
 
-    if (!(0, _primitives.isDict)(obj)) {
+    if (!(obj instanceof _primitives.Dict)) {
       return null;
     }
 
@@ -252,7 +254,7 @@ class Catalog {
   get toplevelPagesDict() {
     const pagesObj = this._catDict.get("Pages");
 
-    if (!(0, _primitives.isDict)(pagesObj)) {
+    if (!(pagesObj instanceof _primitives.Dict)) {
       throw new _util.FormatError("Invalid top-level pages dictionary.");
     }
 
@@ -278,13 +280,13 @@ class Catalog {
   _readDocumentOutline() {
     let obj = this._catDict.get("Outlines");
 
-    if (!(0, _primitives.isDict)(obj)) {
+    if (!(obj instanceof _primitives.Dict)) {
       return null;
     }
 
     obj = obj.getRaw("First");
 
-    if (!(0, _primitives.isRef)(obj)) {
+    if (!(obj instanceof _primitives.Ref)) {
       return null;
     }
 
@@ -346,7 +348,7 @@ class Catalog {
       i.parent.items.push(outlineItem);
       obj = outlineDict.getRaw("First");
 
-      if ((0, _primitives.isRef)(obj) && !processed.has(obj)) {
+      if (obj instanceof _primitives.Ref && !processed.has(obj)) {
         queue.push({
           obj,
           parent: outlineItem
@@ -356,7 +358,7 @@ class Catalog {
 
       obj = outlineDict.getRaw("Next");
 
-      if ((0, _primitives.isRef)(obj) && !processed.has(obj)) {
+      if (obj instanceof _primitives.Ref && !processed.has(obj)) {
         queue.push({
           obj,
           parent: i.parent
@@ -387,13 +389,13 @@ class Catalog {
   _readPermissions() {
     const encrypt = this.xref.trailer.get("Encrypt");
 
-    if (!(0, _primitives.isDict)(encrypt)) {
+    if (!(encrypt instanceof _primitives.Dict)) {
       return null;
     }
 
     let flags = encrypt.get("P");
 
-    if (!(0, _util.isNum)(flags)) {
+    if (typeof flags !== "number") {
       return null;
     }
 
@@ -437,7 +439,7 @@ class Catalog {
       const groupRefs = [];
 
       for (const groupRef of groupsData) {
-        if (!(0, _primitives.isRef)(groupRef)) {
+        if (!(groupRef instanceof _primitives.Ref)) {
           continue;
         }
 
@@ -445,8 +447,8 @@ class Catalog {
         const group = this.xref.fetchIfRef(groupRef);
         groups.push({
           id: groupRef.toString(),
-          name: (0, _util.isString)(group.get("Name")) ? (0, _util.stringToPDFString)(group.get("Name")) : null,
-          intent: (0, _util.isString)(group.get("Intent")) ? (0, _util.stringToPDFString)(group.get("Intent")) : null
+          name: typeof group.get("Name") === "string" ? (0, _util.stringToPDFString)(group.get("Name")) : null,
+          intent: typeof group.get("Intent") === "string" ? (0, _util.stringToPDFString)(group.get("Intent")) : null
         });
       }
 
@@ -469,7 +471,7 @@ class Catalog {
 
       if (Array.isArray(refs)) {
         for (const value of refs) {
-          if (!(0, _primitives.isRef)(value)) {
+          if (!(value instanceof _primitives.Ref)) {
             continue;
           }
 
@@ -490,7 +492,7 @@ class Catalog {
       const order = [];
 
       for (const value of refs) {
-        if ((0, _primitives.isRef)(value) && contentGroupRefs.includes(value)) {
+        if (value instanceof _primitives.Ref && contentGroupRefs.includes(value)) {
           parsedOrderRefs.put(value);
           order.push(value.toString());
           continue;
@@ -561,9 +563,9 @@ class Catalog {
           parsedOrderRefs = new _primitives.RefSet(),
           MAX_NESTED_LEVELS = 10;
     return {
-      name: (0, _util.isString)(config.get("Name")) ? (0, _util.stringToPDFString)(config.get("Name")) : null,
-      creator: (0, _util.isString)(config.get("Creator")) ? (0, _util.stringToPDFString)(config.get("Creator")) : null,
-      baseState: (0, _primitives.isName)(config.get("BaseState")) ? config.get("BaseState").name : null,
+      name: typeof config.get("Name") === "string" ? (0, _util.stringToPDFString)(config.get("Name")) : null,
+      creator: typeof config.get("Creator") === "string" ? (0, _util.stringToPDFString)(config.get("Creator")) : null,
+      baseState: config.get("BaseState") instanceof _primitives.Name ? config.get("BaseState").name : null,
       on: parseOnOff(config.get("ON")),
       off: parseOnOff(config.get("OFF")),
       order: parseOrder(config.get("Order")),
@@ -692,7 +694,7 @@ class Catalog {
       const labelDict = nums.get(i);
 
       if (labelDict !== undefined) {
-        if (!(0, _primitives.isDict)(labelDict)) {
+        if (!(labelDict instanceof _primitives.Dict)) {
           throw new _util.FormatError("PageLabel is not a dictionary.");
         }
 
@@ -703,7 +705,7 @@ class Catalog {
         if (labelDict.has("S")) {
           const s = labelDict.get("S");
 
-          if (!(0, _primitives.isName)(s)) {
+          if (!(s instanceof _primitives.Name)) {
             throw new _util.FormatError("Invalid style in PageLabel dictionary.");
           }
 
@@ -715,7 +717,7 @@ class Catalog {
         if (labelDict.has("P")) {
           const p = labelDict.get("P");
 
-          if (!(0, _util.isString)(p)) {
+          if (typeof p !== "string") {
             throw new _util.FormatError("Invalid prefix in PageLabel dictionary.");
           }
 
@@ -784,7 +786,7 @@ class Catalog {
 
     let pageLayout = "";
 
-    if ((0, _primitives.isName)(obj)) {
+    if (obj instanceof _primitives.Name) {
       switch (obj.name) {
         case "SinglePage":
         case "OneColumn":
@@ -804,7 +806,7 @@ class Catalog {
 
     let pageMode = "UseNone";
 
-    if ((0, _primitives.isName)(obj)) {
+    if (obj instanceof _primitives.Name) {
       switch (obj.name) {
         case "UseNone":
         case "UseOutlines":
@@ -820,47 +822,34 @@ class Catalog {
   }
 
   get viewerPreferences() {
-    const ViewerPreferencesValidators = {
-      HideToolbar: _util.isBool,
-      HideMenubar: _util.isBool,
-      HideWindowUI: _util.isBool,
-      FitWindow: _util.isBool,
-      CenterWindow: _util.isBool,
-      DisplayDocTitle: _util.isBool,
-      NonFullScreenPageMode: _primitives.isName,
-      Direction: _primitives.isName,
-      ViewArea: _primitives.isName,
-      ViewClip: _primitives.isName,
-      PrintArea: _primitives.isName,
-      PrintClip: _primitives.isName,
-      PrintScaling: _primitives.isName,
-      Duplex: _primitives.isName,
-      PickTrayByPDFSize: _util.isBool,
-      PrintPageRange: Array.isArray,
-      NumCopies: Number.isInteger
-    };
-
     const obj = this._catDict.get("ViewerPreferences");
 
-    let prefs = null;
-
-    if ((0, _primitives.isDict)(obj)) {
-      for (const key in ViewerPreferencesValidators) {
-        if (!obj.has(key)) {
-          continue;
-        }
+    if (!(obj instanceof _primitives.Dict)) {
+      return (0, _util.shadow)(this, "viewerPreferences", null);
+    }
 
-        const value = obj.get(key);
+    let prefs = null;
 
-        if (!ViewerPreferencesValidators[key](value)) {
-          (0, _util.info)(`Bad value in ViewerPreferences for "${key}".`);
-          continue;
-        }
+    for (const key of obj.getKeys()) {
+      const value = obj.get(key);
+      let prefValue;
+
+      switch (key) {
+        case "HideToolbar":
+        case "HideMenubar":
+        case "HideWindowUI":
+        case "FitWindow":
+        case "CenterWindow":
+        case "DisplayDocTitle":
+        case "PickTrayByPDFSize":
+          if (typeof value === "boolean") {
+            prefValue = value;
+          }
 
-        let prefValue;
+          break;
 
-        switch (key) {
-          case "NonFullScreenPageMode":
+        case "NonFullScreenPageMode":
+          if (value instanceof _primitives.Name) {
             switch (value.name) {
               case "UseNone":
               case "UseOutlines":
@@ -872,10 +861,12 @@ class Catalog {
               default:
                 prefValue = "UseNone";
             }
+          }
 
-            break;
+          break;
 
-          case "Direction":
+        case "Direction":
+          if (value instanceof _primitives.Name) {
             switch (value.name) {
               case "L2R":
               case "R2L":
@@ -885,13 +876,15 @@ class Catalog {
               default:
                 prefValue = "L2R";
             }
+          }
 
-            break;
+          break;
 
-          case "ViewArea":
-          case "ViewClip":
-          case "PrintArea":
-          case "PrintClip":
+        case "ViewArea":
+        case "ViewClip":
+        case "PrintArea":
+        case "PrintClip":
+          if (value instanceof _primitives.Name) {
             switch (value.name) {
               case "MediaBox":
               case "CropBox":
@@ -904,10 +897,12 @@ class Catalog {
               default:
                 prefValue = "CropBox";
             }
+          }
 
-            break;
+          break;
 
-          case "PrintScaling":
+        case "PrintScaling":
+          if (value instanceof _primitives.Name) {
             switch (value.name) {
               case "None":
               case "AppDefault":
@@ -917,10 +912,12 @@ class Catalog {
               default:
                 prefValue = "AppDefault";
             }
+          }
 
-            break;
+          break;
 
-          case "Duplex":
+        case "Duplex":
+          if (value instanceof _primitives.Name) {
             switch (value.name) {
               case "Simplex":
               case "DuplexFlipShortEdge":
@@ -931,16 +928,12 @@ class Catalog {
               default:
                 prefValue = "None";
             }
+          }
 
-            break;
-
-          case "PrintPageRange":
-            const length = value.length;
-
-            if (length % 2 !== 0) {
-              break;
-            }
+          break;
 
+        case "PrintPageRange":
+          if (Array.isArray(value) && value.length % 2 === 0) {
             const isValid = value.every((page, i, arr) => {
               return Number.isInteger(page) && page > 0 && (i === 0 || page >= arr[i - 1]) && page <= this.numPages;
             });
@@ -948,34 +941,32 @@ class Catalog {
             if (isValid) {
               prefValue = value;
             }
+          }
 
-            break;
-
-          case "NumCopies":
-            if (value > 0) {
-              prefValue = value;
-            }
+          break;
 
-            break;
+        case "NumCopies":
+          if (Number.isInteger(value) && value > 0) {
+            prefValue = value;
+          }
 
-          default:
-            if (typeof value !== "boolean") {
-              throw new _util.FormatError(`viewerPreferences - expected a boolean value for: ${key}`);
-            }
+          break;
 
-            prefValue = value;
-        }
+        default:
+          (0, _util.warn)(`Ignoring non-standard key in ViewerPreferences: ${key}.`);
+          continue;
+      }
 
-        if (prefValue !== undefined) {
-          if (!prefs) {
-            prefs = Object.create(null);
-          }
+      if (prefValue === undefined) {
+        (0, _util.warn)(`Bad value, for key "${key}", in ViewerPreferences: ${value}.`);
+        continue;
+      }
 
-          prefs[key] = prefValue;
-        } else {
-          (0, _util.info)(`Bad value in ViewerPreferences for "${key}".`);
-        }
+      if (!prefs) {
+        prefs = Object.create(null);
       }
+
+      prefs[key] = prefValue;
     }
 
     return (0, _util.shadow)(this, "viewerPreferences", prefs);
@@ -986,7 +977,7 @@ class Catalog {
 
     const openAction = Object.create(null);
 
-    if ((0, _primitives.isDict)(obj)) {
+    if (obj instanceof _primitives.Dict) {
       const destDict = new _primitives.Dict(this.xref);
       destDict.set("A", obj);
       const resultObj = {
@@ -1069,7 +1060,7 @@ class Catalog {
 
       let js = jsDict.get("JS");
 
-      if ((0, _primitives.isStream)(js)) {
+      if (js instanceof _base_stream.BaseStream) {
         js = js.getString();
       } else if (typeof js !== "string") {
         return;
@@ -1143,7 +1134,7 @@ class Catalog {
   }
 
   cleanup(manuallyTriggered = false) {
-    (0, _primitives.clearPrimitiveCaches)();
+    (0, _cleanup_helper.clearGlobalCaches)();
     this.globalImageCache.clear(manuallyTriggered);
     this.pageKidsCountCache.clear();
     this.pageIndexCache.clear();
@@ -1165,8 +1156,7 @@ class Catalog {
     });
   }
 
-  getPageDict(pageIndex) {
-    const capability = (0, _util.createPromiseCapability)();
+  async getPageDict(pageIndex) {
     const nodesToVisit = [this.toplevelPagesDict];
     const visitedNodes = new _primitives.RefSet();
 
@@ -1177,125 +1167,115 @@ class Catalog {
     }
 
     const xref = this.xref,
-          pageKidsCountCache = this.pageKidsCountCache;
+          pageKidsCountCache = this.pageKidsCountCache,
+          pageIndexCache = this.pageIndexCache;
     let currentPageIndex = 0;
 
-    function next() {
-      while (nodesToVisit.length) {
-        const currentNode = nodesToVisit.pop();
+    while (nodesToVisit.length) {
+      const currentNode = nodesToVisit.pop();
 
-        if (currentNode instanceof _primitives.Ref) {
-          const count = pageKidsCountCache.get(currentNode);
+      if (currentNode instanceof _primitives.Ref) {
+        const count = pageKidsCountCache.get(currentNode);
 
-          if (count >= 0 && currentPageIndex + count <= pageIndex) {
-            currentPageIndex += count;
-            continue;
-          }
+        if (count >= 0 && currentPageIndex + count <= pageIndex) {
+          currentPageIndex += count;
+          continue;
+        }
 
-          if (visitedNodes.has(currentNode)) {
-            capability.reject(new _util.FormatError("Pages tree contains circular reference."));
-            return;
-          }
+        if (visitedNodes.has(currentNode)) {
+          throw new _util.FormatError("Pages tree contains circular reference.");
+        }
 
-          visitedNodes.put(currentNode);
-          xref.fetchAsync(currentNode).then(function (obj) {
-            if ((0, _primitives.isDict)(obj, "Page") || (0, _primitives.isDict)(obj) && !obj.has("Kids")) {
-              if (currentNode && !pageKidsCountCache.has(currentNode)) {
-                pageKidsCountCache.put(currentNode, 1);
-              }
+        visitedNodes.put(currentNode);
+        const obj = await xref.fetchAsync(currentNode);
 
-              if (pageIndex === currentPageIndex) {
-                capability.resolve([obj, currentNode]);
-              } else {
-                currentPageIndex++;
-                next();
-              }
+        if (obj instanceof _primitives.Dict) {
+          let type = obj.getRaw("Type");
 
-              return;
-            }
+          if (type instanceof _primitives.Ref) {
+            type = await xref.fetchAsync(type);
+          }
 
-            nodesToVisit.push(obj);
-            next();
-          }, capability.reject);
-          return;
-        }
+          if ((0, _primitives.isName)(type, "Page") || !obj.has("Kids")) {
+            if (!pageKidsCountCache.has(currentNode)) {
+              pageKidsCountCache.put(currentNode, 1);
+            }
 
-        if (!(currentNode instanceof _primitives.Dict)) {
-          capability.reject(new _util.FormatError("Page dictionary kid reference points to wrong type of object."));
-          return;
-        }
+            if (!pageIndexCache.has(currentNode)) {
+              pageIndexCache.put(currentNode, currentPageIndex);
+            }
 
-        let count;
+            if (currentPageIndex === pageIndex) {
+              return [obj, currentNode];
+            }
 
-        try {
-          count = currentNode.get("Count");
-        } catch (ex) {
-          if (ex instanceof _core_utils.MissingDataException) {
-            throw ex;
+            currentPageIndex++;
+            continue;
           }
         }
 
-        if (Number.isInteger(count) && count >= 0) {
-          const objId = currentNode.objId;
+        nodesToVisit.push(obj);
+        continue;
+      }
 
-          if (objId && !pageKidsCountCache.has(objId)) {
-            pageKidsCountCache.put(objId, count);
-          }
+      if (!(currentNode instanceof _primitives.Dict)) {
+        throw new _util.FormatError("Page dictionary kid reference points to wrong type of object.");
+      }
 
-          if (currentPageIndex + count <= pageIndex) {
-            currentPageIndex += count;
-            continue;
-          }
-        }
+      const {
+        objId
+      } = currentNode;
+      let count = currentNode.getRaw("Count");
 
-        let kids;
+      if (count instanceof _primitives.Ref) {
+        count = await xref.fetchAsync(count);
+      }
 
-        try {
-          kids = currentNode.get("Kids");
-        } catch (ex) {
-          if (ex instanceof _core_utils.MissingDataException) {
-            throw ex;
-          }
+      if (Number.isInteger(count) && count >= 0) {
+        if (objId && !pageKidsCountCache.has(objId)) {
+          pageKidsCountCache.put(objId, count);
         }
 
-        if (!Array.isArray(kids)) {
-          let type;
+        if (currentPageIndex + count <= pageIndex) {
+          currentPageIndex += count;
+          continue;
+        }
+      }
 
-          try {
-            type = currentNode.get("Type");
-          } catch (ex) {
-            if (ex instanceof _core_utils.MissingDataException) {
-              throw ex;
-            }
-          }
+      let kids = currentNode.getRaw("Kids");
 
-          if ((0, _primitives.isName)(type, "Page") || !currentNode.has("Type") && currentNode.has("Contents")) {
-            if (currentPageIndex === pageIndex) {
-              capability.resolve([currentNode, null]);
-              return;
-            }
+      if (kids instanceof _primitives.Ref) {
+        kids = await xref.fetchAsync(kids);
+      }
 
-            currentPageIndex++;
-            continue;
-          }
+      if (!Array.isArray(kids)) {
+        let type = currentNode.getRaw("Type");
 
-          capability.reject(new _util.FormatError("Page dictionary kids object is not an array."));
-          return;
+        if (type instanceof _primitives.Ref) {
+          type = await xref.fetchAsync(type);
         }
 
-        for (let last = kids.length - 1; last >= 0; last--) {
-          nodesToVisit.push(kids[last]);
+        if ((0, _primitives.isName)(type, "Page") || !currentNode.has("Kids")) {
+          if (currentPageIndex === pageIndex) {
+            return [currentNode, null];
+          }
+
+          currentPageIndex++;
+          continue;
         }
+
+        throw new _util.FormatError("Page dictionary kids object is not an array.");
       }
 
-      capability.reject(new Error(`Page index ${pageIndex} not found.`));
+      for (let last = kids.length - 1; last >= 0; last--) {
+        nodesToVisit.push(kids[last]);
+      }
     }
 
-    next();
-    return capability.promise;
+    throw new Error(`Page index ${pageIndex} not found.`);
   }
 
-  getAllPageDicts(recoveryMode = false) {
+  async getAllPageDicts(recoveryMode = false) {
     const queue = [{
       currentNode: this.toplevelPagesDict,
       posInKids: 0
@@ -1308,14 +1288,24 @@ class Catalog {
       visitedNodes.put(pagesRef);
     }
 
-    const map = new Map();
+    const map = new Map(),
+          xref = this.xref,
+          pageIndexCache = this.pageIndexCache;
     let pageIndex = 0;
 
     function addPageDict(pageDict, pageRef) {
+      if (pageRef && !pageIndexCache.has(pageRef)) {
+        pageIndexCache.put(pageRef, pageIndex);
+      }
+
       map.set(pageIndex++, [pageDict, pageRef]);
     }
 
     function addPageError(error) {
+      if (error instanceof _core_utils.XRefEntryException && !recoveryMode) {
+        throw error;
+      }
+
       map.set(pageIndex++, [error, null]);
     }
 
@@ -1325,21 +1315,15 @@ class Catalog {
         currentNode,
         posInKids
       } = queueItem;
-      let kids;
+      let kids = currentNode.getRaw("Kids");
 
-      try {
-        kids = currentNode.get("Kids");
-      } catch (ex) {
-        if (ex instanceof _core_utils.MissingDataException) {
-          throw ex;
-        }
-
-        if (ex instanceof _core_utils.XRefEntryException && !recoveryMode) {
-          throw ex;
+      if (kids instanceof _primitives.Ref) {
+        try {
+          kids = await xref.fetchAsync(kids);
+        } catch (ex) {
+          addPageError(ex);
+          break;
         }
-
-        addPageError(ex);
-        break;
       }
 
       if (!Array.isArray(kids)) {
@@ -1356,27 +1340,19 @@ class Catalog {
       let obj;
 
       if (kidObj instanceof _primitives.Ref) {
-        try {
-          obj = this.xref.fetch(kidObj);
-        } catch (ex) {
-          if (ex instanceof _core_utils.MissingDataException) {
-            throw ex;
-          }
-
-          if (ex instanceof _core_utils.XRefEntryException && !recoveryMode) {
-            throw ex;
-          }
-
-          addPageError(ex);
-          break;
-        }
-
         if (visitedNodes.has(kidObj)) {
           addPageError(new _util.FormatError("Pages tree contains circular reference."));
           break;
         }
 
         visitedNodes.put(kidObj);
+
+        try {
+          obj = await xref.fetchAsync(kidObj);
+        } catch (ex) {
+          addPageError(ex);
+          break;
+        }
       } else {
         obj = kidObj;
       }
@@ -1386,7 +1362,18 @@ class Catalog {
         break;
       }
 
-      if ((0, _primitives.isDict)(obj, "Page") || !obj.has("Kids")) {
+      let type = obj.getRaw("Type");
+
+      if (type instanceof _primitives.Ref) {
+        try {
+          type = await xref.fetchAsync(type);
+        } catch (ex) {
+          addPageError(ex);
+          break;
+        }
+      }
+
+      if ((0, _primitives.isName)(type, "Page") || !obj.has("Kids")) {
         addPageDict(obj, kidObj instanceof _primitives.Ref ? kidObj : null);
       } else {
         queue.push({
@@ -1414,7 +1401,7 @@ class Catalog {
       let total = 0,
           parentRef;
       return xref.fetchAsync(kidRef).then(function (node) {
-        if ((0, _primitives.isRefsEqual)(kidRef, pageRef) && !(0, _primitives.isDict)(node, "Page") && !((0, _primitives.isDict)(node) && !node.has("Type") && node.has("Contents"))) {
+        if ((0, _primitives.isRefsEqual)(kidRef, pageRef) && !(0, _primitives.isDict)(node, "Page") && !(node instanceof _primitives.Dict && !node.has("Type") && node.has("Contents"))) {
           throw new _util.FormatError("The reference does not point to a /Page dictionary.");
         }
 
@@ -1422,7 +1409,7 @@ class Catalog {
           return null;
         }
 
-        if (!(0, _primitives.isDict)(node)) {
+        if (!(node instanceof _primitives.Dict)) {
           throw new _util.FormatError("Node must be a dictionary.");
         }
 
@@ -1433,7 +1420,7 @@ class Catalog {
           return null;
         }
 
-        if (!(0, _primitives.isDict)(parent)) {
+        if (!(parent instanceof _primitives.Dict)) {
           throw new _util.FormatError("Parent must be a dictionary.");
         }
 
@@ -1449,7 +1436,7 @@ class Catalog {
         for (let i = 0, ii = kids.length; i < ii; i++) {
           const kid = kids[i];
 
-          if (!(0, _primitives.isRef)(kid)) {
+          if (!(kid instanceof _primitives.Ref)) {
             throw new _util.FormatError("Kid must be a reference.");
           }
 
@@ -1459,7 +1446,7 @@ class Catalog {
           }
 
           kidPromises.push(xref.fetchAsync(kid).then(function (obj) {
-            if (!(0, _primitives.isDict)(obj)) {
+            if (!(obj instanceof _primitives.Dict)) {
               throw new _util.FormatError("Kid node must be a dictionary.");
             }
 
@@ -1500,7 +1487,7 @@ class Catalog {
   static parseDestDictionary(params) {
     const destDict = params.destDict;
 
-    if (!(0, _primitives.isDict)(destDict)) {
+    if (!(destDict instanceof _primitives.Dict)) {
       (0, _util.warn)("parseDestDictionary: `destDict` must be a dictionary.");
       return;
     }
@@ -1517,13 +1504,13 @@ class Catalog {
         url,
         dest;
 
-    if (!(0, _primitives.isDict)(action)) {
+    if (!(action instanceof _primitives.Dict)) {
       if (destDict.has("Dest")) {
         action = destDict.get("Dest");
       } else {
         action = destDict.get("AA");
 
-        if ((0, _primitives.isDict)(action)) {
+        if (action instanceof _primitives.Dict) {
           if (action.has("D")) {
             action = action.get("D");
           } else if (action.has("U")) {
@@ -1533,10 +1520,10 @@ class Catalog {
       }
     }
 
-    if ((0, _primitives.isDict)(action)) {
+    if (action instanceof _primitives.Dict) {
       const actionType = action.get("S");
 
-      if (!(0, _primitives.isName)(actionType)) {
+      if (!(actionType instanceof _primitives.Name)) {
         (0, _util.warn)("parseDestDictionary: Invalid type in Action dictionary.");
         return;
       }
@@ -1546,14 +1533,14 @@ class Catalog {
       switch (actionName) {
         case "ResetForm":
           const flags = action.get("Flags");
-          const include = (((0, _util.isNum)(flags) ? flags : 0) & 1) === 0;
+          const include = ((typeof flags === "number" ? flags : 0) & 1) === 0;
           const fields = [];
           const refs = [];
 
           for (const obj of action.get("Fields") || []) {
-            if ((0, _primitives.isRef)(obj)) {
+            if (obj instanceof _primitives.Ref) {
               refs.push(obj.toString());
-            } else if ((0, _util.isString)(obj)) {
+            } else if (typeof obj === "string") {
               fields.push((0, _util.stringToPDFString)(obj));
             }
           }
@@ -1582,23 +1569,23 @@ class Catalog {
         case "GoToR":
           const urlDict = action.get("F");
 
-          if ((0, _primitives.isDict)(urlDict)) {
+          if (urlDict instanceof _primitives.Dict) {
             url = urlDict.get("F") || null;
-          } else if ((0, _util.isString)(urlDict)) {
+          } else if (typeof urlDict === "string") {
             url = urlDict;
           }
 
           let remoteDest = action.get("D");
 
           if (remoteDest) {
-            if ((0, _primitives.isName)(remoteDest)) {
+            if (remoteDest instanceof _primitives.Name) {
               remoteDest = remoteDest.name;
             }
 
-            if ((0, _util.isString)(url)) {
+            if (typeof url === "string") {
               const baseUrl = url.split("#")[0];
 
-              if ((0, _util.isString)(remoteDest)) {
+              if (typeof remoteDest === "string") {
                 url = baseUrl + "#" + remoteDest;
               } else if (Array.isArray(remoteDest)) {
                 url = baseUrl + "#" + JSON.stringify(remoteDest);
@@ -1608,7 +1595,7 @@ class Catalog {
 
           const newWindow = action.get("NewWindow");
 
-          if ((0, _util.isBool)(newWindow)) {
+          if (typeof newWindow === "boolean") {
             resultObj.newWindow = newWindow;
           }
 
@@ -1617,7 +1604,7 @@ class Catalog {
         case "Named":
           const namedAction = action.get("N");
 
-          if ((0, _primitives.isName)(namedAction)) {
+          if (namedAction instanceof _primitives.Name) {
             resultObj.action = namedAction.name;
           }
 
@@ -1627,9 +1614,9 @@ class Catalog {
           const jsAction = action.get("JS");
           let js;
 
-          if ((0, _primitives.isStream)(jsAction)) {
+          if (jsAction instanceof _base_stream.BaseStream) {
             js = jsAction.getString();
-          } else if ((0, _util.isString)(jsAction)) {
+          } else if (typeof jsAction === "string") {
             js = jsAction;
           }
 
@@ -1653,7 +1640,7 @@ class Catalog {
       dest = destDict.get("Dest");
     }
 
-    if ((0, _util.isString)(url)) {
+    if (typeof url === "string") {
       const absoluteUrl = (0, _util.createValidAbsoluteUrl)(url, docBaseUrl, {
         addDefaultProtocol: true,
         tryConvertEncoding: true
@@ -1667,11 +1654,11 @@ class Catalog {
     }
 
     if (dest) {
-      if ((0, _primitives.isName)(dest)) {
+      if (dest instanceof _primitives.Name) {
         dest = dest.name;
       }
 
-      if ((0, _util.isString)(dest) || Array.isArray(dest)) {
+      if (typeof dest === "string" || Array.isArray(dest)) {
         resultObj.dest = dest;
       }
     }

+ 1 - 1
lib/core/ccitt.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 4 - 4
lib/core/ccitt_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,19 +26,19 @@ Object.defineProperty(exports, "__esModule", {
 });
 exports.CCITTFaxStream = void 0;
 
-var _primitives = require("./primitives.js");
-
 var _ccitt = require("./ccitt.js");
 
 var _decode_stream = require("./decode_stream.js");
 
+var _primitives = require("./primitives.js");
+
 class CCITTFaxStream extends _decode_stream.DecodeStream {
   constructor(str, maybeLength, params) {
     super(maybeLength);
     this.str = str;
     this.dict = str.dict;
 
-    if (!(0, _primitives.isDict)(params)) {
+    if (!(params instanceof _primitives.Dict)) {
       params = _primitives.Dict.empty;
     }
 

+ 1 - 1
lib/core/cff_font.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/cff_parser.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/charsets.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/chunked_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 36 - 0
lib/core/cleanup_helper.js

@@ -0,0 +1,36 @@
+/**
+ * @licstart The following is the entire license notice for the
+ * Javascript code in this page
+ *
+ * Copyright 2022 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.
+ *
+ * @licend The above is the entire license notice for the
+ * Javascript code in this page
+ */
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.clearGlobalCaches = clearGlobalCaches;
+
+var _primitives = require("./primitives.js");
+
+var _unicode = require("./unicode.js");
+
+function clearGlobalCaches() {
+  (0, _primitives.clearPrimitiveCaches)();
+  (0, _unicode.clearUnicodeCaches)();
+}

+ 13 - 11
lib/core/cmap.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -30,6 +30,8 @@ var _util = require("../shared/util.js");
 
 var _primitives = require("./primitives.js");
 
+var _base_stream = require("./base_stream.js");
+
 var _parser = require("./parser.js");
 
 var _core_utils = require("./core_utils.js");
@@ -622,7 +624,7 @@ const CMapFactory = function CMapFactoryClosure() {
   }
 
   function expectString(obj) {
-    if (!(0, _util.isString)(obj)) {
+    if (typeof obj !== "string") {
       throw new _util.FormatError("Malformed CMap: expected string.");
     }
   }
@@ -673,7 +675,7 @@ const CMapFactory = function CMapFactoryClosure() {
       const high = strToInt(obj);
       obj = lexer.getObj();
 
-      if (Number.isInteger(obj) || (0, _util.isString)(obj)) {
+      if (Number.isInteger(obj) || typeof obj === "string") {
         const dstLow = Number.isInteger(obj) ? String.fromCharCode(obj) : obj;
         cMap.mapBfRange(low, high, dstLow);
       } else if ((0, _primitives.isCmd)(obj, "[")) {
@@ -751,14 +753,14 @@ const CMapFactory = function CMapFactoryClosure() {
         return;
       }
 
-      if (!(0, _util.isString)(obj)) {
+      if (typeof obj !== "string") {
         break;
       }
 
       const low = strToInt(obj);
       obj = lexer.getObj();
 
-      if (!(0, _util.isString)(obj)) {
+      if (typeof obj !== "string") {
         break;
       }
 
@@ -780,7 +782,7 @@ const CMapFactory = function CMapFactoryClosure() {
   function parseCMapName(cMap, lexer) {
     const obj = lexer.getObj();
 
-    if ((0, _primitives.isName)(obj) && (0, _util.isString)(obj.name)) {
+    if (obj instanceof _primitives.Name) {
       cMap.name = obj.name;
     }
   }
@@ -794,7 +796,7 @@ const CMapFactory = function CMapFactoryClosure() {
 
         if (obj === _primitives.EOF) {
           break;
-        } else if ((0, _primitives.isName)(obj)) {
+        } else if (obj instanceof _primitives.Name) {
           if (obj.name === "WMode") {
             parseWMode(cMap, lexer);
           } else if (obj.name === "CMapName") {
@@ -802,13 +804,13 @@ const CMapFactory = function CMapFactoryClosure() {
           }
 
           previous = obj;
-        } else if ((0, _primitives.isCmd)(obj)) {
+        } else if (obj instanceof _primitives.Cmd) {
           switch (obj.cmd) {
             case "endcmap":
               break objLoop;
 
             case "usecmap":
-              if ((0, _primitives.isName)(previous)) {
+              if (previous instanceof _primitives.Name) {
                 embeddedUseCMap = previous.name;
               }
 
@@ -918,9 +920,9 @@ const CMapFactory = function CMapFactoryClosure() {
       const fetchBuiltInCMap = params.fetchBuiltInCMap;
       const useCMap = params.useCMap;
 
-      if ((0, _primitives.isName)(encoding)) {
+      if (encoding instanceof _primitives.Name) {
         return createBuiltInCMap(encoding.name, fetchBuiltInCMap);
-      } else if ((0, _primitives.isStream)(encoding)) {
+      } else if (encoding instanceof _base_stream.BaseStream) {
         const parsedCMap = await parseCMap(new CMap(), new _parser.Lexer(encoding), fetchBuiltInCMap, useCMap);
 
         if (parsedCMap.isIdentityCMap) {

+ 8 - 6
lib/core/colorspace.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -30,6 +30,8 @@ var _util = require("../shared/util.js");
 
 var _primitives = require("./primitives.js");
 
+var _base_stream = require("./base_stream.js");
+
 var _core_utils = require("./core_utils.js");
 
 function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) {
@@ -258,7 +260,7 @@ class ColorSpace {
   static _parse(cs, xref, resources = null, pdfFunctionFactory) {
     cs = xref.fetchIfRef(cs);
 
-    if ((0, _primitives.isName)(cs)) {
+    if (cs instanceof _primitives.Name) {
       switch (cs.name) {
         case "G":
         case "DeviceGray":
@@ -276,14 +278,14 @@ class ColorSpace {
           return new PatternCS(null);
 
         default:
-          if ((0, _primitives.isDict)(resources)) {
+          if (resources instanceof _primitives.Dict) {
             const colorSpaces = resources.get("ColorSpace");
 
-            if ((0, _primitives.isDict)(colorSpaces)) {
+            if (colorSpaces instanceof _primitives.Dict) {
               const resourcesCS = colorSpaces.get(cs.name);
 
               if (resourcesCS) {
-                if ((0, _primitives.isName)(resourcesCS)) {
+                if (resourcesCS instanceof _primitives.Name) {
                   return this._parse(resourcesCS, xref, resources, pdfFunctionFactory);
                 }
 
@@ -510,7 +512,7 @@ class IndexedCS extends ColorSpace {
     const length = base.numComps * highVal;
     this.lookup = new Uint8Array(length);
 
-    if ((0, _primitives.isStream)(lookup)) {
+    if (lookup instanceof _base_stream.BaseStream) {
       const bytes = lookup.getBytes(length);
       this.lookup.set(bytes);
     } else if (typeof lookup === "string") {

+ 8 - 6
lib/core/core_utils.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -45,6 +45,8 @@ var _util = require("../shared/util.js");
 
 var _primitives = require("./primitives.js");
 
+var _base_stream = require("./base_stream.js");
+
 function getLookupTableFactory(initializer) {
   let lookup;
   return function () {
@@ -299,7 +301,7 @@ function _collectJS(entry, xref, list, parents) {
 
   let parent = null;
 
-  if ((0, _primitives.isRef)(entry)) {
+  if (entry instanceof _primitives.Ref) {
     if (parents.has(entry)) {
       return;
     }
@@ -314,17 +316,17 @@ function _collectJS(entry, xref, list, parents) {
       _collectJS(element, xref, list, parents);
     }
   } else if (entry instanceof _primitives.Dict) {
-    if ((0, _primitives.isName)(entry.get("S"), "JavaScript") && entry.has("JS")) {
+    if ((0, _primitives.isName)(entry.get("S"), "JavaScript")) {
       const js = entry.get("JS");
       let code;
 
-      if ((0, _primitives.isStream)(js)) {
+      if (js instanceof _base_stream.BaseStream) {
         code = js.getString();
-      } else {
+      } else if (typeof js === "string") {
         code = js;
       }
 
-      code = (0, _util.stringToPDFString)(code);
+      code = code && (0, _util.stringToPDFString)(code);
 
       if (code) {
         list.push(code);

+ 4 - 4
lib/core/crypto.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -1441,7 +1441,7 @@ const CipherTransformFactory = function CipherTransformFactoryClosure() {
   }
 
   function buildCipherConstructor(cf, name, num, gen, key) {
-    if (!(0, _primitives.isName)(name)) {
+    if (!(name instanceof _primitives.Name)) {
       throw new _util.FormatError("Invalid crypt filter name.");
     }
 
@@ -1505,7 +1505,7 @@ const CipherTransformFactory = function CipherTransformFactoryClosure() {
           const cfDict = dict.get("CF");
           const streamCryptoName = dict.get("StmF");
 
-          if ((0, _primitives.isDict)(cfDict) && (0, _primitives.isName)(streamCryptoName)) {
+          if (cfDict instanceof _primitives.Dict && streamCryptoName instanceof _primitives.Name) {
             cfDict.suppressEncryption = true;
             const handlerDict = cfDict.get(streamCryptoName.name);
             keyLength = handlerDict && handlerDict.get("Length") || 128;
@@ -1574,7 +1574,7 @@ const CipherTransformFactory = function CipherTransformFactoryClosure() {
       if (algorithm >= 4) {
         const cf = dict.get("CF");
 
-        if ((0, _primitives.isDict)(cf)) {
+        if (cf instanceof _primitives.Dict) {
           cf.suppressEncryption = true;
         }
 

+ 1 - 1
lib/core/decode_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/decrypt_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/default_appearance.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 97 - 53
lib/core/document.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,10 +28,10 @@ exports.Page = exports.PDFDocument = void 0;
 
 var _util = require("../shared/util.js");
 
-var _primitives = require("./primitives.js");
-
 var _core_utils = require("./core_utils.js");
 
+var _primitives = require("./primitives.js");
+
 var _xfa_fonts = require("./xfa_fonts.js");
 
 var _stream = require("./stream.js");
@@ -44,6 +44,8 @@ var _crypto = require("./crypto.js");
 
 var _catalog = require("./catalog.js");
 
+var _cleanup_helper = require("./cleanup_helper.js");
+
 var _parser = require("./parser.js");
 
 var _object_loader = require("./object_loader.js");
@@ -118,7 +120,7 @@ class Page {
       return value;
     }
 
-    if (value.length === 1 || !(0, _primitives.isDict)(value[0])) {
+    if (value.length === 1 || !(value[0] instanceof _primitives.Dict)) {
       return value[0];
     }
 
@@ -165,7 +167,7 @@ class Page {
   get userUnit() {
     let obj = this.pageDict.get("UserUnit");
 
-    if (!(0, _util.isNum)(obj) || obj <= 0) {
+    if (typeof obj !== "number" || obj <= 0) {
       obj = DEFAULT_USER_UNIT;
     }
 
@@ -361,7 +363,6 @@ class Page {
   extractTextContent({
     handler,
     task,
-    normalizeWhitespace,
     includeMarkedContent,
     sink,
     combineTextItems
@@ -385,10 +386,10 @@ class Page {
         stream: contentStream,
         task,
         resources: this.resources,
-        normalizeWhitespace,
         includeMarkedContent,
         combineTextItems,
-        sink
+        sink,
+        viewBox: this.view
       });
     });
   }
@@ -524,7 +525,7 @@ class PDFDocument {
   constructor(pdfManager, arg) {
     let stream;
 
-    if ((0, _primitives.isStream)(arg)) {
+    if (arg instanceof _base_stream.BaseStream) {
       stream = arg;
     } else if ((0, _util.isArrayBuffer)(arg)) {
       stream = new _stream.Stream(arg);
@@ -737,7 +738,7 @@ class PDFDocument {
       "/xdp:xdp": ""
     };
 
-    if ((0, _primitives.isStream)(xfa) && !xfa.isEmpty) {
+    if (xfa instanceof _base_stream.BaseStream && !xfa.isEmpty) {
       try {
         entries["xdp:xdp"] = (0, _util.stringToUTF8String)(xfa.getString());
         return entries;
@@ -768,7 +769,7 @@ class PDFDocument {
 
       const data = this.xref.fetchIfRef(xfa[i + 1]);
 
-      if (!(0, _primitives.isStream)(data) || data.isEmpty) {
+      if (!(data instanceof _base_stream.BaseStream) || data.isEmpty) {
         continue;
       }
 
@@ -816,11 +817,9 @@ class PDFDocument {
     for (const key of keys) {
       const stream = xfaImagesDict.get(key);
 
-      if (!(0, _primitives.isStream)(stream)) {
-        continue;
+      if (stream instanceof _base_stream.BaseStream) {
+        xfaImages.set(key, stream.getBytes());
       }
-
-      xfaImages.set(key, stream.getBytes());
     }
 
     this.xfaFactory.setImages(xfaImages);
@@ -991,7 +990,7 @@ class PDFDocument {
       const hasFields = Array.isArray(fields) && fields.length > 0;
       formInfo.hasFields = hasFields;
       const xfa = acroForm.get("XFA");
-      formInfo.hasXfa = Array.isArray(xfa) && xfa.length > 0 || (0, _primitives.isStream)(xfa) && !xfa.isEmpty;
+      formInfo.hasXfa = Array.isArray(xfa) && xfa.length > 0 || xfa instanceof _base_stream.BaseStream && !xfa.isEmpty;
       const sigFlags = acroForm.get("SigFlags");
       const hasSignatures = !!(sigFlags & 0x1);
 
@@ -1011,17 +1010,6 @@ class PDFDocument {
   }
 
   get documentInfo() {
-    const DocumentInfoValidators = {
-      Title: _util.isString,
-      Author: _util.isString,
-      Subject: _util.isString,
-      Keywords: _util.isString,
-      Creator: _util.isString,
-      Producer: _util.isString,
-      CreationDate: _util.isString,
-      ModDate: _util.isString,
-      Trapped: _primitives.isName
-    };
     let version = this._version;
 
     if (typeof version !== "string" || !PDF_HEADER_VERSION_REGEXP.test(version)) {
@@ -1051,25 +1039,60 @@ class PDFDocument {
       (0, _util.info)("The document information dictionary is invalid.");
     }
 
-    if ((0, _primitives.isDict)(infoDict)) {
-      for (const key of infoDict.getKeys()) {
-        const value = infoDict.get(key);
+    if (!(infoDict instanceof _primitives.Dict)) {
+      return (0, _util.shadow)(this, "documentInfo", docInfo);
+    }
 
-        if (DocumentInfoValidators[key]) {
-          if (DocumentInfoValidators[key](value)) {
-            docInfo[key] = typeof value !== "string" ? value : (0, _util.stringToPDFString)(value);
-          } else {
-            (0, _util.info)(`Bad value in document info for "${key}".`);
+    for (const key of infoDict.getKeys()) {
+      const value = infoDict.get(key);
+
+      switch (key) {
+        case "Title":
+        case "Author":
+        case "Subject":
+        case "Keywords":
+        case "Creator":
+        case "Producer":
+        case "CreationDate":
+        case "ModDate":
+          if (typeof value === "string") {
+            docInfo[key] = (0, _util.stringToPDFString)(value);
+            continue;
+          }
+
+          break;
+
+        case "Trapped":
+          if (value instanceof _primitives.Name) {
+            docInfo[key] = value;
+            continue;
           }
-        } else if (typeof key === "string") {
+
+          break;
+
+        default:
           let customValue;
 
-          if ((0, _util.isString)(value)) {
-            customValue = (0, _util.stringToPDFString)(value);
-          } else if ((0, _primitives.isName)(value) || (0, _util.isNum)(value) || (0, _util.isBool)(value)) {
-            customValue = value;
-          } else {
-            (0, _util.info)(`Unsupported value in document info for (custom) "${key}".`);
+          switch (typeof value) {
+            case "string":
+              customValue = (0, _util.stringToPDFString)(value);
+              break;
+
+            case "number":
+            case "boolean":
+              customValue = value;
+              break;
+
+            default:
+              if (value instanceof _primitives.Name) {
+                customValue = value;
+              }
+
+              break;
+          }
+
+          if (customValue === undefined) {
+            (0, _util.warn)(`Bad value, for custom key "${key}", in Info: ${value}.`);
             continue;
           }
 
@@ -1078,8 +1101,10 @@ class PDFDocument {
           }
 
           docInfo.Custom[key] = customValue;
-        }
+          continue;
       }
+
+      (0, _util.warn)(`Bad value, for key "${key}", in Info: ${value}.`);
     }
 
     return (0, _util.shadow)(this, "documentInfo", docInfo);
@@ -1120,25 +1145,38 @@ class PDFDocument {
   async _getLinearizationPage(pageIndex) {
     const {
       catalog,
-      linearization
+      linearization,
+      xref
     } = this;
 
     const ref = _primitives.Ref.get(linearization.objectNumberFirst, 0);
 
     try {
-      const obj = await this.xref.fetchAsync(ref);
+      const obj = await xref.fetchAsync(ref);
+
+      if (obj instanceof _primitives.Dict) {
+        let type = obj.getRaw("Type");
 
-      if ((0, _primitives.isDict)(obj, "Page") || (0, _primitives.isDict)(obj) && !obj.has("Type") && obj.has("Contents")) {
-        if (ref && !catalog.pageKidsCountCache.has(ref)) {
-          catalog.pageKidsCountCache.put(ref, 1);
+        if (type instanceof _primitives.Ref) {
+          type = await xref.fetchAsync(type);
         }
 
-        return [obj, ref];
+        if ((0, _primitives.isName)(type, "Page") || !obj.has("Type") && !obj.has("Kids")) {
+          if (!catalog.pageKidsCountCache.has(ref)) {
+            catalog.pageKidsCountCache.put(ref, 1);
+          }
+
+          if (!catalog.pageIndexCache.has(ref)) {
+            catalog.pageIndexCache.put(ref, 0);
+          }
+
+          return [obj, ref];
+        }
       }
 
       throw new _util.FormatError("The Linearization dictionary doesn't point to a valid Page dictionary.");
     } catch (reason) {
-      (0, _util.info)(reason);
+      (0, _util.warn)(`_getLinearizationPage: "${reason.message}".`);
       return catalog.getPageDict(pageIndex);
     }
   }
@@ -1243,7 +1281,7 @@ class PDFDocument {
       let pagesTree;
 
       try {
-        pagesTree = await pdfManager.ensureCatalog("getAllPageDicts", [recoveryMode]);
+        pagesTree = await catalog.getAllPageDicts(recoveryMode);
       } catch (reasonAll) {
         if (reasonAll instanceof _core_utils.XRefEntryException && !recoveryMode) {
           throw new _core_utils.XRefParseException();
@@ -1288,7 +1326,7 @@ class PDFDocument {
   }
 
   async cleanup(manuallyTriggered = false) {
-    return this.catalog ? this.catalog.cleanup(manuallyTriggered) : (0, _primitives.clearPrimitiveCaches)();
+    return this.catalog ? this.catalog.cleanup(manuallyTriggered) : (0, _cleanup_helper.clearGlobalCaches)();
   }
 
   _collectFieldObjects(name, fieldRef, promises) {
@@ -1381,7 +1419,13 @@ class PDFDocument {
       return (0, _util.shadow)(this, "calculationOrderIds", null);
     }
 
-    const ids = calculationOrder.filter(_primitives.isRef).map(ref => ref.toString());
+    const ids = [];
+
+    for (const id of calculationOrder) {
+      if (id instanceof _primitives.Ref) {
+        ids.push(id.toString());
+      }
+    }
 
     if (ids.length === 0) {
       return (0, _util.shadow)(this, "calculationOrderIds", null);

+ 1 - 1
lib/core/encodings.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 156 - 127
lib/core/evaluator.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -107,7 +107,7 @@ function normalizeBlendMode(value, parsingArray = false) {
     return "source-over";
   }
 
-  if (!(0, _primitives.isName)(value)) {
+  if (!(value instanceof _primitives.Name)) {
     if (parsingArray) {
       return null;
     }
@@ -329,7 +329,7 @@ class PartialEvaluator {
           }
         }
 
-        if (!(0, _primitives.isStream)(xObject)) {
+        if (!(xObject instanceof _base_stream.BaseStream)) {
           continue;
         }
 
@@ -545,7 +545,7 @@ class PartialEvaluator {
     const w = dict.get("W", "Width");
     const h = dict.get("H", "Height");
 
-    if (!(w && (0, _util.isNum)(w)) || !(h && (0, _util.isNum)(h))) {
+    if (!(w && typeof w === "number") || !(h && typeof h === "number")) {
       (0, _util.warn)("Image dimensions are missing, or not numbers.");
       return;
     }
@@ -925,7 +925,7 @@ class PartialEvaluator {
             break;
           }
 
-          if ((0, _primitives.isDict)(value)) {
+          if (value instanceof _primitives.Dict) {
             isSimpleGState = false;
             promise = promise.then(() => {
               return this.handleSMask(value, resources, operatorList, task, stateManager, localColorSpaceCache);
@@ -989,7 +989,7 @@ class PartialEvaluator {
     let fontRef;
 
     if (font) {
-      if (!(0, _primitives.isRef)(font)) {
+      if (!(font instanceof _primitives.Ref)) {
         throw new _util.FormatError('The "font" object should be a reference.');
       }
 
@@ -1022,13 +1022,17 @@ class PartialEvaluator {
       }
     }
 
+    if (this.parsingType3Font && this.type3FontRefs.has(fontRef)) {
+      return errorFont();
+    }
+
     if (this.fontCache.has(fontRef)) {
       return this.fontCache.get(fontRef);
     }
 
     font = xref.fetchIfRef(fontRef);
 
-    if (!(0, _primitives.isDict)(font)) {
+    if (!(font instanceof _primitives.Dict)) {
       return errorFont();
     }
 
@@ -1051,14 +1055,14 @@ class PartialEvaluator {
       descriptor,
       hash
     } = preEvaluatedFont;
-    const fontRefIsRef = (0, _primitives.isRef)(fontRef);
+    const fontRefIsRef = fontRef instanceof _primitives.Ref;
     let fontID;
 
     if (fontRefIsRef) {
       fontID = `f${fontRef.toString()}`;
     }
 
-    if (hash && (0, _primitives.isDict)(descriptor)) {
+    if (hash && descriptor instanceof _primitives.Dict) {
       if (!descriptor.fontAliases) {
         descriptor.fontAliases = Object.create(null);
       }
@@ -1227,7 +1231,7 @@ class PartialEvaluator {
       const pattern = this.xref.fetchIfRef(rawPattern);
 
       if (pattern) {
-        const dict = (0, _primitives.isStream)(pattern) ? pattern.dict : pattern;
+        const dict = pattern instanceof _base_stream.BaseStream ? pattern.dict : pattern;
         const typeNum = dict.get("PatternType");
 
         if (typeNum === PatternType.TILING) {
@@ -1264,7 +1268,7 @@ class PartialEvaluator {
     const length = array.length;
     const operator = this.xref.fetchIfRef(array[0]);
 
-    if (length < 2 || !(0, _primitives.isName)(operator)) {
+    if (length < 2 || !(operator instanceof _primitives.Name)) {
       (0, _util.warn)("Invalid visibility expression");
       return;
     }
@@ -1290,7 +1294,7 @@ class PartialEvaluator {
         currentResult.push(nestedResult);
 
         this._parseVisibilityExpression(object, nestingCounter, nestedResult);
-      } else if ((0, _primitives.isRef)(raw)) {
+      } else if (raw instanceof _primitives.Ref) {
         currentResult.push(raw.toString());
       }
     }
@@ -1299,10 +1303,10 @@ class PartialEvaluator {
   async parseMarkedContentProps(contentProperties, resources) {
     let optionalContent;
 
-    if ((0, _primitives.isName)(contentProperties)) {
+    if (contentProperties instanceof _primitives.Name) {
       const properties = resources.get("Properties");
       optionalContent = properties.get(contentProperties.name);
-    } else if ((0, _primitives.isDict)(contentProperties)) {
+    } else if (contentProperties instanceof _primitives.Dict) {
       optionalContent = contentProperties;
     } else {
       throw new _util.FormatError("Optional content properties malformed.");
@@ -1333,7 +1337,7 @@ class PartialEvaluator {
 
       const optionalContentGroups = optionalContent.get("OCGs");
 
-      if (Array.isArray(optionalContentGroups) || (0, _primitives.isDict)(optionalContentGroups)) {
+      if (Array.isArray(optionalContentGroups) || optionalContentGroups instanceof _primitives.Dict) {
         const groupIds = [];
 
         if (Array.isArray(optionalContentGroups)) {
@@ -1347,10 +1351,10 @@ class PartialEvaluator {
         return {
           type: optionalContentType,
           ids: groupIds,
-          policy: (0, _primitives.isName)(optionalContent.get("P")) ? optionalContent.get("P").name : null,
+          policy: optionalContent.get("P") instanceof _primitives.Name ? optionalContent.get("P").name : null,
           expression: null
         };
-      } else if ((0, _primitives.isRef)(optionalContentGroups)) {
+      } else if (optionalContentGroups instanceof _primitives.Ref) {
         return {
           type: optionalContentType,
           id: optionalContentGroups.toString()
@@ -1468,13 +1472,13 @@ class PartialEvaluator {
                 xobj = xref.fetch(xobj);
               }
 
-              if (!(0, _primitives.isStream)(xobj)) {
+              if (!(xobj instanceof _base_stream.BaseStream)) {
                 throw new _util.FormatError("XObject should be a stream");
               }
 
               const type = xobj.dict.get("Subtype");
 
-              if (!(0, _primitives.isName)(type)) {
+              if (!(type instanceof _primitives.Name)) {
                 throw new _util.FormatError("XObject should have a Name subtype");
               }
 
@@ -1582,9 +1586,9 @@ class PartialEvaluator {
             for (i = 0; i < arrLength; ++i) {
               const arrItem = arr[i];
 
-              if ((0, _util.isString)(arrItem)) {
+              if (typeof arrItem === "string") {
                 Array.prototype.push.apply(combinedGlyphs, self.handleText(arrItem, state));
-              } else if ((0, _util.isNum)(arrItem)) {
+              } else if (typeof arrItem === "number") {
                 combinedGlyphs.push(arrItem);
               }
             }
@@ -1834,7 +1838,7 @@ class PartialEvaluator {
             continue;
 
           case _util.OPS.beginMarkedContentProps:
-            if (!(0, _primitives.isName)(args[0])) {
+            if (!(args[0] instanceof _primitives.Name)) {
               (0, _util.warn)(`Expected name for beginMarkedContentProps arg0=${args[0]}`);
               continue;
             }
@@ -1914,16 +1918,14 @@ class PartialEvaluator {
     task,
     resources,
     stateManager = null,
-    normalizeWhitespace = false,
     combineTextItems = false,
     includeMarkedContent = false,
     sink,
-    seenStyles = new Set()
+    seenStyles = new Set(),
+    viewBox
   }) {
     resources = resources || _primitives.Dict.empty;
     stateManager = stateManager || new StateManager(new TextState());
-    const WhitespaceRegexp = /\s/g;
-    const DiacriticRegExp = new RegExp("^\\p{Mn}$", "u");
     const NormalizedUnicodes = (0, _unicode.getNormalizedUnicodes)();
     const textContent = {
       items: [],
@@ -2042,27 +2044,14 @@ class PartialEvaluator {
       textContentItem.textAdvanceScale = scaleFactor;
     }
 
-    function replaceWhitespace(str) {
-      const ii = str.length;
-      let i = 0,
-          code;
-
-      while (i < ii && (code = str.charCodeAt(i)) >= 0x20 && code <= 0x7f) {
-        i++;
-      }
-
-      return i < ii ? str.replace(WhitespaceRegexp, " ") : str;
-    }
-
     function runBidiTransform(textChunk) {
       const text = textChunk.str.join("");
       const bidiResult = (0, _bidi.bidi)(text, -1, textChunk.vertical);
-      const str = normalizeWhitespace ? replaceWhitespace(bidiResult.str) : bidiResult.str;
       return {
-        str,
+        str: bidiResult.str,
         dir: bidiResult.dir,
-        width: textChunk.totalWidth,
-        height: textChunk.totalHeight,
+        width: Math.abs(textChunk.totalWidth),
+        height: Math.abs(textChunk.totalHeight),
         transform: textChunk.transform,
         fontName: textChunk.fontName,
         hasEOL: textChunk.hasEOL
@@ -2084,75 +2073,93 @@ class PartialEvaluator {
       });
     }
 
-    function compareWithLastPosition() {
-      if (!combineTextItems || !textState.font || !textContentItem.prevTransform) {
-        return;
-      }
+    function applyInverseRotation(x, y, matrix) {
+      const scale = Math.hypot(matrix[0], matrix[1]);
+      return [(matrix[0] * x + matrix[1] * y) / scale, (matrix[2] * x + matrix[3] * y) / scale];
+    }
 
+    function compareWithLastPosition() {
       const currentTransform = getCurrentTextTransform();
       let posX = currentTransform[4];
       let posY = currentTransform[5];
+      const shiftedX = posX - viewBox[0];
+      const shiftedY = posY - viewBox[1];
+
+      if (shiftedX < 0 || shiftedX > viewBox[2] || shiftedY < 0 || shiftedY > viewBox[3]) {
+        return false;
+      }
+
+      if (!combineTextItems || !textState.font || !textContentItem.prevTransform) {
+        return true;
+      }
+
       let lastPosX = textContentItem.prevTransform[4];
       let lastPosY = textContentItem.prevTransform[5];
 
       if (lastPosX === posX && lastPosY === posY) {
-        return;
+        return true;
       }
 
-      let rotate = 0;
+      let rotate = -1;
 
       if (currentTransform[0] && currentTransform[1] === 0 && currentTransform[2] === 0) {
         rotate = currentTransform[0] > 0 ? 0 : 180;
       } else if (currentTransform[1] && currentTransform[0] === 0 && currentTransform[3] === 0) {
-        rotate += currentTransform[1] > 0 ? 90 : 270;
+        rotate = currentTransform[1] > 0 ? 90 : 270;
       }
 
-      if (rotate !== 0) {
-        switch (rotate) {
-          case 90:
-            [posX, posY] = [posY, posX];
-            [lastPosX, lastPosY] = [lastPosY, lastPosX];
-            break;
+      switch (rotate) {
+        case 0:
+          break;
 
-          case 180:
-            [posX, posY, lastPosX, lastPosY] = [-posX, -posY, -lastPosX, -lastPosY];
-            break;
+        case 90:
+          [posX, posY] = [posY, posX];
+          [lastPosX, lastPosY] = [lastPosY, lastPosX];
+          break;
 
-          case 270:
-            [posX, posY] = [-posY, -posX];
-            [lastPosX, lastPosY] = [-lastPosY, -lastPosX];
-            break;
-        }
+        case 180:
+          [posX, posY, lastPosX, lastPosY] = [-posX, -posY, -lastPosX, -lastPosY];
+          break;
+
+        case 270:
+          [posX, posY] = [-posY, -posX];
+          [lastPosX, lastPosY] = [-lastPosY, -lastPosX];
+          break;
+
+        default:
+          [posX, posY] = applyInverseRotation(posX, posY, currentTransform);
+          [lastPosX, lastPosY] = applyInverseRotation(lastPosX, lastPosY, textContentItem.prevTransform);
       }
 
       if (textState.font.vertical) {
         const advanceY = (lastPosY - posY) / textContentItem.textAdvanceScale;
         const advanceX = posX - lastPosX;
+        const textOrientation = Math.sign(textContentItem.height);
 
-        if (advanceY < textContentItem.negativeSpaceMax) {
+        if (advanceY < textOrientation * textContentItem.negativeSpaceMax) {
           if (Math.abs(advanceX) > 0.5 * textContentItem.width) {
             appendEOL();
-            return;
+            return true;
           }
 
           flushTextContentItem();
-          return;
+          return true;
         }
 
-        if (Math.abs(advanceX) > textContentItem.height) {
+        if (Math.abs(advanceX) > textContentItem.width) {
           appendEOL();
-          return;
+          return true;
         }
 
-        if (advanceY <= textContentItem.trackingSpaceMin) {
+        if (advanceY <= textOrientation * textContentItem.trackingSpaceMin) {
           textContentItem.height += advanceY;
-        } else if (!addFakeSpaces(advanceY, textContentItem.prevTransform)) {
+        } else if (!addFakeSpaces(advanceY, textContentItem.prevTransform, textOrientation)) {
           if (textContentItem.str.length === 0) {
             textContent.items.push({
               str: " ",
               dir: "ltr",
               width: 0,
-              height: advanceY,
+              height: Math.abs(advanceY),
               transform: textContentItem.prevTransform,
               fontName: textContentItem.fontName,
               hasEOL: false
@@ -2162,35 +2169,36 @@ class PartialEvaluator {
           }
         }
 
-        return;
+        return true;
       }
 
       const advanceX = (posX - lastPosX) / textContentItem.textAdvanceScale;
       const advanceY = posY - lastPosY;
+      const textOrientation = Math.sign(textContentItem.width);
 
-      if (advanceX < textContentItem.negativeSpaceMax) {
+      if (advanceX < textOrientation * textContentItem.negativeSpaceMax) {
         if (Math.abs(advanceY) > 0.5 * textContentItem.height) {
           appendEOL();
-          return;
+          return true;
         }
 
         flushTextContentItem();
-        return;
+        return true;
       }
 
       if (Math.abs(advanceY) > textContentItem.height) {
         appendEOL();
-        return;
+        return true;
       }
 
-      if (advanceX <= textContentItem.trackingSpaceMin) {
+      if (advanceX <= textOrientation * textContentItem.trackingSpaceMin) {
         textContentItem.width += advanceX;
-      } else if (!addFakeSpaces(advanceX, textContentItem.prevTransform)) {
+      } else if (!addFakeSpaces(advanceX, textContentItem.prevTransform, textOrientation)) {
         if (textContentItem.str.length === 0) {
           textContent.items.push({
             str: " ",
             dir: "ltr",
-            width: advanceX,
+            width: Math.abs(advanceX),
             height: 0,
             transform: textContentItem.prevTransform,
             fontName: textContentItem.fontName,
@@ -2200,6 +2208,8 @@ class PartialEvaluator {
           textContentItem.width += advanceX;
         }
       }
+
+      return true;
     }
 
     function buildTextContentItem({
@@ -2227,6 +2237,11 @@ class PartialEvaluator {
 
       for (let i = 0, ii = glyphs.length; i < ii; i++) {
         const glyph = glyphs[i];
+
+        if (glyph.isInvisibleFormatMark) {
+          continue;
+        }
+
         let charSpacing = textState.charSpacing + (i + 1 === ii ? extraSpacing : 0);
         let glyphWidth = glyph.width;
 
@@ -2235,9 +2250,8 @@ class PartialEvaluator {
         }
 
         let scaledDim = glyphWidth * scale;
-        let glyphUnicode = glyph.unicode;
 
-        if (glyphUnicode === " " && (i === 0 || i + 1 === ii || glyphs[i - 1].unicode === " " || glyphs[i + 1].unicode === " " || extraSpacing)) {
+        if (glyph.isWhitespace && (i === 0 || i + 1 === ii || glyphs[i - 1].isWhitespace || glyphs[i + 1].isWhitespace || extraSpacing)) {
           if (!font.vertical) {
             charSpacing += scaledDim + textState.wordSpacing;
             textState.translateTextMatrix(charSpacing * textState.textHScale, 0);
@@ -2249,10 +2263,13 @@ class PartialEvaluator {
           continue;
         }
 
-        compareWithLastPosition();
+        if (!compareWithLastPosition()) {
+          continue;
+        }
+
         const textChunk = ensureTextContentItem();
 
-        if (DiacriticRegExp.test(glyph.unicode)) {
+        if (glyph.isZeroWidthDiacritic) {
           scaledDim = 0;
         }
 
@@ -2270,9 +2287,14 @@ class PartialEvaluator {
           textChunk.prevTransform = getCurrentTextTransform();
         }
 
-        glyphUnicode = NormalizedUnicodes[glyphUnicode] || glyphUnicode;
-        glyphUnicode = (0, _unicode.reverseIfRtl)(glyphUnicode);
-        textChunk.str.push(glyphUnicode);
+        if (glyph.isWhitespace) {
+          textChunk.str.push(" ");
+        } else {
+          let glyphUnicode = glyph.unicode;
+          glyphUnicode = NormalizedUnicodes[glyphUnicode] || glyphUnicode;
+          glyphUnicode = (0, _unicode.reverseIfRtl)(glyphUnicode);
+          textChunk.str.push(glyphUnicode);
+        }
 
         if (charSpacing) {
           if (!font.vertical) {
@@ -2301,8 +2323,8 @@ class PartialEvaluator {
       }
     }
 
-    function addFakeSpaces(width, transf) {
-      if (textContentItem.spaceInFlowMin <= width && width <= textContentItem.spaceInFlowMax) {
+    function addFakeSpaces(width, transf, textOrientation) {
+      if (textOrientation * textContentItem.spaceInFlowMin <= width && width <= textOrientation * textContentItem.spaceInFlowMax) {
         if (textContentItem.initialized) {
           textContentItem.str.push(" ");
         }
@@ -2322,8 +2344,8 @@ class PartialEvaluator {
       textContent.items.push({
         str: " ",
         dir: "ltr",
-        width,
-        height,
+        width: Math.abs(width),
+        height: Math.abs(height),
         transform: transf || getCurrentTextTransform(),
         fontName,
         hasEOL: false
@@ -2573,13 +2595,13 @@ class PartialEvaluator {
                 xobj = xref.fetch(xobj);
               }
 
-              if (!(0, _primitives.isStream)(xobj)) {
+              if (!(xobj instanceof _base_stream.BaseStream)) {
                 throw new _util.FormatError("XObject should be a stream");
               }
 
               const type = xobj.dict.get("Subtype");
 
-              if (!(0, _primitives.isName)(type)) {
+              if (!(type instanceof _primitives.Name)) {
                 throw new _util.FormatError("XObject should have a Name subtype");
               }
 
@@ -2620,11 +2642,11 @@ class PartialEvaluator {
                 task,
                 resources: xobj.dict.get("Resources") || resources,
                 stateManager: xObjStateManager,
-                normalizeWhitespace,
                 combineTextItems,
                 includeMarkedContent,
                 sink: sinkWrapper,
-                seenStyles
+                seenStyles,
+                viewBox
               }).then(function () {
                 if (!sinkWrapper.enqueueInvoked) {
                   emptyXObjectCache.set(name, xobj.dict.objId, true);
@@ -2701,7 +2723,7 @@ class PartialEvaluator {
             if (includeMarkedContent) {
               textContent.items.push({
                 type: "beginMarkedContent",
-                tag: (0, _primitives.isName)(args[0]) ? args[0].name : null
+                tag: args[0] instanceof _primitives.Name ? args[0].name : null
               });
             }
 
@@ -2712,14 +2734,14 @@ class PartialEvaluator {
               flushTextContentItem();
               let mcid = null;
 
-              if ((0, _primitives.isDict)(args[1])) {
+              if (args[1] instanceof _primitives.Dict) {
                 mcid = args[1].get("MCID");
               }
 
               textContent.items.push({
                 type: "beginMarkedContentProps",
                 id: Number.isInteger(mcid) ? `${self.idFactory.getPageObjId()}_mcid${mcid}` : null,
-                tag: (0, _primitives.isName)(args[0]) ? args[0].name : null
+                tag: args[0] instanceof _primitives.Name ? args[0].name : null
               });
             }
 
@@ -2774,7 +2796,7 @@ class PartialEvaluator {
     if (properties.composite) {
       const cidSystemInfo = dict.get("CIDSystemInfo");
 
-      if ((0, _primitives.isDict)(cidSystemInfo)) {
+      if (cidSystemInfo instanceof _primitives.Dict) {
         properties.cidSystemInfo = {
           registry: (0, _util.stringToPDFString)(cidSystemInfo.get("Registry")),
           ordering: (0, _util.stringToPDFString)(cidSystemInfo.get("Ordering")),
@@ -2796,9 +2818,9 @@ class PartialEvaluator {
     if (dict.has("Encoding")) {
       encoding = dict.get("Encoding");
 
-      if ((0, _primitives.isDict)(encoding)) {
+      if (encoding instanceof _primitives.Dict) {
         baseEncodingName = encoding.get("BaseEncoding");
-        baseEncodingName = (0, _primitives.isName)(baseEncodingName) ? baseEncodingName.name : null;
+        baseEncodingName = baseEncodingName instanceof _primitives.Name ? baseEncodingName.name : null;
 
         if (encoding.has("Differences")) {
           const diffEncoding = encoding.get("Differences");
@@ -2807,16 +2829,16 @@ class PartialEvaluator {
           for (let j = 0, jj = diffEncoding.length; j < jj; j++) {
             const data = xref.fetchIfRef(diffEncoding[j]);
 
-            if ((0, _util.isNum)(data)) {
+            if (typeof data === "number") {
               index = data;
-            } else if ((0, _primitives.isName)(data)) {
+            } else if (data instanceof _primitives.Name) {
               differences[index++] = data.name;
             } else {
               throw new _util.FormatError(`Invalid entry in 'Differences' array: ${data}`);
             }
           }
         }
-      } else if ((0, _primitives.isName)(encoding)) {
+      } else if (encoding instanceof _primitives.Name) {
         baseEncodingName = encoding.name;
       } else {
         throw new _util.FormatError("Encoding is not a Name nor a Dict");
@@ -3014,7 +3036,7 @@ class PartialEvaluator {
       return Promise.resolve(null);
     }
 
-    if ((0, _primitives.isName)(cmapObj)) {
+    if (cmapObj instanceof _primitives.Name) {
       return _cmap.CMapFactory.create({
         encoding: cmapObj,
         fetchBuiltInCMap: this._fetchBuiltInCMapBound,
@@ -3026,7 +3048,7 @@ class PartialEvaluator {
 
         return new _to_unicode_map.ToUnicodeMap(cmap.getMap());
       });
-    } else if ((0, _primitives.isStream)(cmapObj)) {
+    } else if (cmapObj instanceof _base_stream.BaseStream) {
       return _cmap.CMapFactory.create({
         encoding: cmapObj,
         fetchBuiltInCMap: this._fetchBuiltInCMapBound,
@@ -3168,7 +3190,7 @@ class PartialEvaluator {
       } else {
         const baseFontName = dict.get("BaseFont");
 
-        if ((0, _primitives.isName)(baseFontName)) {
+        if (baseFontName instanceof _primitives.Name) {
           const metrics = this.getBaseFontMetrics(baseFontName.name);
           glyphsWidths = this.buildCharCodeToWidth(metrics.widths, properties);
           defaultWidth = metrics.defaultWidth;
@@ -3230,7 +3252,7 @@ class PartialEvaluator {
 
     const glyphWidths = Metrics[lookupName];
 
-    if ((0, _util.isNum)(glyphWidths)) {
+    if (typeof glyphWidths === "number") {
       defaultWidth = glyphWidths;
       monospace = true;
     } else {
@@ -3268,7 +3290,7 @@ class PartialEvaluator {
     const baseDict = dict;
     let type = dict.get("Subtype");
 
-    if (!(0, _primitives.isName)(type)) {
+    if (!(type instanceof _primitives.Name)) {
       throw new _util.FormatError("invalid font Subtype");
     }
 
@@ -3290,7 +3312,7 @@ class PartialEvaluator {
 
       type = dict.get("Subtype");
 
-      if (!(0, _primitives.isName)(type)) {
+      if (!(type instanceof _primitives.Name)) {
         throw new _util.FormatError("invalid font Subtype");
       }
 
@@ -3305,15 +3327,15 @@ class PartialEvaluator {
       hash = new _murmurhash.MurmurHash3_64();
       const encoding = baseDict.getRaw("Encoding");
 
-      if ((0, _primitives.isName)(encoding)) {
+      if (encoding instanceof _primitives.Name) {
         hash.update(encoding.name);
-      } else if ((0, _primitives.isRef)(encoding)) {
+      } else if (encoding instanceof _primitives.Ref) {
         hash.update(encoding.toString());
-      } else if ((0, _primitives.isDict)(encoding)) {
+      } else if (encoding instanceof _primitives.Dict) {
         for (const entry of encoding.getRawValues()) {
-          if ((0, _primitives.isName)(entry)) {
+          if (entry instanceof _primitives.Name) {
             hash.update(entry.name);
-          } else if ((0, _primitives.isRef)(entry)) {
+          } else if (entry instanceof _primitives.Ref) {
             hash.update(entry.toString());
           } else if (Array.isArray(entry)) {
             const diffLength = entry.length,
@@ -3322,9 +3344,9 @@ class PartialEvaluator {
             for (let j = 0; j < diffLength; j++) {
               const diffEntry = entry[j];
 
-              if ((0, _primitives.isName)(diffEntry)) {
+              if (diffEntry instanceof _primitives.Name) {
                 diffBuf[j] = diffEntry.name;
-              } else if ((0, _util.isNum)(diffEntry) || (0, _primitives.isRef)(diffEntry)) {
+              } else if (typeof diffEntry === "number" || diffEntry instanceof _primitives.Ref) {
                 diffBuf[j] = diffEntry.toString();
               }
             }
@@ -3337,11 +3359,11 @@ class PartialEvaluator {
       hash.update(`${firstChar}-${lastChar}`);
       toUnicode = dict.get("ToUnicode") || baseDict.get("ToUnicode");
 
-      if ((0, _primitives.isStream)(toUnicode)) {
+      if (toUnicode instanceof _base_stream.BaseStream) {
         const stream = toUnicode.str || toUnicode;
         const uint8array = stream.buffer ? new Uint8Array(stream.buffer.buffer, 0, stream.bufferLength) : new Uint8Array(stream.bytes.buffer, stream.start, stream.end - stream.start);
         hash.update(uint8array);
-      } else if ((0, _primitives.isName)(toUnicode)) {
+      } else if (toUnicode instanceof _primitives.Name) {
         hash.update(toUnicode.name);
       }
 
@@ -3351,7 +3373,7 @@ class PartialEvaluator {
         const widthsBuf = [];
 
         for (const entry of widths) {
-          if ((0, _util.isNum)(entry) || (0, _primitives.isRef)(entry)) {
+          if (typeof entry === "number" || entry instanceof _primitives.Ref) {
             widthsBuf.push(entry.toString());
           }
         }
@@ -3367,13 +3389,13 @@ class PartialEvaluator {
           const widthsBuf = [];
 
           for (const entry of compositeWidths) {
-            if ((0, _util.isNum)(entry) || (0, _primitives.isRef)(entry)) {
+            if (typeof entry === "number" || entry instanceof _primitives.Ref) {
               widthsBuf.push(entry.toString());
             } else if (Array.isArray(entry)) {
               const subWidthsBuf = [];
 
               for (const element of entry) {
-                if ((0, _util.isNum)(element) || (0, _primitives.isRef)(element)) {
+                if (typeof element === "number" || element instanceof _primitives.Ref) {
                   subWidthsBuf.push(element.toString());
                 }
               }
@@ -3432,7 +3454,7 @@ class PartialEvaluator {
       } else {
         let baseFontName = dict.get("BaseFont");
 
-        if (!(0, _primitives.isName)(baseFontName)) {
+        if (!(baseFontName instanceof _primitives.Name)) {
           throw new _util.FormatError("Base font is not specified");
         }
 
@@ -3488,11 +3510,11 @@ class PartialEvaluator {
     let fontName = descriptor.get("FontName");
     let baseFont = dict.get("BaseFont");
 
-    if ((0, _util.isString)(fontName)) {
+    if (typeof fontName === "string") {
       fontName = _primitives.Name.get(fontName);
     }
 
-    if ((0, _util.isString)(baseFont)) {
+    if (typeof baseFont === "string") {
       baseFont = _primitives.Name.get(baseFont);
     }
 
@@ -3511,7 +3533,7 @@ class PartialEvaluator {
 
     fontName = fontName || baseFont;
 
-    if (!(0, _primitives.isName)(fontName)) {
+    if (!(fontName instanceof _primitives.Name)) {
       throw new _util.FormatError("invalid font name");
     }
 
@@ -3598,7 +3620,7 @@ class PartialEvaluator {
     if (composite) {
       const cidEncoding = baseDict.get("Encoding");
 
-      if ((0, _primitives.isName)(cidEncoding)) {
+      if (cidEncoding instanceof _primitives.Name) {
         properties.cidEncoding = cidEncoding.name;
       }
 
@@ -3710,6 +3732,13 @@ class TranslatedFont {
       ignoreErrors: false
     });
     type3Evaluator.parsingType3Font = true;
+    const type3FontRefs = new _primitives.RefSet(evaluator.type3FontRefs);
+
+    if (this.dict.objId && !type3FontRefs.has(this.dict.objId)) {
+      type3FontRefs.put(this.dict.objId);
+    }
+
+    type3Evaluator.type3FontRefs = type3FontRefs;
     const translatedFont = this.font,
           type3Dependencies = this.type3Dependencies;
     let loadCharProcsPromise = Promise.resolve();
@@ -4314,7 +4343,7 @@ class EvaluatorPreprocessor {
   }
 
   static get MAX_INVALID_PATH_OPS() {
-    return (0, _util.shadow)(this, "MAX_INVALID_PATH_OPS", 20);
+    return (0, _util.shadow)(this, "MAX_INVALID_PATH_OPS", 10);
   }
 
   constructor(stream, xref, stateManager = new StateManager()) {

+ 7 - 5
lib/core/file_spec.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,10 +26,12 @@ Object.defineProperty(exports, "__esModule", {
 });
 exports.FileSpec = void 0;
 
-var _primitives = require("./primitives.js");
-
 var _util = require("../shared/util.js");
 
+var _base_stream = require("./base_stream.js");
+
+var _primitives = require("./primitives.js");
+
 function pickPlatformItem(dict) {
   if (dict.has("UF")) {
     return dict.get("UF");
@@ -48,7 +50,7 @@ function pickPlatformItem(dict) {
 
 class FileSpec {
   constructor(root, xref) {
-    if (!root || !(0, _primitives.isDict)(root)) {
+    if (!(root instanceof _primitives.Dict)) {
       return;
     }
 
@@ -96,7 +98,7 @@ class FileSpec {
     if (this.contentRef) {
       const fileObj = this.xref.fetchIfRef(this.contentRef);
 
-      if (fileObj && (0, _primitives.isStream)(fileObj)) {
+      if (fileObj instanceof _base_stream.BaseStream) {
         content = fileObj.getBytes();
       } else {
         (0, _util.warn)("Embedded file specification points to non-existing/invalid content");

+ 1 - 1
lib/core/flate_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 69 - 48
lib/core/font_renderer.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,14 +36,26 @@ var _encodings = require("./encodings.js");
 
 var _stream = require("./stream.js");
 
-function getLong(data, offset) {
-  return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
+function getUint32(data, offset) {
+  return (data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]) >>> 0;
 }
 
-function getUshort(data, offset) {
+function getUint16(data, offset) {
   return data[offset] << 8 | data[offset + 1];
 }
 
+function getInt16(data, offset) {
+  return (data[offset] << 24 | data[offset + 1] << 16) >> 16;
+}
+
+function getInt8(data, offset) {
+  return data[offset] << 24 >> 24;
+}
+
+function getFloat214(data, offset) {
+  return getInt16(data, offset) / 16384;
+}
+
 function getSubroutineBias(subrs) {
   const numSubrs = subrs.length;
   let bias = 32768;
@@ -58,34 +70,34 @@ function getSubroutineBias(subrs) {
 }
 
 function parseCmap(data, start, end) {
-  const offset = getUshort(data, start + 2) === 1 ? getLong(data, start + 8) : getLong(data, start + 16);
-  const format = getUshort(data, start + offset);
+  const offset = getUint16(data, start + 2) === 1 ? getUint32(data, start + 8) : getUint32(data, start + 16);
+  const format = getUint16(data, start + offset);
   let ranges, p, i;
 
   if (format === 4) {
-    getUshort(data, start + offset + 2);
-    const segCount = getUshort(data, start + offset + 6) >> 1;
+    getUint16(data, start + offset + 2);
+    const segCount = getUint16(data, start + offset + 6) >> 1;
     p = start + offset + 14;
     ranges = [];
 
     for (i = 0; i < segCount; i++, p += 2) {
       ranges[i] = {
-        end: getUshort(data, p)
+        end: getUint16(data, p)
       };
     }
 
     p += 2;
 
     for (i = 0; i < segCount; i++, p += 2) {
-      ranges[i].start = getUshort(data, p);
+      ranges[i].start = getUint16(data, p);
     }
 
     for (i = 0; i < segCount; i++, p += 2) {
-      ranges[i].idDelta = getUshort(data, p);
+      ranges[i].idDelta = getUint16(data, p);
     }
 
     for (i = 0; i < segCount; i++, p += 2) {
-      let idOffset = getUshort(data, p);
+      let idOffset = getUint16(data, p);
 
       if (idOffset === 0) {
         continue;
@@ -94,23 +106,23 @@ function parseCmap(data, start, end) {
       ranges[i].ids = [];
 
       for (let j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) {
-        ranges[i].ids[j] = getUshort(data, p + idOffset);
+        ranges[i].ids[j] = getUint16(data, p + idOffset);
         idOffset += 2;
       }
     }
 
     return ranges;
   } else if (format === 12) {
-    getLong(data, start + offset + 4);
-    const groups = getLong(data, start + offset + 12);
+    const groups = getUint32(data, start + offset + 12);
     p = start + offset + 16;
     ranges = [];
 
     for (i = 0; i < groups; i++) {
+      start = getUint32(data, p);
       ranges.push({
-        start: getLong(data, p),
-        end: getLong(data, p + 4),
-        idDelta: getLong(data, p + 8) - getLong(data, p)
+        start,
+        end: getUint32(data, p + 4),
+        idDelta: getUint32(data, p + 8) - start
       });
       p += 12;
     }
@@ -140,16 +152,11 @@ function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {
 
   if (isGlyphLocationsLong) {
     itemSize = 4;
-
-    itemDecode = function fontItemDecodeLong(data, offset) {
-      return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
-    };
+    itemDecode = getUint32;
   } else {
     itemSize = 2;
 
-    itemDecode = function fontItemDecode(data, offset) {
-      return data[offset] << 9 | data[offset + 1] << 1;
-    };
+    itemDecode = (data, offset) => 2 * getUint16(data, offset);
   }
 
   const glyphs = [];
@@ -213,7 +220,7 @@ function compileGlyf(code, cmds, font) {
   }
 
   let i = 0;
-  const numberOfContours = (code[i] << 24 | code[i + 1] << 16) >> 16;
+  const numberOfContours = getInt16(code, i);
   let flags;
   let x = 0,
       y = 0;
@@ -221,18 +228,29 @@ function compileGlyf(code, cmds, font) {
 
   if (numberOfContours < 0) {
     do {
-      flags = code[i] << 8 | code[i + 1];
-      const glyphIndex = code[i + 2] << 8 | code[i + 3];
+      flags = getUint16(code, i);
+      const glyphIndex = getUint16(code, i + 2);
       i += 4;
       let arg1, arg2;
 
       if (flags & 0x01) {
-        arg1 = (code[i] << 24 | code[i + 1] << 16) >> 16;
-        arg2 = (code[i + 2] << 24 | code[i + 3] << 16) >> 16;
+        if (flags & 0x02) {
+          arg1 = getInt16(code, i);
+          arg2 = getInt16(code, i + 2);
+        } else {
+          arg1 = getUint16(code, i);
+          arg2 = getUint16(code, i + 2);
+        }
+
         i += 4;
       } else {
-        arg1 = code[i++];
-        arg2 = code[i++];
+        if (flags & 0x02) {
+          arg1 = getInt8(code, i++);
+          arg2 = getInt8(code, i++);
+        } else {
+          arg1 = code[i++];
+          arg2 = code[i++];
+        }
       }
 
       if (flags & 0x02) {
@@ -249,17 +267,17 @@ function compileGlyf(code, cmds, font) {
           scale10 = 0;
 
       if (flags & 0x08) {
-        scaleX = scaleY = (code[i] << 24 | code[i + 1] << 16) / 1073741824;
+        scaleX = scaleY = getFloat214(code, i);
         i += 2;
       } else if (flags & 0x40) {
-        scaleX = (code[i] << 24 | code[i + 1] << 16) / 1073741824;
-        scaleY = (code[i + 2] << 24 | code[i + 3] << 16) / 1073741824;
+        scaleX = getFloat214(code, i);
+        scaleY = getFloat214(code, i + 2);
         i += 4;
       } else if (flags & 0x80) {
-        scaleX = (code[i] << 24 | code[i + 1] << 16) / 1073741824;
-        scale01 = (code[i + 2] << 24 | code[i + 3] << 16) / 1073741824;
-        scale10 = (code[i + 4] << 24 | code[i + 5] << 16) / 1073741824;
-        scaleY = (code[i + 6] << 24 | code[i + 7] << 16) / 1073741824;
+        scaleX = getFloat214(code, i);
+        scale01 = getFloat214(code, i + 2);
+        scale10 = getFloat214(code, i + 4);
+        scaleY = getFloat214(code, i + 6);
         i += 8;
       }
 
@@ -272,6 +290,9 @@ function compileGlyf(code, cmds, font) {
           cmd: "transform",
           args: [scaleX, scale01, scale10, scaleY, x, y]
         });
+
+        if (!(flags & 0x02)) {}
+
         compileGlyf(subglyph, cmds, font);
         cmds.push({
           cmd: "restore"
@@ -283,11 +304,11 @@ function compileGlyf(code, cmds, font) {
     let j, jj;
 
     for (j = 0; j < numberOfContours; j++) {
-      endPtsOfContours.push(code[i] << 8 | code[i + 1]);
+      endPtsOfContours.push(getUint16(code, i));
       i += 2;
     }
 
-    const instructionLength = code[i] << 8 | code[i + 1];
+    const instructionLength = getUint16(code, i);
     i += 2 + instructionLength;
     const numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;
     const points = [];
@@ -310,7 +331,7 @@ function compileGlyf(code, cmds, font) {
     for (j = 0; j < numberOfPoints; j++) {
       switch (points[j].flags & 0x12) {
         case 0x00:
-          x += (code[i] << 24 | code[i + 1] << 16) >> 16;
+          x += getInt16(code, i);
           i += 2;
           break;
 
@@ -329,7 +350,7 @@ function compileGlyf(code, cmds, font) {
     for (j = 0; j < numberOfPoints; j++) {
       switch (points[j].flags & 0x24) {
         case 0x00:
-          y += (code[i] << 24 | code[i + 1] << 16) >> 16;
+          y += getInt16(code, i);
           i += 2;
           break;
 
@@ -947,12 +968,12 @@ class FontRendererFactory {
   static create(font, seacAnalysisEnabled) {
     const data = new Uint8Array(font.data);
     let cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
-    const numTables = getUshort(data, 4);
+    const numTables = getUint16(data, 4);
 
     for (let i = 0, p = 12; i < numTables; i++, p += 16) {
       const tag = (0, _util.bytesToString)(data.subarray(p, p + 4));
-      const offset = getLong(data, p + 8);
-      const length = getLong(data, p + 12);
+      const offset = getUint32(data, p + 8);
+      const length = getUint32(data, p + 12);
 
       switch (tag) {
         case "cmap":
@@ -968,8 +989,8 @@ class FontRendererFactory {
           break;
 
         case "head":
-          unitsPerEm = getUshort(data, offset + 18);
-          indexToLocFormat = getUshort(data, offset + 50);
+          unitsPerEm = getUint16(data, offset + 18);
+          indexToLocFormat = getUint16(data, offset + 50);
           break;
 
         case "CFF ":

+ 31 - 4
lib/core/fonts.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,20 +32,22 @@ var _cff_parser = require("./cff_parser.js");
 
 var _fonts_utils = require("./fonts_utils.js");
 
+var _unicode = require("./unicode.js");
+
 var _glyphlist = require("./glyphlist.js");
 
 var _encodings = require("./encodings.js");
 
 var _standard_fonts = require("./standard_fonts.js");
 
-var _unicode = require("./unicode.js");
-
 var _to_unicode_map = require("./to_unicode_map.js");
 
 var _cff_font = require("./cff_font.js");
 
 var _font_renderer = require("./font_renderer.js");
 
+var _metrics = require("./metrics.js");
+
 var _glyf = require("./glyf.js");
 
 var _cmap = require("./cmap.js");
@@ -157,6 +159,10 @@ class Glyph {
     this.operatorListId = operatorListId;
     this.isSpace = isSpace;
     this.isInFont = isInFont;
+    const category = (0, _unicode.getCharUnicodeCategory)(unicode);
+    this.isWhitespace = category.isWhitespace;
+    this.isZeroWidthDiacritic = category.isZeroWidthDiacritic;
+    this.isInvisibleFormatMark = category.isInvisibleFormatMark;
   }
 
   matchesForCache(originalCharCode, fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont) {
@@ -835,6 +841,23 @@ class Font {
     const isStandardFont = !!stdFontMap[fontName];
     const isMappedToStandardFont = !!(nonStdFontMap[fontName] && stdFontMap[nonStdFontMap[fontName]]);
     fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;
+    const fontBasicMetricsMap = (0, _metrics.getFontBasicMetrics)();
+    const metrics = fontBasicMetricsMap[fontName];
+
+    if (metrics) {
+      if (isNaN(this.ascent)) {
+        this.ascent = metrics.ascent / PDF_GLYPH_SPACE_UNITS;
+      }
+
+      if (isNaN(this.descent)) {
+        this.descent = metrics.descent / PDF_GLYPH_SPACE_UNITS;
+      }
+
+      if (isNaN(this.capHeight)) {
+        this.capHeight = metrics.capHeight / PDF_GLYPH_SPACE_UNITS;
+      }
+    }
+
     this.bold = fontName.search(/bold/gi) !== -1;
     this.italic = fontName.search(/oblique/gi) !== -1 || fontName.search(/italic/gi) !== -1;
     this.black = name.search(/Black/g) !== -1;
@@ -2662,7 +2685,11 @@ class Font {
     }
 
     width = this.widths[widthCode];
-    width = (0, _util.isNum)(width) ? width : this.defaultWidth;
+
+    if (typeof width !== "number") {
+      width = this.defaultWidth;
+    }
+
     const vmetric = this.vmetrics && this.vmetrics[widthCode];
     let unicode = this.toUnicode.get(charcode) || charcode;
 

+ 1 - 1
lib/core/fonts_utils.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 11 - 9
lib/core/function.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,6 +33,8 @@ var _util = require("../shared/util.js");
 
 var _ps_parser = require("./ps_parser.js");
 
+var _base_stream = require("./base_stream.js");
+
 var _image_utils = require("./image_utils.js");
 
 class PDFFunctionFactory {
@@ -87,7 +89,7 @@ class PDFFunctionFactory {
       fnRef = cacheKey;
     } else if (cacheKey instanceof _primitives.Dict) {
       fnRef = cacheKey.objId;
-    } else if ((0, _primitives.isStream)(cacheKey)) {
+    } else if (cacheKey instanceof _base_stream.BaseStream) {
       fnRef = cacheKey.dict && cacheKey.dict.objId;
     }
 
@@ -113,7 +115,7 @@ class PDFFunctionFactory {
       fnRef = cacheKey;
     } else if (cacheKey instanceof _primitives.Dict) {
       fnRef = cacheKey.objId;
-    } else if ((0, _primitives.isStream)(cacheKey)) {
+    } else if (cacheKey instanceof _base_stream.BaseStream) {
       fnRef = cacheKey.dict && cacheKey.dict.objId;
     }
 
@@ -562,9 +564,9 @@ function isPDFFunction(v) {
 
   if (typeof v !== "object") {
     return false;
-  } else if ((0, _primitives.isDict)(v)) {
+  } else if (v instanceof _primitives.Dict) {
     fnDict = v;
-  } else if ((0, _primitives.isStream)(v)) {
+  } else if (v instanceof _base_stream.BaseStream) {
     fnDict = v.dict;
   } else {
     return false;
@@ -692,7 +694,7 @@ class PostScriptEvaluator {
           b = stack.pop();
           a = stack.pop();
 
-          if ((0, _util.isBool)(a) && (0, _util.isBool)(b)) {
+          if (typeof a === "boolean" && typeof b === "boolean") {
             stack.push(a && b);
           } else {
             stack.push(a & b);
@@ -846,7 +848,7 @@ class PostScriptEvaluator {
         case "not":
           a = stack.pop();
 
-          if ((0, _util.isBool)(a)) {
+          if (typeof a === "boolean") {
             stack.push(!a);
           } else {
             stack.push(~a);
@@ -858,7 +860,7 @@ class PostScriptEvaluator {
           b = stack.pop();
           a = stack.pop();
 
-          if ((0, _util.isBool)(a) && (0, _util.isBool)(b)) {
+          if (typeof a === "boolean" && typeof b === "boolean") {
             stack.push(a || b);
           } else {
             stack.push(a | b);
@@ -911,7 +913,7 @@ class PostScriptEvaluator {
           b = stack.pop();
           a = stack.pop();
 
-          if ((0, _util.isBool)(a) && (0, _util.isBool)(b)) {
+          if (typeof a === "boolean" && typeof b === "boolean") {
             stack.push(a !== b);
           } else {
             stack.push(a ^ b);

+ 6 - 8
lib/core/glyf.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -556,14 +556,12 @@ class CompositeGlyph {
       pos += 4;
       flags ^= ARG_1_AND_2_ARE_WORDS;
     } else {
-      argument1 = glyf.getUint8(pos);
-      argument2 = glyf.getUint8(pos + 1);
-
       if (flags & ARGS_ARE_XY_VALUES) {
-        const abs1 = argument1 & 0x7f;
-        argument1 = argument1 & 0x80 ? -abs1 : abs1;
-        const abs2 = argument2 & 0x7f;
-        argument2 = argument2 & 0x80 ? -abs2 : abs2;
+        argument1 = glyf.getInt8(pos);
+        argument2 = glyf.getInt8(pos + 1);
+      } else {
+        argument1 = glyf.getUint8(pos);
+        argument2 = glyf.getUint8(pos + 1);
       }
 
       pos += 2;

+ 1 - 1
lib/core/glyphlist.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/helvetica_factors.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 7 - 5
lib/core/image.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ exports.PDFImage = void 0;
 
 var _util = require("../shared/util.js");
 
-var _primitives = require("./primitives.js");
+var _base_stream = require("./base_stream.js");
 
 var _colorspace = require("./colorspace.js");
 
@@ -38,6 +38,8 @@ var _jpeg_stream = require("./jpeg_stream.js");
 
 var _jpx = require("./jpx.js");
 
+var _primitives = require("./primitives.js");
+
 function decodeAndClamp(value, addend, coefficient, max) {
   value = addend + value * coefficient;
 
@@ -104,7 +106,7 @@ class PDFImage {
     const dict = image.dict;
     const filter = dict.get("F", "Filter");
 
-    if ((0, _primitives.isName)(filter)) {
+    if (filter instanceof _primitives.Name) {
       switch (filter.name) {
         case "JPXDecode":
           const jpxImage = new _jpx.JpxImage();
@@ -219,7 +221,7 @@ class PDFImage {
         localColorSpaceCache
       });
     } else if (mask) {
-      if ((0, _primitives.isStream)(mask)) {
+      if (mask instanceof _base_stream.BaseStream) {
         const maskDict = mask.dict,
               imageMask = maskDict.get("IM", "ImageMask");
 
@@ -259,7 +261,7 @@ class PDFImage {
     if (smask) {
       smaskData = smask;
     } else if (mask) {
-      if ((0, _primitives.isStream)(mask) || Array.isArray(mask)) {
+      if (mask instanceof _base_stream.BaseStream || Array.isArray(mask)) {
         maskData = mask;
       } else {
         (0, _util.warn)("Unsupported mask format.");

+ 1 - 1
lib/core/image_utils.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/jbig2.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 6 - 4
lib/core/jbig2_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,10 +26,12 @@ Object.defineProperty(exports, "__esModule", {
 });
 exports.Jbig2Stream = void 0;
 
-var _primitives = require("./primitives.js");
+var _base_stream = require("./base_stream.js");
 
 var _decode_stream = require("./decode_stream.js");
 
+var _primitives = require("./primitives.js");
+
 var _jbig = require("./jbig2.js");
 
 var _util = require("../shared/util.js");
@@ -57,10 +59,10 @@ class Jbig2Stream extends _decode_stream.DecodeStream {
     const jbig2Image = new _jbig.Jbig2Image();
     const chunks = [];
 
-    if ((0, _primitives.isDict)(this.params)) {
+    if (this.params instanceof _primitives.Dict) {
       const globalsStream = this.params.get("JBIG2Globals");
 
-      if ((0, _primitives.isStream)(globalsStream)) {
+      if (globalsStream instanceof _base_stream.BaseStream) {
         const globals = globalsStream.getBytes();
         chunks.push({
           data: globals,

+ 2 - 2
lib/core/jpeg_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -90,7 +90,7 @@ class JpegStream extends _decode_stream.DecodeStream {
       }
     }
 
-    if ((0, _primitives.isDict)(this.params)) {
+    if (this.params instanceof _primitives.Dict) {
       const colorTransform = this.params.get("ColorTransform");
 
       if (Number.isInteger(colorTransform)) {

+ 1 - 1
lib/core/jpg.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 8 - 7
lib/core/jpx.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -396,10 +396,6 @@ class JpxImage {
               unsupported.push("selectiveArithmeticCodingBypass");
             }
 
-            if (cod.resetContextProbabilities) {
-              unsupported.push("resetContextProbabilities");
-            }
-
             if (cod.terminationOnEachCodingPass) {
               unsupported.push("terminationOnEachCodingPass");
             }
@@ -1344,7 +1340,7 @@ function parseTilePackets(context, data, offset, dataLength) {
   return position;
 }
 
-function copyCoefficients(coefficients, levelWidth, levelHeight, subband, delta, mb, reversible, segmentationSymbolUsed) {
+function copyCoefficients(coefficients, levelWidth, levelHeight, subband, delta, mb, reversible, segmentationSymbolUsed, resetContextProbabilities) {
   const x0 = subband.tbx0;
   const y0 = subband.tby0;
   const width = subband.tbx1 - subband.tbx0;
@@ -1411,6 +1407,10 @@ function copyCoefficients(coefficients, levelWidth, levelHeight, subband, delta,
           break;
       }
 
+      if (resetContextProbabilities) {
+        bitModel.reset();
+      }
+
       currentCodingpassType = (currentCodingpassType + 1) % 3;
     }
 
@@ -1465,6 +1465,7 @@ function transformTile(context, tile, c) {
   const scalarExpounded = quantizationParameters.scalarExpounded;
   const guardBits = quantizationParameters.guardBits;
   const segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed;
+  const resetContextProbabilities = codingStyleParameters.resetContextProbabilities;
   const precision = context.components[c].precision;
   const reversible = codingStyleParameters.reversibleTransformation;
   const transform = reversible ? new ReversibleTransform() : new IrreversibleTransform();
@@ -1493,7 +1494,7 @@ function transformTile(context, tile, c) {
       const gainLog2 = SubbandsGainLog2[subband.type];
       const delta = reversible ? 1 : 2 ** (precision + gainLog2 - epsilon) * (1 + mu / 2048);
       const mb = guardBits + epsilon - 1;
-      copyCoefficients(coefficients, width, height, subband, delta, mb, reversible, segmentationSymbolUsed);
+      copyCoefficients(coefficients, width, height, subband, delta, mb, reversible, segmentationSymbolUsed, resetContextProbabilities);
     }
 
     subbandCoefficients.push({

+ 1 - 1
lib/core/jpx_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/liberationsans_widths.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/lzw_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/metadata_parser.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 90 - 3
lib/core/metrics.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.getMetrics = void 0;
+exports.getMetrics = exports.getFontBasicMetrics = void 0;
 
 var _core_utils = require("./core_utils.js");
 
@@ -2966,4 +2966,91 @@ const getMetrics = (0, _core_utils.getLookupTableFactory)(function (t) {
     t.a191 = 918;
   });
 });
-exports.getMetrics = getMetrics;
+exports.getMetrics = getMetrics;
+const getFontBasicMetrics = (0, _core_utils.getLookupTableFactory)(function (t) {
+  t.Courier = {
+    ascent: 629,
+    descent: -157,
+    capHeight: 562,
+    xHeight: -426
+  };
+  t["Courier-Bold"] = {
+    ascent: 629,
+    descent: -157,
+    capHeight: 562,
+    xHeight: 439
+  };
+  t["Courier-Oblique"] = {
+    ascent: 629,
+    descent: -157,
+    capHeight: 562,
+    xHeight: 426
+  };
+  t["Courier-BoldOblique"] = {
+    ascent: 629,
+    descent: -157,
+    capHeight: 562,
+    xHeight: 426
+  };
+  t.Helvetica = {
+    ascent: 718,
+    descent: -207,
+    capHeight: 718,
+    xHeight: 523
+  };
+  t["Helvetica-Bold"] = {
+    ascent: 718,
+    descent: -207,
+    capHeight: 718,
+    xHeight: 532
+  };
+  t["Helvetica-Oblique"] = {
+    ascent: 718,
+    descent: -207,
+    capHeight: 718,
+    xHeight: 523
+  };
+  t["Helvetica-BoldOblique"] = {
+    ascent: 718,
+    descent: -207,
+    capHeight: 718,
+    xHeight: 532
+  };
+  t["Times-Roman"] = {
+    ascent: 683,
+    descent: -217,
+    capHeight: 662,
+    xHeight: 450
+  };
+  t["Times-Bold"] = {
+    ascent: 683,
+    descent: -217,
+    capHeight: 676,
+    xHeight: 461
+  };
+  t["Times-Italic"] = {
+    ascent: 683,
+    descent: -217,
+    capHeight: 653,
+    xHeight: 441
+  };
+  t["Times-BoldItalic"] = {
+    ascent: 683,
+    descent: -217,
+    capHeight: 669,
+    xHeight: 462
+  };
+  t.Symbol = {
+    ascent: Math.NaN,
+    descent: Math.NaN,
+    capHeight: Math.NaN,
+    xHeight: Math.NaN
+  };
+  t.ZapfDingbats = {
+    ascent: Math.NaN,
+    descent: Math.NaN,
+    capHeight: Math.NaN,
+    xHeight: Math.NaN
+  };
+});
+exports.getFontBasicMetrics = getFontBasicMetrics;

+ 2 - 2
lib/core/murmurhash3.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@ class MurmurHash3_64 {
   update(input) {
     let data, length;
 
-    if ((0, _util.isString)(input)) {
+    if (typeof input === "string") {
       data = new Uint8Array(input.length * 2);
       length = 0;
 

+ 1 - 1
lib/core/myriadpro_factors.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 4 - 4
lib/core/name_number_tree.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,10 +26,10 @@ Object.defineProperty(exports, "__esModule", {
 });
 exports.NumberTree = exports.NameTree = void 0;
 
-var _util = require("../shared/util.js");
-
 var _primitives = require("./primitives.js");
 
+var _util = require("../shared/util.js");
+
 class NameOrNumberTree {
   constructor(root, xref, type) {
     if (this.constructor === NameOrNumberTree) {
@@ -56,7 +56,7 @@ class NameOrNumberTree {
     while (queue.length > 0) {
       const obj = xref.fetchIfRef(queue.shift());
 
-      if (!(0, _primitives.isDict)(obj)) {
+      if (!(obj instanceof _primitives.Dict)) {
         continue;
       }
 

+ 6 - 4
lib/core/object_loader.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,18 +28,20 @@ exports.ObjectLoader = void 0;
 
 var _primitives = require("./primitives.js");
 
+var _base_stream = require("./base_stream.js");
+
 var _core_utils = require("./core_utils.js");
 
 var _util = require("../shared/util.js");
 
 function mayHaveChildren(value) {
-  return value instanceof _primitives.Ref || value instanceof _primitives.Dict || Array.isArray(value) || (0, _primitives.isStream)(value);
+  return value instanceof _primitives.Ref || value instanceof _primitives.Dict || value instanceof _base_stream.BaseStream || Array.isArray(value);
 }
 
 function addChildren(node, nodesToVisit) {
   if (node instanceof _primitives.Dict) {
     node = node.getRawValues();
-  } else if ((0, _primitives.isStream)(node)) {
+  } else if (node instanceof _base_stream.BaseStream) {
     node = node.dict.getRawValues();
   } else if (!Array.isArray(node)) {
     return;
@@ -116,7 +118,7 @@ class ObjectLoader {
         }
       }
 
-      if ((0, _primitives.isStream)(currentNode)) {
+      if (currentNode instanceof _base_stream.BaseStream) {
         const baseStreams = currentNode.getBaseStreams();
 
         if (baseStreams) {

+ 1 - 1
lib/core/opentype_file_builder.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/operator_list.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 18 - 11
lib/core/parser.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -144,7 +144,7 @@ class Parser {
           const dict = new _primitives.Dict(this.xref);
 
           while (!(0, _primitives.isCmd)(this.buf1, ">>") && this.buf1 !== _primitives.EOF) {
-            if (!(0, _primitives.isName)(this.buf1)) {
+            if (!(this.buf1 instanceof _primitives.Name)) {
               (0, _util.info)("Malformed dictionary: key must be a name object");
               this.shift();
               continue;
@@ -465,7 +465,7 @@ class Parser {
     let dictLength;
 
     while (!(0, _primitives.isCmd)(this.buf1, "ID") && this.buf1 !== _primitives.EOF) {
-      if (!(0, _primitives.isName)(this.buf1)) {
+      if (!(this.buf1 instanceof _primitives.Name)) {
         throw new _util.FormatError("Dictionary key must be a name object");
       }
 
@@ -486,12 +486,12 @@ class Parser {
     const filter = dict.get("F", "Filter");
     let filterName;
 
-    if ((0, _primitives.isName)(filter)) {
+    if (filter instanceof _primitives.Name) {
       filterName = filter.name;
     } else if (Array.isArray(filter)) {
       const filterZero = this.xref.fetchIfRef(filter[0]);
 
-      if ((0, _primitives.isName)(filterZero)) {
+      if (filterZero instanceof _primitives.Name) {
         filterName = filterZero.name;
       }
     }
@@ -667,7 +667,7 @@ class Parser {
     let filter = dict.get("F", "Filter");
     let params = dict.get("DP", "DecodeParms");
 
-    if ((0, _primitives.isName)(filter)) {
+    if (filter instanceof _primitives.Name) {
       if (Array.isArray(params)) {
         (0, _util.warn)("/DecodeParms should not be an Array, when /Filter is a Name.");
       }
@@ -684,7 +684,7 @@ class Parser {
       for (let i = 0, ii = filterArray.length; i < ii; ++i) {
         filter = this.xref.fetchIfRef(filterArray[i]);
 
-        if (!(0, _primitives.isName)(filter)) {
+        if (!(filter instanceof _primitives.Name)) {
           throw new _util.FormatError(`Bad filter name "${filter}"`);
         }
 
@@ -849,9 +849,16 @@ class Lexer {
     }
 
     if (ch < 0x30 || ch > 0x39) {
-      if (divideBy === 10 && sign === 0 && ((0, _core_utils.isWhiteSpace)(ch) || ch === -1)) {
-        (0, _util.warn)("Lexer.getNumber - treating a single decimal point as zero.");
-        return 0;
+      if ((0, _core_utils.isWhiteSpace)(ch) || ch === -1) {
+        if (divideBy === 10 && sign === 0) {
+          (0, _util.warn)("Lexer.getNumber - treating a single decimal point as zero.");
+          return 0;
+        }
+
+        if (divideBy === 0 && sign === -1) {
+          (0, _util.warn)("Lexer.getNumber - treating a single minus sign as zero.");
+          return 0;
+        }
       }
 
       throw new _util.FormatError(`Invalid number: ${String.fromCharCode(ch)} (charCode ${ch})`);
@@ -1370,7 +1377,7 @@ class Linearization {
     const linDict = parser.getObj();
     let obj, length;
 
-    if (!(Number.isInteger(obj1) && Number.isInteger(obj2) && (0, _primitives.isCmd)(obj3, "obj") && (0, _primitives.isDict)(linDict) && (0, _util.isNum)(obj = linDict.get("Linearized")) && obj > 0)) {
+    if (!(Number.isInteger(obj1) && Number.isInteger(obj2) && (0, _primitives.isCmd)(obj3, "obj") && linDict instanceof _primitives.Dict && typeof (obj = linDict.get("Linearized")) === "number" && obj > 0)) {
       return null;
     } else if ((length = getInt(linDict, "L")) !== stream.length) {
       throw new Error('The "L" parameter in the linearization dictionary ' + "does not equal the stream length.");

+ 5 - 5
lib/core/pattern.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,9 +29,9 @@ exports.getTilingPatternIR = getTilingPatternIR;
 
 var _util = require("../shared/util.js");
 
-var _colorspace = require("./colorspace.js");
+var _base_stream = require("./base_stream.js");
 
-var _primitives = require("./primitives.js");
+var _colorspace = require("./colorspace.js");
 
 var _core_utils = require("./core_utils.js");
 
@@ -51,7 +51,7 @@ class Pattern {
   }
 
   static parseShading(shading, xref, res, handler, pdfFunctionFactory, localColorSpaceCache) {
-    const dict = (0, _primitives.isStream)(shading) ? shading.dict : shading;
+    const dict = shading instanceof _base_stream.BaseStream ? shading.dict : shading;
     const type = dict.get("ShadingType");
 
     try {
@@ -367,7 +367,7 @@ class MeshShading extends BaseShading {
   constructor(stream, xref, resources, pdfFunctionFactory, localColorSpaceCache) {
     super();
 
-    if (!(0, _primitives.isStream)(stream)) {
+    if (!(stream instanceof _base_stream.BaseStream)) {
       throw new _util.FormatError("Mesh data is not a stream");
     }
 

+ 1 - 1
lib/core/pdf_manager.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 4 - 4
lib/core/predictor_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -28,15 +28,15 @@ exports.PredictorStream = void 0;
 
 var _decode_stream = require("./decode_stream.js");
 
-var _util = require("../shared/util.js");
-
 var _primitives = require("./primitives.js");
 
+var _util = require("../shared/util.js");
+
 class PredictorStream extends _decode_stream.DecodeStream {
   constructor(str, maybeLength, params) {
     super(maybeLength);
 
-    if (!(0, _primitives.isDict)(params)) {
+    if (!(params instanceof _primitives.Dict)) {
       return str;
     }
 

+ 1 - 13
lib/core/primitives.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,14 +29,10 @@ exports.clearPrimitiveCaches = clearPrimitiveCaches;
 exports.isCmd = isCmd;
 exports.isDict = isDict;
 exports.isName = isName;
-exports.isRef = isRef;
 exports.isRefsEqual = isRefsEqual;
-exports.isStream = isStream;
 
 var _util = require("../shared/util.js");
 
-var _base_stream = require("./base_stream.js");
-
 const CIRCULAR_REF = Symbol("CIRCULAR_REF");
 exports.CIRCULAR_REF = CIRCULAR_REF;
 const EOF = Symbol("EOF");
@@ -383,18 +379,10 @@ function isDict(v, type) {
   return v instanceof Dict && (type === undefined || isName(v.get("Type"), type));
 }
 
-function isRef(v) {
-  return v instanceof Ref;
-}
-
 function isRefsEqual(v1, v2) {
   return v1.num === v2.num && v1.gen === v2.gen;
 }
 
-function isStream(v) {
-  return v instanceof _base_stream.BaseStream;
-}
-
 function clearPrimitiveCaches() {
   Cmd._clearCache();
 

+ 1 - 1
lib/core/ps_parser.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/run_length_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/segoeui_factors.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/standard_fonts.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 15 - 15
lib/core/struct_tree.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -53,12 +53,12 @@ class StructTreeRoot {
   readRoleMap() {
     const roleMapDict = this.dict.get("RoleMap");
 
-    if (!(0, _primitives.isDict)(roleMapDict)) {
+    if (!(roleMapDict instanceof _primitives.Dict)) {
       return;
     }
 
     roleMapDict.forEach((key, value) => {
-      if (!(0, _primitives.isName)(value)) {
+      if (!(value instanceof _primitives.Name)) {
         return;
       }
 
@@ -80,7 +80,7 @@ class StructElementNode {
 
   get role() {
     const nameObj = this.dict.get("S");
-    const name = (0, _primitives.isName)(nameObj) ? nameObj.name : "";
+    const name = nameObj instanceof _primitives.Name ? nameObj.name : "";
     const {
       root
     } = this.tree;
@@ -96,7 +96,7 @@ class StructElementNode {
     let pageObjId = null;
     const objRef = this.dict.getRaw("Pg");
 
-    if ((0, _primitives.isRef)(objRef)) {
+    if (objRef instanceof _primitives.Ref) {
       pageObjId = objRef.toString();
     }
 
@@ -134,9 +134,9 @@ class StructElementNode {
 
     let kidDict = null;
 
-    if ((0, _primitives.isRef)(kid)) {
+    if (kid instanceof _primitives.Ref) {
       kidDict = this.dict.xref.fetch(kid);
-    } else if ((0, _primitives.isDict)(kid)) {
+    } else if (kid instanceof _primitives.Dict) {
       kidDict = kid;
     }
 
@@ -146,11 +146,11 @@ class StructElementNode {
 
     const pageRef = kidDict.getRaw("Pg");
 
-    if ((0, _primitives.isRef)(pageRef)) {
+    if (pageRef instanceof _primitives.Ref) {
       pageObjId = pageRef.toString();
     }
 
-    const type = (0, _primitives.isName)(kidDict.get("Type")) ? kidDict.get("Type").name : null;
+    const type = kidDict.get("Type") instanceof _primitives.Name ? kidDict.get("Type").name : null;
 
     if (type === "MCR") {
       if (this.tree.pageDict.objId !== pageObjId) {
@@ -159,7 +159,7 @@ class StructElementNode {
 
       return new StructElement({
         type: StructElementType.STREAM_CONTENT,
-        refObjId: (0, _primitives.isRef)(kidDict.getRaw("Stm")) ? kidDict.getRaw("Stm").toString() : null,
+        refObjId: kidDict.getRaw("Stm") instanceof _primitives.Ref ? kidDict.getRaw("Stm").toString() : null,
         pageObjId,
         mcid: kidDict.get("MCID")
       });
@@ -172,7 +172,7 @@ class StructElementNode {
 
       return new StructElement({
         type: StructElementType.OBJECT,
-        refObjId: (0, _primitives.isRef)(kidDict.getRaw("Obj")) ? kidDict.getRaw("Obj").toString() : null,
+        refObjId: kidDict.getRaw("Obj") instanceof _primitives.Ref ? kidDict.getRaw("Obj").toString() : null,
         pageObjId
       });
     }
@@ -238,7 +238,7 @@ class StructTreePage {
     const map = new Map();
 
     for (const ref of parentArray) {
-      if ((0, _primitives.isRef)(ref)) {
+      if (ref instanceof _primitives.Ref) {
         this.addNode(this.rootDict.xref.fetch(ref), map);
       }
     }
@@ -295,7 +295,7 @@ class StructTreePage {
       return false;
     }
 
-    if ((0, _primitives.isDict)(obj)) {
+    if (obj instanceof _primitives.Dict) {
       if (obj.objId !== dict.objId) {
         return false;
       }
@@ -335,13 +335,13 @@ class StructTreePage {
       parent.children.push(obj);
       const alt = node.dict.get("Alt");
 
-      if ((0, _util.isString)(alt)) {
+      if (typeof alt === "string") {
         obj.alt = (0, _util.stringToPDFString)(alt);
       }
 
       const lang = node.dict.get("Lang");
 
-      if ((0, _util.isString)(lang)) {
+      if (typeof lang === "string") {
         obj.lang = (0, _util.stringToPDFString)(lang);
       }
 

+ 1 - 1
lib/core/to_unicode_map.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 1 - 1
lib/core/type1_font.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 8 - 1
lib/core/type1_parser.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -465,6 +465,11 @@ const Type1Parser = function Type1ParserClosure() {
       return this.currentChar = this.stream.getByte();
     }
 
+    prevChar() {
+      this.stream.skip(-2);
+      return this.currentChar = this.stream.getByte();
+    }
+
     getToken() {
       let comment = false;
       let ch = this.currentChar;
@@ -561,6 +566,8 @@ const Type1Parser = function Type1ParserClosure() {
 
               if (token === "noaccess") {
                 this.getToken();
+              } else if (token === "/") {
+                this.prevChar();
               }
 
               charstrings.push({

+ 27 - 1
lib/core/unicode.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
+exports.clearUnicodeCaches = clearUnicodeCaches;
+exports.getCharUnicodeCategory = getCharUnicodeCategory;
 exports.getNormalizedUnicodes = void 0;
 exports.getUnicodeForGlyph = getUnicodeForGlyph;
 exports.getUnicodeRangeFor = getUnicodeRangeFor;
@@ -524,4 +526,28 @@ function reverseIfRtl(chars) {
   }
 
   return buf.join("");
+}
+
+const SpecialCharRegExp = new RegExp("^(\\s)|(\\p{Mn})|(\\p{Cf})$", "u");
+const CategoryCache = new Map();
+
+function getCharUnicodeCategory(char) {
+  const cachedCategory = CategoryCache.get(char);
+
+  if (cachedCategory) {
+    return cachedCategory;
+  }
+
+  const groups = char.match(SpecialCharRegExp);
+  const category = {
+    isWhitespace: !!(groups && groups[1]),
+    isZeroWidthDiacritic: !!(groups && groups[2]),
+    isInvisibleFormatMark: !!(groups && groups[3])
+  };
+  CategoryCache.set(char, category);
+  return category;
+}
+
+function clearUnicodeCaches() {
+  CategoryCache.clear();
 }

+ 15 - 10
lib/core/worker.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +32,8 @@ var _primitives = require("./primitives.js");
 
 var _pdf_manager = require("./pdf_manager.js");
 
+var _cleanup_helper = require("./cleanup_helper.js");
+
 var _writer = require("./writer.js");
 
 var _is_node = require("../shared/is_node.js");
@@ -97,7 +99,7 @@ class WorkerMessageHandler {
     const WorkerTasks = [];
     const verbosity = (0, _util.getVerbosityLevel)();
     const apiVersion = docParams.apiVersion;
-    const workerVersion = '2.12.313';
+    const workerVersion = '2.13.216';
 
     if (apiVersion !== workerVersion) {
       throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
@@ -114,7 +116,13 @@ class WorkerMessageHandler {
     }
 
     if (typeof ReadableStream === "undefined") {
-      throw new Error("The browser/environment lacks native support for critical " + "functionality used by the PDF.js library (e.g. `ReadableStream`); " + "please use a `legacy`-build instead.");
+      const partialMsg = "The browser/environment lacks native support for critical " + "functionality used by the PDF.js library (e.g. `ReadableStream`); ";
+
+      if (_is_node.isNodeJS) {
+        throw new Error(partialMsg + "please use a `legacy`-build instead.");
+      }
+
+      throw new Error(partialMsg + "please update to a supported browser.");
     }
 
     const docId = docParams.docId;
@@ -371,10 +379,8 @@ class WorkerMessageHandler {
         });
       });
     });
-    handler.on("GetPageIndex", function wphSetupGetPageIndex({
-      ref
-    }) {
-      const pageRef = _primitives.Ref.get(ref.num, ref.gen);
+    handler.on("GetPageIndex", function wphSetupGetPageIndex(data) {
+      const pageRef = _primitives.Ref.get(data.num, data.gen);
 
       return pdfManager.ensureCatalog("getPageIndex", [pageRef]);
     });
@@ -524,7 +530,7 @@ class WorkerMessageHandler {
 
           if (xrefInfo instanceof _primitives.Dict) {
             xrefInfo.forEach((key, value) => {
-              if ((0, _util.isString)(key) && (0, _util.isString)(value)) {
+              if (typeof value === "string") {
                 infoObj[key] = (0, _util.stringToPDFString)(value);
               }
             });
@@ -602,7 +608,6 @@ class WorkerMessageHandler {
           handler,
           task,
           sink,
-          normalizeWhitespace: data.normalizeWhitespace,
           includeMarkedContent: data.includeMarkedContent,
           combineTextItems: data.combineTextItems
         }).then(function () {
@@ -645,7 +650,7 @@ class WorkerMessageHandler {
         waitOn.push(cleanupPromise);
         pdfManager = null;
       } else {
-        (0, _primitives.clearPrimitiveCaches)();
+        (0, _cleanup_helper.clearGlobalCaches)();
       }
 
       if (cancelXHRs) {

+ 1 - 1
lib/core/worker_stream.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 7 - 5
lib/core/writer.js

@@ -2,7 +2,7 @@
  * @licstart The following is the entire license notice for the
  * Javascript code in this page
  *
- * Copyright 2021 Mozilla Foundation
+ * Copyright 2022 Mozilla Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,6 +35,8 @@ var _core_utils = require("./core_utils.js");
 
 var _xml_parser = require("./xml_parser.js");
 
+var _base_stream = require("./base_stream.js");
+
 var _crypto = require("./crypto.js");
 
 function writeDict(dict, buffer, transform) {
@@ -96,9 +98,9 @@ function numberToString(value) {
 }
 
 function writeValue(value, buffer, transform) {
-  if ((0, _primitives.isName)(value)) {
+  if (value instanceof _primitives.Name) {
     buffer.push(`/${(0, _core_utils.escapePDFName)(value.name)}`);
-  } else if ((0, _primitives.isRef)(value)) {
+  } else if (value instanceof _primitives.Ref) {
     buffer.push(`${value.num} ${value.gen} R`);
   } else if (Array.isArray(value)) {
     writeArray(value, buffer, transform);
@@ -112,9 +114,9 @@ function writeValue(value, buffer, transform) {
     buffer.push(numberToString(value));
   } else if (typeof value === "boolean") {
     buffer.push(value.toString());
-  } else if ((0, _primitives.isDict)(value)) {
+  } else if (value instanceof _primitives.Dict) {
     writeDict(value, buffer, transform);
-  } else if ((0, _primitives.isStream)(value)) {
+  } else if (value instanceof _base_stream.BaseStream) {
     writeStream(value, buffer, transform);
   } else if (value === null) {
     buffer.push("null");

Vissa filer visades inte eftersom för många filer har ändrats