From d1f13a6af36a734816a69e3992dc320fe7686994 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 7 May 2022 22:00:54 +0200 Subject: [PATCH] Use the regular `preprocess`-function for the CSS files as well An old shortcoming of the `preprocessCSS`-function is its complete lack of support for our "normal" defines, which makes it very difficult to have build-specific CSS rules. Recently we've started using specially crafted comments to remove CSS rules from the MOZCENTRAL build, but (ab)using the `preprocessCSS`-function in this way really doesn't feel great. However, it turns out to be surprisingly simple to instead use the "regular" `preprocess`-function for the CSS files as well. The only special-handling that's still necessary is the helper-function for dealing with CSS-imports, but apart from that everything seems to just work. One reason, as far as I can tell, for having a separate `preprocessCSS`-function was likely that we originally used *lots* of vendor-prefixed CSS rules in our CSS files. With improvements over the years, especially thanks to Autoprefixer and PostCSS, we've been able to remove *almost* all non-standard CSS rules and the need for special-casing the CSS parsing has mostly vanished. *Please note:* As part of testing this patch I've diffed the output of `gulp generic`, `gulp mozcentral`, and `gulp chromium` against the `master`-branch to check that there was no obvious breakage. --- external/builder/builder.js | 98 ++++--------------- .../builder/fixtures/if-nested-expected.css | 3 + external/builder/fixtures/if-nested.css | 14 +++ gulpfile.js | 2 +- web/viewer.css | 35 ++++--- 5 files changed, 61 insertions(+), 91 deletions(-) create mode 100644 external/builder/fixtures/if-nested-expected.css create mode 100644 external/builder/fixtures/if-nested.css diff --git a/external/builder/builder.js b/external/builder/builder.js index 378de9bd6..8c44ddeb2 100644 --- a/external/builder/builder.js +++ b/external/builder/builder.js @@ -38,9 +38,25 @@ function preprocess(inFilename, outFilename, defines) { return fs.realpathSync(inFilename) + ":" + lineNumber; } + function expandCssImports(content, baseUrl) { + return content.replace( + /^\s*@import\s+url\(([^)]+)\);\s*$/gm, + function (all, url) { + const file = path.join(path.dirname(baseUrl), url); + const imported = fs.readFileSync(file, "utf8").toString(); + return expandCssImports(imported, file); + } + ); + } + // TODO make this really read line by line. - const lines = fs.readFileSync(inFilename).toString().split("\n"); - const totalLines = lines.length; + let content = fs.readFileSync(inFilename, "utf8").toString(); + // Handle CSS-imports first, when necessary. + if (/\.css$/i.test(inFilename)) { + content = expandCssImports(content, inFilename); + } + const lines = content.split("\n"), + totalLines = lines.length; let out = ""; let i = 0; function readLine() { @@ -123,7 +139,7 @@ function preprocess(inFilename, outFilename, defines) { let state = STATE_NONE; const stack = []; const control = - /^(?:\/\/|)?$)?/; + /^(?:\/\/|\s*\/\*|)?$)?/; while ((line = readLine()) !== null) { ++lineNumber; @@ -199,82 +215,6 @@ function preprocess(inFilename, outFilename, defines) { } exports.preprocess = preprocess; -function preprocessCSS(inFilename, outFilename, defines) { - function hasPrefixedMozcentral(line) { - return /(^|\W)-(ms|o|webkit)-\w/.test(line); - } - - function expandImports(content, baseUrl) { - return content.replace( - /^\s*@import\s+url\(([^)]+)\);\s*$/gm, - function (all, url) { - const file = path.join(path.dirname(baseUrl), url); - const imported = fs.readFileSync(file, "utf8").toString(); - return expandImports(imported, file); - } - ); - } - - function removePrefixed(content, hasPrefixedFilter) { - const lines = content.split(/\r?\n/g); - let i = 0; - while (i < lines.length) { - const line = lines[i]; - if (!hasPrefixedFilter(line)) { - i++; - continue; - } - if (/\{\s*$/.test(line)) { - let bracketLevel = 1; - let j = i + 1; - while (j < lines.length && bracketLevel > 0) { - const checkBracket = /([{}])\s*$/.exec(lines[j]); - if (checkBracket) { - if (checkBracket[1] === "{") { - bracketLevel++; - } else if (!lines[j].includes("{")) { - bracketLevel--; - } - } - j++; - } - lines.splice(i, j - i); - } else if (/[};]\s*$/.test(line)) { - lines.splice(i, 1); - } else { - // multiline? skipping until next directive or bracket - do { - lines.splice(i, 1); - } while ( - i < lines.length && - !/\}\s*$/.test(lines[i]) && - !lines[i].includes(":") - ); - if (i < lines.length && /\S\s*}\s*$/.test(lines[i])) { - lines[i] = lines[i].substring(lines[i].indexOf("}")); - } - } - // collapse whitespaces - while (lines[i] === "" && lines[i - 1] === "") { - lines.splice(i, 1); - } - } - return lines.join("\n"); - } - - if (!defines) { - throw new Error("Missing CSS preprocessor defines."); - } - - let content = fs.readFileSync(inFilename, "utf8").toString(); - content = expandImports(content, inFilename); - if (defines.MOZCENTRAL) { - content = removePrefixed(content, hasPrefixedMozcentral); - } - fs.writeFileSync(outFilename, content); -} -exports.preprocessCSS = preprocessCSS; - /** * Merge two defines arrays. Values in the second param will override values in * the first. diff --git a/external/builder/fixtures/if-nested-expected.css b/external/builder/fixtures/if-nested-expected.css new file mode 100644 index 000000000..e3859d72f --- /dev/null +++ b/external/builder/fixtures/if-nested-expected.css @@ -0,0 +1,3 @@ +div { + margin: 0; +} diff --git a/external/builder/fixtures/if-nested.css b/external/builder/fixtures/if-nested.css new file mode 100644 index 000000000..67ae1b309 --- /dev/null +++ b/external/builder/fixtures/if-nested.css @@ -0,0 +1,14 @@ +/*#if TRUE*/ +div { + margin: 0; + /*#if FALSE*/ + padding: 0; + /*#endif*/ +} +/*#endif*/ + +/*#if FALSE*/ +p { + margin: 0; +} +/*#endif*/ diff --git a/gulpfile.js b/gulpfile.js index 16a635371..d3da8bea5 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -816,7 +816,7 @@ gulp.task("cmaps", function (done) { function preprocessCSS(source, defines) { const outName = getTempFile("~preprocess", ".css"); - builder.preprocessCSS(source, outName, defines); + builder.preprocess(source, outName, defines); let out = fs.readFileSync(outName).toString(); fs.unlinkSync(outName); diff --git a/web/viewer.css b/web/viewer.css index 23f2fe9e0..5ba13bd93 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -29,7 +29,9 @@ --main-color: rgba(12, 12, 13, 1); --body-bg-color: rgba(237, 237, 240, 1); - --errorWrapper-bg-color: rgba(255, 110, 110, 1); /* -webkit-non-mozcentral */ + /*#if !MOZCENTRAL*/ + --errorWrapper-bg-color: rgba(255, 110, 110, 1); + /*#endif*/ --progressBar-color: rgba(10, 132, 255, 1); --progressBar-indeterminate-bg-color: rgba(221, 221, 222, 1); --progressBar-indeterminate-blend-color: rgba(116, 177, 239, 1); @@ -77,7 +79,9 @@ --toolbarButton-zoomIn-icon: url(images/toolbarButton-zoomIn.svg); --toolbarButton-presentationMode-icon: url(images/toolbarButton-presentationMode.svg); --toolbarButton-print-icon: url(images/toolbarButton-print.svg); - --toolbarButton-openFile-icon: url(images/toolbarButton-openFile.svg); /* -webkit-non-mozcentral */ + /*#if GENERIC*/ + --toolbarButton-openFile-icon: url(images/toolbarButton-openFile.svg); + /*#endif*/ --toolbarButton-download-icon: url(images/toolbarButton-download.svg); --toolbarButton-bookmark-icon: url(images/toolbarButton-bookmark.svg); --toolbarButton-viewThumbnail-icon: url(images/toolbarButton-viewThumbnail.svg); @@ -112,7 +116,9 @@ :root { --main-color: rgba(249, 249, 250, 1); --body-bg-color: rgba(42, 42, 46, 1); - --errorWrapper-bg-color: rgba(169, 14, 14, 1); /* -webkit-non-mozcentral */ + /*#if !MOZCENTRAL*/ + --errorWrapper-bg-color: rgba(169, 14, 14, 1); + /*#endif*/ --progressBar-color: rgba(0, 96, 223, 1); --progressBar-indeterminate-bg-color: rgba(40, 40, 43, 1); --progressBar-indeterminate-blend-color: rgba(20, 68, 133, 1); @@ -457,9 +463,11 @@ select { #findInput { width: 200px; } +/*#if !MOZCENTRAL*/ #findInput::-webkit-input-placeholder { color: rgba(191, 191, 191, 1); } +/*#endif*/ #findInput::placeholder { font-style: normal; } @@ -817,10 +825,12 @@ select { mask-image: var(--toolbarButton-print-icon); } -#openFile::before, /* -webkit-non-mozcentral */ -#secondaryOpenFile::before /* -webkit-non-mozcentral */ { +/*#if GENERIC*/ +#openFile::before, +#secondaryOpenFile::before { mask-image: var(--toolbarButton-openFile-icon); } +/*#endif*/ #download::before, #secondaryDownload::before { @@ -1002,10 +1012,11 @@ a.secondaryToolbarButton[href="#"] { background-repeat: no-repeat; background-position: 3px; } - +/*#if !MOZCENTRAL*/ #pageNumber::-webkit-inner-spin-button { -webkit-appearance: none; } +/*#endif*/ .toolbarField:focus { border-color: #0a84ff; @@ -1174,7 +1185,8 @@ a:focus > .thumbnail > .thumbnailSelectionRing, background: rgba(0, 0, 255, 0.3); } -#errorWrapper /* -webkit-non-mozcentral */ { +/*#if !MOZCENTRAL*/ +#errorWrapper { background-color: var(--errorWrapper-bg-color); color: var(--main-color); left: 0; @@ -1184,17 +1196,17 @@ a:focus > .thumbnail > .thumbnailSelectionRing, padding: 3px 6px; } -#errorMessageLeft /* -webkit-non-mozcentral */ { +#errorMessageLeft { float: left; } -#errorMessageRight /* -webkit-non-mozcentral */ { +#errorMessageRight { float: right; } -#errorSpacer /* -webkit-non-mozcentral */ { +#errorSpacer { clear: both; } -#errorMoreInfo /* -webkit-non-mozcentral */ { +#errorMoreInfo { background-color: var(--field-bg-color); color: var(--field-color); border: 1px solid var(--field-border-color); @@ -1202,6 +1214,7 @@ a:focus > .thumbnail > .thumbnailSelectionRing, margin: 3px; width: 98%; } +/*#endif*/ .dialogButton { width: auto;