Web Inspector: Styles: `::-webkit-scrollbar*` rules aren't shown
authordrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Mar 2019 09:33:24 +0000 (09:33 +0000)
committerdrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Mar 2019 09:33:24 +0000 (09:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195123
<rdar://problem/48450148>

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

* inspector/protocol/CSS.json:
Add `CSS.PseudoId` enum, rather than send a number, so that we have more knowledge about
which pseudo type the rule corresponds to (e.g. a string is more descriptive than a number).

Source/WebCore:

Test: inspector/css/getMatchedStylesForNode.html

* inspector/agents/InspectorCSSAgent.cpp:
(WebCore::protocolValueForPseudoId): Added.
(WebCore::InspectorCSSAgent::getMatchedStylesForNode):

Source/WebInspectorUI:

* UserInterface/Controllers/CSSManager.js:
(WI.CSSManager.displayNameForPseudoId): Added.

* UserInterface/Models/DOMNodeStyles.js:
(WI.DOMNodeStyles.static uniqueOrderedStyles): Added.
(WI.DOMNodeStyles.prototype.get uniqueOrderedStyles):

* UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.js:
(WI.SpreadsheetRulesStyleDetailsPanel.prototype.layout):
(WI.SpreadsheetRulesStyleDetailsPanel.prototype._handleSectionFilterApplied):
Rather than iterate over the `WI.DOMNode`'s list of pseudo-elements (which is only ::before
and ::after), we iterate over the `WI.DOMNodeStyle`'s list of pseudo-element rules. This is
an object where the key is a `CSS.PseudoId` and the value is an object containing all the
matched rules and ordered styles for that pseudo-type. We can preserve the current
functionality by using the ::before/::after `WI.DOMNode` when we encounter one of those
pseudo-ids.

An additional benefit of this change is that `::before`/`::after` styles will still appear
in the Rules panel even if they don't have a `content` property set (e.g. when the
`::before`/`::after` pseudo-element doesn't exist). This is because the styles are no longer
fetched from those pseudo-element nodes directly, but rather as a matched style for the
parent node. As such, editing a `content` property to become invalid/disablde in a
`::before`/`::after` rule won't make the entire rule disappeaer.

LayoutTests:

* inspector/css/getMatchedStylesForNode.html: Added.
* inspector/css/getMatchedStylesForNode-expected.txt: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242939 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/css/getMatchedStylesForNode-expected.txt [new file with mode: 0644]
LayoutTests/inspector/css/getMatchedStylesForNode.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/protocol/CSS.json
Source/WebCore/ChangeLog
Source/WebCore/inspector/agents/InspectorCSSAgent.cpp
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js
Source/WebInspectorUI/UserInterface/Models/DOMNodeStyles.js
Source/WebInspectorUI/UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.js

index 2e5867c..96a6884 100644 (file)
@@ -1,3 +1,14 @@
+2019-03-14  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Styles: `::-webkit-scrollbar*` rules aren't shown
+        https://bugs.webkit.org/show_bug.cgi?id=195123
+        <rdar://problem/48450148>
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/css/getMatchedStylesForNode.html: Added.
+        * inspector/css/getMatchedStylesForNode-expected.txt: Added.
+
 2019-03-13  Justin Fan  <justin_fan@apple.com>
 
         [Web GPU] Updates to GPUCommandBuffer for new GPUCommandQueue concept
