Compile scrollbar pseudoclass css selectors.
authorachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Aug 2014 18:55:50 +0000 (18:55 +0000)
committerachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Aug 2014 18:55:50 +0000 (18:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=135242

Reviewed by Benjamin Poulain.

Source/WebCore:

Tests: scrollbars/corner-resizer-window-inactive.html
       scrollbars/scrollbar-selectors.html

* css/ElementRuleCollector.cpp:
(WebCore::ElementRuleCollector::ruleMatches):
Changed assertion because there are pseudo-elements selectors that return CannotCompileAnything now, which
make SimpleSelectorCheckers.
Add scrollbar, scrollbarPart, and document to the CheckingContext and compile scrollbar pseudo-element selectors.
* css/SelectorChecker.cpp:
(WebCore::hasScrollbarPseudoElement):
Added.  Logic moved from matchRecursively to be easier to read and to add assertions.
context.scrollbar is always non-null when dynamicPseudo is SCROLLBAR_CORNER.
(WebCore::SelectorChecker::matchRecursively):
Moved logic to hasScrollbarPseudoElement.
(WebCore::SelectorChecker::checkOne):
checkScrollbarPseudoClass accesses the document through the element now.
(WebCore::SelectorChecker::checkScrollbarPseudoClass):
* css/SelectorChecker.h:
(WebCore::SelectorChecker::SelectorCheckingContext::SelectorCheckingContext):
* css/SelectorCheckerTestFunctions.h:
(WebCore::scrollbarMatchesEnabledPseudoClass):
(WebCore::scrollbarMatchesDisabledPseudoClass):
(WebCore::scrollbarMatchesHoverPseudoClass):
(WebCore::scrollbarMatchesActivePseudoClass):
(WebCore::scrollbarMatchesHorizontalPseudoClass):
(WebCore::scrollbarMatchesVerticalPseudoClass):
(WebCore::scrollbarMatchesDecrementPseudoClass):
(WebCore::scrollbarMatchesIncrementPseudoClass):
(WebCore::scrollbarMatchesStartPseudoClass):
(WebCore::scrollbarMatchesEndPseudoClass):
(WebCore::scrollbarMatchesDoubleButtonPseudoClass):
(WebCore::scrollbarMatchesSingleButtonPseudoClass):
(WebCore::scrollbarMatchesNoButtonPseudoClass):
(WebCore::scrollbarMatchesCornerPresentPseudoClass):
Move scrollbar selector logic from SelectorChecker.cpp to SelectorCheckerTestFunctions.h
For window-inactive pseudo classes, we now access the document through the element instead of as a separate parameter.
* cssjit/SelectorCompiler.cpp:
(WebCore::SelectorCompiler::SelectorFragment::appendUnoptimizedPseudoClassWithContext):
(WebCore::SelectorCompiler::addScrollbarPseudoClassType):
(WebCore::SelectorCompiler::addPseudoClassType):
(WebCore::SelectorCompiler::isScrollbarPseudoElement):
(WebCore::SelectorCompiler::constructFragments):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementMatching):
Call functions for unoptimized pseudo classes that require a context.
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateContextFunctionCallTest):
Added.  Similar to generateElementFunctionCallTest, but the CheckingContext pointer is stored on the stack instead of a dedicated register.
* cssjit/SelectorCompiler.h:
Added scrollbar, scrollbarPart, and document to the CheckingContext.
(WebCore::SelectorCompiler::CheckingContext::document):
Added method to access the document in a way that is syntactically equal to SelectorCheckingContext.
This way, the template functions in SelectorCheckerTestFunctions.h can be compiled with both context types,
but the context types store the document differently.

LayoutTests:

* platform/wk2/TestExpectations:
Don't run corner-resizer-window-inactive-expected in WK2 because testRunner.setWindowIsKey doesn't work with WK2.
* scrollbars/corner-resizer-window-inactive-expected.html: Added.
* scrollbars/corner-resizer-window-inactive.html: Added.
* scrollbars/scrollbar-selectors-expected.txt: Added.
* scrollbars/scrollbar-selectors.html: Added.

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

13 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/wk2/TestExpectations
LayoutTests/scrollbars/corner-resizer-window-inactive-expected.html [new file with mode: 0644]
LayoutTests/scrollbars/corner-resizer-window-inactive.html [new file with mode: 0644]
LayoutTests/scrollbars/scrollbar-selectors-expected.txt [new file with mode: 0644]
LayoutTests/scrollbars/scrollbar-selectors.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/ElementRuleCollector.cpp
Source/WebCore/css/SelectorChecker.cpp
Source/WebCore/css/SelectorChecker.h
Source/WebCore/css/SelectorCheckerTestFunctions.h
Source/WebCore/cssjit/SelectorCompiler.cpp
Source/WebCore/cssjit/SelectorCompiler.h

index 70f7e95..f719b05 100644 (file)
@@ -1,3 +1,17 @@
+2014-08-07  Alex Christensen  <achristensen@webkit.org>
+
+        Compile scrollbar pseudoclass css selectors.
+        https://bugs.webkit.org/show_bug.cgi?id=135242
+
+        Reviewed by Benjamin Poulain.
+
+        * platform/wk2/TestExpectations:
+        Don't run corner-resizer-window-inactive-expected in WK2 because testRunner.setWindowIsKey doesn't work with WK2.
+        * scrollbars/corner-resizer-window-inactive-expected.html: Added.
+        * scrollbars/corner-resizer-window-inactive.html: Added.
+        * scrollbars/scrollbar-selectors-expected.txt: Added.
+        * scrollbars/scrollbar-selectors.html: Added.
+
 2014-08-07  Zalan Bujtas  <zalan@apple.com>
 
         border-radius on html does not render properly.
index b011cf8..3982a38 100644 (file)
@@ -213,6 +213,7 @@ fast/events/blur-focus-window-should-blur-focus-element.html
 fast/selectors/querySelector-window-inactive.html
 fast/selectors/selection-window-inactive.html
 fast/dom/Window/window-focus-self.html
