Title: [202197] trunk
Revision
202197
Author
benja...@webkit.org
Date
2016-06-17 22:53:28 -0700 (Fri, 17 Jun 2016)

Log Message

:indeterminate pseudo-class should match radios whose group has no checked radio
https://bugs.webkit.org/show_bug.cgi?id=156270

Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

* web-platform-tests/html/semantics/selectors/pseudo-classes/indeterminate-expected.txt:
One more pass on official tests :)

Source/WebCore:

The pseudo-class ":indeterminate" is supposed to match radio buttons
for which the entire group has no checked button.
Spec: https://html.spec.whatwg.org/#pseudo-classes:selector-indeterminate

The change is straightforward with one non-obvious choice:
I added matchesIndeterminatePseudoClass() in addition to shouldAppearIndeterminate().

The reason is shouldAppearIndeterminate() is used for styling and AX of elements
with an indeterminate states (check boxes and progress element). There is no such
UI for radio boxes.
I could have extended shouldAppearIndeterminate() to radio box
then filter out this case in RenderTheme. The problem is doing that would also requires
changes to the repaint logic to match :indeterminate. It seemed overkill to me to
change repaint() for a case that is never used in practice.

Tests: fast/css/pseudo-indeterminate-radio-buttons-basics.html
       fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation.html
       fast/selectors/detached-radio-button-checked-and-indeterminate-states.html
       fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update.html

* css/SelectorCheckerTestFunctions.h:
(WebCore::shouldAppearIndeterminate):
* dom/Element.cpp:
(WebCore::Element::matchesIndeterminatePseudoClass):
* dom/Element.h:
* dom/RadioButtonGroups.cpp:
(WebCore::RadioButtonGroup::setCheckedButton):
(WebCore::RadioButtonGroup::updateCheckedState):
(WebCore::RadioButtonGroup::remove):
(WebCore::RadioButtonGroup::setNeedsStyleRecalcForAllButtons):
(WebCore::RadioButtonGroups::hasCheckedButton):
* dom/RadioButtonGroups.h:
* html/CheckboxInputType.cpp:
(WebCore::CheckboxInputType::matchesIndeterminatePseudoClass):
(WebCore::CheckboxInputType::shouldAppearIndeterminate):
(WebCore::CheckboxInputType::supportsIndeterminateAppearance): Deleted.
* html/CheckboxInputType.h:
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::setChecked):
(WebCore::HTMLInputElement::matchesIndeterminatePseudoClass):
(WebCore::HTMLInputElement::shouldAppearIndeterminate):
(WebCore::HTMLInputElement::radioButtonGroups):
* html/HTMLInputElement.h:
* html/InputType.cpp:
(WebCore::InputType::matchesIndeterminatePseudoClass):
(WebCore::InputType::shouldAppearIndeterminate):
(WebCore::InputType::supportsIndeterminateAppearance): Deleted.
* html/InputType.h:
* html/RadioInputType.cpp:
(WebCore::RadioInputType::matchesIndeterminatePseudoClass):
(WebCore::RadioInputType::willDispatchClick): Deleted.
(WebCore::RadioInputType::didDispatchClick): Deleted.
(WebCore::RadioInputType::supportsIndeterminateAppearance): Deleted.
The iOS specific code is just plain wrong.
It was changing the indeterminate state of the input element.
The spec clearly says that state is only used by checkbox:
https://html.spec.whatwg.org/#dom-input-indeterminate

Moreover, the style update would not change the indeterminate state
of other buttons in the Button Group, which is just bizarre.
RenderThemeIOS does not make use of any of this with the current style.

* html/RadioInputType.h:
* style/StyleSharingResolver.cpp:
(WebCore::Style::SharingResolver::canShareStyleWithElement):
(WebCore::Style::canShareStyleWithControl): Deleted.
(WebCore::Style::SharingResolver::sharingCandidateHasIdenticalStyleAffectingAttributes): Deleted.
Style sharing is unified behind the selector matching which is neat.

LayoutTests:

There are two important aspect to cover for this change:
1) The style is updated correctly when a Button Group composition change.
2) When the checkness changes for a Button Group, all its elements
   are invalidated to match :indeterminate.

* fast/forms/radio/indeterminate-radio.html:
This test was verifying that the property "indeterminate" of the input element
is not reflected to the style through :indeterminate.
I updated the test to still verify that except that we now match :indeterminate
before changing the property.

* fast/css/pseudo-indeterminate-radio-buttons-basics-expected.html: Added.
* fast/css/pseudo-indeterminate-radio-buttons-basics.html: Added.

* fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation-expected.txt: Added.
* fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation.html: Added.
Verify that we don't invalidate everything when the checked button changes.
We only need to invalidate everything if the checked state of the whole group changes.

* fast/selectors/detached-radio-button-checked-and-indeterminate-states-expected.txt: Added.
* fast/selectors/detached-radio-button-checked-and-indeterminate-states.html: Added.
* fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update-expected.txt: Added.
* fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update.html: Added.

Modified Paths

Added Paths

Removed Paths

  • trunk/LayoutTests/platform/ios-simulator/imported/w3c/web-platform-tests/html/semantics/selectors/

Diff

Modified: trunk/LayoutTests/ChangeLog (202196 => 202197)


--- trunk/LayoutTests/ChangeLog	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/LayoutTests/ChangeLog	2016-06-18 05:53:28 UTC (rev 202197)
@@ -1,3 +1,34 @@
+2016-06-17  Benjamin Poulain  <benja...@webkit.org>
+
+        :indeterminate pseudo-class should match radios whose group has no checked radio
+        https://bugs.webkit.org/show_bug.cgi?id=156270
+
+        Reviewed by Simon Fraser.
+
+        There are two important aspect to cover for this change:
+        1) The style is updated correctly when a Button Group composition change.
+        2) When the checkness changes for a Button Group, all its elements
+           are invalidated to match :indeterminate.
+
+        * fast/forms/radio/indeterminate-radio.html:
+        This test was verifying that the property "indeterminate" of the input element
+        is not reflected to the style through :indeterminate.
+        I updated the test to still verify that except that we now match :indeterminate
+        before changing the property.
+
+        * fast/css/pseudo-indeterminate-radio-buttons-basics-expected.html: Added.
+        * fast/css/pseudo-indeterminate-radio-buttons-basics.html: Added.
+
+        * fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation-expected.txt: Added.
+        * fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation.html: Added.
+        Verify that we don't invalidate everything when the checked button changes.
+        We only need to invalidate everything if the checked state of the whole group changes.
+
+        * fast/selectors/detached-radio-button-checked-and-indeterminate-states-expected.txt: Added.
+        * fast/selectors/detached-radio-button-checked-and-indeterminate-states.html: Added.
+        * fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update-expected.txt: Added.
+        * fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update.html: Added.
+
 2016-06-17  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, rolling out r202152.

Added: trunk/LayoutTests/fast/css/pseudo-indeterminate-radio-buttons-basics-expected.html (0 => 202197)