diff --git a/LayoutTests/inspector/css/getMatchedStylesForNode-expected.txt b/LayoutTests/inspector/css/getMatchedStylesForNode-expected.txt
new file mode 100644 (file)
index 0000000..f8fd63a
--- /dev/null
@@ -0,0 +1,818 @@
+Testing CSS.getMatchedStylesForNode.
+
+Requesting document...
+Querying for "div#x"...
+Getting matched styles for "div#x"...
+
+Matched:
+[
+  {
+    "rule": {
+      "selectorList": {
+        "selectors": [
+          {
+            "text": "div",
+            "specificity": [
+              0,
+              0,
+              1
+            ]
+          }
+        ],
+        "text": "div",
+        "range": "<filtered>"
+      },
+      "sourceLine": "<filtered>",
+      "origin": "regular",
+      "style": {
+        "cssProperties": [
+          {
+            "name": "z-index",
+            "value": "300",
+            "text": "z-index: 300;",
+            "range": "<filtered>",
+            "implicit": false,
+            "status": "active"
+          }
+        ],
+        "shorthandEntries": [],
+        "styleId": "<filtered>",
+        "width": "",
+        "height": "",
+        "range": "<filtered>",
+        "cssText": " z-index: 300; "
+      },
+      "sourceURL": "<filtered>",
+      "ruleId": "<filtered>"
+    },
+    "matchingSelectors": [
+      0
+    ]
+  },
+  {
+    "rule": {
+      "selectorList": {
+        "selectors": [
+          {
+            "text": "#x",
+            "specificity": [
+              1,
+              0,
+              0
+            ]
+          }
+        ],
+        "text": "#x",
+        "range": "<filtered>"
+      },
+      "sourceLine": "<filtered>",
+      "origin": "regular",
+      "style": {
+        "cssProperties": [
+          {
+            "name": "z-index",
+            "value": "200",
+            "text": "z-index: 200;",
+            "range": "<filtered>",
+            "implicit": false,
+            "status": "active"
+          }
+        ],
+        "shorthandEntries": [],
+        "styleId": "<filtered>",
+        "width": "",
+        "height": "",
+        "range": "<filtered>",
+        "cssText": " z-index: 200; "
+      },
+      "sourceURL": "<filtered>",
+      "ruleId": "<filtered>"
+    },
+    "matchingSelectors": [
+      0
+    ]
+  },
+  {
+    "rule": {
+      "selectorList": {
+        "selectors": [
+          {
+            "text": "div#x",
+            "specificity": [
+              1,
+              0,
+              1
+            ]
+          }
+        ],
+        "text": "div#x",
+        "range": "<filtered>"
+      },
+      "sourceLine": "<filtered>",
+      "origin": "regular",
+      "style": {
+        "cssProperties": [
+          {
+            "name": "z-index",
+            "value": "100",
+            "text": "z-index: 100;",
+            "range": "<filtered>",
+            "implicit": false,
+            "status": "active"
+          }
+        ],
+        "shorthandEntries": [],
+        "styleId": "<filtered>",
+        "width": "",
+        "height": "",
+        "range": "<filtered>",
+        "cssText": " z-index: 100; "
+      },
+      "sourceURL": "<filtered>",
+      "ruleId": "<filtered>"
+    },
+    "matchingSelectors": [
+      0
+    ]
+  }
+]
+
+Pseudo:
+[
+  {
+    "pseudoId": "first-line",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::first-line",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::first-line",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "1",
+                "text": "z-index: 1;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 1; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "first-letter",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::first-letter",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::first-letter",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "2",
+                "text": "z-index: 2;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 2; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "marker",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::marker",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::marker",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "3",
+                "text": "z-index: 3;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 3; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "before",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::before",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::before",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "4",
+                "text": "z-index: 4;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 4; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "after",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::after",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::after",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "5",
+                "text": "z-index: 5;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 5; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "selection",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::selection",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::selection",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "6",
+                "text": "z-index: 6;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 6; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "scrollbar",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::-webkit-scrollbar",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::-webkit-scrollbar",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "7",
+                "text": "z-index: 7;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 7; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "scrollbar-thumb",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::-webkit-scrollbar-thumb",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::-webkit-scrollbar-thumb",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "8",
+                "text": "z-index: 8;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 8; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "scrollbar-button",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::-webkit-scrollbar-button",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::-webkit-scrollbar-button",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "9",
+                "text": "z-index: 9;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 9; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "scrollbar-track",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::-webkit-scrollbar-track",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::-webkit-scrollbar-track",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "10",
+                "text": "z-index: 10;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 10; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "scrollbar-track-piece",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::-webkit-scrollbar-track-piece",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::-webkit-scrollbar-track-piece",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "11",
+                "text": "z-index: 11;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 11; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "scrollbar-corner",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::-webkit-scrollbar-corner",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::-webkit-scrollbar-corner",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "12",
+                "text": "z-index: 12;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 12; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  },
+  {
+    "pseudoId": "resizer",
+    "matches": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "div::-webkit-resizer",
+                "specificity": [
+                  0,
+                  0,
+                  2
+                ]
+              }
+            ],
+            "text": "div::-webkit-resizer",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "13",
+                "text": "z-index: 13;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 13; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  }
+]
+
+Inherited:
+[
+  {
+    "matchedCSSRules": [
+      {
+        "rule": {
+          "selectorList": {
+            "selectors": [
+              {
+                "text": "body",
+                "specificity": [
+                  0,
+                  0,
+                  1
+                ]
+              }
+            ],
+            "text": "body",
+            "range": "<filtered>"
+          },
+          "sourceLine": "<filtered>",
+          "origin": "regular",
+          "style": {
+            "cssProperties": [
+              {
+                "name": "z-index",
+                "value": "0",
+                "text": "z-index: 0;",
+                "range": "<filtered>",
+                "implicit": false,
+                "status": "active"
+              }
+            ],
+            "shorthandEntries": [],
+            "styleId": "<filtered>",
+            "width": "",
+            "height": "",
+            "range": "<filtered>",
+            "cssText": " z-index: 0; "
+          },
+          "sourceURL": "<filtered>",
+          "ruleId": "<filtered>"
+        },
+        "matchingSelectors": [
+          0
+        ]
+      }
+    ]
+  }
+]
+
diff --git a/LayoutTests/inspector/css/getMatchedStylesForNode.html b/LayoutTests/inspector/css/getMatchedStylesForNode.html
new file mode 100644 (file)
index 0000000..61c80b1
--- /dev/null
@@ -0,0 +1,103 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/protocol-test.js"></script>
+<script>
+function test()
+{
+    Promise.resolve()
+    .then(() => {
+        ProtocolTest.log("Requesting document...");
+        return InspectorProtocol.awaitCommand({
+            method: "DOM.getDocument",
+            params: {},
+        });
+    })
+    .then(({root}) => {
+        ProtocolTest.log("Querying for \"div#x\"...");
+        return InspectorProtocol.awaitCommand({
+            method: "DOM.querySelector",
+            params: {
+                nodeId: root.nodeId,
+                selector: "div#x",
+            },
+        });
+    })
+    .then(({nodeId}) => {
+        ProtocolTest.log("Getting matched styles for \"div#x\"...");
+        return InspectorProtocol.awaitCommand({
+            method: "CSS.getMatchedStylesForNode",
+            params: {
+                nodeId,
+                includePseudo: true,
+                includeInherited: true,
+            },
+        });
+    })
+    .then(({matchedCSSRules, pseudoElements, inherited}) => {
+        function filterRuleMatches(ruleMatches) {
+            return ruleMatches.filter((ruleMatch) => ruleMatch.rule.origin !== "user-agent");
+        }
+
+        function replacer(key, value) {
+            if (key === "ruleId" || key === "styleId" || key === "range" || key === "sourceLine" || key === "sourceURL")
+                return "<filtered>";
+            return value;
+        }
+
+        ProtocolTest.log("");
+        ProtocolTest.log("Matched:");
+        matchedCSSRules = filterRuleMatches(matchedCSSRules);
+        ProtocolTest.json(matchedCSSRules, replacer);
+
+        ProtocolTest.log("");
+        ProtocolTest.log("Pseudo:");
+        pseudoElements = pseudoElements.filter((pseudoIdMatch) => {
+            pseudoIdMatch.matches = filterRuleMatches(pseudoIdMatch.matches);
+            return pseudoIdMatch.matches.length;
+        });
+        ProtocolTest.json(pseudoElements, replacer);
+
+        ProtocolTest.log("");
+        ProtocolTest.log("Inherited:");
+        inherited = inherited.filter((inheritedStyleEntry) => {
+            inheritedStyleEntry.matchedCSSRules = filterRuleMatches(inheritedStyleEntry.matchedCSSRules);
+            return inheritedStyleEntry.matchedCSSRules.length;
+        });
+        ProtocolTest.json(inherited, replacer);
+    })
+    .catch((error) => {
+        ProtocolTest.log(error);
+    })
+    .finally(() => {
+        ProtocolTest.completeTest();
+    });
+}
+</script>
+</head>
+<body onLoad="runTest()">
+    <p>Testing CSS.getMatchedStylesForNode.</p>
+
+    <style>
+    body { z-index: 0; }
+
+    div#x { z-index: 100; }
+    #x { z-index: 200; }
+    div { z-index: 300; }
+
+    div::first-line { z-index: 1; }
+    div::first-letter { z-index: 2; }
+    div::marker { z-index: 3; }
+    div::before { z-index: 4; }
+    div::after { z-index: 5; }
+    div::selection { z-index: 6; }
+    div::-webkit-scrollbar { z-index: 7; }
+    div::-webkit-scrollbar-thumb { z-index: 8; }
+    div::-webkit-scrollbar-button { z-index: 9; }
+    div::-webkit-scrollbar-track { z-index: 10; }
+    div::-webkit-scrollbar-track-piece { z-index: 11; }
+    div::-webkit-scrollbar-corner { z-index: 12; }
+    div::-webkit-resizer { z-index: 13; }
+    </style>
+    <div id="x"></div>
+</body>
+</html>
index d912251..a5e23d0 100644 (file)
@@ -1,3 +1,15 @@
+2019-03-14  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Styles: `::-webkit-scrollbar*` rules aren't shown
+        https://bugs.webkit.org/show_bug.cgi?id=195123
+        <rdar://problem/48450148>
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/protocol/CSS.json:
+        Add `CSS.PseudoId` enum, rather than send a number, so that we have more knowledge about
+        which pseudo type the rule corresponds to (e.g. a string is more descriptive than a number).
+
 2019-03-13  Caio Lima  <ticaiolima@gmail.com>
 
         [JSC] CodeBlock::visitChildren is reporting extra memory even when its JITCode is singleton
