void HTMLFormattingElementList::tryToEnsureNoahsArkConditionQuickly(HTMLStackItem* newItem, Vector<HTMLStackItem*>& remainingCandidates) { ASSERT(remainingCandidates.isEmpty()); if (m_entries.size() < kNoahsArkCapacity) return; // Use a vector with inline capacity to avoid a malloc in the common case // of a quickly ensuring the condition. Vector<HTMLStackItem*, 10> candidates; size_t newItemAttributeCount = newItem->attributes().size(); for (size_t i = m_entries.size(); i; ) { --i; Entry& entry = m_entries[i]; if (entry.isMarker()) break; // Quickly reject obviously non-matching candidates. HTMLStackItem* candidate = entry.stackItem().get(); if (newItem->localName() != candidate->localName() || newItem->namespaceURI() != candidate->namespaceURI()) continue; if (candidate->attributes().size() != newItemAttributeCount) continue; candidates.append(candidate); } if (candidates.size() < kNoahsArkCapacity) return; // There's room for the new element in the ark. There's no need to copy out the remainingCandidates. remainingCandidates.append(candidates); }
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#mathml-text-integration-point bool HTMLElementStack::isMathMLTextIntegrationPoint(HTMLStackItem& item) { return item.hasTagName(MathMLNames::miTag) || item.hasTagName(MathMLNames::moTag) || item.hasTagName(MathMLNames::mnTag) || item.hasTagName(MathMLNames::msTag) || item.hasTagName(MathMLNames::mtextTag); }
bool HTMLElementStack::inScope(Element* targetElement) const { for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) { HTMLStackItem* item = pos->stackItem(); if (item->node() == targetElement) return true; if (isScopeMarker(item)) return false; } ASSERT_NOT_REACHED(); // <html> is always on the stack and is a scope marker. return false; }
bool HTMLElementStack::hasNumberedHeaderElementInScope() const { for (ElementRecord* record = m_top.get(); record; record = record->next()) { HTMLStackItem* item = record->stackItem(); if (item->isNumberedHeaderElement()) return true; if (isScopeMarker(item)) return false; } ASSERT_NOT_REACHED(); // <html> is always on the stack and is a scope marker. return false; }
bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& targetTag) { for (HTMLElementStack::ElementRecord* pos = top; pos; pos = pos->next()) { HTMLStackItem* item = pos->stackItem().get(); if (item->matchesHTMLTag(targetTag)) return true; if (isMarker(item)) return false; } ASSERT_NOT_REACHED(); // <html> is always on the stack and is a scope marker. return false; }
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#html-integration-point bool HTMLElementStack::isHTMLIntegrationPoint(HTMLStackItem& item) { if (item.hasTagName(MathMLNames::annotation_xmlTag)) { const Attribute* encodingAttr = item.findAttribute(MathMLNames::encodingAttr); if (encodingAttr) { const String& encoding = encodingAttr->value(); return equalLettersIgnoringASCIICase(encoding, "text/html") || equalLettersIgnoringASCIICase(encoding, "application/xhtml+xml"); } return false; } return item.hasTagName(SVGNames::foreignObjectTag) || item.hasTagName(SVGNames::descTag) || item.hasTagName(SVGNames::titleTag); }
void HTMLFormattingElementList::ensureNoahsArkCondition(HTMLStackItem* newItem) { Vector<HTMLStackItem*> candidates; tryToEnsureNoahsArkConditionQuickly(newItem, candidates); if (candidates.isEmpty()) return; // We pre-allocate and re-use this second vector to save one malloc per // attribute that we verify. Vector<HTMLStackItem*> remainingCandidates; remainingCandidates.reserveInitialCapacity(candidates.size()); const Vector<Attribute>& attributes = newItem->attributes(); for (size_t i = 0; i < attributes.size(); ++i) { const Attribute& attribute = attributes[i]; for (size_t j = 0; j < candidates.size(); ++j) { HTMLStackItem* candidate = candidates[j]; // These properties should already have been checked by tryToEnsureNoahsArkConditionQuickly. ASSERT(newItem->attributes().size() == candidate->attributes().size()); ASSERT(newItem->localName() == candidate->localName() && newItem->namespaceURI() == candidate->namespaceURI()); Attribute* candidateAttribute = candidate->getAttributeItem(attribute.name()); if (candidateAttribute && candidateAttribute->value() == attribute.value()) remainingCandidates.append(candidate); } if (remainingCandidates.size() < kNoahsArkCapacity) return; candidates.swap(remainingCandidates); remainingCandidates.shrink(0); } // Inductively, we shouldn't spin this loop very many times. It's possible, // however, that we wil spin the loop more than once because of how the // formatting element list gets permuted. for (size_t i = kNoahsArkCapacity - 1; i < candidates.size(); ++i) remove(candidates[i]->element()); }