WebKit Bugzilla
Attachment 349116 Details for
Bug 166748
: :first-child, :last-child, :nth-child, and :nth-of-type don't work on shadow root's children
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP
wip166748.patch (text/plain), 36.42 KB, created by
Ryosuke Niwa
on 2018-09-07 00:19:14 PDT
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Ryosuke Niwa
Created:
2018-09-07 00:19:14 PDT
Size:
36.42 KB
patch
obsolete
>Index: Source/WebCore/css/SelectorChecker.cpp >=================================================================== >--- Source/WebCore/css/SelectorChecker.cpp (revision 235780) >+++ Source/WebCore/css/SelectorChecker.cpp (working copy) >@@ -736,44 +736,58 @@ > > return result; > } >- case CSSSelector::PseudoClassFirstChild: >+ case CSSSelector::PseudoClassFirstChild: { > // first-child matches the first child that is an element >- if (const Element* parentElement = element.parentElement()) { >- bool isFirstChild = isFirstChildElement(element); >- if (isFirstChild) >- addStyleRelation(checkingContext, element, Style::Relation::FirstChild); >- addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByFirstChildRules); >- return isFirstChild; >- } >- break; >- case CSSSelector::PseudoClassFirstOfType: >+ bool isFirstChild = isFirstChildElement(element); >+ auto* parent = element.parentNode(); >+ if (is<Element>(parent)) >+ addStyleRelation(checkingContext, downcast<Element>(*parent), Style::Relation::ChildrenAffectedByFirstChildRules); >+ else if (!is<ShadowRoot>(parent)) >+ break; // FIXME: Add the support for specifying relations on ShadowRoot. >+ if (!isFirstChild) >+ break; >+ addStyleRelation(checkingContext, element, Style::Relation::FirstChild); >+ return true; >+ } >+ case CSSSelector::PseudoClassFirstOfType: { > // first-of-type matches the first element of its type >- if (auto* parentElement = element.parentElement()) { >+ auto* parent = element.parentNode(); >+ if (is<Element>(parent)) { > auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules; >- addStyleRelation(checkingContext, *parentElement, relation); >- return isFirstOfType(element, element.tagQName()); >- } >- break; >- case CSSSelector::PseudoClassLastChild: >+ addStyleRelation(checkingContext, downcast<Element>(*parent), relation); >+ } else if (!is<ShadowRoot>(parent)) >+ break; // FIXME: Add the support for specifying relations on ShadowRoot. >+ return isFirstOfType(element, element.tagQName()); >+ } >+ case CSSSelector::PseudoClassLastChild: { > // last-child matches the last child that is an element >- if (const Element* parentElement = element.parentElement()) { >- bool isLastChild = parentElement->isFinishedParsingChildren() && isLastChildElement(element); >- if (isLastChild) >- addStyleRelation(checkingContext, element, Style::Relation::LastChild); >- addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByLastChildRules); >- return isLastChild; >- } >- break; >- case CSSSelector::PseudoClassLastOfType: >+ auto* parent = element.parentNode(); >+ bool isLastChild = isLastChildElement(element); >+ if (is<Element>(parent)) { >+ auto& parentElement = downcast<Element>(*parent); >+ if (!parentElement.isFinishedParsingChildren()) >+ isLastChild = false; >+ addStyleRelation(checkingContext, parentElement, Style::Relation::ChildrenAffectedByLastChildRules); >+ } else if (!is<ShadowRoot>(parent)) >+ break; // FIXME: Add the support for specifying relations on ShadowRoot. >+ if (!isLastChild) >+ break; >+ addStyleRelation(checkingContext, element, Style::Relation::LastChild); >+ return true; >+ } >+ case CSSSelector::PseudoClassLastOfType: { > // last-of-type matches the last element of its type >- if (Element* parentElement = element.parentElement()) { >+ auto* parent = element.parentNode(); >+ if (is<Element>(parent)) { >+ auto& parentElement = downcast<Element>(*parent); > auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules; >- addStyleRelation(checkingContext, *parentElement, relation); >- if (!parentElement->isFinishedParsingChildren()) >+ addStyleRelation(checkingContext, parentElement, relation); >+ if (!parentElement.isFinishedParsingChildren()) > return false; >- return isLastOfType(element, element.tagQName()); >- } >- break; >+ } else if (!is<ShadowRoot>(parent)) >+ break; // FIXME: Add the support for specifying relations on ShadowRoot. >+ return isLastOfType(element, element.tagQName()); >+ } > case CSSSelector::PseudoClassOnlyChild: > if (Element* parentElement = element.parentElement()) { > bool firstChild = isFirstChildElement(element); >@@ -787,18 +801,22 @@ > return onlyChild; > } > break; >- case CSSSelector::PseudoClassOnlyOfType: >+ case CSSSelector::PseudoClassOnlyOfType: { > // FIXME: This selector is very slow. >- if (Element* parentElement = element.parentElement()) { >+ auto* parent = element.parentNode(); >+ if (is<Element>(parent)) { >+ auto& parentElement = downcast<Element>(*parent); > auto forwardRelation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules; >- addStyleRelation(checkingContext, *parentElement, forwardRelation); >+ addStyleRelation(checkingContext, parentElement, forwardRelation); > auto backwardRelation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules; >- addStyleRelation(checkingContext, *parentElement, backwardRelation); >- if (!parentElement->isFinishedParsingChildren()) >+ addStyleRelation(checkingContext, parentElement, backwardRelation); >+ >+ if (!parentElement.isFinishedParsingChildren()) > return false; >- return isFirstOfType(element, element.tagQName()) && isLastOfType(element, element.tagQName()); >- } >- break; >+ } else if (!is<ShadowRoot>(parent)) >+ break; // FIXME: Add the support for specifying relations on ShadowRoot. >+ return isFirstOfType(element, element.tagQName()) && isLastOfType(element, element.tagQName()); >+ } > case CSSSelector::PseudoClassMatches: > { > bool hasMatchedAnything = false; >@@ -836,46 +854,54 @@ > return downcast<HTMLTextFormControlElement>(element).isPlaceholderVisible(); > } > return false; >- case CSSSelector::PseudoClassNthChild: >- if (auto* parentElement = element.parentElement()) { >+ case CSSSelector::PseudoClassNthChild: { >+ auto* parent = element.parentNode(); >+ if (is<Element>(parent)) { > auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules; >- addStyleRelation(checkingContext, *parentElement, relation); >+ addStyleRelation(checkingContext, downcast<Element>(*parent), relation); >+ } else if (!is<ShadowRoot>(parent)) >+ break; // FIXME: Add the support for specifying relations on ShadowRoot. > >- if (const CSSSelectorList* selectorList = selector.selectorList()) { >- unsigned selectorListSpecificity; >- if (!matchSelectorList(checkingContext, context, element, *selectorList, selectorListSpecificity)) >- return false; >- specificity = CSSSelector::addSpecificities(specificity, selectorListSpecificity); >- } >+ if (const CSSSelectorList* selectorList = selector.selectorList()) { >+ unsigned selectorListSpecificity; >+ if (!matchSelectorList(checkingContext, context, element, *selectorList, selectorListSpecificity)) >+ return false; >+ specificity = CSSSelector::addSpecificities(specificity, selectorListSpecificity); >+ } > >- int count = 1; >- if (const CSSSelectorList* selectorList = selector.selectorList()) { >- for (Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) { >- unsigned ignoredSpecificity; >- if (matchSelectorList(checkingContext, context, *sibling, *selectorList, ignoredSpecificity)) >- ++count; >- } >- } else { >- count += countElementsBefore(element); >- addStyleRelation(checkingContext, element, Style::Relation::NthChildIndex, count); >+ int count = 1; >+ if (const CSSSelectorList* selectorList = selector.selectorList()) { >+ for (Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) { >+ unsigned ignoredSpecificity; >+ if (matchSelectorList(checkingContext, context, *sibling, *selectorList, ignoredSpecificity)) >+ ++count; > } >+ } else { >+ count += countElementsBefore(element); >+ addStyleRelation(checkingContext, element, Style::Relation::NthChildIndex, count); >+ } > >- if (selector.matchNth(count)) >- return true; >- } >+ if (selector.matchNth(count)) >+ return true; > break; >- case CSSSelector::PseudoClassNthOfType: >- if (auto* parentElement = element.parentElement()) { >+ } >+ case CSSSelector::PseudoClassNthOfType: { >+ auto* parent = element.parentNode(); >+ if (is<Element>(parent)) { > auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByForwardPositionalRules : Style::Relation::DescendantsAffectedByForwardPositionalRules; >- addStyleRelation(checkingContext, *parentElement, relation); >+ addStyleRelation(checkingContext, downcast<Element>(*parent), relation); >+ } else if (!is<ShadowRoot>(parent)) >+ break; // FIXME: Add the support for specifying relations on ShadowRoot. > >- int count = 1 + countElementsOfTypeBefore(element, element.tagQName()); >- if (selector.matchNth(count)) >- return true; >- } >+ int count = 1 + countElementsOfTypeBefore(element, element.tagQName()); >+ if (selector.matchNth(count)) >+ return true; > break; >- case CSSSelector::PseudoClassNthLastChild: >- if (Element* parentElement = element.parentElement()) { >+ } >+ case CSSSelector::PseudoClassNthLastChild: { >+ auto* parent = element.parentNode(); >+ if (is<Element>(parent)) { >+ auto& parentElement = downcast<Element>(*parent); > if (const CSSSelectorList* selectorList = selector.selectorList()) { > unsigned selectorListSpecificity; > if (!matchSelectorList(checkingContext, context, element, *selectorList, selectorListSpecificity)) >@@ -882,42 +908,42 @@ > return false; > specificity = CSSSelector::addSpecificities(specificity, selectorListSpecificity); > >- addStyleRelation(checkingContext, *parentElement, Style::Relation::ChildrenAffectedByPropertyBasedBackwardPositionalRules); >+ addStyleRelation(checkingContext, parentElement, Style::Relation::ChildrenAffectedByPropertyBasedBackwardPositionalRules); > } else { > auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules; >- addStyleRelation(checkingContext, *parentElement, relation); >+ addStyleRelation(checkingContext, parentElement, relation); > } >- >- if (!parentElement->isFinishedParsingChildren()) >+ if (!parentElement.isFinishedParsingChildren()) > return false; >+ } else if (!is<ShadowRoot>(parent)) >+ break; // FIXME: Add the support for specifying relations on ShadowRoot. > >- int count = 1; >- if (const CSSSelectorList* selectorList = selector.selectorList()) { >- for (Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling)) { >- unsigned ignoredSpecificity; >- if (matchSelectorList(checkingContext, context, *sibling, *selectorList, ignoredSpecificity)) >- ++count; >- } >- } else >- count += countElementsAfter(element); >+ int count = 1; >+ if (const CSSSelectorList* selectorList = selector.selectorList()) { >+ for (Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling)) { >+ unsigned ignoredSpecificity; >+ if (matchSelectorList(checkingContext, context, *sibling, *selectorList, ignoredSpecificity)) >+ ++count; >+ } >+ } else >+ count += countElementsAfter(element); > >- if (selector.matchNth(count)) >- return true; >- } >- break; >- case CSSSelector::PseudoClassNthLastOfType: >- if (Element* parentElement = element.parentElement()) { >+ return selector.matchNth(count); >+ } >+ case CSSSelector::PseudoClassNthLastOfType: { >+ auto* parent = element.parentNode(); >+ if (is<Element>(parent)) { >+ auto& parentElement = downcast<Element>(*parent); > auto relation = context.isSubjectOrAdjacentElement ? Style::Relation::ChildrenAffectedByBackwardPositionalRules : Style::Relation::DescendantsAffectedByBackwardPositionalRules; >- addStyleRelation(checkingContext, *parentElement, relation); >+ addStyleRelation(checkingContext, parentElement, relation); > >- if (!parentElement->isFinishedParsingChildren()) >+ if (!parentElement.isFinishedParsingChildren()) > return false; >- >- int count = 1 + countElementsOfTypeAfter(element, element.tagQName()); >- if (selector.matchNth(count)) >- return true; >- } >- break; >+ } else if (!is<ShadowRoot>(parent)) >+ break; // FIXME: Add the support for specifying relations on ShadowRoot. >+ int count = 1 + countElementsOfTypeAfter(element, element.tagQName()); >+ return selector.matchNth(count); >+ } > case CSSSelector::PseudoClassTarget: > if (&element == element.document().cssTarget()) > return true; >Index: Source/WebCore/cssjit/SelectorCompiler.cpp >=================================================================== >--- Source/WebCore/cssjit/SelectorCompiler.cpp (revision 235780) >+++ Source/WebCore/cssjit/SelectorCompiler.cpp (working copy) >@@ -345,6 +345,9 @@ > Assembler::Jump modulo(JSC::MacroAssembler::ResultCondition, Assembler::RegisterID inputDividend, int divisor); > void moduloIsZero(Assembler::JumpList& failureCases, Assembler::RegisterID inputDividend, int divisor); > >+ void generateNthChildParentCheckAndRelationUpdate(Assembler::JumpList& failureCases, const SelectorFragment&); >+ void generateNthLastChildParentCheckAndRelationUpdate(Assembler::JumpList& failureCases, const SelectorFragment&); >+ > void pushMacroAssemblerRegisters(); > void popMacroAssemblerRegisters(StackAllocator&); > bool generatePrologue(); >@@ -3170,9 +3173,6 @@ > return; > } > >- Assembler::RegisterID parentElement = m_registerAllocator.allocateRegister(); >- generateWalkToParentElement(failureCases, parentElement); >- > // Zero in isFirstChildRegister is the success case. The register is set to non-zero if a sibling if found. > LocalRegister isFirstChildRegister(m_registerAllocator); > m_assembler.move(Assembler::TrustedImm32(0), isFirstChildRegister); >@@ -3186,20 +3186,37 @@ > successCase.link(&m_assembler); > } > >+ Assembler::RegisterID parentNode = m_registerAllocator.allocateRegister(); >+ generateWalkToParentNode(parentNode); >+ failureCases.append(m_assembler.branchTestPtr(Assembler::Zero, parentNode)); >+ Assembler::Jump notElement = DOMJIT::branchTestIsElementFlagOnNode(m_assembler, Assembler::Zero, parentNode); >+ > LocalRegister checkingContext(m_registerAllocator); > Assembler::Jump notResolvingStyle = jumpIfNotResolvingStyle(checkingContext); >+ Assembler::JumpList successCases; > >- generateAddStyleRelation(checkingContext, parentElement, Style::Relation::ChildrenAffectedByFirstChildRules); >- m_registerAllocator.deallocateRegister(parentElement); >- >+ generateAddStyleRelation(checkingContext, parentNode, Style::Relation::ChildrenAffectedByFirstChildRules); > // The parent marking is unconditional. If the matching is not a success, we can now fail. > // Otherwise we need to apply setFirstChildState() on the RenderStyle. >+ Assembler::Label checkWithRelation(m_assembler.label()); > failureCases.append(m_assembler.branchTest32(Assembler::NonZero, isFirstChildRegister)); >- > generateAddStyleRelation(checkingContext, elementAddressRegister, Style::Relation::FirstChild); >+ successCases.append(m_assembler.jump()); > >+ Assembler::Label checkWithoutRelation(m_assembler.label()); > notResolvingStyle.link(&m_assembler); > failureCases.append(m_assembler.branchTest32(Assembler::NonZero, isFirstChildRegister)); >+ successCases.append(m_assembler.jump()); >+ >+ // Go back to checkWithRelation or checkWithoutRelation if it's a ShadowRoot. >+ notElement.link(&m_assembler); >+ failureCases.append(DOMJIT::branchTestIsShadowRootFlagOnNode(m_assembler, Assembler::Zero, parentNode)); >+ jumpIfNotResolvingStyle(checkingContext).linkTo(checkWithRelation, &m_assembler); >+ m_assembler.jump().linkTo(checkWithoutRelation, &m_assembler); >+ >+ m_registerAllocator.deallocateRegister(parentNode); >+ >+ successCases.link(&m_assembler); > } > > static bool elementIsHovered(const Element* element) >@@ -3264,8 +3281,9 @@ > return; > } > >- Assembler::RegisterID parentElement = m_registerAllocator.allocateRegister(); >- generateWalkToParentElement(failureCases, parentElement); >+ Assembler::RegisterID parentNode = m_registerAllocator.allocateRegister(); >+ generateWalkToParentNode(parentNode); >+ failureCases.append(m_assembler.branchTestPtr(Assembler::Zero, parentNode)); > > // Zero in isLastChildRegister is the success case. The register is set to non-zero if a sibling if found. > LocalRegister isLastChildRegister(m_registerAllocator); >@@ -3272,7 +3290,7 @@ > m_assembler.move(Assembler::TrustedImm32(0), isLastChildRegister); > > { >- Assembler::Jump notFinishedParsingChildren = m_assembler.branchTest32(Assembler::Zero, Assembler::Address(parentElement, Node::nodeFlagsMemoryOffset()), Assembler::TrustedImm32(Node::flagIsParsingChildrenFinished())); >+ Assembler::Jump notFinishedParsingChildren = m_assembler.branchTest32(Assembler::Zero, Assembler::Address(parentNode, Node::nodeFlagsMemoryOffset()), Assembler::TrustedImm32(Node::flagIsParsingChildrenFinished())); > > Assembler::JumpList successCase = jumpIfNoNextAdjacentElement(); > >@@ -3282,20 +3300,34 @@ > successCase.link(&m_assembler); > } > >+ Assembler::Jump notElement = DOMJIT::branchTestIsElementFlagOnNode(m_assembler, Assembler::Zero, parentNode); >+ > LocalRegister checkingContext(m_registerAllocator); > Assembler::Jump notResolvingStyle = jumpIfNotResolvingStyle(checkingContext); >+ Assembler::JumpList successCases; > >- generateAddStyleRelation(checkingContext, parentElement, Style::Relation::ChildrenAffectedByLastChildRules); >- m_registerAllocator.deallocateRegister(parentElement); >- >+ generateAddStyleRelation(checkingContext, parentNode, Style::Relation::ChildrenAffectedByLastChildRules); > // The parent marking is unconditional. If the matching is not a success, we can now fail. > // Otherwise we need to apply setLastChildState() on the RenderStyle. >+ Assembler::Label checkWithRelation(m_assembler.label()); > failureCases.append(m_assembler.branchTest32(Assembler::NonZero, isLastChildRegister)); >- > generateAddStyleRelation(checkingContext, elementAddressRegister, Style::Relation::LastChild); >+ successCases.append(m_assembler.jump()); > >+ Assembler::Label checkWithoutRelation(m_assembler.label()); > notResolvingStyle.link(&m_assembler); > failureCases.append(m_assembler.branchTest32(Assembler::NonZero, isLastChildRegister)); >+ successCases.append(m_assembler.jump()); >+ >+ // Go back to checkWithRelation or checkWithoutRelation if it's a ShadowRoot. >+ notElement.link(&m_assembler); >+ failureCases.append(DOMJIT::branchTestIsShadowRootFlagOnNode(m_assembler, Assembler::Zero, parentNode)); >+ jumpIfNotResolvingStyle(checkingContext).linkTo(checkWithRelation, &m_assembler); >+ m_assembler.jump().linkTo(checkWithoutRelation, &m_assembler); >+ >+ m_registerAllocator.deallocateRegister(parentNode); >+ >+ successCases.link(&m_assembler); > } > > void SelectorCodeGenerator::generateElementIsOnlyChild(Assembler::JumpList& failureCases) >@@ -3500,16 +3532,29 @@ > return false; > } > >+void SelectorCodeGenerator::generateNthChildParentCheckAndRelationUpdate(Assembler::JumpList& failureCases, const SelectorFragment& fragment) >+{ >+ LocalRegister parentNode(m_registerAllocator); >+ generateWalkToParentNode(parentNode); >+ failureCases.append(m_assembler.branchTestPtr(Assembler::Zero, parentNode)); >+ Assembler::Jump notElement = DOMJIT::branchTestIsElementFlagOnNode(m_assembler, Assembler::Zero, parentNode); >+ >+ generateWalkToParentElement(failureCases, parentNode); >+ auto relation = fragmentMatchesRightmostOrAdjacentElement(fragment) >+ ? Style::Relation::ChildrenAffectedByForwardPositionalRules >+ : Style::Relation::DescendantsAffectedByForwardPositionalRules; >+ generateAddStyleRelationIfResolvingStyle(parentNode, relation); >+ Assembler::Jump parentNodeCheckEnd = m_assembler.jump(); >+ >+ notElement.link(&m_assembler); >+ failureCases.append(DOMJIT::branchTestIsShadowRootFlagOnNode(m_assembler, Assembler::Zero, parentNode)); >+ >+ parentNodeCheckEnd.link(&m_assembler); >+} >+ > void SelectorCodeGenerator::generateElementIsNthChild(Assembler::JumpList& failureCases, const SelectorFragment& fragment) > { >- { >- LocalRegister parentElement(m_registerAllocator); >- generateWalkToParentElement(failureCases, parentElement); >- auto relation = fragmentMatchesRightmostOrAdjacentElement(fragment) >- ? Style::Relation::ChildrenAffectedByForwardPositionalRules >- : Style::Relation::DescendantsAffectedByForwardPositionalRules; >- generateAddStyleRelationIfResolvingStyle(parentElement, relation); >- } >+ generateNthChildParentCheckAndRelationUpdate(failureCases, fragment); > > Vector<std::pair<int, int>, 32> validSubsetFilters; > validSubsetFilters.reserveInitialCapacity(fragment.nthChildFilters.size()); >@@ -3565,14 +3610,7 @@ > > void SelectorCodeGenerator::generateElementIsNthChildOf(Assembler::JumpList& failureCases, const SelectorFragment& fragment) > { >- { >- LocalRegister parentElement(m_registerAllocator); >- generateWalkToParentElement(failureCases, parentElement); >- auto relation = fragmentMatchesRightmostOrAdjacentElement(fragment) >- ? Style::Relation::ChildrenAffectedByForwardPositionalRules >- : Style::Relation::DescendantsAffectedByForwardPositionalRules; >- generateAddStyleRelationIfResolvingStyle(parentElement, relation); >- } >+ generateNthChildParentCheckAndRelationUpdate(failureCases, fragment); > > // The initial element must match the selector list. > for (const NthChildOfSelectorInfo& nthChildOfSelectorInfo : fragment.nthChildOfFilters) >@@ -3616,29 +3654,42 @@ > } > } > >+void SelectorCodeGenerator::generateNthLastChildParentCheckAndRelationUpdate(Assembler::JumpList& failureCases, const SelectorFragment& fragment) >+{ >+ LocalRegister parentNode(m_registerAllocator); >+ generateWalkToParentNode(parentNode); >+ failureCases.append(m_assembler.branchTestPtr(Assembler::Zero, parentNode)); >+ Assembler::Jump notElement = DOMJIT::branchTestIsElementFlagOnNode(m_assembler, Assembler::Zero, parentNode); >+ >+ generateWalkToParentElement(failureCases, parentNode); >+ auto relation = fragmentMatchesRightmostOrAdjacentElement(fragment) >+ ? Style::Relation::ChildrenAffectedByBackwardPositionalRules >+ : Style::Relation::DescendantsAffectedByBackwardPositionalRules; >+ generateAddStyleRelationIfResolvingStyle(parentNode, relation); >+ Assembler::Jump parentNodeCheckEnd = m_assembler.jump(); >+ >+ failureCases.append(m_assembler.branchTest32(Assembler::Zero, Assembler::Address(parentNode, Node::nodeFlagsMemoryOffset()), >+ Assembler::TrustedImm32(Node::flagIsParsingChildrenFinished()))); >+ >+ notElement.link(&m_assembler); >+ failureCases.append(DOMJIT::branchTestIsShadowRootFlagOnNode(m_assembler, Assembler::Zero, parentNode)); >+ >+ parentNodeCheckEnd.link(&m_assembler); >+} >+ > void SelectorCodeGenerator::generateElementIsNthLastChild(Assembler::JumpList& failureCases, const SelectorFragment& fragment) > { >+ generateNthLastChildParentCheckAndRelationUpdate(failureCases, fragment); >+ > Vector<std::pair<int, int>, 32> validSubsetFilters; > validSubsetFilters.reserveInitialCapacity(fragment.nthLastChildFilters.size()); >- { // :nth-last-child() must have a parent to match. If there is a parent, do the invalidation marking. >- LocalRegister parentElement(m_registerAllocator); >- generateWalkToParentElement(failureCases, parentElement); >- >- 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()))); >- >- for (const auto& slot : fragment.nthLastChildFilters) { >- if (nthFilterIsAlwaysSatisified(slot.first, slot.second)) >- continue; >- validSubsetFilters.uncheckedAppend(slot); >- } >- if (validSubsetFilters.isEmpty()) >- return; >+ for (const auto& slot : fragment.nthLastChildFilters) { >+ if (nthFilterIsAlwaysSatisified(slot.first, slot.second)) >+ continue; >+ validSubsetFilters.uncheckedAppend(slot); > } >+ if (validSubsetFilters.isEmpty()) >+ return; > > LocalRegister elementCounter(m_registerAllocator); > { // Loop over the following sibling elements and increment the counter. >@@ -3664,28 +3715,22 @@ > > void SelectorCodeGenerator::generateElementIsNthLastChildOf(Assembler::JumpList& failureCases, const SelectorFragment& fragment) > { >+ generateNthLastChildParentCheckAndRelationUpdate(failureCases, fragment); >+ > Vector<const NthChildOfSelectorInfo*> validSubsetFilters; > validSubsetFilters.reserveInitialCapacity(fragment.nthLastChildOfFilters.size()); >- { >- LocalRegister parentElement(m_registerAllocator); >- generateWalkToParentElement(failureCases, parentElement); > >- generateAddStyleRelationIfResolvingStyle(parentElement, Style::Relation::ChildrenAffectedByPropertyBasedBackwardPositionalRules); >- >- failureCases.append(m_assembler.branchTest32(Assembler::Zero, Assembler::Address(parentElement, Node::nodeFlagsMemoryOffset()), Assembler::TrustedImm32(Node::flagIsParsingChildrenFinished()))); >- >- // The initial element must match the selector list. >- for (const NthChildOfSelectorInfo& nthLastChildOfSelectorInfo : fragment.nthLastChildOfFilters) >- generateElementMatchesSelectorList(failureCases, elementAddressRegister, nthLastChildOfSelectorInfo.selectorList); >- >- for (const NthChildOfSelectorInfo& nthLastChildOfSelectorInfo : fragment.nthLastChildOfFilters) { >- if (nthFilterIsAlwaysSatisified(nthLastChildOfSelectorInfo.a, nthLastChildOfSelectorInfo.b)) >- continue; >- validSubsetFilters.uncheckedAppend(&nthLastChildOfSelectorInfo); >- } >- if (validSubsetFilters.isEmpty()) >- return; >+ // The initial element must match the selector list. >+ for (const NthChildOfSelectorInfo& nthLastChildOfSelectorInfo : fragment.nthLastChildOfFilters) >+ generateElementMatchesSelectorList(failureCases, elementAddressRegister, nthLastChildOfSelectorInfo.selectorList); >+ >+ for (const NthChildOfSelectorInfo& nthLastChildOfSelectorInfo : fragment.nthLastChildOfFilters) { >+ if (nthFilterIsAlwaysSatisified(nthLastChildOfSelectorInfo.a, nthLastChildOfSelectorInfo.b)) >+ continue; >+ validSubsetFilters.uncheckedAppend(&nthLastChildOfSelectorInfo); > } >+ if (validSubsetFilters.isEmpty()) >+ return; > > for (const NthChildOfSelectorInfo* nthLastChildOfSelectorInfo : validSubsetFilters) { > // Setup the counter at 1. >Index: Source/WebCore/domjit/DOMJITHelpers.h >=================================================================== >--- Source/WebCore/domjit/DOMJITHelpers.h (revision 235780) >+++ Source/WebCore/domjit/DOMJITHelpers.h (working copy) >@@ -179,6 +179,17 @@ > return jit.branchTest32(condition, CCallHelpers::Address(nodeAddress, Node::nodeFlagsMemoryOffset()), CCallHelpers::TrustedImm32(Node::flagIsElement())); > } > >+inline CCallHelpers::Jump branchTestIsShadowRootFlagOnNode(MacroAssembler& jit, CCallHelpers::ResultCondition condition, GPRReg nodeAddress) >+{ >+ return jit.branchTest32(condition, CCallHelpers::Address(nodeAddress, Node::nodeFlagsMemoryOffset()), CCallHelpers::TrustedImm32(Node::flagIsShadowRoot())); >+} >+ >+inline CCallHelpers::Jump branchTestIsElementOrShadowRootFlagOnNode(MacroAssembler& jit, CCallHelpers::ResultCondition condition, GPRReg nodeAddress) >+{ >+ return jit.branchTest32(condition, CCallHelpers::Address(nodeAddress, Node::nodeFlagsMemoryOffset()), >+ CCallHelpers::TrustedImm32(Node::flagIsShadowRoot() | Node::flagIsElement())); >+} >+ > inline CCallHelpers::Jump branchTestIsHTMLFlagOnNode(MacroAssembler& jit, CCallHelpers::ResultCondition condition, GPRReg nodeAddress) > { > return jit.branchTest32(condition, CCallHelpers::Address(nodeAddress, Node::nodeFlagsMemoryOffset()), CCallHelpers::TrustedImm32(Node::flagIsHTML())); >Index: LayoutTests/fast/shadow-dom/nth-node-on-shadow-child-expected.html >=================================================================== >--- LayoutTests/fast/shadow-dom/nth-node-on-shadow-child-expected.html (nonexistent) >+++ LayoutTests/fast/shadow-dom/nth-node-on-shadow-child-expected.html (working copy) >@@ -0,0 +1,7 @@ >+<!DOCTYPE html> >+<html> >+<body> >+ <p>Test passes if you see a single 100px by 100px green box below.</p> >+ <div style="width: 100px; height: 100px; background: green;"></div> >+</body> >+</html> >Index: LayoutTests/fast/shadow-dom/nth-node-on-shadow-child-no-jit-expected.html >=================================================================== >--- LayoutTests/fast/shadow-dom/nth-node-on-shadow-child-no-jit-expected.html (nonexistent) >+++ LayoutTests/fast/shadow-dom/nth-node-on-shadow-child-no-jit-expected.html (working copy) >@@ -0,0 +1,7 @@ >+<!DOCTYPE html> >+<html> >+<body> >+ <p>Test passes if you see a single 100px by 100px green box below.</p> >+ <div style="width: 100px; height: 100px; background: green;"></div> >+</body> >+</html> >Index: LayoutTests/fast/shadow-dom/nth-node-on-shadow-child-no-jit.html >=================================================================== >--- LayoutTests/fast/shadow-dom/nth-node-on-shadow-child-no-jit.html (nonexistent) >+++ LayoutTests/fast/shadow-dom/nth-node-on-shadow-child-no-jit.html (working copy) >@@ -0,0 +1,40 @@ >+<!DOCTYPE html> >+<html> >+<body> >+<p>Test passes if you see a single 100px by 100px green box below.</p> >+<script> >+const host = document.createElement('div'); >+ >+const shadowRoot = host.attachShadow({mode: 'closed'}); >+shadowRoot.innerHTML = ` >+<some-element class="item"> >+ :first-child >+ <style> >+ .item { display: block; width: 100px; height: 10px; background: red; color: green; font-size: 9px; overflow: hidden; } >+ :matches(noop, :first-child) { background: green; } >+ :matches(noop, div:nth-of-type(1)) { background: green; } >+ :matches(noop, div:nth-child(3)) { background: green; } >+ :matches(noop, .item:nth-last-child(7)) { background: green; } >+ :matches(noop, a-element:first-of-type) { background: green; } >+ :matches(noop, a-element:last-of-type) { background: green; } >+ :matches(noop, b-element:only-of-type) { background: green; } >+ :matches(noop, .item:only-child) { background: green; } >+ :matches(noop, c-element:nth-last-of-type(1)) { background: green; } >+ :matches(noop, .item:last-child) { background: green; } >+ </style> >+</some-element> >+<div class="item">div:nth-of-type(1)</div> >+<div class="item">div:nth-child(3)</div> >+<div class="item">.item:nth-last-child(7)</div> >+<a-element class="item">a-element:first-of-type</a-element> >+<b-element class="item">b-element:only-of-type</b-element> >+<a-element class="item">a-element:last-of-type</a-element> >+<c-element><div class="item">.item:only-child</div></c-element> >+<c-element class="item">.item:nth-last-of-type(1)</c-element> >+<other-element class="item">.item:last-child</other-element>`; >+ >+document.body.appendChild(host); >+ >+</script> >+</body> >+</html> >Index: LayoutTests/fast/shadow-dom/nth-node-on-shadow-child.html >=================================================================== >--- LayoutTests/fast/shadow-dom/nth-node-on-shadow-child.html (nonexistent) >+++ LayoutTests/fast/shadow-dom/nth-node-on-shadow-child.html (working copy) >@@ -0,0 +1,40 @@ >+<!DOCTYPE html> >+<html> >+<body> >+<p>Test passes if you see a single 100px by 100px green box below.</p> >+<script> >+const host = document.createElement('div'); >+ >+const shadowRoot = host.attachShadow({mode: 'closed'}); >+shadowRoot.innerHTML = ` >+<some-element class="item"> >+ :first-child >+ <style> >+ .item { display: block; width: 100px; height: 10px; background: red; color: green; font-size: 9px; overflow: hidden; } >+ :first-child { background: green; } >+ div:nth-of-type(1) { background: green; } >+ div:nth-child(3) { background: green; } >+ .item:nth-last-child(7) { background: green; } >+ a-element:first-of-type { background: green; } >+ a-element:last-of-type { background: green; } >+ b-element:only-of-type { background: green; } >+ .item:only-child { background: green; } >+ c-element:nth-last-of-type(1) { background: green; } >+ .item:last-child { background: green; } >+ </style> >+</some-element> >+<div class="item">div:nth-of-type(1)</div> >+<div class="item">div:nth-child(3)</div> >+<div class="item">.item:nth-last-child(7)</div> >+<a-element class="item">a-element:first-of-type</a-element> >+<b-element class="item">b-element:only-of-type</b-element> >+<a-element class="item">a-element:last-of-type</a-element> >+<c-element><div class="item">.item:only-child</div></c-element> >+<c-element class="item">.item:nth-last-of-type(1)</c-element> >+<other-element class="item">.item:last-child</other-element>`; >+ >+document.body.appendChild(host); >+ >+</script> >+</body> >+</html>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 166748
:
298151
|
349116
|
349124
|
349125
|
349127
|
349128
|
349252
|
349359