index 01ce3c8..e48f3bb 100644 (file)
             ]
         },
         {
+            "id": "PseudoId",
+            "type": "string",
+            "enum": [
+                "first-line",
+                "first-letter",
+                "marker",
+                "before",
+                "after",
+                "selection",
+                "scrollbar",
+                "scrollbar-thumb",
+                "scrollbar-button",
+                "scrollbar-track",
+                "scrollbar-track-piece",
+                "scrollbar-corner",
+                "resizer"
+            ],
+            "description": "Pseudo-style identifier (see <code>enum PseudoId</code> in <code>RenderStyleConstants.h</code>)."
+        },
+        {
             "id": "PseudoIdMatches",
             "type": "object",
             "description": "CSS rule collection for a single pseudo style.",
             "properties": [
-                { "name": "pseudoId", "type": "integer", "description": "Pseudo style identifier (see <code>enum PseudoId</code> in <code>RenderStyleConstants.h</code>)."},
+                { "name": "pseudoId", "$ref": "PseudoId" },
                 { "name": "matches", "type": "array", "items": { "$ref": "RuleMatch" }, "description": "Matches of CSS rules applicable to the pseudo style."}
             ]
         },
index 092b306..6148888 100644 (file)
@@ -1,3 +1,17 @@
+2019-03-14  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Styles: `::-webkit-scrollbar*` rules aren't shown
+        https://bugs.webkit.org/show_bug.cgi?id=195123
+        <rdar://problem/48450148>
+
+        Reviewed by Joseph Pecoraro.
+
+        Test: inspector/css/getMatchedStylesForNode.html
+
+        * inspector/agents/InspectorCSSAgent.cpp:
+        (WebCore::protocolValueForPseudoId): Added.
+        (WebCore::InspectorCSSAgent::getMatchedStylesForNode):
+
 2019-03-13  Benjamin Poulain  <benjamin@webkit.org>
 
         Fix the argument type of RenderView::resumePausedImageAnimationsIfNeeded()
