Don't invalidate descendants for nth pseudo classes unless needed
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 12 Mar 2018 16:15:46 +0000 (16:15 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 12 Mar 2018 16:15:46 +0000 (16:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=183566

Reviewed by Zalan Bujtas.

We currently invalidate the whole subtrees that may match :nth-child and similar. In many common
cases we know that only the direct siblings may be affected.

* css/SelectorChecker.cpp:
(WebCore::localContextForParent):
(WebCore::SelectorChecker::matchRecursively const):

    Track if the context matches the subject element if the selector or its siblings only.

(WebCore::SelectorChecker::checkOne const):

    Use different bits of descendant and child invalidation cases.

* cssjit/SelectorCompiler.cpp:
(WebCore::SelectorCompiler::fragmentMatchesRightmostOrAdjacentElement):
(WebCore::SelectorCompiler::constructFragmentsInternal):

    Track if the context matches the subject element if the selector or its siblings only.

(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsNthChild):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsNthChildOf):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsNthLastChild):

    Use different bits of descendant and child invalidation cases.

* dom/Element.cpp:
(WebCore::invalidateForForwardPositionalRules):
(WebCore::invalidateForBackwardPositionalRules):

    Invalidate more precisely based on the new bits.

(WebCore::checkForSiblingStyleChanges):
(WebCore::Element::setDescendantsAffectedByForwardPositionalRules):
(WebCore::Element::setDescendantsAffectedByBackwardPositionalRules):
(WebCore::Element::hasFlagsSetDuringStylingOfChildren const):
(WebCore::Element::rareDataDescendantsAffectedByForwardPositionalRules const):
(WebCore::Element::rareDataDescendantsAffectedByBackwardPositionalRules const):

    New bits.

* dom/Element.h:
(WebCore::Element::descendantsAffectedByForwardPositionalRules const):
(WebCore::Element::descendantsAffectedByBackwardPositionalRules const):
* dom/ElementRareData.h:
(WebCore::ElementRareData::descendantsAffectedByForwardPositionalRules const):
(WebCore::ElementRareData::setDescendantsAffectedByForwardPositionalRules):
(WebCore::ElementRareData::descendantsAffectedByBackwardPositionalRules const):
(WebCore::ElementRareData::setDescendantsAffectedByBackwardPositionalRules):
(WebCore::ElementRareData::ElementRareData):
(WebCore::ElementRareData::resetStyleRelations):
* style/StyleRelations.cpp:
(WebCore::Style::commitRelationsToRenderStyle):
(WebCore::Style::commitRelations):
* style/StyleRelations.h:

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

Source/WebCore/ChangeLog
Source/WebCore/css/SelectorChecker.cpp
Source/WebCore/cssjit/SelectorCompiler.cpp
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Element.h
Source/WebCore/dom/ElementRareData.h
Source/WebCore/style/StyleRelations.cpp
Source/WebCore/style/StyleRelations.h

