1// ==UserScript== 2// @name pdfjs polyfill 3// @include qute://pdfjs/* 4// @run-at document-start 5// @grant unsafeWindow 6// ==/UserScript== 7 8// https://github.com/tc39/proposal-relative-indexing-method#polyfill 9// https://github.com/qutebrowser/qutebrowser/commit/726d5e614b1f80c339084eba7d1c240bf467fa9b 10 11(function() { 12 function at(idx) { 13 // ToInteger() abstract op 14 let n = Math.trunc(idx) || 0; 15 // Allow negative indexing from the end 16 if (n < 0) { 17 n += this.length; 18 } 19 // OOB access is guaranteed to return undefined 20 if (n < 0 || n >= this.length) { 21 return undefined; 22 } 23 // Otherwise, this is just normal property access 24 return this[n]; 25 } 26 27 const TypedArray = Reflect.getPrototypeOf(Int8Array); 28 for (const type of [Array, String, TypedArray]) { 29 Object.defineProperty( 30 type.prototype, 31 "at", 32 { 33 "value": at, 34 "writable": true, 35 "enumerable": false, 36 "configurable": true, 37 } 38 ); 39 } 40})(); 41 42// We can't patch Array.at for Workers, so we just pretend we don't support 43// them, as PDF.js works without them too. 44//window.Worker = undefined; 45 46// https://github.com/mozilla/pdf.js/commit/7cc761a8c0ff12217ff8478bdb5a2fce3a07833a 47window.structuredClone = function(object, transfers) { 48// https://youmightnotneed.com/lodash 49const isArrayBuffer = value => value.toString() === '[object ArrayBuffer]' 50 51// Trying to perform a structured clone close to the spec, including 52// transfers. 53function fallbackCloneValue(value) { 54 if ( 55 typeof value === "function" || 56 typeof value === "symbol" || 57 value instanceof URL 58 ) { 59 throw new Error( 60 `LoopbackPort.postMessage - cannot clone: ${value?.toString()}` 61 ); 62 } 63 64 if (typeof value !== "object" || value === null) { 65 return value; 66 } 67 if (cloned.has(value)) { 68 // already cloned the object 69 return cloned.get(value); 70 } 71 let buffer, result; 72 if ((buffer = value.buffer) && isArrayBuffer(buffer)) { 73 // We found object with ArrayBuffer (typed array). 74 if (transfers?.includes(buffer)) { 75 result = new value.constructor( 76 buffer, 77 value.byteOffset, 78 value.byteLength 79 ); 80 } else { 81 result = new value.constructor(value); 82 } 83 cloned.set(value, result); 84 return result; 85 } 86 if (value instanceof Map) { 87 result = new Map(); 88 cloned.set(value, result); // Adding to cache now for cyclic references. 89 for (const [key, val] of value) { 90 result.set(key, fallbackCloneValue(val)); 91 } 92 return result; 93 } 94 if (value instanceof Set) { 95 result = new Set(); 96 cloned.set(value, result); // Adding to cache now for cyclic references. 97 for (const val of value) { 98 result.add(fallbackCloneValue(val)); 99 } 100 return result; 101 } 102 result = Array.isArray(value) ? [] : Object.create(null); 103 cloned.set(value, result); // Adding to cache now for cyclic references. 104 // Cloning all value and object properties, however ignoring properties 105 // defined via getter. 106 for (const i in value) { 107 let desc, 108 p = value; 109 while (!(desc = Object.getOwnPropertyDescriptor(p, i))) { 110 p = Object.getPrototypeOf(p); 111 } 112 if (typeof desc.value === "undefined") { 113 continue; 114 } 115 if (typeof desc.value === "function" && !value.hasOwnProperty?.(i)) { 116 continue; 117 } 118 result[i] = fallbackCloneValue(desc.value); 119 } 120 return result; 121} 122 123const cloned = new WeakMap(); 124return fallbackCloneValue(object); 125}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.