Support for resolving highlight pseudo element style
https://bugs.webkit.org/show_bug.cgi?id=204937

Reviewed by Simon Fraser.

Source/WebCore:

Test: highlight/highlight-pseudo-element-style.html

* css/SelectorChecker.cpp:
(WebCore::SelectorChecker::checkOne const):

Returns always true when checked without pseudoId, so it gets added to the set of seen pseudo elements.
Match argument with the provided highlight name otherwise.

* css/SelectorChecker.h:
* css/parser/CSSSelectorParser.cpp:
(WebCore::CSSSelectorParser::consumePseudo):
* rendering/style/RenderStyle.h:
* style/ElementRuleCollector.cpp:
(WebCore::Style::ElementRuleCollector::ruleMatches):
* style/ElementRuleCollector.h:
(WebCore::Style::PseudoElementRequest::PseudoElementRequest):

Add the requested highlight name.

* style/StyleResolver.h:
* style/StyleScope.h:
* testing/Internals.cpp:
(WebCore::Internals::highlightPseudoElementColor):

Testing support.

* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:

* highlight/highlight-pseudo-element-style-expected.txt: Added.
* highlight/highlight-pseudo-element-style.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@253210 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index aec00ca..1892efe 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,13 @@
+2019-12-06  Antti Koivisto  <antti@apple.com>
+
+        Support for resolving highlight pseudo element style
+        https://bugs.webkit.org/show_bug.cgi?id=204937
+
+        Reviewed by Simon Fraser.
+
+        * highlight/highlight-pseudo-element-style-expected.txt: Added.
+        * highlight/highlight-pseudo-element-style.html: Added.
+
 2019-12-06  youenn fablet  <youenn@apple.com>
 
         Protect WebRTC network monitoring to wait forever in edge cases
diff --git a/LayoutTests/highlight/highlight-pseudo-element-style-expected.txt b/LayoutTests/highlight/highlight-pseudo-element-style-expected.txt
new file mode 100644
index 0000000..e0faac8
--- /dev/null
+++ b/LayoutTests/highlight/highlight-pseudo-element-style-expected.txt
@@ -0,0 +1,21 @@
+Tests computing the highlight pseudo element style.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS internals.highlightPseudoElementColor('green-yellow-range', testdiv) is "rgb(0, 128, 0)"
+PASS internals.highlightPseudoElementColor('green-yellow-range', testspan1) is "rgb(0, 128, 0)"
+PASS internals.highlightPseudoElementColor('green-yellow-range', testspan2) is "rgb(255, 255, 0)"
+PASS internals.highlightPseudoElementColor('green-yellow-range', testspan3) is "rgb(0, 128, 0)"
+PASS internals.highlightPseudoElementColor('blue-range', testdiv) is ""
+PASS internals.highlightPseudoElementColor('blue-range', testspan1) is ""
+PASS internals.highlightPseudoElementColor('blue-range', testspan2) is ""
+PASS internals.highlightPseudoElementColor('blue-range', testspan3) is "rgb(0, 0, 255)"
+PASS internals.highlightPseudoElementColor('non-existent-range', testdiv) is ""
+PASS internals.highlightPseudoElementColor('non-existent-range', testspan1) is ""
+PASS internals.highlightPseudoElementColor('non-existent-range', testspan2) is ""
+PASS internals.highlightPseudoElementColor('non-existent-range', testspan3) is ""
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/highlight/highlight-pseudo-element-style.html b/LayoutTests/highlight/highlight-pseudo-element-style.html
new file mode 100644
index 0000000..0e4f441
--- /dev/null
+++ b/LayoutTests/highlight/highlight-pseudo-element-style.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ experimental:HighlightAPIEnabled=true ] -->
+<html>
+<script src="../resources/js-test.js"></script>
+<style>
+#testDiv { color: red }
+::highlight(green-yellow-range) { color: green }
+#testspan1::highlight(green-yellow-range) { background-color: yellow; }
+#testspan2::highlight(green-yellow-range) { color: yellow; }
+#testspan3::highlight(blue-range) { color: blue }
+</style>
+<body>
+<div id=testdiv>
+    <span id=testspan1></span>
+    <span id=testspan2></span>
+    <span id=testspan3></span>
+</div>
+<script>
+
+description("Tests computing the highlight pseudo element style.");
+
+shouldBeEqualToString("internals.highlightPseudoElementColor('green-yellow-range', testdiv)", "rgb(0, 128, 0)");
+shouldBeEqualToString("internals.highlightPseudoElementColor('green-yellow-range', testspan1)", "rgb(0, 128, 0)");
+shouldBeEqualToString("internals.highlightPseudoElementColor('green-yellow-range', testspan2)", "rgb(255, 255, 0)");
+shouldBeEqualToString("internals.highlightPseudoElementColor('green-yellow-range', testspan3)", "rgb(0, 128, 0)");
+shouldBeEqualToString("internals.highlightPseudoElementColor('blue-range', testdiv)", "");
+shouldBeEqualToString("internals.highlightPseudoElementColor('blue-range', testspan1)", "");
+shouldBeEqualToString("internals.highlightPseudoElementColor('blue-range', testspan2)", "");
+shouldBeEqualToString("internals.highlightPseudoElementColor('blue-range', testspan3)", "rgb(0, 0, 255)");
+shouldBeEqualToString("internals.highlightPseudoElementColor('non-existent-range', testdiv)", "");
+shouldBeEqualToString("internals.highlightPseudoElementColor('non-existent-range', testspan1)", "");
+shouldBeEqualToString("internals.highlightPseudoElementColor('non-existent-range', testspan2)", "");
+shouldBeEqualToString("internals.highlightPseudoElementColor('non-existent-range', testspan3)", "");
+
+</script>
+</body>
+</html>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 5b553f8..11d21f1 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,5 +1,41 @@
 2019-12-06  Antti Koivisto  <antti@apple.com>
 