index d5a2274..17a5426 100644 (file)
@@ -49,6 +49,7 @@
 #include "Node.h"
 #include "NodeList.h"
 #include "PseudoElement.h"
+#include "RenderStyleConstants.h"
 #include "SVGStyleElement.h"
 #include "SelectorChecker.h"
 #include "ShadowRoot.h"
@@ -59,6 +60,7 @@
 #include "StyleScope.h"
 #include "StyleSheetList.h"
 #include <JavaScriptCore/InspectorProtocolObjects.h>
+#include <wtf/Optional.h>
 #include <wtf/Ref.h>
 #include <wtf/Vector.h>
 #include <wtf/text/CString.h>
@@ -432,6 +434,42 @@ bool InspectorCSSAgent::forcePseudoState(const Element& element, CSSSelector::Ps
     }
 }
 
+static Optional<Inspector::Protocol::CSS::PseudoId> protocolValueForPseudoId(PseudoId pseudoId)
+{
+    switch (pseudoId) {
+    case PseudoId::FirstLine:
+        return Inspector::Protocol::CSS::PseudoId::FirstLine;
+    case PseudoId::FirstLetter:
+        return Inspector::Protocol::CSS::PseudoId::FirstLetter;
+    case PseudoId::Marker:
+        return Inspector::Protocol::CSS::PseudoId::Marker;
+    case PseudoId::Before:
+        return Inspector::Protocol::CSS::PseudoId::Before;
+    case PseudoId::After:
+        return Inspector::Protocol::CSS::PseudoId::After;
+    case PseudoId::Selection:
+        return Inspector::Protocol::CSS::PseudoId::Selection;
+    case PseudoId::Scrollbar:
+        return Inspector::Protocol::CSS::PseudoId::Scrollbar;
+    case PseudoId::ScrollbarThumb:
+        return Inspector::Protocol::CSS::PseudoId::ScrollbarThumb;
+    case PseudoId::ScrollbarButton:
+        return Inspector::Protocol::CSS::PseudoId::ScrollbarButton;
+    case PseudoId::ScrollbarTrack:
+        return Inspector::Protocol::CSS::PseudoId::ScrollbarTrack;
+    case PseudoId::ScrollbarTrackPiece:
+        return Inspector::Protocol::CSS::PseudoId::ScrollbarTrackPiece;
+    case PseudoId::ScrollbarCorner:
+        return Inspector::Protocol::CSS::PseudoId::ScrollbarCorner;
+    case PseudoId::Resizer:
+        return Inspector::Protocol::CSS::PseudoId::Resizer;
+
+    default:
+        ASSERT_NOT_REACHED();
+        return { };
+    }
+}
+
 void InspectorCSSAgent::getMatchedStylesForNode(ErrorString& errorString, int nodeId, const bool* includePseudo, const bool* includeInherited, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::RuleMatch>>& matchedCSSRules, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::PseudoIdMatches>>& pseudoIdMatches, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::InheritedStyleEntry>>& inheritedEntries)
 {
     Element* element = elementForId(errorString, nodeId);
@@ -458,13 +496,15 @@ void InspectorCSSAgent::getMatchedStylesForNode(ErrorString& errorString, int no
         if (!includePseudo || *includePseudo) {
             auto pseudoElements = JSON::ArrayOf<Inspector::Protocol::CSS::PseudoIdMatches>::create();
             for (PseudoId pseudoId = PseudoId::FirstPublicPseudoId; pseudoId < PseudoId::AfterLastInternalPseudoId; pseudoId = static_cast<PseudoId>(static_cast<unsigned>(pseudoId) + 1)) {
-                auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
-                if (!matchedRules.isEmpty()) {
-                    auto matches = Inspector::Protocol::CSS::PseudoIdMatches::create()
-                        .setPseudoId(static_cast<int>(pseudoId))
-                        .setMatches(buildArrayForMatchedRuleList(matchedRules, styleResolver, *element, pseudoId))
-                        .release();
-                    pseudoElements->addItem(WTFMove(matches));
+                if (auto protocolPseudoId = protocolValueForPseudoId(pseudoId)) {
+                    auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
+                    if (!matchedRules.isEmpty()) {
+                        auto matches = Inspector::Protocol::CSS::PseudoIdMatches::create()
+                            .setPseudoId(protocolPseudoId.value())
+                            .setMatches(buildArrayForMatchedRuleList(matchedRules, styleResolver, *element, pseudoId))
+                            .release();
+                        pseudoElements->addItem(WTFMove(matches));
+                    }
                 }
             }
 
index 6e9da2b..1a5faa5 100644 (file)
@@ -1,5 +1,37 @@
 2019-03-14  Devin Rousso  <drousso@apple.com>
 
+        Web Inspector: Styles: `::-webkit-scrollbar*` rules aren't shown
+        https://bugs.webkit.org/show_bug.cgi?id=195123
+        <rdar://problem/48450148>
+
+        Reviewed by Joseph Pecoraro.
+
+        * UserInterface/Controllers/CSSManager.js:
+        (WI.CSSManager.displayNameForPseudoId): Added.
+
+        * UserInterface/Models/DOMNodeStyles.js:
+        (WI.DOMNodeStyles.static uniqueOrderedStyles): Added.
+        (WI.DOMNodeStyles.prototype.get uniqueOrderedStyles):
+
+        * UserInterface/Views/SpreadsheetRulesStyleDetailsPanel.js:
+        (WI.SpreadsheetRulesStyleDetailsPanel.prototype.layout):
+        (WI.SpreadsheetRulesStyleDetailsPanel.prototype._handleSectionFilterApplied):
+        Rather than iterate over the `WI.DOMNode`'s list of pseudo-elements (which is only ::before
+        and ::after), we iterate over the `WI.DOMNodeStyle`'s list of pseudo-element rules. This is
+        an object where the key is a `CSS.PseudoId` and the value is an object containing all the
+        matched rules and ordered styles for that pseudo-type. We can preserve the current
+        functionality by using the ::before/::after `WI.DOMNode` when we encounter one of those
+        pseudo-ids.
+
+        An additional benefit of this change is that `::before`/`::after` styles will still appear
+        in the Rules panel even if they don't have a `content` property set (e.g. when the
+        `::before`/`::after` pseudo-element doesn't exist). This is because the styles are no longer
+        fetched from those pseudo-element nodes directly, but rather as a matched style for the
+        parent node. As such, editing a `content` property to become invalid/disablde in a
+        `::before`/`::after` rule won't make the entire rule disappeaer.
+
+2019-03-14  Devin Rousso  <drousso@apple.com>
+
         Web Inspector: we should show artificial context menus on mousedown instead of click
         https://bugs.webkit.org/show_bug.cgi?id=195494
 
index 6045496..da701a0 100644 (file)
@@ -770,7 +770,7 @@ localizedStrings["Processing Instruction"] = "Processing Instruction";
 localizedStrings["Program %d"] = "Program %d";
 localizedStrings["Properties"] = "Properties";
 localizedStrings["Protocol"] = "Protocol";
-localizedStrings["Pseudo Element"] = "Pseudo Element";
+localizedStrings["Pseudo-Element"] = "Pseudo-Element";
 localizedStrings["Query Parameters"] = "Query Parameters";
 localizedStrings["Query String"] = "Query String";
 localizedStrings["Query String Parameters"] = "Query String Parameters";
index c00cda2..b9323a4 100644 (file)
@@ -98,6 +98,78 @@ WI.CSSManager = class CSSManager extends WI.Object
         }
     }
 
+    static displayNameForPseudoId(pseudoId)
+    {
+        // Compatibility (iOS 12.2): CSS.PseudoId did not exist.
+        if (!InspectorBackend.domains.CSS.PseudoId) {
+            switch (pseudoId) {
+            case 1: // PseudoId.FirstLine
+                return WI.unlocalizedString("::first-line");
+            case 2: // PseudoId.FirstLetter
+                return WI.unlocalizedString("::first-letter");
+            case 3: // PseudoId.Marker
+                return WI.unlocalizedString("::marker");
+            case 4: // PseudoId.Before
+                return WI.unlocalizedString("::before");
+            case 5: // PseudoId.After
+                return WI.unlocalizedString("::after");
+            case 6: // PseudoId.Selection
+                return WI.unlocalizedString("::selection");
+            case 7: // PseudoId.Scrollbar
+                return WI.unlocalizedString("::scrollbar");
+            case 8: // PseudoId.ScrollbarThumb
+                return WI.unlocalizedString("::scrollbar-thumb");
+            case 9: // PseudoId.ScrollbarButton
+                return WI.unlocalizedString("::scrollbar-button");
+            case 10: // PseudoId.ScrollbarTrack
+                return WI.unlocalizedString("::scrollbar-track");
+            case 11: // PseudoId.ScrollbarTrackPiece
+                return WI.unlocalizedString("::scrollbar-track-piece");
+            case 12: // PseudoId.ScrollbarCorner
+                return WI.unlocalizedString("::scrollbar-corner");
+            case 13: // PseudoId.Resizer
+                return WI.unlocalizedString("::resizer");
+
+            default:
+                console.error("Unknown pseudo id", pseudoId);
+                return "";
+            }
+        }
+
+        switch (pseudoId) {
+        case InspectorBackend.domains.CSS.PseudoId.FirstLine:
+            return WI.unlocalizedString("::first-line");
+        case InspectorBackend.domains.CSS.PseudoId.FirstLetter:
+            return WI.unlocalizedString("::first-letter");
+        case InspectorBackend.domains.CSS.PseudoId.Marker:
+            return WI.unlocalizedString("::marker");
+        case InspectorBackend.domains.CSS.PseudoId.Before:
+            return WI.unlocalizedString("::before");
+        case InspectorBackend.domains.CSS.PseudoId.After:
+            return WI.unlocalizedString("::after");
+        case InspectorBackend.domains.CSS.PseudoId.Selection:
+            return WI.unlocalizedString("::selection");
+        case InspectorBackend.domains.CSS.PseudoId.Scrollbar:
+            return WI.unlocalizedString("::scrollbar");
+        case InspectorBackend.domains.CSS.PseudoId.ScrollbarThumb:
+            return WI.unlocalizedString("::scrollbar-thumb");
+        case InspectorBackend.domains.CSS.PseudoId.ScrollbarButton:
+            return WI.unlocalizedString("::scrollbar-button");
+        case InspectorBackend.domains.CSS.PseudoId.ScrollbarTrack:
+            return WI.unlocalizedString("::scrollbar-track");
+        case InspectorBackend.domains.CSS.PseudoId.ScrollbarTrackPiece:
+            return WI.unlocalizedString("::scrollbar-track-piece");
+        case InspectorBackend.domains.CSS.PseudoId.ScrollbarCorner:
+            return WI.unlocalizedString("::scrollbar-corner");
+        case InspectorBackend.domains.CSS.PseudoId.Resizer:
+            return WI.unlocalizedString("::resizer");
+
+        default:
+            console.error("Unknown pseudo id", pseudoId);
+            return "";
+        }
+    }
+
     // Public
 
     get preferredColorFormat()
index d7786c7..5135589 100644 (file)
@@ -37,7 +37,7 @@ WI.DOMNodeStyles = class DOMNodeStyles extends WI.Object
 
         this._matchedRules = [];
         this._inheritedRules = [];
-        this._pseudoElements = {};
+        this._pseudoElements = new Map;
         this._inlineStyle = null;
         this._attributesStyle = null;
         this._computedStyle = null;
@@ -49,6 +49,33 @@ WI.DOMNodeStyles = class DOMNodeStyles extends WI.Object
         this.refresh();
     }
 