+scrollbars/corner-resizer-window-inactive.html
 
 # css3-conditionals support is not yet enabled.
 webkit.org/b/86146 css3/supports.html
diff --git a/LayoutTests/scrollbars/corner-resizer-window-inactive-expected.html b/LayoutTests/scrollbars/corner-resizer-window-inactive-expected.html
new file mode 100644 (file)
index 0000000..6472d78
--- /dev/null
@@ -0,0 +1,48 @@
+<head>
+<style>
+body > div {
+    padding: 10px;
+    margin: 20px;
+    border: 1px solid lightgray;
+    width: 125px;
+    height: 100px;
+}
+
+::-webkit-scrollbar {
+    width: 13px;
+    height: 13px;
+    background-color: blue;
+}
+
+::-webkit-resizer {
+    background-color: green;
+}
+
+::-webkit-scrollbar-corner {
+    background-color: green;
+}
+
+</style>
+</head>
+<body>
+The scrollbar corner (bottom right) should be green when the window is inactive.
+<div style="overflow: auto; padding: 0">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+</div>
+
+The resizer (bottom right) should be green when the window is inactive.
+<div style="overflow: auto; resize: both; padding: 0">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+</div>
diff --git a/LayoutTests/scrollbars/corner-resizer-window-inactive.html b/LayoutTests/scrollbars/corner-resizer-window-inactive.html
new file mode 100644 (file)
index 0000000..711d240
--- /dev/null
@@ -0,0 +1,61 @@
+<head>
+<style>
+body > div {
+    padding: 10px;
+    margin: 20px;
+    border: 1px solid lightgray;
+    width: 125px;
+    height: 100px;
+}
+
+::-webkit-scrollbar {
+    width: 13px;
+    height: 13px;
+    background-color: blue;
+}
+
+::-webkit-resizer {
+    background-color: white;
+}
+
+::-webkit-resizer:window-inactive {
+    background-color: green;
+}
+
+::-webkit-scrollbar-corner {
+    background-color: white;
+}
+
+::-webkit-scrollbar-corner:window-inactive {
+    background-color: green;
+}
+
+</style>
+</head>
+<body>
+The scrollbar corner (bottom right) should be green when the window is inactive.
+<div style="overflow: auto; padding: 0">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+</div>
+
+The resizer (bottom right) should be green when the window is inactive.
+<div style="overflow: auto; resize: both; padding: 0">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+</div>
+
+<script>
+if (window.testRunner)
+    window.testRunner.setWindowIsKey(false);
+</script>
\ No newline at end of file
diff --git a/LayoutTests/scrollbars/scrollbar-selectors-expected.txt b/LayoutTests/scrollbars/scrollbar-selectors-expected.txt
new file mode 100644 (file)
index 0000000..98b8a63
--- /dev/null
@@ -0,0 +1,9 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderText {#text} at (0,0) size 448x18
+        text run at (0,0) width 272: "This test runs many scrollbar selector tests. "
+        text run at (272,0) width 176: "It passes if it does not crash."
+      RenderText {#text} at (0,0) size 0x0
diff --git a/LayoutTests/scrollbars/scrollbar-selectors.html b/LayoutTests/scrollbars/scrollbar-selectors.html
new file mode 100644 (file)
index 0000000..8b75298
--- /dev/null
@@ -0,0 +1,254 @@
+<head>
+<style>
+body > div {
+    padding: 10px;
+    margin: 20px;
+    display: inline-block;
+    border: 1px solid lightgray;
+    -webkit-box-sizing: border-box;
+    vertical-align: top;
+    font-family: Verdana, sans-serif;
+    font-size: 12px;
+    -webkit-user-select: text;
+    width: 125px;
+    height: 100px;
+}
+</style>
+</head>
+
+<body>
+This test runs many scrollbar selector tests.  It passes if it does not crash.
+<div style="overflow: scroll">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+
+<div style="overflow: auto">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+
+<div style="overflow: auto; padding: 0">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+</div>
+
+<div style="overflow: scroll; resize: both">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+
+<div style="overflow: auto; resize: both">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+
+<div style="overflow: auto; resize: both; padding: 0">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+</div>
+
+<div style="overflow-x: hidden; overflow-y: scroll">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+
+<div style="overflow-x: scroll; overflow-y: hidden; padding: 0">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+</div>
+</div>
+
+<div style="overflow-x: hidden; overflow-y: scroll; resize: both">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+
+<div style="overflow-x: scroll; overflow-y: hidden; resize: both; padding: 0">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+</div>
+</div>
+
+<div style="overflow: scroll; padding: 0" class="single">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+</div>
+
+<div style="overflow: scroll; padding: 0" class="double-end">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+</div>
+
+<div style="overflow: scroll; padding: 0" class="double-start">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+</div>
+
+<div style="overflow: scroll; padding: 0" class="double-both">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+</div>
+
+<div style="overflow: scroll; padding: 0" class="none">
+<div style="width: 400px; padding: 10px">
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi et nisi ut est venenatis viverra. Aenean pede orci, blandit quis, faucibus quis, egestas ut, mi. Pellentesque enim purus, venenatis dignissim, tincidunt a, ullamcorper eget, nibh. Nullam ut sem adipiscing orci vehicula interdum. Proin a enim. Phasellus sollicitudin, magna vitae vestibulum facilisis, tellus nunc iaculis arcu, in molestie sem velit tempus est. In eleifend velit at sem adipiscing sodales. Nunc sapien felis, aliquam et, volutpat rhoncus, condimentum ut, tortor. Integer est. Quisque viverra. Praesent sed arcu. Maecenas id lorem a leo lobortis condimentum.
+<br><br>
+Cras commodo rutrum augue. Vivamus iaculis. Nullam est. Maecenas consequat. Sed id dui. Vivamus a nisl. Donec pretium sapien. Proin et ligula et ligula placerat pulvinar. Aliquam erat volutpat. Proin id est. Suspendisse cursus, magna at hendrerit consequat, mauris est imperdiet neque, a ultrices arcu urna non nunc. Quisque tellus. Nulla nulla justo, vehicula nec, pellentesque eu, iaculis et, ligula. Praesent mattis ante vel sem. Suspendisse porta rhoncus urna. Phasellus felis. Praesent viverra convallis libero. Maecenas non augue. Donec hendrerit lectus id enim.
+<br><br>
+Nulla ligula dui, euismod et, sodales quis, sollicitudin quis, elit. In adipiscing est sed enim. Fusce at massa vitae metus semper hendrerit. Integer vitae urna. Nulla eget ligula. Etiam libero. Maecenas nisi nibh, convallis a, feugiat vitae, pulvinar et, mi. Curabitur arcu pede, adipiscing sed, egestas nec, commodo in, elit. Nulla facilisi. Proin varius pede et dui lacinia dapibus. Morbi nec augue. Proin imperdiet lacus eu tellus.
+</div>
+</div>
+
+<script>
+var pseudoElements = 
+[
+    "-webkit-scrollbar", 
+    "-webkit-scrollbar-button", 
+    "-webkit-scrollbar-track", 
+    "-webkit-scrollbar-track-piece", 
+    "-webkit-scrollbar-thumb", 
+    "-webkit-scrollbar-corner", 
+    "-webkit-resizer",
+    "invalidPseudoElement"
+];
+
+function toColor(n) {
+    var hex = "0123456789ABCDEF";
+    // Multiplying by 7 just makes the colors more diverse.
+    return "#"
+        + hex.substr(n * 7 >> 00 & 0x0F, 1)
+        + hex.substr(n * 7 >> 04 & 0x0F, 1)
+        + hex.substr(n * 7 >> 08 & 0x0F, 1)
+        + hex.substr(n * 7 >> 12 & 0x0F, 1)
+        + hex.substr(n * 7 >> 16 & 0x0F, 1)
+        + hex.substr(n * 7 >> 20 & 0x0F, 1);
+}
+
+function getPseudoClasses(n, pseudoClasses) {
+    var pseudoClassString = "";
+    for (var i = 0; i < pseudoClasses.length; i++)
+        if (n & (1 << i))
+            pseudoClassString += ":" + pseudoClasses[i];
+    return pseudoClassString;
+}
+
+function appendStyle(css) {
+    var style = document.createElement('style');
+    style.type = 'text/css';
+    style.appendChild(document.createTextNode(css));
+    document.head.appendChild(style);
+    
+    var divs = document.querySelectorAll("div");
+    for (var i = 0; i < divs.length; i++) {
+        // Redraw each div
+        divs[i].style.display = "none";
+        divs[i].style.display = "inline-block";
+        // Switch whether window-inactive works.
+        if (window.testRunner) {
+            window.testRunner.setWindowIsKey(false);
+            window.testRunner.setWindowIsKey(true);
+        }
+    }
+}
+
+function testPseudoClasses(pseudoClasses) {
+    // Generate css with every pseudo element having every possible combination of pseudo class.
+    var css = "";
+    var color = 0;
+    for (pseudoElement of pseudoElements)
+        for (var i = 0; i < 1 << pseudoClasses.length; i++)
+            css += "::" + pseudoElement + getPseudoClasses(i, pseudoClasses) + " { background-color: " + toColor(color++) + "; }";
+    appendStyle(css);
+}
+
+var pseudoClasses1 = 
+[
+    "disabled",
+    "enabled",
+    "horizontal",
+    "active",
+    "hover",
+    "vertical",
+    "decrement",
+    "increment",
+    "visited", // This is not a valid scrollbar pseudo class, but it is a valid pseudo class.
+    "invalidPseudoClass"
+];
+var pseudoClasses2 = 
+[
+    "start",
+    "end",
+    "double-button",
+    "single-button",
+    "no-button",
+    "corner-present",
+    "window-inactive",
+    "visited", // This is not a valid scrollbar pseudo class, but it is a valid pseudo class.
+    "invalidPseudoClass"
+];
+
+// Testing all combinations of pseudo classes would generate 2^17 combinations, which times out.
+// This is not quite comprehensive, but tests 2^10 + 2^9 combinations in a fraction of the time.
+testPseudoClasses(pseudoClasses1);
+testPseudoClasses(pseudoClasses2);
+
+// This tests various other unexpected things.
+appendStyle("::-webkit-scrollbar:start:start:start:start:start:start:start:start:start { color: red; }");
+appendStyle("::-webkit-scrollbar:invalid:invalid:invalid:invalid:invalid:invalid:invalid:invalid:invalid { color: red; }");
+appendStyle("::-webkit-scrollbar:visited:visited:visited:visited:visited:visited:visited:visited:visited { color: red; }");
+appendStyle("::-not-a-valid-pseudo-element::start:start:start:start:start:start:start:start:start { color: red; }");
+appendStyle("div:start { color: red; }");
+
+var divs = document.querySelectorAll("div");
+for (var i = 0; i < divs.length; i++)
+    divs[i].outerHTML = "";
+</script>
index dece33c..9b1690e 100644 (file)
@@ -1,3 +1,63 @@
+2014-08-07  Alex Christensen  <achristensen@webkit.org>
+
+        Compile scrollbar pseudoclass css selectors.
+        https://bugs.webkit.org/show_bug.cgi?id=135242
+
+        Reviewed by Benjamin Poulain.
+
+        Tests: scrollbars/corner-resizer-window-inactive.html
+               scrollbars/scrollbar-selectors.html
+
+        * css/ElementRuleCollector.cpp:
+        (WebCore::ElementRuleCollector::ruleMatches):
+        Changed assertion because there are pseudo-elements selectors that return CannotCompileAnything now, which
+        make SimpleSelectorCheckers.
+        Add scrollbar, scrollbarPart, and document to the CheckingContext and compile scrollbar pseudo-element selectors.
+        * css/SelectorChecker.cpp:
+        (WebCore::hasScrollbarPseudoElement):
+        Added.  Logic moved from matchRecursively to be easier to read and to add assertions.
+        context.scrollbar is always non-null when dynamicPseudo is SCROLLBAR_CORNER.
+        (WebCore::SelectorChecker::matchRecursively):
+        Moved logic to hasScrollbarPseudoElement.
+        (WebCore::SelectorChecker::checkOne):
+        checkScrollbarPseudoClass accesses the document through the element now.
+        (WebCore::SelectorChecker::checkScrollbarPseudoClass):
+        * css/SelectorChecker.h:
+        (WebCore::SelectorChecker::SelectorCheckingContext::SelectorCheckingContext):
+        * css/SelectorCheckerTestFunctions.h:
+        (WebCore::scrollbarMatchesEnabledPseudoClass):
+        (WebCore::scrollbarMatchesDisabledPseudoClass):
+        (WebCore::scrollbarMatchesHoverPseudoClass):
+        (WebCore::scrollbarMatchesActivePseudoClass):
+        (WebCore::scrollbarMatchesHorizontalPseudoClass):
+        (WebCore::scrollbarMatchesVerticalPseudoClass):
+        (WebCore::scrollbarMatchesDecrementPseudoClass):
+        (WebCore::scrollbarMatchesIncrementPseudoClass):
+        (WebCore::scrollbarMatchesStartPseudoClass):
+        (WebCore::scrollbarMatchesEndPseudoClass):
+        (WebCore::scrollbarMatchesDoubleButtonPseudoClass):
+        (WebCore::scrollbarMatchesSingleButtonPseudoClass):
+        (WebCore::scrollbarMatchesNoButtonPseudoClass):
+        (WebCore::scrollbarMatchesCornerPresentPseudoClass):
+        Move scrollbar selector logic from SelectorChecker.cpp to SelectorCheckerTestFunctions.h
+        For window-inactive pseudo classes, we now access the document through the element instead of as a separate parameter.
+        * cssjit/SelectorCompiler.cpp:
+        (WebCore::SelectorCompiler::SelectorFragment::appendUnoptimizedPseudoClassWithContext):
+        (WebCore::SelectorCompiler::addScrollbarPseudoClassType):
+        (WebCore::SelectorCompiler::addPseudoClassType):
+        (WebCore::SelectorCompiler::isScrollbarPseudoElement):
+        (WebCore::SelectorCompiler::constructFragments):
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementMatching):
+        Call functions for unoptimized pseudo classes that require a context.
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateContextFunctionCallTest):
+        Added.  Similar to generateElementFunctionCallTest, but the CheckingContext pointer is stored on the stack instead of a dedicated register.
+        * cssjit/SelectorCompiler.h:
+        Added scrollbar, scrollbarPart, and document to the CheckingContext.
+        (WebCore::SelectorCompiler::CheckingContext::document):
+        Added method to access the document in a way that is syntactically equal to SelectorCheckingContext.
+        This way, the template functions in SelectorCheckerTestFunctions.h can be compiled with both context types,
+        but the context types store the document differently.
+
 2014-08-07  Daniel Bates  <dabates@apple.com>
 
         Sometimes Gmail cannot load messages, particularly on refresh ("...the application ran into an unexpected error...")