+        Support for resolving highlight pseudo element style
+        https://bugs.webkit.org/show_bug.cgi?id=204937
+
+        Reviewed by Simon Fraser.
+
+        Test: highlight/highlight-pseudo-element-style.html
+
+        * css/SelectorChecker.cpp:
+        (WebCore::SelectorChecker::checkOne const):
+
+        Returns always true when checked without pseudoId, so it gets added to the set of seen pseudo elements.
+        Match argument with the provided highlight name otherwise.
+
+        * css/SelectorChecker.h:
+        * css/parser/CSSSelectorParser.cpp:
+        (WebCore::CSSSelectorParser::consumePseudo):
+        * rendering/style/RenderStyle.h:
+        * style/ElementRuleCollector.cpp:
+        (WebCore::Style::ElementRuleCollector::ruleMatches):
+        * style/ElementRuleCollector.h:
+        (WebCore::Style::PseudoElementRequest::PseudoElementRequest):
+
+        Add the requested highlight name.
+
+        * style/StyleResolver.h:
+        * style/StyleScope.h:
+        * testing/Internals.cpp:
+        (WebCore::Internals::highlightPseudoElementColor):
+
+        Testing support.
+
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
+2019-12-06  Antti Koivisto  <antti@apple.com>
+
         [LFC][Integration] Fix DisplayRunPath offsets
         https://bugs.webkit.org/show_bug.cgi?id=204949
 
diff --git a/Source/WebCore/css/SelectorChecker.cpp b/Source/WebCore/css/SelectorChecker.cpp
index 5559fbd..18349e10 100644
--- a/Source/WebCore/css/SelectorChecker.cpp
+++ b/Source/WebCore/css/SelectorChecker.cpp
@@ -1191,6 +1191,15 @@
             }
             return true;
         }
+
+        case CSSSelector::PseudoElementHighlight:
+            // Always matches when not specifically requested so it gets added to the pseudoIdSet.
+            if (checkingContext.pseudoId == PseudoId::None)
+                return true;
+            if (checkingContext.pseudoId != PseudoId::Highlight)
+                return false;
+            return selector.argumentList()->first() == checkingContext.nameForHightlightPseudoElement;
+
         default:
             return true;
         }