+    // Static
+
+    static uniqueOrderedStyles(orderedStyles)
+    {
+        let uniqueOrderedStyles = [];
+
+        for (let style of orderedStyles) {
+            let rule = style.ownerRule;
+            if (!rule) {
+                uniqueOrderedStyles.push(style);
+                continue;
+            }
+
+            let found = false;
+            for (let existingStyle of uniqueOrderedStyles) {
+                if (rule.isEqualTo(existingStyle.ownerRule)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found)
+                uniqueOrderedStyles.push(style);
+        }
+
+        return uniqueOrderedStyles;
+    }
+
     // Public
 
     get node()
@@ -125,10 +152,10 @@ WI.DOMNodeStyles = class DOMNodeStyles extends WI.Object
 
             this._matchedRules = parseRuleMatchArrayPayload.call(this, matchedRulesPayload, this._node);
 
-            this._pseudoElements = {};
+            this._pseudoElements.clear();
             for (var pseudoElementRulePayload of pseudoElementRulesPayload) {
                 var pseudoElementRules = parseRuleMatchArrayPayload.call(this, pseudoElementRulePayload.matches, this._node);
-                this._pseudoElements[pseudoElementRulePayload.pseudoId] = {matchedRules: pseudoElementRules};
+                this._pseudoElements.set(pseudoElementRulePayload.pseudoId, {matchedRules: pseudoElementRules});
             }
 
             this._inheritedRules = [];
@@ -327,8 +354,8 @@ WI.DOMNodeStyles = class DOMNodeStyles extends WI.Object
 
         let rules = this._matchedRules.filter(ruleHasSelector);
 
-        for (let id in this._pseudoElements)
-            rules = rules.concat(this._pseudoElements[id].matchedRules.filter(ruleHasSelector));
+        for (let pseudoElementInfo of this._pseudoElements.values())
+            rules = rules.concat(pseudoElementInfo.matchedRules.filter(ruleHasSelector));
 
         return rules;
     }
