diff --git a/dom/chrome-webidl/InspectorUtils.webidl b/dom/chrome-webidl/InspectorUtils.webidl index a0e9618cccc4..8af0f2752dd5 100644 --- a/dom/chrome-webidl/InspectorUtils.webidl +++ b/dom/chrome-webidl/InspectorUtils.webidl @@ -38,7 +38,7 @@ namespace InspectorUtils { sequence getCSSPropertyPrefs(); [Throws] sequence getCSSValuesForProperty(UTF8String property); [Throws] DOMString rgbToColorName(octet r, octet g, octet b); - InspectorRGBATuple? colorToRGBA(UTF8String colorString, optional Document? doc = null); + InspectorRGBATuple? colorToRGBA(UTF8String colorString); boolean isValidCSSColor(UTF8String colorString); [Throws] sequence getSubpropertiesForCSSProperty(UTF8String property); [Throws] boolean cssPropertyIsShorthand(UTF8String property); diff --git a/layout/inspector/InspectorUtils.cpp b/layout/inspector/InspectorUtils.cpp index 4ce8eced34c2..729713c7ce7b 100644 --- a/layout/inspector/InspectorUtils.cpp +++ b/layout/inspector/InspectorUtils.cpp @@ -483,19 +483,12 @@ void InspectorUtils::RgbToColorName(GlobalObject& aGlobalObject, uint8_t aR, } /* static */ -void InspectorUtils::ColorToRGBA(GlobalObject&, const nsACString& aColorString, - const Document* aDoc, +void InspectorUtils::ColorToRGBA(GlobalObject& aGlobalObject, + const nsACString& aColorString, Nullable& aResult) { nscolor color = NS_RGB(0, 0, 0); - ServoStyleSet* styleSet = nullptr; - if (aDoc) { - if (PresShell* ps = aDoc->GetPresShell()) { - styleSet = ps->StyleSet(); - } - } - - if (!ServoCSSParser::ComputeColor(styleSet, NS_RGB(0, 0, 0), aColorString, + if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), aColorString, &color)) { aResult.SetNull(); return; diff --git a/layout/inspector/InspectorUtils.h b/layout/inspector/InspectorUtils.h index 6fb7e0977037..87d8ec5e70b1 100644 --- a/layout/inspector/InspectorUtils.h +++ b/layout/inspector/InspectorUtils.h @@ -133,8 +133,7 @@ class InspectorUtils { // // NOTE: Converting a color to RGBA may be lossy when converting from some // formats e.g. CMYK. - static void ColorToRGBA(GlobalObject&, const nsACString& aColorString, - const Document*, + static void ColorToRGBA(GlobalObject& aGlobal, const nsACString& aColorString, Nullable& aResult); // Check whether a given color is a valid CSS color. diff --git a/layout/inspector/tests/test_color_to_rgba.html b/layout/inspector/tests/test_color_to_rgba.html index 96952ad8f20f..09ea20da04ab 100644 --- a/layout/inspector/tests/test_color_to_rgba.html +++ b/layout/inspector/tests/test_color_to_rgba.html @@ -25,15 +25,6 @@ testColor("hsl(170,60%,40%,0.9)", {r:41, g:163, b:143, a:0.9}); testColor("hsla(170,60%,40%,0.9)", {r:41, g:163, b:143, a:0.9}); - // NOTE: LightweightThemeConsumer is the only consumer of this API, for - // backwards compat reasons... But it doesn't seem like it'd really need to - // care about system colors, so maybe we can remove it in the future. - isnot( - InspectorUtils.colorToRGBA("ButtonText", document), - null, - "Should support system colors when given a displayed document" - ); - function testColor(color, expected) { let rgb = InspectorUtils.colorToRGBA(color); diff --git a/toolkit/modules/LightweightThemeConsumer.jsm b/toolkit/modules/LightweightThemeConsumer.jsm index e5971a2b8e08..133ce377a05b 100644 --- a/toolkit/modules/LightweightThemeConsumer.jsm +++ b/toolkit/modules/LightweightThemeConsumer.jsm @@ -342,8 +342,9 @@ LightweightThemeConsumer.prototype = { if (properties.colors) { for (const property in properties.colors) { const cssVariable = experiment.colors[property]; - const value = _rgbaToString( - _cssColorToRGBA(root.ownerDocument, properties.colors[property]) + const value = _sanitizeCSSColor( + root.ownerDocument, + properties.colors[property] ); usedVariables.push([cssVariable, value]); } @@ -389,7 +390,7 @@ function _getContentProperties(doc, active, data) { let properties = {}; for (let property in data) { if (ThemeContentPropertyList.includes(property)) { - properties[property] = _cssColorToRGBA(doc, data[property]); + properties[property] = _parseRGBA(_sanitizeCSSColor(doc, data[property])); } } return properties; @@ -416,6 +417,7 @@ function _setProperty(elem, active, variableName, value) { } function _setProperties(root, active, themeData) { + let properties = []; let propertyOverrides = new Map(); for (let map of [toolkitVariableMap, ThemeVariableMap]) { @@ -432,41 +434,65 @@ function _setProperties(root, active, themeData) { : root; let val = propertyOverrides.get(lwtProperty) || themeData[lwtProperty]; if (isColor) { - val = _cssColorToRGBA(root.ownerDocument, val); + val = _sanitizeCSSColor(root.ownerDocument, val); if (!val && fallbackProperty) { - val = _cssColorToRGBA( + val = _sanitizeCSSColor( root.ownerDocument, themeData[fallbackProperty] ); } if (processColor) { - val = processColor(val, elem, propertyOverrides); - } else { - val = _rgbaToString(val); + val = processColor(_parseRGBA(val), elem, propertyOverrides); } } - _setProperty(elem, active, cssVarName, val); + properties.push([elem, cssVarName, val]); } } + + // Set all the properties together, since _sanitizeCSSColor flushes. + for (const [elem, cssVarName, val] of properties) { + _setProperty(elem, active, cssVarName, val); + } } -const kInvalidColor = { r: 0, g: 0, b: 0, a: 1 }; - -function _cssColorToRGBA(doc, cssColor) { +function _sanitizeCSSColor(doc, cssColor) { if (!cssColor) { return null; } - return ( - doc.defaultView.InspectorUtils.colorToRGBA(cssColor, doc) || kInvalidColor - ); + const HTML_NS = "http://www.w3.org/1999/xhtml"; + // style.color normalizes color values and makes invalid ones black, so a + // simple round trip gets us a sanitized color value. + // Use !important so that the theme's stylesheets cannot override us. + let div = doc.createElementNS(HTML_NS, "div"); + div.style.setProperty("color", "black", "important"); + div.style.setProperty("display", "none", "important"); + let span = doc.createElementNS(HTML_NS, "span"); + span.style.setProperty("color", cssColor, "important"); + + // CSS variables are not allowed and should compute to black. + if (span.style.color.includes("var(")) { + span.style.color = ""; + } + + div.appendChild(span); + doc.documentElement.appendChild(div); + cssColor = doc.defaultView.getComputedStyle(span).color; + div.remove(); + return cssColor; } -function _rgbaToString(parsedColor) { - if (!parsedColor) { +function _parseRGBA(aColorString) { + if (!aColorString) { return null; } - let { r, g, b, a } = parsedColor; - return `rgba(${r}, ${g}, ${b}, ${a})`; + var rgba = aColorString.replace(/(rgba?\()|(\)$)/g, "").split(","); + rgba = rgba.map(x => parseFloat(x)); + return { + r: rgba[0], + g: rgba[1], + b: rgba[2], + a: 3 in rgba ? rgba[3] : 1, + }; } function _isColorDark(r, g, b) {