fix(runtime): support PDF preview on Chrome 143

This commit is contained in:
2026-10-18 15:51:26 +08:00
parent 605a48adb0
commit e36f3c1fdd
5 changed files with 147 additions and 0 deletions
+71
View File
@@ -0,0 +1,71 @@
// PDF.js 6 uses Map upsert APIs absent from Chrome 143 / older WebViews.
// Run in both the document and its separate worker realm. Never replace natives.
(() => {
'use strict';
const { has, get, set } = Map.prototype;
// Accumulate finite doubles exactly in units of the smallest subnormal.
// Round only once, avoiding both cancellation loss and intermediate overflow.
if (typeof Math.sumPrecise !== 'function') {
Object.defineProperty(Math, 'sumPrecise', {
configurable: true, writable: true,
value: function sumPrecise(values) {
const bits = new DataView(new ArrayBuffer(8));
let total = 0n, negativeZero = true, positiveInfinity = false, negativeInfinity = false, nan = false;
for (const value of values) {
if (typeof value !== 'number') throw new TypeError('sumPrecise requires numbers');
if (!Object.is(value, -0)) negativeZero = false;
if (!Number.isFinite(value)) {
if (Number.isNaN(value)) nan = true;
else if (value > 0) positiveInfinity = true;
else negativeInfinity = true;
continue;
}
bits.setFloat64(0, value);
const high = bits.getUint32(0), low = bits.getUint32(4);
const exponent = (high >>> 20) & 0x7ff;
let mantissa = (BigInt(high & 0xfffff) << 32n) | BigInt(low);
if (exponent) mantissa = (mantissa | (1n << 52n)) << BigInt(exponent - 1);
total += high >>> 31 ? -mantissa : mantissa;
}
if (nan || (positiveInfinity && negativeInfinity)) return NaN;
if (positiveInfinity) return Infinity;
if (negativeInfinity) return -Infinity;
if (total === 0n) return negativeZero ? -0 : 0;
const sign = total < 0n ? -1 : 1;
if (total < 0n) total = -total;
const shift = Math.max(0, total.toString(2).length - 53);
let rounded = total >> BigInt(shift);
if (shift) {
const remainder = total - (rounded << BigInt(shift));
const half = 1n << BigInt(shift - 1);
if (remainder > half || (remainder === half && (rounded & 1n))) rounded++;
}
return sign * Number(rounded) * 2 ** (shift - 1074);
},
});
}
if (typeof Map.prototype.getOrInsert !== 'function') {
Object.defineProperty(Map.prototype, 'getOrInsert', {
configurable: true, writable: true,
value: function getOrInsert(key, value) {
if (has.call(this, key)) return get.call(this, key);
set.call(this, key, value);
return value;
},
});
}
if (typeof Map.prototype.getOrInsertComputed !== 'function') {
Object.defineProperty(Map.prototype, 'getOrInsertComputed', {
configurable: true, writable: true,
value: function getOrInsertComputed(key, callback) {
const present = has.call(this, key); // Also validates the Map receiver.
if (typeof callback !== 'function') throw new TypeError('callback must be callable');
if (present) return get.call(this, key);
if (key === 0) key = 0; // Canonicalize -0 before calling the callback.
const value = callback(key);
set.call(this, key, value); // Callback may have inserted the same key.
return value;
},
});
}
})();