darkreader 4.9.104 → 4.9.108
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/darkreader.js +991 -853
- package/darkreader.mjs +949 -810
- package/package.json +27 -28
package/darkreader.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Dark Reader v4.9.
|
|
2
|
+
* Dark Reader v4.9.108
|
|
3
3
|
* https://darkreader.org/
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -43,6 +43,8 @@
|
|
|
43
43
|
"ui-bg-apply-dev-static-themes";
|
|
44
44
|
MessageTypeUItoBG["RESET_DEV_STATIC_THEMES"] =
|
|
45
45
|
"ui-bg-reset-dev-static-themes";
|
|
46
|
+
MessageTypeUItoBG["START_ACTIVATION"] = "ui-bg-start-activation";
|
|
47
|
+
MessageTypeUItoBG["RESET_ACTIVATION"] = "ui-bg-reset-activation";
|
|
46
48
|
MessageTypeUItoBG["COLOR_SCHEME_CHANGE"] = "ui-bg-color-scheme-change";
|
|
47
49
|
MessageTypeUItoBG["HIDE_HIGHLIGHTS"] = "ui-bg-hide-highlights";
|
|
48
50
|
})(MessageTypeUItoBG || (MessageTypeUItoBG = {}));
|
|
@@ -364,6 +366,7 @@
|
|
|
364
366
|
darkColorScheme: "Default",
|
|
365
367
|
immediateModify: false
|
|
366
368
|
};
|
|
369
|
+
if (__PLUS__);
|
|
367
370
|
const filterModeSites = [
|
|
368
371
|
"*.officeapps.live.com",
|
|
369
372
|
"*.sharepoint.com",
|
|
@@ -372,9 +375,7 @@
|
|
|
372
375
|
];
|
|
373
376
|
({
|
|
374
377
|
customThemes: filterModeSites.map((url) => {
|
|
375
|
-
const engine =
|
|
376
|
-
? ThemeEngine.svgFilter
|
|
377
|
-
: ThemeEngine.cssFilter;
|
|
378
|
+
const engine = ThemeEngine.cssFilter;
|
|
378
379
|
return {
|
|
379
380
|
url: [url],
|
|
380
381
|
theme: {...DEFAULT_THEME, engine},
|
|
@@ -985,10 +986,16 @@
|
|
|
985
986
|
function parse($color) {
|
|
986
987
|
const c = $color.trim().toLowerCase();
|
|
987
988
|
if (c.includes("(from ")) {
|
|
989
|
+
if (c.indexOf("(from") !== c.lastIndexOf("(from")) {
|
|
990
|
+
return null;
|
|
991
|
+
}
|
|
988
992
|
return domParseColor(c);
|
|
989
993
|
}
|
|
990
994
|
if (c.match(rgbMatch)) {
|
|
991
995
|
if (c.startsWith("rgb(#") || c.startsWith("rgba(#")) {
|
|
996
|
+
if (c.lastIndexOf("rgb") > 0) {
|
|
997
|
+
return null;
|
|
998
|
+
}
|
|
992
999
|
return domParseColor(c);
|
|
993
1000
|
}
|
|
994
1001
|
return parseRGB(c);
|
|
@@ -1011,7 +1018,10 @@
|
|
|
1011
1018
|
if (
|
|
1012
1019
|
c.endsWith(")") &&
|
|
1013
1020
|
supportedColorFuncs.some(
|
|
1014
|
-
(fn) =>
|
|
1021
|
+
(fn) =>
|
|
1022
|
+
c.startsWith(fn) &&
|
|
1023
|
+
c[fn.length] === "(" &&
|
|
1024
|
+
c.lastIndexOf(fn) === 0
|
|
1015
1025
|
)
|
|
1016
1026
|
) {
|
|
1017
1027
|
return domParseColor(c);
|
|
@@ -1840,6 +1850,9 @@
|
|
|
1840
1850
|
forEach(rules, (rule) => {
|
|
1841
1851
|
if (isStyleRule(rule)) {
|
|
1842
1852
|
iterate(rule);
|
|
1853
|
+
if (rule.cssRules?.length > 0) {
|
|
1854
|
+
iterateCSSRules(rule.cssRules, iterate);
|
|
1855
|
+
}
|
|
1843
1856
|
} else if (isImportRule(rule)) {
|
|
1844
1857
|
try {
|
|
1845
1858
|
iterateCSSRules(
|
|
@@ -2097,862 +2110,911 @@
|
|
|
2097
2110
|
return null;
|
|
2098
2111
|
}
|
|
2099
2112
|
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
const conicGradientLength = conicGradient.length;
|
|
2103
|
-
const radialGradient = "radial-";
|
|
2104
|
-
const linearGradient = "linear-";
|
|
2105
|
-
function parseGradient(value) {
|
|
2106
|
-
const result = [];
|
|
2107
|
-
let index = 0;
|
|
2108
|
-
let startIndex = conicGradient.length;
|
|
2109
|
-
while ((index = value.indexOf("gradient", startIndex)) !== -1) {
|
|
2110
|
-
let typeGradient;
|
|
2111
|
-
[linearGradient, radialGradient, conicGradient].find(
|
|
2112
|
-
(possibleType) => {
|
|
2113
|
-
if (index - possibleType.length >= 0) {
|
|
2114
|
-
const possibleGradient = value.substring(
|
|
2115
|
-
index - possibleType.length,
|
|
2116
|
-
index
|
|
2117
|
-
);
|
|
2118
|
-
if (possibleGradient === possibleType) {
|
|
2119
|
-
if (
|
|
2120
|
-
value.slice(
|
|
2121
|
-
index - possibleType.length - 10,
|
|
2122
|
-
index - possibleType.length - 1
|
|
2123
|
-
) === "repeating"
|
|
2124
|
-
) {
|
|
2125
|
-
typeGradient = `repeating-${possibleType}gradient`;
|
|
2126
|
-
return true;
|
|
2127
|
-
}
|
|
2128
|
-
if (
|
|
2129
|
-
value.slice(
|
|
2130
|
-
index - possibleType.length - 8,
|
|
2131
|
-
index - possibleType.length - 1
|
|
2132
|
-
) === "-webkit"
|
|
2133
|
-
) {
|
|
2134
|
-
typeGradient = `-webkit-${possibleType}gradient`;
|
|
2135
|
-
return true;
|
|
2136
|
-
}
|
|
2137
|
-
typeGradient = `${possibleType}gradient`;
|
|
2138
|
-
return true;
|
|
2139
|
-
}
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
);
|
|
2143
|
-
if (!typeGradient) {
|
|
2144
|
-
break;
|
|
2145
|
-
}
|
|
2146
|
-
const {start, end} = getParenthesesRange(
|
|
2147
|
-
value,
|
|
2148
|
-
index + gradientLength
|
|
2149
|
-
);
|
|
2150
|
-
const match = value.substring(start + 1, end - 1);
|
|
2151
|
-
startIndex = end + 1 + conicGradientLength;
|
|
2152
|
-
result.push({
|
|
2153
|
-
typeGradient,
|
|
2154
|
-
match,
|
|
2155
|
-
offset: typeGradient.length + 2,
|
|
2156
|
-
index: index - typeGradient.length + gradientLength,
|
|
2157
|
-
hasComma: true
|
|
2158
|
-
});
|
|
2159
|
-
}
|
|
2160
|
-
if (result.length) {
|
|
2161
|
-
result[result.length - 1].hasComma = false;
|
|
2162
|
-
}
|
|
2163
|
-
return result;
|
|
2113
|
+
function getBackgroundPoles(_theme) {
|
|
2114
|
+
return ["", ""];
|
|
2164
2115
|
}
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
const STORAGE_KEY_IMAGE_DETAILS_PREFIX = "__darkreader__imageDetails_v2_";
|
|
2168
|
-
const STORAGE_KEY_CSS_FETCH_PREFIX = "__darkreader__cssFetch_";
|
|
2169
|
-
let imageCacheTimeout = 0;
|
|
2170
|
-
const imageDetailsCacheQueue = new Map();
|
|
2171
|
-
const cachedImageUrls = [];
|
|
2172
|
-
function writeImageDetailsQueue() {
|
|
2173
|
-
imageDetailsCacheQueue.forEach((details, url) => {
|
|
2174
|
-
if (url && url.startsWith("https://")) {
|
|
2175
|
-
try {
|
|
2176
|
-
const json = JSON.stringify(details);
|
|
2177
|
-
sessionStorage.setItem(
|
|
2178
|
-
`${STORAGE_KEY_IMAGE_DETAILS_PREFIX}${url}`,
|
|
2179
|
-
json
|
|
2180
|
-
);
|
|
2181
|
-
cachedImageUrls.push(url);
|
|
2182
|
-
} catch (err) {}
|
|
2183
|
-
}
|
|
2184
|
-
});
|
|
2185
|
-
imageDetailsCacheQueue.clear();
|
|
2186
|
-
sessionStorage.setItem(
|
|
2187
|
-
STORAGE_KEY_IMAGE_DETAILS_LIST,
|
|
2188
|
-
JSON.stringify(cachedImageUrls)
|
|
2189
|
-
);
|
|
2116
|
+
function getTextPoles(_theme) {
|
|
2117
|
+
return ["", ""];
|
|
2190
2118
|
}
|
|
2191
|
-
function
|
|
2192
|
-
|
|
2193
|
-
return;
|
|
2194
|
-
}
|
|
2195
|
-
imageDetailsCacheQueue.set(url, imageDetails);
|
|
2196
|
-
clearTimeout(imageCacheTimeout);
|
|
2197
|
-
imageCacheTimeout = setTimeout(writeImageDetailsQueue, 1000);
|
|
2119
|
+
function modifyBgColorExtended({h, s, l, a}, _pole1, _pole2) {
|
|
2120
|
+
return {h, s, l, a};
|
|
2198
2121
|
}
|
|
2199
|
-
function
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2122
|
+
function modifyFgColorExtended({h, s, l, a}, _pole1, _pole2) {
|
|
2123
|
+
return {h, s, l, a};
|
|
2124
|
+
}
|
|
2125
|
+
function modifyLightSchemeColorExtended({h, s, l, a}, _pole1, _pole2) {
|
|
2126
|
+
return {h, s, l, a};
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
let variablesSheet;
|
|
2130
|
+
const registeredColors = new Map();
|
|
2131
|
+
function registerVariablesSheet(sheet) {
|
|
2132
|
+
variablesSheet = sheet;
|
|
2133
|
+
const types = ["background", "text", "border"];
|
|
2134
|
+
registeredColors.forEach((registered) => {
|
|
2135
|
+
types.forEach((type) => {
|
|
2136
|
+
if (registered[type]) {
|
|
2137
|
+
const {variable, value} = registered[type];
|
|
2138
|
+
variablesSheet?.cssRules[0].style.setProperty(
|
|
2139
|
+
variable,
|
|
2140
|
+
value
|
|
2141
|
+
);
|
|
2215
2142
|
}
|
|
2216
2143
|
});
|
|
2217
|
-
}
|
|
2218
|
-
}
|
|
2219
|
-
function writeCSSFetchCache(url, cssText) {
|
|
2220
|
-
const key = `${STORAGE_KEY_CSS_FETCH_PREFIX}${url}`;
|
|
2221
|
-
try {
|
|
2222
|
-
sessionStorage.setItem(key, cssText);
|
|
2223
|
-
} catch (err) {}
|
|
2144
|
+
});
|
|
2224
2145
|
}
|
|
2225
|
-
function
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
return sessionStorage.getItem(key) ?? null;
|
|
2229
|
-
} catch (err) {}
|
|
2230
|
-
return null;
|
|
2146
|
+
function releaseVariablesSheet() {
|
|
2147
|
+
variablesSheet = null;
|
|
2148
|
+
clearColorPalette();
|
|
2231
2149
|
}
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
return matrix
|
|
2235
|
-
.slice(0, 4)
|
|
2236
|
-
.map((m) => m.map((m) => m.toFixed(3)).join(" "))
|
|
2237
|
-
.join(" ");
|
|
2150
|
+
function getRegisteredVariableValue(type, registered) {
|
|
2151
|
+
return `var(${registered[type].variable}, ${registered[type].value})`;
|
|
2238
2152
|
}
|
|
2239
|
-
function
|
|
2240
|
-
|
|
2153
|
+
function getRegisteredColor(type, parsed) {
|
|
2154
|
+
const hex = rgbToHexString(parsed);
|
|
2155
|
+
const registered = registeredColors.get(hex);
|
|
2156
|
+
if (registered?.[type]) {
|
|
2157
|
+
return getRegisteredVariableValue(type, registered);
|
|
2158
|
+
}
|
|
2159
|
+
return null;
|
|
2241
2160
|
}
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2161
|
+
function registerColor(type, parsed, value) {
|
|
2162
|
+
const hex = rgbToHexString(parsed);
|
|
2163
|
+
let registered;
|
|
2164
|
+
if (registeredColors.has(hex)) {
|
|
2165
|
+
registered = registeredColors.get(hex);
|
|
2166
|
+
} else {
|
|
2167
|
+
const parsed = parseColorWithCache(hex);
|
|
2168
|
+
registered = {parsed};
|
|
2169
|
+
registeredColors.set(hex, registered);
|
|
2248
2170
|
}
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2171
|
+
const variable = `--darkreader-${type}-${hex.replace("#", "")}`;
|
|
2172
|
+
registered[type] = {variable, value};
|
|
2173
|
+
if (variablesSheet?.cssRules[0]?.style) {
|
|
2174
|
+
variablesSheet?.cssRules[0].style.setProperty(variable, value);
|
|
2252
2175
|
}
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2176
|
+
return getRegisteredVariableValue(type, registered);
|
|
2177
|
+
}
|
|
2178
|
+
function getColorPalette() {
|
|
2179
|
+
const background = [];
|
|
2180
|
+
const border = [];
|
|
2181
|
+
const text = [];
|
|
2182
|
+
registeredColors.forEach((registered) => {
|
|
2183
|
+
if (registered.background) {
|
|
2184
|
+
background.push(registered.parsed);
|
|
2257
2185
|
}
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
scheduleFrame() {
|
|
2261
|
-
if (this.timerId) {
|
|
2262
|
-
return;
|
|
2186
|
+
if (registered.border) {
|
|
2187
|
+
border.push(registered.parsed);
|
|
2263
2188
|
}
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
break;
|
|
2273
|
-
}
|
|
2274
|
-
}
|
|
2275
|
-
});
|
|
2276
|
-
}
|
|
2189
|
+
if (registered.text) {
|
|
2190
|
+
text.push(registered.parsed);
|
|
2191
|
+
}
|
|
2192
|
+
});
|
|
2193
|
+
return {background, border, text};
|
|
2194
|
+
}
|
|
2195
|
+
function clearColorPalette() {
|
|
2196
|
+
registeredColors.clear();
|
|
2277
2197
|
}
|
|
2278
2198
|
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
return new Promise((resolve, reject) => {
|
|
2286
|
-
const id = generateUID();
|
|
2287
|
-
resolvers$1.set(id, resolve);
|
|
2288
|
-
rejectors.set(id, reject);
|
|
2289
|
-
chrome.runtime.sendMessage({
|
|
2290
|
-
type: MessageTypeCStoBG.FETCH,
|
|
2291
|
-
data: request,
|
|
2292
|
-
id
|
|
2293
|
-
});
|
|
2294
|
-
});
|
|
2199
|
+
function getBgPole(theme) {
|
|
2200
|
+
const isDarkScheme = theme.mode === 1;
|
|
2201
|
+
const prop = isDarkScheme
|
|
2202
|
+
? "darkSchemeBackgroundColor"
|
|
2203
|
+
: "lightSchemeBackgroundColor";
|
|
2204
|
+
return theme[prop];
|
|
2295
2205
|
}
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
} else {
|
|
2324
|
-
image =
|
|
2325
|
-
(await tryCreateImageBitmap(blob)) ??
|
|
2326
|
-
(await loadImage(dataURL));
|
|
2327
|
-
}
|
|
2328
|
-
imageManager.addTask(() => {
|
|
2329
|
-
const analysis = analyzeImage(image);
|
|
2330
|
-
resolve({
|
|
2331
|
-
src: url,
|
|
2332
|
-
dataURL: analysis.isLarge ? "" : dataURL,
|
|
2333
|
-
width: image.width,
|
|
2334
|
-
height: image.height,
|
|
2335
|
-
...analysis
|
|
2336
|
-
});
|
|
2337
|
-
});
|
|
2338
|
-
} catch (error) {
|
|
2339
|
-
reject(error);
|
|
2340
|
-
}
|
|
2206
|
+
function getFgPole(theme) {
|
|
2207
|
+
const isDarkScheme = theme.mode === 1;
|
|
2208
|
+
const prop = isDarkScheme
|
|
2209
|
+
? "darkSchemeTextColor"
|
|
2210
|
+
: "lightSchemeTextColor";
|
|
2211
|
+
return theme[prop];
|
|
2212
|
+
}
|
|
2213
|
+
const colorModificationCache = new Map();
|
|
2214
|
+
function clearColorModificationCache() {
|
|
2215
|
+
colorModificationCache.clear();
|
|
2216
|
+
}
|
|
2217
|
+
const rgbCacheKeys = ["r", "g", "b", "a"];
|
|
2218
|
+
const themeCacheKeys = [
|
|
2219
|
+
"mode",
|
|
2220
|
+
"brightness",
|
|
2221
|
+
"contrast",
|
|
2222
|
+
"grayscale",
|
|
2223
|
+
"sepia",
|
|
2224
|
+
"darkSchemeBackgroundColor",
|
|
2225
|
+
"darkSchemeTextColor",
|
|
2226
|
+
"lightSchemeBackgroundColor",
|
|
2227
|
+
"lightSchemeTextColor"
|
|
2228
|
+
];
|
|
2229
|
+
function getCacheId(rgb, theme) {
|
|
2230
|
+
let resultId = "";
|
|
2231
|
+
rgbCacheKeys.forEach((key) => {
|
|
2232
|
+
resultId += `${rgb[key]};`;
|
|
2341
2233
|
});
|
|
2234
|
+
themeCacheKeys.forEach((key) => {
|
|
2235
|
+
resultId += `${theme[key]};`;
|
|
2236
|
+
});
|
|
2237
|
+
return resultId;
|
|
2342
2238
|
}
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2239
|
+
function modifyColorWithCache(
|
|
2240
|
+
rgb,
|
|
2241
|
+
theme,
|
|
2242
|
+
modifyHSL,
|
|
2243
|
+
poleColor,
|
|
2244
|
+
anotherPoleColor
|
|
2245
|
+
) {
|
|
2246
|
+
let fnCache;
|
|
2247
|
+
if (colorModificationCache.has(modifyHSL)) {
|
|
2248
|
+
fnCache = colorModificationCache.get(modifyHSL);
|
|
2249
|
+
} else {
|
|
2250
|
+
fnCache = new Map();
|
|
2251
|
+
colorModificationCache.set(modifyHSL, fnCache);
|
|
2347
2252
|
}
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
try {
|
|
2352
|
-
return await createImageBitmap(blob);
|
|
2353
|
-
} catch (err) {
|
|
2354
|
-
logWarn(
|
|
2355
|
-
`Unable to create image bitmap for type ${blob.type}: ${String(err)}`
|
|
2356
|
-
);
|
|
2357
|
-
return null;
|
|
2253
|
+
const id = getCacheId(rgb, theme);
|
|
2254
|
+
if (fnCache.has(id)) {
|
|
2255
|
+
return fnCache.get(id);
|
|
2358
2256
|
}
|
|
2257
|
+
const hsl = rgbToHSL(rgb);
|
|
2258
|
+
const pole = poleColor == null ? null : parseToHSLWithCache(poleColor);
|
|
2259
|
+
const anotherPole =
|
|
2260
|
+
anotherPoleColor == null
|
|
2261
|
+
? null
|
|
2262
|
+
: parseToHSLWithCache(anotherPoleColor);
|
|
2263
|
+
const modified = modifyHSL(hsl, pole, anotherPole);
|
|
2264
|
+
const {r, g, b, a} = hslToRGB(modified);
|
|
2265
|
+
const matrix = createFilterMatrix({...theme, mode: 0});
|
|
2266
|
+
const [rf, gf, bf] = applyColorMatrix([r, g, b], matrix);
|
|
2267
|
+
const color =
|
|
2268
|
+
a === 1
|
|
2269
|
+
? rgbToHexString({r: rf, g: gf, b: bf})
|
|
2270
|
+
: rgbToString({r: rf, g: gf, b: bf, a});
|
|
2271
|
+
fnCache.set(id, color);
|
|
2272
|
+
return color;
|
|
2359
2273
|
}
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
if (
|
|
2368
|
-
++loadingImagesCount <= INCOMPLETE_DOC_LOADING_IMAGE_LIMIT ||
|
|
2369
|
-
isReadyStateComplete()
|
|
2370
|
-
) {
|
|
2371
|
-
image.src = url;
|
|
2372
|
-
} else {
|
|
2373
|
-
addReadyStateCompleteListener(() => (image.src = url));
|
|
2374
|
-
}
|
|
2375
|
-
});
|
|
2376
|
-
}
|
|
2377
|
-
const MAX_ANALYSIS_PIXELS_COUNT = 32 * 32;
|
|
2378
|
-
let canvas;
|
|
2379
|
-
let context;
|
|
2380
|
-
function createCanvas() {
|
|
2381
|
-
const maxWidth = MAX_ANALYSIS_PIXELS_COUNT;
|
|
2382
|
-
const maxHeight = MAX_ANALYSIS_PIXELS_COUNT;
|
|
2383
|
-
canvas = document.createElement("canvas");
|
|
2384
|
-
canvas.width = maxWidth;
|
|
2385
|
-
canvas.height = maxHeight;
|
|
2386
|
-
context = canvas.getContext("2d", {willReadFrequently: true});
|
|
2387
|
-
context.imageSmoothingEnabled = false;
|
|
2274
|
+
function modifyAndRegisterColor(type, rgb, theme, modifier) {
|
|
2275
|
+
const registered = getRegisteredColor(type, rgb);
|
|
2276
|
+
if (registered) {
|
|
2277
|
+
return registered;
|
|
2278
|
+
}
|
|
2279
|
+
const value = modifier(rgb, theme);
|
|
2280
|
+
return registerColor(type, rgb, value);
|
|
2388
2281
|
}
|
|
2389
|
-
function
|
|
2390
|
-
|
|
2391
|
-
|
|
2282
|
+
function modifyLightSchemeColor(rgb, theme) {
|
|
2283
|
+
const poleBg = getBgPole(theme);
|
|
2284
|
+
const poleFg = getFgPole(theme);
|
|
2285
|
+
return modifyColorWithCache(
|
|
2286
|
+
rgb,
|
|
2287
|
+
theme,
|
|
2288
|
+
modifyLightModeHSL,
|
|
2289
|
+
poleFg,
|
|
2290
|
+
poleBg
|
|
2291
|
+
);
|
|
2392
2292
|
}
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
let sw;
|
|
2399
|
-
let sh;
|
|
2400
|
-
if (image instanceof HTMLImageElement) {
|
|
2401
|
-
sw = image.naturalWidth;
|
|
2402
|
-
sh = image.naturalHeight;
|
|
2293
|
+
function modifyLightModeHSL({h, s, l, a}, poleFg, poleBg) {
|
|
2294
|
+
const isDark = l < 0.5;
|
|
2295
|
+
let isNeutral;
|
|
2296
|
+
if (isDark) {
|
|
2297
|
+
isNeutral = l < 0.2 || s < 0.12;
|
|
2403
2298
|
} else {
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
}
|
|
2407
|
-
if (sw === 0 || sh === 0) {
|
|
2408
|
-
logWarn("Image is empty");
|
|
2409
|
-
return {
|
|
2410
|
-
isDark: false,
|
|
2411
|
-
isLight: false,
|
|
2412
|
-
isTransparent: false,
|
|
2413
|
-
isLarge: false
|
|
2414
|
-
};
|
|
2299
|
+
const isBlue = h > 200 && h < 280;
|
|
2300
|
+
isNeutral = s < 0.24 || (l > 0.8 && isBlue);
|
|
2415
2301
|
}
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
context.drawImage(image, 0, 0, sw, sh, 0, 0, width, height);
|
|
2426
|
-
const imageData = context.getImageData(0, 0, width, height);
|
|
2427
|
-
const d = imageData.data;
|
|
2428
|
-
const TRANSPARENT_ALPHA_THRESHOLD = 0.05;
|
|
2429
|
-
const DARK_LIGHTNESS_THRESHOLD = 0.4;
|
|
2430
|
-
const LIGHT_LIGHTNESS_THRESHOLD = 0.7;
|
|
2431
|
-
let transparentPixelsCount = 0;
|
|
2432
|
-
let darkPixelsCount = 0;
|
|
2433
|
-
let lightPixelsCount = 0;
|
|
2434
|
-
let i, x, y;
|
|
2435
|
-
let r, g, b, a;
|
|
2436
|
-
let l;
|
|
2437
|
-
for (y = 0; y < height; y++) {
|
|
2438
|
-
for (x = 0; x < width; x++) {
|
|
2439
|
-
i = 4 * (y * width + x);
|
|
2440
|
-
r = d[i + 0];
|
|
2441
|
-
g = d[i + 1];
|
|
2442
|
-
b = d[i + 2];
|
|
2443
|
-
a = d[i + 3];
|
|
2444
|
-
if (a / 255 < TRANSPARENT_ALPHA_THRESHOLD) {
|
|
2445
|
-
transparentPixelsCount++;
|
|
2446
|
-
} else {
|
|
2447
|
-
l = getSRGBLightness(r, g, b);
|
|
2448
|
-
if (l < DARK_LIGHTNESS_THRESHOLD) {
|
|
2449
|
-
darkPixelsCount++;
|
|
2450
|
-
}
|
|
2451
|
-
if (l > LIGHT_LIGHTNESS_THRESHOLD) {
|
|
2452
|
-
lightPixelsCount++;
|
|
2453
|
-
}
|
|
2454
|
-
}
|
|
2302
|
+
let hx = h;
|
|
2303
|
+
let sx = s;
|
|
2304
|
+
if (isNeutral) {
|
|
2305
|
+
if (isDark) {
|
|
2306
|
+
hx = poleFg.h;
|
|
2307
|
+
sx = poleFg.s;
|
|
2308
|
+
} else {
|
|
2309
|
+
hx = poleBg.h;
|
|
2310
|
+
sx = poleBg.s;
|
|
2455
2311
|
}
|
|
2456
2312
|
}
|
|
2457
|
-
const
|
|
2458
|
-
|
|
2459
|
-
const DARK_IMAGE_THRESHOLD = 0.7;
|
|
2460
|
-
const LIGHT_IMAGE_THRESHOLD = 0.7;
|
|
2461
|
-
const TRANSPARENT_IMAGE_THRESHOLD = 0.1;
|
|
2462
|
-
return {
|
|
2463
|
-
isDark: darkPixelsCount / opaquePixelsCount >= DARK_IMAGE_THRESHOLD,
|
|
2464
|
-
isLight:
|
|
2465
|
-
lightPixelsCount / opaquePixelsCount >= LIGHT_IMAGE_THRESHOLD,
|
|
2466
|
-
isTransparent:
|
|
2467
|
-
transparentPixelsCount / totalPixelsCount >=
|
|
2468
|
-
TRANSPARENT_IMAGE_THRESHOLD,
|
|
2469
|
-
isLarge
|
|
2470
|
-
};
|
|
2313
|
+
const lx = scale(l, 0, 1, poleFg.l, poleBg.l);
|
|
2314
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2471
2315
|
}
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2316
|
+
const MAX_BG_LIGHTNESS = 0.4;
|
|
2317
|
+
function modifyBgHSL({h, s, l, a}, pole) {
|
|
2318
|
+
const isDark = l < 0.5;
|
|
2319
|
+
const isBlue = h > 200 && h < 280;
|
|
2320
|
+
const isNeutral = s < 0.12 || (l > 0.8 && isBlue);
|
|
2321
|
+
if (isDark) {
|
|
2322
|
+
const lx = scale(l, 0, 0.5, 0, MAX_BG_LIGHTNESS);
|
|
2323
|
+
if (isNeutral) {
|
|
2324
|
+
const hx = pole.h;
|
|
2325
|
+
const sx = pole.s;
|
|
2326
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2327
|
+
}
|
|
2328
|
+
return {h, s, l: lx, a};
|
|
2484
2329
|
}
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2330
|
+
let lx = scale(l, 0.5, 1, MAX_BG_LIGHTNESS, pole.l);
|
|
2331
|
+
if (isNeutral) {
|
|
2332
|
+
const hx = pole.h;
|
|
2333
|
+
const sx = pole.s;
|
|
2334
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2489
2335
|
}
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
);
|
|
2505
|
-
});
|
|
2336
|
+
let hx = h;
|
|
2337
|
+
const isYellow = h > 60 && h < 180;
|
|
2338
|
+
if (isYellow) {
|
|
2339
|
+
const isCloserToGreen = h > 120;
|
|
2340
|
+
if (isCloserToGreen) {
|
|
2341
|
+
hx = scale(h, 120, 180, 135, 180);
|
|
2342
|
+
} else {
|
|
2343
|
+
hx = scale(h, 60, 120, 60, 105);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
if (hx > 40 && hx < 80) {
|
|
2347
|
+
lx *= 0.75;
|
|
2348
|
+
}
|
|
2349
|
+
return {h: hx, s, l: lx, a};
|
|
2506
2350
|
}
|
|
2507
|
-
function
|
|
2508
|
-
|
|
2351
|
+
function _modifyBackgroundColor(rgb, theme) {
|
|
2352
|
+
if (theme.mode === 0) {
|
|
2353
|
+
if (__PLUS__) {
|
|
2354
|
+
const poles = getBackgroundPoles();
|
|
2355
|
+
return modifyColorWithCache(
|
|
2356
|
+
rgb,
|
|
2357
|
+
theme,
|
|
2358
|
+
modifyLightSchemeColorExtended,
|
|
2359
|
+
poles[0],
|
|
2360
|
+
poles[1]
|
|
2361
|
+
);
|
|
2362
|
+
}
|
|
2363
|
+
return modifyLightSchemeColor(rgb, theme);
|
|
2364
|
+
}
|
|
2365
|
+
if (__PLUS__) {
|
|
2366
|
+
const poles = getBackgroundPoles();
|
|
2367
|
+
return modifyColorWithCache(
|
|
2368
|
+
rgb,
|
|
2369
|
+
theme,
|
|
2370
|
+
modifyBgColorExtended,
|
|
2371
|
+
poles[0],
|
|
2372
|
+
poles[1]
|
|
2373
|
+
);
|
|
2374
|
+
}
|
|
2375
|
+
const pole = getBgPole(theme);
|
|
2376
|
+
return modifyColorWithCache(rgb, theme, modifyBgHSL, pole);
|
|
2509
2377
|
}
|
|
2510
|
-
function
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2378
|
+
function modifyBackgroundColor(
|
|
2379
|
+
rgb,
|
|
2380
|
+
theme,
|
|
2381
|
+
shouldRegisterColorVariable = true
|
|
2382
|
+
) {
|
|
2383
|
+
if (!shouldRegisterColorVariable) {
|
|
2384
|
+
return _modifyBackgroundColor(rgb, theme);
|
|
2514
2385
|
}
|
|
2386
|
+
return modifyAndRegisterColor(
|
|
2387
|
+
"background",
|
|
2388
|
+
rgb,
|
|
2389
|
+
theme,
|
|
2390
|
+
_modifyBackgroundColor
|
|
2391
|
+
);
|
|
2515
2392
|
}
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2393
|
+
const MIN_FG_LIGHTNESS = 0.55;
|
|
2394
|
+
function modifyBlueFgHue(hue) {
|
|
2395
|
+
return scale(hue, 205, 245, 205, 220);
|
|
2396
|
+
}
|
|
2397
|
+
function modifyFgHSL({h, s, l, a}, pole) {
|
|
2398
|
+
const isLight = l > 0.5;
|
|
2399
|
+
const isNeutral = l < 0.2 || s < 0.24;
|
|
2400
|
+
const isBlue = !isNeutral && h > 205 && h < 245;
|
|
2401
|
+
if (isLight) {
|
|
2402
|
+
const lx = scale(l, 0.5, 1, MIN_FG_LIGHTNESS, pole.l);
|
|
2403
|
+
if (isNeutral) {
|
|
2404
|
+
const hx = pole.h;
|
|
2405
|
+
const sx = pole.s;
|
|
2406
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2407
|
+
}
|
|
2408
|
+
let hx = h;
|
|
2409
|
+
if (isBlue) {
|
|
2410
|
+
hx = modifyBlueFgHue(h);
|
|
2411
|
+
}
|
|
2412
|
+
return {h: hx, s, l: lx, a};
|
|
2521
2413
|
}
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
`<feColorMatrix type="matrix" values="${matrix}" />`,
|
|
2528
|
-
"</filter>",
|
|
2529
|
-
"</defs>",
|
|
2530
|
-
`<image width="${width}" height="${height}" filter="url(#darkreader-image-filter)" xlink:href="${dataURL}" />`,
|
|
2531
|
-
"</svg>"
|
|
2532
|
-
].join("");
|
|
2533
|
-
if (!isBlobURLSupported) {
|
|
2534
|
-
return `data:image/svg+xml;base64,${btoa(svg)}`;
|
|
2414
|
+
if (isNeutral) {
|
|
2415
|
+
const hx = pole.h;
|
|
2416
|
+
const sx = pole.s;
|
|
2417
|
+
const lx = scale(l, 0, 0.5, pole.l, MIN_FG_LIGHTNESS);
|
|
2418
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2535
2419
|
}
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2420
|
+
let hx = h;
|
|
2421
|
+
let lx;
|
|
2422
|
+
if (isBlue) {
|
|
2423
|
+
hx = modifyBlueFgHue(h);
|
|
2424
|
+
lx = scale(l, 0, 0.5, pole.l, Math.min(1, MIN_FG_LIGHTNESS + 0.05));
|
|
2425
|
+
} else {
|
|
2426
|
+
lx = scale(l, 0, 0.5, pole.l, MIN_FG_LIGHTNESS);
|
|
2539
2427
|
}
|
|
2540
|
-
|
|
2541
|
-
const objectURL = URL.createObjectURL(blob);
|
|
2542
|
-
objectURLs.add(objectURL);
|
|
2543
|
-
return objectURL;
|
|
2544
|
-
}
|
|
2545
|
-
const xmlEscapeChars = {
|
|
2546
|
-
"<": "<",
|
|
2547
|
-
">": ">",
|
|
2548
|
-
"&": "&",
|
|
2549
|
-
"'": "'",
|
|
2550
|
-
'"': """
|
|
2551
|
-
};
|
|
2552
|
-
function escapeXML(str) {
|
|
2553
|
-
return str.replace(/[<>&'"]/g, (c) => xmlEscapeChars[c] ?? c);
|
|
2428
|
+
return {h: hx, s, l: lx, a};
|
|
2554
2429
|
}
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2430
|
+
function _modifyForegroundColor(rgb, theme) {
|
|
2431
|
+
if (theme.mode === 0) {
|
|
2432
|
+
if (__PLUS__) {
|
|
2433
|
+
const poles = getTextPoles();
|
|
2434
|
+
return modifyColorWithCache(
|
|
2435
|
+
rgb,
|
|
2436
|
+
theme,
|
|
2437
|
+
modifyLightSchemeColorExtended,
|
|
2438
|
+
poles[0],
|
|
2439
|
+
poles[1]
|
|
2440
|
+
);
|
|
2441
|
+
}
|
|
2442
|
+
return modifyLightSchemeColor(rgb, theme);
|
|
2566
2443
|
}
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2444
|
+
if (__PLUS__) {
|
|
2445
|
+
const poles = getTextPoles();
|
|
2446
|
+
return modifyColorWithCache(
|
|
2447
|
+
rgb,
|
|
2448
|
+
theme,
|
|
2449
|
+
modifyFgColorExtended,
|
|
2450
|
+
poles[0],
|
|
2451
|
+
poles[1]
|
|
2452
|
+
);
|
|
2571
2453
|
}
|
|
2572
|
-
|
|
2454
|
+
const pole = getFgPole(theme);
|
|
2455
|
+
return modifyColorWithCache(rgb, theme, modifyFgHSL, pole);
|
|
2573
2456
|
}
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2457
|
+
function modifyForegroundColor(
|
|
2458
|
+
rgb,
|
|
2459
|
+
theme,
|
|
2460
|
+
shouldRegisterColorVariable = true
|
|
2461
|
+
) {
|
|
2462
|
+
if (!shouldRegisterColorVariable) {
|
|
2463
|
+
return _modifyForegroundColor(rgb, theme);
|
|
2577
2464
|
}
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2465
|
+
return modifyAndRegisterColor(
|
|
2466
|
+
"text",
|
|
2467
|
+
rgb,
|
|
2468
|
+
theme,
|
|
2469
|
+
_modifyForegroundColor
|
|
2470
|
+
);
|
|
2471
|
+
}
|
|
2472
|
+
function modifyBorderHSL({h, s, l, a}, poleFg, poleBg) {
|
|
2473
|
+
const isDark = l < 0.5;
|
|
2474
|
+
const isNeutral = l < 0.2 || s < 0.24;
|
|
2475
|
+
let hx = h;
|
|
2476
|
+
let sx = s;
|
|
2477
|
+
if (isNeutral) {
|
|
2478
|
+
if (isDark) {
|
|
2479
|
+
hx = poleFg.h;
|
|
2480
|
+
sx = poleFg.s;
|
|
2481
|
+
} else {
|
|
2482
|
+
hx = poleBg.h;
|
|
2483
|
+
sx = poleBg.s;
|
|
2484
|
+
}
|
|
2582
2485
|
}
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2486
|
+
const lx = scale(l, 0, 1, 0.5, 0.2);
|
|
2487
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2488
|
+
}
|
|
2489
|
+
function _modifyBorderColor(rgb, theme) {
|
|
2490
|
+
if (theme.mode === 0) {
|
|
2491
|
+
return modifyLightSchemeColor(rgb, theme);
|
|
2587
2492
|
}
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
return
|
|
2493
|
+
const poleFg = getFgPole(theme);
|
|
2494
|
+
const poleBg = getBgPole(theme);
|
|
2495
|
+
return modifyColorWithCache(
|
|
2496
|
+
rgb,
|
|
2497
|
+
theme,
|
|
2498
|
+
modifyBorderHSL,
|
|
2499
|
+
poleFg,
|
|
2500
|
+
poleBg
|
|
2501
|
+
);
|
|
2591
2502
|
}
|
|
2592
|
-
function
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2503
|
+
function modifyBorderColor(rgb, theme, shouldRegisterColorVariable = true) {
|
|
2504
|
+
if (!shouldRegisterColorVariable) {
|
|
2505
|
+
return _modifyBorderColor(rgb, theme);
|
|
2506
|
+
}
|
|
2507
|
+
return modifyAndRegisterColor("border", rgb, theme, _modifyBorderColor);
|
|
2508
|
+
}
|
|
2509
|
+
function modifyShadowColor(rgb, theme) {
|
|
2510
|
+
return modifyBackgroundColor(rgb, theme);
|
|
2511
|
+
}
|
|
2512
|
+
function modifyGradientColor(rgb, theme) {
|
|
2513
|
+
return modifyBackgroundColor(rgb, theme);
|
|
2514
|
+
}
|
|
2515
|
+
|
|
2516
|
+
const gradientLength = "gradient".length;
|
|
2517
|
+
const conicGradient = "conic-";
|
|
2518
|
+
const conicGradientLength = conicGradient.length;
|
|
2519
|
+
const radialGradient = "radial-";
|
|
2520
|
+
const linearGradient = "linear-";
|
|
2521
|
+
function parseGradient(value) {
|
|
2522
|
+
const result = [];
|
|
2523
|
+
let index = 0;
|
|
2524
|
+
let startIndex = conicGradient.length;
|
|
2525
|
+
while ((index = value.indexOf("gradient", startIndex)) !== -1) {
|
|
2526
|
+
let typeGradient;
|
|
2527
|
+
[linearGradient, radialGradient, conicGradient].find(
|
|
2528
|
+
(possibleType) => {
|
|
2529
|
+
if (index - possibleType.length >= 0) {
|
|
2530
|
+
const possibleGradient = value.substring(
|
|
2531
|
+
index - possibleType.length,
|
|
2532
|
+
index
|
|
2533
|
+
);
|
|
2534
|
+
if (possibleGradient === possibleType) {
|
|
2535
|
+
if (
|
|
2536
|
+
value.slice(
|
|
2537
|
+
index - possibleType.length - 10,
|
|
2538
|
+
index - possibleType.length - 1
|
|
2539
|
+
) === "repeating"
|
|
2540
|
+
) {
|
|
2541
|
+
typeGradient = `repeating-${possibleType}gradient`;
|
|
2542
|
+
return true;
|
|
2543
|
+
}
|
|
2544
|
+
if (
|
|
2545
|
+
value.slice(
|
|
2546
|
+
index - possibleType.length - 8,
|
|
2547
|
+
index - possibleType.length - 1
|
|
2548
|
+
) === "-webkit"
|
|
2549
|
+
) {
|
|
2550
|
+
typeGradient = `-webkit-${possibleType}gradient`;
|
|
2551
|
+
return true;
|
|
2552
|
+
}
|
|
2553
|
+
typeGradient = `${possibleType}gradient`;
|
|
2554
|
+
return true;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
);
|
|
2559
|
+
if (!typeGradient) {
|
|
2560
|
+
break;
|
|
2561
|
+
}
|
|
2562
|
+
const {start, end} = getParenthesesRange(
|
|
2563
|
+
value,
|
|
2564
|
+
index + gradientLength
|
|
2565
|
+
);
|
|
2566
|
+
const match = value.substring(start + 1, end - 1);
|
|
2567
|
+
startIndex = end + 1 + conicGradientLength;
|
|
2568
|
+
result.push({
|
|
2569
|
+
typeGradient,
|
|
2570
|
+
match,
|
|
2571
|
+
offset: typeGradient.length + 2,
|
|
2572
|
+
index: index - typeGradient.length + gradientLength,
|
|
2573
|
+
hasComma: true
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
2576
|
+
if (result.length) {
|
|
2577
|
+
result[result.length - 1].hasComma = false;
|
|
2578
|
+
}
|
|
2579
|
+
return result;
|
|
2599
2580
|
}
|
|
2600
2581
|
|
|
2601
|
-
|
|
2602
|
-
const
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2582
|
+
const STORAGE_KEY_IMAGE_DETAILS_LIST = "__darkreader__imageDetails_v2_list";
|
|
2583
|
+
const STORAGE_KEY_IMAGE_DETAILS_PREFIX = "__darkreader__imageDetails_v2_";
|
|
2584
|
+
const STORAGE_KEY_CSS_FETCH_PREFIX = "__darkreader__cssFetch_";
|
|
2585
|
+
let imageCacheTimeout = 0;
|
|
2586
|
+
const imageDetailsCacheQueue = new Map();
|
|
2587
|
+
const cachedImageUrls = [];
|
|
2588
|
+
function writeImageDetailsQueue() {
|
|
2589
|
+
imageDetailsCacheQueue.forEach((details, url) => {
|
|
2590
|
+
if (url && url.startsWith("https://")) {
|
|
2591
|
+
try {
|
|
2592
|
+
const json = JSON.stringify(details);
|
|
2593
|
+
sessionStorage.setItem(
|
|
2594
|
+
`${STORAGE_KEY_IMAGE_DETAILS_PREFIX}${url}`,
|
|
2595
|
+
json
|
|
2613
2596
|
);
|
|
2614
|
-
|
|
2615
|
-
|
|
2597
|
+
cachedImageUrls.push(url);
|
|
2598
|
+
} catch (err) {}
|
|
2599
|
+
}
|
|
2616
2600
|
});
|
|
2601
|
+
imageDetailsCacheQueue.clear();
|
|
2602
|
+
sessionStorage.setItem(
|
|
2603
|
+
STORAGE_KEY_IMAGE_DETAILS_LIST,
|
|
2604
|
+
JSON.stringify(cachedImageUrls)
|
|
2605
|
+
);
|
|
2617
2606
|
}
|
|
2618
|
-
function
|
|
2619
|
-
|
|
2620
|
-
|
|
2607
|
+
function writeImageDetailsCache(url, imageDetails) {
|
|
2608
|
+
if (!url || !url.startsWith("https://")) {
|
|
2609
|
+
return;
|
|
2610
|
+
}
|
|
2611
|
+
imageDetailsCacheQueue.set(url, imageDetails);
|
|
2612
|
+
clearTimeout(imageCacheTimeout);
|
|
2613
|
+
imageCacheTimeout = setTimeout(writeImageDetailsQueue, 1000);
|
|
2621
2614
|
}
|
|
2622
|
-
function
|
|
2623
|
-
|
|
2615
|
+
function readImageDetailsCache(targetMap) {
|
|
2616
|
+
try {
|
|
2617
|
+
const jsonList = sessionStorage.getItem(
|
|
2618
|
+
STORAGE_KEY_IMAGE_DETAILS_LIST
|
|
2619
|
+
);
|
|
2620
|
+
if (!jsonList) {
|
|
2621
|
+
return;
|
|
2622
|
+
}
|
|
2623
|
+
const list = JSON.parse(jsonList);
|
|
2624
|
+
list.forEach((url) => {
|
|
2625
|
+
const json = sessionStorage.getItem(
|
|
2626
|
+
`${STORAGE_KEY_IMAGE_DETAILS_PREFIX}${url}`
|
|
2627
|
+
);
|
|
2628
|
+
if (json) {
|
|
2629
|
+
const details = JSON.parse(json);
|
|
2630
|
+
targetMap.set(url, details);
|
|
2631
|
+
}
|
|
2632
|
+
});
|
|
2633
|
+
} catch (err) {}
|
|
2624
2634
|
}
|
|
2625
|
-
function
|
|
2626
|
-
const
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2635
|
+
function writeCSSFetchCache(url, cssText) {
|
|
2636
|
+
const key = `${STORAGE_KEY_CSS_FETCH_PREFIX}${url}`;
|
|
2637
|
+
try {
|
|
2638
|
+
sessionStorage.setItem(key, cssText);
|
|
2639
|
+
} catch (err) {}
|
|
2640
|
+
}
|
|
2641
|
+
function readCSSFetchCache(url) {
|
|
2642
|
+
const key = `${STORAGE_KEY_CSS_FETCH_PREFIX}${url}`;
|
|
2643
|
+
try {
|
|
2644
|
+
return sessionStorage.getItem(key) ?? null;
|
|
2645
|
+
} catch (err) {}
|
|
2631
2646
|
return null;
|
|
2632
2647
|
}
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2648
|
+
|
|
2649
|
+
function toSVGMatrix(matrix) {
|
|
2650
|
+
return matrix
|
|
2651
|
+
.slice(0, 4)
|
|
2652
|
+
.map((m) => m.map((m) => m.toFixed(3)).join(" "))
|
|
2653
|
+
.join(" ");
|
|
2654
|
+
}
|
|
2655
|
+
function getSVGFilterMatrixValue(config) {
|
|
2656
|
+
return toSVGMatrix(createFilterMatrix(config));
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
const MAX_FRAME_DURATION = 1000 / 60;
|
|
2660
|
+
class AsyncQueue {
|
|
2661
|
+
constructor() {
|
|
2662
|
+
this.queue = [];
|
|
2663
|
+
this.timerId = null;
|
|
2642
2664
|
}
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
variablesSheet?.cssRules[0].style.setProperty(variable, value);
|
|
2665
|
+
addTask(task) {
|
|
2666
|
+
this.queue.push(task);
|
|
2667
|
+
this.scheduleFrame();
|
|
2647
2668
|
}
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
const border = [];
|
|
2653
|
-
const text = [];
|
|
2654
|
-
registeredColors.forEach((registered) => {
|
|
2655
|
-
if (registered.background) {
|
|
2656
|
-
background.push(registered.parsed);
|
|
2657
|
-
}
|
|
2658
|
-
if (registered.border) {
|
|
2659
|
-
border.push(registered.parsed);
|
|
2669
|
+
stop() {
|
|
2670
|
+
if (this.timerId !== null) {
|
|
2671
|
+
cancelAnimationFrame(this.timerId);
|
|
2672
|
+
this.timerId = null;
|
|
2660
2673
|
}
|
|
2661
|
-
|
|
2662
|
-
|
|
2674
|
+
this.queue = [];
|
|
2675
|
+
}
|
|
2676
|
+
scheduleFrame() {
|
|
2677
|
+
if (this.timerId) {
|
|
2678
|
+
return;
|
|
2663
2679
|
}
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2680
|
+
this.timerId = requestAnimationFrame(() => {
|
|
2681
|
+
this.timerId = null;
|
|
2682
|
+
const start = Date.now();
|
|
2683
|
+
let cb;
|
|
2684
|
+
while ((cb = this.queue.shift())) {
|
|
2685
|
+
cb();
|
|
2686
|
+
if (Date.now() - start >= MAX_FRAME_DURATION) {
|
|
2687
|
+
this.scheduleFrame();
|
|
2688
|
+
break;
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
});
|
|
2692
|
+
}
|
|
2669
2693
|
}
|
|
2670
2694
|
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
function clearColorModificationCache() {
|
|
2687
|
-
colorModificationCache.clear();
|
|
2688
|
-
}
|
|
2689
|
-
const rgbCacheKeys = ["r", "g", "b", "a"];
|
|
2690
|
-
const themeCacheKeys$1 = [
|
|
2691
|
-
"mode",
|
|
2692
|
-
"brightness",
|
|
2693
|
-
"contrast",
|
|
2694
|
-
"grayscale",
|
|
2695
|
-
"sepia",
|
|
2696
|
-
"darkSchemeBackgroundColor",
|
|
2697
|
-
"darkSchemeTextColor",
|
|
2698
|
-
"lightSchemeBackgroundColor",
|
|
2699
|
-
"lightSchemeTextColor"
|
|
2700
|
-
];
|
|
2701
|
-
function getCacheId(rgb, theme) {
|
|
2702
|
-
let resultId = "";
|
|
2703
|
-
rgbCacheKeys.forEach((key) => {
|
|
2704
|
-
resultId += `${rgb[key]};`;
|
|
2695
|
+
const resolvers$1 = new Map();
|
|
2696
|
+
const rejectors = new Map();
|
|
2697
|
+
async function bgFetch(request) {
|
|
2698
|
+
if (window.DarkReader?.Plugins?.fetch) {
|
|
2699
|
+
return window.DarkReader.Plugins.fetch(request);
|
|
2700
|
+
}
|
|
2701
|
+
return new Promise((resolve, reject) => {
|
|
2702
|
+
const id = generateUID();
|
|
2703
|
+
resolvers$1.set(id, resolve);
|
|
2704
|
+
rejectors.set(id, reject);
|
|
2705
|
+
chrome.runtime.sendMessage({
|
|
2706
|
+
type: MessageTypeCStoBG.FETCH,
|
|
2707
|
+
data: request,
|
|
2708
|
+
id
|
|
2709
|
+
});
|
|
2705
2710
|
});
|
|
2706
|
-
|
|
2707
|
-
|
|
2711
|
+
}
|
|
2712
|
+
chrome.runtime.onMessage.addListener(({type, data, error, id}) => {
|
|
2713
|
+
if (type === MessageTypeBGtoCS.FETCH_RESPONSE) {
|
|
2714
|
+
const resolve = resolvers$1.get(id);
|
|
2715
|
+
const reject = rejectors.get(id);
|
|
2716
|
+
resolvers$1.delete(id);
|
|
2717
|
+
rejectors.delete(id);
|
|
2718
|
+
if (error) {
|
|
2719
|
+
reject &&
|
|
2720
|
+
reject(
|
|
2721
|
+
typeof error === "string" ? new Error(error) : error
|
|
2722
|
+
);
|
|
2723
|
+
} else {
|
|
2724
|
+
resolve && resolve(data);
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
});
|
|
2728
|
+
|
|
2729
|
+
const imageManager = new AsyncQueue();
|
|
2730
|
+
async function getImageDetails(url) {
|
|
2731
|
+
return new Promise(async (resolve, reject) => {
|
|
2732
|
+
try {
|
|
2733
|
+
const dataURL = url.startsWith("data:")
|
|
2734
|
+
? url
|
|
2735
|
+
: await getDataURL(url);
|
|
2736
|
+
const blob =
|
|
2737
|
+
tryConvertDataURLToBlobSync(dataURL) ??
|
|
2738
|
+
(await loadAsBlob(url));
|
|
2739
|
+
let image;
|
|
2740
|
+
if (dataURL.startsWith("data:image/svg+xml")) {
|
|
2741
|
+
image = await loadImage(dataURL);
|
|
2742
|
+
} else {
|
|
2743
|
+
image =
|
|
2744
|
+
(await tryCreateImageBitmap(blob)) ??
|
|
2745
|
+
(await loadImage(dataURL));
|
|
2746
|
+
}
|
|
2747
|
+
imageManager.addTask(() => {
|
|
2748
|
+
const analysis = analyzeImage(image);
|
|
2749
|
+
resolve({
|
|
2750
|
+
src: url,
|
|
2751
|
+
dataURL: analysis.isLarge ? "" : dataURL,
|
|
2752
|
+
width: image.width,
|
|
2753
|
+
height: image.height,
|
|
2754
|
+
...analysis
|
|
2755
|
+
});
|
|
2756
|
+
});
|
|
2757
|
+
} catch (error) {
|
|
2758
|
+
reject(error);
|
|
2759
|
+
}
|
|
2708
2760
|
});
|
|
2709
|
-
return resultId;
|
|
2710
2761
|
}
|
|
2711
|
-
function
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
poleColor,
|
|
2716
|
-
anotherPoleColor
|
|
2717
|
-
) {
|
|
2718
|
-
let fnCache;
|
|
2719
|
-
if (colorModificationCache.has(modifyHSL)) {
|
|
2720
|
-
fnCache = colorModificationCache.get(modifyHSL);
|
|
2721
|
-
} else {
|
|
2722
|
-
fnCache = new Map();
|
|
2723
|
-
colorModificationCache.set(modifyHSL, fnCache);
|
|
2724
|
-
}
|
|
2725
|
-
const id = getCacheId(rgb, theme);
|
|
2726
|
-
if (fnCache.has(id)) {
|
|
2727
|
-
return fnCache.get(id);
|
|
2762
|
+
async function getDataURL(url) {
|
|
2763
|
+
const parsedURL = new URL(url);
|
|
2764
|
+
if (parsedURL.origin === location.origin) {
|
|
2765
|
+
return await loadAsDataURL(url);
|
|
2728
2766
|
}
|
|
2729
|
-
|
|
2730
|
-
const pole = poleColor == null ? null : parseToHSLWithCache(poleColor);
|
|
2731
|
-
const anotherPole =
|
|
2732
|
-
anotherPoleColor == null
|
|
2733
|
-
? null
|
|
2734
|
-
: parseToHSLWithCache(anotherPoleColor);
|
|
2735
|
-
const modified = modifyHSL(hsl, pole, anotherPole);
|
|
2736
|
-
const {r, g, b, a} = hslToRGB(modified);
|
|
2737
|
-
const matrix = createFilterMatrix(theme);
|
|
2738
|
-
const [rf, gf, bf] = applyColorMatrix([r, g, b], matrix);
|
|
2739
|
-
const color =
|
|
2740
|
-
a === 1
|
|
2741
|
-
? rgbToHexString({r: rf, g: gf, b: bf})
|
|
2742
|
-
: rgbToString({r: rf, g: gf, b: bf, a});
|
|
2743
|
-
fnCache.set(id, color);
|
|
2744
|
-
return color;
|
|
2767
|
+
return await bgFetch({url, responseType: "data-url"});
|
|
2745
2768
|
}
|
|
2746
|
-
function
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2769
|
+
async function tryCreateImageBitmap(blob) {
|
|
2770
|
+
try {
|
|
2771
|
+
return await createImageBitmap(blob);
|
|
2772
|
+
} catch (err) {
|
|
2773
|
+
logWarn(
|
|
2774
|
+
`Unable to create image bitmap for type ${blob.type}: ${String(err)}`
|
|
2775
|
+
);
|
|
2776
|
+
return null;
|
|
2750
2777
|
}
|
|
2751
|
-
const value = modifier(rgb, theme);
|
|
2752
|
-
return registerColor(type, rgb, value);
|
|
2753
|
-
}
|
|
2754
|
-
function modifyLightSchemeColor(rgb, theme) {
|
|
2755
|
-
const poleBg = getBgPole(theme);
|
|
2756
|
-
const poleFg = getFgPole(theme);
|
|
2757
|
-
return modifyColorWithCache(
|
|
2758
|
-
rgb,
|
|
2759
|
-
theme,
|
|
2760
|
-
modifyLightModeHSL,
|
|
2761
|
-
poleFg,
|
|
2762
|
-
poleBg
|
|
2763
|
-
);
|
|
2764
2778
|
}
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
if (isDark) {
|
|
2778
|
-
hx = poleFg.h;
|
|
2779
|
-
sx = poleFg.s;
|
|
2779
|
+
const INCOMPLETE_DOC_LOADING_IMAGE_LIMIT = 256;
|
|
2780
|
+
let loadingImagesCount = 0;
|
|
2781
|
+
async function loadImage(url) {
|
|
2782
|
+
return new Promise((resolve, reject) => {
|
|
2783
|
+
const image = new Image();
|
|
2784
|
+
image.onload = () => resolve(image);
|
|
2785
|
+
image.onerror = () => reject(`Unable to load image ${url}`);
|
|
2786
|
+
if (
|
|
2787
|
+
++loadingImagesCount <= INCOMPLETE_DOC_LOADING_IMAGE_LIMIT ||
|
|
2788
|
+
isReadyStateComplete()
|
|
2789
|
+
) {
|
|
2790
|
+
image.src = url;
|
|
2780
2791
|
} else {
|
|
2781
|
-
|
|
2782
|
-
sx = poleBg.s;
|
|
2792
|
+
addReadyStateCompleteListener(() => (image.src = url));
|
|
2783
2793
|
}
|
|
2784
|
-
}
|
|
2785
|
-
const lx = scale(l, 0, 1, poleFg.l, poleBg.l);
|
|
2786
|
-
return {h: hx, s: sx, l: lx, a};
|
|
2794
|
+
});
|
|
2787
2795
|
}
|
|
2788
|
-
const
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
const
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2796
|
+
const MAX_ANALYSIS_PIXELS_COUNT = 32 * 32;
|
|
2797
|
+
let canvas;
|
|
2798
|
+
let context;
|
|
2799
|
+
function createCanvas() {
|
|
2800
|
+
const maxWidth = MAX_ANALYSIS_PIXELS_COUNT;
|
|
2801
|
+
const maxHeight = MAX_ANALYSIS_PIXELS_COUNT;
|
|
2802
|
+
canvas = document.createElement("canvas");
|
|
2803
|
+
canvas.width = maxWidth;
|
|
2804
|
+
canvas.height = maxHeight;
|
|
2805
|
+
context = canvas.getContext("2d", {willReadFrequently: true});
|
|
2806
|
+
context.imageSmoothingEnabled = false;
|
|
2807
|
+
}
|
|
2808
|
+
function removeCanvas() {
|
|
2809
|
+
canvas = null;
|
|
2810
|
+
context = null;
|
|
2811
|
+
}
|
|
2812
|
+
const LARGE_IMAGE_PIXELS_COUNT = 512 * 512;
|
|
2813
|
+
function analyzeImage(image) {
|
|
2814
|
+
if (!canvas) {
|
|
2815
|
+
createCanvas();
|
|
2801
2816
|
}
|
|
2802
|
-
let
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2817
|
+
let sw;
|
|
2818
|
+
let sh;
|
|
2819
|
+
if (image instanceof HTMLImageElement) {
|
|
2820
|
+
sw = image.naturalWidth;
|
|
2821
|
+
sh = image.naturalHeight;
|
|
2822
|
+
} else {
|
|
2823
|
+
sw = image.width;
|
|
2824
|
+
sh = image.height;
|
|
2807
2825
|
}
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
}
|
|
2826
|
+
if (sw === 0 || sh === 0) {
|
|
2827
|
+
logWarn("Image is empty");
|
|
2828
|
+
return {
|
|
2829
|
+
isDark: false,
|
|
2830
|
+
isLight: false,
|
|
2831
|
+
isTransparent: false,
|
|
2832
|
+
isLarge: false
|
|
2833
|
+
};
|
|
2817
2834
|
}
|
|
2818
|
-
|
|
2819
|
-
|
|
2835
|
+
const isLarge = sw * sh > LARGE_IMAGE_PIXELS_COUNT;
|
|
2836
|
+
const sourcePixelsCount = sw * sh;
|
|
2837
|
+
const k = Math.min(
|
|
2838
|
+
1,
|
|
2839
|
+
Math.sqrt(MAX_ANALYSIS_PIXELS_COUNT / sourcePixelsCount)
|
|
2840
|
+
);
|
|
2841
|
+
const width = Math.ceil(sw * k);
|
|
2842
|
+
const height = Math.ceil(sh * k);
|
|
2843
|
+
context.clearRect(0, 0, width, height);
|
|
2844
|
+
context.drawImage(image, 0, 0, sw, sh, 0, 0, width, height);
|
|
2845
|
+
const imageData = context.getImageData(0, 0, width, height);
|
|
2846
|
+
const d = imageData.data;
|
|
2847
|
+
const TRANSPARENT_ALPHA_THRESHOLD = 0.05;
|
|
2848
|
+
const DARK_LIGHTNESS_THRESHOLD = 0.4;
|
|
2849
|
+
const LIGHT_LIGHTNESS_THRESHOLD = 0.7;
|
|
2850
|
+
let transparentPixelsCount = 0;
|
|
2851
|
+
let darkPixelsCount = 0;
|
|
2852
|
+
let lightPixelsCount = 0;
|
|
2853
|
+
let i, x, y;
|
|
2854
|
+
let r, g, b, a;
|
|
2855
|
+
let l;
|
|
2856
|
+
for (y = 0; y < height; y++) {
|
|
2857
|
+
for (x = 0; x < width; x++) {
|
|
2858
|
+
i = 4 * (y * width + x);
|
|
2859
|
+
r = d[i + 0];
|
|
2860
|
+
g = d[i + 1];
|
|
2861
|
+
b = d[i + 2];
|
|
2862
|
+
a = d[i + 3];
|
|
2863
|
+
if (a / 255 < TRANSPARENT_ALPHA_THRESHOLD) {
|
|
2864
|
+
transparentPixelsCount++;
|
|
2865
|
+
} else {
|
|
2866
|
+
l = getSRGBLightness(r, g, b);
|
|
2867
|
+
if (l < DARK_LIGHTNESS_THRESHOLD) {
|
|
2868
|
+
darkPixelsCount++;
|
|
2869
|
+
}
|
|
2870
|
+
if (l > LIGHT_LIGHTNESS_THRESHOLD) {
|
|
2871
|
+
lightPixelsCount++;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2820
2875
|
}
|
|
2821
|
-
|
|
2876
|
+
const totalPixelsCount = width * height;
|
|
2877
|
+
const opaquePixelsCount = totalPixelsCount - transparentPixelsCount;
|
|
2878
|
+
const DARK_IMAGE_THRESHOLD = 0.7;
|
|
2879
|
+
const LIGHT_IMAGE_THRESHOLD = 0.7;
|
|
2880
|
+
const TRANSPARENT_IMAGE_THRESHOLD = 0.1;
|
|
2881
|
+
return {
|
|
2882
|
+
isDark: darkPixelsCount / opaquePixelsCount >= DARK_IMAGE_THRESHOLD,
|
|
2883
|
+
isLight:
|
|
2884
|
+
lightPixelsCount / opaquePixelsCount >= LIGHT_IMAGE_THRESHOLD,
|
|
2885
|
+
isTransparent:
|
|
2886
|
+
transparentPixelsCount / totalPixelsCount >=
|
|
2887
|
+
TRANSPARENT_IMAGE_THRESHOLD,
|
|
2888
|
+
isLarge
|
|
2889
|
+
};
|
|
2822
2890
|
}
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2891
|
+
let isBlobURLSupported = null;
|
|
2892
|
+
let canUseProxy = false;
|
|
2893
|
+
let blobURLCheckRequested = false;
|
|
2894
|
+
const blobURLCheckAwaiters = [];
|
|
2895
|
+
document.addEventListener(
|
|
2896
|
+
"__darkreader__inlineScriptsAllowed",
|
|
2897
|
+
() => (canUseProxy = true),
|
|
2898
|
+
{once: true}
|
|
2899
|
+
);
|
|
2900
|
+
async function requestBlobURLCheck() {
|
|
2901
|
+
if (!canUseProxy) {
|
|
2902
|
+
return;
|
|
2826
2903
|
}
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
)
|
|
2904
|
+
if (blobURLCheckRequested) {
|
|
2905
|
+
return await new Promise((resolve) =>
|
|
2906
|
+
blobURLCheckAwaiters.push(resolve)
|
|
2907
|
+
);
|
|
2908
|
+
}
|
|
2909
|
+
blobURLCheckRequested = true;
|
|
2910
|
+
await new Promise((resolve) => {
|
|
2911
|
+
document.addEventListener(
|
|
2912
|
+
"__darkreader__blobURLCheckResponse",
|
|
2913
|
+
(e) => {
|
|
2914
|
+
isBlobURLSupported = e.detail.blobURLAllowed;
|
|
2915
|
+
resolve();
|
|
2916
|
+
blobURLCheckAwaiters.forEach((r) => r());
|
|
2917
|
+
blobURLCheckAwaiters.splice(0);
|
|
2918
|
+
},
|
|
2919
|
+
{once: true}
|
|
2920
|
+
);
|
|
2921
|
+
document.dispatchEvent(
|
|
2922
|
+
new CustomEvent("__darkreader__blobURLCheckRequest")
|
|
2923
|
+
);
|
|
2924
|
+
});
|
|
2834
2925
|
}
|
|
2835
|
-
function
|
|
2836
|
-
|
|
2837
|
-
theme,
|
|
2838
|
-
shouldRegisterColorVariable = true
|
|
2839
|
-
) {
|
|
2840
|
-
if (!shouldRegisterColorVariable) {
|
|
2841
|
-
return _modifyBackgroundColor(rgb, theme);
|
|
2842
|
-
}
|
|
2843
|
-
return modifyAndRegisterColor(
|
|
2844
|
-
"background",
|
|
2845
|
-
rgb,
|
|
2846
|
-
theme,
|
|
2847
|
-
_modifyBackgroundColor
|
|
2848
|
-
);
|
|
2926
|
+
function isBlobURLCheckResultReady() {
|
|
2927
|
+
return isBlobURLSupported != null || !canUseProxy;
|
|
2849
2928
|
}
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2929
|
+
function onCSPError(err) {
|
|
2930
|
+
if (err.blockedURI === "blob") {
|
|
2931
|
+
isBlobURLSupported = false;
|
|
2932
|
+
document.removeEventListener("securitypolicyviolation", onCSPError);
|
|
2933
|
+
}
|
|
2853
2934
|
}
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
const lx = scale(l, 0.5, 1, MIN_FG_LIGHTNESS, pole.l);
|
|
2860
|
-
if (isNeutral) {
|
|
2861
|
-
const hx = pole.h;
|
|
2862
|
-
const sx = pole.s;
|
|
2863
|
-
return {h: hx, s: sx, l: lx, a};
|
|
2864
|
-
}
|
|
2865
|
-
let hx = h;
|
|
2866
|
-
if (isBlue) {
|
|
2867
|
-
hx = modifyBlueFgHue(h);
|
|
2868
|
-
}
|
|
2869
|
-
return {h: hx, s, l: lx, a};
|
|
2935
|
+
document.addEventListener("securitypolicyviolation", onCSPError);
|
|
2936
|
+
const objectURLs = new Set();
|
|
2937
|
+
function getFilteredImageURL({dataURL, width, height}, theme) {
|
|
2938
|
+
if (dataURL.startsWith("data:image/svg+xml")) {
|
|
2939
|
+
dataURL = escapeXML(dataURL);
|
|
2870
2940
|
}
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2941
|
+
const matrix = getSVGFilterMatrixValue(theme);
|
|
2942
|
+
const svg = [
|
|
2943
|
+
`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${width}" height="${height}">`,
|
|
2944
|
+
"<defs>",
|
|
2945
|
+
'<filter id="darkreader-image-filter">',
|
|
2946
|
+
`<feColorMatrix type="matrix" values="${matrix}" />`,
|
|
2947
|
+
"</filter>",
|
|
2948
|
+
"</defs>",
|
|
2949
|
+
`<image width="${width}" height="${height}" filter="url(#darkreader-image-filter)" xlink:href="${dataURL}" />`,
|
|
2950
|
+
"</svg>"
|
|
2951
|
+
].join("");
|
|
2952
|
+
if (!isBlobURLSupported) {
|
|
2953
|
+
return `data:image/svg+xml;base64,${btoa(svg)}`;
|
|
2876
2954
|
}
|
|
2877
|
-
|
|
2878
|
-
let
|
|
2879
|
-
|
|
2880
|
-
hx = modifyBlueFgHue(h);
|
|
2881
|
-
lx = scale(l, 0, 0.5, pole.l, Math.min(1, MIN_FG_LIGHTNESS + 0.05));
|
|
2882
|
-
} else {
|
|
2883
|
-
lx = scale(l, 0, 0.5, pole.l, MIN_FG_LIGHTNESS);
|
|
2955
|
+
const bytes = new Uint8Array(svg.length);
|
|
2956
|
+
for (let i = 0; i < svg.length; i++) {
|
|
2957
|
+
bytes[i] = svg.charCodeAt(i);
|
|
2884
2958
|
}
|
|
2885
|
-
|
|
2959
|
+
const blob = new Blob([bytes], {type: "image/svg+xml"});
|
|
2960
|
+
const objectURL = URL.createObjectURL(blob);
|
|
2961
|
+
objectURLs.add(objectURL);
|
|
2962
|
+
return objectURL;
|
|
2886
2963
|
}
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
pole
|
|
2897
|
-
);
|
|
2964
|
+
const xmlEscapeChars = {
|
|
2965
|
+
"<": "<",
|
|
2966
|
+
">": ">",
|
|
2967
|
+
"&": "&",
|
|
2968
|
+
"'": "'",
|
|
2969
|
+
'"': """
|
|
2970
|
+
};
|
|
2971
|
+
function escapeXML(str) {
|
|
2972
|
+
return str.replace(/[<>&'"]/g, (c) => xmlEscapeChars[c] ?? c);
|
|
2898
2973
|
}
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2974
|
+
const dataURLBlobURLs = new Map();
|
|
2975
|
+
function tryConvertDataURLToBlobSync(dataURL) {
|
|
2976
|
+
const colonIndex = dataURL.indexOf(":");
|
|
2977
|
+
const semicolonIndex = dataURL.indexOf(";", colonIndex + 1);
|
|
2978
|
+
const commaIndex = dataURL.indexOf(",", semicolonIndex + 1);
|
|
2979
|
+
const encoding = dataURL
|
|
2980
|
+
.substring(semicolonIndex + 1, commaIndex)
|
|
2981
|
+
.toLocaleLowerCase();
|
|
2982
|
+
const mediaType = dataURL.substring(colonIndex + 1, semicolonIndex);
|
|
2983
|
+
if (encoding !== "base64" || !mediaType) {
|
|
2984
|
+
return null;
|
|
2906
2985
|
}
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
_modifyForegroundColor
|
|
2912
|
-
);
|
|
2913
|
-
}
|
|
2914
|
-
function modifyBorderHSL({h, s, l, a}, poleFg, poleBg) {
|
|
2915
|
-
const isDark = l < 0.5;
|
|
2916
|
-
const isNeutral = l < 0.2 || s < 0.24;
|
|
2917
|
-
let hx = h;
|
|
2918
|
-
let sx = s;
|
|
2919
|
-
if (isNeutral) {
|
|
2920
|
-
if (isDark) {
|
|
2921
|
-
hx = poleFg.h;
|
|
2922
|
-
sx = poleFg.s;
|
|
2923
|
-
} else {
|
|
2924
|
-
hx = poleBg.h;
|
|
2925
|
-
sx = poleBg.s;
|
|
2926
|
-
}
|
|
2986
|
+
const characters = atob(dataURL.substring(commaIndex + 1));
|
|
2987
|
+
const bytes = new Uint8Array(characters.length);
|
|
2988
|
+
for (let i = 0; i < characters.length; i++) {
|
|
2989
|
+
bytes[i] = characters.charCodeAt(i);
|
|
2927
2990
|
}
|
|
2928
|
-
|
|
2929
|
-
return {h: hx, s: sx, l: lx, a};
|
|
2991
|
+
return new Blob([bytes], {type: mediaType});
|
|
2930
2992
|
}
|
|
2931
|
-
function
|
|
2932
|
-
if (
|
|
2933
|
-
return
|
|
2993
|
+
async function tryConvertDataURLToBlobURL(dataURL) {
|
|
2994
|
+
if (!isBlobURLSupported) {
|
|
2995
|
+
return null;
|
|
2934
2996
|
}
|
|
2935
|
-
const
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
{...theme, mode: 0},
|
|
2940
|
-
modifyBorderHSL,
|
|
2941
|
-
poleFg,
|
|
2942
|
-
poleBg
|
|
2943
|
-
);
|
|
2944
|
-
}
|
|
2945
|
-
function modifyBorderColor(rgb, theme, shouldRegisterColorVariable = true) {
|
|
2946
|
-
if (!shouldRegisterColorVariable) {
|
|
2947
|
-
return _modifyBorderColor(rgb, theme);
|
|
2997
|
+
const hash = getHashCode(dataURL);
|
|
2998
|
+
let blobURL = dataURLBlobURLs.get(hash);
|
|
2999
|
+
if (blobURL) {
|
|
3000
|
+
return blobURL;
|
|
2948
3001
|
}
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
3002
|
+
let blob = tryConvertDataURLToBlobSync(dataURL);
|
|
3003
|
+
if (!blob) {
|
|
3004
|
+
const response = await fetch(dataURL);
|
|
3005
|
+
blob = await response.blob();
|
|
3006
|
+
}
|
|
3007
|
+
blobURL = URL.createObjectURL(blob);
|
|
3008
|
+
dataURLBlobURLs.set(hash, blobURL);
|
|
3009
|
+
return blobURL;
|
|
2953
3010
|
}
|
|
2954
|
-
function
|
|
2955
|
-
|
|
3011
|
+
function cleanImageProcessingCache() {
|
|
3012
|
+
imageManager && imageManager.stop();
|
|
3013
|
+
removeCanvas();
|
|
3014
|
+
objectURLs.forEach((u) => URL.revokeObjectURL(u));
|
|
3015
|
+
objectURLs.clear();
|
|
3016
|
+
dataURLBlobURLs.forEach((u) => URL.revokeObjectURL(u));
|
|
3017
|
+
dataURLBlobURLs.clear();
|
|
2956
3018
|
}
|
|
2957
3019
|
|
|
2958
3020
|
function getPriority(ruleStyle, property) {
|
|
@@ -3223,10 +3285,18 @@
|
|
|
3223
3285
|
"auto"
|
|
3224
3286
|
]);
|
|
3225
3287
|
function getColorModifier(prop, value, rule) {
|
|
3226
|
-
if (
|
|
3288
|
+
if (
|
|
3289
|
+
unparsableColors.has(value.toLowerCase()) &&
|
|
3290
|
+
!(prop === "color" && value === "initial")
|
|
3291
|
+
) {
|
|
3227
3292
|
return value;
|
|
3228
3293
|
}
|
|
3229
|
-
|
|
3294
|
+
let rgb = null;
|
|
3295
|
+
if (prop === "color" && value === "initial") {
|
|
3296
|
+
rgb = {r: 0, g: 0, b: 0, a: 1};
|
|
3297
|
+
} else {
|
|
3298
|
+
rgb = parseColorWithCache(value);
|
|
3299
|
+
}
|
|
3230
3300
|
if (!rgb) {
|
|
3231
3301
|
logWarn("Couldn't parse color", value);
|
|
3232
3302
|
return null;
|
|
@@ -3655,7 +3725,7 @@
|
|
|
3655
3725
|
return null;
|
|
3656
3726
|
}
|
|
3657
3727
|
return (theme) =>
|
|
3658
|
-
`${modifyForegroundColor(thumb, theme)} ${modifyBackgroundColor(
|
|
3728
|
+
`${modifyForegroundColor(thumb, theme)} ${modifyBackgroundColor(track, theme)}`;
|
|
3659
3729
|
}
|
|
3660
3730
|
function getColorSchemeModifier() {
|
|
3661
3731
|
return (theme) => (theme.mode === 0 ? "dark light" : "dark");
|
|
@@ -4014,7 +4084,7 @@
|
|
|
4014
4084
|
const modified = modify();
|
|
4015
4085
|
if (unknownVars.size > 0) {
|
|
4016
4086
|
const isFallbackResolved = modified.match(
|
|
4017
|
-
/^var\(.*?, (var\(--darkreader-bg--.*\))|(#[0-9A-Fa-f]+)|([a-z]+)|(rgba?\(.+\))|(hsla?\(.+\))\)$/
|
|
4087
|
+
/^var\(.*?, ((var\(--darkreader-bg--.*\))|(#[0-9A-Fa-f]+)|([a-z]+)|(rgba?\(.+\))|(hsla?\(.+\)))\)$/
|
|
4018
4088
|
);
|
|
4019
4089
|
if (isFallbackResolved) {
|
|
4020
4090
|
return modified;
|
|
@@ -4492,17 +4562,6 @@
|
|
|
4492
4562
|
return replaced;
|
|
4493
4563
|
}
|
|
4494
4564
|
|
|
4495
|
-
const themeCacheKeys = [
|
|
4496
|
-
"mode",
|
|
4497
|
-
"brightness",
|
|
4498
|
-
"contrast",
|
|
4499
|
-
"grayscale",
|
|
4500
|
-
"sepia",
|
|
4501
|
-
"darkSchemeBackgroundColor",
|
|
4502
|
-
"darkSchemeTextColor",
|
|
4503
|
-
"lightSchemeBackgroundColor",
|
|
4504
|
-
"lightSchemeTextColor"
|
|
4505
|
-
];
|
|
4506
4565
|
function getThemeKey(theme) {
|
|
4507
4566
|
let resultKey = "";
|
|
4508
4567
|
themeCacheKeys.forEach((key) => {
|
|
@@ -4816,6 +4875,12 @@
|
|
|
4816
4875
|
function buildStyleSheet() {
|
|
4817
4876
|
function createTarget(group, parent) {
|
|
4818
4877
|
const {rule} = group;
|
|
4878
|
+
if (isStyleRule(rule)) {
|
|
4879
|
+
const {selectorText} = rule;
|
|
4880
|
+
const index = parent.cssRules.length;
|
|
4881
|
+
parent.insertRule(`${selectorText} {}`, index);
|
|
4882
|
+
return parent.cssRules[index];
|
|
4883
|
+
}
|
|
4819
4884
|
if (isMediaRule(rule)) {
|
|
4820
4885
|
const {media} = rule;
|
|
4821
4886
|
const index = parent.cssRules.length;
|
|
@@ -5123,6 +5188,27 @@
|
|
|
5123
5188
|
return {render, destroy, commands};
|
|
5124
5189
|
}
|
|
5125
5190
|
|
|
5191
|
+
const hostsBreakingOnStylePosition = ["www.diffusioneshop.com", "zhale.me"];
|
|
5192
|
+
const mode = hostsBreakingOnStylePosition.includes(location.hostname)
|
|
5193
|
+
? "away"
|
|
5194
|
+
: "next";
|
|
5195
|
+
function getStyleInjectionMode() {
|
|
5196
|
+
return mode;
|
|
5197
|
+
}
|
|
5198
|
+
function injectStyleAway(styleElement) {
|
|
5199
|
+
let container = document.body.querySelector(
|
|
5200
|
+
".darkreader-style-container"
|
|
5201
|
+
);
|
|
5202
|
+
if (!container) {
|
|
5203
|
+
container = document.createElement("div");
|
|
5204
|
+
container.classList.add("darkreader");
|
|
5205
|
+
container.classList.add("darkreader-style-container");
|
|
5206
|
+
container.style.display = "none";
|
|
5207
|
+
document.body.append(container);
|
|
5208
|
+
}
|
|
5209
|
+
container.append(styleElement);
|
|
5210
|
+
}
|
|
5211
|
+
|
|
5126
5212
|
const overrides = {
|
|
5127
5213
|
"background-color": {
|
|
5128
5214
|
customProp: "--darkreader-inline-bgcolor",
|
|
@@ -5923,22 +6009,29 @@
|
|
|
5923
6009
|
rejectorsForLoadingLinks.clear();
|
|
5924
6010
|
}
|
|
5925
6011
|
function manageStyle(element, {update, loadingStart, loadingEnd}) {
|
|
5926
|
-
const
|
|
5927
|
-
let
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
6012
|
+
const inMode = getStyleInjectionMode();
|
|
6013
|
+
let corsCopy = null;
|
|
6014
|
+
let syncStyle = null;
|
|
6015
|
+
if (inMode === "next") {
|
|
6016
|
+
const prevStyles = [];
|
|
6017
|
+
let next = element;
|
|
6018
|
+
while (
|
|
6019
|
+
(next = next.nextElementSibling) &&
|
|
6020
|
+
next.matches(".darkreader")
|
|
6021
|
+
) {
|
|
6022
|
+
prevStyles.push(next);
|
|
6023
|
+
}
|
|
6024
|
+
corsCopy =
|
|
6025
|
+
prevStyles.find(
|
|
6026
|
+
(el) =>
|
|
6027
|
+
el.matches(".darkreader--cors") && !corsStyleSet.has(el)
|
|
6028
|
+
) || null;
|
|
6029
|
+
syncStyle =
|
|
6030
|
+
prevStyles.find(
|
|
6031
|
+
(el) =>
|
|
6032
|
+
el.matches(".darkreader--sync") && !syncStyleSet.has(el)
|
|
6033
|
+
) || null;
|
|
6034
|
+
}
|
|
5942
6035
|
let corsCopyPositionWatcher = null;
|
|
5943
6036
|
let syncStylePositionWatcher = null;
|
|
5944
6037
|
let cancelAsyncOperations = false;
|
|
@@ -6023,21 +6116,31 @@
|
|
|
6023
6116
|
return cssRules;
|
|
6024
6117
|
}
|
|
6025
6118
|
function insertStyle() {
|
|
6026
|
-
if (
|
|
6027
|
-
if (
|
|
6119
|
+
if (inMode === "next") {
|
|
6120
|
+
if (corsCopy) {
|
|
6121
|
+
if (element.nextSibling !== corsCopy) {
|
|
6122
|
+
element.parentNode.insertBefore(
|
|
6123
|
+
corsCopy,
|
|
6124
|
+
element.nextSibling
|
|
6125
|
+
);
|
|
6126
|
+
}
|
|
6127
|
+
if (corsCopy.nextSibling !== syncStyle) {
|
|
6128
|
+
element.parentNode.insertBefore(
|
|
6129
|
+
syncStyle,
|
|
6130
|
+
corsCopy.nextSibling
|
|
6131
|
+
);
|
|
6132
|
+
}
|
|
6133
|
+
} else if (element.nextSibling !== syncStyle) {
|
|
6028
6134
|
element.parentNode.insertBefore(
|
|
6029
|
-
|
|
6135
|
+
syncStyle,
|
|
6030
6136
|
element.nextSibling
|
|
6031
6137
|
);
|
|
6032
6138
|
}
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
corsCopy.nextSibling
|
|
6037
|
-
);
|
|
6139
|
+
} else if (inMode === "away") {
|
|
6140
|
+
if (corsCopy && !corsCopy.parentNode) {
|
|
6141
|
+
injectStyleAway(corsCopy);
|
|
6038
6142
|
}
|
|
6039
|
-
|
|
6040
|
-
element.parentNode.insertBefore(syncStyle, element.nextSibling);
|
|
6143
|
+
injectStyleAway(syncStyle);
|
|
6041
6144
|
}
|
|
6042
6145
|
}
|
|
6043
6146
|
function createSyncStyle() {
|
|
@@ -6095,7 +6198,12 @@
|
|
|
6095
6198
|
return cssRules;
|
|
6096
6199
|
}
|
|
6097
6200
|
}
|
|
6098
|
-
|
|
6201
|
+
try {
|
|
6202
|
+
cssText = await loadText(element.href);
|
|
6203
|
+
} catch (err) {
|
|
6204
|
+
logWarn(err);
|
|
6205
|
+
cssText = "";
|
|
6206
|
+
}
|
|
6099
6207
|
cssBasePath = getCSSBaseBath(element.href);
|
|
6100
6208
|
if (cancelAsyncOperations) {
|
|
6101
6209
|
return null;
|
|
@@ -6127,12 +6235,31 @@
|
|
|
6127
6235
|
corsCopy.textContent = fullCSSText;
|
|
6128
6236
|
}
|
|
6129
6237
|
} else {
|
|
6130
|
-
corsCopy = createCORSCopy(
|
|
6238
|
+
corsCopy = createCORSCopy(
|
|
6239
|
+
fullCSSText,
|
|
6240
|
+
inMode === "next"
|
|
6241
|
+
? (cc) =>
|
|
6242
|
+
element.parentNode.insertBefore(
|
|
6243
|
+
cc,
|
|
6244
|
+
element.nextSibling
|
|
6245
|
+
)
|
|
6246
|
+
: injectStyleAway
|
|
6247
|
+
);
|
|
6248
|
+
if (corsCopy) {
|
|
6249
|
+
if (inMode === "next") {
|
|
6250
|
+
element.parentNode.insertBefore(
|
|
6251
|
+
corsCopy,
|
|
6252
|
+
element.nextSibling
|
|
6253
|
+
);
|
|
6254
|
+
} else if (inMode === "away") {
|
|
6255
|
+
injectStyleAway(corsCopy);
|
|
6256
|
+
}
|
|
6257
|
+
}
|
|
6131
6258
|
}
|
|
6132
6259
|
} catch (err) {
|
|
6133
6260
|
logWarn(err);
|
|
6134
6261
|
}
|
|
6135
|
-
if (corsCopy) {
|
|
6262
|
+
if (corsCopy && inMode === "next") {
|
|
6136
6263
|
corsCopyPositionWatcher = watchForNodePosition(
|
|
6137
6264
|
corsCopy,
|
|
6138
6265
|
"prev-sibling"
|
|
@@ -6199,7 +6326,7 @@
|
|
|
6199
6326
|
removeCSSRulesFromSheet(sheet);
|
|
6200
6327
|
if (syncStylePositionWatcher) {
|
|
6201
6328
|
syncStylePositionWatcher.run();
|
|
6202
|
-
} else {
|
|
6329
|
+
} else if (inMode === "next") {
|
|
6203
6330
|
syncStylePositionWatcher = watchForNodePosition(
|
|
6204
6331
|
syncStyle,
|
|
6205
6332
|
"prev-sibling",
|
|
@@ -6422,7 +6549,7 @@
|
|
|
6422
6549
|
cssText = cssText.trim();
|
|
6423
6550
|
return cssText;
|
|
6424
6551
|
}
|
|
6425
|
-
function createCORSCopy(
|
|
6552
|
+
function createCORSCopy(cssText, inject) {
|
|
6426
6553
|
if (!cssText) {
|
|
6427
6554
|
return null;
|
|
6428
6555
|
}
|
|
@@ -6431,7 +6558,7 @@
|
|
|
6431
6558
|
cors.classList.add("darkreader--cors");
|
|
6432
6559
|
cors.media = "screen";
|
|
6433
6560
|
cors.textContent = cssText;
|
|
6434
|
-
|
|
6561
|
+
inject(cors);
|
|
6435
6562
|
cors.sheet.disabled = true;
|
|
6436
6563
|
corsStyleSet.add(cors);
|
|
6437
6564
|
return cors;
|
|
@@ -6675,7 +6802,7 @@
|
|
|
6675
6802
|
);
|
|
6676
6803
|
}
|
|
6677
6804
|
let blobURLAllowed = null;
|
|
6678
|
-
|
|
6805
|
+
function checkBlobURLSupport() {
|
|
6679
6806
|
if (blobURLAllowed != null) {
|
|
6680
6807
|
document.dispatchEvent(
|
|
6681
6808
|
new CustomEvent("__darkreader__blobURLCheckResponse", {
|
|
@@ -6692,17 +6819,18 @@
|
|
|
6692
6819
|
}
|
|
6693
6820
|
const blob = new Blob([bytes], {type: "image/svg+xml"});
|
|
6694
6821
|
const objectURL = URL.createObjectURL(blob);
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
await new Promise((resolve, reject) => {
|
|
6698
|
-
image.onload = () => resolve();
|
|
6699
|
-
image.onerror = () => reject();
|
|
6700
|
-
image.src = objectURL;
|
|
6701
|
-
});
|
|
6822
|
+
const image = new Image();
|
|
6823
|
+
image.onload = () => {
|
|
6702
6824
|
blobURLAllowed = true;
|
|
6703
|
-
|
|
6825
|
+
sendBlobURLCheckResponse();
|
|
6826
|
+
};
|
|
6827
|
+
image.onerror = () => {
|
|
6704
6828
|
blobURLAllowed = false;
|
|
6705
|
-
|
|
6829
|
+
sendBlobURLCheckResponse();
|
|
6830
|
+
};
|
|
6831
|
+
image.src = objectURL;
|
|
6832
|
+
}
|
|
6833
|
+
function sendBlobURLCheckResponse() {
|
|
6706
6834
|
document.dispatchEvent(
|
|
6707
6835
|
new CustomEvent("__darkreader__blobURLCheckResponse", {
|
|
6708
6836
|
detail: {blobURLAllowed}
|
|
@@ -7233,20 +7361,24 @@
|
|
|
7233
7361
|
let isIFrame$1 = null;
|
|
7234
7362
|
let ignoredImageAnalysisSelectors = [];
|
|
7235
7363
|
let ignoredInlineSelectors = [];
|
|
7236
|
-
|
|
7364
|
+
let staticStyleMap = new WeakMap();
|
|
7237
7365
|
function createOrUpdateStyle(className, root = document.head || document) {
|
|
7238
7366
|
let element = root.querySelector(`.${className}`);
|
|
7367
|
+
if (!staticStyleMap.has(root)) {
|
|
7368
|
+
staticStyleMap.set(root, new Map());
|
|
7369
|
+
}
|
|
7370
|
+
const classMap = staticStyleMap.get(root);
|
|
7239
7371
|
if (element) {
|
|
7240
|
-
|
|
7241
|
-
} else if (
|
|
7242
|
-
element =
|
|
7372
|
+
classMap.set(className, element);
|
|
7373
|
+
} else if (classMap.has(className)) {
|
|
7374
|
+
element = classMap.get(className);
|
|
7243
7375
|
} else {
|
|
7244
7376
|
element = document.createElement("style");
|
|
7245
7377
|
element.classList.add("darkreader");
|
|
7246
7378
|
element.classList.add(className);
|
|
7247
7379
|
element.media = "screen";
|
|
7248
7380
|
element.textContent = "";
|
|
7249
|
-
|
|
7381
|
+
classMap.set(className, element);
|
|
7250
7382
|
}
|
|
7251
7383
|
return element;
|
|
7252
7384
|
}
|
|
@@ -7272,6 +7404,18 @@
|
|
|
7272
7404
|
forEach(nodePositionWatchers.values(), (watcher) => watcher.stop());
|
|
7273
7405
|
nodePositionWatchers.clear();
|
|
7274
7406
|
}
|
|
7407
|
+
function injectStaticStyle(style, prevNode, watchAlias, callback) {
|
|
7408
|
+
const mode = getStyleInjectionMode();
|
|
7409
|
+
if (mode === "next") {
|
|
7410
|
+
document.head.insertBefore(
|
|
7411
|
+
style,
|
|
7412
|
+
prevNode ? prevNode.nextSibling : document.head.firstChild
|
|
7413
|
+
);
|
|
7414
|
+
setupNodePositionWatcher(style, watchAlias, callback);
|
|
7415
|
+
} else if (mode === "away") {
|
|
7416
|
+
injectStyleAway(style);
|
|
7417
|
+
}
|
|
7418
|
+
}
|
|
7275
7419
|
function createStaticStyleOverrides() {
|
|
7276
7420
|
const fallbackStyle = createOrUpdateStyle(
|
|
7277
7421
|
"darkreader--fallback",
|
|
@@ -7280,24 +7424,21 @@
|
|
|
7280
7424
|
fallbackStyle.textContent = getModifiedFallbackStyle(theme, {
|
|
7281
7425
|
strict: true
|
|
7282
7426
|
});
|
|
7283
|
-
|
|
7284
|
-
setupNodePositionWatcher(fallbackStyle, "fallback");
|
|
7427
|
+
injectStaticStyle(fallbackStyle, null, "fallback");
|
|
7285
7428
|
const userAgentStyle = createOrUpdateStyle("darkreader--user-agent");
|
|
7286
7429
|
userAgentStyle.textContent = getModifiedUserAgentStyle(
|
|
7287
7430
|
theme,
|
|
7288
7431
|
isIFrame$1,
|
|
7289
7432
|
theme.styleSystemControls
|
|
7290
7433
|
);
|
|
7291
|
-
|
|
7292
|
-
setupNodePositionWatcher(userAgentStyle, "user-agent");
|
|
7434
|
+
injectStaticStyle(userAgentStyle, fallbackStyle, "user-agent");
|
|
7293
7435
|
const textStyle = createOrUpdateStyle("darkreader--text");
|
|
7294
7436
|
if (theme.useFont || theme.textStroke > 0) {
|
|
7295
7437
|
textStyle.textContent = createTextStyle(theme);
|
|
7296
7438
|
} else {
|
|
7297
7439
|
textStyle.textContent = "";
|
|
7298
7440
|
}
|
|
7299
|
-
|
|
7300
|
-
setupNodePositionWatcher(textStyle, "text");
|
|
7441
|
+
injectStaticStyle(textStyle, userAgentStyle, "text");
|
|
7301
7442
|
const invertStyle = createOrUpdateStyle("darkreader--invert");
|
|
7302
7443
|
if (fixes && Array.isArray(fixes.invert) && fixes.invert.length > 0) {
|
|
7303
7444
|
invertStyle.textContent = [
|
|
@@ -7314,17 +7455,10 @@
|
|
|
7314
7455
|
} else {
|
|
7315
7456
|
invertStyle.textContent = "";
|
|
7316
7457
|
}
|
|
7317
|
-
|
|
7318
|
-
setupNodePositionWatcher(invertStyle, "invert");
|
|
7458
|
+
injectStaticStyle(invertStyle, textStyle, "invert");
|
|
7319
7459
|
const inlineStyle = createOrUpdateStyle("darkreader--inline");
|
|
7320
7460
|
inlineStyle.textContent = getInlineOverrideStyle();
|
|
7321
|
-
|
|
7322
|
-
setupNodePositionWatcher(inlineStyle, "inline");
|
|
7323
|
-
const overrideStyle = createOrUpdateStyle("darkreader--override");
|
|
7324
|
-
overrideStyle.textContent =
|
|
7325
|
-
fixes && fixes.css ? replaceCSSTemplates(fixes.css) : "";
|
|
7326
|
-
document.head.appendChild(overrideStyle);
|
|
7327
|
-
setupNodePositionWatcher(overrideStyle, "override");
|
|
7461
|
+
injectStaticStyle(inlineStyle, invertStyle, "inline");
|
|
7328
7462
|
const variableStyle = createOrUpdateStyle("darkreader--variables");
|
|
7329
7463
|
const selectionColors = theme?.selectionColor
|
|
7330
7464
|
? getSelectionColor(theme)
|
|
@@ -7345,13 +7479,12 @@
|
|
|
7345
7479
|
` --darkreader-selection-text: ${selectionColors?.foregroundColorSelection ?? "initial"};`,
|
|
7346
7480
|
`}`
|
|
7347
7481
|
].join("\n");
|
|
7348
|
-
|
|
7349
|
-
setupNodePositionWatcher(variableStyle, "variables", () =>
|
|
7482
|
+
injectStaticStyle(variableStyle, inlineStyle, "variables", () =>
|
|
7350
7483
|
registerVariablesSheet(variableStyle.sheet)
|
|
7351
7484
|
);
|
|
7352
7485
|
registerVariablesSheet(variableStyle.sheet);
|
|
7353
7486
|
const rootVarsStyle = createOrUpdateStyle("darkreader--root-vars");
|
|
7354
|
-
|
|
7487
|
+
injectStaticStyle(rootVarsStyle, variableStyle, "root-vars");
|
|
7355
7488
|
const enableStyleSheetsProxy = !(
|
|
7356
7489
|
fixes && fixes.disableStyleSheetsProxy
|
|
7357
7490
|
);
|
|
@@ -7367,6 +7500,10 @@
|
|
|
7367
7500
|
document.head.insertBefore(proxyScript, rootVarsStyle.nextSibling);
|
|
7368
7501
|
proxyScript.remove();
|
|
7369
7502
|
}
|
|
7503
|
+
const overrideStyle = createOrUpdateStyle("darkreader--override");
|
|
7504
|
+
overrideStyle.textContent =
|
|
7505
|
+
fixes && fixes.css ? replaceCSSTemplates(fixes.css) : "";
|
|
7506
|
+
injectStaticStyle(overrideStyle, document.head.lastChild, "override");
|
|
7370
7507
|
}
|
|
7371
7508
|
const shadowRootsWithOverrides = new Set();
|
|
7372
7509
|
function createShadowStaticStyleOverridesInner(root) {
|
|
@@ -7442,7 +7579,8 @@
|
|
|
7442
7579
|
}
|
|
7443
7580
|
function cleanFallbackStyle() {
|
|
7444
7581
|
const fallback =
|
|
7445
|
-
staticStyleMap.get("darkreader--fallback") ||
|
|
7582
|
+
staticStyleMap.get(document.head)?.get("darkreader--fallback") ||
|
|
7583
|
+
staticStyleMap.get(document)?.get("darkreader--fallback") ||
|
|
7446
7584
|
document.querySelector(".darkreader--fallback");
|
|
7447
7585
|
if (fallback) {
|
|
7448
7586
|
fallback.textContent = "";
|
|
@@ -7991,7 +8129,7 @@
|
|
|
7991
8129
|
selectors.forEach((selector) =>
|
|
7992
8130
|
removeNode(document.head.querySelector(selector))
|
|
7993
8131
|
);
|
|
7994
|
-
staticStyleMap
|
|
8132
|
+
staticStyleMap = new WeakMap();
|
|
7995
8133
|
removeProxy();
|
|
7996
8134
|
}
|
|
7997
8135
|
shadowRootsWithOverrides.forEach((root) => {
|