--- trunk/LayoutTests/fast/css/pseudo-indeterminate-radio-buttons-basics-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/css/pseudo-indeterminate-radio-buttons-basics-expected.html	2016-06-18 05:53:28 UTC (rev 202197)
@@ -0,0 +1,206 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style>
+    input {
+        background-color: blue;
+        width: 15px;
+        height: 15px;
+        -webkit-appearance: none;
+    }
+    .checked {
+        border: 2px solid red;
+    }
+    .indeterminate {
+        background-color: green;
+    }
+    .disabled {
+        border-left: 3px solid orange;
+    }
+</style>
+</head>
+<body>
+    <div>
+        <input type="radio" class="indeterminate">
+        <input type="radio" class="indeterminate">
+        <input type="radio" name="group1" class="indeterminate">
+        <input type="radio" name="group1" class="indeterminate">
+        <input type="radio" name="group2" class="indeterminate">
+        <span><input type="radio" name="group2" class="indeterminate"></span>
+        <input type="radio" name="group3">
+        <input type="radio" name="group3" checked>
+        <input type="radio" name="group4">
+        <span><input type="radio" name="group4" checked></span>
+        <input type="radio" disabled class="indeterminate disabled">
+        <input type="radio" name="group5" disabled class="indeterminate disabled">
+        <input type="radio" name="group5" disabled class="indeterminate disabled">
+        <input type="radio" name="group6" disabled class="indeterminate disabled">
+        <span><input type="radio" name="group6" disabled class="indeterminate disabled"></span>
+        <input type="radio" name="group7" disabled class="disabled">
+        <input type="radio" name="group7" checked disabled class="disabled">
+        <input type="radio" name="group8" disabled class="disabled">
+        <span><input type="radio" name="group8" checked disabled class="disabled"></span>
+        <input type="radio" readonly class="indeterminate">
+        <input type="radio" name="group9" readonly class="indeterminate">
+        <input type="radio" name="group9" readonly class="indeterminate">
+        <input type="radio" name="group10" readonly class="indeterminate">
+        <span><input type="radio" name="group10" readonly class="indeterminate"></span>
+        <input type="radio" name="group11" readonly>
+        <input type="radio" name="group11" checked readonly>
+        <input type="radio" name="group12" readonly>
+        <span><input type="radio" name="group12" checked readonly></span>
+    </div>
+    <form>
+        <input type="radio" class="indeterminate">
+        <input type="radio" class="indeterminate">
+        <input type="radio" name="group1" class="indeterminate">
+        <input type="radio" name="group1" class="indeterminate">
+        <input type="radio" name="group2" class="indeterminate">
+        <span><input type="radio" name="group2" class="indeterminate"></span>
+        <input type="radio" name="group3">
+        <input type="radio" name="group3" checked class="checked">
+        <input type="radio" name="group4">
+        <span><input type="radio" name="group4" checked class="checked"></span>
+        <input type="radio" disabled class="indeterminate disabled">
+        <input type="radio" name="group5" disabled class="indeterminate disabled">
+        <input type="radio" name="group5" disabled class="indeterminate disabled">
+        <input type="radio" name="group6" disabled class="indeterminate disabled">
+        <span><input type="radio" name="group6" disabled class="indeterminate disabled"></span>
+        <input type="radio" name="group7" disabled class="disabled">
+        <input type="radio" name="group7" checked disabled class="checked disabled">
+        <input type="radio" name="group8" disabled class="disabled">
+        <span><input type="radio" name="group8" checked disabled class="checked disabled"></span>
+        <input type="radio" readonly class="indeterminate">
+        <input type="radio" name="group9" readonly class="indeterminate">
+        <input type="radio" name="group9" readonly class="indeterminate">
+        <input type="radio" name="group10" readonly class="indeterminate">
+        <span><input type="radio" name="group10" readonly class="indeterminate"></span>
+        <input type="radio" name="group11" readonly>
+        <input type="radio" name="group11" checked readonly class="checked">
+        <input type="radio" name="group12" readonly>
+        <span><input type="radio" name="group12" checked readonly class="checked"></span>
+    </form>
+    <form disabled>
+        <input type="radio" class="indeterminate">
+        <input type="radio" class="indeterminate">
+        <input type="radio" name="group1" class="indeterminate">
+        <input type="radio" name="group1" class="indeterminate">
+        <input type="radio" name="group2" class="indeterminate">
+        <span><input type="radio" name="group2" class="indeterminate"></span>
+        <input type="radio" name="group3">
+        <input type="radio" name="group3" checked class="checked">
+        <input type="radio" name="group4">
+        <span><input type="radio" name="group4" checked class="checked"></span>
+        <input type="radio" disabled class="indeterminate disabled">
+        <input type="radio" name="group5" disabled class="indeterminate disabled">
+        <input type="radio" name="group5" disabled class="indeterminate disabled">
+        <input type="radio" name="group6" disabled class="indeterminate disabled">
+        <span><input type="radio" name="group6" disabled class="indeterminate disabled"></span>
+        <input type="radio" name="group7" disabled class="disabled">
+        <input type="radio" name="group7" checked disabled class="checked disabled">
+        <input type="radio" name="group8" disabled class="disabled">
+        <span><input type="radio" name="group8" checked disabled class="checked disabled"></span>
+        <input type="radio" readonly class="indeterminate">
+        <input type="radio" name="group9" readonly class="indeterminate">
+        <input type="radio" name="group9" readonly class="indeterminate">
+        <input type="radio" name="group10" readonly class="indeterminate">
+        <span><input type="radio" name="group10" readonly class="indeterminate"></span>
+        <input type="radio" name="group11" readonly>
+        <input type="radio" name="group11" checked readonly class="checked">
+        <input type="radio" name="group12" readonly>
+        <span><input type="radio" name="group12" checked readonly class="checked"></span>
+    </form>
+    <fieldset disabled class="disabled">
+        <input type="radio" class="indeterminate disabled">
+        <input type="radio" class="indeterminate disabled">
+        <input type="radio" name="group1" class="indeterminate disabled">
+        <input type="radio" name="group1" class="indeterminate disabled">
+        <input type="radio" name="group2" class="indeterminate disabled">
+        <span><input type="radio" name="group2" class="indeterminate disabled"></span>
+        <input type="radio" name="group3" class="disabled">
+        <input type="radio" name="group3" checked class="checked disabled">
+        <input type="radio" name="group4" class="disabled">
+        <span><input type="radio" name="group4" checked class="checked disabled"></span>
+        <input type="radio" disabled class="indeterminate disabled">
+        <input type="radio" name="group5" disabled class="indeterminate disabled">
+        <input type="radio" name="group5" disabled class="indeterminate disabled">
+        <input type="radio" name="group6" disabled class="indeterminate disabled">
+        <span><input type="radio" name="group6" disabled class="indeterminate disabled"></span>
+        <input type="radio" name="group7" disabled class="disabled">
+        <input type="radio" name="group7" checked disabled class="checked disabled">
+        <input type="radio" name="group8" disabled class="disabled">
+        <span><input type="radio" name="group8" checked disabled class="checked disabled"></span>
+        <input type="radio" readonly class="indeterminate disabled">
+        <input type="radio" name="group9" readonly class="indeterminate disabled">
+        <input type="radio" name="group9" readonly class="indeterminate disabled">
+        <input type="radio" name="group10" readonly class="indeterminate disabled">
+        <span><input type="radio" name="group10" readonly class="indeterminate disabled"></span>
+        <input type="radio" name="group11" readonly class="disabled">
+        <input type="radio" name="group11" checked readonly class="checked disabled">
+        <input type="radio" name="group12" readonly class="disabled">
+        <span><input type="radio" name="group12" checked readonly class="checked disabled"></span>
+    </fieldset>
+    <form>
+        <fieldset disabled class="disabled">
+            <input type="radio" class="indeterminate disabled">
+            <input type="radio" class="indeterminate disabled">
+            <input type="radio" name="group1" class="indeterminate disabled">
+            <input type="radio" name="group1" class="indeterminate disabled">
+            <input type="radio" name="group2" class="indeterminate disabled">
+            <span><input type="radio" name="group2" class="indeterminate disabled"></span>
+            <input type="radio" name="group3" class="disabled">
+            <input type="radio" name="group3" checked class="disabled">
+            <input type="radio" name="group4" class="disabled">
+            <span><input type="radio" name="group4" checked class="disabled"></span>
+            <input type="radio" disabled class="indeterminate disabled">
+            <input type="radio" name="group5" disabled class="indeterminate disabled">
+            <input type="radio" name="group5" disabled class="indeterminate disabled">
+            <input type="radio" name="group6" disabled class="indeterminate disabled">
+            <span><input type="radio" name="group6" disabled class="indeterminate disabled"></span>
+            <input type="radio" name="group7" disabled class="disabled">
+            <input type="radio" name="group7" checked disabled class="disabled">
+            <input type="radio" name="group8" disabled class="disabled">
+            <span><input type="radio" name="group8" checked disabled class="disabled"></span>
+            <input type="radio" readonly class="indeterminate disabled">
+            <input type="radio" name="group9" readonly class="indeterminate disabled">
+            <input type="radio" name="group9" readonly class="indeterminate disabled">
+            <input type="radio" name="group10" readonly class="indeterminate disabled">
+            <span><input type="radio" name="group10" readonly class="indeterminate disabled"></span>
+            <input type="radio" name="group11" readonly class="disabled">
+            <input type="radio" name="group11" checked readonly class="disabled">
+            <input type="radio" name="group12" readonly class="disabled">
+            <span><input type="radio" name="group12" checked readonly class="disabled"></span>
+        </fieldset>
+        <fieldset>
+            <input type="radio" class="indeterminate">
+            <input type="radio" class="indeterminate">
+            <input type="radio" name="group1" class="indeterminate">
+            <input type="radio" name="group1" class="indeterminate">
+            <input type="radio" name="group2" class="indeterminate">
+            <span><input type="radio" name="group2" class="indeterminate"></span>
+            <input type="radio" name="group3">
+            <input type="radio" name="group3" checked class="checked">
+            <input type="radio" name="group4">
+            <span><input type="radio" name="group4" checked class="checked"></span>
+            <input type="radio" disabled class="indeterminate disabled">
+            <input type="radio" name="group5" disabled class="indeterminate disabled">
+            <input type="radio" name="group5" disabled class="indeterminate disabled">
+            <input type="radio" name="group6" disabled class="indeterminate disabled">
+            <span><input type="radio" name="group6" disabled class="indeterminate disabled"></span>
+            <input type="radio" name="group7" disabled class="disabled">
+            <input type="radio" name="group7" checked disabled class="checked disabled">
+            <input type="radio" name="group8" disabled class="disabled">
+            <span><input type="radio" name="group8" checked disabled class="checked disabled"></span>
+            <input type="radio" readonly class="indeterminate">
+            <input type="radio" name="group9" readonly class="indeterminate">
+            <input type="radio" name="group9" readonly class="indeterminate">
+            <input type="radio" name="group10" readonly class="indeterminate">
+            <span><input type="radio" name="group10" readonly class="indeterminate"></span>
+            <input type="radio" name="group11" readonly>
+            <input type="radio" name="group11" checked readonly class="checked">
+            <input type="radio" name="group12" readonly>
+            <span><input type="radio" name="group12" checked readonly class="checked"></span>
+        </fieldset>
+    </form>
+</body>
+</html>

Added: trunk/LayoutTests/fast/css/pseudo-indeterminate-radio-buttons-basics.html (0 => 202197)