index d828d0f..9169b47 100644 (file)
@@ -1,3 +1,65 @@
+2018-03-12  Antti Koivisto  <antti@apple.com>
+
+        Don't invalidate descendants for nth pseudo classes unless needed
+        https://bugs.webkit.org/show_bug.cgi?id=183566
+
+        Reviewed by Zalan Bujtas.
+
+        We currently invalidate the whole subtrees that may match :nth-child and similar. In many common
+        cases we know that only the direct siblings may be affected.
+
+        * css/SelectorChecker.cpp:
+        (WebCore::localContextForParent):
+        (WebCore::SelectorChecker::matchRecursively const):
+
+            Track if the context matches the subject element if the selector or its siblings only.
+
+        (WebCore::SelectorChecker::checkOne const):
+
+            Use different bits of descendant and child invalidation cases.
+
+        * cssjit/SelectorCompiler.cpp:
+        (WebCore::SelectorCompiler::fragmentMatchesRightmostOrAdjacentElement):
+        (WebCore::SelectorCompiler::constructFragmentsInternal):
+
+            Track if the context matches the subject element if the selector or its siblings only.
+
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsNthChild):
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsNthChildOf):
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsNthLastChild):
+
+            Use different bits of descendant and child invalidation cases.
+
+        * dom/Element.cpp:
+        (WebCore::invalidateForForwardPositionalRules):
+        (WebCore::invalidateForBackwardPositionalRules):
+
+            Invalidate more precisely based on the new bits.
+
+        (WebCore::checkForSiblingStyleChanges):
+        (WebCore::Element::setDescendantsAffectedByForwardPositionalRules):
+        (WebCore::Element::setDescendantsAffectedByBackwardPositionalRules):
+        (WebCore::Element::hasFlagsSetDuringStylingOfChildren const):
+        (WebCore::Element::rareDataDescendantsAffectedByForwardPositionalRules const):
+        (WebCore::Element::rareDataDescendantsAffectedByBackwardPositionalRules const):
+
+            New bits.
+
+        * dom/Element.h:
+        (WebCore::Element::descendantsAffectedByForwardPositionalRules const):
+        (WebCore::Element::descendantsAffectedByBackwardPositionalRules const):
+        * dom/ElementRareData.h:
+        (WebCore::ElementRareData::descendantsAffectedByForwardPositionalRules const):
+        (WebCore::ElementRareData::setDescendantsAffectedByForwardPositionalRules):
+        (WebCore::ElementRareData::descendantsAffectedByBackwardPositionalRules const):
+        (WebCore::ElementRareData::setDescendantsAffectedByBackwardPositionalRules):
+        (WebCore::ElementRareData::ElementRareData):
+        (WebCore::ElementRareData::resetStyleRelations):
+        * style/StyleRelations.cpp:
+        (WebCore::Style::commitRelationsToRenderStyle):
+        (WebCore::Style::commitRelations):
+        * style/StyleRelations.h:
+
 2018-03-12  Javier Fernandez  <jfernandez@igalia.com>
 
         Remove GridLayout runtime flag