index 180c3de..ccb8dbf 100644 (file)
@@ -297,8 +297,8 @@ inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData)
 
     if (compiledSelectorChecker) {
         if (ruleData.compilationStatus() == SelectorCompilationStatus::SimpleSelectorChecker) {
-            ASSERT_WITH_MESSAGE(m_pseudoStyleRequest.pseudoId == NOPSEUDO, "When matching pseudo elements, we should never compile a selector checker without context. ElementRuleCollector::collectMatchingRulesForList() should filter out useless rules for pseudo elements.");
             SelectorCompiler::SimpleSelectorChecker selectorChecker = SelectorCompiler::simpleSelectorCheckerFunction(compiledSelectorChecker, ruleData.compilationStatus());
+            ASSERT_WITH_MESSAGE(!selectorChecker(&m_element) || m_pseudoStyleRequest.pseudoId == NOPSEUDO, "When matching pseudo elements, we should never compile a selector checker without context unless it cannot match anything.");
 #if CSS_SELECTOR_JIT_PROFILING
             ruleData.compiledSelectorUsed();
 #endif
@@ -306,18 +306,17 @@ inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData)
         }
         ASSERT(ruleData.compilationStatus() == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
 
-        // FIXME: Currently a compiled selector doesn't support scrollbar / selection's exceptional case.
-        if (!m_pseudoStyleRequest.scrollbar) {
-            SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::selectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, ruleData.compilationStatus());
-            SelectorCompiler::CheckingContext context;
-            context.elementStyle = m_style;
-            context.resolvingMode = m_mode;
-            context.pseudoId = m_pseudoStyleRequest.pseudoId;
+        SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::selectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, ruleData.compilationStatus());
+        SelectorCompiler::CheckingContext context;
+        context.elementStyle = m_style;
+        context.resolvingMode = m_mode;
+        context.pseudoId = m_pseudoStyleRequest.pseudoId;
+        context.scrollbar = m_pseudoStyleRequest.scrollbar;
+        context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart;
 #if CSS_SELECTOR_JIT_PROFILING
