Add a new preference, viewerCssTheme, to allow forcing the use of the light/dark viewer CSS themes (issue 12290)

While this does work pretty well in my quick testing, it's *very much* a hack since as far as I can tell there's no support in the CSS specification for using e.g. a CSS variable to override a `@media (prefers-color-scheme: dark) {...}` block.

The solution implemented here is thus to *edit* the viewer CSS, by either removing the entire `@media ...` block in light-mode or by ensuring that its rules become *unconditionally* applied in dark-mode.
To simplify the overall implementation, since all of this does seem like somewhat of an edge-case, the `viewerCssTheme` preference will *only* be read during viewer initialization. (Similar to many other existing preferences, a reload is thus required when changing it.)
This commit is contained in:
Jonas Jenwald 2020-11-15 13:29:50 +01:00
parent f39d87bff1
commit 40a4d53fb3
3 changed files with 61 additions and 0 deletions

View File

@ -198,6 +198,15 @@
2 2
], ],
"default": -1 "default": -1
},
"viewerCssTheme": {
"type": "integer",
"enum": [
0,
1,
2
],
"default": 0
} }
} }
} }

View File

@ -90,6 +90,12 @@ const ViewOnLoad = {
INITIAL: 1, INITIAL: 1,
}; };
const ViewerCssTheme = {
AUTOMATIC: 0, // Default value.
LIGHT: 1,
DARK: 2,
};
// Keep these in sync with mozilla-central's Histograms.json. // Keep these in sync with mozilla-central's Histograms.json.
const KNOWN_VERSIONS = [ const KNOWN_VERSIONS = [
"1.0", "1.0",
@ -256,6 +262,7 @@ const PDFViewerApplication = {
await this._readPreferences(); await this._readPreferences();
await this._parseHashParameters(); await this._parseHashParameters();
this._forceCssTheme();
await this._initializeL10n(); await this._initializeL10n();
if ( if (
@ -396,6 +403,46 @@ const PDFViewerApplication = {
document.getElementsByTagName("html")[0].dir = dir; document.getElementsByTagName("html")[0].dir = dir;
}, },
/**
* @private
*/
_forceCssTheme() {
const cssTheme = AppOptions.get("viewerCssTheme");
if (
cssTheme === ViewerCssTheme.AUTOMATIC ||
!Object.values(ViewerCssTheme).includes(cssTheme)
) {
return;
}
try {
const styleSheet = document.styleSheets[0];
const cssRules = styleSheet?.cssRules || [];
for (let i = 0, ii = cssRules.length; i < ii; i++) {
const rule = cssRules[i];
if (
rule instanceof CSSMediaRule &&
rule.media?.[0] === "(prefers-color-scheme: dark)"
) {
if (cssTheme === ViewerCssTheme.LIGHT) {
styleSheet.deleteRule(i);
return;
}
// cssTheme === ViewerCssTheme.DARK
const darkRules = /^@media \(prefers-color-scheme: dark\) {\n\s*([\w\s-.,:;/\\{}()]+)\n}$/.exec(
rule.cssText
);
if (darkRules?.[1]) {
styleSheet.deleteRule(i);
styleSheet.insertRule(darkRules[1], i);
}
return;
}
}
} catch (reason) {
console.error(`_forceCssTheme: "${reason?.message}".`);
}
},
/** /**
* @private * @private
*/ */

View File

@ -154,6 +154,11 @@ const defaultOptions = {
value: false, value: false,
kind: OptionKind.VIEWER + OptionKind.PREFERENCE, kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
}, },
viewerCssTheme: {
/** @type {number} */
value: 0,
kind: OptionKind.VIEWER + OptionKind.PREFERENCE,
},
viewOnLoad: { viewOnLoad: {
/** @type {boolean} */ /** @type {boolean} */
value: 0, value: 0,