void CSSSelectorList::adoptSelectorVector(Vector<OwnPtr<CSSParserSelector>>& selectorVector) { deleteSelectors(); size_t flattenedSize = 0; for (size_t i = 0; i < selectorVector.size(); ++i) { for (CSSParserSelector* selector = selectorVector[i].get(); selector; selector = selector->tagHistory()) ++flattenedSize; } ASSERT(flattenedSize); m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * flattenedSize)); size_t arrayIndex = 0; for (size_t i = 0; i < selectorVector.size(); ++i) { CSSParserSelector* current = selectorVector[i].get(); while (current) { // Move item from the parser selector vector into m_selectorArray without invoking destructor (Ugh.) CSSSelector* currentSelector = current->releaseSelector().leakPtr(); memcpy(&m_selectorArray[arrayIndex], currentSelector, sizeof(CSSSelector)); fastFree(currentSelector); current = current->tagHistory(); ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList()); if (current) m_selectorArray[arrayIndex].setNotLastInTagHistory(); ++arrayIndex; } ASSERT(m_selectorArray[arrayIndex - 1].isLastInTagHistory()); } ASSERT(flattenedSize == arrayIndex); m_selectorArray[arrayIndex - 1].setLastInSelectorList(); selectorVector.clear(); }
void CSSParserSelector::appendTagHistory(CSSSelector::Relation relation, PassOwnPtr<CSSParserSelector> selector) { CSSParserSelector* end = this; while (end->tagHistory()) end = end->tagHistory(); end->setRelation(relation); end->setTagHistory(selector); }
void CSSParserSelector::appendTagHistory(CSSSelector::Relation relation, std::unique_ptr<CSSParserSelector> selector) { CSSParserSelector* end = this; while (end->tagHistory()) end = end->tagHistory(); end->setRelation(relation); end->setTagHistory(std::move(selector)); }
CSSParserSelector* CSSParserSelector::findDistributedPseudoElementSelector() const { CSSParserSelector* selector = const_cast<CSSParserSelector*>(this); do { if (selector->isDistributedPseudoElement()) return selector; } while ((selector = selector->tagHistory())); return 0; }
bool CSSParserSelector::hasHostPseudoSelector() const { CSSParserSelector* selector = const_cast<CSSParserSelector*>(this); do { if (selector->pseudoType() == CSSSelector::PseudoHost || selector->pseudoType() == CSSSelector::PseudoHostContext) return true; } while ((selector = selector->tagHistory())); return false; }
void CSSParserSelector::appendTagHistory(CSSParserSelectorCombinator relation, std::unique_ptr<CSSParserSelector> selector) { CSSParserSelector* end = this; while (end->tagHistory()) end = end->tagHistory(); CSSSelector::Relation selectorRelation; switch (relation) { case CSSParserSelectorCombinator::Child: selectorRelation = CSSSelector::Child; break; case CSSParserSelectorCombinator::DescendantSpace: selectorRelation = CSSSelector::Descendant; break; #if ENABLE(CSS_SELECTORS_LEVEL4) case CSSParserSelectorCombinator::DescendantDoubleChild: selectorRelation = CSSSelector::Descendant; break; #endif case CSSParserSelectorCombinator::DirectAdjacent: selectorRelation = CSSSelector::DirectAdjacent; break; case CSSParserSelectorCombinator::IndirectAdjacent: selectorRelation = CSSSelector::IndirectAdjacent; break; } end->setRelation(selectorRelation); #if ENABLE(CSS_SELECTORS_LEVEL4) if (relation == CSSParserSelectorCombinator::DescendantDoubleChild) end->setDescendantUseDoubleChildSyntax(); #endif end->setTagHistory(WTFMove(selector)); }
CSSSelectorList CSSSelectorList::adoptSelectorVector( Vector<std::unique_ptr<CSSParserSelector>>& selectorVector) { size_t flattenedSize = 0; for (size_t i = 0; i < selectorVector.size(); ++i) { for (CSSParserSelector* selector = selectorVector[i].get(); selector; selector = selector->tagHistory()) ++flattenedSize; } ASSERT(flattenedSize); CSSSelectorList list; list.m_selectorArray = reinterpret_cast<CSSSelector*>(WTF::Partitions::fastMalloc( sizeof(CSSSelector) * flattenedSize, kCSSSelectorTypeName)); size_t arrayIndex = 0; for (size_t i = 0; i < selectorVector.size(); ++i) { CSSParserSelector* current = selectorVector[i].get(); while (current) { // Move item from the parser selector vector into m_selectorArray without // invoking destructor (Ugh.) CSSSelector* currentSelector = current->releaseSelector().release(); memcpy(&list.m_selectorArray[arrayIndex], currentSelector, sizeof(CSSSelector)); WTF::Partitions::fastFree(currentSelector); current = current->tagHistory(); ASSERT(!list.m_selectorArray[arrayIndex].isLastInSelectorList()); if (current) list.m_selectorArray[arrayIndex].setNotLastInTagHistory(); ++arrayIndex; } ASSERT(list.m_selectorArray[arrayIndex - 1].isLastInTagHistory()); } ASSERT(flattenedSize == arrayIndex); list.m_selectorArray[arrayIndex - 1].setLastInSelectorList(); selectorVector.clear(); return list; }
void CSSSelectorParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(const QualifiedName& tag, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule) { CSSParserSelector* lastShadowPseudo = specifiers; CSSParserSelector* history = specifiers; while (history->tagHistory()) { history = history->tagHistory(); if (history->crossesTreeScopes() || history->hasShadowPseudo()) lastShadowPseudo = history; } if (lastShadowPseudo->tagHistory()) { if (tag != anyQName()) lastShadowPseudo->tagHistory()->prependTagSelector(tag, tagIsForNamespaceRule); return; } // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used. // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*'). OwnPtr<CSSParserSelector> elementNameSelector = adoptPtr(new CSSParserSelector(tag)); lastShadowPseudo->setTagHistory(elementNameSelector.release()); lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo); }
void CSSSelectorList::adoptSelectorVector(Vector<OwnPtr<CSSParserSelector> >& selectorVector) { deleteSelectors(); const size_t vectorSize = selectorVector.size(); size_t flattenedSize = 0; for (size_t i = 0; i < vectorSize; ++i) { for (CSSParserSelector* selector = selectorVector[i].get(); selector; selector = selector->tagHistory()) ++flattenedSize; } ASSERT(flattenedSize); if (flattenedSize == 1) { m_selectorArray = selectorVector[0]->releaseSelector().leakPtr(); m_selectorArray->setLastInSelectorList(); ASSERT(m_selectorArray->isLastInTagHistory()); selectorVector.shrink(0); return; } m_selectorArray = reinterpret_cast<CSSSelector*>(fastMalloc(sizeof(CSSSelector) * flattenedSize)); size_t arrayIndex = 0; for (size_t i = 0; i < vectorSize; ++i) { CSSParserSelector* current = selectorVector[i].get(); while (current) { OwnPtr<CSSSelector> selector = current->releaseSelector(); current = current->tagHistory(); move(selector.release(), &m_selectorArray[arrayIndex]); ASSERT(!m_selectorArray[arrayIndex].isLastInSelectorList()); if (current) m_selectorArray[arrayIndex].setNotLastInTagHistory(); ++arrayIndex; } ASSERT(m_selectorArray[arrayIndex - 1].isLastInTagHistory()); } ASSERT(flattenedSize == arrayIndex); m_selectorArray[arrayIndex - 1].setLastInSelectorList(); selectorVector.shrink(0); }
std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeComplexSelector( CSSParserTokenRange& range) { std::unique_ptr<CSSParserSelector> selector = consumeCompoundSelector(range); if (!selector) return nullptr; unsigned previousCompoundFlags = 0; for (CSSParserSelector* simple = selector.get(); simple && !previousCompoundFlags; simple = simple->tagHistory()) previousCompoundFlags |= extractCompoundFlags(*simple, m_context.mode()); while (CSSSelector::RelationType combinator = consumeCombinator(range)) { std::unique_ptr<CSSParserSelector> nextSelector = consumeCompoundSelector(range); if (!nextSelector) return combinator == CSSSelector::Descendant ? std::move(selector) : nullptr; if (previousCompoundFlags & HasPseudoElementForRightmostCompound) return nullptr; CSSParserSelector* end = nextSelector.get(); unsigned compoundFlags = extractCompoundFlags(*end, m_context.mode()); while (end->tagHistory()) { end = end->tagHistory(); compoundFlags |= extractCompoundFlags(*end, m_context.mode()); } end->setRelation(combinator); if (previousCompoundFlags & HasContentPseudoElement) end->setRelationIsAffectedByPseudoContent(); previousCompoundFlags = compoundFlags; end->setTagHistory(std::move(selector)); selector = std::move(nextSelector); } return selector; }
std::unique_ptr<CSSParserSelector> CSSSelectorParser::splitCompoundAtImplicitShadowCrossingCombinator( std::unique_ptr<CSSParserSelector> compoundSelector) { // The tagHistory is a linked list that stores combinator separated compound // selectors from right-to-left. Yet, within a single compound selector, // stores the simple selectors from left-to-right. // // ".a.b > div#id" is stored in a tagHistory as [div, #id, .a, .b], each // element in the list stored with an associated relation (combinator or // SubSelector). // // ::cue, ::shadow, and custom pseudo elements have an implicit ShadowPseudo // combinator to their left, which really makes for a new compound selector, // yet it's consumed by the selector parser as a single compound selector. // // Example: // // input#x::-webkit-clear-button -> [ ::-webkit-clear-button, input, #x ] // // Likewise, ::slotted() pseudo element has an implicit ShadowSlot combinator // to its left for finding matching slot element in other TreeScope. // // Example: // // slot[name=foo]::slotted(div) -> [ ::slotted(div), slot, [name=foo] ] CSSParserSelector* splitAfter = compoundSelector.get(); while (splitAfter->tagHistory() && !splitAfter->tagHistory()->needsImplicitShadowCombinatorForMatching()) splitAfter = splitAfter->tagHistory(); if (!splitAfter || !splitAfter->tagHistory()) return compoundSelector; std::unique_ptr<CSSParserSelector> secondCompound = splitAfter->releaseTagHistory(); secondCompound->appendTagHistory( secondCompound->pseudoType() == CSSSelector::PseudoSlotted ? CSSSelector::ShadowSlot : CSSSelector::ShadowPseudo, std::move(compoundSelector)); return secondCompound; }
PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeComplexSelector(CSSParserTokenRange& range) { OwnPtr<CSSParserSelector> selector = consumeCompoundSelector(range); if (!selector) return nullptr; while (CSSSelector::Relation combinator = consumeCombinator(range)) { OwnPtr<CSSParserSelector> nextSelector = consumeCompoundSelector(range); if (!nextSelector) return combinator == CSSSelector::Descendant ? selector.release() : nullptr; CSSParserSelector* end = nextSelector.get(); while (end->tagHistory()) end = end->tagHistory(); end->setRelation(combinator); if (selector->isContentPseudoElement()) end->setRelationIsAffectedByPseudoContent(); end->setTagHistory(selector.release()); selector = nextSelector.release(); } return selector.release(); }