void HTMLImport::recalcTreeState(HTMLImport* root) { WillBeHeapHashMap<RawPtrWillBeMember<HTMLImport>, HTMLImportState> snapshot; WillBeHeapVector<RawPtrWillBeMember<HTMLImport>> updated; for (HTMLImport* i = root; i; i = traverseNext(i)) { snapshot.add(i, i->state()); i->m_state = HTMLImportState::invalidState(); } // The post-visit DFS order matters here because // HTMLImportStateResolver in recalcState() Depends on // |m_state| of its children and precedents of ancestors. // Accidental cycle dependency of state computation is prevented // by invalidateCachedState() and isStateCacheValid() check. for (HTMLImport* i = traverseFirstPostOrder(root); i; i = traverseNextPostOrder(i)) { ASSERT(!i->m_state.isValid()); i->m_state = HTMLImportStateResolver(i).resolve(); HTMLImportState newState = i->state(); HTMLImportState oldState = snapshot.get(i); // Once the state reaches Ready, it shouldn't go back. ASSERT(!oldState.isReady() || oldState <= newState); if (newState != oldState) updated.append(i); } for (size_t i = 0; i < updated.size(); ++i) updated[i]->stateDidChange(); }
bool HTMLImport::precedes(HTMLImport* import) { for (HTMLImport* i = this; i; i = traverseNext(i)) { if (i == import) return true; } return false; }
void RenderTreeUpdater::updateRenderTree(ContainerNode& root) { ASSERT(root.renderer()); ASSERT(m_parentStack.isEmpty()); m_parentStack.append(Parent(root)); auto descendants = composedTreeDescendants(root); auto it = descendants.begin(); auto end = descendants.end(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=156172 it.dropAssertions(); while (it != end) { popParentsToDepth(it.depth()); auto& node = *it; if (auto* renderer = node.renderer()) renderTreePosition().invalidateNextSibling(*renderer); if (is<Text>(node)) { auto& text = downcast<Text>(node); if (parent().styleChange == Style::Detach || m_styleUpdate->textUpdate(text) || m_invalidatedWhitespaceOnlyTextSiblings.contains(&text)) updateTextRenderer(text); it.traverseNextSkippingChildren(); continue; } auto& element = downcast<Element>(node); auto* elementUpdate = m_styleUpdate->elementUpdate(element); if (!elementUpdate) { it.traverseNextSkippingChildren(); continue; } updateElementRenderer(element, *elementUpdate); bool mayHaveRenderedDescendants = element.renderer() || (element.hasDisplayContents() && shouldCreateRenderer(element, renderTreePosition().parent())); if (!mayHaveRenderedDescendants) { it.traverseNextSkippingChildren(); continue; } pushParent(element, elementUpdate ? elementUpdate->change : Style::NoChange); it.traverseNext(); } popParentsToDepth(0); m_invalidatedWhitespaceOnlyTextSiblings.clear(); }
Frame* FrameTree::traverseNextWithWrap(bool wrap) const { if (Frame* result = traverseNext()) return result; if (wrap) return &m_thisFrame.mainFrame(); return nullptr; }
Frame* FrameTree::traverseNextWithWrap(bool wrap) const { if (Frame* result = traverseNext()) return result; if (wrap) return m_thisFrame->page()->mainFrame(); return 0; }
TEST(TreeNodeTest, TraverseNext) { TrioWithGrandChild trio; trio.appendChildren(); TestTree* order[] = {trio.root.get(), trio.firstChild.get(), trio.middleChild.get(), trio.grandChild.get(), trio.lastChild.get()}; unsigned orderIndex = 0; for (TestTree *node = trio.root.get(); node; node = traverseNext(node), orderIndex++) EXPECT_EQ(node, order[orderIndex]); EXPECT_EQ(orderIndex, sizeof(order) / sizeof(TestTree*)); }
void TreeResolver::resolveComposedTree() { ASSERT(m_parentStack.size() == 1); ASSERT(m_scopeStack.size() == 1); auto descendants = composedTreeDescendants(m_document); auto it = descendants.begin(); auto end = descendants.end(); // FIXME: SVG <use> element may cause tree mutations during style recalc. it.dropAssertions(); while (it != end) { popParentsToDepth(it.depth()); auto& node = *it; auto& parent = this->parent(); ASSERT(node.containingShadowRoot() == scope().shadowRoot); ASSERT(node.parentElement() == parent.element || is<ShadowRoot>(node.parentNode()) || node.parentElement()->shadowRoot()); if (is<Text>(node)) { auto& text = downcast<Text>(node); if (text.styleChangeType() == ReconstructRenderTree && parent.change != Detach) m_update->addText(text, parent.element); text.clearNeedsStyleRecalc(); it.traverseNextSkippingChildren(); continue; } auto& element = downcast<Element>(node); if (it.depth() > Settings::defaultMaximumRenderTreeDepth) { resetStyleForNonRenderedDescendants(element); element.clearChildNeedsStyleRecalc(); it.traverseNextSkippingChildren(); continue; } // FIXME: We should deal with this during style invalidation. bool affectedByPreviousSibling = element.styleIsAffectedByPreviousSibling() && parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle; if (element.needsStyleRecalc() || parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle) parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle = element.affectsNextSiblingElementStyle(); bool shouldResolveForPseudoElement = shouldResolvePseudoElement(element.beforePseudoElement()) || shouldResolvePseudoElement(element.afterPseudoElement()); const RenderStyle* style; Change change; bool shouldResolve = parent.change >= Inherit || element.needsStyleRecalc() || shouldResolveForPseudoElement || affectedByPreviousSibling || element.hasDisplayContents(); if (shouldResolve) { #if PLATFORM(IOS) CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&element, element.renderStyle()); #endif element.resetComputedStyle(); if (element.hasCustomStyleResolveCallbacks()) { if (!element.willRecalcStyle(parent.change)) { it.traverseNextSkippingChildren(); continue; } } auto elementUpdate = resolveElement(element); if (element.hasCustomStyleResolveCallbacks()) element.didRecalcStyle(elementUpdate.change); style = elementUpdate.style.get(); change = elementUpdate.change; if (affectedByPreviousSibling && change != Detach) change = Force; if (elementUpdate.style) m_update->addElement(element, parent.element, WTFMove(elementUpdate)); element.clearNeedsStyleRecalc(); } else { style = element.renderStyle(); change = NoChange; } if (!style) { resetStyleForNonRenderedDescendants(element); element.clearChildNeedsStyleRecalc(); } bool shouldIterateChildren = style && (element.childNeedsStyleRecalc() || change != NoChange); if (!shouldIterateChildren) { it.traverseNextSkippingChildren(); continue; } pushParent(element, *style, change); it.traverseNext(); } popParentsToDepth(1); }