Dactyloidae/browser/internaluserscripts/bundled-scripts/imagedecode-polyfill.user.js
2026-07-13 08:48:40 -07:00

111 lines
2.8 KiB
JavaScript

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// ==UserScript==
// @name HTMLImageElement.decode Polyfill (best-effort)
// @namespace internal-userscripts
// @description Adds a Promise-based decode() that resolves on load and rejects on error.
// @match *://*/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function () {
"use strict";
var global = typeof window !== "undefined" ? window : null;
if (!global || !global.HTMLImageElement) {
return;
}
var proto = global.HTMLImageElement.prototype;
if (typeof proto.decode === "function") {
return;
}
var PromiseCtor = global.Promise;
if (typeof PromiseCtor !== "function") {
return;
}
function rejectPromise(error) {
return new PromiseCtor(function (resolve, reject) {
reject(error);
});
}
function hasLoadedImage(img) {
return img.complete && (img.naturalWidth > 0 || img.naturalHeight > 0);
}
function isBrokenImage(img) {
return img.complete && img.naturalWidth === 0 && img.naturalHeight === 0;
}
function decode() {
var img = this;
if (!(img instanceof global.HTMLImageElement)) {
return rejectPromise(new TypeError("decode can only be used on an HTMLImageElement"));
}
if (hasLoadedImage(img)) {
return PromiseCtor.resolve();
}
if (isBrokenImage(img)) {
return rejectPromise(new Error("Image decode failed"));
}
var src = "";
try {
src = img.currentSrc || img.src || "";
} catch (e) {}
if (!src) {
return rejectPromise(new Error("Image has no src"));
}
return new PromiseCtor(function (resolve, reject) {
var settled = false;
function cleanup() {
if (settled) {
return;
}
settled = true;
img.removeEventListener("load", onLoad, false);
img.removeEventListener("error", onError, false);
}
function onLoad() {
cleanup();
resolve();
}
function onError() {
cleanup();
reject(new Error("Image decode failed"));
}
img.addEventListener("load", onLoad, false);
img.addEventListener("error", onError, false);
if (hasLoadedImage(img)) {
cleanup();
resolve();
} else if (isBrokenImage(img)) {
cleanup();
reject(new Error("Image decode failed"));
}
});
}
try {
Object.defineProperty(proto, "decode", {
value: decode,
writable: true,
configurable: true
});
} catch (e) {
proto.decode = decode;
}
try { global.__internalUserscriptsImageDecodePolyfill = true; } catch (e) {}
})();