--- trunk/LayoutTests/fast/css/pseudo-indeterminate-radio-buttons-basics.html	                        (rev 0)
+++ trunk/LayoutTests/fast/css/pseudo-indeterminate-radio-buttons-basics.html	2016-06-18 05:53:28 UTC (rev 202197)
@@ -0,0 +1,206 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<style>
+    input {
+        background-color: blue;
+        width: 15px;
+        height: 15px;
+        -webkit-appearance: none;
+    }
+    :checked {
+        border: 2px solid red;
+    }
+    :indeterminate {
+        background-color: green;
+    }
+    :disabled {
+        border-left: 3px solid orange;
+    }
+</style>
+</head>
+<body>
+    <div>
+        <input type="radio">
+        <input type="radio">
+        <input type="radio" name="group1">
+        <input type="radio" name="group1">
+        <input type="radio" name="group2">
+        <span><input type="radio" name="group2"></span>
+        <input type="radio" name="group3">
+        <input type="radio" name="group3" checked>
+        <input type="radio" name="group4">
+        <span><input type="radio" name="group4" checked></span>
+        <input type="radio" disabled>
+        <input type="radio" name="group5" disabled>
+        <input type="radio" name="group5" disabled>
+        <input type="radio" name="group6" disabled>
+        <span><input type="radio" name="group6" disabled></span>
+        <input type="radio" name="group7" disabled>
+        <input type="radio" name="group7" checked disabled>
+        <input type="radio" name="group8" disabled>
+        <span><input type="radio" name="group8" checked disabled></span>
+        <input type="radio" readonly>
+        <input type="radio" name="group9" readonly>
+        <input type="radio" name="group9" readonly>
+        <input type="radio" name="group10" readonly>
+        <span><input type="radio" name="group10" readonly></span>
+        <input type="radio" name="group11" readonly>
+        <input type="radio" name="group11" checked readonly>
+        <input type="radio" name="group12" readonly>
+        <span><input type="radio" name="group12" checked readonly></span>
+    </div>
+    <form>
+        <input type="radio">
+        <input type="radio">
+        <input type="radio" name="group1">
+        <input type="radio" name="group1">
+        <input type="radio" name="group2">
+        <span><input type="radio" name="group2"></span>
+        <input type="radio" name="group3">
+        <input type="radio" name="group3" checked>
+        <input type="radio" name="group4">
+        <span><input type="radio" name="group4" checked></span>
+        <input type="radio" disabled>
+        <input type="radio" name="group5" disabled>
+        <input type="radio" name="group5" disabled>
+        <input type="radio" name="group6" disabled>
+        <span><input type="radio" name="group6" disabled></span>
+        <input type="radio" name="group7" disabled>
+        <input type="radio" name="group7" checked disabled>
+        <input type="radio" name="group8" disabled>
+        <span><input type="radio" name="group8" checked disabled></span>
+        <input type="radio" readonly>
+        <input type="radio" name="group9" readonly>
+        <input type="radio" name="group9" readonly>
+        <input type="radio" name="group10" readonly>
+        <span><input type="radio" name="group10" readonly></span>
+        <input type="radio" name="group11" readonly>
+        <input type="radio" name="group11" checked readonly>
+        <input type="radio" name="group12" readonly>
+        <span><input type="radio" name="group12" checked readonly></span>
+    </form>
+    <form disabled>
+        <input type="radio">
+        <input type="radio">
+        <input type="radio" name="group1">
+        <input type="radio" name="group1">
+        <input type="radio" name="group2">
+        <span><input type="radio" name="group2"></span>
+        <input type="radio" name="group3">
+        <input type="radio" name="group3" checked>
+        <input type="radio" name="group4">
+        <span><input type="radio" name="group4" checked></span>
+        <input type="radio" disabled>
+        <input type="radio" name="group5" disabled>
+        <input type="radio" name="group5" disabled>
+        <input type="radio" name="group6" disabled>
+        <span><input type="radio" name="group6" disabled></span>
+        <input type="radio" name="group7" disabled>
+        <input type="radio" name="group7" checked disabled>
+        <input type="radio" name="group8" disabled>
+        <span><input type="radio" name="group8" checked disabled></span>
+        <input type="radio" readonly>
+        <input type="radio" name="group9" readonly>
+        <input type="radio" name="group9" readonly>
+        <input type="radio" name="group10" readonly>
+        <span><input type="radio" name="group10" readonly></span>
+        <input type="radio" name="group11" readonly>
+        <input type="radio" name="group11" checked readonly>
+        <input type="radio" name="group12" readonly>
+        <span><input type="radio" name="group12" checked readonly></span>
+    </form>
+    <fieldset disabled>
+        <input type="radio">
+        <input type="radio">
+        <input type="radio" name="group1">
+        <input type="radio" name="group1">
+        <input type="radio" name="group2">
+        <span><input type="radio" name="group2"></span>
+        <input type="radio" name="group3">
+        <input type="radio" name="group3" checked>
+        <input type="radio" name="group4">
+        <span><input type="radio" name="group4" checked></span>
+        <input type="radio" disabled>
+        <input type="radio" name="group5" disabled>
+        <input type="radio" name="group5" disabled>
+        <input type="radio" name="group6" disabled>
+        <span><input type="radio" name="group6" disabled></span>
+        <input type="radio" name="group7" disabled>
+        <input type="radio" name="group7" checked disabled>
+        <input type="radio" name="group8" disabled>
+        <span><input type="radio" name="group8" checked disabled></span>
+        <input type="radio" readonly>
+        <input type="radio" name="group9" readonly>
+        <input type="radio" name="group9" readonly>
+        <input type="radio" name="group10" readonly>
+        <span><input type="radio" name="group10" readonly></span>
+        <input type="radio" name="group11" readonly>
+        <input type="radio" name="group11" checked readonly>
+        <input type="radio" name="group12" readonly>
+        <span><input type="radio" name="group12" checked readonly></span>
+    </fieldset>
+    <form>
+        <fieldset disabled>
+            <input type="radio">
+            <input type="radio">
+            <input type="radio" name="group1">
+            <input type="radio" name="group1">
+            <input type="radio" name="group2">
+            <span><input type="radio" name="group2"></span>
+            <input type="radio" name="group3">
+            <input type="radio" name="group3" checked>
+            <input type="radio" name="group4">
+            <span><input type="radio" name="group4" checked></span>
+            <input type="radio" disabled>
+            <input type="radio" name="group5" disabled>
+            <input type="radio" name="group5" disabled>
+            <input type="radio" name="group6" disabled>
+            <span><input type="radio" name="group6" disabled></span>
+            <input type="radio" name="group7" disabled>
+            <input type="radio" name="group7" checked disabled>
+            <input type="radio" name="group8" disabled>
+            <span><input type="radio" name="group8" checked disabled></span>
+            <input type="radio" readonly>
+            <input type="radio" name="group9" readonly>
+            <input type="radio" name="group9" readonly>
+            <input type="radio" name="group10" readonly>
+            <span><input type="radio" name="group10" readonly></span>
+            <input type="radio" name="group11" readonly>
+            <input type="radio" name="group11" checked readonly>
+            <input type="radio" name="group12" readonly>
+            <span><input type="radio" name="group12" checked readonly></span>
+        </fieldset>
+        <fieldset>
+            <input type="radio">
+            <input type="radio">
+            <input type="radio" name="group1">
+            <input type="radio" name="group1">
+            <input type="radio" name="group2">
+            <span><input type="radio" name="group2"></span>
+            <input type="radio" name="group3">
+            <input type="radio" name="group3" checked>
+            <input type="radio" name="group4">
+            <span><input type="radio" name="group4" checked></span>
+            <input type="radio" disabled>
+            <input type="radio" name="group5" disabled>
+            <input type="radio" name="group5" disabled>
+            <input type="radio" name="group6" disabled>
+            <span><input type="radio" name="group6" disabled></span>
+            <input type="radio" name="group7" disabled>
+            <input type="radio" name="group7" checked disabled>
+            <input type="radio" name="group8" disabled>
+            <span><input type="radio" name="group8" checked disabled></span>
+            <input type="radio" readonly>
+            <input type="radio" name="group9" readonly>
+            <input type="radio" name="group9" readonly>
+            <input type="radio" name="group10" readonly>
+            <span><input type="radio" name="group10" readonly></span>
+            <input type="radio" name="group11" readonly>
+            <input type="radio" name="group11" checked readonly>
+            <input type="radio" name="group12" readonly>
+            <span><input type="radio" name="group12" checked readonly></span>
+        </fieldset>
+    </form>
+</body>
+</html>

Added: trunk/LayoutTests/fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation-expected.txt (0 => 202197)


--- trunk/LayoutTests/fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation-expected.txt	2016-06-18 05:53:28 UTC (rev 202197)
@@ -0,0 +1,28 @@
+Verify that we do not invalidate more than needed to satisfy :indeterminate
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS elementsNeedingStyleRecalc() is []
+PASS elementsWithIndeterminateStyle() is ["radio1", "radio2", "radio3", "radio4", "radio5", "radio6", "radio7", "radio8", "radio9", "radio10"]
+PASS checkedElements() is []
+Check radio3
+PASS elementsNeedingStyleRecalc() is ["radio1", "radio2", "radio3", "radio4", "radio5"]
+PASS elementsWithIndeterminateStyle() is ["radio6", "radio7", "radio8", "radio9", "radio10"]
+PASS checkedElements() is ["radio3"]
+Check radio8
+PASS elementsNeedingStyleRecalc() is ["radio6", "radio7", "radio8", "radio9", "radio10"]
+PASS elementsWithIndeterminateStyle() is []
+PASS checkedElements() is ["radio3", "radio8"]
+Check radio4
+PASS elementsNeedingStyleRecalc() is ["radio3", "radio4"]
+PASS elementsWithIndeterminateStyle() is []
+PASS checkedElements() is ["radio4", "radio8"]
+Check radio9
+PASS elementsNeedingStyleRecalc() is ["radio8", "radio9"]
+PASS elementsWithIndeterminateStyle() is []
+PASS checkedElements() is ["radio4", "radio9"]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation.html (0 => 202197)


--- trunk/LayoutTests/fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation.html	                        (rev 0)
+++ trunk/LayoutTests/fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation.html	2016-06-18 05:53:28 UTC (rev 202197)
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<style>
+    input {
+        background-color: rgb(1, 2, 3);
+    }
+    :indeterminate {
+        background-color: rgb(4, 5, 6);
+    }
+</style>
+</head>
+<body>
+    <div id="with-renderer">
+        <!-- With renderer -->
+        <input type="radio" name="group1" id="radio1">
+        <input type="radio" name="group1" id="radio2">
+        <input type="radio" name="group1" id="radio3">
+        <input type="radio" name="group1" id="radio4">
+        <input type="radio" name="group1" id="radio5">
+    </div>
+    <div style="display:none;">
+        <!-- Without renderer -->
+        <input type="radio" name="group2" id="radio6">
+        <input type="radio" name="group2" id="radio7">
+        <input type="radio" name="group2" id="radio8">
+        <input type="radio" name="group2" id="radio9">
+        <input type="radio" name="group2" id="radio10">
+    </div>
+</body>
+<script>
+
+description('Verify that we do not invalidate more than needed to satisfy :indeterminate');
+let allInputs = document.querySelectorAll("input");
+
+function elementsNeedingStyleRecalc() {
+    let elementsRequiringNeedStyleRecalc = []
+    for (let inputElement of allInputs) {
+        let needsStyleRecalc = window.internals.nodeNeedsStyleRecalc(inputElement);
+        if (needsStyleRecalc)
+            elementsRequiringNeedStyleRecalc.push(inputElement.id);
+    }
+    return elementsRequiringNeedStyleRecalc;
+}
+
+function elementsWithIndeterminateStyle() {
+    let elements = [];
+    for (let inputElement of allInputs) {
+        let backgroundColor = getComputedStyle(inputElement).backgroundColor;
+        if (backgroundColor === "rgb(4, 5, 6)")
+            elements.push(inputElement.id);
+    }
+    return elements;
+}
+
+function checkedElements() {
+    let elements = [];
+    for (let inputElement of allInputs) {
+        if (inputElement.checked)
+            elements.push(inputElement.id);
+    }
+    return elements;
+}
+
+// Force a layout to ensure we don't have dirty styles.
+var offsetTop = document.documentElement.offsetTop;
+
+// Initial state.
+shouldBe("elementsNeedingStyleRecalc()", '[]');
+shouldBe("elementsWithIndeterminateStyle()", '["radio1", "radio2", "radio3", "radio4", "radio5", "radio6", "radio7", "radio8", "radio9", "radio10"]');
+shouldBe("checkedElements()", '[]');
+
+// Check radio3. All the group1 require style recalc.
+debug("Check radio3");
+document.getElementById("radio3").checked = true;
+shouldBe("elementsNeedingStyleRecalc()", '["radio1", "radio2", "radio3", "radio4", "radio5"]');
+shouldBe("elementsWithIndeterminateStyle()", '["radio6", "radio7", "radio8", "radio9", "radio10"]');
+shouldBe("checkedElements()", '["radio3"]');
+
+// Check radio8. All the group1 require style recalc.
+debug("Check radio8");
+document.getElementById("radio8").checked = true;
+shouldBe("elementsNeedingStyleRecalc()", '["radio6", "radio7", "radio8", "radio9", "radio10"]');
+shouldBe("elementsWithIndeterminateStyle()", '[]');
+shouldBe("checkedElements()", '["radio3", "radio8"]');
+
+// Checking radio4, we should not need to invalidate anything but the two modified elements.
+debug("Check radio4");
+document.getElementById("radio4").checked = true;
+shouldBe("elementsNeedingStyleRecalc()", '["radio3", "radio4"]');
+shouldBe("elementsWithIndeterminateStyle()", '[]');
+shouldBe("checkedElements()", '["radio4", "radio8"]');
+
+// Checking radio9, we should not need to invalidate anything but the two modified elements.
+debug("Check radio9");
+document.getElementById("radio9").checked = true;
+shouldBe("elementsNeedingStyleRecalc()", '["radio8", "radio9"]');
+shouldBe("elementsWithIndeterminateStyle()", '[]');
+shouldBe("checkedElements()", '["radio4", "radio9"]');
+
+// Hide the elements to make the results prettier.
+document.getElementById("with-renderer").style.display = "none";
+</script>
+<script src=""
+</html>

Modified: trunk/LayoutTests/fast/forms/radio/indeterminate-radio.html (202196 => 202197)