diff --git a/Source/WebCore/css/SelectorChecker.h b/Source/WebCore/css/SelectorChecker.h
index ce31016..5376318 100644
--- a/Source/WebCore/css/SelectorChecker.h
+++ b/Source/WebCore/css/SelectorChecker.h
@@ -91,6 +91,7 @@
         const SelectorChecker::Mode resolvingMode;
         PseudoId pseudoId { PseudoId::None };
         Optional<StyleScrollbarState> scrollbarState;
+        AtomString nameForHightlightPseudoElement;
         const ContainerNode* scope { nullptr };
         bool isMatchingHostPseudoClass { false };
         const Element* shadowHostInPartRuleScope { nullptr };
diff --git a/Source/WebCore/css/parser/CSSSelectorParser.cpp b/Source/WebCore/css/parser/CSSSelectorParser.cpp
index 538ff10..62f20c6 100644
--- a/Source/WebCore/css/parser/CSSSelectorParser.cpp
+++ b/Source/WebCore/css/parser/CSSSelectorParser.cpp
@@ -630,11 +630,13 @@
             DisallowPseudoElementsScope scope(this);
 
             auto& ident = block.consumeIncludingWhitespace();
-            if (ident.type() != IdentToken)
+            if (ident.type() != IdentToken || !block.atEnd())
                 return nullptr;
 
             auto argumentList = makeUnique<Vector<AtomString>>();
             argumentList->append(ident.value().toAtomString());
+            selector->setArgumentList(WTFMove(argumentList));
+
             return selector;
         }
         case CSSSelector::PseudoElementPart: {
diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h
index c2ec48e..5dcb21c 100644
--- a/Source/WebCore/rendering/style/RenderStyle.h
+++ b/Source/WebCore/rendering/style/RenderStyle.h
@@ -134,7 +134,7 @@
 public:
     RenderStyle(RenderStyle&&);
     RenderStyle& operator=(RenderStyle&&);
-    ~RenderStyle();
+    WEBCORE_EXPORT ~RenderStyle();
 
     RenderStyle replace(RenderStyle&&) WARN_UNUSED_RETURN;
 
@@ -1747,7 +1747,7 @@
     const Color& borderTopColor() const { return m_surroundData->border.top().color(); }
     const Color& borderBottomColor() const { return m_surroundData->border.bottom().color(); }
     const Color& backgroundColor() const { return m_backgroundData->color; }
-    const Color& color() const;
+    WEBCORE_EXPORT const Color& color() const;
     const Color& columnRuleColor() const { return m_rareNonInheritedData->multiCol->rule.color(); }
     const Color& outlineColor() const { return m_backgroundData->outline.color(); }
     const Color& textEmphasisColor() const { return m_rareInheritedData->textEmphasisColor; }
diff --git a/Source/WebCore/style/ElementRuleCollector.cpp b/Source/WebCore/style/ElementRuleCollector.cpp
index 7b03c89..d7068d5 100644
--- a/Source/WebCore/style/ElementRuleCollector.cpp
+++ b/Source/WebCore/style/ElementRuleCollector.cpp
@@ -477,6 +477,7 @@
     SelectorChecker::CheckingContext context(m_mode);
     context.pseudoId = m_pseudoElementRequest.pseudoId;
     context.scrollbarState = m_pseudoElementRequest.scrollbarState;
+    context.nameForHightlightPseudoElement = m_pseudoElementRequest.highlightName;
     context.isMatchingHostPseudoClass = m_isMatchingHostPseudoClass;
     context.shadowHostInPartRuleScope = m_shadowHostInPartRuleScope.get();
 
diff --git a/Source/WebCore/style/ElementRuleCollector.h b/Source/WebCore/style/ElementRuleCollector.h
index 0b00a2e..188aa8e 100644
--- a/Source/WebCore/style/ElementRuleCollector.h
+++ b/Source/WebCore/style/ElementRuleCollector.h
@@ -46,8 +46,16 @@
     {
     }
 
+    PseudoElementRequest(PseudoId pseudoId, const AtomString& highlightName)
+        : pseudoId(pseudoId)
+        , highlightName(highlightName)
+    {
+        ASSERT(pseudoId == PseudoId::Highlight);
+    }
+
     PseudoId pseudoId;
     Optional<StyleScrollbarState> scrollbarState;
+    AtomString highlightName;
 };
 
 struct MatchedRule {
diff --git a/Source/WebCore/style/StyleResolver.h b/Source/WebCore/style/StyleResolver.h
index d1e5d41..e7e3f77 100644
--- a/Source/WebCore/style/StyleResolver.h
+++ b/Source/WebCore/style/StyleResolver.h
@@ -89,7 +89,7 @@
 
     void keyframeStylesForAnimation(const Element&, const RenderStyle*, KeyframeList&);
 
-    std::unique_ptr<RenderStyle> pseudoStyleForElement(const Element&, const PseudoElementRequest&, const RenderStyle& parentStyle, const RenderStyle* parentBoxStyle = nullptr, const SelectorFilter* = nullptr);
+    WEBCORE_EXPORT std::unique_ptr<RenderStyle> pseudoStyleForElement(const Element&, const PseudoElementRequest&, const RenderStyle& parentStyle, const RenderStyle* parentBoxStyle = nullptr, const SelectorFilter* = nullptr);
 
     std::unique_ptr<RenderStyle> styleForPage(int pageIndex);
     std::unique_ptr<RenderStyle> defaultStyleForElement(const Element*);
diff --git a/Source/WebCore/style/StyleScope.h b/Source/WebCore/style/StyleScope.h
index ed14b5b..02a8bb4 100644
--- a/Source/WebCore/style/StyleScope.h
+++ b/Source/WebCore/style/StyleScope.h
@@ -115,7 +115,7 @@
     Vector<Ref<ProcessingInstruction>> collectXSLTransforms();
 #endif
 
-    Resolver& resolver();
+    WEBCORE_EXPORT Resolver& resolver();
     Resolver* resolverIfExists();
     void clearResolver();
     void releaseMemory();
diff --git a/Source/WebCore/testing/Internals.cpp b/Source/WebCore/testing/Internals.cpp
index 73de036..0d0aa07 100644
--- a/Source/WebCore/testing/Internals.cpp
+++ b/Source/WebCore/testing/Internals.cpp
@@ -170,6 +170,7 @@
 #include "SpellChecker.h"
 #include "StaticNodeList.h"
 #include "StringCallback.h"
+#include "StyleResolver.h"
 #include "StyleRule.h"
 #include "StyleScope.h"
 #include "StyleSheetContents.h"
@@ -5242,6 +5243,22 @@
     PlatformMediaSessionManager::sharedManager().setIsPlayingToAutomotiveHeadUnit(isPlaying);
 #endif
 }