@@ -370,27 +397,7 @@ WI.DOMNodeStyles = class DOMNodeStyles extends WI.Object
 
     get uniqueOrderedStyles()
     {
-        let uniqueStyles = [];
-
-        for (let style of this._orderedStyles) {
-            let rule = style.ownerRule;
-            if (!rule) {
-                uniqueStyles.push(style);
-                continue;
-            }
-
-            let found = false;
-            for (let existingStyle of uniqueStyles) {
-                if (rule.isEqualTo(existingStyle.ownerRule)) {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found)
-                uniqueStyles.push(style);
-        }
-
-        return uniqueStyles;
+        return WI.DOMNodeStyles.uniqueOrderedStyles(this._orderedStyles);
     }
 
     effectivePropertyForName(name)
@@ -846,8 +853,7 @@ WI.DOMNodeStyles = class DOMNodeStyles extends WI.Object
         this._markOverriddenProperties(cascadeOrderedStyleDeclarations, this._propertyNameToEffectivePropertyMap);
         this._associateRelatedProperties(cascadeOrderedStyleDeclarations, this._propertyNameToEffectivePropertyMap);
 
-        for (var pseudoIdentifier in this._pseudoElements) {
-            var pseudoElementInfo = this._pseudoElements[pseudoIdentifier];
+        for (let pseudoElementInfo of this._pseudoElements.values()) {
             pseudoElementInfo.orderedStyles = this._collectStylesInCascadeOrder(pseudoElementInfo.matchedRules, null, null);
             this._markOverriddenProperties(pseudoElementInfo.orderedStyles);
             this._associateRelatedProperties(pseudoElementInfo.orderedStyles);
index 0c759b9..8f52af7 100644 (file)
@@ -220,16 +220,22 @@ WI.SpreadsheetRulesStyleDetailsPanel = class SpreadsheetRulesStyleDetailsPanel e
         this._headerMap.clear();
         this._sections = [];
 
-        let createHeader = (text, node) => {
+        let createHeader = (text, nodeOrPseudoId) => {
             let header = this.element.appendChild(document.createElement("h2"));
             header.classList.add("section-header");
             header.append(text);
-            header.append(" ", WI.linkifyNodeReference(node, {
-                maxLength: 100,
-                excludeRevealElement: true,
-            }));
 
-            this._headerMap.set(node, header);
+            if (nodeOrPseudoId) {
+                if (nodeOrPseudoId instanceof WI.DOMNode) {
+                    header.append(" ", WI.linkifyNodeReference(nodeOrPseudoId, {
+                        maxLength: 100,
+                        excludeRevealElement: true,
+                    }));
+                } else
+                    header.append(" ", WI.CSSManager.displayNameForPseudoId(nodeOrPseudoId));
+
+                this._headerMap.set(nodeOrPseudoId, header);
+            }
         };
 
         let createSection = (style) => {
@@ -249,6 +255,8 @@ WI.SpreadsheetRulesStyleDetailsPanel = class SpreadsheetRulesStyleDetailsPanel e
             this._sections.push(section);
 
             previousStyle = style;
+
+            return section;
         };
 
         for (let style of this.nodeStyles.uniqueOrderedStyles) {
@@ -258,16 +266,35 @@ WI.SpreadsheetRulesStyleDetailsPanel = class SpreadsheetRulesStyleDetailsPanel e
             createSection(style);
         }
 
-        let pseudoElements = Array.from(this.nodeStyles.node.pseudoElements().values());
-        Promise.all(pseudoElements.map((pseudoElement) => WI.cssManager.stylesForNode(pseudoElement).refreshIfNeeded()))
-        .then((pseudoNodeStyles) => {
-            for (let pseudoNodeStyle of pseudoNodeStyles) {
-                createHeader(WI.UIString("Pseudo Element"), pseudoNodeStyle.node);
+        let beforePseudoId = null;
+        let afterPseudoId = null;
+        if (InspectorBackend.domains.CSS.PseudoId) {
+            beforePseudoId = InspectorBackend.domains.CSS.PseudoId.Before;
+            afterPseudoId = InspectorBackend.domains.CSS.PseudoId.After;
+        } else {
+            // Compatibility (iOS 12.2): CSS.PseudoId did not exist.
+            beforePseudoId = 4;
+            afterPseudoId = 5;
+        }
+
+        for (let [pseudoId, pseudoElementInfo] of this.nodeStyles.pseudoElements) {
+            let nodeOrPseudoId = null;
+            if (pseudoId === beforePseudoId)
+                nodeOrPseudoId = this.nodeStyles.node.beforePseudoElement();
+            else if (pseudoId === afterPseudoId)
+                nodeOrPseudoId = this.nodeStyles.node.afterPseudoElement();
+            else
+                nodeOrPseudoId = pseudoId;
 
-                for (let style of pseudoNodeStyle.uniqueOrderedStyles)
-                    createSection(style);
+            createHeader(WI.UIString("Pseudo-Element"), nodeOrPseudoId);
+
+            for (let style of WI.DOMNodeStyles.uniqueOrderedStyles(pseudoElementInfo.orderedStyles)) {
+                let section = createSection(style);
+
+                if (nodeOrPseudoId === pseudoId)
+                    section.__pseudoId = pseudoId;
             }
-        });
+        }
 
         this._newRuleSelector = null;
 
@@ -293,7 +320,7 @@ WI.SpreadsheetRulesStyleDetailsPanel = class SpreadsheetRulesStyleDetailsPanel e
 
         this.element.classList.remove("filter-non-matching");
 
-        let header = this._headerMap.get(event.target.style.node);
+        let header = this._headerMap.get(event.target.__pseudoId || event.target.style.node);
         if (header)
             header.classList.remove(WI.GeneralStyleDetailsSidebarPanel.NoFilterMatchInSectionClassName);
     }