--- trunk/LayoutTests/fast/forms/radio/indeterminate-radio.html	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/LayoutTests/fast/forms/radio/indeterminate-radio.html	2016-06-18 05:53:28 UTC (rev 202197)
@@ -27,9 +27,6 @@
     {
         try
         {
-
-        document.getElementsByTagName("input")[0].indeterminate = true;
-
         function ArrayContains(array, value, ci)
         {
             ci = ci == true ? true : false;
@@ -46,11 +43,15 @@
             }
             return false;
         }
+
         var target = document.getElementById("test");
         var val = getComputedStyle(target, null).getPropertyValue("color");
-        var aExpectedValues = new Array("green", "#008000", "rgb(0, 128, 0)");
+        var aExpectedValues = new Array("red", "#FF0000", "rgb(255, 0, 0)");
+        let wasIndeterminate = ArrayContains(aExpectedValues, val, true);
 
-        if (ArrayContains(aExpectedValues, val, true))
+        document.getElementsByTagName("input")[0].indeterminate = true;
+
+        if (wasIndeterminate && ArrayContains(aExpectedValues, val, true))
         {
 
           document.getElementById("testresult").innerHTML = "Pass";
@@ -66,4 +67,4 @@
 
 
 </body>
-</html>
\ No newline at end of file
+</html>

Added: trunk/LayoutTests/fast/selectors/detached-radio-button-checked-and-indeterminate-states-expected.txt (0 => 202197)


--- trunk/LayoutTests/fast/selectors/detached-radio-button-checked-and-indeterminate-states-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/detached-radio-button-checked-and-indeterminate-states-expected.txt	2016-06-18 05:53:28 UTC (rev 202197)
@@ -0,0 +1,148 @@
+Verify :indeterminate, :checked and the indeterminate property on radio button detached from the document.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Initial state
+PASS document.getElementById('radio1-in-document').indeterminate is false
+PASS document.getElementById('radio2-in-document').indeterminate is false
+PASS document.getElementById('radio3-in-document').indeterminate is false
+PASS document.getElementById('radio4-in-document').indeterminate is false
+PASS document.getElementById('radio1-in-document').checked is false
+PASS document.getElementById('radio2-in-document').checked is true
+PASS document.getElementById('radio3-in-document').checked is false
+PASS document.getElementById('radio4-in-document').checked is false
+PASS document.getElementById('radio1-in-document').matches(':indeterminate') is false
+PASS document.getElementById('radio2-in-document').matches(':indeterminate') is false
+PASS document.getElementById('radio3-in-document').matches(':indeterminate') is true
+PASS document.getElementById('radio4-in-document').matches(':indeterminate') is true
+PASS document.getElementById('radio1-in-document').matches(':checked') is false
+PASS document.getElementById('radio2-in-document').matches(':checked') is true
+PASS document.getElementById('radio3-in-document').matches(':checked') is false
+PASS document.getElementById('radio4-in-document').matches(':checked') is false
+PASS getComputedStyle(document.getElementById('radio1-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById('radio2-in-document')).backgroundColor is "rgb(7, 8, 9)"
+PASS getComputedStyle(document.getElementById('radio3-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById('radio4-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById('radio1-in-document')).color is "rgb(4, 5, 6)"
+PASS getComputedStyle(document.getElementById('radio2-in-document')).color is "rgb(4, 5, 6)"
+PASS getComputedStyle(document.getElementById('radio3-in-document')).color is "rgb(10, 11, 12)"
+PASS getComputedStyle(document.getElementById('radio4-in-document')).color is "rgb(10, 11, 12)"
+Remove radio2-in-document from document, into variable radio2
+PASS document.querySelectorAll('radio2-in-document') is []
+PASS document.getElementById('radio1-in-document').indeterminate is false
+PASS radio2.indeterminate is false
+PASS document.getElementById('radio3-in-document').indeterminate is false
+PASS document.getElementById('radio4-in-document').indeterminate is false
+PASS document.getElementById('radio1-in-document').checked is false
+PASS radio2.checked is true
+PASS document.getElementById('radio3-in-document').checked is false
+PASS document.getElementById('radio4-in-document').checked is false
+PASS document.getElementById('radio1-in-document').matches(':indeterminate') is true
+PASS radio2.matches(':indeterminate') is false
+PASS document.getElementById('radio3-in-document').matches(':indeterminate') is true
+PASS document.getElementById('radio4-in-document').matches(':indeterminate') is true
+PASS document.getElementById('radio1-in-document').matches(':checked') is false
+PASS radio2.matches(':checked') is true
+PASS document.getElementById('radio3-in-document').matches(':checked') is false
+PASS document.getElementById('radio4-in-document').matches(':checked') is false
+PASS getComputedStyle(document.getElementById('radio1-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(radio2).backgroundColor is ""
+PASS getComputedStyle(document.getElementById('radio3-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById('radio4-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById('radio1-in-document')).color is "rgb(10, 11, 12)"
+PASS getComputedStyle(radio2).color is ""
+PASS getComputedStyle(document.getElementById('radio3-in-document')).color is "rgb(10, 11, 12)"
+PASS getComputedStyle(document.getElementById('radio4-in-document')).color is "rgb(10, 11, 12)"
+Remove radio3-in-document from document, into variable radio3
+PASS document.querySelectorAll('radio3-in-document') is []
+PASS document.getElementById('radio1-in-document').indeterminate is false
+PASS radio2.indeterminate is false
+PASS radio3.indeterminate is false
+PASS document.getElementById('radio4-in-document').indeterminate is false
+PASS document.getElementById('radio1-in-document').checked is false
+PASS radio2.checked is true
+PASS radio3.checked is false
+PASS document.getElementById('radio4-in-document').checked is false
+PASS document.getElementById('radio1-in-document').matches(':indeterminate') is true
+PASS radio2.matches(':indeterminate') is false
+PASS radio3.matches(':indeterminate') is true
+PASS document.getElementById('radio4-in-document').matches(':indeterminate') is true
+PASS document.getElementById('radio1-in-document').matches(':checked') is false
+PASS radio2.matches(':checked') is true
+PASS radio3.matches(':checked') is false
+PASS document.getElementById('radio4-in-document').matches(':checked') is false
+PASS getComputedStyle(document.getElementById('radio1-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(radio2).backgroundColor is ""
+PASS getComputedStyle(radio3).backgroundColor is ""
+PASS getComputedStyle(document.getElementById('radio4-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(document.getElementById('radio1-in-document')).color is "rgb(10, 11, 12)"
+PASS getComputedStyle(radio2).color is ""
+PASS getComputedStyle(radio3).color is ""
+PASS getComputedStyle(document.getElementById('radio4-in-document')).color is "rgb(10, 11, 12)"
+Create new element named webkitRadio
+PASS document.getElementById('radio1-in-document').indeterminate is false
+PASS radio2.indeterminate is false
+PASS radio3.indeterminate is false
+PASS document.getElementById('radio4-in-document').indeterminate is false
+PASS webkitRadio.indeterminate is false
+PASS document.getElementById('radio1-in-document').checked is false
+PASS radio2.checked is true
+PASS radio3.checked is false
+PASS document.getElementById('radio4-in-document').checked is false
+PASS webkitRadio.checked is false
+PASS document.getElementById('radio1-in-document').matches(':indeterminate') is true
+PASS radio2.matches(':indeterminate') is false
+PASS radio3.matches(':indeterminate') is true
+PASS document.getElementById('radio4-in-document').matches(':indeterminate') is true
+PASS webkitRadio.matches(':indeterminate') is true
+PASS document.getElementById('radio1-in-document').matches(':checked') is false
+PASS radio2.matches(':checked') is true
+PASS radio3.matches(':checked') is false
+PASS document.getElementById('radio4-in-document').matches(':checked') is false
+PASS webkitRadio.matches(':checked') is false
+PASS getComputedStyle(document.getElementById('radio1-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(radio2).backgroundColor is ""
+PASS getComputedStyle(radio3).backgroundColor is ""
+PASS getComputedStyle(document.getElementById('radio4-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(webkitRadio).backgroundColor is ""
+PASS getComputedStyle(document.getElementById('radio1-in-document')).color is "rgb(10, 11, 12)"
+PASS getComputedStyle(radio2).color is ""
+PASS getComputedStyle(radio3).color is ""
+PASS getComputedStyle(document.getElementById('radio4-in-document')).color is "rgb(10, 11, 12)"
+PASS getComputedStyle(webkitRadio).color is ""
+Check webkitRadio
+PASS document.getElementById('radio1-in-document').indeterminate is false
+PASS radio2.indeterminate is false
+PASS radio3.indeterminate is false
+PASS document.getElementById('radio4-in-document').indeterminate is false
+PASS webkitRadio.indeterminate is false
+PASS document.getElementById('radio1-in-document').checked is false
+PASS radio2.checked is true
+PASS radio3.checked is false
+PASS document.getElementById('radio4-in-document').checked is false
+PASS webkitRadio.checked is true
+PASS document.getElementById('radio1-in-document').matches(':indeterminate') is true
+PASS radio2.matches(':indeterminate') is false
+PASS radio3.matches(':indeterminate') is true
+PASS document.getElementById('radio4-in-document').matches(':indeterminate') is true
+PASS webkitRadio.matches(':indeterminate') is false
+PASS document.getElementById('radio1-in-document').matches(':checked') is false
+PASS radio2.matches(':checked') is true
+PASS radio3.matches(':checked') is false
+PASS document.getElementById('radio4-in-document').matches(':checked') is false
+PASS webkitRadio.matches(':checked') is true
+PASS getComputedStyle(document.getElementById('radio1-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(radio2).backgroundColor is ""
+PASS getComputedStyle(radio3).backgroundColor is ""
+PASS getComputedStyle(document.getElementById('radio4-in-document')).backgroundColor is "rgb(1, 2, 3)"
+PASS getComputedStyle(webkitRadio).backgroundColor is ""
+PASS getComputedStyle(document.getElementById('radio1-in-document')).color is "rgb(10, 11, 12)"
+PASS getComputedStyle(radio2).color is ""
+PASS getComputedStyle(radio3).color is ""
+PASS getComputedStyle(document.getElementById('radio4-in-document')).color is "rgb(10, 11, 12)"
+PASS getComputedStyle(webkitRadio).color is ""
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/selectors/detached-radio-button-checked-and-indeterminate-states.html (0 => 202197)


--- trunk/LayoutTests/fast/selectors/detached-radio-button-checked-and-indeterminate-states.html	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/detached-radio-button-checked-and-indeterminate-states.html	2016-06-18 05:53:28 UTC (rev 202197)
@@ -0,0 +1,208 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<style>
+    input {
+        background-color: rgb(1, 2, 3);
+        color: rgb(4, 5, 6);
+    }
+    :checked {
+        background-color: rgb(7, 8, 9);
+    }
+    :indeterminate {
+        color: rgb(10, 11, 12);
+    }
+</style>
+</head>
+<body>
+    <div id="testcases">
+        <input type="radio" name="group1" id="radio1-in-document">
+        <input type="radio" name="group1" id="radio2-in-document" checked>
+        <input type="radio" name="group2" id="radio3-in-document">
+        <input type="radio" name="group2" id="radio4-in-document">
+    </div>
+</body>
+<script>
+description('Verify :indeterminate, :checked and the indeterminate property on radio button detached from the document.');
+
+debug("Initial state");
+shouldBeFalse("document.getElementById('radio1-in-document').indeterminate");
+shouldBeFalse("document.getElementById('radio2-in-document').indeterminate");
+shouldBeFalse("document.getElementById('radio3-in-document').indeterminate");
+shouldBeFalse("document.getElementById('radio4-in-document').indeterminate");
+
+shouldBeFalse("document.getElementById('radio1-in-document').checked");
+shouldBeTrue("document.getElementById('radio2-in-document').checked");
+shouldBeFalse("document.getElementById('radio3-in-document').checked");
+shouldBeFalse("document.getElementById('radio4-in-document').checked");
+
+shouldBeFalse("document.getElementById('radio1-in-document').matches(':indeterminate')");
+shouldBeFalse("document.getElementById('radio2-in-document').matches(':indeterminate')");
+shouldBeTrue("document.getElementById('radio3-in-document').matches(':indeterminate')");
+shouldBeTrue("document.getElementById('radio4-in-document').matches(':indeterminate')");
+
+shouldBeFalse("document.getElementById('radio1-in-document').matches(':checked')");
+shouldBeTrue("document.getElementById('radio2-in-document').matches(':checked')");
+shouldBeFalse("document.getElementById('radio3-in-document').matches(':checked')");
+shouldBeFalse("document.getElementById('radio4-in-document').matches(':checked')");
+
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio1-in-document')).backgroundColor", "rgb(1, 2, 3)");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio2-in-document')).backgroundColor", "rgb(7, 8, 9)");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio3-in-document')).backgroundColor", "rgb(1, 2, 3)");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio4-in-document')).backgroundColor", "rgb(1, 2, 3)");
+
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio1-in-document')).color", "rgb(4, 5, 6)");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio2-in-document')).color", "rgb(4, 5, 6)");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio3-in-document')).color", "rgb(10, 11, 12)");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio4-in-document')).color", "rgb(10, 11, 12)");
+
+debug("Remove radio2-in-document from document, into variable radio2");
+let radio2 = document.getElementById('radio2-in-document');
+radio2.parentElement.removeChild(radio2);
+shouldBe("document.querySelectorAll('radio2-in-document')", "[]");
+shouldBeFalse("document.getElementById('radio1-in-document').indeterminate");
+shouldBeFalse("radio2.indeterminate");
+shouldBeFalse("document.getElementById('radio3-in-document').indeterminate");
+shouldBeFalse("document.getElementById('radio4-in-document').indeterminate");
+
+shouldBeFalse("document.getElementById('radio1-in-document').checked");
+shouldBeTrue("radio2.checked");
+shouldBeFalse("document.getElementById('radio3-in-document').checked");
+shouldBeFalse("document.getElementById('radio4-in-document').checked");
+
+shouldBeTrue("document.getElementById('radio1-in-document').matches(':indeterminate')");
+shouldBeFalse("radio2.matches(':indeterminate')");
+shouldBeTrue("document.getElementById('radio3-in-document').matches(':indeterminate')");
+shouldBeTrue("document.getElementById('radio4-in-document').matches(':indeterminate')");
+
+shouldBeFalse("document.getElementById('radio1-in-document').matches(':checked')");
+shouldBeTrue("radio2.matches(':checked')");
+shouldBeFalse("document.getElementById('radio3-in-document').matches(':checked')");
+shouldBeFalse("document.getElementById('radio4-in-document').matches(':checked')");
+
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio1-in-document')).backgroundColor", "rgb(1, 2, 3)");
+shouldBeEqualToString("getComputedStyle(radio2).backgroundColor", "");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio3-in-document')).backgroundColor", "rgb(1, 2, 3)");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio4-in-document')).backgroundColor", "rgb(1, 2, 3)");
+
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio1-in-document')).color", "rgb(10, 11, 12)");
+shouldBeEqualToString("getComputedStyle(radio2).color", "");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio3-in-document')).color", "rgb(10, 11, 12)");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio4-in-document')).color", "rgb(10, 11, 12)");
+
+debug("Remove radio3-in-document from document, into variable radio3");
+let radio3 = document.getElementById('radio3-in-document');
+radio3.parentElement.removeChild(radio3);
+shouldBe("document.querySelectorAll('radio3-in-document')", "[]");
+shouldBeFalse("document.getElementById('radio1-in-document').indeterminate");
+shouldBeFalse("radio2.indeterminate");
+shouldBeFalse("radio3.indeterminate");
+shouldBeFalse("document.getElementById('radio4-in-document').indeterminate");
+
+shouldBeFalse("document.getElementById('radio1-in-document').checked");
+shouldBeTrue("radio2.checked");
+shouldBeFalse("radio3.checked");
+shouldBeFalse("document.getElementById('radio4-in-document').checked");
+
+shouldBeTrue("document.getElementById('radio1-in-document').matches(':indeterminate')");
+shouldBeFalse("radio2.matches(':indeterminate')");
+shouldBeTrue("radio3.matches(':indeterminate')");
+shouldBeTrue("document.getElementById('radio4-in-document').matches(':indeterminate')");
+
+shouldBeFalse("document.getElementById('radio1-in-document').matches(':checked')");
+shouldBeTrue("radio2.matches(':checked')");
+shouldBeFalse("radio3.matches(':checked')");
+shouldBeFalse("document.getElementById('radio4-in-document').matches(':checked')");
+
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio1-in-document')).backgroundColor", "rgb(1, 2, 3)");
+shouldBeEqualToString("getComputedStyle(radio2).backgroundColor", "");
+shouldBeEqualToString("getComputedStyle(radio3).backgroundColor", "");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio4-in-document')).backgroundColor", "rgb(1, 2, 3)");
+
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio1-in-document')).color", "rgb(10, 11, 12)");
+shouldBeEqualToString("getComputedStyle(radio2).color", "");
+shouldBeEqualToString("getComputedStyle(radio3).color", "");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio4-in-document')).color", "rgb(10, 11, 12)");
+
+debug("Create new element named webkitRadio");
+let webkitRadio = document.createElement("input");
+webkitRadio.type = "radio";
+shouldBeFalse("document.getElementById('radio1-in-document').indeterminate");
+shouldBeFalse("radio2.indeterminate");
+shouldBeFalse("radio3.indeterminate");
+shouldBeFalse("document.getElementById('radio4-in-document').indeterminate");
+shouldBeFalse("webkitRadio.indeterminate");
+
+shouldBeFalse("document.getElementById('radio1-in-document').checked");
+shouldBeTrue("radio2.checked");
+shouldBeFalse("radio3.checked");
+shouldBeFalse("document.getElementById('radio4-in-document').checked");
+shouldBeFalse("webkitRadio.checked");
+
+shouldBeTrue("document.getElementById('radio1-in-document').matches(':indeterminate')");
+shouldBeFalse("radio2.matches(':indeterminate')");
+shouldBeTrue("radio3.matches(':indeterminate')");
+shouldBeTrue("document.getElementById('radio4-in-document').matches(':indeterminate')");
+shouldBeTrue("webkitRadio.matches(':indeterminate')");
+
+shouldBeFalse("document.getElementById('radio1-in-document').matches(':checked')");
+shouldBeTrue("radio2.matches(':checked')");
+shouldBeFalse("radio3.matches(':checked')");
+shouldBeFalse("document.getElementById('radio4-in-document').matches(':checked')");
+shouldBeFalse("webkitRadio.matches(':checked')");
+
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio1-in-document')).backgroundColor", "rgb(1, 2, 3)");
+shouldBeEqualToString("getComputedStyle(radio2).backgroundColor", "");
+shouldBeEqualToString("getComputedStyle(radio3).backgroundColor", "");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio4-in-document')).backgroundColor", "rgb(1, 2, 3)");
+shouldBeEqualToString("getComputedStyle(webkitRadio).backgroundColor", "");
+
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio1-in-document')).color", "rgb(10, 11, 12)");
+shouldBeEqualToString("getComputedStyle(radio2).color", "");
+shouldBeEqualToString("getComputedStyle(radio3).color", "");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio4-in-document')).color", "rgb(10, 11, 12)");
+shouldBeEqualToString("getComputedStyle(webkitRadio).color", "");
+
+debug("Check webkitRadio");
+webkitRadio.checked = true;
+shouldBeFalse("document.getElementById('radio1-in-document').indeterminate");
+shouldBeFalse("radio2.indeterminate");
+shouldBeFalse("radio3.indeterminate");
+shouldBeFalse("document.getElementById('radio4-in-document').indeterminate");
+shouldBeFalse("webkitRadio.indeterminate");
+
+shouldBeFalse("document.getElementById('radio1-in-document').checked");
+shouldBeTrue("radio2.checked");
+shouldBeFalse("radio3.checked");
+shouldBeFalse("document.getElementById('radio4-in-document').checked");
+shouldBeTrue("webkitRadio.checked");
+
+shouldBeTrue("document.getElementById('radio1-in-document').matches(':indeterminate')");
+shouldBeFalse("radio2.matches(':indeterminate')");
+shouldBeTrue("radio3.matches(':indeterminate')");
+shouldBeTrue("document.getElementById('radio4-in-document').matches(':indeterminate')");
+shouldBeFalse("webkitRadio.matches(':indeterminate')");
+
+shouldBeFalse("document.getElementById('radio1-in-document').matches(':checked')");
+shouldBeTrue("radio2.matches(':checked')");
+shouldBeFalse("radio3.matches(':checked')");
+shouldBeFalse("document.getElementById('radio4-in-document').matches(':checked')");
+shouldBeTrue("webkitRadio.matches(':checked')");
+
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio1-in-document')).backgroundColor", "rgb(1, 2, 3)");
+shouldBeEqualToString("getComputedStyle(radio2).backgroundColor", "");
+shouldBeEqualToString("getComputedStyle(radio3).backgroundColor", "");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio4-in-document')).backgroundColor", "rgb(1, 2, 3)");
+shouldBeEqualToString("getComputedStyle(webkitRadio).backgroundColor", "");
+
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio1-in-document')).color", "rgb(10, 11, 12)");
+shouldBeEqualToString("getComputedStyle(radio2).color", "");
+shouldBeEqualToString("getComputedStyle(radio3).color", "");
+shouldBeEqualToString("getComputedStyle(document.getElementById('radio4-in-document')).color", "rgb(10, 11, 12)");
+shouldBeEqualToString("getComputedStyle(webkitRadio).color", "");
+
+document.getElementById("testcases").style.display = "none";
+</script>
+<script src=""
+</html>

Added: trunk/LayoutTests/fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update-expected.txt (0 => 202197)


--- trunk/LayoutTests/fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update-expected.txt	2016-06-18 05:53:28 UTC (rev 202197)
@@ -0,0 +1,59 @@
+Verify we invalidate radio button groups to match :indeterminate when a button is checked/unchecked
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS elementsWithIndeterminateStyle() is ["radio1", "radio2", "radio3", "radio4", "radio5", "radio6", "radio7", "radio8", "radio9", "radio10"]
+PASS checkedElements() is []
+Check radio3
+PASS elementsWithIndeterminateStyle() is ["radio6", "radio7", "radio8", "radio9", "radio10"]
+PASS checkedElements() is ["radio3"]
+Check radio8
+PASS elementsWithIndeterminateStyle() is []
+PASS checkedElements() is ["radio3", "radio8"]
+Check radio4
+PASS elementsWithIndeterminateStyle() is []
+PASS checkedElements() is ["radio4", "radio8"]
+Check radio9
+PASS elementsWithIndeterminateStyle() is []
+PASS checkedElements() is ["radio4", "radio9"]
+Uncheck radio4
+PASS elementsWithIndeterminateStyle() is ["radio1", "radio2", "radio3", "radio4", "radio5"]
+PASS checkedElements() is ["radio9"]
+Uncheck radio9
+PASS elementsWithIndeterminateStyle() is ["radio1", "radio2", "radio3", "radio4", "radio5", "radio6", "radio7", "radio8", "radio9", "radio10"]
+PASS checkedElements() is []
+Check radio1
+PASS elementsWithIndeterminateStyle() is ["radio6", "radio7", "radio8", "radio9", "radio10"]
+PASS checkedElements() is ["radio1"]
+Check radio2
+PASS elementsWithIndeterminateStyle() is ["radio6", "radio7", "radio8", "radio9", "radio10"]
+PASS checkedElements() is ["radio2"]
+Remove radio3 from its group
+PASS elementsWithIndeterminateStyle() is ["radio3", "radio6", "radio7", "radio8", "radio9", "radio10"]
+PASS checkedElements() is ["radio2"]
+Remove radio6 from its group
+PASS elementsWithIndeterminateStyle() is ["radio3", "radio6", "radio7", "radio8", "radio9", "radio10"]
+PASS checkedElements() is ["radio2"]
+Remove radio2 from its group
+PASS elementsWithIndeterminateStyle() is ["radio1", "radio3", "radio4", "radio5", "radio6", "radio7", "radio8", "radio9", "radio10"]
+PASS checkedElements() is ["radio2"]
+Check radio7
+PASS elementsWithIndeterminateStyle() is ["radio1", "radio3", "radio4", "radio5", "radio6"]
+PASS checkedElements() is ["radio2", "radio7"]
+Check radio8
+PASS elementsWithIndeterminateStyle() is ["radio1", "radio3", "radio4", "radio5", "radio6"]
+PASS checkedElements() is ["radio2", "radio8"]
+Remove radio9 from its group
+PASS elementsWithIndeterminateStyle() is ["radio1", "radio3", "radio4", "radio5", "radio6", "radio9"]
+PASS checkedElements() is ["radio2", "radio8"]
+Remove radio8 from its group
+PASS elementsWithIndeterminateStyle() is ["radio1", "radio3", "radio4", "radio5", "radio6", "radio7", "radio9", "radio10"]
+PASS checkedElements() is ["radio2", "radio8"]
+Remove radio7 from its group
+PASS elementsWithIndeterminateStyle() is ["radio1", "radio3", "radio4", "radio5", "radio6", "radio7", "radio9", "radio10"]
+PASS checkedElements() is ["radio2", "radio8"]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update.html (0 => 202197)


--- trunk/LayoutTests/fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update.html	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update.html	2016-06-18 05:53:28 UTC (rev 202197)
@@ -0,0 +1,148 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<style>
+    input {
+        background-color: rgb(1, 2, 3);
+    }
+    :indeterminate {
+        background-color: rgb(4, 5, 6);
+    }
+</style>
+</head>
+<body>
+    <div id="with-renderer">
+        <!-- With renderer -->
+        <input type="radio" name="group1" id="radio1">
+        <input type="radio" name="group1" id="radio2">
+        <input type="radio" name="group1" id="radio3">
+        <span>
+            <input type="radio" name="group1" id="radio4">
+            <input type="radio" name="group1" id="radio5">
+        </span>
+    </div>
+    <div style="display:none;">
+        <!-- Without renderer -->
+        <input type="radio" name="group2" id="radio6">
+        <span>
+            <input type="radio" name="group2" id="radio7">
+            <input type="radio" name="group2" id="radio8">
+        </span>
+        <input type="radio" name="group2" id="radio9">
+        <input type="radio" name="group2" id="radio10">
+    </div>
+</body>
+<script>
+
+description('Verify we invalidate radio button groups to match :indeterminate when a button is checked/unchecked');
+let allInputs = document.querySelectorAll("input");
+
+function elementsWithIndeterminateStyle() {
+    let elements = [];
+    for (let inputElement of allInputs) {
+        let backgroundColor = getComputedStyle(inputElement).backgroundColor;
+        if (backgroundColor === "rgb(4, 5, 6)")
+            elements.push(inputElement.id);
+    }
+    return elements;
+}
+
+function checkedElements() {
+    let elements = [];
+    for (let inputElement of allInputs) {
+        if (inputElement.checked)
+            elements.push(inputElement.id);
+    }
+    return elements;
+}
+
+shouldBe("elementsWithIndeterminateStyle()", '["radio1", "radio2", "radio3", "radio4", "radio5", "radio6", "radio7", "radio8", "radio9", "radio10"]');
+shouldBe("checkedElements()", '[]');
+
+debug("Check radio3");
+document.getElementById("radio3").checked = true;
+shouldBe("elementsWithIndeterminateStyle()", '["radio6", "radio7", "radio8", "radio9", "radio10"]');
+shouldBe("checkedElements()", '["radio3"]');
+
+debug("Check radio8");
+document.getElementById("radio8").checked = true;
+shouldBe("elementsWithIndeterminateStyle()", '[]');
+shouldBe("checkedElements()", '["radio3", "radio8"]');
+
+debug("Check radio4");
+document.getElementById("radio4").checked = true;
+shouldBe("elementsWithIndeterminateStyle()", '[]');
+shouldBe("checkedElements()", '["radio4", "radio8"]');
+
+debug("Check radio9");
+document.getElementById("radio9").checked = true;
+shouldBe("elementsWithIndeterminateStyle()", '[]');
+shouldBe("checkedElements()", '["radio4", "radio9"]');
+
+debug("Uncheck radio4");
+document.getElementById("radio4").checked = false;
+shouldBe("elementsWithIndeterminateStyle()", '["radio1", "radio2", "radio3", "radio4", "radio5"]');
+shouldBe("checkedElements()", '["radio9"]');
+
+debug("Uncheck radio9");
+document.getElementById("radio9").checked = false;
+shouldBe("elementsWithIndeterminateStyle()", '["radio1", "radio2", "radio3", "radio4", "radio5", "radio6", "radio7", "radio8", "radio9", "radio10"]');
+shouldBe("checkedElements()", '[]');
+
+debug("Check radio1");
+document.getElementById("radio1").checked = true;
+shouldBe("elementsWithIndeterminateStyle()", '["radio6", "radio7", "radio8", "radio9", "radio10"]');
+shouldBe("checkedElements()", '["radio1"]');
+
+debug("Check radio2");
+document.getElementById("radio2").checked = true;
+shouldBe("elementsWithIndeterminateStyle()", '["radio6", "radio7", "radio8", "radio9", "radio10"]');
+shouldBe("checkedElements()", '["radio2"]');
+
+debug("Remove radio3 from its group");
+document.getElementById("radio3").name = "";
+shouldBe("elementsWithIndeterminateStyle()", '["radio3", "radio6", "radio7", "radio8", "radio9", "radio10"]');
+shouldBe("checkedElements()", '["radio2"]');
+
+debug("Remove radio6 from its group");
+document.getElementById("radio6").name = "";
+shouldBe("elementsWithIndeterminateStyle()", '["radio3", "radio6", "radio7", "radio8", "radio9", "radio10"]');
+shouldBe("checkedElements()", '["radio2"]');
+
+debug("Remove radio2 from its group");
+document.getElementById("radio2").name = "";
+shouldBe("elementsWithIndeterminateStyle()", '["radio1", "radio3", "radio4", "radio5", "radio6", "radio7", "radio8", "radio9", "radio10"]');
+shouldBe("checkedElements()", '["radio2"]');
+
+debug("Check radio7");
+document.getElementById("radio7").checked = true;
+shouldBe("elementsWithIndeterminateStyle()", '["radio1", "radio3", "radio4", "radio5", "radio6"]');
+shouldBe("checkedElements()", '["radio2", "radio7"]');
+
+debug("Check radio8");
+document.getElementById("radio8").checked = true;
+shouldBe("elementsWithIndeterminateStyle()", '["radio1", "radio3", "radio4", "radio5", "radio6"]');
+shouldBe("checkedElements()", '["radio2", "radio8"]');
+
+debug("Remove radio9 from its group");
+document.getElementById("radio9").name = "";
+shouldBe("elementsWithIndeterminateStyle()", '["radio1", "radio3", "radio4", "radio5", "radio6", "radio9"]');
+shouldBe("checkedElements()", '["radio2", "radio8"]');
+
+debug("Remove radio8 from its group");
+document.getElementById("radio8").name = "";
+shouldBe("elementsWithIndeterminateStyle()", '["radio1", "radio3", "radio4", "radio5", "radio6", "radio7", "radio9", "radio10"]');
+shouldBe("checkedElements()", '["radio2", "radio8"]');
+
+debug("Remove radio7 from its group");
+document.getElementById("radio7").name = "";
+shouldBe("elementsWithIndeterminateStyle()", '["radio1", "radio3", "radio4", "radio5", "radio6", "radio7", "radio9", "radio10"]');
+shouldBe("checkedElements()", '["radio2", "radio8"]');
+
+
+// Hide the elements to make the results prettier.
+document.getElementById("with-renderer").style.display = "none";
+</script>
+<script src=""
+</html>

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (202196 => 202197)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2016-06-18 05:53:28 UTC (rev 202197)
@@ -1,3 +1,13 @@
+2016-06-17  Benjamin Poulain  <benja...@webkit.org>
+
+        :indeterminate pseudo-class should match radios whose group has no checked radio
+        https://bugs.webkit.org/show_bug.cgi?id=156270
+
+        Reviewed by Simon Fraser.
+
+        * web-platform-tests/html/semantics/selectors/pseudo-classes/indeterminate-expected.txt:
+        One more pass on official tests :)
+
 2016-06-17  Youenn Fablet  <youenn.fab...@crf.canon.fr>
 
         CORS preflight with a non-200 response should be a preflight failure

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/semantics/selectors/pseudo-classes/indeterminate-expected.txt (202196 => 202197)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/semantics/selectors/pseudo-classes/indeterminate-expected.txt	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/semantics/selectors/pseudo-classes/indeterminate-expected.txt	2016-06-18 05:53:28 UTC (rev 202197)
@@ -1,7 +1,7 @@
         
 
-FAIL ':progress' matches <input>s radio buttons whose radio button group contains no checked input and <progress> elements without value attribute assert_array_equals: lengths differ, expected 5 got 1
-FAIL dynamically check a radio input in a radio button group assert_array_equals: lengths differ, expected 3 got 1
+PASS ':progress' matches <input>s radio buttons whose radio button group contains no checked input and <progress> elements without value attribute 
+PASS dynamically check a radio input in a radio button group 
 FAIL click on radio4 which is in the indeterminate state assert_array_equals: lengths differ, expected 2 got 1
 PASS adding a value to progress1 should put it in a determinate state 
 PASS removing progress2's value should put it in an indeterminate state 

Modified: trunk/Source/WebCore/ChangeLog (202196 => 202197)


--- trunk/Source/WebCore/ChangeLog	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/ChangeLog	2016-06-18 05:53:28 UTC (rev 202197)
@@ -1,3 +1,79 @@
+2016-06-17  Benjamin Poulain  <benja...@webkit.org>
+
+        :indeterminate pseudo-class should match radios whose group has no checked radio
+        https://bugs.webkit.org/show_bug.cgi?id=156270
+
+        Reviewed by Simon Fraser.
+
+        The pseudo-class ":indeterminate" is supposed to match radio buttons
+        for which the entire group has no checked button.
+        Spec: https://html.spec.whatwg.org/#pseudo-classes:selector-indeterminate
+
+        The change is straightforward with one non-obvious choice:
+        I added matchesIndeterminatePseudoClass() in addition to shouldAppearIndeterminate().
+
+        The reason is shouldAppearIndeterminate() is used for styling and AX of elements
+        with an indeterminate states (check boxes and progress element). There is no such
+        UI for radio boxes.
+        I could have extended shouldAppearIndeterminate() to radio box
+        then filter out this case in RenderTheme. The problem is doing that would also requires
+        changes to the repaint logic to match :indeterminate. It seemed overkill to me to
+        change repaint() for a case that is never used in practice.
+
+        Tests: fast/css/pseudo-indeterminate-radio-buttons-basics.html
+               fast/css/pseudo-indeterminate-with-radio-buttons-style-invalidation.html
+               fast/selectors/detached-radio-button-checked-and-indeterminate-states.html
+               fast/selectors/pseudo-indeterminate-with-radio-buttons-style-update.html
+
+        * css/SelectorCheckerTestFunctions.h:
+        (WebCore::shouldAppearIndeterminate):
+        * dom/Element.cpp:
+        (WebCore::Element::matchesIndeterminatePseudoClass):
+        * dom/Element.h:
+        * dom/RadioButtonGroups.cpp:
+        (WebCore::RadioButtonGroup::setCheckedButton):
+        (WebCore::RadioButtonGroup::updateCheckedState):
+        (WebCore::RadioButtonGroup::remove):
+        (WebCore::RadioButtonGroup::setNeedsStyleRecalcForAllButtons):
+        (WebCore::RadioButtonGroups::hasCheckedButton):
+        * dom/RadioButtonGroups.h:
+        * html/CheckboxInputType.cpp:
+        (WebCore::CheckboxInputType::matchesIndeterminatePseudoClass):
+        (WebCore::CheckboxInputType::shouldAppearIndeterminate):
+        (WebCore::CheckboxInputType::supportsIndeterminateAppearance): Deleted.
+        * html/CheckboxInputType.h:
+        * html/HTMLInputElement.cpp:
+        (WebCore::HTMLInputElement::setChecked):
+        (WebCore::HTMLInputElement::matchesIndeterminatePseudoClass):
+        (WebCore::HTMLInputElement::shouldAppearIndeterminate):
+        (WebCore::HTMLInputElement::radioButtonGroups):
+        * html/HTMLInputElement.h:
+        * html/InputType.cpp:
+        (WebCore::InputType::matchesIndeterminatePseudoClass):
+        (WebCore::InputType::shouldAppearIndeterminate):
+        (WebCore::InputType::supportsIndeterminateAppearance): Deleted.
+        * html/InputType.h:
+        * html/RadioInputType.cpp:
+        (WebCore::RadioInputType::matchesIndeterminatePseudoClass):
+        (WebCore::RadioInputType::willDispatchClick): Deleted.
+        (WebCore::RadioInputType::didDispatchClick): Deleted.
+        (WebCore::RadioInputType::supportsIndeterminateAppearance): Deleted.
+        The iOS specific code is just plain wrong.
+        It was changing the indeterminate state of the input element.
+        The spec clearly says that state is only used by checkbox:
+        https://html.spec.whatwg.org/#dom-input-indeterminate
+
+        Moreover, the style update would not change the indeterminate state
+        of other buttons in the Button Group, which is just bizarre.
+        RenderThemeIOS does not make use of any of this with the current style.
+
+        * html/RadioInputType.h:
+        * style/StyleSharingResolver.cpp:
+        (WebCore::Style::SharingResolver::canShareStyleWithElement):
+        (WebCore::Style::canShareStyleWithControl): Deleted.
+        (WebCore::Style::SharingResolver::sharingCandidateHasIdenticalStyleAffectingAttributes): Deleted.
+        Style sharing is unified behind the selector matching which is neat.
+
 2016-06-17  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, rolling out r202152.

Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (202196 => 202197)


--- trunk/Source/WebCore/css/SelectorChecker.cpp	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp	2016-06-18 05:53:28 UTC (rev 202197)
@@ -983,7 +983,7 @@
         case CSSSelector::PseudoClassChecked:
             return isChecked(element);
         case CSSSelector::PseudoClassIndeterminate:
-            return shouldAppearIndeterminate(element);
+            return matchesIndeterminatePseudoClass(element);
         case CSSSelector::PseudoClassRoot:
             if (&element == element.document().documentElement())
                 return true;

Modified: trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h (202196 => 202197)


--- trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h	2016-06-18 05:53:28 UTC (rev 202197)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
  * Copyright (C) 2014 Dhi Aurrahman <diorah...@rockybars.com>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -221,9 +221,9 @@
     return element.matchesReadWritePseudoClass();
 }
 
-ALWAYS_INLINE bool shouldAppearIndeterminate(const Element& element)
+ALWAYS_INLINE bool matchesIndeterminatePseudoClass(const Element& element)
 {
-    return element.shouldAppearIndeterminate();
+    return element.matchesIndeterminatePseudoClass();
 }
 
 ALWAYS_INLINE bool scrollbarMatchesEnabledPseudoClass(const SelectorChecker::CheckingContext& context)

Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.cpp (202196 => 202197)


--- trunk/Source/WebCore/cssjit/SelectorCompiler.cpp	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.cpp	2016-06-18 05:53:28 UTC (rev 202197)
@@ -558,7 +558,7 @@
         fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr(isInRange));
         return FunctionType::SimpleSelectorChecker;
     case CSSSelector::PseudoClassIndeterminate:
-        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr(shouldAppearIndeterminate));
+        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr(matchesIndeterminatePseudoClass));
         return FunctionType::SimpleSelectorChecker;
     case CSSSelector::PseudoClassInvalid:
         fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr(isInvalid));

Modified: trunk/Source/WebCore/dom/Element.cpp (202196 => 202197)


--- trunk/Source/WebCore/dom/Element.cpp	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/dom/Element.cpp	2016-06-18 05:53:28 UTC (rev 202197)
@@ -4,7 +4,7 @@
  *           (C) 2001 Peter Kelly (p...@post.com)
  *           (C) 2001 Dirk Mueller (muel...@kde.org)
  *           (C) 2007 David Smith (catfish....@gmail.com)
- * Copyright (C) 2004-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2016 Apple Inc. All rights reserved.
  *           (C) 2007 Eric Seidel (e...@webkit.org)
  *
  * This library is free software; you can redistribute it and/or
@@ -2755,6 +2755,11 @@
     return false;
 }
 
+bool Element::matchesIndeterminatePseudoClass() const
+{
+    return shouldAppearIndeterminate();
+}
+
 bool Element::matches(const String& selector, ExceptionCode& ec)
 {
     SelectorQuery* selectorQuery = document().selectorQueryForString(selector, ec);

Modified: trunk/Source/WebCore/dom/Element.h (202196 => 202197)


--- trunk/Source/WebCore/dom/Element.h	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/dom/Element.h	2016-06-18 05:53:28 UTC (rev 202197)
@@ -3,7 +3,7 @@
  *           (C) 1999 Antti Koivisto (koivi...@kde.org)
  *           (C) 2001 Peter Kelly (p...@post.com)
  *           (C) 2001 Dirk Mueller (muel...@kde.org)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2016 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -386,6 +386,7 @@
     void didShadowTreeAwareChildrenChange();
 
     virtual bool matchesReadWritePseudoClass() const;
+    virtual bool matchesIndeterminatePseudoClass() const;
     bool matches(const String& selectors, ExceptionCode&);
     Element* closest(const String& selectors, ExceptionCode&);
     virtual bool shouldAppearIndeterminate() const;

Modified: trunk/Source/WebCore/dom/RadioButtonGroups.cpp (202196 => 202197)


--- trunk/Source/WebCore/dom/RadioButtonGroups.cpp	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/dom/RadioButtonGroups.cpp	2016-06-18 05:53:28 UTC (rev 202197)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2016 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -42,8 +42,10 @@
     Vector<HTMLInputElement*> members() const;
 
 private:
+    void setNeedsStyleRecalcForAllButtons();
     void updateValidityForAllButtons();
     bool isValid() const;
+    void changeCheckedButton(HTMLInputElement*);
     void setCheckedButton(HTMLInputElement*);
 
     HashSet<HTMLInputElement*> m_members;
@@ -75,6 +77,12 @@
     HTMLInputElement* oldCheckedButton = m_checkedButton;
     if (oldCheckedButton == button)
         return;
+
+    bool hadCheckedButton = m_checkedButton;
+    bool willHaveCheckedButton = button;
+    if (hadCheckedButton != willHaveCheckedButton)
+        setNeedsStyleRecalcForAllButtons();
+
     m_checkedButton = button;
     if (oldCheckedButton)
         oldCheckedButton->setChecked(false);
@@ -110,7 +118,7 @@
         setCheckedButton(button);
     else {
         if (m_checkedButton == button)
-            m_checkedButton = nullptr;
+            setCheckedButton(nullptr);
     }
     if (wasValid != isValid())
         updateValidityForAllButtons();
@@ -137,14 +145,20 @@
     HashSet<HTMLInputElement*>::iterator it = m_members.find(button);
     if (it == m_members.end())
         return;
+
     bool wasValid = isValid();
     m_members.remove(it);
     if (button->isRequired()) {
         ASSERT(m_requiredCount);
         --m_requiredCount;
     }
-    if (m_checkedButton == button)
-        m_checkedButton = nullptr;
+    if (m_checkedButton) {
+        button->setNeedsStyleRecalc();
+        if (m_checkedButton == button) {
+            m_checkedButton = nullptr;
+            setNeedsStyleRecalcForAllButtons();
+        }
+    }
 
     if (m_members.isEmpty()) {
         ASSERT(!m_requiredCount);
@@ -158,6 +172,14 @@
     }
 }
 
+void RadioButtonGroup::setNeedsStyleRecalcForAllButtons()
+{
+    for (auto& button : m_members) {
+        ASSERT(button->isRadioButton());
+        button->setNeedsStyleRecalc();
+    }
+}
+
 void RadioButtonGroup::updateValidityForAllButtons()
 {
     for (auto& button : m_members) {
@@ -250,6 +272,17 @@
     return group ? group->checkedButton() : nullptr;
 }
 
+bool RadioButtonGroups::hasCheckedButton(const HTMLInputElement* element) const
+{
+    ASSERT(element->isRadioButton());
+    const AtomicString& name = element->name();
+    if (name.isEmpty() || !m_nameToGroupMap)
+        return element->checked();
+
+    const RadioButtonGroup* group = m_nameToGroupMap->get(name.impl());
+    return group->checkedButton();
+}
+
 bool RadioButtonGroups::isInRequiredGroup(HTMLInputElement* element) const
 {
     ASSERT(element->isRadioButton());

Modified: trunk/Source/WebCore/dom/RadioButtonGroups.h (202196 => 202197)


--- trunk/Source/WebCore/dom/RadioButtonGroups.h	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/dom/RadioButtonGroups.h	2016-06-18 05:53:28 UTC (rev 202197)
@@ -39,6 +39,7 @@
     void requiredAttributeChanged(HTMLInputElement*);
     void removeButton(HTMLInputElement*);
     HTMLInputElement* checkedButtonForGroup(const AtomicString& groupName) const;
+    bool hasCheckedButton(const HTMLInputElement*) const;
     bool isInRequiredGroup(HTMLInputElement*) const;
     Vector<HTMLInputElement*> groupMembers(const HTMLInputElement&) const;
 

Modified: trunk/Source/WebCore/html/CheckboxInputType.cpp (202196 => 202197)


--- trunk/Source/WebCore/html/CheckboxInputType.cpp	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/html/CheckboxInputType.cpp	2016-06-18 05:53:28 UTC (rev 202197)
@@ -92,9 +92,14 @@
     return true;
 }
 
-bool CheckboxInputType::supportsIndeterminateAppearance() const
+bool CheckboxInputType::matchesIndeterminatePseudoClass() const
 {
-    return true;
+    return shouldAppearIndeterminate();
 }
 
+bool CheckboxInputType::shouldAppearIndeterminate() const
+{
+    return element().indeterminate();
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/html/CheckboxInputType.h (202196 => 202197)


--- trunk/Source/WebCore/html/CheckboxInputType.h	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/html/CheckboxInputType.h	2016-06-18 05:53:28 UTC (rev 202197)
@@ -47,7 +47,8 @@
     void willDispatchClick(InputElementClickState&) override;
     void didDispatchClick(Event*, const InputElementClickState&) override;
     bool isCheckbox() const override;
-    bool supportsIndeterminateAppearance() const override;
+    bool matchesIndeterminatePseudoClass() const override;
+    bool shouldAppearIndeterminate() const override;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/html/HTMLInputElement.cpp (202196 => 202197)


--- trunk/Source/WebCore/html/HTMLInputElement.cpp	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/html/HTMLInputElement.cpp	2016-06-18 05:53:28 UTC (rev 202197)
@@ -861,7 +861,7 @@
     setNeedsStyleRecalc();
 
     if (RadioButtonGroups* buttons = radioButtonGroups())
-            buttons->updateCheckedState(this);
+        buttons->updateCheckedState(this);
     if (renderer() && renderer()->style().hasAppearance())
         renderer()->theme().stateChanged(*renderer(), ControlStates::CheckedState);
     updateValidity();
@@ -1763,9 +1763,21 @@
     return m_inputType->defaultToolTip();
 }
 
+bool HTMLInputElement::matchesIndeterminatePseudoClass() const
+{
+    // For input elements, matchesIndeterminatePseudoClass()
+    // is not equivalent to shouldAppearIndeterminate() because of radio button.
+    //
+    // A group of radio button without any checked button is indeterminate
+    // for the :indeterminate selector. On the other hand, RenderTheme
+    // currently only supports single element being indeterminate.
+    // Because of this, radio is indetermindate for CSS but not for render theme.
+    return m_inputType->matchesIndeterminatePseudoClass();
+}
+
 bool HTMLInputElement::shouldAppearIndeterminate() const 
 {
-    return m_inputType->supportsIndeterminateAppearance() && indeterminate();
+    return m_inputType->shouldAppearIndeterminate();
 }
 
 #if ENABLE(MEDIA_CAPTURE)
@@ -1801,12 +1813,12 @@
 RadioButtonGroups* HTMLInputElement::radioButtonGroups() const
 {
     if (!isRadioButton())
-        return 0;
+        return nullptr;
     if (HTMLFormElement* formElement = form())
         return &formElement->radioButtonGroups();
     if (inDocument())
         return &document().formController().radioButtonGroups();
-    return 0;
+    return nullptr;
 }
 
 inline void HTMLInputElement::addToRadioButtonGroup()

Modified: trunk/Source/WebCore/html/HTMLInputElement.h (202196 => 202197)


--- trunk/Source/WebCore/html/HTMLInputElement.h	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/html/HTMLInputElement.h	2016-06-18 05:53:28 UTC (rev 202197)
@@ -2,7 +2,7 @@
  * Copyright (C) 1999 Lars Knoll (kn...@kde.org)
  *           (C) 1999 Antti Koivisto (koivi...@kde.org)
  *           (C) 2000 Dirk Mueller (muel...@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2010, 2016 Apple Inc. All rights reserved.
  * Copyright (C) 2012 Samsung Electronics. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
@@ -162,6 +162,7 @@
     void setIndeterminate(bool);
     // shouldAppearChecked is used by the rendering tree/CSS while checked() is used by JS to determine checked state
     bool shouldAppearChecked() const;
+    bool matchesIndeterminatePseudoClass() const final;
     bool shouldAppearIndeterminate() const final;
 
     unsigned size() const;
@@ -274,6 +275,8 @@
     Vector<HTMLInputElement*> radioButtonGroup() const;
     HTMLInputElement* checkedRadioButtonForGroup() const;
     bool isInRequiredRadioButtonGroup();
+    // Returns null if this isn't associated with any radio button group.
+    RadioButtonGroups* radioButtonGroups() const;
 
     // Functions for InputType classes.
     void setValueInternal(const String&, TextFieldEventBehavior);
@@ -422,8 +425,6 @@
     void maxLengthAttributeChanged(const AtomicString& newValue);
     void updateValueIfNeeded();
 
-    // Returns null if this isn't associated with any radio button group.
-    RadioButtonGroups* radioButtonGroups() const;
     void addToRadioButtonGroup();
     void removeFromRadioButtonGroup();
 

Modified: trunk/Source/WebCore/html/InputType.cpp (202196 => 202197)


--- trunk/Source/WebCore/html/InputType.cpp	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/html/InputType.cpp	2016-06-18 05:53:28 UTC (rev 202197)
@@ -966,11 +966,16 @@
 }
 #endif
 
-bool InputType::supportsIndeterminateAppearance() const
+bool InputType::matchesIndeterminatePseudoClass() const
 {
     return false;
 }
 
+bool InputType::shouldAppearIndeterminate() const
+{
+    return false;
+}
+
 bool InputType::supportsSelectionAPI() const
 {
     return false;

Modified: trunk/Source/WebCore/html/InputType.h (202196 => 202197)


--- trunk/Source/WebCore/html/InputType.h	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/html/InputType.h	2016-06-18 05:53:28 UTC (rev 202197)
@@ -267,7 +267,8 @@
     virtual void capsLockStateMayHaveChanged();
     virtual void updateAutoFillButton();
     virtual String defaultToolTip() const;
-    virtual bool supportsIndeterminateAppearance() const;
+    virtual bool matchesIndeterminatePseudoClass() const;
+    virtual bool shouldAppearIndeterminate() const;
     virtual bool supportsSelectionAPI() const;
     virtual Color valueAsColor() const;
     virtual void selectColor(const Color&);

Modified: trunk/Source/WebCore/html/RadioInputType.cpp (202196 => 202197)


--- trunk/Source/WebCore/html/RadioInputType.cpp	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/html/RadioInputType.cpp	2016-06-18 05:53:28 UTC (rev 202197)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2011, 2016 Apple Inc. All rights reserved.
  * Copyright (C) 2010 Google Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
@@ -151,13 +151,6 @@
     state.checked = element().checked();
     state.checkedRadioButton = element().checkedRadioButtonForGroup();
 
-#if PLATFORM(IOS)
-    state.indeterminate = element().indeterminate();
-
-    if (element().indeterminate())
-        element().setIndeterminate(false);
-#endif
-
     element().setChecked(true, DispatchChangeEvent);
 }
 
@@ -173,11 +166,6 @@
                 && checkedRadioButton->name() == element().name()) {
             checkedRadioButton->setChecked(true);
         }
-
-#if PLATFORM(IOS)        
-        element().setIndeterminate(state.indeterminate);
-#endif
-
     }
 
     // The work we did in willDispatchClick was default handling.
