Title: [286558] trunk
Revision
286558
Author
[email protected]
Date
2021-12-06 11:45:45 -0800 (Mon, 06 Dec 2021)

Log Message

Web Inspector: Support Cascade Layers in the Styles sidebar
https://bugs.webkit.org/show_bug.cgi?id=233208

Reviewed by Devin Rousso.

Source/_javascript_Core:

Add new values to `CSS.Grouping`'s `type` enum for cascade layers and make the `text` optional since an
anonymous layer will not have a name or other text.

* inspector/protocol/CSS.json:

Source/WebCore:

Test: inspector/css/getMatchedStylesForNodeLayerGrouping.html

Add support for parsing and grouping CSS `@layer` rules in `InspectorStyleSheet` to the existing paths for
handling other groupings so that the frontend is made aware of rules wrapped inside a layer or multiple layers.

* Headers.cmake:
* WebCore.xcodeproj/project.pbxproj:
- CompiledSelector.h needs to be exported as a private header to include in WebKitLegacy's build, since it is
imported by StyleRule.h, which is now imported by CSSImportRule.h, which is imported in WebKitLegacy.

* css/CSSImportRule.cpp:
(WebCore::CSSImportRule::cascadeLayerName const):
* css/CSSImportRule.h:
* css/CSSLayerRule.cpp:
(WebCore::CSSLayerRule::cssText const):
(WebCore::CSSLayerRule::layerName const):
(WebCore::CSSLayerRule::stringFromCascadeLayerName):
* css/CSSLayerRule.h:
* inspector/InspectorStyleSheet.cpp:
(flattenSourceData):
(WebCore::asCSSRuleList):
(WebCore::buildArrayForGroupings):
* style/InspectorCSSOMWrappers.cpp:
(WebCore::Style::InspectorCSSOMWrappers::collect):

Source/WebInspectorUI:

* UserInterface/Models/CSSGrouping.js:
(WI.CSSGrouping):
(WI.CSSGrouping.prototype.get isLayer):
(WI.CSSGrouping.prototype.get prefix):
- Update `CSSGrouping` to support `@layer` rules, and make `text` optional for a grouping, since anonymous layers
will not have a name.

* UserInterface/Models/CSSStyleDeclaration.js:
(WI.CSSStyleDeclaration.prototype.generateFormattedText):
- Ensure that spacing remains correct and "null" isn't shown for groupings without text.

* UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js:
(WI.SpreadsheetCSSStyleDeclarationSection.prototype.initialLayout):
- When merging layer groups, ensure that a "." is used as a separator, and that each group has a name (to
prevent having a hanging period or the "null" text appearing).

LayoutTests:

Add new test cases for `CSS.getMatchesStyleForNode` to make sure that layer groupings are correctly determined,
and that rules nested in `@layer` rules and `@import layer()`s are correctly represented and sorted by the order
they are applied to an element.

* inspector/css/getMatchedStylesForNode-expected.txt:
- Re-baseline to account for change in order of CSSGrouping properties in the protocol due to `text` now being
optional.
* inspector/css/getMatchedStylesForNodeLayerGrouping-expected.txt: Added.
* inspector/css/getMatchedStylesForNodeLayerGrouping.html: Added.
* inspector/css/resources/external-layers.css: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (286557 => 286558)


--- trunk/LayoutTests/ChangeLog	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/LayoutTests/ChangeLog	2021-12-06 19:45:45 UTC (rev 286558)
@@ -1,3 +1,21 @@
+2021-12-06  Patrick Angle  <[email protected]>
+
+        Web Inspector: Support Cascade Layers in the Styles sidebar
+        https://bugs.webkit.org/show_bug.cgi?id=233208
+
+        Reviewed by Devin Rousso.
+
+        Add new test cases for `CSS.getMatchesStyleForNode` to make sure that layer groupings are correctly determined,
+        and that rules nested in `@layer` rules and `@import layer()`s are correctly represented and sorted by the order
+        they are applied to an element.
+
+        * inspector/css/getMatchedStylesForNode-expected.txt:
+        - Re-baseline to account for change in order of CSSGrouping properties in the protocol due to `text` now being
+        optional.
+        * inspector/css/getMatchedStylesForNodeLayerGrouping-expected.txt: Added.
+        * inspector/css/getMatchedStylesForNodeLayerGrouping.html: Added.
+        * inspector/css/resources/external-layers.css: Added.
+
 2021-12-06  Antoine Quint  <[email protected]>
 
         [Web Animations] Add a way to run scripted animations

Modified: trunk/LayoutTests/inspector/css/getMatchedStylesForNode-expected.txt (286557 => 286558)


--- trunk/LayoutTests/inspector/css/getMatchedStylesForNode-expected.txt	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/LayoutTests/inspector/css/getMatchedStylesForNode-expected.txt	2021-12-06 19:45:45 UTC (rev 286558)
@@ -904,8 +904,8 @@
           "ruleId": "<filtered>",
           "groupings": [
             {
+              "type": "media-import-rule",
               "text": "(min-width: 0px)",
-              "type": "media-import-rule",
               "sourceURL": "<filtered>"
             }
           ]
@@ -997,8 +997,8 @@
           "ruleId": "<filtered>",
           "groupings": [
             {
+              "type": "media-rule",
               "text": "(min-width: 1px)",
-              "type": "media-rule",
               "sourceURL": "<filtered>"
             }
           ]
@@ -1047,13 +1047,13 @@
           "ruleId": "<filtered>",
           "groupings": [
             {
+              "type": "supports-rule",
               "text": "(display: block)",
-              "type": "supports-rule",
               "sourceURL": "<filtered>"
             },
             {
+              "type": "media-rule",
               "text": "(min-width: 2px)",
-              "type": "media-rule",
               "sourceURL": "<filtered>"
             }
           ]