index ccf9be7..e33a3ab 100644 (file)
@@ -69,6 +69,7 @@ struct SelectorChecker::LocalContext {
     const CSSSelector* firstSelectorOfTheFragment;
     PseudoId pseudoId;
     bool isMatchElement { true };
+    bool isSubjectOrAdjacentElement { true };
     bool inFunctionalPseudoClass { false };
     bool pseudoElementEffective { true };
     bool hasScrollbarPseudo { false };
@@ -238,6 +239,7 @@ static SelectorChecker::LocalContext localContextForParent(const SelectorChecker
         updatedContext.visitedMatchType = VisitedMatchType::Disabled;
 
     updatedContext.isMatchElement = false;
+    updatedContext.isSubjectOrAdjacentElement = false;
 
     if (updatedContext.mayMatchHostPseudoClass) {
         updatedContext.element = nullptr;
@@ -432,6 +434,7 @@ SelectorChecker::MatchResult SelectorChecker::matchRecursively(CheckingContext&
                 return MatchResult::fails(Match::SelectorFailsCompletely);
             nextContext.element = shadowHostNode;
             nextContext.firstSelectorOfTheFragment = nextContext.selector;
+            nextContext.isSubjectOrAdjacentElement = false;
             PseudoIdSet ignoreDynamicPseudo;
             unsigned shadowDescendantSpecificity = 0;
             MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, shadowDescendantSpecificity);
@@ -746,7 +749,8 @@ bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
         case CSSSelector::PseudoClassFirstOfType:
             // first-of-type matches the first element of its type
             if (auto* parentElement = element.parentElement()) {
-                addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByForwardPositionalRules);
+                auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules;
+                addStyleRelation(checkingContext, *parentElement, relation);
                 return isFirstOfType(element, element.tagQName());
             }
             break;
@@ -763,7 +767,8 @@ bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
         case CSSSelector::PseudoClassLastOfType:
             // last-of-type matches the last element of its type
             if (Element* parentElement = element.parentElement()) {
-                addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByBackwardPositionalRules);
+                auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules;
+                addStyleRelation(checkingContext, *parentElement, relation);
                 if (!parentElement->isFinishedParsingChildren())
                     return false;
                 return isLastOfType(element, element.tagQName());
@@ -785,8 +790,10 @@ bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
         case CSSSelector::PseudoClassOnlyOfType:
             // FIXME: This selector is very slow.
             if (Element* parentElement = element.parentElement()) {
-                addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByForwardPositionalRules);
-                addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByBackwardPositionalRules);
+                auto forwardRelation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules;
+                addStyleRelation(checkingContext, *parentElement, forwardRelation);
+                auto backwardRelation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules;
+                addStyleRelation(checkingContext, *parentElement, backwardRelation);
                 if (!parentElement->isFinishedParsingChildren())
                     return false;
                 return isFirstOfType(element, element.tagQName()) && isLastOfType(element, element.tagQName());
@@ -833,7 +840,8 @@ bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
             if (!selector.parseNth())
                 break;
             if (auto* parentElement = element.parentElement()) {
-                addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByForwardPositionalRules);
+                auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules;
+                addStyleRelation(checkingContext, *parentElement, relation);
 
                 if (const CSSSelectorList* selectorList = selector.selectorList()) {
                     unsigned selectorListSpecificity;
@@ -863,7 +871,8 @@ bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
                 break;
 
             if (auto* parentElement = element.parentElement()) {
-                addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByForwardPositionalRules);
+                auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules;
+                addStyleRelation(checkingContext, *parentElement, relation);
 
                 int count = 1 + countElementsOfTypeBefore(element, element.tagQName());
                 if (selector.matchNth(count))
@@ -881,8 +890,10 @@ bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
                     specificity = CSSSelector::addSpecificities(specificity, selectorListSpecificity);
 
                     addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByPropertyBasedBackwardPositionalRules);
-                } else
-                    addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByBackwardPositionalRules);
+                } else {
+                    auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules;
+                    addStyleRelation(checkingContext, *parentElement, relation);
+                }
 
                 if (!parentElement->isFinishedParsingChildren())
                     return false;
@@ -905,7 +916,8 @@ bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
             if (!selector.parseNth())
                 break;
             if (Element* parentElement = element.parentElement()) {
-                addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByBackwardPositionalRules);
+                auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules;
+                addStyleRelation(checkingContext, *parentElement, relation);
 
                 if (!parentElement->isFinishedParsingChildren())
                     return false;
