Remove the Uint8Array.prototype.toHex(), Uint8Array.prototype.toBase64(), and Uint8Array.fromBase64() polyfills

(During rebasing of the previous patches I happened to look at the polyfills and noticed that this one could be removed now.)

See:
 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toHex#browser_compatibility
 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toBase64#browser_compatibility
 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromBase64#browser_compatibility

Note that technically this functionality can still be disabled via a preference in Firefox, however that's slated for removal in [bug 1985120](https://bugzilla.mozilla.org/show_bug.cgi?id=1985120).
Looking at the Firefox source-code, see https://searchfox.org/firefox-main/search?q=array.tobase64%28%29&path=&case=false&regexp=false, you can see that it's already being used *unconditionally* elsewhere in the browser hence removing the polyfills ought to be fine (since toggling the preference would break other parts of the browser).
This commit is contained in:
Jonas Jenwald 2026-01-25 13:32:11 +01:00
parent 247ee02299
commit 5b368dd58a
11 changed files with 23 additions and 67 deletions

View File

@ -27,7 +27,6 @@ import {
stringToBytes,
stringToPDFString,
stringToUTF8String,
toHexUtil,
unreachable,
Util,
warn,
@ -1605,8 +1604,8 @@ class PDFDocument {
}
return shadow(this, "fingerprints", [
toHexUtil(hashOriginal),
hashModified ? toHexUtil(hashModified) : null,
hashOriginal.toHex(),
hashModified?.toHex() ?? null,
]);
}

View File

@ -90,7 +90,6 @@ import {
XFAObject,
XFAObjectArray,
} from "./xfa_object.js";
import { fromBase64Util, Util, warn } from "../../shared/util.js";
import {
getBBox,
getColor,
@ -103,6 +102,7 @@ import {
getStringOption,
HTMLResult,
} from "./utils.js";
import { Util, warn } from "../../shared/util.js";
import { getMetrics } from "./fonts.js";
import { recoverJsURL } from "../core_utils.js";
import { searchNode } from "./som.js";
@ -3420,7 +3420,7 @@ class Image extends StringObject {
}
if (!buffer && this.transferEncoding === "base64") {
buffer = fromBase64Util(this[$content]);
buffer = Uint8Array.fromBase64(this[$content]);
}
if (!buffer) {

View File

@ -13,10 +13,10 @@
* limitations under the License.
*/
import { fromBase64Util, toBase64Util, warn } from "../../../shared/util.js";
import { ContourDrawOutline } from "./contour.js";
import { InkDrawOutline } from "./inkdraw.js";
import { Outline } from "./outline.js";
import { warn } from "../../../shared/util.js";
const BASE_HEADER_LENGTH = 8;
const POINTS_PROPERTIES_NUMBER = 3;
@ -749,12 +749,12 @@ class SignatureExtractor {
const buf = await new Response(cs.readable).arrayBuffer();
const bytes = new Uint8Array(buf);
return toBase64Util(bytes);
return bytes.toBase64();
}
static async decompressSignature(signatureData) {
try {
const bytes = fromBase64Util(signatureData);
const bytes = Uint8Array.fromBase64(signatureData);
const { readable, writable } = new DecompressionStream("deflate-raw");
const writer = writable.getWriter();
await writer.ready;

View File

@ -19,7 +19,6 @@ import {
isNodeJS,
shadow,
string32,
toBase64Util,
unreachable,
warn,
} from "../shared/util.js";
@ -408,7 +407,7 @@ class FontFaceObject {
return null;
}
// Add the @font-face rule to the document.
const url = `url(data:${this.mimetype};base64,${toBase64Util(this.data)});`;
const url = `url(data:${this.mimetype};base64,${this.data.toBase64()});`;
let rule;
if (!this.cssFontInfo) {
rule = `@font-face {font-family:"${this.loadedName}";src:${url}}`;

View File

@ -1235,31 +1235,6 @@ function MathClamp(v, min, max) {
return Math.min(Math.max(v, min), max);
}
// TODO: Remove this once `Uint8Array.prototype.toHex` is generally available.
function toHexUtil(arr) {
if (Uint8Array.prototype.toHex) {
return arr.toHex();
}
return Array.from(arr, num => hexNumbers[num]).join("");
}
// TODO: Remove this once `Uint8Array.prototype.toBase64` is generally
// available.
function toBase64Util(arr) {
if (Uint8Array.prototype.toBase64) {
return arr.toBase64();
}
return btoa(bytesToString(arr));
}
// TODO: Remove this once `Uint8Array.fromBase64` is generally available.
function fromBase64Util(str) {
if (Uint8Array.fromBase64) {
return Uint8Array.fromBase64(str);
}
return stringToBytes(atob(str));
}
// TODO: Remove this once the `javascript.options.experimental.math_sumprecise`
// preference is removed from Firefox.
if (typeof Math.sumPrecise !== "function") {
@ -1325,7 +1300,6 @@ export {
FeatureTest,
FONT_IDENTITY_MATRIX,
FormatError,
fromBase64Util,
getModificationDate,
getUuid,
getVerbosityLevel,
@ -1355,8 +1329,6 @@ export {
stringToPDFString,
stringToUTF8String,
TextRenderingMode,
toBase64Util,
toHexUtil,
UnknownErrorException,
unreachable,
updateUrlHash,

View File

@ -1,7 +1,7 @@
import { decodeFontData, ttx, verifyTtxOutput } from "./fontutils.js";
import { ttx, verifyTtxOutput } from "./fontutils.js";
describe("font1", function () {
const font1_1 = decodeFontData(
const font1_1 = Uint8Array.fromBase64(
// eslint-disable-next-line max-len
"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"
);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -14,22 +14,10 @@
* limitations under the License.
*/
import { bytesToString, stringToBytes } from "../../src/shared/util.js";
function decodeFontData(base64) {
const str = atob(base64);
return stringToBytes(str);
}
function encodeFontData(data) {
const str = bytesToString(data);
return btoa(str);
}
async function ttx(data) {
const response = await fetch("/ttx", {
method: "POST",
body: encodeFontData(data),
body: data.toBase64(),
});
if (!response.ok) {
@ -45,4 +33,4 @@ function verifyTtxOutput(output) {
}
}
export { decodeFontData, encodeFontData, ttx, verifyTtxOutput };
export { ttx, verifyTtxOutput };

View File

@ -22,7 +22,7 @@ import {
PDFDateString,
renderRichText,
} from "../../src/display/display_utils.js";
import { isNodeJS, toBase64Util } from "../../src/shared/util.js";
import { isNodeJS } from "../../src/shared/util.js";
describe("display_utils", function () {
describe("getFilenameFromUrl", function () {
@ -183,9 +183,7 @@ describe("display_utils", function () {
it('gets fallback filename from query string appended to "data:" URL', function () {
const typedArray = new Uint8Array([1, 2, 3, 4, 5]);
const dataUrl = `data:application/pdf;base64,${toBase64Util(typedArray)}`;
// Sanity check to ensure that a "data:" URL was returned.
expect(dataUrl.startsWith("data:")).toEqual(true);
const dataUrl = `data:application/pdf;base64,${typedArray.toBase64()}`;
expect(getPdfFilenameFromUrl(dataUrl + "?file1.pdf")).toEqual(
"document.pdf"