+
+String Internals::highlightPseudoElementColor(const String& highlightName, Element& element)
+{
+    element.document().updateStyleIfNeeded();
+
+    auto& styleResolver = element.document().styleScope().resolver();
+    auto* parentStyle = element.computedStyle();
+    if (!parentStyle)
+        return { };
+
+    auto style = styleResolver.pseudoStyleForElement(element, { PseudoId::Highlight, highlightName }, *parentStyle);
+    if (!style)
+        return { };
+
+    return style->color().cssText();
+}
     
 Internals::TextIndicatorInfo::TextIndicatorInfo()
 {
diff --git a/Source/WebCore/testing/Internals.h b/Source/WebCore/testing/Internals.h
index 25322ed..31e98f7 100644
--- a/Source/WebCore/testing/Internals.h
+++ b/Source/WebCore/testing/Internals.h
@@ -911,6 +911,8 @@
     Ref<InternalsSetLike> createInternalsSetLike();
     Ref<InternalsMapLike> createInternalsMapLike();
 
+    String highlightPseudoElementColor(const String& highlightName, Element&);
+
 private:
     explicit Internals(Document&);
     Document* contextDocument() const;
diff --git a/Source/WebCore/testing/Internals.idl b/Source/WebCore/testing/Internals.idl
index 4529216..ee000cc 100644
--- a/Source/WebCore/testing/Internals.idl
+++ b/Source/WebCore/testing/Internals.idl
@@ -819,4 +819,6 @@
 
     InternalsMapLike createInternalsMapLike();
     InternalsSetLike createInternalsSetLike();
+
+    DOMString highlightPseudoElementColor(DOMString highlightName, Element element);
 };