@@ -1102,8 +1102,8 @@
           "ruleId": "<filtered>",
           "groupings": [
             {
+              "type": "media-style-node",
               "text": "(min-width: 3px)",
-              "type": "media-style-node",
               "sourceURL": "<filtered>"
             }
           ]
@@ -1152,8 +1152,8 @@
           "ruleId": "<filtered>",
           "groupings": [
             {
+              "type": "media-link-node",
               "text": "(min-width: 4px)",
-              "type": "media-link-node",
               "sourceURL": "<filtered>"
             }
           ]

Added: trunk/LayoutTests/inspector/css/getMatchedStylesForNodeLayerGrouping-expected.txt (0 => 286558)


--- trunk/LayoutTests/inspector/css/getMatchedStylesForNodeLayerGrouping-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/css/getMatchedStylesForNodeLayerGrouping-expected.txt	2021-12-06 19:45:45 UTC (rev 286558)
@@ -0,0 +1,103 @@
+Tests for the CSS.getMatchedStyleForNode command and style rule groupings.
+
+
+== Running test suite: CSS.getMatchedStyleForNode.LayerGrouping
+-- Running test case: CSS.getMatchedStyleForNode.LayerGrouping.Normal
+PASS: Should have 3 authored rules.
+- Testing rule #0
+PASS: Selector text should be ".item".
+PASS: "color" property value should be "red".
+PASS: Source code for rule should be in file named "getMatchedStylesForNodeLayerGrouping.html".
+PASS: Rule should have no groupings.
+- Testing rule #1
+PASS: Selector text should be ".item".
+PASS: "color" property value should be "lawngreen".
+PASS: Source code for rule should be in file named "getMatchedStylesForNodeLayerGrouping.html".
+PASS: Rule should have 2 grouping(s).
+PASS: Grouping 0 should have a type of "layer-rule".
+PASS: Grouping 0 should have a text of "special".
+PASS: Grouping 1 should have a type of "supports-rule".
+PASS: Grouping 1 should have a text of "(color: red)".
+- Testing rule #2
+PASS: Selector text should be ".item".
+PASS: "color" property value should be "peachpuff".
+PASS: Source code for rule should be in file named "getMatchedStylesForNodeLayerGrouping.html".
+PASS: Rule should have 1 grouping(s).
+PASS: Grouping 0 should have a type of "layer-rule".
+PASS: Grouping 0 should have a text of "base".
+
+-- Running test case: CSS.getMatchedStyleForNode.LayerGrouping.Imported
+PASS: Should have 5 authored rules.
+- Testing rule #0
+PASS: Selector text should be ".item".
+PASS: "color" property value should be "red".
+PASS: Source code for rule should be in file named "getMatchedStylesForNodeLayerGrouping.html".
+PASS: Rule should have no groupings.
+- Testing rule #1
+PASS: Selector text should be ".item".
+PASS: "color" property value should be "lawngreen".
+PASS: Source code for rule should be in file named "getMatchedStylesForNodeLayerGrouping.html".
+PASS: Rule should have 2 grouping(s).
+PASS: Grouping 0 should have a type of "layer-rule".
+PASS: Grouping 0 should have a text of "special".
+PASS: Grouping 1 should have a type of "supports-rule".
+PASS: Grouping 1 should have a text of "(color: red)".
+- Testing rule #2
+PASS: Selector text should be ".item".
+PASS: "color" property value should be "peachpuff".
+PASS: Source code for rule should be in file named "getMatchedStylesForNodeLayerGrouping.html".
+PASS: Rule should have 1 grouping(s).
+PASS: Grouping 0 should have a type of "layer-rule".
+PASS: Grouping 0 should have a text of "base".
+- Testing rule #3
+PASS: Selector text should be ".imported".
+PASS: "color" property value should be "darkslategray".
+PASS: Source code for rule should be in file named "external-layers.css".
+PASS: Rule should have 3 grouping(s).
+PASS: Grouping 0 should have a type of "layer-rule".
+PASS: Grouping 0 should have a text of "special".
+PASS: Grouping 1 should have a type of "supports-rule".
+PASS: Grouping 1 should have a text of "(color: red)".
+PASS: Grouping 2 should have a type of "layer-import-rule".
+PASS: Grouping 2 should have a text of "imported".
+- Testing rule #4
+PASS: Selector text should be ".imported".
+PASS: "color" property value should be "mintcream".
+PASS: Source code for rule should be in file named "external-layers.css".
+PASS: Rule should have 2 grouping(s).
+PASS: Grouping 0 should have a type of "layer-rule".
+PASS: Grouping 0 should have a text of "base".
+PASS: Grouping 1 should have a type of "layer-import-rule".
+PASS: Grouping 1 should have a text of "imported".
+
+-- Running test case: CSS.getMatchedStyleForNode.LayerGrouping.Anonymous
+PASS: Should have 4 authored rules.
+- Testing rule #0
+PASS: Selector text should be ".item".
+PASS: "color" property value should be "red".
+PASS: Source code for rule should be in file named "getMatchedStylesForNodeLayerGrouping.html".
+PASS: Rule should have no groupings.
+- Testing rule #1
+PASS: Selector text should be ".anonymous".
+PASS: "color" property value should be "darkviolet".
+PASS: Source code for rule should be in file named "getMatchedStylesForNodeLayerGrouping.html".
+PASS: Rule should have 1 grouping(s).
+PASS: Grouping 0 should have a type of "layer-rule".
+PASS: Grouping 0 should not have any text.
+- Testing rule #2
+PASS: Selector text should be ".item".
+PASS: "color" property value should be "lawngreen".
+PASS: Source code for rule should be in file named "getMatchedStylesForNodeLayerGrouping.html".
+PASS: Rule should have 2 grouping(s).
+PASS: Grouping 0 should have a type of "layer-rule".
+PASS: Grouping 0 should have a text of "special".
+PASS: Grouping 1 should have a type of "supports-rule".
+PASS: Grouping 1 should have a text of "(color: red)".
+- Testing rule #3
+PASS: Selector text should be ".item".
+PASS: "color" property value should be "peachpuff".
+PASS: Source code for rule should be in file named "getMatchedStylesForNodeLayerGrouping.html".
+PASS: Rule should have 1 grouping(s).
+PASS: Grouping 0 should have a type of "layer-rule".
+PASS: Grouping 0 should have a text of "base".
+