-            ruleData.compiledSelectorUsed();
+        ruleData.compiledSelectorUsed();
 #endif
-            return selectorChecker(&m_element, &context);
-        }
+        return selectorChecker(&m_element, &context);
     }
 #endif // ENABLE(CSS_SELECTOR_JIT)
 
index 7b70418..5ebbc20 100644 (file)
 #include "NodeRenderStyle.h"
 #include "Page.h"
 #include "RenderElement.h"
-#include "RenderScrollbar.h"
 #include "RenderStyle.h"
-#include "ScrollableArea.h"
-#include "ScrollbarTheme.h"
 #include "SelectorCheckerTestFunctions.h"
 #include "ShadowRoot.h"
 #include "StyledElement.h"
@@ -155,6 +152,23 @@ bool SelectorChecker::match(const SelectorCheckingContext& context) const
     return true;
 }
 
+inline static bool hasScrollbarPseudoElement(const SelectorChecker::SelectorCheckingContext& context, PseudoId& dynamicPseudo)
+{
+    if (dynamicPseudo == SCROLLBAR
+        || dynamicPseudo == SCROLLBAR_THUMB
+        || dynamicPseudo == SCROLLBAR_BUTTON
+        || dynamicPseudo == SCROLLBAR_TRACK
+        || dynamicPseudo == SCROLLBAR_TRACK_PIECE
+        || dynamicPseudo == SCROLLBAR_CORNER) {
+        ASSERT(context.scrollbar);
+        return true;
+    }
+    
+    // RESIZER does not always have a scrollbar but it is a scrollbar-like pseudo element
+    // because it can have more than one pseudo element.
+    return dynamicPseudo == RESIZER;
+}
+    
 // Recursive check of selectors and combinators
 // It can return 4 different values:
 // * SelectorMatches          - the selector matches the element e