index a79b267..f06e6be 100644 (file)
@@ -106,7 +106,8 @@ enum class FunctionType {
 
 enum class FragmentPositionInRootFragments {
     Rightmost,
-    NotRightmost
+    AdjacentToRightmost,
+    Other
 };
 
 enum class VisitedMode {
@@ -178,6 +179,7 @@ struct SelectorFragment {
     FragmentRelation relationToLeftFragment;
     FragmentRelation relationToRightFragment;
     FragmentPositionInRootFragments positionInRootFragments;
+    bool isRightmostOrAdjacent { false };
 
     BacktrackingAction traversalBacktrackingAction = BacktrackingAction::NoBacktracking;
     BacktrackingAction matchingTagNameBacktrackingAction = BacktrackingAction::NoBacktracking;
@@ -427,6 +429,11 @@ static inline bool fragmentMatchesTheRightmostElement(const SelectorFragment& fr
     return fragment.relationToRightFragment == FragmentRelation::Rightmost && fragment.positionInRootFragments == FragmentPositionInRootFragments::Rightmost;
 }
 
+static inline bool fragmentMatchesRightmostOrAdjacentElement(const SelectorFragment& fragment)
+{
+    return fragment.isRightmostOrAdjacent && fragment.positionInRootFragments != FragmentPositionInRootFragments::Other;
+}
+
 FunctionType SelectorFragment::appendUnoptimizedPseudoClassWithContext(bool (*matcher)(const SelectorChecker::CheckingContext&))
 {
     unoptimizedPseudoClassesWithContext.append(JSC::FunctionPtr(matcher));
@@ -873,6 +880,7 @@ static bool isScrollbarPseudoElement(CSSSelector::PseudoElementType type)
 static FunctionType constructFragmentsInternal(const CSSSelector* rootSelector, SelectorContext selectorContext, SelectorFragmentList& selectorFragments, FragmentsLevel fragmentLevel, FragmentPositionInRootFragments positionInRootFragments, bool visitedMatchEnabled, VisitedMode& visitedMode, PseudoElementMatchingBehavior pseudoElementMatchingBehavior)
 {
     FragmentRelation relationToPreviousFragment = FragmentRelation::Rightmost;
+    bool isRightmostOrAdjacent = positionInRootFragments != FragmentPositionInRootFragments::Other;
     FunctionType functionType = FunctionType::SimpleSelectorChecker;
     SelectorFragment* fragment = nullptr;
     unsigned specificity = 0;
@@ -914,7 +922,7 @@ static FunctionType constructFragmentsInternal(const CSSSelector* rootSelector,
         case CSSSelector::PseudoClass: {
             FragmentPositionInRootFragments subPosition = positionInRootFragments;
             if (relationToPreviousFragment != FragmentRelation::Rightmost)
-                subPosition = FragmentPositionInRootFragments::NotRightmost;
+                subPosition = isRightmostOrAdjacent ? FragmentPositionInRootFragments::AdjacentToRightmost : FragmentPositionInRootFragments::Other;
             if (fragment->pseudoElementSelector && isScrollbarPseudoElement(fragment->pseudoElementSelector->pseudoElementType()))
                 functionType = mostRestrictiveFunctionType(functionType, addScrollbarPseudoClassType(*selector, *fragment));
             else {
@@ -1016,7 +1024,10 @@ static FunctionType constructFragmentsInternal(const CSSSelector* rootSelector,
         fragment->relationToLeftFragment = fragmentRelationForSelectorRelation(relation);
         fragment->relationToRightFragment = relationToPreviousFragment;
         fragment->positionInRootFragments = positionInRootFragments;
+        fragment->isRightmostOrAdjacent = isRightmostOrAdjacent;
         relationToPreviousFragment = fragment->relationToLeftFragment;
+        if (relationToPreviousFragment != FragmentRelation::Rightmost && relationToPreviousFragment != FragmentRelation::DirectAdjacent && relationToPreviousFragment != FragmentRelation::IndirectAdjacent)
+            isRightmostOrAdjacent = false;
 
         if (fragmentLevel != FragmentsLevel::Root)
             fragment->onlyMatchesLinksInQuirksMode = false;
@@ -3491,7 +3502,10 @@ void SelectorCodeGenerator::generateElementIsNthChild(Assembler::JumpList& failu
     {
         LocalRegister parentElement(m_registerAllocator);
         generateWalkToParentElement(failureCases, parentElement);
-        generateAddStyleRelationIfResolvingStyle(parentElement, Style::Relation::ChildrenAffectedByForwardPositionalRules);
+        auto relation = fragmentMatchesRightmostOrAdjacentElement(fragment)
+            ? Style::Relation::ChildrenAffectedByForwardPositionalRules
+            : Style::Relation::DescendantsAffectedByForwardPositionalRules;
+        generateAddStyleRelationIfResolvingStyle(parentElement, relation);
     }
 
     Vector<std::pair<int, int>, 32> validSubsetFilters;
@@ -3551,7 +3565,10 @@ void SelectorCodeGenerator::generateElementIsNthChildOf(Assembler::JumpList& fai
     {
         LocalRegister parentElement(m_registerAllocator);
         generateWalkToParentElement(failureCases, parentElement);
-        generateAddStyleRelationIfResolvingStyle(parentElement, Style::Relation::ChildrenAffectedByForwardPositionalRules);
+        auto relation = fragmentMatchesRightmostOrAdjacentElement(fragment)
+            ? Style::Relation::ChildrenAffectedByForwardPositionalRules
+            : Style::Relation::DescendantsAffectedByForwardPositionalRules;
+        generateAddStyleRelationIfResolvingStyle(parentElement, relation);
     }
 
     // The initial element must match the selector list.
@@ -3604,7 +3621,10 @@ void SelectorCodeGenerator::generateElementIsNthLastChild(Assembler::JumpList& f
         LocalRegister parentElement(m_registerAllocator);
         generateWalkToParentElement(failureCases, parentElement);
 
-        generateAddStyleRelationIfResolvingStyle(parentElement, Style::Relation::ChildrenAffectedByBackwardPositionalRules);
+        auto relation = fragmentMatchesRightmostOrAdjacentElement(fragment)
+            ? Style::Relation::ChildrenAffectedByBackwardPositionalRules
+            : Style::Relation::DescendantsAffectedByBackwardPositionalRules;
+        generateAddStyleRelationIfResolvingStyle(parentElement, relation);
 
         failureCases.append(m_assembler.branchTest32(Assembler::Zero, Assembler::Address(parentElement, Node::nodeFlagsMemoryOffset()), Assembler::TrustedImm32(Node::flagIsParsingChildrenFinished())));
 
index 31f17d9..5768c46 100644 (file)
@@ -2014,6 +2014,43 @@ static void checkForEmptyStyleChange(Element& element)
     }
 }
 
+
+static void invalidateForForwardPositionalRules(Element& parent, Element* elementAfterChange)
+{
+    bool childrenAffected = parent.childrenAffectedByForwardPositionalRules();
+    bool descendantsAffected = parent.descendantsAffectedByForwardPositionalRules();
+
+    if (!childrenAffected && !descendantsAffected)
+        return;
+
+    for (auto* sibling = elementAfterChange; sibling; sibling = sibling->nextElementSibling()) {
+        if (childrenAffected)
+            sibling->invalidateStyleInternal();
+        if (descendantsAffected) {
+            for (auto* siblingChild = sibling->firstElementChild(); siblingChild; siblingChild = siblingChild->nextElementSibling())
+                siblingChild->invalidateStyleForSubtreeInternal();
+        }
+    }
+}
+
+static void invalidateForBackwardPositionalRules(Element& parent, Element* elementBeforeChange)
+{
+    bool childrenAffected = parent.childrenAffectedByBackwardPositionalRules();
+    bool descendantsAffected = parent.descendantsAffectedByBackwardPositionalRules();
+
+    if (!childrenAffected && !descendantsAffected)
+        return;
+
+    for (auto* sibling = elementBeforeChange; sibling; sibling = sibling->previousElementSibling()) {
+        if (childrenAffected)
+            sibling->invalidateStyleInternal();
+        if (descendantsAffected) {
+            for (auto* siblingChild = sibling->firstElementChild(); siblingChild; siblingChild = siblingChild->nextElementSibling())
+                siblingChild->invalidateStyleForSubtreeInternal();
+        }
+    }
+}
+
 enum SiblingCheckType { FinishedParsingChildren, SiblingElementRemoved, Other };
 
 static void checkForSiblingStyleChanges(Element& parent, SiblingCheckType checkType, Element* elementBeforeChange, Element* elementAfterChange)
@@ -2070,17 +2107,8 @@ static void checkForSiblingStyleChanges(Element& parent, SiblingCheckType checkT
 
     invalidateForSiblingCombinators(elementAfterChange);
 
-    // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
-    // backward case.
-    if (parent.childrenAffectedByForwardPositionalRules()) {
-        for (auto* next = elementAfterChange; next; next = next->nextElementSibling())
-            next->invalidateStyleForSubtreeInternal();
-    }
-    // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
-    if (parent.childrenAffectedByBackwardPositionalRules()) {
-        for (auto* previous = elementBeforeChange; previous; previous = previous->previousElementSibling())
-            previous->invalidateStyleForSubtreeInternal();
-    }
+    invalidateForForwardPositionalRules(parent, elementAfterChange);
+    invalidateForBackwardPositionalRules(parent, elementBeforeChange);
 }
 
 void Element::childrenChanged(const ChildChange& change)
@@ -2815,11 +2843,21 @@ void Element::setChildrenAffectedByForwardPositionalRules()
     ensureElementRareData().setChildrenAffectedByForwardPositionalRules(true);
 }
 
+void Element::setDescendantsAffectedByForwardPositionalRules()
+{
+    ensureElementRareData().setDescendantsAffectedByForwardPositionalRules(true);
+}
+
 void Element::setChildrenAffectedByBackwardPositionalRules()
 {
     ensureElementRareData().setChildrenAffectedByBackwardPositionalRules(true);
 }
 
+void Element::setDescendantsAffectedByBackwardPositionalRules()
+{
+    ensureElementRareData().setDescendantsAffectedByBackwardPositionalRules(true);
+}
+
 void Element::setChildrenAffectedByPropertyBasedBackwardPositionalRules()
 {
     ensureElementRareData().setChildrenAffectedByPropertyBasedBackwardPositionalRules(true);
@@ -2841,7 +2879,9 @@ bool Element::hasFlagsSetDuringStylingOfChildren() const
     return rareDataStyleAffectedByActive()
         || rareDataChildrenAffectedByDrag()
         || rareDataChildrenAffectedByForwardPositionalRules()
+        || rareDataDescendantsAffectedByForwardPositionalRules()
         || rareDataChildrenAffectedByBackwardPositionalRules()
+        || rareDataDescendantsAffectedByBackwardPositionalRules()
         || rareDataChildrenAffectedByPropertyBasedBackwardPositionalRules();
 }
 
@@ -2875,12 +2915,24 @@ bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
     return elementRareData()->childrenAffectedByForwardPositionalRules();
 }
 
+bool Element::rareDataDescendantsAffectedByForwardPositionalRules() const
+{
+    ASSERT(hasRareData());
+    return elementRareData()->descendantsAffectedByForwardPositionalRules();
+}
+
 bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
 {
     ASSERT(hasRareData());
     return elementRareData()->childrenAffectedByBackwardPositionalRules();
 }
 
+bool Element::rareDataDescendantsAffectedByBackwardPositionalRules() const
+{
+    ASSERT(hasRareData());
+    return elementRareData()->descendantsAffectedByBackwardPositionalRules();
+}
+
 bool Element::rareDataChildrenAffectedByPropertyBasedBackwardPositionalRules() const
 {
     ASSERT(hasRareData());
index 38f2487..aa17815 100644 (file)
@@ -333,7 +333,9 @@ public:
     bool childrenAffectedByFirstChildRules() const { return getFlag(ChildrenAffectedByFirstChildRulesFlag); }
     bool childrenAffectedByLastChildRules() const { return getFlag(ChildrenAffectedByLastChildRulesFlag); }
     bool childrenAffectedByForwardPositionalRules() const { return hasRareData() && rareDataChildrenAffectedByForwardPositionalRules(); }
+    bool descendantsAffectedByForwardPositionalRules() const { return hasRareData() && rareDataDescendantsAffectedByForwardPositionalRules(); }
     bool childrenAffectedByBackwardPositionalRules() const { return hasRareData() && rareDataChildrenAffectedByBackwardPositionalRules(); }
+    bool descendantsAffectedByBackwardPositionalRules() const { return hasRareData() && rareDataDescendantsAffectedByBackwardPositionalRules(); }
     bool childrenAffectedByPropertyBasedBackwardPositionalRules() const { return hasRareData() && rareDataChildrenAffectedByPropertyBasedBackwardPositionalRules(); }
     bool affectsNextSiblingElementStyle() const { return getFlag(AffectsNextSiblingElementStyle); }
     unsigned childIndex() const { return hasRareData() ? rareDataChildIndex() : 0; }
@@ -349,7 +351,9 @@ public:
     void setChildrenAffectedByFirstChildRules() { setFlag(ChildrenAffectedByFirstChildRulesFlag); }
     void setChildrenAffectedByLastChildRules() { setFlag(ChildrenAffectedByLastChildRulesFlag); }
     void setChildrenAffectedByForwardPositionalRules();
+    void setDescendantsAffectedByForwardPositionalRules();
     void setChildrenAffectedByBackwardPositionalRules();
+    void setDescendantsAffectedByBackwardPositionalRules();
     void setChildrenAffectedByPropertyBasedBackwardPositionalRules();
     void setAffectsNextSiblingElementStyle() { setFlag(AffectsNextSiblingElementStyle); }
     void setStyleIsAffectedByPreviousSibling() { setFlag(StyleIsAffectedByPreviousSibling); }
@@ -653,7 +657,9 @@ private:
     bool rareDataChildrenAffectedByDrag() const;
     bool rareDataChildrenAffectedByLastChildRules() const;
     bool rareDataChildrenAffectedByForwardPositionalRules() const;
+    bool rareDataDescendantsAffectedByForwardPositionalRules() const;
     bool rareDataChildrenAffectedByBackwardPositionalRules() const;
+    bool rareDataDescendantsAffectedByBackwardPositionalRules() const;
     bool rareDataChildrenAffectedByPropertyBasedBackwardPositionalRules() const;
     unsigned rareDataChildIndex() const;
 
index e6a8ad0..a0f301e 100644 (file)
@@ -72,8 +72,12 @@ public:
     void setChildrenAffectedByLastChildRules(bool value) { m_childrenAffectedByLastChildRules = value; }
     bool childrenAffectedByForwardPositionalRules() const { return m_childrenAffectedByForwardPositionalRules; }
     void setChildrenAffectedByForwardPositionalRules(bool value) { m_childrenAffectedByForwardPositionalRules = value; }
+    bool descendantsAffectedByForwardPositionalRules() const { return m_descendantsAffectedByForwardPositionalRules; }
+    void setDescendantsAffectedByForwardPositionalRules(bool value) { m_descendantsAffectedByForwardPositionalRules = value; }
     bool childrenAffectedByBackwardPositionalRules() const { return m_childrenAffectedByBackwardPositionalRules; }
     void setChildrenAffectedByBackwardPositionalRules(bool value) { m_childrenAffectedByBackwardPositionalRules = value; }
+    bool descendantsAffectedByBackwardPositionalRules() const { return m_descendantsAffectedByBackwardPositionalRules; }
+    void setDescendantsAffectedByBackwardPositionalRules(bool value) { m_descendantsAffectedByBackwardPositionalRules = value; }
     bool childrenAffectedByPropertyBasedBackwardPositionalRules() const { return m_childrenAffectedByPropertyBasedBackwardPositionalRules; }
     void setChildrenAffectedByPropertyBasedBackwardPositionalRules(bool value) { m_childrenAffectedByPropertyBasedBackwardPositionalRules = value; }
 
@@ -131,7 +135,9 @@ private:
     // *-child-of-type, we will just give up and re-evaluate whenever children change at all.
     unsigned m_childrenAffectedByLastChildRules : 1;
     unsigned m_childrenAffectedByForwardPositionalRules : 1;
+    unsigned m_descendantsAffectedByForwardPositionalRules : 1;
     unsigned m_childrenAffectedByBackwardPositionalRules : 1;
+    unsigned m_descendantsAffectedByBackwardPositionalRules : 1;
     unsigned m_childrenAffectedByPropertyBasedBackwardPositionalRules : 1;
 
     LayoutSize m_minimumSizeForResizing;
@@ -172,7 +178,9 @@ inline ElementRareData::ElementRareData(RenderElement* renderer)
     , m_childrenAffectedByDrag(false)
     , m_childrenAffectedByLastChildRules(false)
     , m_childrenAffectedByForwardPositionalRules(false)
+    , m_descendantsAffectedByForwardPositionalRules(false)
     , m_childrenAffectedByBackwardPositionalRules(false)
+    , m_descendantsAffectedByBackwardPositionalRules(false)
     , m_childrenAffectedByPropertyBasedBackwardPositionalRules(false)
     , m_minimumSizeForResizing(defaultMinimumSizeForResizing())
 {
@@ -211,7 +219,9 @@ inline void ElementRareData::resetStyleRelations()
     setChildrenAffectedByDrag(false);
     setChildrenAffectedByLastChildRules(false);
     setChildrenAffectedByForwardPositionalRules(false);
+    setDescendantsAffectedByForwardPositionalRules(false);
     setChildrenAffectedByBackwardPositionalRules(false);
+    setDescendantsAffectedByBackwardPositionalRules(false);
     setChildrenAffectedByPropertyBasedBackwardPositionalRules(false);
 }
 
index 5e9fa76..4d8148b 100644 (file)
@@ -78,7 +78,9 @@ std::unique_ptr<Relations> commitRelationsToRenderStyle(RenderStyle& style, cons
         case Relation::DescendantsAffectedByPreviousSibling:
         case Relation::AffectsNextSibling:
         case Relation::ChildrenAffectedByForwardPositionalRules:
+        case Relation::DescendantsAffectedByForwardPositionalRules:
         case Relation::ChildrenAffectedByBackwardPositionalRules:
+        case Relation::DescendantsAffectedByBackwardPositionalRules:
         case Relation::ChildrenAffectedByFirstChildRules:
         case Relation::ChildrenAffectedByPropertyBasedBackwardPositionalRules:
         case Relation::ChildrenAffectedByLastChildRules:
@@ -127,9 +129,15 @@ void commitRelations(std::unique_ptr<Relations> relations, Update& update)
         case Relation::ChildrenAffectedByForwardPositionalRules:
             element.setChildrenAffectedByForwardPositionalRules();
             break;
+        case Relation::DescendantsAffectedByForwardPositionalRules:
+            element.setDescendantsAffectedByForwardPositionalRules();
+            break;
         case Relation::ChildrenAffectedByBackwardPositionalRules:
             element.setChildrenAffectedByBackwardPositionalRules();
             break;
+        case Relation::DescendantsAffectedByBackwardPositionalRules:
+            element.setDescendantsAffectedByBackwardPositionalRules();
+            break;
         case Relation::ChildrenAffectedByFirstChildRules:
             element.setChildrenAffectedByFirstChildRules();
             break;
index fb1b5dc..0c9b76b 100644 (file)
@@ -47,8 +47,10 @@ struct Relation {
         DescendantsAffectedByPreviousSibling,
         // For AffectsNextSibling 'value' tells how many element siblings to mark starting with 'element'.
         AffectsNextSibling,
-        ChildrenAffectedByForwardPositionalRules, 
+        ChildrenAffectedByForwardPositionalRules,
+        DescendantsAffectedByForwardPositionalRules,
         ChildrenAffectedByBackwardPositionalRules,
+        DescendantsAffectedByBackwardPositionalRules,
         ChildrenAffectedByFirstChildRules,
         ChildrenAffectedByPropertyBasedBackwardPositionalRules,
         ChildrenAffectedByLastChildRules,