Added: trunk/LayoutTests/inspector/css/getMatchedStylesForNodeLayerGrouping.html (0 => 286558)


--- trunk/LayoutTests/inspector/css/getMatchedStylesForNodeLayerGrouping.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/css/getMatchedStylesForNodeLayerGrouping.html	2021-12-06 19:45:45 UTC (rev 286558)
@@ -0,0 +1,217 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script>
+function test()
+{
+    let suite = InspectorTest.createAsyncSuite("CSS.getMatchedStyleForNode.LayerGrouping");
+
+    function expectRuleAtIndex(rules, index, {selectorText, colorPropertyValue, file, lineNumber, groupings})
+    {
+        InspectorTest.log(`- Testing rule #${index}`);
+
+        let rule = rules[index];
+        InspectorTest.expectEqual(rule.selectorText, selectorText, `Selector text should be "${selectorText}".`);
+        InspectorTest.expectEqual(rule.style.propertyForName("color").value, colorPropertyValue, `"color" property value should be "${colorPropertyValue}".`);
+        InspectorTest.expectEqual(rule.sourceCodeLocation?.sourceCode.urlComponents.lastPathComponent, file, `Source code for rule should be in file named "${file}".`);
+
+        if (!groupings) {
+            InspectorTest.expectEmpty(rule.groupings, "Rule should have no groupings.");
+            return;
+        }
+
+        InspectorTest.expectEqual(rule.groupings.length, groupings.length, `Rule should have ${groupings.length} grouping(s).`);
+
+        for (let i = 0; i < groupings.length; ++i) {
+            InspectorTest.expectEqual(rule.groupings[i].type, groupings[i].type, `Grouping ${i} should have a type of "${groupings[i].type}".`);
+
+            if (groupings[i].text)
+                InspectorTest.expectEqual(rule.groupings[i].text, groupings[i].text, `Grouping ${i} should have a text of "${groupings[i].text}".`);
+            else
+                InspectorTest.expectNull(rule.groupings[i].text, `Grouping ${i} should not have any text.`);
+        }
+    }
+
+    function addTestCase({name, description, selector, expectedAuthoredRuleCount, authoredRulesHandler})
+    {
+        suite.addTestCase({
+            name,
+            description,
+            async test() {
+                let documentNode = await WI.domManager.requestDocument();
+                let nodeId = await documentNode.querySelector(selector);
+                let domNode = WI.domManager.nodeForId(nodeId);
+                InspectorTest.assert(domNode, `Should find DOM Node for selector '${selector}'.`);
+
+                let domNodeStyles = WI.cssManager.stylesForNode(domNode);
+                InspectorTest.assert(domNodeStyles, `Should find CSS Styles for DOM Node.`);
+                await domNodeStyles.refreshIfNeeded();
+
+                let authoredRules = domNodeStyles.matchedRules.filter((rule) => rule.type === WI.CSSStyleSheet.Type.Author);
+                InspectorTest.expectEqual(authoredRules.length, expectedAuthoredRuleCount, `Should have ${expectedAuthoredRuleCount} authored rules.`);
+                authoredRulesHandler(authoredRules);
+            },
+        });
+    }
+
+    addTestCase({
+        name: "CSS.getMatchedStyleForNode.LayerGrouping.Normal",
+        description: "Layers should be presented in the expected order, with layers applied in the order they are declared.",
+        selector: "#normal",
+        expectedAuthoredRuleCount: 3,
+        authoredRulesHandler(rules) {
+            expectRuleAtIndex(rules, 0, {
+                selectorText: ".item",
+                colorPropertyValue: "red",
+                file: "getMatchedStylesForNodeLayerGrouping.html",
+            });
+            expectRuleAtIndex(rules, 1, {
+                selectorText: ".item",
+                colorPropertyValue: "lawngreen",
+                file: "getMatchedStylesForNodeLayerGrouping.html",
+                groupings: [
+                    {type: WI.CSSGrouping.Type.LayerRule, text: "special"},
+                    {type: WI.CSSGrouping.Type.SupportsRule, text: "(color: red)"},
+                ],
+            });
+            expectRuleAtIndex(rules, 2, {
+                selectorText: ".item",
+                colorPropertyValue: "peachpuff",
+                file: "getMatchedStylesForNodeLayerGrouping.html",
+                groupings: [
+                    {type: WI.CSSGrouping.Type.LayerRule, text: "base"},
+                ],
+            });
+        }
+    });
+
+    addTestCase({
+        name: "CSS.getMatchedStyleForNode.LayerGrouping.Imported",
+        description: "Stylesheets imported with @import with a layer parameter should have nested layer groupings.",
+        selector: "#imported",
+        expectedAuthoredRuleCount: 5,
+        authoredRulesHandler(rules) {
+            expectRuleAtIndex(rules, 0, {
+                selectorText: ".item",
+                colorPropertyValue: "red",
+                file: "getMatchedStylesForNodeLayerGrouping.html",
+            });
+            expectRuleAtIndex(rules, 1, {
+                selectorText: ".item",
+                colorPropertyValue: "lawngreen",
+                file: "getMatchedStylesForNodeLayerGrouping.html",
+                groupings: [
+                    {type: WI.CSSGrouping.Type.LayerRule, text: "special"},
+                    {type: WI.CSSGrouping.Type.SupportsRule, text: "(color: red)"},
+                ],
+            });
+            expectRuleAtIndex(rules, 2, {
+                selectorText: ".item",
+                colorPropertyValue: "peachpuff",
+                file: "getMatchedStylesForNodeLayerGrouping.html",
+                groupings: [
+                    {type: WI.CSSGrouping.Type.LayerRule, text: "base"},
+                ],
+            });
+            expectRuleAtIndex(rules, 3, {
+                selectorText: ".imported",
+                colorPropertyValue: "darkslategray",
+                file: "external-layers.css",
+                groupings: [
+                    {type: WI.CSSGrouping.Type.LayerRule, text: "special"},
+                    {type: WI.CSSGrouping.Type.SupportsRule, text: "(color: red)"},
+                    {type: WI.CSSGrouping.Type.LayerImportRule, text: "imported"},
+                ],
+            });
+            expectRuleAtIndex(rules, 4, {
+                selectorText: ".imported",
+                colorPropertyValue: "mintcream",
+                file: "external-layers.css",
+                groupings: [
+                    {type: WI.CSSGrouping.Type.LayerRule, text: "base"},
+                    {type: WI.CSSGrouping.Type.LayerImportRule, text: "imported"},
+                ],
+            });
+        }
+    });
+
+    addTestCase({
+        name: "CSS.getMatchedStyleForNode.LayerGrouping.Anonymous",
+        description: "Anonymous layers (layers without a name) should be separate and be applied in the order they are declared relative to other anonymous and named layers.",
+        selector: "#anonymous",
+        expectedAuthoredRuleCount: 4,
+        authoredRulesHandler(rules) {
+            expectRuleAtIndex(rules, 0, {
+                selectorText: ".item",
+                colorPropertyValue: "red",
+                file: "getMatchedStylesForNodeLayerGrouping.html",
+            });
+            expectRuleAtIndex(rules, 1, {
+                selectorText: ".anonymous",
+                colorPropertyValue: "darkviolet",
+                file: "getMatchedStylesForNodeLayerGrouping.html",
+                groupings: [
+                    {type: WI.CSSGrouping.Type.LayerRule},
+                ],
+            });
+            expectRuleAtIndex(rules, 2, {
+                selectorText: ".item",
+                colorPropertyValue: "lawngreen",
+                file: "getMatchedStylesForNodeLayerGrouping.html",
+                groupings: [
+                    {type: WI.CSSGrouping.Type.LayerRule, text: "special"},
+                    {type: WI.CSSGrouping.Type.SupportsRule, text: "(color: red)"},
+                ],
+            });
+            expectRuleAtIndex(rules, 3, {
+                selectorText: ".item",
+                colorPropertyValue: "peachpuff",
+                file: "getMatchedStylesForNodeLayerGrouping.html",
+                groupings: [
+                    {type: WI.CSSGrouping.Type.LayerRule, text: "base"},
+                ],
+            });
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+<style>
+    @layer imported, base, special;
+
+    @import url("./resources/external-layers.css") layer(imported);
+
+    @supports(color: red) {
+        @layer special {
+            .item {
+                color: lawngreen;
+            }
+        }
+    }
+
+    @layer base {
+        .item {
+            color: peachpuff;
+        }
+    }
+
+    @layer {
+        .anonymous {
+            color: darkviolet;
+        }
+    }
+
+    .item {
+        color: red;
+    }
+</style>
+</head>
+<body _onload_="runTest()">
+    <p>Tests for the CSS.getMatchedStyleForNode command and style rule groupings.</p>
+    <div id="normal" class="item"></div>
+    <div id="imported" class="item imported"></div>
+    <div id="anonymous" class="item anonymous"></div>
+</body>
+</html>

Added: trunk/LayoutTests/inspector/css/resources/external-layers.css (0 => 286558)


--- trunk/LayoutTests/inspector/css/resources/external-layers.css	                        (rev 0)
+++ trunk/LayoutTests/inspector/css/resources/external-layers.css	2021-12-06 19:45:45 UTC (rev 286558)
@@ -0,0 +1,15 @@
+@layer base, special;
+
+@supports(color: red) {
+    @layer special {
+        .imported {
+            color: darkslategray;
+        }
+    }
+}
+
+@layer base {
+    .imported {
+        color: mintcream;
+    }
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (286557 => 286558)


--- trunk/Source/_javascript_Core/ChangeLog	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-12-06 19:45:45 UTC (rev 286558)
@@ -1,3 +1,15 @@
+2021-12-06  Patrick Angle  <[email protected]>
+
+        Web Inspector: Support Cascade Layers in the Styles sidebar
+        https://bugs.webkit.org/show_bug.cgi?id=233208
+
+        Reviewed by Devin Rousso.
+
+        Add new values to `CSS.Grouping`'s `type` enum for cascade layers and make the `text` optional since an
+        anonymous layer will not have a name or other text.
+
+        * inspector/protocol/CSS.json:
+
 2021-12-03  Keith Miller  <[email protected]>
 
         Remove StructureIDBlob

Modified: trunk/Source/_javascript_Core/inspector/protocol/CSS.json (286557 => 286558)


--- trunk/Source/_javascript_Core/inspector/protocol/CSS.json	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/_javascript_Core/inspector/protocol/CSS.json	2021-12-06 19:45:45 UTC (rev 286558)
@@ -226,10 +226,10 @@
         {
             "id": "Grouping",
             "type": "object",
-            "description": "CSS @media (as well as other users of media queries, like @import, <style>, <link>, etc.) and @supports descriptor.",
+            "description": "CSS @media (as well as other users of media queries, like @import, <style>, <link>, etc.), @supports, and @layer descriptor.",
             "properties": [
-                { "name": "text", "type": "string", "description": "Media query text." },
-                { "name": "type", "type": "string", "enum": ["media-rule", "media-import-rule", "media-link-node", "media-style-node", "supports-rule"], "description": "Source of the media query: \"media-rule\" if specified by a @media rule, \"media-import-rule\" if specified by an @import rule, \"media-link-node\" if specified by a \"media\" attribute in a linked style sheet's LINK tag, \"media-style-node\" if specified by a \"media\" attribute in an inline style sheet's STYLE tag, \"supports-rule\" if specified by an @supports rule, ." },
+                { "name": "type", "type": "string", "enum": ["media-rule", "media-import-rule", "media-link-node", "media-style-node", "supports-rule", "layer-rule", "layer-import-rule"], "description": "Source of the media query: \"media-rule\" if specified by a @media rule, \"media-import-rule\" if specified by an @import rule, \"media-link-node\" if specified by a \"media\" attribute in a linked style sheet's LINK tag, \"media-style-node\" if specified by a \"media\" attribute in an inline style sheet's STYLE tag, \"supports-rule\" if specified by an @supports rule, \"layer-rule\" if specified by an @layer rule." },
+                { "name": "text", "type": "string", "optional": true, "description": "Query text if specified by a @media or @supports rule. Layer name (or not present for anonymous layers) for @layer rules." },
                 { "name": "sourceURL", "type": "string", "optional": true, "description": "URL of the document containing the CSS grouping." }
             ]
         },

Modified: trunk/Source/WebCore/ChangeLog (286557 => 286558)


--- trunk/Source/WebCore/ChangeLog	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebCore/ChangeLog	2021-12-06 19:45:45 UTC (rev 286558)
@@ -1,3 +1,35 @@
+2021-12-06  Patrick Angle  <[email protected]>
+
+        Web Inspector: Support Cascade Layers in the Styles sidebar
+        https://bugs.webkit.org/show_bug.cgi?id=233208
+
+        Reviewed by Devin Rousso.
+
+        Test: inspector/css/getMatchedStylesForNodeLayerGrouping.html
+
+        Add support for parsing and grouping CSS `@layer` rules in `InspectorStyleSheet` to the existing paths for
+        handling other groupings so that the frontend is made aware of rules wrapped inside a layer or multiple layers.
+
+        * Headers.cmake:
+        * WebCore.xcodeproj/project.pbxproj:
+        - CompiledSelector.h needs to be exported as a private header to include in WebKitLegacy's build, since it is
+        imported by StyleRule.h, which is now imported by CSSImportRule.h, which is imported in WebKitLegacy.
+
+        * css/CSSImportRule.cpp:
+        (WebCore::CSSImportRule::cascadeLayerName const):
+        * css/CSSImportRule.h:
+        * css/CSSLayerRule.cpp:
+        (WebCore::CSSLayerRule::cssText const):
+        (WebCore::CSSLayerRule::layerName const):
+        (WebCore::CSSLayerRule::stringFromCascadeLayerName):
+        * css/CSSLayerRule.h:
+        * inspector/InspectorStyleSheet.cpp:
+        (flattenSourceData):
+        (WebCore::asCSSRuleList):
+        (WebCore::buildArrayForGroupings):
+        * style/InspectorCSSOMWrappers.cpp:
+        (WebCore::Style::InspectorCSSOMWrappers::collect):
+
 2021-12-06  Wenson Hsieh  <[email protected]>
 
         Unreviewed, add some missing #includes in WebCore

Modified: trunk/Source/WebCore/Headers.cmake (286557 => 286558)


--- trunk/Source/WebCore/Headers.cmake	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebCore/Headers.cmake	2021-12-06 19:45:45 UTC (rev 286558)
@@ -525,6 +525,8 @@
     css/CSSRegisteredCustomProperty.h
     css/CSSRule.h
     css/CSSRuleList.h
+    css/CSSSelector.h
+    css/CSSSelectorList.h
     css/CSSStyleDeclaration.h
     css/CSSStyleRule.h
     css/CSSStyleSheet.h
@@ -551,6 +553,7 @@
     css/Rect.h
     css/StyleColor.h
     css/StyleProperties.h
+    css/StyleRule.h
     css/StyleRuleType.h
     css/StyleSheet.h
     css/StyleSheetContents.h
@@ -564,6 +567,8 @@
     css/parser/CSSParserToken.h
     css/parser/CSSParserTokenRange.h
 
+    cssjit/CompiledSelector.h
+
     display/DisplayTree.h
     display/DisplayTreeBuilder.h
     display/DisplayView.h

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (286557 => 286558)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-12-06 19:45:45 UTC (rev 286558)
@@ -892,6 +892,7 @@
 		2DFA488F1DB541D000362B99 /* BufferSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DFA488E1DB541C200362B99 /* BufferSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		2E0888D51148848A00AF4265 /* JSDOMFormData.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E0888D31148848A00AF4265 /* JSDOMFormData.h */; };
 		2E2D99CE10E2BBDA00496337 /* JSBlob.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E2D99CC10E2BBDA00496337 /* JSBlob.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		2E301BE82745947200C0564F /* CompiledSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = E4451077202C7E0100657D33 /* CompiledSelector.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		2E37DFDB12DBAFB800A6B233 /* DOMURL.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E37DFD812DBAFB800A6B233 /* DOMURL.h */; };
 		2E37E00612DBC5A400A6B233 /* JSDOMURL.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E37E00412DBC5A400A6B233 /* JSDOMURL.h */; };
 		2E4346460F546A8200B0F1BA /* Worker.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E4346340F546A8200B0F1BA /* Worker.h */; };
@@ -33527,6 +33528,7 @@
 				E1FE137518402A6700892F13 /* CommonCryptoUtilities.h in Headers */,
 				0F60F32B1DFBB10700416D6C /* CommonVM.h in Headers */,
 				7C93F34A1AA6BA5E00A98BAB /* CompiledContentExtension.h in Headers */,
+				2E301BE82745947200C0564F /* CompiledSelector.h in Headers */,
 				C2F4E78C1E45C3EF006D7105 /* ComplexTextController.h in Headers */,
 				E4BA50901BCFBD9500E34EF7 /* ComposedTreeAncestorIterator.h in Headers */,
 				E44FA1851BCA6B5A0091B6EF /* ComposedTreeIterator.h in Headers */,

Modified: trunk/Source/WebCore/css/CSSImportRule.cpp (286557 => 286558)


--- trunk/Source/WebCore/css/CSSImportRule.cpp	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebCore/css/CSSImportRule.cpp	2021-12-06 19:45:45 UTC (rev 286558)
@@ -56,6 +56,11 @@
     return *m_mediaCSSOMWrapper;
 }
 
