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.mjs
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
|
|
|
@@ -29,6 +29,8 @@ var MessageTypeUItoBG;
|
|
|
29
29
|
"ui-bg-apply-dev-static-themes";
|
|
30
30
|
MessageTypeUItoBG["RESET_DEV_STATIC_THEMES"] =
|
|
31
31
|
"ui-bg-reset-dev-static-themes";
|
|
32
|
+
MessageTypeUItoBG["START_ACTIVATION"] = "ui-bg-start-activation";
|
|
33
|
+
MessageTypeUItoBG["RESET_ACTIVATION"] = "ui-bg-reset-activation";
|
|
32
34
|
MessageTypeUItoBG["COLOR_SCHEME_CHANGE"] = "ui-bg-color-scheme-change";
|
|
33
35
|
MessageTypeUItoBG["HIDE_HIGHLIGHTS"] = "ui-bg-hide-highlights";
|
|
34
36
|
})(MessageTypeUItoBG || (MessageTypeUItoBG = {}));
|
|
@@ -347,6 +349,7 @@ const DEFAULT_THEME = {
|
|
|
347
349
|
darkColorScheme: "Default",
|
|
348
350
|
immediateModify: false
|
|
349
351
|
};
|
|
352
|
+
if (__PLUS__);
|
|
350
353
|
const filterModeSites = [
|
|
351
354
|
"*.officeapps.live.com",
|
|
352
355
|
"*.sharepoint.com",
|
|
@@ -355,9 +358,7 @@ const filterModeSites = [
|
|
|
355
358
|
];
|
|
356
359
|
({
|
|
357
360
|
customThemes: filterModeSites.map((url) => {
|
|
358
|
-
const engine =
|
|
359
|
-
? ThemeEngine.svgFilter
|
|
360
|
-
: ThemeEngine.cssFilter;
|
|
361
|
+
const engine = ThemeEngine.cssFilter;
|
|
361
362
|
return {
|
|
362
363
|
url: [url],
|
|
363
364
|
theme: {...DEFAULT_THEME, engine},
|
|
@@ -956,10 +957,16 @@ const supportedColorFuncs = [
|
|
|
956
957
|
function parse($color) {
|
|
957
958
|
const c = $color.trim().toLowerCase();
|
|
958
959
|
if (c.includes("(from ")) {
|
|
960
|
+
if (c.indexOf("(from") !== c.lastIndexOf("(from")) {
|
|
961
|
+
return null;
|
|
962
|
+
}
|
|
959
963
|
return domParseColor(c);
|
|
960
964
|
}
|
|
961
965
|
if (c.match(rgbMatch)) {
|
|
962
966
|
if (c.startsWith("rgb(#") || c.startsWith("rgba(#")) {
|
|
967
|
+
if (c.lastIndexOf("rgb") > 0) {
|
|
968
|
+
return null;
|
|
969
|
+
}
|
|
963
970
|
return domParseColor(c);
|
|
964
971
|
}
|
|
965
972
|
return parseRGB(c);
|
|
@@ -982,7 +989,10 @@ function parse($color) {
|
|
|
982
989
|
if (
|
|
983
990
|
c.endsWith(")") &&
|
|
984
991
|
supportedColorFuncs.some(
|
|
985
|
-
(fn) =>
|
|
992
|
+
(fn) =>
|
|
993
|
+
c.startsWith(fn) &&
|
|
994
|
+
c[fn.length] === "(" &&
|
|
995
|
+
c.lastIndexOf(fn) === 0
|
|
986
996
|
)
|
|
987
997
|
) {
|
|
988
998
|
return domParseColor(c);
|
|
@@ -1798,6 +1808,9 @@ function iterateCSSRules(rules, iterate, onImportError) {
|
|
|
1798
1808
|
forEach(rules, (rule) => {
|
|
1799
1809
|
if (isStyleRule(rule)) {
|
|
1800
1810
|
iterate(rule);
|
|
1811
|
+
if (rule.cssRules?.length > 0) {
|
|
1812
|
+
iterateCSSRules(rule.cssRules, iterate);
|
|
1813
|
+
}
|
|
1801
1814
|
} else if (isImportRule(rule)) {
|
|
1802
1815
|
try {
|
|
1803
1816
|
iterateCSSRules(
|
|
@@ -2055,817 +2068,868 @@ function getSheetScope(sheet) {
|
|
|
2055
2068
|
return null;
|
|
2056
2069
|
}
|
|
2057
2070
|
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
const conicGradientLength = conicGradient.length;
|
|
2061
|
-
const radialGradient = "radial-";
|
|
2062
|
-
const linearGradient = "linear-";
|
|
2063
|
-
function parseGradient(value) {
|
|
2064
|
-
const result = [];
|
|
2065
|
-
let index = 0;
|
|
2066
|
-
let startIndex = conicGradient.length;
|
|
2067
|
-
while ((index = value.indexOf("gradient", startIndex)) !== -1) {
|
|
2068
|
-
let typeGradient;
|
|
2069
|
-
[linearGradient, radialGradient, conicGradient].find((possibleType) => {
|
|
2070
|
-
if (index - possibleType.length >= 0) {
|
|
2071
|
-
const possibleGradient = value.substring(
|
|
2072
|
-
index - possibleType.length,
|
|
2073
|
-
index
|
|
2074
|
-
);
|
|
2075
|
-
if (possibleGradient === possibleType) {
|
|
2076
|
-
if (
|
|
2077
|
-
value.slice(
|
|
2078
|
-
index - possibleType.length - 10,
|
|
2079
|
-
index - possibleType.length - 1
|
|
2080
|
-
) === "repeating"
|
|
2081
|
-
) {
|
|
2082
|
-
typeGradient = `repeating-${possibleType}gradient`;
|
|
2083
|
-
return true;
|
|
2084
|
-
}
|
|
2085
|
-
if (
|
|
2086
|
-
value.slice(
|
|
2087
|
-
index - possibleType.length - 8,
|
|
2088
|
-
index - possibleType.length - 1
|
|
2089
|
-
) === "-webkit"
|
|
2090
|
-
) {
|
|
2091
|
-
typeGradient = `-webkit-${possibleType}gradient`;
|
|
2092
|
-
return true;
|
|
2093
|
-
}
|
|
2094
|
-
typeGradient = `${possibleType}gradient`;
|
|
2095
|
-
return true;
|
|
2096
|
-
}
|
|
2097
|
-
}
|
|
2098
|
-
});
|
|
2099
|
-
if (!typeGradient) {
|
|
2100
|
-
break;
|
|
2101
|
-
}
|
|
2102
|
-
const {start, end} = getParenthesesRange(value, index + gradientLength);
|
|
2103
|
-
const match = value.substring(start + 1, end - 1);
|
|
2104
|
-
startIndex = end + 1 + conicGradientLength;
|
|
2105
|
-
result.push({
|
|
2106
|
-
typeGradient,
|
|
2107
|
-
match,
|
|
2108
|
-
offset: typeGradient.length + 2,
|
|
2109
|
-
index: index - typeGradient.length + gradientLength,
|
|
2110
|
-
hasComma: true
|
|
2111
|
-
});
|
|
2112
|
-
}
|
|
2113
|
-
if (result.length) {
|
|
2114
|
-
result[result.length - 1].hasComma = false;
|
|
2115
|
-
}
|
|
2116
|
-
return result;
|
|
2071
|
+
function getBackgroundPoles(_theme) {
|
|
2072
|
+
return ["", ""];
|
|
2117
2073
|
}
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
const STORAGE_KEY_IMAGE_DETAILS_PREFIX = "__darkreader__imageDetails_v2_";
|
|
2121
|
-
const STORAGE_KEY_CSS_FETCH_PREFIX = "__darkreader__cssFetch_";
|
|
2122
|
-
let imageCacheTimeout = 0;
|
|
2123
|
-
const imageDetailsCacheQueue = new Map();
|
|
2124
|
-
const cachedImageUrls = [];
|
|
2125
|
-
function writeImageDetailsQueue() {
|
|
2126
|
-
imageDetailsCacheQueue.forEach((details, url) => {
|
|
2127
|
-
if (url && url.startsWith("https://")) {
|
|
2128
|
-
try {
|
|
2129
|
-
const json = JSON.stringify(details);
|
|
2130
|
-
sessionStorage.setItem(
|
|
2131
|
-
`${STORAGE_KEY_IMAGE_DETAILS_PREFIX}${url}`,
|
|
2132
|
-
json
|
|
2133
|
-
);
|
|
2134
|
-
cachedImageUrls.push(url);
|
|
2135
|
-
} catch (err) {}
|
|
2136
|
-
}
|
|
2137
|
-
});
|
|
2138
|
-
imageDetailsCacheQueue.clear();
|
|
2139
|
-
sessionStorage.setItem(
|
|
2140
|
-
STORAGE_KEY_IMAGE_DETAILS_LIST,
|
|
2141
|
-
JSON.stringify(cachedImageUrls)
|
|
2142
|
-
);
|
|
2074
|
+
function getTextPoles(_theme) {
|
|
2075
|
+
return ["", ""];
|
|
2143
2076
|
}
|
|
2144
|
-
function
|
|
2145
|
-
|
|
2146
|
-
return;
|
|
2147
|
-
}
|
|
2148
|
-
imageDetailsCacheQueue.set(url, imageDetails);
|
|
2149
|
-
clearTimeout(imageCacheTimeout);
|
|
2150
|
-
imageCacheTimeout = setTimeout(writeImageDetailsQueue, 1000);
|
|
2077
|
+
function modifyBgColorExtended({h, s, l, a}, _pole1, _pole2) {
|
|
2078
|
+
return {h, s, l, a};
|
|
2151
2079
|
}
|
|
2152
|
-
function
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2080
|
+
function modifyFgColorExtended({h, s, l, a}, _pole1, _pole2) {
|
|
2081
|
+
return {h, s, l, a};
|
|
2082
|
+
}
|
|
2083
|
+
function modifyLightSchemeColorExtended({h, s, l, a}, _pole1, _pole2) {
|
|
2084
|
+
return {h, s, l, a};
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
let variablesSheet;
|
|
2088
|
+
const registeredColors = new Map();
|
|
2089
|
+
function registerVariablesSheet(sheet) {
|
|
2090
|
+
variablesSheet = sheet;
|
|
2091
|
+
const types = ["background", "text", "border"];
|
|
2092
|
+
registeredColors.forEach((registered) => {
|
|
2093
|
+
types.forEach((type) => {
|
|
2094
|
+
if (registered[type]) {
|
|
2095
|
+
const {variable, value} = registered[type];
|
|
2096
|
+
variablesSheet?.cssRules[0].style.setProperty(variable, value);
|
|
2166
2097
|
}
|
|
2167
2098
|
});
|
|
2168
|
-
}
|
|
2169
|
-
}
|
|
2170
|
-
function writeCSSFetchCache(url, cssText) {
|
|
2171
|
-
const key = `${STORAGE_KEY_CSS_FETCH_PREFIX}${url}`;
|
|
2172
|
-
try {
|
|
2173
|
-
sessionStorage.setItem(key, cssText);
|
|
2174
|
-
} catch (err) {}
|
|
2099
|
+
});
|
|
2175
2100
|
}
|
|
2176
|
-
function
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
return sessionStorage.getItem(key) ?? null;
|
|
2180
|
-
} catch (err) {}
|
|
2181
|
-
return null;
|
|
2101
|
+
function releaseVariablesSheet() {
|
|
2102
|
+
variablesSheet = null;
|
|
2103
|
+
clearColorPalette();
|
|
2182
2104
|
}
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
return matrix
|
|
2186
|
-
.slice(0, 4)
|
|
2187
|
-
.map((m) => m.map((m) => m.toFixed(3)).join(" "))
|
|
2188
|
-
.join(" ");
|
|
2105
|
+
function getRegisteredVariableValue(type, registered) {
|
|
2106
|
+
return `var(${registered[type].variable}, ${registered[type].value})`;
|
|
2189
2107
|
}
|
|
2190
|
-
function
|
|
2191
|
-
|
|
2108
|
+
function getRegisteredColor(type, parsed) {
|
|
2109
|
+
const hex = rgbToHexString(parsed);
|
|
2110
|
+
const registered = registeredColors.get(hex);
|
|
2111
|
+
if (registered?.[type]) {
|
|
2112
|
+
return getRegisteredVariableValue(type, registered);
|
|
2113
|
+
}
|
|
2114
|
+
return null;
|
|
2192
2115
|
}
|
|
2193
|
-
|
|
2194
|
-
const
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2116
|
+
function registerColor(type, parsed, value) {
|
|
2117
|
+
const hex = rgbToHexString(parsed);
|
|
2118
|
+
let registered;
|
|
2119
|
+
if (registeredColors.has(hex)) {
|
|
2120
|
+
registered = registeredColors.get(hex);
|
|
2121
|
+
} else {
|
|
2122
|
+
const parsed = parseColorWithCache(hex);
|
|
2123
|
+
registered = {parsed};
|
|
2124
|
+
registeredColors.set(hex, registered);
|
|
2199
2125
|
}
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2126
|
+
const variable = `--darkreader-${type}-${hex.replace("#", "")}`;
|
|
2127
|
+
registered[type] = {variable, value};
|
|
2128
|
+
if (variablesSheet?.cssRules[0]?.style) {
|
|
2129
|
+
variablesSheet?.cssRules[0].style.setProperty(variable, value);
|
|
2203
2130
|
}
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2131
|
+
return getRegisteredVariableValue(type, registered);
|
|
2132
|
+
}
|
|
2133
|
+
function getColorPalette() {
|
|
2134
|
+
const background = [];
|
|
2135
|
+
const border = [];
|
|
2136
|
+
const text = [];
|
|
2137
|
+
registeredColors.forEach((registered) => {
|
|
2138
|
+
if (registered.background) {
|
|
2139
|
+
background.push(registered.parsed);
|
|
2208
2140
|
}
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
if (
|
|
2213
|
-
|
|
2141
|
+
if (registered.border) {
|
|
2142
|
+
border.push(registered.parsed);
|
|
2143
|
+
}
|
|
2144
|
+
if (registered.text) {
|
|
2145
|
+
text.push(registered.parsed);
|
|
2214
2146
|
}
|
|
2215
|
-
this.timerId = requestAnimationFrame(() => {
|
|
2216
|
-
this.timerId = null;
|
|
2217
|
-
const start = Date.now();
|
|
2218
|
-
let cb;
|
|
2219
|
-
while ((cb = this.queue.shift())) {
|
|
2220
|
-
cb();
|
|
2221
|
-
if (Date.now() - start >= MAX_FRAME_DURATION) {
|
|
2222
|
-
this.scheduleFrame();
|
|
2223
|
-
break;
|
|
2224
|
-
}
|
|
2225
|
-
}
|
|
2226
|
-
});
|
|
2227
|
-
}
|
|
2228
|
-
}
|
|
2229
|
-
|
|
2230
|
-
const resolvers$1 = new Map();
|
|
2231
|
-
const rejectors = new Map();
|
|
2232
|
-
async function bgFetch(request) {
|
|
2233
|
-
if (window.DarkReader?.Plugins?.fetch) {
|
|
2234
|
-
return window.DarkReader.Plugins.fetch(request);
|
|
2235
|
-
}
|
|
2236
|
-
return new Promise((resolve, reject) => {
|
|
2237
|
-
const id = generateUID();
|
|
2238
|
-
resolvers$1.set(id, resolve);
|
|
2239
|
-
rejectors.set(id, reject);
|
|
2240
|
-
chrome.runtime.sendMessage({
|
|
2241
|
-
type: MessageTypeCStoBG.FETCH,
|
|
2242
|
-
data: request,
|
|
2243
|
-
id
|
|
2244
|
-
});
|
|
2245
2147
|
});
|
|
2148
|
+
return {background, border, text};
|
|
2149
|
+
}
|
|
2150
|
+
function clearColorPalette() {
|
|
2151
|
+
registeredColors.clear();
|
|
2246
2152
|
}
|
|
2247
|
-
chrome.runtime.onMessage.addListener(({type, data, error, id}) => {
|
|
2248
|
-
if (type === MessageTypeBGtoCS.FETCH_RESPONSE) {
|
|
2249
|
-
const resolve = resolvers$1.get(id);
|
|
2250
|
-
const reject = rejectors.get(id);
|
|
2251
|
-
resolvers$1.delete(id);
|
|
2252
|
-
rejectors.delete(id);
|
|
2253
|
-
if (error) {
|
|
2254
|
-
reject && reject(error);
|
|
2255
|
-
} else {
|
|
2256
|
-
resolve && resolve(data);
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
|
-
});
|
|
2260
2153
|
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2154
|
+
function getBgPole(theme) {
|
|
2155
|
+
const isDarkScheme = theme.mode === 1;
|
|
2156
|
+
const prop = isDarkScheme
|
|
2157
|
+
? "darkSchemeBackgroundColor"
|
|
2158
|
+
: "lightSchemeBackgroundColor";
|
|
2159
|
+
return theme[prop];
|
|
2160
|
+
}
|
|
2161
|
+
function getFgPole(theme) {
|
|
2162
|
+
const isDarkScheme = theme.mode === 1;
|
|
2163
|
+
const prop = isDarkScheme ? "darkSchemeTextColor" : "lightSchemeTextColor";
|
|
2164
|
+
return theme[prop];
|
|
2165
|
+
}
|
|
2166
|
+
const colorModificationCache = new Map();
|
|
2167
|
+
function clearColorModificationCache() {
|
|
2168
|
+
colorModificationCache.clear();
|
|
2169
|
+
}
|
|
2170
|
+
const rgbCacheKeys = ["r", "g", "b", "a"];
|
|
2171
|
+
const themeCacheKeys = [
|
|
2172
|
+
"mode",
|
|
2173
|
+
"brightness",
|
|
2174
|
+
"contrast",
|
|
2175
|
+
"grayscale",
|
|
2176
|
+
"sepia",
|
|
2177
|
+
"darkSchemeBackgroundColor",
|
|
2178
|
+
"darkSchemeTextColor",
|
|
2179
|
+
"lightSchemeBackgroundColor",
|
|
2180
|
+
"lightSchemeTextColor"
|
|
2181
|
+
];
|
|
2182
|
+
function getCacheId(rgb, theme) {
|
|
2183
|
+
let resultId = "";
|
|
2184
|
+
rgbCacheKeys.forEach((key) => {
|
|
2185
|
+
resultId += `${rgb[key]};`;
|
|
2291
2186
|
});
|
|
2187
|
+
themeCacheKeys.forEach((key) => {
|
|
2188
|
+
resultId += `${theme[key]};`;
|
|
2189
|
+
});
|
|
2190
|
+
return resultId;
|
|
2292
2191
|
}
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2192
|
+
function modifyColorWithCache(
|
|
2193
|
+
rgb,
|
|
2194
|
+
theme,
|
|
2195
|
+
modifyHSL,
|
|
2196
|
+
poleColor,
|
|
2197
|
+
anotherPoleColor
|
|
2198
|
+
) {
|
|
2199
|
+
let fnCache;
|
|
2200
|
+
if (colorModificationCache.has(modifyHSL)) {
|
|
2201
|
+
fnCache = colorModificationCache.get(modifyHSL);
|
|
2202
|
+
} else {
|
|
2203
|
+
fnCache = new Map();
|
|
2204
|
+
colorModificationCache.set(modifyHSL, fnCache);
|
|
2297
2205
|
}
|
|
2298
|
-
|
|
2206
|
+
const id = getCacheId(rgb, theme);
|
|
2207
|
+
if (fnCache.has(id)) {
|
|
2208
|
+
return fnCache.get(id);
|
|
2209
|
+
}
|
|
2210
|
+
const hsl = rgbToHSL(rgb);
|
|
2211
|
+
const pole = poleColor == null ? null : parseToHSLWithCache(poleColor);
|
|
2212
|
+
const anotherPole =
|
|
2213
|
+
anotherPoleColor == null ? null : parseToHSLWithCache(anotherPoleColor);
|
|
2214
|
+
const modified = modifyHSL(hsl, pole, anotherPole);
|
|
2215
|
+
const {r, g, b, a} = hslToRGB(modified);
|
|
2216
|
+
const matrix = createFilterMatrix({...theme, mode: 0});
|
|
2217
|
+
const [rf, gf, bf] = applyColorMatrix([r, g, b], matrix);
|
|
2218
|
+
const color =
|
|
2219
|
+
a === 1
|
|
2220
|
+
? rgbToHexString({r: rf, g: gf, b: bf})
|
|
2221
|
+
: rgbToString({r: rf, g: gf, b: bf, a});
|
|
2222
|
+
fnCache.set(id, color);
|
|
2223
|
+
return color;
|
|
2299
2224
|
}
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
logWarn(
|
|
2305
|
-
`Unable to create image bitmap for type ${blob.type}: ${String(err)}`
|
|
2306
|
-
);
|
|
2307
|
-
return null;
|
|
2225
|
+
function modifyAndRegisterColor(type, rgb, theme, modifier) {
|
|
2226
|
+
const registered = getRegisteredColor(type, rgb);
|
|
2227
|
+
if (registered) {
|
|
2228
|
+
return registered;
|
|
2308
2229
|
}
|
|
2230
|
+
const value = modifier(rgb, theme);
|
|
2231
|
+
return registerColor(type, rgb, value);
|
|
2309
2232
|
}
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
return
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2233
|
+
function modifyLightSchemeColor(rgb, theme) {
|
|
2234
|
+
const poleBg = getBgPole(theme);
|
|
2235
|
+
const poleFg = getFgPole(theme);
|
|
2236
|
+
return modifyColorWithCache(rgb, theme, modifyLightModeHSL, poleFg, poleBg);
|
|
2237
|
+
}
|
|
2238
|
+
function modifyLightModeHSL({h, s, l, a}, poleFg, poleBg) {
|
|
2239
|
+
const isDark = l < 0.5;
|
|
2240
|
+
let isNeutral;
|
|
2241
|
+
if (isDark) {
|
|
2242
|
+
isNeutral = l < 0.2 || s < 0.12;
|
|
2243
|
+
} else {
|
|
2244
|
+
const isBlue = h > 200 && h < 280;
|
|
2245
|
+
isNeutral = s < 0.24 || (l > 0.8 && isBlue);
|
|
2246
|
+
}
|
|
2247
|
+
let hx = h;
|
|
2248
|
+
let sx = s;
|
|
2249
|
+
if (isNeutral) {
|
|
2250
|
+
if (isDark) {
|
|
2251
|
+
hx = poleFg.h;
|
|
2252
|
+
sx = poleFg.s;
|
|
2322
2253
|
} else {
|
|
2323
|
-
|
|
2254
|
+
hx = poleBg.h;
|
|
2255
|
+
sx = poleBg.s;
|
|
2324
2256
|
}
|
|
2325
|
-
}
|
|
2257
|
+
}
|
|
2258
|
+
const lx = scale(l, 0, 1, poleFg.l, poleBg.l);
|
|
2259
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2326
2260
|
}
|
|
2327
|
-
const
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
const
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2261
|
+
const MAX_BG_LIGHTNESS = 0.4;
|
|
2262
|
+
function modifyBgHSL({h, s, l, a}, pole) {
|
|
2263
|
+
const isDark = l < 0.5;
|
|
2264
|
+
const isBlue = h > 200 && h < 280;
|
|
2265
|
+
const isNeutral = s < 0.12 || (l > 0.8 && isBlue);
|
|
2266
|
+
if (isDark) {
|
|
2267
|
+
const lx = scale(l, 0, 0.5, 0, MAX_BG_LIGHTNESS);
|
|
2268
|
+
if (isNeutral) {
|
|
2269
|
+
const hx = pole.h;
|
|
2270
|
+
const sx = pole.s;
|
|
2271
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2272
|
+
}
|
|
2273
|
+
return {h, s, l: lx, a};
|
|
2274
|
+
}
|
|
2275
|
+
let lx = scale(l, 0.5, 1, MAX_BG_LIGHTNESS, pole.l);
|
|
2276
|
+
if (isNeutral) {
|
|
2277
|
+
const hx = pole.h;
|
|
2278
|
+
const sx = pole.s;
|
|
2279
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2280
|
+
}
|
|
2281
|
+
let hx = h;
|
|
2282
|
+
const isYellow = h > 60 && h < 180;
|
|
2283
|
+
if (isYellow) {
|
|
2284
|
+
const isCloserToGreen = h > 120;
|
|
2285
|
+
if (isCloserToGreen) {
|
|
2286
|
+
hx = scale(h, 120, 180, 135, 180);
|
|
2287
|
+
} else {
|
|
2288
|
+
hx = scale(h, 60, 120, 60, 105);
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
if (hx > 40 && hx < 80) {
|
|
2292
|
+
lx *= 0.75;
|
|
2293
|
+
}
|
|
2294
|
+
return {h: hx, s, l: lx, a};
|
|
2338
2295
|
}
|
|
2339
|
-
function
|
|
2340
|
-
|
|
2341
|
-
|
|
2296
|
+
function _modifyBackgroundColor(rgb, theme) {
|
|
2297
|
+
if (theme.mode === 0) {
|
|
2298
|
+
if (__PLUS__) {
|
|
2299
|
+
const poles = getBackgroundPoles();
|
|
2300
|
+
return modifyColorWithCache(
|
|
2301
|
+
rgb,
|
|
2302
|
+
theme,
|
|
2303
|
+
modifyLightSchemeColorExtended,
|
|
2304
|
+
poles[0],
|
|
2305
|
+
poles[1]
|
|
2306
|
+
);
|
|
2307
|
+
}
|
|
2308
|
+
return modifyLightSchemeColor(rgb, theme);
|
|
2309
|
+
}
|
|
2310
|
+
if (__PLUS__) {
|
|
2311
|
+
const poles = getBackgroundPoles();
|
|
2312
|
+
return modifyColorWithCache(
|
|
2313
|
+
rgb,
|
|
2314
|
+
theme,
|
|
2315
|
+
modifyBgColorExtended,
|
|
2316
|
+
poles[0],
|
|
2317
|
+
poles[1]
|
|
2318
|
+
);
|
|
2319
|
+
}
|
|
2320
|
+
const pole = getBgPole(theme);
|
|
2321
|
+
return modifyColorWithCache(rgb, theme, modifyBgHSL, pole);
|
|
2342
2322
|
}
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
createCanvas();
|
|
2323
|
+
function modifyBackgroundColor(rgb, theme, shouldRegisterColorVariable = true) {
|
|
2324
|
+
if (!shouldRegisterColorVariable) {
|
|
2325
|
+
return _modifyBackgroundColor(rgb, theme);
|
|
2347
2326
|
}
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2327
|
+
return modifyAndRegisterColor(
|
|
2328
|
+
"background",
|
|
2329
|
+
rgb,
|
|
2330
|
+
theme,
|
|
2331
|
+
_modifyBackgroundColor
|
|
2332
|
+
);
|
|
2333
|
+
}
|
|
2334
|
+
const MIN_FG_LIGHTNESS = 0.55;
|
|
2335
|
+
function modifyBlueFgHue(hue) {
|
|
2336
|
+
return scale(hue, 205, 245, 205, 220);
|
|
2337
|
+
}
|
|
2338
|
+
function modifyFgHSL({h, s, l, a}, pole) {
|
|
2339
|
+
const isLight = l > 0.5;
|
|
2340
|
+
const isNeutral = l < 0.2 || s < 0.24;
|
|
2341
|
+
const isBlue = !isNeutral && h > 205 && h < 245;
|
|
2342
|
+
if (isLight) {
|
|
2343
|
+
const lx = scale(l, 0.5, 1, MIN_FG_LIGHTNESS, pole.l);
|
|
2344
|
+
if (isNeutral) {
|
|
2345
|
+
const hx = pole.h;
|
|
2346
|
+
const sx = pole.s;
|
|
2347
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2348
|
+
}
|
|
2349
|
+
let hx = h;
|
|
2350
|
+
if (isBlue) {
|
|
2351
|
+
hx = modifyBlueFgHue(h);
|
|
2352
|
+
}
|
|
2353
|
+
return {h: hx, s, l: lx, a};
|
|
2354
|
+
}
|
|
2355
|
+
if (isNeutral) {
|
|
2356
|
+
const hx = pole.h;
|
|
2357
|
+
const sx = pole.s;
|
|
2358
|
+
const lx = scale(l, 0, 0.5, pole.l, MIN_FG_LIGHTNESS);
|
|
2359
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2360
|
+
}
|
|
2361
|
+
let hx = h;
|
|
2362
|
+
let lx;
|
|
2363
|
+
if (isBlue) {
|
|
2364
|
+
hx = modifyBlueFgHue(h);
|
|
2365
|
+
lx = scale(l, 0, 0.5, pole.l, Math.min(1, MIN_FG_LIGHTNESS + 0.05));
|
|
2353
2366
|
} else {
|
|
2354
|
-
|
|
2355
|
-
sh = image.height;
|
|
2367
|
+
lx = scale(l, 0, 0.5, pole.l, MIN_FG_LIGHTNESS);
|
|
2356
2368
|
}
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2369
|
+
return {h: hx, s, l: lx, a};
|
|
2370
|
+
}
|
|
2371
|
+
function _modifyForegroundColor(rgb, theme) {
|
|
2372
|
+
if (theme.mode === 0) {
|
|
2373
|
+
if (__PLUS__) {
|
|
2374
|
+
const poles = getTextPoles();
|
|
2375
|
+
return modifyColorWithCache(
|
|
2376
|
+
rgb,
|
|
2377
|
+
theme,
|
|
2378
|
+
modifyLightSchemeColorExtended,
|
|
2379
|
+
poles[0],
|
|
2380
|
+
poles[1]
|
|
2381
|
+
);
|
|
2382
|
+
}
|
|
2383
|
+
return modifyLightSchemeColor(rgb, theme);
|
|
2365
2384
|
}
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
const
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2385
|
+
if (__PLUS__) {
|
|
2386
|
+
const poles = getTextPoles();
|
|
2387
|
+
return modifyColorWithCache(
|
|
2388
|
+
rgb,
|
|
2389
|
+
theme,
|
|
2390
|
+
modifyFgColorExtended,
|
|
2391
|
+
poles[0],
|
|
2392
|
+
poles[1]
|
|
2393
|
+
);
|
|
2394
|
+
}
|
|
2395
|
+
const pole = getFgPole(theme);
|
|
2396
|
+
return modifyColorWithCache(rgb, theme, modifyFgHSL, pole);
|
|
2397
|
+
}
|
|
2398
|
+
function modifyForegroundColor(rgb, theme, shouldRegisterColorVariable = true) {
|
|
2399
|
+
if (!shouldRegisterColorVariable) {
|
|
2400
|
+
return _modifyForegroundColor(rgb, theme);
|
|
2401
|
+
}
|
|
2402
|
+
return modifyAndRegisterColor("text", rgb, theme, _modifyForegroundColor);
|
|
2403
|
+
}
|
|
2404
|
+
function modifyBorderHSL({h, s, l, a}, poleFg, poleBg) {
|
|
2405
|
+
const isDark = l < 0.5;
|
|
2406
|
+
const isNeutral = l < 0.2 || s < 0.24;
|
|
2407
|
+
let hx = h;
|
|
2408
|
+
let sx = s;
|
|
2409
|
+
if (isNeutral) {
|
|
2410
|
+
if (isDark) {
|
|
2411
|
+
hx = poleFg.h;
|
|
2412
|
+
sx = poleFg.s;
|
|
2413
|
+
} else {
|
|
2414
|
+
hx = poleBg.h;
|
|
2415
|
+
sx = poleBg.s;
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
const lx = scale(l, 0, 1, 0.5, 0.2);
|
|
2419
|
+
return {h: hx, s: sx, l: lx, a};
|
|
2420
|
+
}
|
|
2421
|
+
function _modifyBorderColor(rgb, theme) {
|
|
2422
|
+
if (theme.mode === 0) {
|
|
2423
|
+
return modifyLightSchemeColor(rgb, theme);
|
|
2424
|
+
}
|
|
2425
|
+
const poleFg = getFgPole(theme);
|
|
2426
|
+
const poleBg = getBgPole(theme);
|
|
2427
|
+
return modifyColorWithCache(rgb, theme, modifyBorderHSL, poleFg, poleBg);
|
|
2428
|
+
}
|
|
2429
|
+
function modifyBorderColor(rgb, theme, shouldRegisterColorVariable = true) {
|
|
2430
|
+
if (!shouldRegisterColorVariable) {
|
|
2431
|
+
return _modifyBorderColor(rgb, theme);
|
|
2432
|
+
}
|
|
2433
|
+
return modifyAndRegisterColor("border", rgb, theme, _modifyBorderColor);
|
|
2434
|
+
}
|
|
2435
|
+
function modifyShadowColor(rgb, theme) {
|
|
2436
|
+
return modifyBackgroundColor(rgb, theme);
|
|
2437
|
+
}
|
|
2438
|
+
function modifyGradientColor(rgb, theme) {
|
|
2439
|
+
return modifyBackgroundColor(rgb, theme);
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
const gradientLength = "gradient".length;
|
|
2443
|
+
const conicGradient = "conic-";
|
|
2444
|
+
const conicGradientLength = conicGradient.length;
|
|
2445
|
+
const radialGradient = "radial-";
|
|
2446
|
+
const linearGradient = "linear-";
|
|
2447
|
+
function parseGradient(value) {
|
|
2448
|
+
const result = [];
|
|
2449
|
+
let index = 0;
|
|
2450
|
+
let startIndex = conicGradient.length;
|
|
2451
|
+
while ((index = value.indexOf("gradient", startIndex)) !== -1) {
|
|
2452
|
+
let typeGradient;
|
|
2453
|
+
[linearGradient, radialGradient, conicGradient].find((possibleType) => {
|
|
2454
|
+
if (index - possibleType.length >= 0) {
|
|
2455
|
+
const possibleGradient = value.substring(
|
|
2456
|
+
index - possibleType.length,
|
|
2457
|
+
index
|
|
2458
|
+
);
|
|
2459
|
+
if (possibleGradient === possibleType) {
|
|
2460
|
+
if (
|
|
2461
|
+
value.slice(
|
|
2462
|
+
index - possibleType.length - 10,
|
|
2463
|
+
index - possibleType.length - 1
|
|
2464
|
+
) === "repeating"
|
|
2465
|
+
) {
|
|
2466
|
+
typeGradient = `repeating-${possibleType}gradient`;
|
|
2467
|
+
return true;
|
|
2468
|
+
}
|
|
2469
|
+
if (
|
|
2470
|
+
value.slice(
|
|
2471
|
+
index - possibleType.length - 8,
|
|
2472
|
+
index - possibleType.length - 1
|
|
2473
|
+
) === "-webkit"
|
|
2474
|
+
) {
|
|
2475
|
+
typeGradient = `-webkit-${possibleType}gradient`;
|
|
2476
|
+
return true;
|
|
2477
|
+
}
|
|
2478
|
+
typeGradient = `${possibleType}gradient`;
|
|
2479
|
+
return true;
|
|
2403
2480
|
}
|
|
2404
2481
|
}
|
|
2482
|
+
});
|
|
2483
|
+
if (!typeGradient) {
|
|
2484
|
+
break;
|
|
2405
2485
|
}
|
|
2486
|
+
const {start, end} = getParenthesesRange(value, index + gradientLength);
|
|
2487
|
+
const match = value.substring(start + 1, end - 1);
|
|
2488
|
+
startIndex = end + 1 + conicGradientLength;
|
|
2489
|
+
result.push({
|
|
2490
|
+
typeGradient,
|
|
2491
|
+
match,
|
|
2492
|
+
offset: typeGradient.length + 2,
|
|
2493
|
+
index: index - typeGradient.length + gradientLength,
|
|
2494
|
+
hasComma: true
|
|
2495
|
+
});
|
|
2406
2496
|
}
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
const TRANSPARENT_IMAGE_THRESHOLD = 0.1;
|
|
2412
|
-
return {
|
|
2413
|
-
isDark: darkPixelsCount / opaquePixelsCount >= DARK_IMAGE_THRESHOLD,
|
|
2414
|
-
isLight: lightPixelsCount / opaquePixelsCount >= LIGHT_IMAGE_THRESHOLD,
|
|
2415
|
-
isTransparent:
|
|
2416
|
-
transparentPixelsCount / totalPixelsCount >=
|
|
2417
|
-
TRANSPARENT_IMAGE_THRESHOLD,
|
|
2418
|
-
isLarge
|
|
2419
|
-
};
|
|
2497
|
+
if (result.length) {
|
|
2498
|
+
result[result.length - 1].hasComma = false;
|
|
2499
|
+
}
|
|
2500
|
+
return result;
|
|
2420
2501
|
}
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
const
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
)
|
|
2430
|
-
|
|
2431
|
-
|
|
2502
|
+
|
|
2503
|
+
const STORAGE_KEY_IMAGE_DETAILS_LIST = "__darkreader__imageDetails_v2_list";
|
|
2504
|
+
const STORAGE_KEY_IMAGE_DETAILS_PREFIX = "__darkreader__imageDetails_v2_";
|
|
2505
|
+
const STORAGE_KEY_CSS_FETCH_PREFIX = "__darkreader__cssFetch_";
|
|
2506
|
+
let imageCacheTimeout = 0;
|
|
2507
|
+
const imageDetailsCacheQueue = new Map();
|
|
2508
|
+
const cachedImageUrls = [];
|
|
2509
|
+
function writeImageDetailsQueue() {
|
|
2510
|
+
imageDetailsCacheQueue.forEach((details, url) => {
|
|
2511
|
+
if (url && url.startsWith("https://")) {
|
|
2512
|
+
try {
|
|
2513
|
+
const json = JSON.stringify(details);
|
|
2514
|
+
sessionStorage.setItem(
|
|
2515
|
+
`${STORAGE_KEY_IMAGE_DETAILS_PREFIX}${url}`,
|
|
2516
|
+
json
|
|
2517
|
+
);
|
|
2518
|
+
cachedImageUrls.push(url);
|
|
2519
|
+
} catch (err) {}
|
|
2520
|
+
}
|
|
2521
|
+
});
|
|
2522
|
+
imageDetailsCacheQueue.clear();
|
|
2523
|
+
sessionStorage.setItem(
|
|
2524
|
+
STORAGE_KEY_IMAGE_DETAILS_LIST,
|
|
2525
|
+
JSON.stringify(cachedImageUrls)
|
|
2526
|
+
);
|
|
2527
|
+
}
|
|
2528
|
+
function writeImageDetailsCache(url, imageDetails) {
|
|
2529
|
+
if (!url || !url.startsWith("https://")) {
|
|
2432
2530
|
return;
|
|
2433
2531
|
}
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
);
|
|
2438
|
-
}
|
|
2439
|
-
blobURLCheckRequested = true;
|
|
2440
|
-
await new Promise((resolve) => {
|
|
2441
|
-
document.addEventListener(
|
|
2442
|
-
"__darkreader__blobURLCheckResponse",
|
|
2443
|
-
(e) => {
|
|
2444
|
-
isBlobURLSupported = e.detail.blobURLAllowed;
|
|
2445
|
-
resolve();
|
|
2446
|
-
blobURLCheckAwaiters.forEach((r) => r());
|
|
2447
|
-
blobURLCheckAwaiters.splice(0);
|
|
2448
|
-
},
|
|
2449
|
-
{once: true}
|
|
2450
|
-
);
|
|
2451
|
-
document.dispatchEvent(
|
|
2452
|
-
new CustomEvent("__darkreader__blobURLCheckRequest")
|
|
2453
|
-
);
|
|
2454
|
-
});
|
|
2532
|
+
imageDetailsCacheQueue.set(url, imageDetails);
|
|
2533
|
+
clearTimeout(imageCacheTimeout);
|
|
2534
|
+
imageCacheTimeout = setTimeout(writeImageDetailsQueue, 1000);
|
|
2455
2535
|
}
|
|
2456
|
-
function
|
|
2457
|
-
|
|
2536
|
+
function readImageDetailsCache(targetMap) {
|
|
2537
|
+
try {
|
|
2538
|
+
const jsonList = sessionStorage.getItem(STORAGE_KEY_IMAGE_DETAILS_LIST);
|
|
2539
|
+
if (!jsonList) {
|
|
2540
|
+
return;
|
|
2541
|
+
}
|
|
2542
|
+
const list = JSON.parse(jsonList);
|
|
2543
|
+
list.forEach((url) => {
|
|
2544
|
+
const json = sessionStorage.getItem(
|
|
2545
|
+
`${STORAGE_KEY_IMAGE_DETAILS_PREFIX}${url}`
|
|
2546
|
+
);
|
|
2547
|
+
if (json) {
|
|
2548
|
+
const details = JSON.parse(json);
|
|
2549
|
+
targetMap.set(url, details);
|
|
2550
|
+
}
|
|
2551
|
+
});
|
|
2552
|
+
} catch (err) {}
|
|
2458
2553
|
}
|
|
2459
|
-
function
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
}
|
|
2554
|
+
function writeCSSFetchCache(url, cssText) {
|
|
2555
|
+
const key = `${STORAGE_KEY_CSS_FETCH_PREFIX}${url}`;
|
|
2556
|
+
try {
|
|
2557
|
+
sessionStorage.setItem(key, cssText);
|
|
2558
|
+
} catch (err) {}
|
|
2464
2559
|
}
|
|
2465
|
-
|
|
2466
|
-
const
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
const matrix = getSVGFilterMatrixValue(theme);
|
|
2472
|
-
const svg = [
|
|
2473
|
-
`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${width}" height="${height}">`,
|
|
2474
|
-
"<defs>",
|
|
2475
|
-
'<filter id="darkreader-image-filter">',
|
|
2476
|
-
`<feColorMatrix type="matrix" values="${matrix}" />`,
|
|
2477
|
-
"</filter>",
|
|
2478
|
-
"</defs>",
|
|
2479
|
-
`<image width="${width}" height="${height}" filter="url(#darkreader-image-filter)" xlink:href="${dataURL}" />`,
|
|
2480
|
-
"</svg>"
|
|
2481
|
-
].join("");
|
|
2482
|
-
if (!isBlobURLSupported) {
|
|
2483
|
-
return `data:image/svg+xml;base64,${btoa(svg)}`;
|
|
2484
|
-
}
|
|
2485
|
-
const bytes = new Uint8Array(svg.length);
|
|
2486
|
-
for (let i = 0; i < svg.length; i++) {
|
|
2487
|
-
bytes[i] = svg.charCodeAt(i);
|
|
2488
|
-
}
|
|
2489
|
-
const blob = new Blob([bytes], {type: "image/svg+xml"});
|
|
2490
|
-
const objectURL = URL.createObjectURL(blob);
|
|
2491
|
-
objectURLs.add(objectURL);
|
|
2492
|
-
return objectURL;
|
|
2560
|
+
function readCSSFetchCache(url) {
|
|
2561
|
+
const key = `${STORAGE_KEY_CSS_FETCH_PREFIX}${url}`;
|
|
2562
|
+
try {
|
|
2563
|
+
return sessionStorage.getItem(key) ?? null;
|
|
2564
|
+
} catch (err) {}
|
|
2565
|
+
return null;
|
|
2493
2566
|
}
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
};
|
|
2501
|
-
function escapeXML(str) {
|
|
2502
|
-
return str.replace(/[<>&'"]/g, (c) => xmlEscapeChars[c] ?? c);
|
|
2567
|
+
|
|
2568
|
+
function toSVGMatrix(matrix) {
|
|
2569
|
+
return matrix
|
|
2570
|
+
.slice(0, 4)
|
|
2571
|
+
.map((m) => m.map((m) => m.toFixed(3)).join(" "))
|
|
2572
|
+
.join(" ");
|
|
2503
2573
|
}
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
const colonIndex = dataURL.indexOf(":");
|
|
2507
|
-
const semicolonIndex = dataURL.indexOf(";", colonIndex + 1);
|
|
2508
|
-
const commaIndex = dataURL.indexOf(",", semicolonIndex + 1);
|
|
2509
|
-
const encoding = dataURL
|
|
2510
|
-
.substring(semicolonIndex + 1, commaIndex)
|
|
2511
|
-
.toLocaleLowerCase();
|
|
2512
|
-
const mediaType = dataURL.substring(colonIndex + 1, semicolonIndex);
|
|
2513
|
-
if (encoding !== "base64" || !mediaType) {
|
|
2514
|
-
return null;
|
|
2515
|
-
}
|
|
2516
|
-
const characters = atob(dataURL.substring(commaIndex + 1));
|
|
2517
|
-
const bytes = new Uint8Array(characters.length);
|
|
2518
|
-
for (let i = 0; i < characters.length; i++) {
|
|
2519
|
-
bytes[i] = characters.charCodeAt(i);
|
|
2520
|
-
}
|
|
2521
|
-
return new Blob([bytes], {type: mediaType});
|
|
2574
|
+
function getSVGFilterMatrixValue(config) {
|
|
2575
|
+
return toSVGMatrix(createFilterMatrix(config));
|
|
2522
2576
|
}
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2577
|
+
|
|
2578
|
+
const MAX_FRAME_DURATION = 1000 / 60;
|
|
2579
|
+
class AsyncQueue {
|
|
2580
|
+
constructor() {
|
|
2581
|
+
this.queue = [];
|
|
2582
|
+
this.timerId = null;
|
|
2526
2583
|
}
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
return blobURL;
|
|
2584
|
+
addTask(task) {
|
|
2585
|
+
this.queue.push(task);
|
|
2586
|
+
this.scheduleFrame();
|
|
2531
2587
|
}
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2588
|
+
stop() {
|
|
2589
|
+
if (this.timerId !== null) {
|
|
2590
|
+
cancelAnimationFrame(this.timerId);
|
|
2591
|
+
this.timerId = null;
|
|
2592
|
+
}
|
|
2593
|
+
this.queue = [];
|
|
2536
2594
|
}
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
}
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
const registeredColors = new Map();
|
|
2552
|
-
function registerVariablesSheet(sheet) {
|
|
2553
|
-
variablesSheet = sheet;
|
|
2554
|
-
const types = ["background", "text", "border"];
|
|
2555
|
-
registeredColors.forEach((registered) => {
|
|
2556
|
-
types.forEach((type) => {
|
|
2557
|
-
if (registered[type]) {
|
|
2558
|
-
const {variable, value} = registered[type];
|
|
2559
|
-
variablesSheet?.cssRules[0].style.setProperty(variable, value);
|
|
2595
|
+
scheduleFrame() {
|
|
2596
|
+
if (this.timerId) {
|
|
2597
|
+
return;
|
|
2598
|
+
}
|
|
2599
|
+
this.timerId = requestAnimationFrame(() => {
|
|
2600
|
+
this.timerId = null;
|
|
2601
|
+
const start = Date.now();
|
|
2602
|
+
let cb;
|
|
2603
|
+
while ((cb = this.queue.shift())) {
|
|
2604
|
+
cb();
|
|
2605
|
+
if (Date.now() - start >= MAX_FRAME_DURATION) {
|
|
2606
|
+
this.scheduleFrame();
|
|
2607
|
+
break;
|
|
2608
|
+
}
|
|
2560
2609
|
}
|
|
2561
2610
|
});
|
|
2562
|
-
});
|
|
2563
|
-
}
|
|
2564
|
-
function releaseVariablesSheet() {
|
|
2565
|
-
variablesSheet = null;
|
|
2566
|
-
clearColorPalette();
|
|
2567
|
-
}
|
|
2568
|
-
function getRegisteredVariableValue(type, registered) {
|
|
2569
|
-
return `var(${registered[type].variable}, ${registered[type].value})`;
|
|
2570
|
-
}
|
|
2571
|
-
function getRegisteredColor(type, parsed) {
|
|
2572
|
-
const hex = rgbToHexString(parsed);
|
|
2573
|
-
const registered = registeredColors.get(hex);
|
|
2574
|
-
if (registered?.[type]) {
|
|
2575
|
-
return getRegisteredVariableValue(type, registered);
|
|
2576
2611
|
}
|
|
2577
|
-
return null;
|
|
2578
2612
|
}
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
const parsed = parseColorWithCache(hex);
|
|
2586
|
-
registered = {parsed};
|
|
2587
|
-
registeredColors.set(hex, registered);
|
|
2588
|
-
}
|
|
2589
|
-
const variable = `--darkreader-${type}-${hex.replace("#", "")}`;
|
|
2590
|
-
registered[type] = {variable, value};
|
|
2591
|
-
if (variablesSheet?.cssRules[0]?.style) {
|
|
2592
|
-
variablesSheet?.cssRules[0].style.setProperty(variable, value);
|
|
2613
|
+
|
|
2614
|
+
const resolvers$1 = new Map();
|
|
2615
|
+
const rejectors = new Map();
|
|
2616
|
+
async function bgFetch(request) {
|
|
2617
|
+
if (window.DarkReader?.Plugins?.fetch) {
|
|
2618
|
+
return window.DarkReader.Plugins.fetch(request);
|
|
2593
2619
|
}
|
|
2594
|
-
return
|
|
2620
|
+
return new Promise((resolve, reject) => {
|
|
2621
|
+
const id = generateUID();
|
|
2622
|
+
resolvers$1.set(id, resolve);
|
|
2623
|
+
rejectors.set(id, reject);
|
|
2624
|
+
chrome.runtime.sendMessage({
|
|
2625
|
+
type: MessageTypeCStoBG.FETCH,
|
|
2626
|
+
data: request,
|
|
2627
|
+
id
|
|
2628
|
+
});
|
|
2629
|
+
});
|
|
2595
2630
|
}
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2631
|
+
chrome.runtime.onMessage.addListener(({type, data, error, id}) => {
|
|
2632
|
+
if (type === MessageTypeBGtoCS.FETCH_RESPONSE) {
|
|
2633
|
+
const resolve = resolvers$1.get(id);
|
|
2634
|
+
const reject = rejectors.get(id);
|
|
2635
|
+
resolvers$1.delete(id);
|
|
2636
|
+
rejectors.delete(id);
|
|
2637
|
+
if (error) {
|
|
2638
|
+
reject &&
|
|
2639
|
+
reject(typeof error === "string" ? new Error(error) : error);
|
|
2640
|
+
} else {
|
|
2641
|
+
resolve && resolve(data);
|
|
2606
2642
|
}
|
|
2607
|
-
|
|
2608
|
-
|
|
2643
|
+
}
|
|
2644
|
+
});
|
|
2645
|
+
|
|
2646
|
+
const imageManager = new AsyncQueue();
|
|
2647
|
+
async function getImageDetails(url) {
|
|
2648
|
+
return new Promise(async (resolve, reject) => {
|
|
2649
|
+
try {
|
|
2650
|
+
const dataURL = url.startsWith("data:")
|
|
2651
|
+
? url
|
|
2652
|
+
: await getDataURL(url);
|
|
2653
|
+
const blob =
|
|
2654
|
+
tryConvertDataURLToBlobSync(dataURL) ?? (await loadAsBlob(url));
|
|
2655
|
+
let image;
|
|
2656
|
+
if (dataURL.startsWith("data:image/svg+xml")) {
|
|
2657
|
+
image = await loadImage(dataURL);
|
|
2658
|
+
} else {
|
|
2659
|
+
image =
|
|
2660
|
+
(await tryCreateImageBitmap(blob)) ??
|
|
2661
|
+
(await loadImage(dataURL));
|
|
2662
|
+
}
|
|
2663
|
+
imageManager.addTask(() => {
|
|
2664
|
+
const analysis = analyzeImage(image);
|
|
2665
|
+
resolve({
|
|
2666
|
+
src: url,
|
|
2667
|
+
dataURL: analysis.isLarge ? "" : dataURL,
|
|
2668
|
+
width: image.width,
|
|
2669
|
+
height: image.height,
|
|
2670
|
+
...analysis
|
|
2671
|
+
});
|
|
2672
|
+
});
|
|
2673
|
+
} catch (error) {
|
|
2674
|
+
reject(error);
|
|
2609
2675
|
}
|
|
2610
2676
|
});
|
|
2611
|
-
return {background, border, text};
|
|
2612
|
-
}
|
|
2613
|
-
function clearColorPalette() {
|
|
2614
|
-
registeredColors.clear();
|
|
2615
|
-
}
|
|
2616
|
-
|
|
2617
|
-
function getBgPole(theme) {
|
|
2618
|
-
const isDarkScheme = theme.mode === 1;
|
|
2619
|
-
const prop = isDarkScheme
|
|
2620
|
-
? "darkSchemeBackgroundColor"
|
|
2621
|
-
: "lightSchemeBackgroundColor";
|
|
2622
|
-
return theme[prop];
|
|
2623
2677
|
}
|
|
2624
|
-
function
|
|
2625
|
-
const
|
|
2626
|
-
|
|
2627
|
-
|
|
2678
|
+
async function getDataURL(url) {
|
|
2679
|
+
const parsedURL = new URL(url);
|
|
2680
|
+
if (parsedURL.origin === location.origin) {
|
|
2681
|
+
return await loadAsDataURL(url);
|
|
2682
|
+
}
|
|
2683
|
+
return await bgFetch({url, responseType: "data-url"});
|
|
2628
2684
|
}
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2685
|
+
async function tryCreateImageBitmap(blob) {
|
|
2686
|
+
try {
|
|
2687
|
+
return await createImageBitmap(blob);
|
|
2688
|
+
} catch (err) {
|
|
2689
|
+
logWarn(
|
|
2690
|
+
`Unable to create image bitmap for type ${blob.type}: ${String(err)}`
|
|
2691
|
+
);
|
|
2692
|
+
return null;
|
|
2693
|
+
}
|
|
2632
2694
|
}
|
|
2633
|
-
const
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
resultId += `${rgb[key]};`;
|
|
2649
|
-
});
|
|
2650
|
-
themeCacheKeys$1.forEach((key) => {
|
|
2651
|
-
resultId += `${theme[key]};`;
|
|
2695
|
+
const INCOMPLETE_DOC_LOADING_IMAGE_LIMIT = 256;
|
|
2696
|
+
let loadingImagesCount = 0;
|
|
2697
|
+
async function loadImage(url) {
|
|
2698
|
+
return new Promise((resolve, reject) => {
|
|
2699
|
+
const image = new Image();
|
|
2700
|
+
image.onload = () => resolve(image);
|
|
2701
|
+
image.onerror = () => reject(`Unable to load image ${url}`);
|
|
2702
|
+
if (
|
|
2703
|
+
++loadingImagesCount <= INCOMPLETE_DOC_LOADING_IMAGE_LIMIT ||
|
|
2704
|
+
isReadyStateComplete()
|
|
2705
|
+
) {
|
|
2706
|
+
image.src = url;
|
|
2707
|
+
} else {
|
|
2708
|
+
addReadyStateCompleteListener(() => (image.src = url));
|
|
2709
|
+
}
|
|
2652
2710
|
});
|
|
2653
|
-
return resultId;
|
|
2654
|
-
}
|
|
2655
|
-
function modifyColorWithCache(
|
|
2656
|
-
rgb,
|
|
2657
|
-
theme,
|
|
2658
|
-
modifyHSL,
|
|
2659
|
-
poleColor,
|
|
2660
|
-
anotherPoleColor
|
|
2661
|
-
) {
|
|
2662
|
-
let fnCache;
|
|
2663
|
-
if (colorModificationCache.has(modifyHSL)) {
|
|
2664
|
-
fnCache = colorModificationCache.get(modifyHSL);
|
|
2665
|
-
} else {
|
|
2666
|
-
fnCache = new Map();
|
|
2667
|
-
colorModificationCache.set(modifyHSL, fnCache);
|
|
2668
|
-
}
|
|
2669
|
-
const id = getCacheId(rgb, theme);
|
|
2670
|
-
if (fnCache.has(id)) {
|
|
2671
|
-
return fnCache.get(id);
|
|
2672
|
-
}
|
|
2673
|
-
const hsl = rgbToHSL(rgb);
|
|
2674
|
-
const pole = poleColor == null ? null : parseToHSLWithCache(poleColor);
|
|
2675
|
-
const anotherPole =
|
|
2676
|
-
anotherPoleColor == null ? null : parseToHSLWithCache(anotherPoleColor);
|
|
2677
|
-
const modified = modifyHSL(hsl, pole, anotherPole);
|
|
2678
|
-
const {r, g, b, a} = hslToRGB(modified);
|
|
2679
|
-
const matrix = createFilterMatrix(theme);
|
|
2680
|
-
const [rf, gf, bf] = applyColorMatrix([r, g, b], matrix);
|
|
2681
|
-
const color =
|
|
2682
|
-
a === 1
|
|
2683
|
-
? rgbToHexString({r: rf, g: gf, b: bf})
|
|
2684
|
-
: rgbToString({r: rf, g: gf, b: bf, a});
|
|
2685
|
-
fnCache.set(id, color);
|
|
2686
|
-
return color;
|
|
2687
2711
|
}
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
const
|
|
2694
|
-
|
|
2712
|
+
const MAX_ANALYSIS_PIXELS_COUNT = 32 * 32;
|
|
2713
|
+
let canvas;
|
|
2714
|
+
let context;
|
|
2715
|
+
function createCanvas() {
|
|
2716
|
+
const maxWidth = MAX_ANALYSIS_PIXELS_COUNT;
|
|
2717
|
+
const maxHeight = MAX_ANALYSIS_PIXELS_COUNT;
|
|
2718
|
+
canvas = document.createElement("canvas");
|
|
2719
|
+
canvas.width = maxWidth;
|
|
2720
|
+
canvas.height = maxHeight;
|
|
2721
|
+
context = canvas.getContext("2d", {willReadFrequently: true});
|
|
2722
|
+
context.imageSmoothingEnabled = false;
|
|
2695
2723
|
}
|
|
2696
|
-
function
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
return modifyColorWithCache(rgb, theme, modifyLightModeHSL, poleFg, poleBg);
|
|
2724
|
+
function removeCanvas() {
|
|
2725
|
+
canvas = null;
|
|
2726
|
+
context = null;
|
|
2700
2727
|
}
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2728
|
+
const LARGE_IMAGE_PIXELS_COUNT = 512 * 512;
|
|
2729
|
+
function analyzeImage(image) {
|
|
2730
|
+
if (!canvas) {
|
|
2731
|
+
createCanvas();
|
|
2732
|
+
}
|
|
2733
|
+
let sw;
|
|
2734
|
+
let sh;
|
|
2735
|
+
if (image instanceof HTMLImageElement) {
|
|
2736
|
+
sw = image.naturalWidth;
|
|
2737
|
+
sh = image.naturalHeight;
|
|
2706
2738
|
} else {
|
|
2707
|
-
|
|
2708
|
-
|
|
2739
|
+
sw = image.width;
|
|
2740
|
+
sh = image.height;
|
|
2709
2741
|
}
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
sx = poleBg.s;
|
|
2719
|
-
}
|
|
2742
|
+
if (sw === 0 || sh === 0) {
|
|
2743
|
+
logWarn("Image is empty");
|
|
2744
|
+
return {
|
|
2745
|
+
isDark: false,
|
|
2746
|
+
isLight: false,
|
|
2747
|
+
isTransparent: false,
|
|
2748
|
+
isLarge: false
|
|
2749
|
+
};
|
|
2720
2750
|
}
|
|
2721
|
-
const
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
const
|
|
2728
|
-
const
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2751
|
+
const isLarge = sw * sh > LARGE_IMAGE_PIXELS_COUNT;
|
|
2752
|
+
const sourcePixelsCount = sw * sh;
|
|
2753
|
+
const k = Math.min(
|
|
2754
|
+
1,
|
|
2755
|
+
Math.sqrt(MAX_ANALYSIS_PIXELS_COUNT / sourcePixelsCount)
|
|
2756
|
+
);
|
|
2757
|
+
const width = Math.ceil(sw * k);
|
|
2758
|
+
const height = Math.ceil(sh * k);
|
|
2759
|
+
context.clearRect(0, 0, width, height);
|
|
2760
|
+
context.drawImage(image, 0, 0, sw, sh, 0, 0, width, height);
|
|
2761
|
+
const imageData = context.getImageData(0, 0, width, height);
|
|
2762
|
+
const d = imageData.data;
|
|
2763
|
+
const TRANSPARENT_ALPHA_THRESHOLD = 0.05;
|
|
2764
|
+
const DARK_LIGHTNESS_THRESHOLD = 0.4;
|
|
2765
|
+
const LIGHT_LIGHTNESS_THRESHOLD = 0.7;
|
|
2766
|
+
let transparentPixelsCount = 0;
|
|
2767
|
+
let darkPixelsCount = 0;
|
|
2768
|
+
let lightPixelsCount = 0;
|
|
2769
|
+
let i, x, y;
|
|
2770
|
+
let r, g, b, a;
|
|
2771
|
+
let l;
|
|
2772
|
+
for (y = 0; y < height; y++) {
|
|
2773
|
+
for (x = 0; x < width; x++) {
|
|
2774
|
+
i = 4 * (y * width + x);
|
|
2775
|
+
r = d[i + 0];
|
|
2776
|
+
g = d[i + 1];
|
|
2777
|
+
b = d[i + 2];
|
|
2778
|
+
a = d[i + 3];
|
|
2779
|
+
if (a / 255 < TRANSPARENT_ALPHA_THRESHOLD) {
|
|
2780
|
+
transparentPixelsCount++;
|
|
2781
|
+
} else {
|
|
2782
|
+
l = getSRGBLightness(r, g, b);
|
|
2783
|
+
if (l < DARK_LIGHTNESS_THRESHOLD) {
|
|
2784
|
+
darkPixelsCount++;
|
|
2785
|
+
}
|
|
2786
|
+
if (l > LIGHT_LIGHTNESS_THRESHOLD) {
|
|
2787
|
+
lightPixelsCount++;
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2735
2790
|
}
|
|
2736
|
-
return {h, s, l: lx, a};
|
|
2737
|
-
}
|
|
2738
|
-
let lx = scale(l, 0.5, 1, MAX_BG_LIGHTNESS, pole.l);
|
|
2739
|
-
if (isNeutral) {
|
|
2740
|
-
const hx = pole.h;
|
|
2741
|
-
const sx = pole.s;
|
|
2742
|
-
return {h: hx, s: sx, l: lx, a};
|
|
2743
2791
|
}
|
|
2744
|
-
|
|
2745
|
-
const
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2792
|
+
const totalPixelsCount = width * height;
|
|
2793
|
+
const opaquePixelsCount = totalPixelsCount - transparentPixelsCount;
|
|
2794
|
+
const DARK_IMAGE_THRESHOLD = 0.7;
|
|
2795
|
+
const LIGHT_IMAGE_THRESHOLD = 0.7;
|
|
2796
|
+
const TRANSPARENT_IMAGE_THRESHOLD = 0.1;
|
|
2797
|
+
return {
|
|
2798
|
+
isDark: darkPixelsCount / opaquePixelsCount >= DARK_IMAGE_THRESHOLD,
|
|
2799
|
+
isLight: lightPixelsCount / opaquePixelsCount >= LIGHT_IMAGE_THRESHOLD,
|
|
2800
|
+
isTransparent:
|
|
2801
|
+
transparentPixelsCount / totalPixelsCount >=
|
|
2802
|
+
TRANSPARENT_IMAGE_THRESHOLD,
|
|
2803
|
+
isLarge
|
|
2804
|
+
};
|
|
2805
|
+
}
|
|
2806
|
+
let isBlobURLSupported = null;
|
|
2807
|
+
let canUseProxy = false;
|
|
2808
|
+
let blobURLCheckRequested = false;
|
|
2809
|
+
const blobURLCheckAwaiters = [];
|
|
2810
|
+
document.addEventListener(
|
|
2811
|
+
"__darkreader__inlineScriptsAllowed",
|
|
2812
|
+
() => (canUseProxy = true),
|
|
2813
|
+
{once: true}
|
|
2814
|
+
);
|
|
2815
|
+
async function requestBlobURLCheck() {
|
|
2816
|
+
if (!canUseProxy) {
|
|
2817
|
+
return;
|
|
2753
2818
|
}
|
|
2754
|
-
if (
|
|
2755
|
-
|
|
2819
|
+
if (blobURLCheckRequested) {
|
|
2820
|
+
return await new Promise((resolve) =>
|
|
2821
|
+
blobURLCheckAwaiters.push(resolve)
|
|
2822
|
+
);
|
|
2756
2823
|
}
|
|
2757
|
-
|
|
2824
|
+
blobURLCheckRequested = true;
|
|
2825
|
+
await new Promise((resolve) => {
|
|
2826
|
+
document.addEventListener(
|
|
2827
|
+
"__darkreader__blobURLCheckResponse",
|
|
2828
|
+
(e) => {
|
|
2829
|
+
isBlobURLSupported = e.detail.blobURLAllowed;
|
|
2830
|
+
resolve();
|
|
2831
|
+
blobURLCheckAwaiters.forEach((r) => r());
|
|
2832
|
+
blobURLCheckAwaiters.splice(0);
|
|
2833
|
+
},
|
|
2834
|
+
{once: true}
|
|
2835
|
+
);
|
|
2836
|
+
document.dispatchEvent(
|
|
2837
|
+
new CustomEvent("__darkreader__blobURLCheckRequest")
|
|
2838
|
+
);
|
|
2839
|
+
});
|
|
2758
2840
|
}
|
|
2759
|
-
function
|
|
2760
|
-
|
|
2761
|
-
return modifyLightSchemeColor(rgb, theme);
|
|
2762
|
-
}
|
|
2763
|
-
const pole = getBgPole(theme);
|
|
2764
|
-
return modifyColorWithCache(rgb, {...theme, mode: 0}, modifyBgHSL, pole);
|
|
2841
|
+
function isBlobURLCheckResultReady() {
|
|
2842
|
+
return isBlobURLSupported != null || !canUseProxy;
|
|
2765
2843
|
}
|
|
2766
|
-
function
|
|
2767
|
-
if (
|
|
2768
|
-
|
|
2844
|
+
function onCSPError(err) {
|
|
2845
|
+
if (err.blockedURI === "blob") {
|
|
2846
|
+
isBlobURLSupported = false;
|
|
2847
|
+
document.removeEventListener("securitypolicyviolation", onCSPError);
|
|
2769
2848
|
}
|
|
2770
|
-
return modifyAndRegisterColor(
|
|
2771
|
-
"background",
|
|
2772
|
-
rgb,
|
|
2773
|
-
theme,
|
|
2774
|
-
_modifyBackgroundColor
|
|
2775
|
-
);
|
|
2776
|
-
}
|
|
2777
|
-
const MIN_FG_LIGHTNESS = 0.55;
|
|
2778
|
-
function modifyBlueFgHue(hue) {
|
|
2779
|
-
return scale(hue, 205, 245, 205, 220);
|
|
2780
2849
|
}
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
const lx = scale(l, 0.5, 1, MIN_FG_LIGHTNESS, pole.l);
|
|
2787
|
-
if (isNeutral) {
|
|
2788
|
-
const hx = pole.h;
|
|
2789
|
-
const sx = pole.s;
|
|
2790
|
-
return {h: hx, s: sx, l: lx, a};
|
|
2791
|
-
}
|
|
2792
|
-
let hx = h;
|
|
2793
|
-
if (isBlue) {
|
|
2794
|
-
hx = modifyBlueFgHue(h);
|
|
2795
|
-
}
|
|
2796
|
-
return {h: hx, s, l: lx, a};
|
|
2850
|
+
document.addEventListener("securitypolicyviolation", onCSPError);
|
|
2851
|
+
const objectURLs = new Set();
|
|
2852
|
+
function getFilteredImageURL({dataURL, width, height}, theme) {
|
|
2853
|
+
if (dataURL.startsWith("data:image/svg+xml")) {
|
|
2854
|
+
dataURL = escapeXML(dataURL);
|
|
2797
2855
|
}
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2856
|
+
const matrix = getSVGFilterMatrixValue(theme);
|
|
2857
|
+
const svg = [
|
|
2858
|
+
`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${width}" height="${height}">`,
|
|
2859
|
+
"<defs>",
|
|
2860
|
+
'<filter id="darkreader-image-filter">',
|
|
2861
|
+
`<feColorMatrix type="matrix" values="${matrix}" />`,
|
|
2862
|
+
"</filter>",
|
|
2863
|
+
"</defs>",
|
|
2864
|
+
`<image width="${width}" height="${height}" filter="url(#darkreader-image-filter)" xlink:href="${dataURL}" />`,
|
|
2865
|
+
"</svg>"
|
|
2866
|
+
].join("");
|
|
2867
|
+
if (!isBlobURLSupported) {
|
|
2868
|
+
return `data:image/svg+xml;base64,${btoa(svg)}`;
|
|
2803
2869
|
}
|
|
2804
|
-
|
|
2805
|
-
let
|
|
2806
|
-
|
|
2807
|
-
hx = modifyBlueFgHue(h);
|
|
2808
|
-
lx = scale(l, 0, 0.5, pole.l, Math.min(1, MIN_FG_LIGHTNESS + 0.05));
|
|
2809
|
-
} else {
|
|
2810
|
-
lx = scale(l, 0, 0.5, pole.l, MIN_FG_LIGHTNESS);
|
|
2870
|
+
const bytes = new Uint8Array(svg.length);
|
|
2871
|
+
for (let i = 0; i < svg.length; i++) {
|
|
2872
|
+
bytes[i] = svg.charCodeAt(i);
|
|
2811
2873
|
}
|
|
2812
|
-
|
|
2874
|
+
const blob = new Blob([bytes], {type: "image/svg+xml"});
|
|
2875
|
+
const objectURL = URL.createObjectURL(blob);
|
|
2876
|
+
objectURLs.add(objectURL);
|
|
2877
|
+
return objectURL;
|
|
2813
2878
|
}
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2879
|
+
const xmlEscapeChars = {
|
|
2880
|
+
"<": "<",
|
|
2881
|
+
">": ">",
|
|
2882
|
+
"&": "&",
|
|
2883
|
+
"'": "'",
|
|
2884
|
+
'"': """
|
|
2885
|
+
};
|
|
2886
|
+
function escapeXML(str) {
|
|
2887
|
+
return str.replace(/[<>&'"]/g, (c) => xmlEscapeChars[c] ?? c);
|
|
2820
2888
|
}
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2889
|
+
const dataURLBlobURLs = new Map();
|
|
2890
|
+
function tryConvertDataURLToBlobSync(dataURL) {
|
|
2891
|
+
const colonIndex = dataURL.indexOf(":");
|
|
2892
|
+
const semicolonIndex = dataURL.indexOf(";", colonIndex + 1);
|
|
2893
|
+
const commaIndex = dataURL.indexOf(",", semicolonIndex + 1);
|
|
2894
|
+
const encoding = dataURL
|
|
2895
|
+
.substring(semicolonIndex + 1, commaIndex)
|
|
2896
|
+
.toLocaleLowerCase();
|
|
2897
|
+
const mediaType = dataURL.substring(colonIndex + 1, semicolonIndex);
|
|
2898
|
+
if (encoding !== "base64" || !mediaType) {
|
|
2899
|
+
return null;
|
|
2824
2900
|
}
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
const isNeutral = l < 0.2 || s < 0.24;
|
|
2830
|
-
let hx = h;
|
|
2831
|
-
let sx = s;
|
|
2832
|
-
if (isNeutral) {
|
|
2833
|
-
if (isDark) {
|
|
2834
|
-
hx = poleFg.h;
|
|
2835
|
-
sx = poleFg.s;
|
|
2836
|
-
} else {
|
|
2837
|
-
hx = poleBg.h;
|
|
2838
|
-
sx = poleBg.s;
|
|
2839
|
-
}
|
|
2901
|
+
const characters = atob(dataURL.substring(commaIndex + 1));
|
|
2902
|
+
const bytes = new Uint8Array(characters.length);
|
|
2903
|
+
for (let i = 0; i < characters.length; i++) {
|
|
2904
|
+
bytes[i] = characters.charCodeAt(i);
|
|
2840
2905
|
}
|
|
2841
|
-
|
|
2842
|
-
return {h: hx, s: sx, l: lx, a};
|
|
2906
|
+
return new Blob([bytes], {type: mediaType});
|
|
2843
2907
|
}
|
|
2844
|
-
function
|
|
2845
|
-
if (
|
|
2846
|
-
return
|
|
2908
|
+
async function tryConvertDataURLToBlobURL(dataURL) {
|
|
2909
|
+
if (!isBlobURLSupported) {
|
|
2910
|
+
return null;
|
|
2847
2911
|
}
|
|
2848
|
-
const
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
{...theme, mode: 0},
|
|
2853
|
-
modifyBorderHSL,
|
|
2854
|
-
poleFg,
|
|
2855
|
-
poleBg
|
|
2856
|
-
);
|
|
2857
|
-
}
|
|
2858
|
-
function modifyBorderColor(rgb, theme, shouldRegisterColorVariable = true) {
|
|
2859
|
-
if (!shouldRegisterColorVariable) {
|
|
2860
|
-
return _modifyBorderColor(rgb, theme);
|
|
2912
|
+
const hash = getHashCode(dataURL);
|
|
2913
|
+
let blobURL = dataURLBlobURLs.get(hash);
|
|
2914
|
+
if (blobURL) {
|
|
2915
|
+
return blobURL;
|
|
2861
2916
|
}
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2917
|
+
let blob = tryConvertDataURLToBlobSync(dataURL);
|
|
2918
|
+
if (!blob) {
|
|
2919
|
+
const response = await fetch(dataURL);
|
|
2920
|
+
blob = await response.blob();
|
|
2921
|
+
}
|
|
2922
|
+
blobURL = URL.createObjectURL(blob);
|
|
2923
|
+
dataURLBlobURLs.set(hash, blobURL);
|
|
2924
|
+
return blobURL;
|
|
2866
2925
|
}
|
|
2867
|
-
function
|
|
2868
|
-
|
|
2926
|
+
function cleanImageProcessingCache() {
|
|
2927
|
+
imageManager && imageManager.stop();
|
|
2928
|
+
removeCanvas();
|
|
2929
|
+
objectURLs.forEach((u) => URL.revokeObjectURL(u));
|
|
2930
|
+
objectURLs.clear();
|
|
2931
|
+
dataURLBlobURLs.forEach((u) => URL.revokeObjectURL(u));
|
|
2932
|
+
dataURLBlobURLs.clear();
|
|
2869
2933
|
}
|
|
2870
2934
|
|
|
2871
2935
|
function getPriority(ruleStyle, property) {
|
|
@@ -3126,10 +3190,18 @@ const unparsableColors = new Set([
|
|
|
3126
3190
|
"auto"
|
|
3127
3191
|
]);
|
|
3128
3192
|
function getColorModifier(prop, value, rule) {
|
|
3129
|
-
if (
|
|
3193
|
+
if (
|
|
3194
|
+
unparsableColors.has(value.toLowerCase()) &&
|
|
3195
|
+
!(prop === "color" && value === "initial")
|
|
3196
|
+
) {
|
|
3130
3197
|
return value;
|
|
3131
3198
|
}
|
|
3132
|
-
|
|
3199
|
+
let rgb = null;
|
|
3200
|
+
if (prop === "color" && value === "initial") {
|
|
3201
|
+
rgb = {r: 0, g: 0, b: 0, a: 1};
|
|
3202
|
+
} else {
|
|
3203
|
+
rgb = parseColorWithCache(value);
|
|
3204
|
+
}
|
|
3133
3205
|
if (!rgb) {
|
|
3134
3206
|
logWarn("Couldn't parse color", value);
|
|
3135
3207
|
return null;
|
|
@@ -3531,7 +3603,7 @@ function getScrollbarColorModifier(value) {
|
|
|
3531
3603
|
return null;
|
|
3532
3604
|
}
|
|
3533
3605
|
return (theme) =>
|
|
3534
|
-
`${modifyForegroundColor(thumb, theme)} ${modifyBackgroundColor(
|
|
3606
|
+
`${modifyForegroundColor(thumb, theme)} ${modifyBackgroundColor(track, theme)}`;
|
|
3535
3607
|
}
|
|
3536
3608
|
function getColorSchemeModifier() {
|
|
3537
3609
|
return (theme) => (theme.mode === 0 ? "dark light" : "dark");
|
|
@@ -3882,7 +3954,7 @@ class VariablesStore {
|
|
|
3882
3954
|
const modified = modify();
|
|
3883
3955
|
if (unknownVars.size > 0) {
|
|
3884
3956
|
const isFallbackResolved = modified.match(
|
|
3885
|
-
/^var\(.*?, (var\(--darkreader-bg--.*\))|(#[0-9A-Fa-f]+)|([a-z]+)|(rgba?\(.+\))|(hsla?\(.+\))\)$/
|
|
3957
|
+
/^var\(.*?, ((var\(--darkreader-bg--.*\))|(#[0-9A-Fa-f]+)|([a-z]+)|(rgba?\(.+\))|(hsla?\(.+\)))\)$/
|
|
3886
3958
|
);
|
|
3887
3959
|
if (isFallbackResolved) {
|
|
3888
3960
|
return modified;
|
|
@@ -4352,17 +4424,6 @@ function insertVarValues(source, varValues, fullStack = new Set()) {
|
|
|
4352
4424
|
return replaced;
|
|
4353
4425
|
}
|
|
4354
4426
|
|
|
4355
|
-
const themeCacheKeys = [
|
|
4356
|
-
"mode",
|
|
4357
|
-
"brightness",
|
|
4358
|
-
"contrast",
|
|
4359
|
-
"grayscale",
|
|
4360
|
-
"sepia",
|
|
4361
|
-
"darkSchemeBackgroundColor",
|
|
4362
|
-
"darkSchemeTextColor",
|
|
4363
|
-
"lightSchemeBackgroundColor",
|
|
4364
|
-
"lightSchemeTextColor"
|
|
4365
|
-
];
|
|
4366
4427
|
function getThemeKey(theme) {
|
|
4367
4428
|
let resultKey = "";
|
|
4368
4429
|
themeCacheKeys.forEach((key) => {
|
|
@@ -4673,6 +4734,12 @@ function createStyleSheetModifier() {
|
|
|
4673
4734
|
function buildStyleSheet() {
|
|
4674
4735
|
function createTarget(group, parent) {
|
|
4675
4736
|
const {rule} = group;
|
|
4737
|
+
if (isStyleRule(rule)) {
|
|
4738
|
+
const {selectorText} = rule;
|
|
4739
|
+
const index = parent.cssRules.length;
|
|
4740
|
+
parent.insertRule(`${selectorText} {}`, index);
|
|
4741
|
+
return parent.cssRules[index];
|
|
4742
|
+
}
|
|
4676
4743
|
if (isMediaRule(rule)) {
|
|
4677
4744
|
const {media} = rule;
|
|
4678
4745
|
const index = parent.cssRules.length;
|
|
@@ -4973,6 +5040,25 @@ function createAdoptedStyleSheetFallback() {
|
|
|
4973
5040
|
return {render, destroy, commands};
|
|
4974
5041
|
}
|
|
4975
5042
|
|
|
5043
|
+
const hostsBreakingOnStylePosition = ["www.diffusioneshop.com", "zhale.me"];
|
|
5044
|
+
const mode = hostsBreakingOnStylePosition.includes(location.hostname)
|
|
5045
|
+
? "away"
|
|
5046
|
+
: "next";
|
|
5047
|
+
function getStyleInjectionMode() {
|
|
5048
|
+
return mode;
|
|
5049
|
+
}
|
|
5050
|
+
function injectStyleAway(styleElement) {
|
|
5051
|
+
let container = document.body.querySelector(".darkreader-style-container");
|
|
5052
|
+
if (!container) {
|
|
5053
|
+
container = document.createElement("div");
|
|
5054
|
+
container.classList.add("darkreader");
|
|
5055
|
+
container.classList.add("darkreader-style-container");
|
|
5056
|
+
container.style.display = "none";
|
|
5057
|
+
document.body.append(container);
|
|
5058
|
+
}
|
|
5059
|
+
container.append(styleElement);
|
|
5060
|
+
}
|
|
5061
|
+
|
|
4976
5062
|
const overrides = {
|
|
4977
5063
|
"background-color": {
|
|
4978
5064
|
customProp: "--darkreader-inline-bgcolor",
|
|
@@ -5738,19 +5824,27 @@ function cleanLoadingLinks() {
|
|
|
5738
5824
|
rejectorsForLoadingLinks.clear();
|
|
5739
5825
|
}
|
|
5740
5826
|
function manageStyle(element, {update, loadingStart, loadingEnd}) {
|
|
5741
|
-
const
|
|
5742
|
-
let
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
(
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5827
|
+
const inMode = getStyleInjectionMode();
|
|
5828
|
+
let corsCopy = null;
|
|
5829
|
+
let syncStyle = null;
|
|
5830
|
+
if (inMode === "next") {
|
|
5831
|
+
const prevStyles = [];
|
|
5832
|
+
let next = element;
|
|
5833
|
+
while (
|
|
5834
|
+
(next = next.nextElementSibling) &&
|
|
5835
|
+
next.matches(".darkreader")
|
|
5836
|
+
) {
|
|
5837
|
+
prevStyles.push(next);
|
|
5838
|
+
}
|
|
5839
|
+
corsCopy =
|
|
5840
|
+
prevStyles.find(
|
|
5841
|
+
(el) => el.matches(".darkreader--cors") && !corsStyleSet.has(el)
|
|
5842
|
+
) || null;
|
|
5843
|
+
syncStyle =
|
|
5844
|
+
prevStyles.find(
|
|
5845
|
+
(el) => el.matches(".darkreader--sync") && !syncStyleSet.has(el)
|
|
5846
|
+
) || null;
|
|
5847
|
+
}
|
|
5754
5848
|
let corsCopyPositionWatcher = null;
|
|
5755
5849
|
let syncStylePositionWatcher = null;
|
|
5756
5850
|
let cancelAsyncOperations = false;
|
|
@@ -5830,18 +5924,28 @@ function manageStyle(element, {update, loadingStart, loadingEnd}) {
|
|
|
5830
5924
|
return cssRules;
|
|
5831
5925
|
}
|
|
5832
5926
|
function insertStyle() {
|
|
5833
|
-
if (
|
|
5834
|
-
if (
|
|
5835
|
-
|
|
5927
|
+
if (inMode === "next") {
|
|
5928
|
+
if (corsCopy) {
|
|
5929
|
+
if (element.nextSibling !== corsCopy) {
|
|
5930
|
+
element.parentNode.insertBefore(
|
|
5931
|
+
corsCopy,
|
|
5932
|
+
element.nextSibling
|
|
5933
|
+
);
|
|
5934
|
+
}
|
|
5935
|
+
if (corsCopy.nextSibling !== syncStyle) {
|
|
5936
|
+
element.parentNode.insertBefore(
|
|
5937
|
+
syncStyle,
|
|
5938
|
+
corsCopy.nextSibling
|
|
5939
|
+
);
|
|
5940
|
+
}
|
|
5941
|
+
} else if (element.nextSibling !== syncStyle) {
|
|
5942
|
+
element.parentNode.insertBefore(syncStyle, element.nextSibling);
|
|
5836
5943
|
}
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
corsCopy.nextSibling
|
|
5841
|
-
);
|
|
5944
|
+
} else if (inMode === "away") {
|
|
5945
|
+
if (corsCopy && !corsCopy.parentNode) {
|
|
5946
|
+
injectStyleAway(corsCopy);
|
|
5842
5947
|
}
|
|
5843
|
-
|
|
5844
|
-
element.parentNode.insertBefore(syncStyle, element.nextSibling);
|
|
5948
|
+
injectStyleAway(syncStyle);
|
|
5845
5949
|
}
|
|
5846
5950
|
}
|
|
5847
5951
|
function createSyncStyle() {
|
|
@@ -5899,7 +6003,12 @@ function manageStyle(element, {update, loadingStart, loadingEnd}) {
|
|
|
5899
6003
|
return cssRules;
|
|
5900
6004
|
}
|
|
5901
6005
|
}
|
|
5902
|
-
|
|
6006
|
+
try {
|
|
6007
|
+
cssText = await loadText(element.href);
|
|
6008
|
+
} catch (err) {
|
|
6009
|
+
logWarn(err);
|
|
6010
|
+
cssText = "";
|
|
6011
|
+
}
|
|
5903
6012
|
cssBasePath = getCSSBaseBath(element.href);
|
|
5904
6013
|
if (cancelAsyncOperations) {
|
|
5905
6014
|
return null;
|
|
@@ -5930,12 +6039,31 @@ function manageStyle(element, {update, loadingStart, loadingEnd}) {
|
|
|
5930
6039
|
corsCopy.textContent = fullCSSText;
|
|
5931
6040
|
}
|
|
5932
6041
|
} else {
|
|
5933
|
-
corsCopy = createCORSCopy(
|
|
6042
|
+
corsCopy = createCORSCopy(
|
|
6043
|
+
fullCSSText,
|
|
6044
|
+
inMode === "next"
|
|
6045
|
+
? (cc) =>
|
|
6046
|
+
element.parentNode.insertBefore(
|
|
6047
|
+
cc,
|
|
6048
|
+
element.nextSibling
|
|
6049
|
+
)
|
|
6050
|
+
: injectStyleAway
|
|
6051
|
+
);
|
|
6052
|
+
if (corsCopy) {
|
|
6053
|
+
if (inMode === "next") {
|
|
6054
|
+
element.parentNode.insertBefore(
|
|
6055
|
+
corsCopy,
|
|
6056
|
+
element.nextSibling
|
|
6057
|
+
);
|
|
6058
|
+
} else if (inMode === "away") {
|
|
6059
|
+
injectStyleAway(corsCopy);
|
|
6060
|
+
}
|
|
6061
|
+
}
|
|
5934
6062
|
}
|
|
5935
6063
|
} catch (err) {
|
|
5936
6064
|
logWarn(err);
|
|
5937
6065
|
}
|
|
5938
|
-
if (corsCopy) {
|
|
6066
|
+
if (corsCopy && inMode === "next") {
|
|
5939
6067
|
corsCopyPositionWatcher = watchForNodePosition(
|
|
5940
6068
|
corsCopy,
|
|
5941
6069
|
"prev-sibling"
|
|
@@ -6002,7 +6130,7 @@ function manageStyle(element, {update, loadingStart, loadingEnd}) {
|
|
|
6002
6130
|
removeCSSRulesFromSheet(sheet);
|
|
6003
6131
|
if (syncStylePositionWatcher) {
|
|
6004
6132
|
syncStylePositionWatcher.run();
|
|
6005
|
-
} else {
|
|
6133
|
+
} else if (inMode === "next") {
|
|
6006
6134
|
syncStylePositionWatcher = watchForNodePosition(
|
|
6007
6135
|
syncStyle,
|
|
6008
6136
|
"prev-sibling",
|
|
@@ -6223,7 +6351,7 @@ async function replaceCSSImports(cssText, basePath, cache = new Map()) {
|
|
|
6223
6351
|
cssText = cssText.trim();
|
|
6224
6352
|
return cssText;
|
|
6225
6353
|
}
|
|
6226
|
-
function createCORSCopy(
|
|
6354
|
+
function createCORSCopy(cssText, inject) {
|
|
6227
6355
|
if (!cssText) {
|
|
6228
6356
|
return null;
|
|
6229
6357
|
}
|
|
@@ -6232,7 +6360,7 @@ function createCORSCopy(srcElement, cssText) {
|
|
|
6232
6360
|
cors.classList.add("darkreader--cors");
|
|
6233
6361
|
cors.media = "screen";
|
|
6234
6362
|
cors.textContent = cssText;
|
|
6235
|
-
|
|
6363
|
+
inject(cors);
|
|
6236
6364
|
cors.sheet.disabled = true;
|
|
6237
6365
|
corsStyleSet.add(cors);
|
|
6238
6366
|
return cors;
|
|
@@ -6470,7 +6598,7 @@ function injectProxy(enableStyleSheetsProxy, enableCustomElementRegistryProxy) {
|
|
|
6470
6598
|
);
|
|
6471
6599
|
}
|
|
6472
6600
|
let blobURLAllowed = null;
|
|
6473
|
-
|
|
6601
|
+
function checkBlobURLSupport() {
|
|
6474
6602
|
if (blobURLAllowed != null) {
|
|
6475
6603
|
document.dispatchEvent(
|
|
6476
6604
|
new CustomEvent("__darkreader__blobURLCheckResponse", {
|
|
@@ -6487,17 +6615,18 @@ function injectProxy(enableStyleSheetsProxy, enableCustomElementRegistryProxy) {
|
|
|
6487
6615
|
}
|
|
6488
6616
|
const blob = new Blob([bytes], {type: "image/svg+xml"});
|
|
6489
6617
|
const objectURL = URL.createObjectURL(blob);
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
await new Promise((resolve, reject) => {
|
|
6493
|
-
image.onload = () => resolve();
|
|
6494
|
-
image.onerror = () => reject();
|
|
6495
|
-
image.src = objectURL;
|
|
6496
|
-
});
|
|
6618
|
+
const image = new Image();
|
|
6619
|
+
image.onload = () => {
|
|
6497
6620
|
blobURLAllowed = true;
|
|
6498
|
-
|
|
6621
|
+
sendBlobURLCheckResponse();
|
|
6622
|
+
};
|
|
6623
|
+
image.onerror = () => {
|
|
6499
6624
|
blobURLAllowed = false;
|
|
6500
|
-
|
|
6625
|
+
sendBlobURLCheckResponse();
|
|
6626
|
+
};
|
|
6627
|
+
image.src = objectURL;
|
|
6628
|
+
}
|
|
6629
|
+
function sendBlobURLCheckResponse() {
|
|
6501
6630
|
document.dispatchEvent(
|
|
6502
6631
|
new CustomEvent("__darkreader__blobURLCheckResponse", {
|
|
6503
6632
|
detail: {blobURLAllowed}
|
|
@@ -7006,20 +7135,24 @@ let fixes = null;
|
|
|
7006
7135
|
let isIFrame$1 = null;
|
|
7007
7136
|
let ignoredImageAnalysisSelectors = [];
|
|
7008
7137
|
let ignoredInlineSelectors = [];
|
|
7009
|
-
|
|
7138
|
+
let staticStyleMap = new WeakMap();
|
|
7010
7139
|
function createOrUpdateStyle(className, root = document.head || document) {
|
|
7011
7140
|
let element = root.querySelector(`.${className}`);
|
|
7141
|
+
if (!staticStyleMap.has(root)) {
|
|
7142
|
+
staticStyleMap.set(root, new Map());
|
|
7143
|
+
}
|
|
7144
|
+
const classMap = staticStyleMap.get(root);
|
|
7012
7145
|
if (element) {
|
|
7013
|
-
|
|
7014
|
-
} else if (
|
|
7015
|
-
element =
|
|
7146
|
+
classMap.set(className, element);
|
|
7147
|
+
} else if (classMap.has(className)) {
|
|
7148
|
+
element = classMap.get(className);
|
|
7016
7149
|
} else {
|
|
7017
7150
|
element = document.createElement("style");
|
|
7018
7151
|
element.classList.add("darkreader");
|
|
7019
7152
|
element.classList.add(className);
|
|
7020
7153
|
element.media = "screen";
|
|
7021
7154
|
element.textContent = "";
|
|
7022
|
-
|
|
7155
|
+
classMap.set(className, element);
|
|
7023
7156
|
}
|
|
7024
7157
|
return element;
|
|
7025
7158
|
}
|
|
@@ -7044,27 +7177,36 @@ function stopStylePositionWatchers() {
|
|
|
7044
7177
|
forEach(nodePositionWatchers.values(), (watcher) => watcher.stop());
|
|
7045
7178
|
nodePositionWatchers.clear();
|
|
7046
7179
|
}
|
|
7180
|
+
function injectStaticStyle(style, prevNode, watchAlias, callback) {
|
|
7181
|
+
const mode = getStyleInjectionMode();
|
|
7182
|
+
if (mode === "next") {
|
|
7183
|
+
document.head.insertBefore(
|
|
7184
|
+
style,
|
|
7185
|
+
prevNode ? prevNode.nextSibling : document.head.firstChild
|
|
7186
|
+
);
|
|
7187
|
+
setupNodePositionWatcher(style, watchAlias, callback);
|
|
7188
|
+
} else if (mode === "away") {
|
|
7189
|
+
injectStyleAway(style);
|
|
7190
|
+
}
|
|
7191
|
+
}
|
|
7047
7192
|
function createStaticStyleOverrides() {
|
|
7048
7193
|
const fallbackStyle = createOrUpdateStyle("darkreader--fallback", document);
|
|
7049
7194
|
fallbackStyle.textContent = getModifiedFallbackStyle(theme, {strict: true});
|
|
7050
|
-
|
|
7051
|
-
setupNodePositionWatcher(fallbackStyle, "fallback");
|
|
7195
|
+
injectStaticStyle(fallbackStyle, null, "fallback");
|
|
7052
7196
|
const userAgentStyle = createOrUpdateStyle("darkreader--user-agent");
|
|
7053
7197
|
userAgentStyle.textContent = getModifiedUserAgentStyle(
|
|
7054
7198
|
theme,
|
|
7055
7199
|
isIFrame$1,
|
|
7056
7200
|
theme.styleSystemControls
|
|
7057
7201
|
);
|
|
7058
|
-
|
|
7059
|
-
setupNodePositionWatcher(userAgentStyle, "user-agent");
|
|
7202
|
+
injectStaticStyle(userAgentStyle, fallbackStyle, "user-agent");
|
|
7060
7203
|
const textStyle = createOrUpdateStyle("darkreader--text");
|
|
7061
7204
|
if (theme.useFont || theme.textStroke > 0) {
|
|
7062
7205
|
textStyle.textContent = createTextStyle(theme);
|
|
7063
7206
|
} else {
|
|
7064
7207
|
textStyle.textContent = "";
|
|
7065
7208
|
}
|
|
7066
|
-
|
|
7067
|
-
setupNodePositionWatcher(textStyle, "text");
|
|
7209
|
+
injectStaticStyle(textStyle, userAgentStyle, "text");
|
|
7068
7210
|
const invertStyle = createOrUpdateStyle("darkreader--invert");
|
|
7069
7211
|
if (fixes && Array.isArray(fixes.invert) && fixes.invert.length > 0) {
|
|
7070
7212
|
invertStyle.textContent = [
|
|
@@ -7081,17 +7223,10 @@ function createStaticStyleOverrides() {
|
|
|
7081
7223
|
} else {
|
|
7082
7224
|
invertStyle.textContent = "";
|
|
7083
7225
|
}
|
|
7084
|
-
|
|
7085
|
-
setupNodePositionWatcher(invertStyle, "invert");
|
|
7226
|
+
injectStaticStyle(invertStyle, textStyle, "invert");
|
|
7086
7227
|
const inlineStyle = createOrUpdateStyle("darkreader--inline");
|
|
7087
7228
|
inlineStyle.textContent = getInlineOverrideStyle();
|
|
7088
|
-
|
|
7089
|
-
setupNodePositionWatcher(inlineStyle, "inline");
|
|
7090
|
-
const overrideStyle = createOrUpdateStyle("darkreader--override");
|
|
7091
|
-
overrideStyle.textContent =
|
|
7092
|
-
fixes && fixes.css ? replaceCSSTemplates(fixes.css) : "";
|
|
7093
|
-
document.head.appendChild(overrideStyle);
|
|
7094
|
-
setupNodePositionWatcher(overrideStyle, "override");
|
|
7229
|
+
injectStaticStyle(inlineStyle, invertStyle, "inline");
|
|
7095
7230
|
const variableStyle = createOrUpdateStyle("darkreader--variables");
|
|
7096
7231
|
const selectionColors = theme?.selectionColor
|
|
7097
7232
|
? getSelectionColor(theme)
|
|
@@ -7112,13 +7247,12 @@ function createStaticStyleOverrides() {
|
|
|
7112
7247
|
` --darkreader-selection-text: ${selectionColors?.foregroundColorSelection ?? "initial"};`,
|
|
7113
7248
|
`}`
|
|
7114
7249
|
].join("\n");
|
|
7115
|
-
|
|
7116
|
-
setupNodePositionWatcher(variableStyle, "variables", () =>
|
|
7250
|
+
injectStaticStyle(variableStyle, inlineStyle, "variables", () =>
|
|
7117
7251
|
registerVariablesSheet(variableStyle.sheet)
|
|
7118
7252
|
);
|
|
7119
7253
|
registerVariablesSheet(variableStyle.sheet);
|
|
7120
7254
|
const rootVarsStyle = createOrUpdateStyle("darkreader--root-vars");
|
|
7121
|
-
|
|
7255
|
+
injectStaticStyle(rootVarsStyle, variableStyle, "root-vars");
|
|
7122
7256
|
const enableStyleSheetsProxy = !(fixes && fixes.disableStyleSheetsProxy);
|
|
7123
7257
|
const enableCustomElementRegistryProxy = !(
|
|
7124
7258
|
fixes && fixes.disableCustomElementRegistryProxy
|
|
@@ -7132,6 +7266,10 @@ function createStaticStyleOverrides() {
|
|
|
7132
7266
|
document.head.insertBefore(proxyScript, rootVarsStyle.nextSibling);
|
|
7133
7267
|
proxyScript.remove();
|
|
7134
7268
|
}
|
|
7269
|
+
const overrideStyle = createOrUpdateStyle("darkreader--override");
|
|
7270
|
+
overrideStyle.textContent =
|
|
7271
|
+
fixes && fixes.css ? replaceCSSTemplates(fixes.css) : "";
|
|
7272
|
+
injectStaticStyle(overrideStyle, document.head.lastChild, "override");
|
|
7135
7273
|
}
|
|
7136
7274
|
const shadowRootsWithOverrides = new Set();
|
|
7137
7275
|
function createShadowStaticStyleOverridesInner(root) {
|
|
@@ -7207,7 +7345,8 @@ function replaceCSSTemplates($cssText) {
|
|
|
7207
7345
|
}
|
|
7208
7346
|
function cleanFallbackStyle() {
|
|
7209
7347
|
const fallback =
|
|
7210
|
-
staticStyleMap.get("darkreader--fallback") ||
|
|
7348
|
+
staticStyleMap.get(document.head)?.get("darkreader--fallback") ||
|
|
7349
|
+
staticStyleMap.get(document)?.get("darkreader--fallback") ||
|
|
7211
7350
|
document.querySelector(".darkreader--fallback");
|
|
7212
7351
|
if (fallback) {
|
|
7213
7352
|
fallback.textContent = "";
|
|
@@ -7736,7 +7875,7 @@ function removeDynamicTheme() {
|
|
|
7736
7875
|
selectors.forEach((selector) =>
|
|
7737
7876
|
removeNode(document.head.querySelector(selector))
|
|
7738
7877
|
);
|
|
7739
|
-
staticStyleMap
|
|
7878
|
+
staticStyleMap = new WeakMap();
|
|
7740
7879
|
removeProxy();
|
|
7741
7880
|
}
|
|
7742
7881
|
shadowRootsWithOverrides.forEach((root) => {
|