@@ -272,7 +286,7 @@ SelectorChecker::Match SelectorChecker::matchRecursively(const SelectorCheckingC
         // a selector is invalid if something follows a pseudo-element
         // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
         // to follow the pseudo elements.
-        nextContext.hasScrollbarPseudo = dynamicPseudo != NOPSEUDO && (context.scrollbar || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER);
+        nextContext.hasScrollbarPseudo = hasScrollbarPseudoElement(context, dynamicPseudo);
         nextContext.hasSelectionPseudo = dynamicPseudo == SELECTION;
         if ((context.elementStyle || m_mode == Mode::CollectingRules) && dynamicPseudo != NOPSEUDO
             && !nextContext.hasSelectionPseudo
@@ -482,8 +496,8 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context) const
             }
         } else if (context.hasScrollbarPseudo) {
             // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each
-            // (since there are no elements involved).
-            return checkScrollbarPseudoClass(context, &element->document(), selector);
+            // (since there are no elements involved except with window-inactive).
+            return checkScrollbarPseudoClass(context, selector);
         }
 
         // Normal element pseudo class checking.
@@ -810,83 +824,41 @@ bool SelectorChecker::checkOne(const SelectorCheckingContext& context) const
     return true;
 }
 
-bool SelectorChecker::checkScrollbarPseudoClass(const SelectorCheckingContext& context, Document* document, const CSSSelector* selector) const
+bool SelectorChecker::checkScrollbarPseudoClass(const SelectorCheckingContext& context, const CSSSelector* selector) const
 {
     ASSERT(selector->m_match == CSSSelector::PseudoClass);
 
-    RenderScrollbar* scrollbar = context.scrollbar;
-    ScrollbarPart part = context.scrollbarPart;
-
-    // FIXME: This is a temporary hack for resizers and scrollbar corners. Eventually :window-inactive should become a real
-    // pseudo class and just apply to everything.
-    if (selector->pseudoClassType() == CSSSelector::PseudoClassWindowInactive)
-        return !document->page()->focusController().isActive();
-
-    if (!scrollbar)
-        return false;
-
     switch (selector->pseudoClassType()) {
+    case CSSSelector::PseudoClassWindowInactive:
+        return isWindowInactive(context.element);
     case CSSSelector::PseudoClassEnabled:
-        return scrollbar->enabled();
+        return scrollbarMatchesEnabledPseudoClass(context);
     case CSSSelector::PseudoClassDisabled:
-        return !scrollbar->enabled();
+        return scrollbarMatchesDisabledPseudoClass(context);
     case CSSSelector::PseudoClassHover:
-        {
-            ScrollbarPart hoveredPart = scrollbar->hoveredPart();
-            if (part == ScrollbarBGPart)
-                return hoveredPart != NoPart;
-            if (part == TrackBGPart)
-                return hoveredPart == BackTrackPart || hoveredPart == ForwardTrackPart || hoveredPart == ThumbPart;
-            return part == hoveredPart;
-        }
+        return scrollbarMatchesHoverPseudoClass(context);
     case CSSSelector::PseudoClassActive:
-        {
-            ScrollbarPart pressedPart = scrollbar->pressedPart();
-            if (part == ScrollbarBGPart)
-                return pressedPart != NoPart;
-            if (part == TrackBGPart)
-                return pressedPart == BackTrackPart || pressedPart == ForwardTrackPart || pressedPart == ThumbPart;
-            return part == pressedPart;
-        }
+        return scrollbarMatchesActivePseudoClass(context);
     case CSSSelector::PseudoClassHorizontal:
-        return scrollbar->orientation() == HorizontalScrollbar;
+        return scrollbarMatchesHorizontalPseudoClass(context);
     case CSSSelector::PseudoClassVertical:
-        return scrollbar->orientation() == VerticalScrollbar;
+        return scrollbarMatchesVerticalPseudoClass(context);
     case CSSSelector::PseudoClassDecrement:
-        return part == BackButtonStartPart || part == BackButtonEndPart || part == BackTrackPart;
+        return scrollbarMatchesDecrementPseudoClass(context);
     case CSSSelector::PseudoClassIncrement:
-        return part == ForwardButtonStartPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
+        return scrollbarMatchesIncrementPseudoClass(context);
     case CSSSelector::PseudoClassStart:
-        return part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart;
+        return scrollbarMatchesStartPseudoClass(context);
     case CSSSelector::PseudoClassEnd:
-        return part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
+        return scrollbarMatchesEndPseudoClass(context);
     case CSSSelector::PseudoClassDoubleButton:
-        {
-            ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
-            if (part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart)
-                return buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth;
-            if (part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart)
-                return buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth;
-            return false;
-        }
+        return scrollbarMatchesDoubleButtonPseudoClass(context);
     case CSSSelector::PseudoClassSingleButton:
-        {
-            ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
-            if (part == BackButtonStartPart || part == ForwardButtonEndPart || part == BackTrackPart || part == ForwardTrackPart)
-                return buttonsPlacement == ScrollbarButtonsSingle;
-            return false;
-        }
+        return scrollbarMatchesSingleButtonPseudoClass(context);
     case CSSSelector::PseudoClassNoButton:
-        {
-            ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
-            if (part == BackTrackPart)
-                return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleEnd;
-            if (part == ForwardTrackPart)
-                return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleStart;
-            return false;
-        }
+        return scrollbarMatchesNoButtonPseudoClass(context);
     case CSSSelector::PseudoClassCornerPresent:
-        return scrollbar->scrollableArea()->isScrollCornerVisible();
+        return scrollbarMatchesCornerPresentPseudoClass(context);
     default:
         return false;
     }
index d6737d3..56c0ae7 100644 (file)
@@ -58,11 +58,11 @@ public:
         SelectorCheckingContext(const CSSSelector* selector, Element* element, VisitedMatchType visitedMatchType)
             : selector(selector)
             , element(element)
-            , scope(0)
+            , scope(nullptr)
             , visitedMatchType(visitedMatchType)
             , pseudoId(NOPSEUDO)
-            , elementStyle(0)
-            , scrollbar(0)
+            , elementStyle(nullptr)
+            , scrollbar(nullptr)
             , firstSelectorOfTheFragment(selector)
             , scrollbarPart(NoPart)
             , inFunctionalPseudoClass(false)
@@ -98,7 +98,7 @@ private:
     Match matchRecursively(const SelectorCheckingContext&, PseudoId&) const;
     bool checkOne(const SelectorCheckingContext&) const;
 
-    bool checkScrollbarPseudoClass(const SelectorCheckingContext&, Document*, const CSSSelector*) const;
+    bool checkScrollbarPseudoClass(const SelectorCheckingContext&, const CSSSelector*) const;
 
     bool m_strictParsing;
     bool m_documentIsHTML;
index c43a5ac..9737a62 100644 (file)
@@ -31,6 +31,9 @@
 #include "HTMLAreaElement.h"
 #include "HTMLInputElement.h"
 #include "HTMLOptionElement.h"
+#include "RenderScrollbar.h"
+#include "ScrollableArea.h"
+#include "ScrollbarTheme.h"
 #include <wtf/Compiler.h>
 
 #if ENABLE(VIDEO_TRACK)
@@ -160,6 +163,123 @@ ALWAYS_INLINE bool shouldAppearIndeterminate(const Element* element)
 {
     return element->shouldAppearIndeterminate();
 }
+    
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesEnabledPseudoClass(const ContextType& context)
+{
+    return context.scrollbar && context.scrollbar->enabled();
+}
+
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesDisabledPseudoClass(const ContextType& context)
+{
+    return context.scrollbar && !context.scrollbar->enabled();
+}
+
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesHoverPseudoClass(const ContextType& context)
+{
+    if (!context.scrollbar)
+        return false;
+    ScrollbarPart hoveredPart = context.scrollbar->hoveredPart();
+    if (context.scrollbarPart == ScrollbarBGPart)
+        return hoveredPart != NoPart;
+    if (context.scrollbarPart == TrackBGPart)
+        return hoveredPart == BackTrackPart || hoveredPart == ForwardTrackPart || hoveredPart == ThumbPart;
+    return context.scrollbarPart == hoveredPart;
+}
+
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesActivePseudoClass(const ContextType& context)
+{
+    if (!context.scrollbar)
+        return false;
+    ScrollbarPart pressedPart = context.scrollbar->pressedPart();
+    if (context.scrollbarPart == ScrollbarBGPart)
+        return pressedPart != NoPart;
+    if (context.scrollbarPart == TrackBGPart)
+        return pressedPart == BackTrackPart || pressedPart == ForwardTrackPart || pressedPart == ThumbPart;
+    return context.scrollbarPart == pressedPart;
+}
+    
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesHorizontalPseudoClass(const ContextType& context)
+{
+    return context.scrollbar && context.scrollbar->orientation() == HorizontalScrollbar;
+}
+
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesVerticalPseudoClass(const ContextType& context)
+{
+    return context.scrollbar && context.scrollbar->orientation() == VerticalScrollbar;
+}
+    
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesDecrementPseudoClass(const ContextType& context)
+{
+    return context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == BackButtonEndPart || context.scrollbarPart == BackTrackPart;
+}
+    
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesIncrementPseudoClass(const ContextType& context)
+{
+    return context.scrollbarPart == ForwardButtonStartPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == ForwardTrackPart;
+}
+    
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesStartPseudoClass(const ContextType& context)
+{
+    return context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == ForwardButtonStartPart || context.scrollbarPart == BackTrackPart;
+}
+    
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesEndPseudoClass(const ContextType& context)
+{
+    return context.scrollbarPart == BackButtonEndPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == ForwardTrackPart;
+}
+    
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesDoubleButtonPseudoClass(const ContextType& context)
+{
+    if (!context.scrollbar)
+        return false;
+    ScrollbarButtonsPlacement buttonsPlacement = context.scrollbar->theme()->buttonsPlacement();
+    if (context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == ForwardButtonStartPart || context.scrollbarPart == BackTrackPart)
+        return buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth;
+    if (context.scrollbarPart == BackButtonEndPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == ForwardTrackPart)
+        return buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth;
+    return false;
+}
+    
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesSingleButtonPseudoClass(const ContextType& context)
+{
+    if (!context.scrollbar)
+        return false;
+    ScrollbarButtonsPlacement buttonsPlacement = context.scrollbar->theme()->buttonsPlacement();
+    if (context.scrollbarPart == BackButtonStartPart || context.scrollbarPart == ForwardButtonEndPart || context.scrollbarPart == BackTrackPart || context.scrollbarPart == ForwardTrackPart)
+        return buttonsPlacement == ScrollbarButtonsSingle;
+    return false;
+}
+    
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesNoButtonPseudoClass(const ContextType& context)
+{
+    if (!context.scrollbar)
+        return false;
+    ScrollbarButtonsPlacement buttonsPlacement = context.scrollbar->theme()->buttonsPlacement();
+    if (context.scrollbarPart == BackTrackPart)
+        return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleEnd;
+    if (context.scrollbarPart == ForwardTrackPart)
+        return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleStart;
+    return false;
+}
+    
+template <typename ContextType>
+ALWAYS_INLINE bool scrollbarMatchesCornerPresentPseudoClass(const ContextType& context)
+{
+    return context.scrollbar && context.scrollbar->scrollableArea()->isScrollCornerVisible();
+}
 
 #if ENABLE(FULLSCREEN_API)
 ALWAYS_INLINE bool matchesFullScreenPseudoClass(const Element* element)
index 476ffc3..46fc0ef 100644 (file)
@@ -157,12 +157,15 @@ struct SelectorFragment {
     unsigned tagNameNotMatchedBacktrackingStartWidthFromIndirectAdjacent;
     unsigned widthFromIndirectAdjacent;
 
+    FunctionType appendUnoptimizedPseudoClassWithContext(bool (*matcher)(const CheckingContext&));
+    
     const QualifiedName* tagName;
     const AtomicString* id;
     const AtomicString* langFilter;
     Vector<const AtomicStringImpl*, 32> classNames;
     HashSet<unsigned> pseudoClasses;
     Vector<JSC::FunctionPtr, 32> unoptimizedPseudoClasses;
+    Vector<JSC::FunctionPtr, 32> unoptimizedPseudoClassesWithContext;
     Vector<AttributeMatchingInfo, 32> attributes;
     Vector<std::pair<int, int>, 32> nthChildFilters;
     Vector<SelectorFragment> notFilters;
@@ -233,6 +236,7 @@ private:
     void generateElementMatching(Assembler::JumpList& matchingTagNameFailureCases, Assembler::JumpList& matchingPostTagNameFailureCases, const SelectorFragment&);
     void generateElementDataMatching(Assembler::JumpList& failureCases, const SelectorFragment&);
     void generateElementFunctionCallTest(Assembler::JumpList& failureCases, JSC::FunctionPtr);
+    void generateContextFunctionCallTest(Assembler::JumpList& failureCases, JSC::FunctionPtr);
     void generateElementIsActive(Assembler::JumpList& failureCases, const SelectorFragment&);
     void generateElementIsFirstChild(Assembler::JumpList& failureCases, const SelectorFragment&);
     void generateElementIsHovered(Assembler::JumpList& failureCases, const SelectorFragment&);
@@ -354,6 +358,52 @@ static inline bool shouldUseRenderStyleFromCheckingContext(const SelectorFragmen
     return fragment.relationToRightFragment == FragmentRelation::Rightmost && fragment.positionInRootFragments == FragmentPositionInRootFragments::Rightmost;
 }
 
+FunctionType SelectorFragment::appendUnoptimizedPseudoClassWithContext(bool (*matcher)(const CheckingContext&))
+{
+    unoptimizedPseudoClassesWithContext.append(JSC::FunctionPtr(matcher));
+    return FunctionType::SelectorCheckerWithCheckingContext;
+}
+
+static inline FunctionType addScrollbarPseudoClassType(const CSSSelector& selector, SelectorFragment& fragment)
+{
+    switch (selector.pseudoClassType()) {
+    case CSSSelector::PseudoClassWindowInactive:
+        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr(isWindowInactive));
+        return FunctionType::SimpleSelectorChecker;
+    case CSSSelector::PseudoClassDisabled:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesDisabledPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassEnabled:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesEnabledPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassHorizontal:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesHorizontalPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassVertical:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesVerticalPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassDecrement:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesDecrementPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassIncrement:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesIncrementPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassStart:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesStartPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassEnd:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesEndPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassDoubleButton:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesDoubleButtonPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassSingleButton:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesSingleButtonPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassNoButton:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesNoButtonPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassCornerPresent:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesCornerPresentPseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassActive:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesActivePseudoClass<CheckingContext>);
+    case CSSSelector::PseudoClassHover:
+        return fragment.appendUnoptimizedPseudoClassWithContext(scrollbarMatchesHoverPseudoClass<CheckingContext>);
+    default:
+        return FunctionType::CannotMatchAnything;
+    }
+    return FunctionType::CannotMatchAnything;
+}
+
 static inline FunctionType addPseudoClassType(const CSSSelector& selector, SelectorFragment& fragment, SelectorContext selectorContext, FragmentPositionInRootFragments positionInRootFragments)
 {
     CSSSelector::PseudoClassType type = selector.pseudoClassType();
@@ -431,6 +481,19 @@ static inline FunctionType addPseudoClassType(const CSSSelector& selector, Selec
         return FunctionType::SimpleSelectorChecker;
 #endif
 
+    // These pseudo-classes only have meaning with scrollbars.
+    case CSSSelector::PseudoClassHorizontal:
+    case CSSSelector::PseudoClassVertical:
+    case CSSSelector::PseudoClassDecrement:
+    case CSSSelector::PseudoClassIncrement:
+    case CSSSelector::PseudoClassStart:
+    case CSSSelector::PseudoClassEnd:
+    case CSSSelector::PseudoClassDoubleButton:
+    case CSSSelector::PseudoClassSingleButton:
+    case CSSSelector::PseudoClassNoButton:
+    case CSSSelector::PseudoClassCornerPresent:
+        return FunctionType::CannotMatchAnything;
+
     // FIXME: Compile these pseudoclasses, too!
     case CSSSelector::PseudoClassEmpty:
     case CSSSelector::PseudoClassFirstOfType:
@@ -443,16 +506,6 @@ static inline FunctionType addPseudoClassType(const CSSSelector& selector, Selec
     case CSSSelector::PseudoClassDrag:
     case CSSSelector::PseudoClassFullPageMedia:
     case CSSSelector::PseudoClassScope:
-    case CSSSelector::PseudoClassCornerPresent:
-    case CSSSelector::PseudoClassDecrement:
-    case CSSSelector::PseudoClassIncrement:
-    case CSSSelector::PseudoClassHorizontal:
-    case CSSSelector::PseudoClassVertical:
-    case CSSSelector::PseudoClassStart:
-    case CSSSelector::PseudoClassEnd:
-    case CSSSelector::PseudoClassDoubleButton:
-    case CSSSelector::PseudoClassSingleButton:
-    case CSSSelector::PseudoClassNoButton:
         return FunctionType::CannotCompile;
 
     // Optimized pseudo selectors.
@@ -612,6 +665,11 @@ static bool pseudoClassOnlyMatchesLinksInQuirksMode(const CSSSelector& selector)
     return pseudoClassType == CSSSelector::PseudoClassHover || pseudoClassType == CSSSelector::PseudoClassActive;
 }
 
+static bool isScrollbarPseudoElement(CSSSelector::PseudoElementType type)
+{
+    return type >= CSSSelector::PseudoElementScrollbar && type <= CSSSelector::PseudoElementScrollbarTrackPiece;
+}
+
 static FunctionType constructFragments(const CSSSelector* rootSelector, SelectorContext selectorContext, SelectorFragmentList& selectorFragments, FragmentsLevel fragmentLevel, FragmentPositionInRootFragments positionInRootFragments)
 {
     SelectorFragment fragment;
@@ -623,10 +681,11 @@ static FunctionType constructFragments(const CSSSelector* rootSelector, Selector
         // A selector is invalid if something follows a pseudo-element.
         // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
         // to follow the pseudo elements.
-        // FIXME: Currently, CSS JIT doesn't support scrollbar and selection's exceptional cases.
-        // So all selectors following a pseudo-element is treated as invalid.
-        if (relation == CSSSelector::SubSelector && fragment.pseudoElementSelector)
-            return FunctionType::CannotCompile;
+        if (relation == CSSSelector::SubSelector
+            && fragment.pseudoElementSelector
+            && !isScrollbarPseudoElement(fragment.pseudoElementSelector->pseudoElementType())) {
+            return FunctionType::CannotMatchAnything;
+        }
 
         switch (selector->m_match) {
         case CSSSelector::Tag:
@@ -653,8 +712,10 @@ static FunctionType constructFragments(const CSSSelector* rootSelector, Selector
             FragmentPositionInRootFragments subPosition = positionInRootFragments;
             if (relationToPreviousFragment != FragmentRelation::Rightmost)
                 subPosition = FragmentPositionInRootFragments::NotRightmost;
-
-            functionType = mostRestrictiveFunctionType(functionType, addPseudoClassType(*selector, fragment, selectorContext, subPosition));
+            if (fragment.pseudoElementSelector && isScrollbarPseudoElement(fragment.pseudoElementSelector->pseudoElementType()))
+                functionType = mostRestrictiveFunctionType(functionType, addScrollbarPseudoClassType(*selector, fragment));
+            else
+                functionType = mostRestrictiveFunctionType(functionType, addPseudoClassType(*selector, fragment, selectorContext, subPosition));
             if (!pseudoClassOnlyMatchesLinksInQuirksMode(*selector))
                 fragment.onlyMatchesLinksInQuirksMode = false;
             if (functionType == FunctionType::CannotCompile || functionType == FunctionType::CannotMatchAnything)
@@ -678,9 +739,18 @@ static FunctionType constructFragments(const CSSSelector* rootSelector, Selector
             case CSSSelector::PseudoElementBefore:
             case CSSSelector::PseudoElementFirstLetter:
             case CSSSelector::PseudoElementFirstLine:
+            case CSSSelector::PseudoElementScrollbar:
+            case CSSSelector::PseudoElementScrollbarButton:
+            case CSSSelector::PseudoElementScrollbarCorner:
+            case CSSSelector::PseudoElementScrollbarThumb:
+            case CSSSelector::PseudoElementScrollbarTrack:
+            case CSSSelector::PseudoElementScrollbarTrackPiece:
                 fragment.pseudoElementSelector = selector;
                 break;
-            // FIXME: Support SCROLLBAR, RESIZER, SELECTION etc.
+            case CSSSelector::PseudoElementUnknown:
+                ASSERT_NOT_REACHED();
+                return FunctionType::CannotMatchAnything;
+            // FIXME: Support RESIZER, SELECTION etc.
             default:
                 return FunctionType::CannotCompile;
             }
@@ -1872,6 +1942,9 @@ void SelectorCodeGenerator::generateElementMatching(Assembler::JumpList& matchin
     for (unsigned i = 0; i < fragment.unoptimizedPseudoClasses.size(); ++i)
         generateElementFunctionCallTest(matchingPostTagNameFailureCases, fragment.unoptimizedPseudoClasses[i]);
 
+    for (unsigned i = 0; i < fragment.unoptimizedPseudoClassesWithContext.size(); ++i)
+        generateContextFunctionCallTest(matchingPostTagNameFailureCases, fragment.unoptimizedPseudoClassesWithContext[i]);
+
     generateElementDataMatching(matchingPostTagNameFailureCases, fragment);
 
     if (fragment.pseudoClasses.contains(CSSSelector::PseudoClassActive))
@@ -2308,6 +2381,18 @@ void SelectorCodeGenerator::generateElementFunctionCallTest(Assembler::JumpList&
     functionCall.setOneArgument(elementAddress);
     failureCases.append(functionCall.callAndBranchOnBooleanReturnValue(Assembler::Zero));
 }
+    
+void SelectorCodeGenerator::generateContextFunctionCallTest(Assembler::JumpList& failureCases, JSC::FunctionPtr testFunction)
+{
+    Assembler::RegisterID checkingContext = m_registerAllocator.allocateRegister();
+    loadCheckingContext(checkingContext);
+    m_registerAllocator.deallocateRegister(checkingContext);
+
+    FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls);
+    functionCall.setFunctionAddress(testFunction);
+    functionCall.setOneArgument(checkingContext);
+    failureCases.append(functionCall.callAndBranchOnBooleanReturnValue(Assembler::Zero));
+}
 
 static void setFirstChildState(Element* element)
 {
index 4be800a..e9445ba 100644 (file)
@@ -73,6 +73,8 @@ struct CheckingContext {
     SelectorChecker::Mode resolvingMode;
     RenderStyle* elementStyle;
     PseudoId pseudoId;
+    RenderScrollbar* scrollbar;
+    ScrollbarPart scrollbarPart;
 };
 
 enum class SelectorContext {