+const std::optional<CascadeLayerName>& CSSImportRule::cascadeLayerName() const
+{
+    return m_importRule.get().cascadeLayerName();
+}
+
 String CSSImportRule::cssText() const
 {
     if (auto queries = m_importRule.get().mediaQueries()) {

Modified: trunk/Source/WebCore/css/CSSImportRule.h (286557 => 286558)


--- trunk/Source/WebCore/css/CSSImportRule.h	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebCore/css/CSSImportRule.h	2021-12-06 19:45:45 UTC (rev 286558)
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "CSSRule.h"
+#include "StyleRule.h"
 
 namespace WebCore {
 
@@ -37,6 +38,7 @@
     WEBCORE_EXPORT String href() const;
     WEBCORE_EXPORT MediaList& media() const;
     WEBCORE_EXPORT CSSStyleSheet* styleSheet() const;
+    WEBCORE_EXPORT const std::optional<CascadeLayerName>& cascadeLayerName() const;
 
 private:
     CSSImportRule(StyleRuleImport&, CSSStyleSheet*);

Modified: trunk/Source/WebCore/css/CSSLayerRule.cpp (286557 => 286558)


--- trunk/Source/WebCore/css/CSSLayerRule.cpp	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebCore/css/CSSLayerRule.cpp	2021-12-06 19:45:45 UTC (rev 286558)
@@ -52,18 +52,10 @@
 
     StringBuilder result;
 
-    auto appendLayerName = [&](auto& name) {
-        for (auto& segment : name) {
-            result.append(segment);
-            if (&segment != &name.last())
-                result.append('.');
-        }
-    };
-
     if (layer.isStatement()) {
         result.append("@layer ");
         for (auto& name : layer.nameList()) {
-            appendLayerName(name);
+            result.append(stringFromCascadeLayerName(name));
             if (&name != &layer.nameList().last())
                 result.append(", ");
         }
@@ -72,10 +64,8 @@
     }
 
     result.append("@layer ");
-    if (!layer.name().isEmpty()) {
-        appendLayerName(layer.name());
-        result.append(' ');
-    }
+    if (auto name = layerName())
+        result.append(*name, " ");
     result.append("{\n");
     appendCSSTextForItems(result);
     result.append('}');
@@ -82,5 +72,26 @@
     return result.toString();
 }
 
+std::optional<String> CSSLayerRule::layerName() const
+{
+    auto& layer = downcast<StyleRuleLayer>(groupRule());
+
+    if (!layer.isStatement() && !layer.name().isEmpty())
+        return stringFromCascadeLayerName(layer.name());
+    
+    return std::nullopt;
+}
+
+String CSSLayerRule::stringFromCascadeLayerName(const CascadeLayerName& name)
+{
+    StringBuilder result;
+    for (auto& segment : name) {
+        result.append(segment);
+        if (&segment != &name.last())
+            result.append('.');
+    }
+    return result.toString();
+}
+
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/css/CSSLayerRule.h (286557 => 286558)


--- trunk/Source/WebCore/css/CSSLayerRule.h	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebCore/css/CSSLayerRule.h	2021-12-06 19:45:45 UTC (rev 286558)
@@ -30,6 +30,7 @@
 #pragma once
 
 #include "CSSGroupingRule.h"
+#include "StyleRule.h"
 
 namespace WebCore {
 
@@ -40,7 +41,10 @@
     static Ref<CSSLayerRule> create(StyleRuleLayer&, CSSStyleSheet* parent);
 
     String cssText() const final;
+    std::optional<String> layerName() const;
 
+    static String stringFromCascadeLayerName(const CascadeLayerName&);
+
 private:
     CSSLayerRule(StyleRuleLayer&, CSSStyleSheet*);
     CSSRule::Type type() const final { return LAYER_RULE; }

Modified: trunk/Source/WebCore/inspector/InspectorStyleSheet.cpp (286557 => 286558)


--- trunk/Source/WebCore/inspector/InspectorStyleSheet.cpp	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebCore/inspector/InspectorStyleSheet.cpp	2021-12-06 19:45:45 UTC (rev 286558)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2010, Google Inc. All rights reserved.
+ * Copyright (C) 2021, Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,6 +28,7 @@
 
 #include "CSSImportRule.h"
 #include "CSSKeyframesRule.h"
+#include "CSSLayerRule.h"
 #include "CSSMediaRule.h"
 #include "CSSParser.h"
 #include "CSSParserObserver.h"
@@ -105,10 +107,8 @@
     for (auto& data : dataList) {
         if (data->type == WebCore::StyleRuleType::Style)
             target.append(data.copyRef());
-        else if (data->type == WebCore::StyleRuleType::Media)
+        else if (data->type == WebCore::StyleRuleType::Media || data->type == WebCore::StyleRuleType::Supports || data->type == WebCore::StyleRuleType::Layer)
             flattenSourceData(data->childRules, target);
-        else if (data->type == WebCore::StyleRuleType::Supports)
-            flattenSourceData(data->childRules, target);
     }
 }
 
@@ -426,6 +426,9 @@
     if (is<CSSSupportsRule>(*rule))
         return &downcast<CSSSupportsRule>(*rule).cssRules();
 
+    if (is<CSSLayerRule>(*rule))
+        return &downcast<CSSLayerRule>(*rule).cssRules();
+
     return nullptr;
 }
 
@@ -435,32 +438,50 @@
 
     auto* parentRule = &rule;
     while (parentRule) {
-        RefPtr<Protocol::CSS::Grouping> ruleGroupingPayload;
+        Vector<Ref<Protocol::CSS::Grouping>> ruleGroupingPayloads;
 
         if (is<CSSMediaRule>(parentRule)) {
             auto* media = downcast<CSSMediaRule>(parentRule)->media();
             if (media && media->length() && media->mediaText() != "all") {
-                ruleGroupingPayload = Protocol::CSS::Grouping::create()
-                    .setText(media->mediaText())
+                auto mediaRulePayload = Protocol::CSS::Grouping::create()
                     .setType(Protocol::CSS::Grouping::Type::MediaRule)
                     .release();
+                mediaRulePayload->setText(media->mediaText());
+                ruleGroupingPayloads.append(WTFMove(mediaRulePayload));
             }
         } else if (is<CSSImportRule>(parentRule)) {
+            if (auto& layerName = downcast<CSSImportRule>(parentRule)->cascadeLayerName()) {
+                auto layerRulePayload = Protocol::CSS::Grouping::create()
+                    .setType(Protocol::CSS::Grouping::Type::LayerImportRule)
+                    .release();
+                layerRulePayload->setText(CSSLayerRule::stringFromCascadeLayerName(*layerName));
+                ruleGroupingPayloads.append(WTFMove(layerRulePayload));
+            }
+
             auto& media = downcast<CSSImportRule>(parentRule)->media();
             if (media.length() && media.mediaText() != "all") {
-                ruleGroupingPayload = Protocol::CSS::Grouping::create()
-                    .setText(media.mediaText())
+                auto mediaRulePayload = Protocol::CSS::Grouping::create()
                     .setType(Protocol::CSS::Grouping::Type::MediaImportRule)
                     .release();
+                mediaRulePayload->setText(media.mediaText());
+                ruleGroupingPayloads.append(WTFMove(mediaRulePayload));
             }
         } else if (is<CSSSupportsRule>(parentRule)) {
-            ruleGroupingPayload = Protocol::CSS::Grouping::create()
-                .setText(downcast<CSSSupportsRule>(parentRule)->conditionText())
+            auto supportsRulePayload = Protocol::CSS::Grouping::create()
                 .setType(Protocol::CSS::Grouping::Type::SupportsRule)
                 .release();
+            supportsRulePayload->setText(downcast<CSSSupportsRule>(parentRule)->conditionText());
+            ruleGroupingPayloads.append(WTFMove(supportsRulePayload));
+        } else if (is<CSSLayerRule>(parentRule)) {
+            auto layerRulePayload = Protocol::CSS::Grouping::create()
+                .setType(Protocol::CSS::Grouping::Type::LayerRule)
+                .release();
+            if (auto layerName = downcast<CSSLayerRule>(parentRule)->layerName())
+                layerRulePayload->setText(*layerName);
+            ruleGroupingPayloads.append(WTFMove(layerRulePayload));
         }
 
-        if (ruleGroupingPayload) {
+        for (auto&& ruleGroupingPayload : WTFMove(ruleGroupingPayloads)) {
             if (auto* parentStyleSheet = parentRule->parentStyleSheet()) {
                 String sourceURL = parentStyleSheet->contents().baseURL().string();
                 if (sourceURL.isEmpty()) {
@@ -471,7 +492,7 @@
                     ruleGroupingPayload->setSourceURL(sourceURL);
             }
 
-            groupingsPayload->addItem(ruleGroupingPayload.releaseNonNull());
+            groupingsPayload->addItem(WTFMove(ruleGroupingPayload));
         }
 
         if (parentRule->parentRule()) {
@@ -484,9 +505,9 @@
             auto* media = styleSheet->media();
             if (media && media->length() && media->mediaText() != "all") {
                 auto sheetGroupingPayload = Protocol::CSS::Grouping::create()
-                    .setText(media->mediaText())
                     .setType(is<HTMLStyleElement>(styleSheet->ownerNode()) ? Protocol::CSS::Grouping::Type::MediaStyleNode: Protocol::CSS::Grouping::Type::MediaLinkNode)
                     .release();
+                sheetGroupingPayload->setText(media->mediaText());
 
                 String sourceURL;
                 if (auto* ownerDocument = styleSheet->ownerDocument())

Modified: trunk/Source/WebCore/style/InspectorCSSOMWrappers.cpp (286557 => 286558)


--- trunk/Source/WebCore/style/InspectorCSSOMWrappers.cpp	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebCore/style/InspectorCSSOMWrappers.cpp	2021-12-06 19:45:45 UTC (rev 286558)
@@ -30,6 +30,7 @@
 #include "InspectorCSSOMWrappers.h"
 
 #include "CSSImportRule.h"
+#include "CSSLayerRule.h"
 #include "CSSMediaRule.h"
 #include "CSSRule.h"
 #include "CSSStyleRule.h"
@@ -61,6 +62,9 @@
         case CSSRule::IMPORT_RULE:
             collect(downcast<CSSImportRule>(*cssRule).styleSheet());
             break;
+        case CSSRule::LAYER_RULE:
+            collect(downcast<CSSLayerRule>(cssRule));
+            break;
         case CSSRule::MEDIA_RULE:
             collect(downcast<CSSMediaRule>(cssRule));
             break;

Modified: trunk/Source/WebInspectorUI/ChangeLog (286557 => 286558)


--- trunk/Source/WebInspectorUI/ChangeLog	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebInspectorUI/ChangeLog	2021-12-06 19:45:45 UTC (rev 286558)
@@ -1,3 +1,26 @@
+2021-12-06  Patrick Angle  <[email protected]>
+
+        Web Inspector: Support Cascade Layers in the Styles sidebar
+        https://bugs.webkit.org/show_bug.cgi?id=233208
+
+        Reviewed by Devin Rousso.
+
+        * UserInterface/Models/CSSGrouping.js:
+        (WI.CSSGrouping):
+        (WI.CSSGrouping.prototype.get isLayer):
+        (WI.CSSGrouping.prototype.get prefix):
+        - Update `CSSGrouping` to support `@layer` rules, and make `text` optional for a grouping, since anonymous layers
+        will not have a name.
+
+        * UserInterface/Models/CSSStyleDeclaration.js:
+        (WI.CSSStyleDeclaration.prototype.generateFormattedText):
+        - Ensure that spacing remains correct and "null" isn't shown for groupings without text.
+
+        * UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js:
+        (WI.SpreadsheetCSSStyleDeclarationSection.prototype.initialLayout):
+        - When merging layer groups, ensure that a "." is used as a separator, and that each group has a name (to
+        prevent having a hanging period or the "null" text appearing).
+
 2021-12-02  Devin Rousso  <[email protected]>
 
         [css-values-4] Support `*vi` (inline) and `*vb` (block) viewport units

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CSSGrouping.js (286557 => 286558)


--- trunk/Source/WebInspectorUI/UserInterface/Models/CSSGrouping.js	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CSSGrouping.js	2021-12-06 19:45:45 UTC (rev 286558)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2019, 2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,11 +28,11 @@
     constructor(type, text, sourceCodeLocation)
     {
         console.assert(Object.values(CSSGrouping.Type).includes(type));
-        console.assert(typeof text === "string" && text.length);
+        console.assert(!text || (typeof text === "string" && text.length));
         console.assert(!sourceCodeLocation || sourceCodeLocation instanceof WI.SourceCodeLocation);
 
         this._type = type;
-        this._text = text;
+        this._text = text || null;
         this._sourceCodeLocation = sourceCodeLocation || null;
     }
 
@@ -55,11 +55,20 @@
         return this._type === WI.CSSGrouping.Type.SupportsRule;
     }
 
+    get isLayer()
+    {
+        return this._type === WI.CSSGrouping.Type.LayerRule
+            || this._type === WI.CSSGrouping.Type.LayerImportRule;
+    }
+
     get prefix()
     {
         if (this.isSupports)
             return "@supports";
 
+        if (this.isLayer)
+            return "@layer";
+
         console.assert(this.isMedia);
         return "@media";
     }
@@ -71,4 +80,6 @@
     MediaLinkNode: "media-link-node",
     MediaStyleNode: "media-style-node",
     SupportsRule: "supports-rule",
+    LayerRule: "layer-rule",
+    LayerImportRule: "layer-import-rule",
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js (286557 => 286558)


--- trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js	2021-12-06 19:45:45 UTC (rev 286558)
@@ -470,7 +470,7 @@
     {
         let indentString = WI.indentString();
         let styleText = "";
-        let groupings = this.groupings.filter((grouping) => grouping.text !== "all");
+        let groupings = this.groupings.filter((grouping) => !grouping.isMedia || grouping.text !== "all");
         let groupingsCount = groupings.length;
 
         if (options.includeGroupingsAndSelectors) {
@@ -478,7 +478,10 @@
                 if (options.multiline)
                     styleText += indentString.repeat(groupingsCount - i - 1);
 
-                styleText += groupings[i].prefix + " " + groupings[i].text + " {";
+                styleText += groupings[i].prefix;
+                if (groupings[i].text)
+                    styleText += " " + groupings[i].text;
+                styleText += " {";
 
                 if (options.multiline)
                     styleText += "\n";

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js (286557 => 286558)


--- trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js	2021-12-06 19:45:31 UTC (rev 286557)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js	2021-12-06 19:45:45 UTC (rev 286558)
@@ -102,24 +102,26 @@
         console.assert(iconClassName);
         this._element.classList.add("has-icon", iconClassName);
 
-        let groupings = this._style.groupings.filter((grouping) => grouping.text !== "all");
+        let groupings = this._style.groupings.filter((grouping) => !grouping.isMedia || grouping.text !== "all").reverse();
         if (groupings.length) {
             let groupingsElement = this.element.appendChild(document.createElement("div"));
             groupingsElement.classList.add("header-groupings");
 
             let currentGroupingType = null;
+            let currentGroupingHadText = false;
             let groupingTypeElement = null;
             this._groupingElements = groupings.map((grouping) => {
-                if (grouping.type !== currentGroupingType) {
+                if (grouping.type !== currentGroupingType || !grouping.text || !currentGroupingHadText) {
                     groupingTypeElement = groupingsElement.appendChild(document.createElement("div"));
                     groupingTypeElement.classList.add("grouping");
                     groupingTypeElement.textContent = grouping.prefix + " ";
                     currentGroupingType = grouping.type;
                 } else
-                    groupingTypeElement.append(", ");
+                    groupingTypeElement.append(grouping.isLayer && grouping.text ? "." : ", ");
 
+                currentGroupingHadText = !!grouping.text;
                 let span = groupingTypeElement.appendChild(document.createElement("span"));
-                span.textContent = grouping.text;
+                span.textContent = grouping.text ?? "";
                 return span;
             });
         }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to