@@ -189,13 +177,12 @@
     return true;
 }
 
-bool RadioInputType::supportsIndeterminateAppearance() const
+bool RadioInputType::matchesIndeterminatePseudoClass() const
 {
-#if PLATFORM(IOS)
-    return true;
-#else
-    return false;
-#endif
+    const HTMLInputElement& element = this->element();
+    if (const RadioButtonGroups* radioButtonGroups = element.radioButtonGroups())
+        return !radioButtonGroups->hasCheckedButton(&element);
+    return !element.checked();
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/html/RadioInputType.h (202196 => 202197)


--- trunk/Source/WebCore/html/RadioInputType.h	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/html/RadioInputType.h	2016-06-18 05:53:28 UTC (rev 202197)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -51,7 +52,7 @@
     void willDispatchClick(InputElementClickState&) override;
     void didDispatchClick(Event*, const InputElementClickState&) override;
     bool isRadioButton() const override;
-    bool supportsIndeterminateAppearance() const override;
+    bool matchesIndeterminatePseudoClass() const override;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/style/StyleSharingResolver.cpp (202196 => 202197)


--- trunk/Source/WebCore/style/StyleSharingResolver.cpp	2016-06-18 03:33:19 UTC (rev 202196)
+++ trunk/Source/WebCore/style/StyleSharingResolver.cpp	2016-06-18 05:53:28 UTC (rev 202197)
@@ -179,8 +179,6 @@
         return false;
     if (thisInputElement.shouldAppearChecked() != otherInputElement.shouldAppearChecked())
         return false;
-    if (thisInputElement.shouldAppearIndeterminate() != otherInputElement.shouldAppearIndeterminate())
-        return false;
     if (thisInputElement.isRequired() != otherInputElement.isRequired())
         return false;
 
@@ -283,6 +281,9 @@
     if (element.matchesInvalidPseudoClass() != element.matchesValidPseudoClass())
         return false;
 
+    if (candidateElement.matchesIndeterminatePseudoClass() != element.matchesIndeterminatePseudoClass())
+        return false;
+
     if (element.shadowRoot() && !element.shadowRoot()->styleResolver().ruleSets().authorStyle()->hostPseudoClassRules().isEmpty())
         return false;
 
@@ -329,11 +330,6 @@
     if (const_cast<StyledElement&>(element).presentationAttributeStyle() != const_cast<StyledElement&>(sharingCandidate).presentationAttributeStyle())
         return false;
 
-    if (element.hasTagName(HTMLNames::progressTag)) {
-        if (element.shouldAppearIndeterminate() != sharingCandidate.shouldAppearIndeterminate())
-            return false;
-    }
-
     return true;
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to