ALWAYS_INLINE void SelectorDataList::executeFastPathForIdSelector(const ContainerNode& rootNode, const SelectorData& selectorData, const CSSSelector* idSelector, typename SelectorQueryTrait::OutputType& output) const { ASSERT(m_selectors.size() == 1); ASSERT(idSelector); const AtomicString& idToMatch = idSelector->value(); if (UNLIKELY(rootNode.treeScope().containsMultipleElementsWithId(idToMatch))) { const Vector<Element*>* elements = rootNode.treeScope().getAllElementsById(idToMatch); ASSERT(elements); size_t count = elements->size(); bool rootNodeIsTreeScopeRoot = isTreeScopeRoot(rootNode); for (size_t i = 0; i < count; ++i) { Element& element = *elements->at(i); if ((rootNodeIsTreeScopeRoot || element.isDescendantOf(&rootNode)) && selectorMatches(selectorData, element, rootNode)) { SelectorQueryTrait::appendOutputForElement(output, &element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } return; } Element* element = rootNode.treeScope().getElementById(idToMatch); if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode))) return; if (selectorMatches(selectorData, *element, rootNode)) SelectorQueryTrait::appendOutputForElement(output, element); }
void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const { if (!canUseFastQuery(rootNode)) { if (m_needsUpdatedDistribution) rootNode.updateDistribution(); if (m_crossesTreeBoundary) { executeSlowTraversingShadowTree<SelectorQueryTrait>(rootNode, output); } else { executeSlow<SelectorQueryTrait>(rootNode, output); } return; } ASSERT(m_selectors.size() == 1); const CSSSelector& selector = *m_selectors[0]; const CSSSelector& firstSelector = selector; // Fast path for querySelector*('#id'), querySelector*('tag#id'). if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { const AtomicString& idToMatch = idSelector->value(); if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) { const WillBeHeapVector<RawPtrWillBeMember<Element>>& elements = rootNode.treeScope().getAllElementsById(idToMatch); size_t count = elements.size(); for (size_t i = 0; i < count; ++i) { Element& element = *elements[i]; if (!(isTreeScopeRoot(rootNode) || element.isDescendantOf(&rootNode))) continue; if (selectorMatches(selector, element, rootNode)) { SelectorQueryTrait::appendElement(output, element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } return; } Element* element = rootNode.treeScope().getElementById(idToMatch); if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode))) return; if (selectorMatches(selector, *element, rootNode)) SelectorQueryTrait::appendElement(output, *element); return; } if (!firstSelector.tagHistory()) { // Fast path for querySelector*('.foo'), and querySelector*('div'). switch (firstSelector.match()) { case CSSSelector::Class: collectElementsByClassName<SelectorQueryTrait>(rootNode, firstSelector.value(), output); return; case CSSSelector::Tag: collectElementsByTagName<SelectorQueryTrait>(rootNode, firstSelector.tagQName(), output); return; default: break; // If we need another fast path, add here. } } findTraverseRootsAndExecute<SelectorQueryTrait>(rootNode, output); }
void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const { if (!canUseFastQuery(rootNode)) { executeSlow<SelectorQueryTrait>(rootNode, output); return; } ASSERT(m_selectors.size() == 1); const SelectorData& selector = m_selectors[0]; const CSSSelector& firstSelector = selector.selector; // Fast path for querySelector*('#id'), querySelector*('tag#id'). if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { const AtomicString& idToMatch = idSelector->value(); Element* singleMatchingElement = 0; if (rootNode.treeScope().getNumberOfElementsWithId(idToMatch, singleMatchingElement) > 1) { const Vector<Element*>& elements = rootNode.treeScope().getAllElementsById(idToMatch); size_t count = elements.size(); for (size_t i = 0; i < count; ++i) { Element& element = *elements[i]; if (!(isTreeScopeRoot(rootNode) || element.isDescendantOf(&rootNode))) continue; if (selectorMatches(selector, element, rootNode)) { SelectorQueryTrait::appendElement(output, element); if (SelectorQueryTrait::shouldOnlyMatchFirstElement) return; } } return; } if (!singleMatchingElement || !(isTreeScopeRoot(rootNode) || singleMatchingElement->isDescendantOf(&rootNode))) return; if (selectorMatches(selector, *singleMatchingElement, rootNode)) SelectorQueryTrait::appendElement(output, *singleMatchingElement); return; } if (!firstSelector.tagHistory()) { // Fast path for querySelector*('.foo'), and querySelector*('div'). switch (firstSelector.m_match) { case CSSSelector::Class: collectElementsByClassName<SelectorQueryTrait>(rootNode, firstSelector.value(), output); return; case CSSSelector::Tag: collectElementsByTagName<SelectorQueryTrait>(rootNode, firstSelector.tagQName(), output); return; default: break; // If we need another fast path, add here. } } findTraverseRootsAndExecute<SelectorQueryTrait>(rootNode, output); }
void SelectorDataList::findTraverseRootsAndExecute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const { // We need to return the matches in document order. To use id lookup while there is possiblity of multiple matches // we would need to sort the results. For now, just traverse the document in that case. ASSERT(m_selectors.size() == 1); bool isRightmostSelector = true; bool startFromParent = false; for (const CSSSelector* selector = m_selectors[0]; selector; selector = selector->tagHistory()) { if (selector->match() == CSSSelector::Id && !rootNode.document().containsMultipleElementsWithId(selector->value())) { Element* element = rootNode.treeScope().getElementById(selector->value()); ContainerNode* adjustedNode = &rootNode; if (element && (isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode))) adjustedNode = element; else if (!element || isRightmostSelector) adjustedNode = 0; if (isRightmostSelector) { executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], adjustedNode, MatchesTraverseRoots, rootNode, output); return; } if (startFromParent && adjustedNode) adjustedNode = adjustedNode->parentNode(); executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], adjustedNode, DoesNotMatchTraverseRoots, rootNode, output); return; } // If we have both CSSSelector::Id and CSSSelector::Class at the same time, we should use Id // to find traverse root. if (!SelectorQueryTrait::shouldOnlyMatchFirstElement && !startFromParent && selector->match() == CSSSelector::Class) { if (isRightmostSelector) { ClassElementList<AllElements> traverseRoots(rootNode, selector->value()); executeForTraverseRoots<SelectorQueryTrait>(*m_selectors[0], traverseRoots, MatchesTraverseRoots, rootNode, output); return; } // Since there exists some ancestor element which has the class name, we need to see all children of rootNode. if (ancestorHasClassName(rootNode, selector->value())) { executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], &rootNode, DoesNotMatchTraverseRoots, rootNode, output); return; } ClassElementList<OnlyRoots> traverseRoots(rootNode, selector->value()); executeForTraverseRoots<SelectorQueryTrait>(*m_selectors[0], traverseRoots, DoesNotMatchTraverseRoots, rootNode, output); return; } if (selector->relation() == CSSSelector::SubSelector) continue; isRightmostSelector = false; if (selector->relation() == CSSSelector::DirectAdjacent || selector->relation() == CSSSelector::IndirectAdjacent) startFromParent = true; else startFromParent = false; } executeForTraverseRoot<SelectorQueryTrait>(*m_selectors[0], &rootNode, DoesNotMatchTraverseRoots, rootNode, output); }
void StyleElement::clearDocumentData(Document& document, Element* element) { if (m_sheet) m_sheet->clearOwnerNode(); if (element->inDocument()) { ContainerNode* scopingNode = isHTMLStyleElement(element) ? toHTMLStyleElement(element)->scopingNode() : 0; TreeScope& treeScope = scopingNode ? scopingNode->treeScope() : element->treeScope(); document.styleEngine()->removeStyleSheetCandidateNode(element, scopingNode, treeScope); } }
HTMLSlotElement::InsertionNotificationRequest HTMLSlotElement::insertedInto(ContainerNode& insertionPoint) { auto insertionResult = HTMLElement::insertedInto(insertionPoint); ASSERT_UNUSED(insertionResult, insertionResult == InsertionDone); // This function could be called when this element's shadow root's host or its ancestor is inserted. // This element is new to the shadow tree (and its tree scope) only if the parent into which this element // or its ancestor is inserted belongs to the same tree scope as this element's. if (insertionPoint.isInShadowTree() && isInShadowTree() && &insertionPoint.treeScope() == &treeScope()) { if (auto shadowRoot = containingShadowRoot()) shadowRoot->addSlotElementByName(attributeWithoutSynchronization(nameAttr), *this); } return InsertionDone; }
Node* HTMLCollection::namedItem(const AtomicString& name) const { // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp // This method first searches for an object with a matching id // attribute. If a match is not found, the method then searches for an // object with a matching name attribute, but only on those elements // that are allowed a name attribute. ContainerNode* root = rootContainerNode(); if (name.isEmpty() || !root) return 0; if (!overridesItemAfter() && root->isInTreeScope()) { TreeScope* treeScope = root->treeScope(); Element* candidate = 0; if (treeScope->hasElementWithId(name.impl())) { if (!treeScope->containsMultipleElementsWithId(name)) candidate = treeScope->getElementById(name); } else if (treeScope->hasElementWithName(name.impl())) { if (!treeScope->containsMultipleElementsWithName(name)) { candidate = treeScope->getElementByName(name); if (candidate && type() == DocAll && (!candidate->isHTMLElement() || !nameShouldBeVisibleInDocumentAll(toHTMLElement(candidate)))) candidate = 0; } } else return 0; if (candidate && isMatchingElement(this, candidate) && (shouldOnlyIncludeDirectChildren() ? candidate->parentNode() == root : candidate->isDescendantOf(root))) return candidate; } // The pathological case. We need to walk the entire subtree. updateNameCache(); if (Vector<Element*>* idResults = idCache(name)) { if (idResults->size()) return idResults->at(0); } if (Vector<Element*>* nameResults = nameCache(name)) { if (nameResults->size()) return nameResults->at(0); } return 0; }