Changeset 173229 in webkit


Ignore:
Timestamp:
Sep 3, 2014 2:30:31 PM (10 years ago)
Author:
benjamin@webkit.org
Message:

Fix style invalidation of elements with multiple siblings dependencies
https://bugs.webkit.org/show_bug.cgi?id=136472

Reviewed by Andreas Kling.

Source/WebCore:

Previously, style invalidation of siblings was driven by a pair of flags:
-ChildrenAffectedByDirectAdjacentRules.
-ChildrenAffectedByForwardPositionalRules.

When ChildrenAffectedByDirectAdjacentRules was set, the element after an element
with "needsStyleRecalc" was also recomputed. While this work for pair of elements:

a + b

It does not work for more than that. For example, with

a.propery + b + c

When the state of <a> changes, the style of <b> was updated, which is useless. The style
of <c> was untouched, which is incorrect.

When ChildrenAffectedByForwardPositionalRules, all elements after one with "needsStyleRecalc"
were invalidated. While more correct, it caused avalanche of style recalc and was not a very
useful "optimization".


To fix the correctness issues (e.g. "a + b + c"), I could have gone two ways:
1) Invalidate the parent of a, b, c. The children would always get a correct style

when their parent's style would be resolved.

2) Create invalidation relations to enforce that the right siblings are invalidated.

I have decided for a weak version of (2). The reason is that most DOM trees are very
shallow while being very wide. Invalidating the parent generally causes massive style
recalculation.

To keep things simple for now, there is no explicit dependency list between siblings.
Instead, each element has a pair of flag:
1) The element's style depends on the state of a previous sibling.
2) The element's state affects following siblings.

With the notation "<-" for (1), "->" for (2), the selector "a + b + c" create this kind
of marking:

a + b + c
-> ->

<-

When <a> is invalidated, the style resolver will go through the chain of dependent elements
and invalidate any element that can be affected by a prior invalidation, here <c>.

Overlaps are possible. For example with the two selector, "a + b + c", "b ~ d"
the marking would be

a + b + c + d
-> -> ->

<- <-

A change in <a> would invalidate both <c> and <d>. This is overkill, but the end result
is correct and it is a net improvement over the previous flags.

As usual, the CSS JIT makes an effort at compile time to reduce tree marking. SelectorChecker
marks everything as usual.

Tests: fast/css/direct-adjacent-style-update-optimization.html

fast/css/indirect-adjacent-style-update-optimization.html
fast/css/non-matching-adjacent-style-update.html
fast/selectors/first-of-type-direct-adjacent-style-update.html
fast/selectors/first-of-type-sibling-style-update.html
fast/selectors/id-direct-adjacent-style-update.html
fast/selectors/id-sibling-style-update.html
fast/selectors/nth-child-as-first-simple-selector-style-update.html
fast/selectors/nth-child-direct-adjacent-style-update.html
fast/selectors/nth-child-style-update.html

  • css/SelectorChecker.cpp:

(WebCore::isFirstOfType):
(WebCore::countElementsBefore):
(WebCore::countElementsOfTypeBefore):
Counting selectors are not unlike adjacent combinators, they are handled the exact same way.
For example a :nth-child(4) would generate somewhat similar marking as

:first-child + * + * + *

Everything prior to the element with the counter affects the style of the element.

(WebCore::hasScrollbarPseudoElement):
The assertion was incorrect. You can get an scrollbar pseudo ID on an element without scrollbar.
It will never match, but such case is possible.

(WebCore::SelectorChecker::matchRecursively):
(WebCore::SelectorChecker::checkOne):

  • css/StyleResolver.cpp:

(WebCore::StyleResolver::canShareStyleWithElement):
Previously, any subtree affected by sibling selectors were unshareable. That was done by checking
for Element::hasFlagsSetDuringStylingOfChildren().

Now that sibling relation are local, they no longer prevent sharing of all children. Instead, we can
test locally for subgroup with sibling relations.

  • cssjit/SelectorCompiler.cpp:

(WebCore::SelectorCompiler::isAdjacentRelation):
(WebCore::SelectorCompiler::shouldMarkStyleIsAffectedByPreviousSibling):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateDirectAdjacentTreeWalker):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateIndirectAdjacentTreeWalker):
(WebCore::SelectorCompiler::SelectorCodeGenerator::markElementIfResolvingStyle):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsNthChild):
(WebCore::SelectorCompiler::SelectorCodeGenerator::markParentElementIfResolvingStyle): Deleted.

  • dom/Document.cpp:

(WebCore::nodeOrItsAncestorNeedsStyleRecalc):

  • dom/Element.cpp:

(WebCore::checkForSiblingStyleChanges):
(WebCore::Element::hasFlagsSetDuringStylingOfChildren):
(WebCore::Element::setChildrenAffectedByForwardPositionalRules): Deleted.
(WebCore::Element::rareDataChildrenAffectedByForwardPositionalRules): Deleted.

  • dom/Element.h:

(WebCore::Element::affectsNextSiblingElementStyle):
(WebCore::Element::setAffectsNextSiblingElementStyle):
(WebCore::Element::setStyleIsAffectedByPreviousSibling):
(WebCore::Element::childrenAffectedByPositionalRules): Deleted.
(WebCore::Element::childrenAffectedByDirectAdjacentRules): Deleted.
(WebCore::Element::childrenAffectedByForwardPositionalRules): Deleted.
(WebCore::Element::setChildrenAffectedByDirectAdjacentRules): Deleted.
(WebCore::Element::setChildrenAffectedByForwardPositionalRules): Deleted.

  • dom/ElementRareData.h:

(WebCore::ElementRareData::ElementRareData):
(WebCore::ElementRareData::resetDynamicRestyleObservations):
(WebCore::ElementRareData::childrenAffectedByForwardPositionalRules): Deleted.
(WebCore::ElementRareData::setChildrenAffectedByForwardPositionalRules): Deleted.

  • dom/Node.h:

(WebCore::Node::styleIsAffectedByPreviousSibling):
(WebCore::Node::flagAffectsNextSiblingElementStyle):
(WebCore::Node::flagStyleIsAffectedByPreviousSibling):
(WebCore::Node::flagChildrenAffectedByDirectAdjacentRulesFlag): Deleted.

  • html/HTMLElement.h:

(WebCore::HTMLElement::isHTMLUnknownElement):

  • html/HTMLUnknownElement.h:
  • style/StyleResolveTree.cpp:

(WebCore::Style::resetStyleForNonRenderedDescendants):
(WebCore::Style::resolveTree):

LayoutTests:

The test coverage was pretty bad. :(
I tried to cover the most obvious problems.

  • fast/css/direct-adjacent-style-update-optimization-expected.txt: Added.
  • fast/css/direct-adjacent-style-update-optimization.html: Added.
  • fast/css/indirect-adjacent-style-update-optimization-expected.txt: Added.
  • fast/css/indirect-adjacent-style-update-optimization.html: Added.
  • fast/css/non-matching-adjacent-style-update-expected.txt: Added.
  • fast/css/non-matching-adjacent-style-update.html: Added.
  • fast/selectors/attribute-direct-adjacent-style-update-expected.txt:
  • fast/selectors/class-direct-adjacent-style-update-expected.txt:
  • fast/selectors/first-child-direct-adjacent-style-update-expected.txt:
  • fast/selectors/first-of-type-direct-adjacent-style-update-expected.txt: Copied from LayoutTests/fast/selectors/attribute-direct-adjacent-style-update-expected.txt.
  • fast/selectors/first-of-type-direct-adjacent-style-update.html: Added.
  • fast/selectors/first-of-type-sibling-style-update-expected.txt: Added.
  • fast/selectors/first-of-type-sibling-style-update.html: Added.
  • fast/selectors/id-direct-adjacent-style-update-expected.txt: Copied from LayoutTests/fast/selectors/attribute-direct-adjacent-style-update-expected.txt.
  • fast/selectors/id-direct-adjacent-style-update.html: Added.
  • fast/selectors/id-sibling-style-update-expected.txt: Added.
  • fast/selectors/id-sibling-style-update.html: Added.
  • fast/selectors/nth-child-as-first-simple-selector-style-update-expected.txt: Added.
  • fast/selectors/nth-child-as-first-simple-selector-style-update.html: Added.
  • fast/selectors/nth-child-direct-adjacent-style-update-expected.txt: Copied from LayoutTests/fast/selectors/attribute-direct-adjacent-style-update-expected.txt.
  • fast/selectors/nth-child-direct-adjacent-style-update.html: Added.
  • fast/selectors/nth-child-style-update-expected.txt: Added.
  • fast/selectors/nth-child-style-update.html: Added.
Location:
trunk
Files:
20 added
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r173227 r173229  
     12014-09-03  Benjamin Poulain  <benjamin@webkit.org>
     2
     3        Fix style invalidation of elements with multiple siblings dependencies
     4        https://bugs.webkit.org/show_bug.cgi?id=136472
     5
     6        Reviewed by Andreas Kling.
     7
     8        The test coverage was pretty bad. :(
     9        I tried to cover the most obvious problems.
     10
     11        * fast/css/direct-adjacent-style-update-optimization-expected.txt: Added.
     12        * fast/css/direct-adjacent-style-update-optimization.html: Added.
     13        * fast/css/indirect-adjacent-style-update-optimization-expected.txt: Added.
     14        * fast/css/indirect-adjacent-style-update-optimization.html: Added.
     15        * fast/css/non-matching-adjacent-style-update-expected.txt: Added.
     16        * fast/css/non-matching-adjacent-style-update.html: Added.
     17        * fast/selectors/attribute-direct-adjacent-style-update-expected.txt:
     18        * fast/selectors/class-direct-adjacent-style-update-expected.txt:
     19        * fast/selectors/first-child-direct-adjacent-style-update-expected.txt:
     20        * fast/selectors/first-of-type-direct-adjacent-style-update-expected.txt: Copied from LayoutTests/fast/selectors/attribute-direct-adjacent-style-update-expected.txt.
     21        * fast/selectors/first-of-type-direct-adjacent-style-update.html: Added.
     22        * fast/selectors/first-of-type-sibling-style-update-expected.txt: Added.
     23        * fast/selectors/first-of-type-sibling-style-update.html: Added.
     24        * fast/selectors/id-direct-adjacent-style-update-expected.txt: Copied from LayoutTests/fast/selectors/attribute-direct-adjacent-style-update-expected.txt.
     25        * fast/selectors/id-direct-adjacent-style-update.html: Added.
     26        * fast/selectors/id-sibling-style-update-expected.txt: Added.
     27        * fast/selectors/id-sibling-style-update.html: Added.
     28        * fast/selectors/nth-child-as-first-simple-selector-style-update-expected.txt: Added.
     29        * fast/selectors/nth-child-as-first-simple-selector-style-update.html: Added.
     30        * fast/selectors/nth-child-direct-adjacent-style-update-expected.txt: Copied from LayoutTests/fast/selectors/attribute-direct-adjacent-style-update-expected.txt.
     31        * fast/selectors/nth-child-direct-adjacent-style-update.html: Added.
     32        * fast/selectors/nth-child-style-update-expected.txt: Added.
     33        * fast/selectors/nth-child-style-update.html: Added.
     34
    1352014-09-03  Benjamin Poulain  <benjamin@webkit.org>
    236
  • trunk/LayoutTests/fast/selectors/attribute-direct-adjacent-style-update-expected.txt

    r172880 r173229  
    1414PASS getComputedStyle(document.getElementById("baz-without-renderer")).color is "rgb(0, 0, 0)"
    1515Adding the attribute, the extra rules should match.
    16 FAIL getComputedStyle(document.getElementById("bar-with-renderer")).backgroundColor should be rgb(1, 2, 3). Was rgb(255, 255, 255).
     16PASS getComputedStyle(document.getElementById("bar-with-renderer")).backgroundColor is "rgb(1, 2, 3)"
    1717PASS getComputedStyle(document.getElementById("baz-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
    1818PASS getComputedStyle(document.getElementById("bar-without-renderer")).backgroundColor is "rgb(1, 2, 3)"
    1919PASS getComputedStyle(document.getElementById("baz-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
    2020PASS getComputedStyle(document.getElementById("bar-with-renderer")).color is "rgb(0, 0, 0)"
    21 FAIL getComputedStyle(document.getElementById("baz-with-renderer")).color should be rgb(4, 5, 6). Was rgb(0, 0, 0).
     21PASS getComputedStyle(document.getElementById("baz-with-renderer")).color is "rgb(4, 5, 6)"
    2222PASS getComputedStyle(document.getElementById("bar-without-renderer")).color is "rgb(0, 0, 0)"
    2323PASS getComputedStyle(document.getElementById("baz-without-renderer")).color is "rgb(4, 5, 6)"
    2424Emptying the attribute, the extra rules should still match.
    25 FAIL getComputedStyle(document.getElementById("bar-with-renderer")).backgroundColor should be rgb(1, 2, 3). Was rgb(255, 255, 255).
     25PASS getComputedStyle(document.getElementById("bar-with-renderer")).backgroundColor is "rgb(1, 2, 3)"
    2626PASS getComputedStyle(document.getElementById("baz-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
    2727PASS getComputedStyle(document.getElementById("bar-without-renderer")).backgroundColor is "rgb(1, 2, 3)"
    2828PASS getComputedStyle(document.getElementById("baz-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
    2929PASS getComputedStyle(document.getElementById("bar-with-renderer")).color is "rgb(0, 0, 0)"
    30 FAIL getComputedStyle(document.getElementById("baz-with-renderer")).color should be rgb(4, 5, 6). Was rgb(0, 0, 0).
     30PASS getComputedStyle(document.getElementById("baz-with-renderer")).color is "rgb(4, 5, 6)"
    3131PASS getComputedStyle(document.getElementById("bar-without-renderer")).color is "rgb(0, 0, 0)"
    3232PASS getComputedStyle(document.getElementById("baz-without-renderer")).color is "rgb(4, 5, 6)"
  • trunk/LayoutTests/fast/selectors/class-direct-adjacent-style-update-expected.txt

    r172880 r173229  
    1414PASS getComputedStyle(document.getElementById("baz-without-renderer")).color is "rgb(0, 0, 0)"
    1515Adding the class, the extra rules should match.
    16 FAIL getComputedStyle(document.getElementById("bar-with-renderer")).backgroundColor should be rgb(1, 2, 3). Was rgb(255, 255, 255).
     16PASS getComputedStyle(document.getElementById("bar-with-renderer")).backgroundColor is "rgb(1, 2, 3)"
    1717PASS getComputedStyle(document.getElementById("baz-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
    1818PASS getComputedStyle(document.getElementById("bar-without-renderer")).backgroundColor is "rgb(1, 2, 3)"
    1919PASS getComputedStyle(document.getElementById("baz-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
    2020PASS getComputedStyle(document.getElementById("bar-with-renderer")).color is "rgb(0, 0, 0)"
    21 FAIL getComputedStyle(document.getElementById("baz-with-renderer")).color should be rgb(4, 5, 6). Was rgb(0, 0, 0).
     21PASS getComputedStyle(document.getElementById("baz-with-renderer")).color is "rgb(4, 5, 6)"
    2222PASS getComputedStyle(document.getElementById("bar-without-renderer")).color is "rgb(0, 0, 0)"
    2323PASS getComputedStyle(document.getElementById("baz-without-renderer")).color is "rgb(4, 5, 6)"
  • trunk/LayoutTests/fast/selectors/first-child-direct-adjacent-style-update-expected.txt

    r172880 r173229  
    1414PASS getComputedStyle(document.getElementById("baz-without-renderer")).color is "rgb(4, 5, 6)"
    1515Adding an element as first child should clear the style.
    16 FAIL getComputedStyle(document.getElementById("bar-with-renderer")).backgroundColor should be rgb(255, 255, 255). Was rgb(1, 2, 3).
     16PASS getComputedStyle(document.getElementById("bar-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
    1717PASS getComputedStyle(document.getElementById("baz-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
    1818PASS getComputedStyle(document.getElementById("bar-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
    1919PASS getComputedStyle(document.getElementById("baz-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
    2020PASS getComputedStyle(document.getElementById("bar-with-renderer")).color is "rgb(0, 0, 0)"
    21 FAIL getComputedStyle(document.getElementById("baz-with-renderer")).color should be rgb(0, 0, 0). Was rgb(4, 5, 6).
     21PASS getComputedStyle(document.getElementById("baz-with-renderer")).color is "rgb(0, 0, 0)"
    2222PASS getComputedStyle(document.getElementById("bar-without-renderer")).color is "rgb(0, 0, 0)"
    2323PASS getComputedStyle(document.getElementById("baz-without-renderer")).color is "rgb(0, 0, 0)"
     
    3232PASS getComputedStyle(document.getElementById("baz-without-renderer")).color is "rgb(4, 5, 6)"
    3333Removing <foo> should clear the style.
    34 FAIL getComputedStyle(document.getElementById("bar-with-renderer")).backgroundColor should be rgb(255, 255, 255). Was rgb(1, 2, 3).
     34PASS getComputedStyle(document.getElementById("bar-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
    3535PASS getComputedStyle(document.getElementById("baz-with-renderer")).backgroundColor is "rgb(255, 255, 255)"
    3636PASS getComputedStyle(document.getElementById("bar-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
    3737PASS getComputedStyle(document.getElementById("baz-without-renderer")).backgroundColor is "rgb(255, 255, 255)"
    3838PASS getComputedStyle(document.getElementById("bar-with-renderer")).color is "rgb(0, 0, 0)"
    39 FAIL getComputedStyle(document.getElementById("baz-with-renderer")).color should be rgb(0, 0, 0). Was rgb(4, 5, 6).
     39PASS getComputedStyle(document.getElementById("baz-with-renderer")).color is "rgb(0, 0, 0)"
    4040PASS getComputedStyle(document.getElementById("bar-without-renderer")).color is "rgb(0, 0, 0)"
    4141PASS getComputedStyle(document.getElementById("baz-without-renderer")).color is "rgb(0, 0, 0)"
  • trunk/Source/WebCore/ChangeLog

    r173226 r173229  
     12014-09-03  Benjamin Poulain  <benjamin@webkit.org>
     2
     3        Fix style invalidation of elements with multiple siblings dependencies
     4        https://bugs.webkit.org/show_bug.cgi?id=136472
     5
     6        Reviewed by Andreas Kling.
     7
     8        Previously, style invalidation of siblings was driven by a pair of flags:
     9        -ChildrenAffectedByDirectAdjacentRules.
     10        -ChildrenAffectedByForwardPositionalRules.
     11
     12        When ChildrenAffectedByDirectAdjacentRules was set, the element after an element
     13        with "needsStyleRecalc" was also recomputed. While this work for pair of elements:
     14            a + b
     15        It does not work for more than that. For example, with
     16            a.propery + b + c
     17        When the state of <a> changes, the style of <b> was updated, which is useless. The style
     18        of <c> was untouched, which is incorrect.
     19
     20        When ChildrenAffectedByForwardPositionalRules, all elements after one with "needsStyleRecalc"
     21        were invalidated. While more correct, it caused avalanche of style recalc and was not a very
     22        useful "optimization".
     23
     24 
     25        To fix the correctness issues (e.g. "a + b + c"), I could have gone two ways:
     26        1) Invalidate the parent of a, b, c. The children would always get a correct style
     27           when their parent's style would be resolved.
     28        2) Create invalidation relations to enforce that the right siblings are invalidated.
     29
     30        I have decided for a weak version of (2). The reason is that most DOM trees are very
     31        shallow while being very wide. Invalidating the parent generally causes massive style
     32        recalculation.
     33
     34        To keep things simple for now, there is no explicit dependency list between siblings.
     35        Instead, each element has a pair of flag:
     36        1) The element's style depends on the state of a previous sibling.
     37        2) The element's state affects following siblings.
     38
     39        With the notation "<-" for (1), "->" for (2), the selector "a + b + c" create this kind
     40        of marking:
     41            a  +  b  +  c
     42            ->    ->
     43                       <-
     44
     45        When <a> is invalidated, the style resolver will go through the chain of dependent elements
     46        and invalidate any element that can be affected by a prior invalidation, here <c>.
     47
     48        Overlaps are possible. For example with the two selector, "a + b + c", "b ~ d"
     49        the marking would be
     50            a  +  b  +  c  +  d
     51            ->    ->    ->
     52                       <-    <-
     53
     54        A change in <a> would invalidate both <c> and <d>. This is overkill, but the end result
     55        is correct and it is a net improvement over the previous flags.
     56
     57
     58        As usual, the CSS JIT makes an effort at compile time to reduce tree marking. SelectorChecker
     59        marks everything as usual.
     60
     61        Tests: fast/css/direct-adjacent-style-update-optimization.html
     62               fast/css/indirect-adjacent-style-update-optimization.html
     63               fast/css/non-matching-adjacent-style-update.html
     64               fast/selectors/first-of-type-direct-adjacent-style-update.html
     65               fast/selectors/first-of-type-sibling-style-update.html
     66               fast/selectors/id-direct-adjacent-style-update.html
     67               fast/selectors/id-sibling-style-update.html
     68               fast/selectors/nth-child-as-first-simple-selector-style-update.html
     69               fast/selectors/nth-child-direct-adjacent-style-update.html
     70               fast/selectors/nth-child-style-update.html
     71
     72        * css/SelectorChecker.cpp:
     73        (WebCore::isFirstOfType):
     74        (WebCore::countElementsBefore):
     75        (WebCore::countElementsOfTypeBefore):
     76        Counting selectors are not unlike adjacent combinators, they are handled the exact same way.
     77        For example a :nth-child(4) would generate somewhat similar marking as
     78            :first-child + * + * + *
     79
     80        Everything prior to the element with the counter affects the style of the element.
     81
     82        (WebCore::hasScrollbarPseudoElement):
     83        The assertion was incorrect. You can get an scrollbar pseudo ID on an element without scrollbar.
     84        It will never match, but such case is possible.
     85
     86        (WebCore::SelectorChecker::matchRecursively):
     87        (WebCore::SelectorChecker::checkOne):
     88        * css/StyleResolver.cpp:
     89        (WebCore::StyleResolver::canShareStyleWithElement):
     90        Previously, any subtree affected by sibling selectors were unshareable. That was done by checking
     91        for Element::hasFlagsSetDuringStylingOfChildren().
     92
     93        Now that sibling relation are local, they no longer prevent sharing of all children. Instead, we can
     94        test locally for subgroup with sibling relations.
     95
     96        * cssjit/SelectorCompiler.cpp:
     97        (WebCore::SelectorCompiler::isAdjacentRelation):
     98        (WebCore::SelectorCompiler::shouldMarkStyleIsAffectedByPreviousSibling):
     99        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):
     100        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateDirectAdjacentTreeWalker):
     101        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateIndirectAdjacentTreeWalker):
     102        (WebCore::SelectorCompiler::SelectorCodeGenerator::markElementIfResolvingStyle):
     103        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsNthChild):
     104        (WebCore::SelectorCompiler::SelectorCodeGenerator::markParentElementIfResolvingStyle): Deleted.
     105        * dom/Document.cpp:
     106        (WebCore::nodeOrItsAncestorNeedsStyleRecalc):
     107        * dom/Element.cpp:
     108        (WebCore::checkForSiblingStyleChanges):
     109        (WebCore::Element::hasFlagsSetDuringStylingOfChildren):
     110        (WebCore::Element::setChildrenAffectedByForwardPositionalRules): Deleted.
     111        (WebCore::Element::rareDataChildrenAffectedByForwardPositionalRules): Deleted.
     112        * dom/Element.h:
     113        (WebCore::Element::affectsNextSiblingElementStyle):
     114        (WebCore::Element::setAffectsNextSiblingElementStyle):
     115        (WebCore::Element::setStyleIsAffectedByPreviousSibling):
     116        (WebCore::Element::childrenAffectedByPositionalRules): Deleted.
     117        (WebCore::Element::childrenAffectedByDirectAdjacentRules): Deleted.
     118        (WebCore::Element::childrenAffectedByForwardPositionalRules): Deleted.
     119        (WebCore::Element::setChildrenAffectedByDirectAdjacentRules): Deleted.
     120        (WebCore::Element::setChildrenAffectedByForwardPositionalRules): Deleted.
     121        * dom/ElementRareData.h:
     122        (WebCore::ElementRareData::ElementRareData):
     123        (WebCore::ElementRareData::resetDynamicRestyleObservations):
     124        (WebCore::ElementRareData::childrenAffectedByForwardPositionalRules): Deleted.
     125        (WebCore::ElementRareData::setChildrenAffectedByForwardPositionalRules): Deleted.
     126        * dom/Node.h:
     127        (WebCore::Node::styleIsAffectedByPreviousSibling):
     128        (WebCore::Node::flagAffectsNextSiblingElementStyle):
     129        (WebCore::Node::flagStyleIsAffectedByPreviousSibling):
     130        (WebCore::Node::flagChildrenAffectedByDirectAdjacentRulesFlag): Deleted.
     131        * html/HTMLElement.h:
     132        (WebCore::HTMLElement::isHTMLUnknownElement):
     133        * html/HTMLUnknownElement.h:
     134        * style/StyleResolveTree.cpp:
     135        (WebCore::Style::resetStyleForNonRenderedDescendants):
     136        (WebCore::Style::resolveTree):
     137
    11382014-09-03  Simon Fraser  <simon.fraser@apple.com>
    2139
  • trunk/Source/WebCore/css/SelectorChecker.cpp

    r173138 r173229  
    6969}
    7070
    71 static inline bool isFirstOfType(const Element* element, const QualifiedName& type)
    72 {
    73     for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(sibling)) {
     71static inline bool isFirstOfType(Element* element, const QualifiedName& type, bool isResolvingStyle)
     72{
     73    for (Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(sibling)) {
     74        if (isResolvingStyle)
     75            sibling->setAffectsNextSiblingElementStyle();
    7476        if (sibling->hasTagName(type))
    7577            return false;
     
    8789}
    8890
    89 static inline int countElementsBefore(const Element* element)
     91static inline int countElementsBefore(Element* element, bool isResolvingStyle)
    9092{
    9193    int count = 0;
    92     for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(sibling)) {
     94    for (Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(sibling)) {
     95        if (isResolvingStyle)
     96            sibling->setAffectsNextSiblingElementStyle();
     97
    9398        unsigned index = sibling->childIndex();
    9499        if (index) {
     
    101106}
    102107
    103 static inline int countElementsOfTypeBefore(const Element* element, const QualifiedName& type)
     108static inline int countElementsOfTypeBefore(Element* element, const QualifiedName& type, bool isResolvingStyle)
    104109{
    105110    int count = 0;
    106     for (const Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(sibling)) {
     111    for (Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(sibling)) {
     112        if (isResolvingStyle)
     113            sibling->setAffectsNextSiblingElementStyle();
     114
    107115        if (sibling->hasTagName(type))
    108116            ++count;
     
    153161}
    154162
    155 inline static bool hasScrollbarPseudoElement(const SelectorChecker::SelectorCheckingContext& context, PseudoId& dynamicPseudo)
     163inline static bool hasScrollbarPseudoElement(PseudoId& dynamicPseudo)
    156164{
    157165    if (dynamicPseudo == SCROLLBAR
     
    161169        || dynamicPseudo == SCROLLBAR_TRACK_PIECE
    162170        || dynamicPseudo == SCROLLBAR_CORNER) {
    163         ASSERT_UNUSED(context, context.scrollbar);
    164171        return true;
    165172    }
     
    267274
    268275    case CSSSelector::DirectAdjacent:
    269         if (context.resolvingMode == Mode::ResolvingStyle) {
    270             if (Element* parentElement = context.element->parentElement())
    271                 parentElement->setChildrenAffectedByDirectAdjacentRules();
    272         }
    273         nextContext.element = context.element->previousElementSibling();
    274         if (!nextContext.element)
    275             return SelectorFailsAllSiblings;
    276         nextContext.firstSelectorOfTheFragment = nextContext.selector;
    277         nextContext.elementStyle = 0;
    278         return matchRecursively(nextContext, ignoreDynamicPseudo);
    279 
     276        {
     277            if (context.resolvingMode == Mode::ResolvingStyle)
     278                context.element->setStyleIsAffectedByPreviousSibling();
     279
     280            Element* previousElement = context.element->previousElementSibling();
     281            if (!previousElement)
     282                return SelectorFailsAllSiblings;
     283            if (context.resolvingMode == Mode::ResolvingStyle)
     284                previousElement->setAffectsNextSiblingElementStyle();
     285            nextContext.element = previousElement;
     286            nextContext.firstSelectorOfTheFragment = nextContext.selector;
     287            nextContext.elementStyle = 0;
     288            return matchRecursively(nextContext, ignoreDynamicPseudo);
     289        }
    280290    case CSSSelector::IndirectAdjacent:
    281         if (context.resolvingMode == Mode::ResolvingStyle) {
    282             if (Element* parentElement = context.element->parentElement())
    283                 parentElement->setChildrenAffectedByForwardPositionalRules();
    284         }
     291        if (context.resolvingMode == Mode::ResolvingStyle)
     292            context.element->setStyleIsAffectedByPreviousSibling();
    285293        nextContext.element = context.element->previousElementSibling();
    286294        nextContext.firstSelectorOfTheFragment = nextContext.selector;
    287295        nextContext.elementStyle = 0;
    288296        for (; nextContext.element; nextContext.element = nextContext.element->previousElementSibling()) {
     297            if (context.resolvingMode == Mode::ResolvingStyle)
     298                context.element->setAffectsNextSiblingElementStyle();
     299
    289300            Match match = this->matchRecursively(nextContext, ignoreDynamicPseudo);
    290301            if (match == SelectorMatches || match == SelectorFailsAllSiblings || match == SelectorFailsCompletely)
     
    297308        // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
    298309        // to follow the pseudo elements.
    299         nextContext.hasScrollbarPseudo = hasScrollbarPseudoElement(context, dynamicPseudo);
     310        nextContext.hasScrollbarPseudo = hasScrollbarPseudoElement(dynamicPseudo);
    300311        nextContext.hasSelectionPseudo = dynamicPseudo == SELECTION;
    301312        if ((context.elementStyle || context.resolvingMode == Mode::CollectingRules) && dynamicPseudo != NOPSEUDO
     
    554565        case CSSSelector::PseudoClassFirstOfType:
    555566            // first-of-type matches the first element of its type
    556             if (Element* parentElement = element->parentElement()) {
    557                 bool result = isFirstOfType(element, element->tagQName());
     567            if (element->parentElement()) {
    558568                if (context.resolvingMode == Mode::ResolvingStyle)
    559                     parentElement->setChildrenAffectedByForwardPositionalRules();
    560                 return result;
     569                    element->setStyleIsAffectedByPreviousSibling();
     570
     571                return isFirstOfType(element, element->tagQName(), context.resolvingMode == Mode::ResolvingStyle);
    561572            }
    562573            break;
     
    604615            if (Element* parentElement = element->parentElement()) {
    605616                if (context.resolvingMode == Mode::ResolvingStyle) {
    606                     parentElement->setChildrenAffectedByForwardPositionalRules();
     617                    element->setStyleIsAffectedByPreviousSibling();
    607618                    parentElement->setChildrenAffectedByBackwardPositionalRules();
    608619                }
    609620                if (!parentElement->isFinishedParsingChildren())
    610621                    return false;
    611                 return isFirstOfType(element, element->tagQName()) && isLastOfType(element, element->tagQName());
     622                return isFirstOfType(element, element->tagQName(), context.resolvingMode == Mode::ResolvingStyle) && isLastOfType(element, element->tagQName());
    612623            }
    613624            break;
     
    626637            if (!selector->parseNth())
    627638                break;
    628             if (Element* parentElement = element->parentElement()) {
    629                 int count = 1 + countElementsBefore(element);
     639            if (element->parentElement()) {
     640                if (context.resolvingMode == Mode::ResolvingStyle)
     641                    element->setStyleIsAffectedByPreviousSibling();
     642
     643                int count = 1 + countElementsBefore(element, context.resolvingMode == Mode::ResolvingStyle);
    630644                if (context.resolvingMode == Mode::ResolvingStyle) {
    631645                    RenderStyle* childStyle = context.elementStyle ? context.elementStyle : element->renderStyle();
     
    633647                    if (childStyle)
    634648                        childStyle->setUnique();
    635                     parentElement->setChildrenAffectedByForwardPositionalRules();
    636649                }
    637650
     
    643656            if (!selector->parseNth())
    644657                break;
    645             if (Element* parentElement = element->parentElement()) {
    646                 int count = 1 + countElementsOfTypeBefore(element, element->tagQName());
     658
     659            if (element->parentElement()) {
    647660                if (context.resolvingMode == Mode::ResolvingStyle)
    648                     parentElement->setChildrenAffectedByForwardPositionalRules();
    649 
     661                    element->setStyleIsAffectedByPreviousSibling();
     662
     663                int count = 1 + countElementsOfTypeBefore(element, element->tagQName(), context.resolvingMode == Mode::ResolvingStyle);
    650664                if (selector->matchNth(count))
    651665                    return true;
  • trunk/Source/WebCore/css/StyleResolver.cpp

    r173217 r173229  
    625625    if (element->additionalPresentationAttributeStyle() != state.styledElement()->additionalPresentationAttributeStyle())
    626626        return false;
     627    if (element->affectsNextSiblingElementStyle() || element->styleIsAffectedByPreviousSibling())
     628        return false;
    627629
    628630    if (element->hasID() && m_ruleSets.features().idsInRules.contains(element->idForStyleResolution().impl()))
  • trunk/Source/WebCore/cssjit/SelectorCompiler.cpp

    r172933 r173229  
    225225    void generateDirectAdjacentTreeWalker(Assembler::JumpList& failureCases, const SelectorFragment&);
    226226    void generateIndirectAdjacentTreeWalker(Assembler::JumpList& failureCases, const SelectorFragment&);
    227     void markParentElementIfResolvingStyle(int32_t);
    228     void markParentElementIfResolvingStyle(JSC::FunctionPtr);
    229227
    230228    void linkFailures(Assembler::JumpList& globalFailureCases, BacktrackingAction, Assembler::JumpList& localFailureCases);
     
    274272    void generateRequestedPseudoElementEqualsToSelectorPseudoElement(Assembler::JumpList& failureCases, const SelectorFragment&, Assembler::RegisterID checkingContext);
    275273    void generateSpecialFailureInQuirksModeForActiveAndHoverIfNeeded(Assembler::JumpList& failureCases, const SelectorFragment&);
     274    void markElementIfResolvingStyle(Assembler::RegisterID, int32_t);
    276275    Assembler::JumpList jumpIfNoPreviousAdjacentElement();
    277276    Assembler::JumpList jumpIfNoNextAdjacentElement();
     
    13401339}
    13411340
     1341static bool isAdjacentRelation(FragmentRelation relation)
     1342{
     1343    return relation == FragmentRelation::DirectAdjacent || relation == FragmentRelation::IndirectAdjacent;
     1344}
     1345
     1346static bool shouldMarkStyleIsAffectedByPreviousSibling(const SelectorFragment& fragment)
     1347{
     1348    return isAdjacentRelation(fragment.relationToLeftFragment) && !isAdjacentRelation(fragment.relationToRightFragment);
     1349}
     1350
    13421351void SelectorCodeGenerator::generateSelectorChecker()
    13431352{
     
    14021411            break;
    14031412        }
     1413        if (shouldMarkStyleIsAffectedByPreviousSibling(fragment))
     1414            markElementIfResolvingStyle(elementAddressRegister, Node::flagStyleIsAffectedByPreviousSibling());
    14041415        generateBacktrackingTailsIfNeeded(failureCases, fragment);
    14051416    }
     
    15611572void SelectorCodeGenerator::generateDirectAdjacentTreeWalker(Assembler::JumpList& failureCases, const SelectorFragment& fragment)
    15621573{
    1563     markParentElementIfResolvingStyle(Node::flagChildrenAffectedByDirectAdjacentRulesFlag());
    1564 
    15651574    generateWalkToPreviousAdjacent(failureCases, fragment);
     1575    markElementIfResolvingStyle(elementAddressRegister, Node::flagAffectsNextSiblingElementStyle());
    15661576
    15671577    Assembler::JumpList matchingTagNameFailureCases;
     
    15791589void SelectorCodeGenerator::generateIndirectAdjacentTreeWalker(Assembler::JumpList& failureCases, const SelectorFragment& fragment)
    15801590{
    1581     markParentElementIfResolvingStyle(Element::setChildrenAffectedByForwardPositionalRules);
    1582 
    15831591    Assembler::Label loopStart(m_assembler.label());
    15841592
     
    15871595
    15881596    generateWalkToPreviousAdjacent(failureCases, fragment);
     1597    markElementIfResolvingStyle(elementAddressRegister, Node::flagAffectsNextSiblingElementStyle());
    15891598
    15901599    if (fragment.backtrackingFlags & BacktrackingFlag::IndirectAdjacentEntryPoint)
     
    18281837}
    18291838
    1830 void SelectorCodeGenerator::markParentElementIfResolvingStyle(int32_t nodeFlag)
     1839void SelectorCodeGenerator::markElementIfResolvingStyle(Assembler::RegisterID element, int32_t nodeFlag)
    18311840{
    18321841    if (m_selectorContext == SelectorContext::QuerySelector)
     
    18391848    }
    18401849
    1841     LocalRegister parentElement(m_registerAllocator);
    1842     generateWalkToParentElement(skipMarking, parentElement);
    1843 
    1844     setNodeFlag(m_assembler, parentElement, nodeFlag);
     1850    setNodeFlag(m_assembler, element, nodeFlag);
    18451851
    18461852    skipMarking.link(&m_assembler);
    18471853}
    1848 
    1849 void SelectorCodeGenerator::markParentElementIfResolvingStyle(JSC::FunctionPtr markingFunction)
    1850 {
    1851     if (m_selectorContext == SelectorContext::QuerySelector)
    1852         return;
    1853 
    1854     //     if (checkingContext.resolvingMode == ResolvingStyle) {
    1855     //         Element* parent = element->parentNode();
    1856     //         markingFunction(parent);
    1857     //     }
    1858 
    1859     Assembler::JumpList skipMarking;
    1860     {
    1861         LocalRegister checkingContext(m_registerAllocator);
    1862         skipMarking.append(jumpIfNotResolvingStyle(checkingContext));
    1863     }
    1864 
    1865     // Get the parent element in a temporary register.
    1866     Assembler::RegisterID parentElement = m_registerAllocator.allocateRegister();
    1867     generateWalkToParentElement(skipMarking, parentElement);
    1868 
    1869     // Return the register parentElement just before the function call since we don't need it to be preserved
    1870     // on the stack.
    1871     m_registerAllocator.deallocateRegister(parentElement);
    1872 
    1873     // Invoke the marking function on the parent element.
    1874     FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls);
    1875     functionCall.setFunctionAddress(markingFunction);
    1876     functionCall.setOneArgument(parentElement);
    1877     functionCall.call();
    1878 
    1879     skipMarking.link(&m_assembler);
    1880 }
    1881 
    18821854
    18831855void SelectorCodeGenerator::linkFailures(Assembler::JumpList& globalFailureCases, BacktrackingAction backtrackingAction, Assembler::JumpList& localFailureCases)
     
    29442916void SelectorCodeGenerator::generateElementIsNthChild(Assembler::JumpList& failureCases, const SelectorFragment& fragment)
    29452917{
    2946     Assembler::RegisterID parentElement = m_registerAllocator.allocateRegister();
    2947     generateWalkToParentElement(failureCases, parentElement);
     2918    {
     2919        LocalRegister parentElement(m_registerAllocator);
     2920        generateWalkToParentElement(failureCases, parentElement);
     2921    }
    29482922
    29492923    Vector<std::pair<int, int>, 32> validSubsetFilters;
     
    29582932        validSubsetFilters.uncheckedAppend(slot);
    29592933    }
    2960     if (validSubsetFilters.isEmpty()) {
    2961         m_registerAllocator.deallocateRegister(parentElement);
     2934    if (validSubsetFilters.isEmpty())
    29622935        return;
    2963     }
    2964     if (m_selectorContext == SelectorContext::QuerySelector)
    2965         m_registerAllocator.deallocateRegister(parentElement);
     2936
     2937    if (!isAdjacentRelation(fragment.relationToRightFragment))
     2938        markElementIfResolvingStyle(elementAddressRegister, Node::flagStyleIsAffectedByPreviousSibling());
    29662939
    29672940    // Setup the counter at 1.
     
    29812954        Assembler::JumpList noCachedChildIndexCases;
    29822955        generateWalkToPreviousAdjacentElement(noMoreSiblingsCases, previousSibling);
     2956        markElementIfResolvingStyle(previousSibling, Node::flagAffectsNextSiblingElementStyle());
    29832957        noCachedChildIndexCases.append(m_assembler.branchTest32(Assembler::Zero, Assembler::Address(previousSibling, Node::nodeFlagsMemoryOffset()), Assembler::TrustedImm32(Node::flagHasRareData())));
    29842958        {
     
    29962970        Assembler::Label loopStart = m_assembler.label();
    29972971        generateWalkToPreviousAdjacentElement(noMoreSiblingsCases, previousSibling);
     2972        markElementIfResolvingStyle(previousSibling, Node::flagAffectsNextSiblingElementStyle());
    29982973        m_assembler.add32(Assembler::TrustedImm32(1), elementCounter);
    29992974        m_assembler.jump().linkTo(loopStart, &m_assembler);
     
    30052980        LocalRegister checkingContext(m_registerAllocator);
    30062981        Assembler::Jump notResolvingStyle = jumpIfNotResolvingStyle(checkingContext);
    3007 
    3008         m_registerAllocator.deallocateRegister(parentElement);
    3009         FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls);
    3010         functionCall.setFunctionAddress(Element::setChildrenAffectedByForwardPositionalRules);
    3011         functionCall.setOneArgument(parentElement);
    3012         functionCall.call();
    30132982
    30142983        if (fragmentMatchesTheRightmostElement(m_selectorContext, fragment)) {
  • trunk/Source/WebCore/dom/Document.cpp

    r173066 r173229  
    61556155        return true;
    61566156
    6157     for (const Element* ancestor = node.parentOrShadowHostElement(); ancestor; ancestor = ancestor->parentOrShadowHostElement()) {
     6157    const Node* currentNode = &node;
     6158    const Element* ancestor = currentNode->parentOrShadowHostElement();
     6159    while (ancestor) {
    61586160        if (ancestor->needsStyleRecalc())
    61596161            return true;
    61606162
    6161         if (ancestor->directChildNeedsStyleRecalc() && (ancestor->childrenAffectedByDirectAdjacentRules() || ancestor->childrenAffectedByForwardPositionalRules()))
     6163        if (ancestor->directChildNeedsStyleRecalc() && currentNode->styleIsAffectedByPreviousSibling())
    61626164            return true;
     6165
     6166        currentNode = ancestor;
     6167        ancestor = currentNode->parentOrShadowHostElement();
    61636168    }
    61646169    return false;
  • trunk/Source/WebCore/dom/Element.cpp

    r173012 r173229  
    15411541    // :empty selector.
    15421542    checkForEmptyStyleChange(*parent);
    1543    
    1544     if (parent->needsStyleRecalc() && parent->childrenAffectedByPositionalRules())
     1543
     1544    if (parent->styleChangeType() >= FullStyleChange)
    15451545        return;
    15461546
     
    15891589    }
    15901590
    1591     // The + selector.  We need to invalidate the first element following the insertion point.  It is the only possible element
    1592     // that could be affected by this DOM change.
    1593     if (parent->childrenAffectedByDirectAdjacentRules() && elementAfterChange)
    1594         elementAfterChange->setNeedsStyleRecalc();
    1595 
    1596     // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
     1591    if (elementAfterChange) {
     1592        if (elementAfterChange->styleIsAffectedByPreviousSibling())
     1593            elementAfterChange->setNeedsStyleRecalc();
     1594        else if (elementAfterChange->affectsNextSiblingElementStyle()) {
     1595            Element* elementToInvalidate = elementAfterChange;
     1596            do {
     1597                elementToInvalidate = elementToInvalidate->nextElementSibling();
     1598            } while (elementToInvalidate && !elementToInvalidate->styleIsAffectedByPreviousSibling());
     1599
     1600            if (elementToInvalidate)
     1601                elementToInvalidate->setNeedsStyleRecalc();
     1602        }
     1603    }
     1604
    15971605    // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
    15981606    // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
     
    16011609    // For performance reasons we just mark the parent node as changed, since we don't want to make childrenChanged O(n^2) by crawling all our kids
    16021610    // here.  recalcStyle will then force a walk of the children when it sees that this has happened.
    1603     if (parent->childrenAffectedByForwardPositionalRules() && elementAfterChange)
    1604         parent->setNeedsStyleRecalc();
    16051611    if (parent->childrenAffectedByBackwardPositionalRules() && elementBeforeChange)
    16061612        parent->setNeedsStyleRecalc();
     
    21092115}
    21102116
    2111 void Element::setChildrenAffectedByForwardPositionalRules(Element* element)
    2112 {
    2113     element->ensureElementRareData().setChildrenAffectedByForwardPositionalRules(true);
    2114 }
    2115 
    21162117void Element::setChildrenAffectedByBackwardPositionalRules()
    21172118{
     
    21292130bool Element::hasFlagsSetDuringStylingOfChildren() const
    21302131{
    2131     if (childrenAffectedByHover() || childrenAffectedByFirstChildRules() || childrenAffectedByLastChildRules() || childrenAffectedByDirectAdjacentRules())
     2132    if (childrenAffectedByHover() || childrenAffectedByFirstChildRules() || childrenAffectedByLastChildRules())
    21322133        return true;
    21332134
     
    21362137    return rareDataChildrenAffectedByActive()
    21372138        || rareDataChildrenAffectedByDrag()
    2138         || rareDataChildrenAffectedByForwardPositionalRules()
    21392139        || rareDataChildrenAffectedByBackwardPositionalRules();
    21402140}
     
    21562156    ASSERT(hasRareData());
    21572157    return elementRareData()->childrenAffectedByDrag();
    2158 }
    2159 
    2160 bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
    2161 {
    2162     ASSERT(hasRareData());
    2163     return elementRareData()->childrenAffectedByForwardPositionalRules();
    21642158}
    21652159
  • trunk/Source/WebCore/dom/Element.h

    r173176 r173229  
    361361    bool childrenAffectedByActive() const { return hasRareData() && rareDataChildrenAffectedByActive(); }
    362362    bool childrenAffectedByDrag() const { return hasRareData() && rareDataChildrenAffectedByDrag(); }
    363     bool childrenAffectedByPositionalRules() const { return hasRareData() && (rareDataChildrenAffectedByForwardPositionalRules() || rareDataChildrenAffectedByBackwardPositionalRules()); }
    364363    bool childrenAffectedByFirstChildRules() const { return getFlag(ChildrenAffectedByFirstChildRulesFlag); }
    365364    bool childrenAffectedByLastChildRules() const { return getFlag(ChildrenAffectedByLastChildRulesFlag); }
    366     bool childrenAffectedByDirectAdjacentRules() const { return getFlag(ChildrenAffectedByDirectAdjacentRulesFlag); }
    367     bool childrenAffectedByForwardPositionalRules() const { return hasRareData() && rareDataChildrenAffectedByForwardPositionalRules(); }
    368365    bool childrenAffectedByBackwardPositionalRules() const { return hasRareData() && rareDataChildrenAffectedByBackwardPositionalRules(); }
     366    bool affectsNextSiblingElementStyle() const { return getFlag(AffectsNextSiblingElementStyle); }
    369367    unsigned childIndex() const { return hasRareData() ? rareDataChildIndex() : 0; }
    370368
     
    377375    void setChildrenAffectedByFirstChildRules() { setFlag(ChildrenAffectedByFirstChildRulesFlag); }
    378376    void setChildrenAffectedByLastChildRules() { setFlag(ChildrenAffectedByLastChildRulesFlag); }
    379     void setChildrenAffectedByDirectAdjacentRules() { setFlag(ChildrenAffectedByDirectAdjacentRulesFlag); }
    380     static void setChildrenAffectedByForwardPositionalRules(Element*);
    381     void setChildrenAffectedByForwardPositionalRules() { setChildrenAffectedByForwardPositionalRules(this); }
    382377    void setChildrenAffectedByBackwardPositionalRules();
     378    void setAffectsNextSiblingElementStyle() { setFlag(AffectsNextSiblingElementStyle); }
     379    void setStyleIsAffectedByPreviousSibling() { setFlag(StyleIsAffectedByPreviousSibling); }
    383380    void setChildIndex(unsigned);
    384381
     
    651648    bool rareDataChildrenAffectedByDrag() const;
    652649    bool rareDataChildrenAffectedByLastChildRules() const;
    653     bool rareDataChildrenAffectedByForwardPositionalRules() const;
    654650    bool rareDataChildrenAffectedByBackwardPositionalRules() const;
    655651    unsigned rareDataChildIndex() const;
  • trunk/Source/WebCore/dom/ElementRareData.h

    r172880 r173229  
    7676    bool childrenAffectedByLastChildRules() const { return m_childrenAffectedByLastChildRules; }
    7777    void setChildrenAffectedByLastChildRules(bool value) { m_childrenAffectedByLastChildRules = value; }
    78     bool childrenAffectedByForwardPositionalRules() const { return m_childrenAffectedByForwardPositionalRules; }
    79     void setChildrenAffectedByForwardPositionalRules(bool value) { m_childrenAffectedByForwardPositionalRules = value; }
    8078    bool childrenAffectedByBackwardPositionalRules() const { return m_childrenAffectedByBackwardPositionalRules; }
    8179    void setChildrenAffectedByBackwardPositionalRules(bool value) { m_childrenAffectedByBackwardPositionalRules = value; }
     
    133131    // *-child-of-type, we will just give up and re-evaluate whenever children change at all.
    134132    unsigned m_childrenAffectedByLastChildRules : 1;
    135     unsigned m_childrenAffectedByForwardPositionalRules : 1;
    136133    unsigned m_childrenAffectedByBackwardPositionalRules : 1;
    137134
     
    174171    , m_childrenAffectedByDrag(false)
    175172    , m_childrenAffectedByLastChildRules(false)
    176     , m_childrenAffectedByForwardPositionalRules(false)
    177173    , m_childrenAffectedByBackwardPositionalRules(false)
    178174    , m_regionOversetState(RegionUndefined)
     
    212208    setChildrenAffectedByDrag(false);
    213209    setChildrenAffectedByLastChildRules(false);
    214     setChildrenAffectedByForwardPositionalRules(false);
    215210    setChildrenAffectedByBackwardPositionalRules(false);
    216211}
  • trunk/Source/WebCore/dom/Node.h

    r173047 r173229  
    326326    StyleChangeType styleChangeType() const { return static_cast<StyleChangeType>(m_nodeFlags & StyleChangeMask); }
    327327    bool childNeedsStyleRecalc() const { return getFlag(ChildNeedsStyleRecalcFlag); }
     328    bool styleIsAffectedByPreviousSibling() const { return getFlag(StyleIsAffectedByPreviousSibling); }
    328329    bool isLink() const { return getFlag(IsLinkFlag); }
    329330    bool isEditingText() const { return getFlag(IsEditingTextFlag); }
     
    579580    static int32_t flagChildrenAffectedByFirstChildRulesFlag() { return ChildrenAffectedByFirstChildRulesFlag; }
    580581    static int32_t flagChildrenAffectedByLastChildRulesFlag() { return ChildrenAffectedByLastChildRulesFlag; }
    581     static int32_t flagChildrenAffectedByDirectAdjacentRulesFlag() { return ChildrenAffectedByDirectAdjacentRulesFlag; }
     582
     583    static int32_t flagAffectsNextSiblingElementStyle() { return AffectsNextSiblingElementStyle; }
     584    static int32_t flagStyleIsAffectedByPreviousSibling() { return StyleIsAffectedByPreviousSibling; }
    582585#endif // ENABLE(CSS_SELECTOR_JIT)
    583586
     
    613616        ChildrenAffectedByFirstChildRulesFlag = 1 << 25,
    614617        ChildrenAffectedByLastChildRulesFlag = 1 << 26,
    615         ChildrenAffectedByDirectAdjacentRulesFlag = 1 << 27,
    616         ChildrenAffectedByHoverRulesFlag = 1 << 28,
    617         DirectChildNeedsStyleRecalcFlag = 1 << 29,
    618 
    619         SelfOrAncestorHasDirAutoFlag = 1 << 30,
    620 
    621         IsHTMLUnknownElementFlag = 1 << 31,
     618        ChildrenAffectedByHoverRulesFlag = 1 << 27,
     619
     620        DirectChildNeedsStyleRecalcFlag = 1 << 28,
     621        AffectsNextSiblingElementStyle = 1 << 29,
     622        StyleIsAffectedByPreviousSibling = 1 << 30,
     623
     624        SelfOrAncestorHasDirAutoFlag = 1 << 31,
    622625
    623626        DefaultNodeFlags = IsParsingChildrenFinishedFlag
     
    643646        CreateInsertionPoint = CreateHTMLElement | NeedsNodeRenderingTraversalSlowPathFlag,
    644647        CreateEditingText = CreateText | IsEditingTextFlag,
    645         CreateMathMLElement = CreateStyledElement | IsMathMLFlag,
    646         CreateHTMLUnknownElement = CreateHTMLElement | IsHTMLUnknownElementFlag,
     648        CreateMathMLElement = CreateStyledElement | IsMathMLFlag
    647649    };
    648650    Node(Document&, ConstructionType);
  • trunk/Source/WebCore/html/HTMLElement.h

    r172862 r173229  
    8989    TextDirection directionalityIfhasDirAutoAttribute(bool& isAuto) const;
    9090
    91     bool isHTMLUnknownElement() const { return getFlag(IsHTMLUnknownElementFlag); }
     91    virtual bool isHTMLUnknownElement() const { return false; }
    9292    virtual bool isTextControlInnerTextElement() const { return false; }
    9393
  • trunk/Source/WebCore/html/HTMLUnknownElement.h

    r166841 r173229  
    4242    }
    4343
     44    virtual bool isHTMLUnknownElement() const override { return true; }
     45
    4446private:
    4547    HTMLUnknownElement(const QualifiedName& tagName, Document& document)
    46         : HTMLElement(tagName, document, CreateHTMLUnknownElement)
     48        : HTMLElement(tagName, document, CreateHTMLElement)
    4749    {
    4850    }
  • trunk/Source/WebCore/style/StyleResolveTree.cpp

    r172985 r173229  
    553553{
    554554    ASSERT(!current.renderer());
    555     bool shouldInvalidateDirectChildren = current.directChildNeedsStyleRecalc() && (current.childrenAffectedByDirectAdjacentRules() || current.childrenAffectedByForwardPositionalRules());
     555    bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
    556556    for (auto& child : childrenOfType<Element>(current)) {
    557557        ASSERT(!child.renderer());
    558         if (shouldInvalidateDirectChildren || child.needsStyleRecalc()) {
     558        if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
     559            if (child.styleIsAffectedByPreviousSibling())
     560                child.setNeedsStyleRecalc();
     561            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
     562        }
     563
     564        if (child.needsStyleRecalc()) {
    559565            child.resetComputedStyle();
    560566            child.clearNeedsStyleRecalc();
    561         }
     567            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
     568        }
     569
    562570        if (child.childNeedsStyleRecalc()) {
    563571            resetStyleForNonRenderedDescendants(child);
     
    898906    }
    899907
    900     bool hasDirectAdjacentRules = current.childrenAffectedByDirectAdjacentRules();
    901     bool hasIndirectAdjacentRules = current.childrenAffectedByForwardPositionalRules();
    902 
    903908#if PLATFORM(IOS)
    904909    CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&current, current.renderStyle());
     
    926931        updateBeforeOrAfterPseudoElement(current, change, BEFORE, childRenderTreePosition);
    927932
    928         // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
    929         // For now we will just worry about the common case, since it's a lot trickier to get the second case right
    930         // without doing way too much re-resolution.
    931         bool forceCheckOfNextElementSibling = false;
    932         bool forceCheckOfAnyElementSibling = false;
     933        bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
    933934        for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
    934935            if (RenderObject* childRenderer = child->renderer())
     
    940941            if (!child->isElementNode())
    941942                continue;
     943
    942944            Element* childElement = toElement(child);
    943             bool childRulesChanged = childElement->needsStyleRecalc() && childElement->styleChangeType() == FullStyleChange;
    944             if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling))
    945                 childElement->setNeedsStyleRecalc();
     945            if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
     946                if (childElement->styleIsAffectedByPreviousSibling())
     947                    childElement->setNeedsStyleRecalc();
     948                elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement->affectsNextSiblingElementStyle();
     949            } else if (childElement->styleChangeType() >= FullStyleChange)
     950                elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement->affectsNextSiblingElementStyle();
    946951            if (change >= Inherit || childElement->childNeedsStyleRecalc() || childElement->needsStyleRecalc()) {
    947952                parentPusher.push();
    948953                resolveTree(*childElement, renderer->style(), childRenderTreePosition, change);
    949954            }
    950             forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
    951             forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
    952955        }
    953956
Note: See TracChangeset for help on using the changeset viewer.