Enable selector filtering for ::before and ::after pseudo element resolution
[WebKit-https.git] / Source / WebCore / style / StyleTreeResolver.cpp
index d67aa87..333e42a 100644 (file)
@@ -4,7 +4,7 @@
  *           (C) 2001 Peter Kelly (pmk@post.com)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
  *           (C) 2007 David Smith (catfish.man@gmail.com)
  *           (C) 2001 Peter Kelly (pmk@post.com)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
  *           (C) 2007 David Smith (catfish.man@gmail.com)
- * Copyright (C) 2004-2010, 2012-2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2010, 2012-2016 Apple Inc. All rights reserved.
  *           (C) 2007 Eric Seidel (eric@webkit.org)
  *
  * This library is free software; you can redistribute it and/or
  *           (C) 2007 Eric Seidel (eric@webkit.org)
  *
  * This library is free software; you can redistribute it and/or
 #include "config.h"
 #include "StyleTreeResolver.h"
 
 #include "config.h"
 #include "StyleTreeResolver.h"
 
-#include "AXObjectCache.h"
-#include "AnimationController.h"
-#include "AuthorStyleSheets.h"
+#include "CSSAnimationController.h"
 #include "CSSFontSelector.h"
 #include "ComposedTreeAncestorIterator.h"
 #include "ComposedTreeIterator.h"
 #include "CSSFontSelector.h"
 #include "ComposedTreeAncestorIterator.h"
 #include "ComposedTreeIterator.h"
+#include "DocumentTimeline.h"
 #include "ElementIterator.h"
 #include "ElementIterator.h"
-#include "ElementRareData.h"
-#include "FlowThreadController.h"
+#include "HTMLBodyElement.h"
+#include "HTMLMeterElement.h"
+#include "HTMLNames.h"
+#include "HTMLProgressElement.h"
 #include "HTMLSlotElement.h"
 #include "HTMLSlotElement.h"
-#include "InspectorInstrumentation.h"
 #include "LoaderStrategy.h"
 #include "MainFrame.h"
 #include "NodeRenderStyle.h"
 #include "LoaderStrategy.h"
 #include "MainFrame.h"
 #include "NodeRenderStyle.h"
-#include "NodeTraversal.h"
+#include "Page.h"
 #include "PlatformStrategies.h"
 #include "PlatformStrategies.h"
-#include "RenderFullScreen.h"
-#include "RenderNamedFlowThread.h"
-#include "RenderText.h"
-#include "RenderTreePosition.h"
-#include "RenderWidget.h"
+#include "RenderElement.h"
+#include "RenderView.h"
 #include "Settings.h"
 #include "ShadowRoot.h"
 #include "Settings.h"
 #include "ShadowRoot.h"
+#include "StyleFontSizeFunctions.h"
 #include "StyleResolver.h"
 #include "StyleResolver.h"
+#include "StyleScope.h"
 #include "Text.h"
 
 #include "Text.h"
 
-#if PLATFORM(IOS)
-#include "WKContentObservation.h"
-#endif
-
 namespace WebCore {
 
 namespace Style {
 
 namespace WebCore {
 
 namespace Style {
 
-enum DetachType { NormalDetach, ReattachDetach };
-
-static void attachTextRenderer(Text&, RenderTreePosition&);
-static void detachRenderTree(Element&, DetachType);
-static void resolveTextNode(Text&, RenderTreePosition&);
-
-class SelectorFilterPusher {
-public:
-    enum PushMode { Push, NoPush };
-    SelectorFilterPusher(SelectorFilter& selectorFilter, Element& parent, PushMode pushMode = Push)
-        : m_selectorFilter(selectorFilter)
-        , m_parent(parent)
-    {
-        if (pushMode == Push)
-            push();
-    }
-    void push()
-    {
-        if (m_didPush)
-            return;
-        m_didPush = true;
-        m_selectorFilter.pushParent(&m_parent);
-    }
-    ~SelectorFilterPusher()
-    {
-        if (!m_didPush)
-            return;
-        m_selectorFilter.popParent();
-    }
-    
-private:
-    SelectorFilter& m_selectorFilter;
-    Element& m_parent;
-    bool m_didPush { false };
-};
-
-
-static RenderStyle* placeholderStyle;
-
-static void ensurePlaceholderStyle(Document& document)
-{
-    if (placeholderStyle)
-        return;
-    placeholderStyle = &RenderStyle::create().leakRef();
-    placeholderStyle->setDisplay(NONE);
-    placeholderStyle->fontCascade().update(&document.fontSelector());
-}
-
 TreeResolver::TreeResolver(Document& document)
     : m_document(document)
 {
 TreeResolver::TreeResolver(Document& document)
     : m_document(document)
 {
-    ensurePlaceholderStyle(document);
-
-    m_scopeStack.append(adoptRef(*new Scope(document)));
 }
 
 }
 
+TreeResolver::~TreeResolver() = default;
+
 TreeResolver::Scope::Scope(Document& document)
 TreeResolver::Scope::Scope(Document& document)
-    : styleResolver(document.ensureStyleResolver())
+    : styleResolver(document.styleScope().resolver())
     , sharingResolver(document, styleResolver.ruleSets(), selectorFilter)
 {
 }
 
 TreeResolver::Scope::Scope(ShadowRoot& shadowRoot, Scope& enclosingScope)
     , sharingResolver(document, styleResolver.ruleSets(), selectorFilter)
 {
 }
 
 TreeResolver::Scope::Scope(ShadowRoot& shadowRoot, Scope& enclosingScope)
-    : styleResolver(shadowRoot.styleResolver())
+    : styleResolver(shadowRoot.styleScope().resolver())
     , sharingResolver(shadowRoot.documentScope(), styleResolver.ruleSets(), selectorFilter)
     , shadowRoot(&shadowRoot)
     , enclosingScope(&enclosingScope)
 {
     , sharingResolver(shadowRoot.documentScope(), styleResolver.ruleSets(), selectorFilter)
     , shadowRoot(&shadowRoot)
     , enclosingScope(&enclosingScope)
 {
+    styleResolver.setOverrideDocumentElementStyle(enclosingScope.styleResolver.overrideDocumentElementStyle());
 }
 
 }
 
-void TreeResolver::pushScope(ShadowRoot& shadowRoot)
-{
-    m_scopeStack.append(adoptRef(*new Scope(shadowRoot, scope())));
-}
-
-void TreeResolver::pushEnclosingScope()
-{
-    ASSERT(scope().enclosingScope);
-    m_scopeStack.append(*scope().enclosingScope);
-}
-
-void TreeResolver::popScope()
-{
-    return m_scopeStack.removeLast();
-}
-
-static bool shouldCreateRenderer(const Element& element, const RenderElement& parentRenderer)
-{
-    if (!element.document().shouldCreateRenderers())
-        return false;
-    if (!parentRenderer.canHaveChildren() && !(element.isPseudoElement() && parentRenderer.canHaveGeneratedChildren()))
-        return false;
-    if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(element))
-        return false;
-    return true;
-}
-
-Ref<RenderStyle> TreeResolver::styleForElement(Element& element, RenderStyle& inheritedStyle)
+TreeResolver::Scope::~Scope()
 {
 {
-    if (!m_document.haveStylesheetsLoaded() && !element.renderer()) {
-        m_document.setHasNodesWithPlaceholderStyle();
-        return *placeholderStyle;
-    }
-
-    if (element.hasCustomStyleResolveCallbacks()) {
-        if (RefPtr<RenderStyle> style = element.customStyleForRenderer(inheritedStyle))
-            return style.releaseNonNull();
-    }
-
-    if (auto* sharingElement = scope().sharingResolver.resolve(element))
-        return *sharingElement->renderStyle();
-
-    return scope().styleResolver.styleForElement(element, &inheritedStyle, MatchAllRules, nullptr, &scope().selectorFilter);
+    styleResolver.setOverrideDocumentElementStyle(nullptr);
 }
 
 }
 
-#if ENABLE(CSS_REGIONS)
-static RenderNamedFlowThread* moveToFlowThreadIfNeeded(Element& element, const RenderStyle& style)
+TreeResolver::Parent::Parent(Document& document)
+    : element(nullptr)
+    , style(*document.renderStyle())
 {
 {
-    if (!element.shouldMoveToFlowThread(style))
-        return 0;
-
-    FlowThreadController& flowThreadController = element.document().renderView()->flowThreadController();
-    RenderNamedFlowThread& parentFlowRenderer = flowThreadController.ensureRenderFlowThreadWithName(style.flowThread());
-    flowThreadController.registerNamedFlowContentElement(element, parentFlowRenderer);
-    return &parentFlowRenderer;
 }
 }
-#endif
 
 
-void TreeResolver::createRenderer(Element& element, RenderTreePosition& renderTreePosition, RefPtr<RenderStyle>&& resolvedStyle)
+TreeResolver::Parent::Parent(Element& element, const RenderStyle& style, Change change)
+    : element(&element)
+    , style(style)
+    , change(change)
 {
 {
-    ASSERT(shouldCreateRenderer(element, renderTreePosition.parent()));
-    ASSERT(resolvedStyle);
-
-    RenderNamedFlowThread* parentFlowRenderer = 0;
-#if ENABLE(CSS_REGIONS)
-    parentFlowRenderer = moveToFlowThreadIfNeeded(element, *resolvedStyle);
-#endif
-
-    if (!element.rendererIsNeeded(*resolvedStyle))
-        return;
-
-    renderTreePosition.computeNextSibling(element);
-
-    RenderTreePosition insertionPosition = parentFlowRenderer
-        ? RenderTreePosition(*parentFlowRenderer, parentFlowRenderer->nextRendererForElement(element))
-        : renderTreePosition;
-
-    RenderElement* newRenderer = element.createElementRenderer(resolvedStyle.releaseNonNull(), insertionPosition).leakPtr();
-    if (!newRenderer)
-        return;
-    if (!insertionPosition.canInsert(*newRenderer)) {
-        newRenderer->destroy();
-        return;
-    }
-
-    // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
-    // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
-    newRenderer->setFlowThreadState(insertionPosition.parent().flowThreadState());
-
-    // Code below updateAnimations() can depend on Element::renderer() already being set.
-    element.setRenderer(newRenderer);
-
-    // FIXME: There's probably a better way to factor this.
-    // This just does what setAnimatedStyle() does, except with setStyleInternal() instead of setStyle().
-    Ref<RenderStyle> animatedStyle = newRenderer->style();
-    newRenderer->animation().updateAnimations(*newRenderer, animatedStyle, animatedStyle);
-    newRenderer->setStyleInternal(WTFMove(animatedStyle));
-
-    newRenderer->initializeStyle();
-
-#if ENABLE(FULLSCREEN_API)
-    if (m_document.webkitIsFullScreen() && m_document.webkitCurrentFullScreenElement() == &element) {
-        newRenderer = RenderFullScreen::wrapRenderer(newRenderer, &insertionPosition.parent(), m_document);
-        if (!newRenderer)
-            return;
-    }
-#endif
-    // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
-    insertionPosition.insert(*newRenderer);
 }
 
 }
 
-static void invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(Node& current)
-{
-    // FIXME: This needs to traverse in composed tree order.
-
-    // This function finds sibling text renderers where the results of textRendererIsNeeded may have changed as a result of
-    // the current node gaining or losing the renderer. This can only affect white space text nodes.
-    for (Node* sibling = current.nextSibling(); sibling; sibling = sibling->nextSibling()) {
-        if (sibling->needsStyleRecalc())
-            return;
-        if (is<Element>(*sibling)) {
-            // Text renderers beyond rendered elements can't be affected.
-            if (!sibling->renderer() || RenderTreePosition::isRendererReparented(*sibling->renderer()))
-                continue;
-            return;
-        }
-        if (!is<Text>(*sibling))
-            continue;
-        Text& textSibling = downcast<Text>(*sibling);
-        if (!textSibling.containsOnlyWhitespace())
-            continue;
-        textSibling.setNeedsStyleRecalc();
-    }
-}
-
-static bool textRendererIsNeeded(const Text& textNode, const RenderTreePosition& renderTreePosition)
-{
-    const RenderElement& parentRenderer = renderTreePosition.parent();
-    if (!parentRenderer.canHaveChildren())
-        return false;
-    if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(textNode))
-        return false;
-    if (textNode.isEditingText())
-        return true;
-    if (!textNode.length())
-        return false;
-    if (!textNode.containsOnlyWhitespace())
-        return true;
-    // This text node has nothing but white space. We may still need a renderer in some cases.
-    if (parentRenderer.isTable() || parentRenderer.isTableRow() || parentRenderer.isTableSection() || parentRenderer.isRenderTableCol() || parentRenderer.isFrameSet())
-        return false;
-    if (parentRenderer.style().preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
-        return true;
-
-    RenderObject* previousRenderer = renderTreePosition.previousSiblingRenderer(textNode);
-    if (previousRenderer && previousRenderer->isBR()) // <span><br/> <br/></span>
-        return false;
-
-    if (parentRenderer.isRenderInline()) {
-        // <span><div/> <div/></span>
-        if (previousRenderer && !previousRenderer->isInline())
-            return false;
-    } else {
-        if (parentRenderer.isRenderBlock() && !parentRenderer.childrenInline() && (!previousRenderer || !previousRenderer->isInline()))
-            return false;
-        
-        RenderObject* first = parentRenderer.firstChild();
-        while (first && first->isFloatingOrOutOfFlowPositioned())
-            first = first->nextSibling();
-        RenderObject* nextRenderer = renderTreePosition.nextSiblingRenderer(textNode);
-        if (!first || nextRenderer == first) {
-            // Whitespace at the start of a block just goes away. Don't even make a render object for this text.
-            return false;
-        }
-    }
-    return true;
-}
-
-static void createTextRendererIfNeeded(Text& textNode, RenderTreePosition& renderTreePosition)
+void TreeResolver::pushScope(ShadowRoot& shadowRoot)
 {
 {
-    ASSERT(!textNode.renderer());
-
-    if (!textRendererIsNeeded(textNode, renderTreePosition))
-        return;
-
-    auto newRenderer = textNode.createTextRenderer(renderTreePosition.parent().style());
-    ASSERT(newRenderer);
-
-    renderTreePosition.computeNextSibling(textNode);
-
-    if (!renderTreePosition.canInsert(*newRenderer))
-        return;
-
-    // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
-    // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
-    newRenderer->setFlowThreadState(renderTreePosition.parent().flowThreadState());
-
-    textNode.setRenderer(newRenderer.get());
-    // Parent takes care of the animations, no need to call setAnimatableStyle.
-    renderTreePosition.insert(*newRenderer.leakPtr());
+    m_scopeStack.append(adoptRef(*new Scope(shadowRoot, scope())));
 }
 
 }
 
-void attachTextRenderer(Text& textNode, RenderTreePosition& renderTreePosition)
+void TreeResolver::pushEnclosingScope()
 {
 {
-    createTextRendererIfNeeded(textNode, renderTreePosition);
-
-    textNode.clearNeedsStyleRecalc();
+    ASSERT(scope().enclosingScope);
+    m_scopeStack.append(*scope().enclosingScope);
 }
 
 }
 
-void detachTextRenderer(Text& textNode)
+void TreeResolver::popScope()
 {
 {
-    if (textNode.renderer())
-        textNode.renderer()->destroyAndCleanupAnonymousWrappers();
-    textNode.setRenderer(0);
+    return m_scopeStack.removeLast();
 }
 
 }
 
-void updateTextRendererAfterContentChange(Text& textNode, unsigned offsetOfReplacedData, unsigned lengthOfReplacedData)
+std::unique_ptr<RenderStyle> TreeResolver::styleForElement(Element& element, const RenderStyle& inheritedStyle)
 {
 {
-    auto* renderingParentNode = composedTreeAncestors(textNode).first();
-    if (!renderingParentNode || !renderingParentNode->renderer())
-        return;
-
-    bool hadRenderer = textNode.renderer();
-
-    RenderTreePosition renderTreePosition(*renderingParentNode->renderer());
-    resolveTextNode(textNode, renderTreePosition);
-
-    if (hadRenderer && textNode.renderer())
-        textNode.renderer()->setTextWithOffset(textNode.data(), offsetOfReplacedData, lengthOfReplacedData);
-}
+    if (element.hasCustomStyleResolveCallbacks()) {
+        RenderStyle* shadowHostStyle = scope().shadowRoot ? m_update->elementStyle(*scope().shadowRoot->host()) : nullptr;
+        if (auto customStyle = element.resolveCustomStyle(inheritedStyle, shadowHostStyle)) {
+            if (customStyle->relations)
+                commitRelations(WTFMove(customStyle->relations), *m_update);
 
 
-void TreeResolver::createRenderTreeForChildren(ContainerNode& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition)
-{
-    for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
-        ASSERT((!child->renderer() || child->isNamedFlowContentNode()) || current.shadowRoot());
-        if (child->renderer()) {
-            renderTreePosition.invalidateNextSibling(*child->renderer());
-            continue;
+            return WTFMove(customStyle->renderStyle);
         }
         }
-        if (is<Text>(*child)) {
-            attachTextRenderer(downcast<Text>(*child), renderTreePosition);
-            continue;
-        }
-        if (is<Element>(*child))
-            createRenderTreeRecursively(downcast<Element>(*child), inheritedStyle, renderTreePosition, nullptr);
     }
     }
-}
-
-void TreeResolver::createRenderTreeForShadowRoot(ShadowRoot& shadowRoot)
-{
-    ASSERT(shadowRoot.host());
-    ASSERT(shadowRoot.host()->renderer());
 
 
-    pushScope(shadowRoot);
-
-    auto& renderer = *shadowRoot.host()->renderer();
-    RenderTreePosition renderTreePosition(renderer);
-    createRenderTreeForChildren(shadowRoot, renderer.style(), renderTreePosition);
-
-    popScope();
+    if (auto style = scope().sharingResolver.resolve(element, *m_update))
+        return style;
 
 
-    shadowRoot.clearNeedsStyleRecalc();
-    shadowRoot.clearChildNeedsStyleRecalc();
-}
+    auto elementStyle = scope().styleResolver.styleForElement(element, &inheritedStyle, parentBoxStyle(), MatchAllRules, &scope().selectorFilter);
 
 
-static PseudoElement* beforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
-{
-    ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
-    if (pseudoId == BEFORE)
-        return current.beforePseudoElement();
-    return current.afterPseudoElement();
-}
+    if (elementStyle.relations)
+        commitRelations(WTFMove(elementStyle.relations), *m_update);
 
 
-static void setBeforeOrAfterPseudoElement(Element& current, Ref<PseudoElement>&& pseudoElement, PseudoId pseudoId)
-{
-    ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
-    if (pseudoId == BEFORE) {
-        current.setBeforePseudoElement(WTFMove(pseudoElement));
-        return;
-    }
-    current.setAfterPseudoElement(WTFMove(pseudoElement));
-}
-
-static void clearBeforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
-{
-    ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
-    if (pseudoId == BEFORE) {
-        current.clearBeforePseudoElement();
-        return;
-    }
-    current.clearAfterPseudoElement();
+    return WTFMove(elementStyle.renderStyle);
 }
 
 static void resetStyleForNonRenderedDescendants(Element& current)
 {
 }
 
 static void resetStyleForNonRenderedDescendants(Element& current)
 {
-    ASSERT(!current.renderer());
+    // FIXME: This is not correct with shadow trees. This should be done with ComposedTreeIterator.
     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
     for (auto& child : childrenOfType<Element>(current)) {
     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
     for (auto& child : childrenOfType<Element>(current)) {
-        ASSERT(!child.renderer());
-        if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
-            if (child.styleIsAffectedByPreviousSibling())
-                child.setNeedsStyleRecalc();
+        bool affectedByPreviousSibling = child.styleIsAffectedByPreviousSibling() && elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
+        if (child.needsStyleRecalc() || elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
-        }
 
 
-        if (child.needsStyleRecalc()) {
+        if (child.needsStyleRecalc() || affectedByPreviousSibling) {
             child.resetComputedStyle();
             child.resetComputedStyle();
-            child.clearNeedsStyleRecalc();
-            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
+            child.resetStyleRelations();
+            child.setHasValidStyle();
         }
 
         if (child.childNeedsStyleRecalc()) {
         }
 
         if (child.childNeedsStyleRecalc()) {
@@ -448,511 +156,402 @@ static void resetStyleForNonRenderedDescendants(Element& current)
     }
 }
 
     }
 }
 
-static bool needsPseudoElement(Element& current, PseudoId pseudoId)
+static bool affectsRenderedSubtree(Element& element, const RenderStyle& newStyle)
 {
 {
-    if (!current.renderer() || !current.renderer()->canHaveGeneratedChildren())
-        return false;
-    if (current.isPseudoElement())
-        return false;
-    if (!pseudoElementRendererIsNeeded(current.renderer()->getCachedPseudoStyle(pseudoId)))
-        return false;
-    return true;
+    if (element.renderer())
+        return true;
+    if (newStyle.display() != NONE)
+        return true;
+    if (element.rendererIsNeeded(newStyle))
+        return true;
+    return false;
 }
 
 }
 
-void TreeResolver::createRenderTreeForBeforeOrAfterPseudoElement(Element& current, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
+static const RenderStyle* renderOrDisplayContentsStyle(const Element& element)
 {
 {
-    if (!needsPseudoElement(current, pseudoId))
-        return;
-    Ref<PseudoElement> pseudoElement = PseudoElement::create(current, pseudoId);
-    InspectorInstrumentation::pseudoElementCreated(m_document.page(), pseudoElement.get());
-    setBeforeOrAfterPseudoElement(current, pseudoElement.copyRef(), pseudoId);
-    createRenderTreeRecursively(pseudoElement.get(), *current.renderStyle(), renderTreePosition, nullptr);
+    if (auto* renderStyle = element.renderStyle())
+        return renderStyle;
+    if (element.hasDisplayContents())
+        return element.existingComputedStyle();
+    return nullptr;
 }
 
 }
 
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-void TreeResolver::createRenderTreeForSlotAssignees(HTMLSlotElement& slot, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition)
+ElementUpdates TreeResolver::resolveElement(Element& element)
 {
 {
-    ASSERT(shouldCreateRenderer(slot, renderTreePosition.parent()));
-
-    if (auto* assignedNodes = slot.assignedNodes()) {
-        pushEnclosingScope();
-        for (auto* child : *assignedNodes) {
-            if (is<Text>(*child))
-                attachTextRenderer(downcast<Text>(*child), renderTreePosition);
-            else if (is<Element>(*child))
-                createRenderTreeRecursively(downcast<Element>(*child), inheritedStyle, renderTreePosition, nullptr);
-        }
-        popScope();
-    } else {
-        SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, slot);
-        createRenderTreeForChildren(slot, inheritedStyle, renderTreePosition);
+    if (m_didSeePendingStylesheet && !element.renderer() && !m_document.isIgnoringPendingStylesheets()) {
+        m_document.setHasNodesWithMissingStyle();
+        return { };
     }
 
     }
 
-    slot.clearNeedsStyleRecalc();
-    slot.clearChildNeedsStyleRecalc();
-}
-#endif
-
-void TreeResolver::createRenderTreeRecursively(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, RefPtr<RenderStyle>&& resolvedStyle)
-{
-    ASSERT(!current.renderer());
-
-    PostResolutionCallbackDisabler callbackDisabler(m_document);
-    WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
+    auto newStyle = styleForElement(element, parent().style);
 
 
-    bool shouldCallCreateRenderer = shouldCreateRenderer(current, renderTreePosition.parent());
+    if (!affectsRenderedSubtree(element, *newStyle))
+        return { };
 
 
-    RefPtr<RenderStyle> style = resolvedStyle;
-    if (!style)
-        style = styleForElement(current, inheritedStyle);
+    auto* existingStyle = renderOrDisplayContentsStyle(element);
 
 
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    if (is<HTMLSlotElement>(current)) {
-        if (shouldCallCreateRenderer && current.rendererIsNeeded(*style))
-            createRenderTreeForSlotAssignees(downcast<HTMLSlotElement>(current), inheritedStyle, renderTreePosition);
-        return;
+    if (m_didSeePendingStylesheet && (!existingStyle || existingStyle->isNotFinal())) {
+        newStyle->setIsNotFinal();
+        m_document.setHasNodesWithNonFinalStyle();
     }
     }
-#endif
 
 
-    if (current.hasCustomStyleResolveCallbacks())
-        current.willAttachRenderers();
+    auto update = createAnimatedElementUpdate(WTFMove(newStyle), element, parent().change);
 
 
-    if (shouldCallCreateRenderer)
-        createRenderer(current, renderTreePosition, style.releaseNonNull());
+    if (&element == m_document.documentElement()) {
+        m_documentElementStyle = RenderStyle::clonePtr(*update.style);
+        scope().styleResolver.setOverrideDocumentElementStyle(m_documentElementStyle.get());
 
 
-    if (auto* renderer = current.renderer()) {
-        SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, current, SelectorFilterPusher::NoPush);
+        if (update.change != NoChange && existingStyle && existingStyle->computedFontPixelSize() != update.style->computedFontPixelSize()) {
+            // "rem" units are relative to the document element's font size so we need to recompute everything.
+            // In practice this is rare.
+            scope().styleResolver.invalidateMatchedPropertiesCache();
+            update.change = std::max(update.change, Force);
+        }
+    }
 
 
-        RenderTreePosition childRenderTreePosition(*renderer);
-        createRenderTreeForBeforeOrAfterPseudoElement(current, BEFORE, childRenderTreePosition);
+    // This is needed for resolving color:-webkit-text for subsequent elements.
+    // FIXME: We shouldn't mutate document when resolving style.
+    if (&element == m_document.body())
+        m_document.setTextColor(update.style->visitedDependentColor(CSSPropertyColor));
 
 
-        auto* shadowRoot = current.shadowRoot();
-        if (shadowRoot) {
-            selectorFilterPusher.push();
-            createRenderTreeForShadowRoot(*shadowRoot);
-        } else if (current.firstChild())
-            selectorFilterPusher.push();
+    // FIXME: These elements should not change renderer based on appearance property.
+    if (element.hasTagName(HTMLNames::meterTag) || is<HTMLProgressElement>(element)) {
+        if (existingStyle && update.style->appearance() != existingStyle->appearance())
+            update.change = Detach;
+    }
 
 
-        bool skipChildren = shadowRoot;
-        if (!skipChildren)
-            createRenderTreeForChildren(current, renderer->style(), childRenderTreePosition);
+    auto beforeUpdate = resolvePseudoStyle(element, update, BEFORE);
+    auto afterUpdate = resolvePseudoStyle(element, update, AFTER);
 
 
-        if (AXObjectCache* cache = m_document.axObjectCache())
-            cache->updateCacheAfterNodeIsAttached(&current);
+    return { WTFMove(update), WTFMove(beforeUpdate), WTFMove(afterUpdate) };
+}
 
 
-        createRenderTreeForBeforeOrAfterPseudoElement(current, AFTER, childRenderTreePosition);
+ElementUpdate TreeResolver::resolvePseudoStyle(Element& element, const ElementUpdate& elementUpdate, PseudoId pseudoId)
+{
+    if (elementUpdate.style->display() == NONE)
+        return { };
+    if (!elementUpdate.style->hasPseudoStyle(pseudoId))
+        return { };
 
 
-        current.updateFocusAppearanceAfterAttachIfNeeded();
-    } else
-        resetStyleForNonRenderedDescendants(current);
+    auto pseudoStyle = scope().styleResolver.pseudoStyleForElement(element, { pseudoId }, *elementUpdate.style, &scope().selectorFilter);
+    if (!pseudoStyle)
+        return { };
 
 
-    current.clearNeedsStyleRecalc();
-    current.clearChildNeedsStyleRecalc();
+    PseudoElement* pseudoElement = pseudoId == BEFORE ? element.beforePseudoElement() : element.afterPseudoElement();
+    if (!pseudoElement) {
+        auto newPseudoElement = PseudoElement::create(element, pseudoId);
+        pseudoElement = newPseudoElement.ptr();
+        if (pseudoId == BEFORE)
+            element.setBeforePseudoElement(WTFMove(newPseudoElement));
+        else
+            element.setAfterPseudoElement(WTFMove(newPseudoElement));
+    }
 
 
-    if (current.hasCustomStyleResolveCallbacks())
-        current.didAttachRenderers();
+    return createAnimatedElementUpdate(WTFMove(pseudoStyle), *pseudoElement, elementUpdate.change);
 }
 
 }
 
-static void detachChildren(ContainerNode& current, DetachType detachType)
+const RenderStyle* TreeResolver::parentBoxStyle() const
 {
 {
-    for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
-        if (is<Text>(*child))
-            detachTextRenderer(downcast<Text>(*child));
-        else if (is<Element>(*child))
-            detachRenderTree(downcast<Element>(*child), detachType);
+    // 'display: contents' doesn't generate boxes.
+    for (unsigned i = m_parentStack.size(); i; --i) {
+        auto& parent = m_parentStack[i - 1];
+        if (parent.style.display() == NONE)
+            return nullptr;
+        if (parent.style.display() != CONTENTS)
+            return &parent.style;
     }
     }
-    current.clearChildNeedsStyleRecalc();
+    ASSERT_NOT_REACHED();
+    return nullptr;
 }
 
 }
 
-static void detachShadowRoot(ShadowRoot& shadowRoot, DetachType detachType)
+ElementUpdate TreeResolver::createAnimatedElementUpdate(std::unique_ptr<RenderStyle> newStyle, Element& element, Change parentChange)
 {
 {
-    detachChildren(shadowRoot, detachType);
-}
+    auto* oldStyle = renderOrDisplayContentsStyle(element);
 
 
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-static void detachSlotAssignees(HTMLSlotElement& slot, DetachType detachType)
-{
-    ASSERT(!slot.renderer());
-    if (auto* assignedNodes = slot.assignedNodes()) {
-        for (auto* child : *assignedNodes) {
-            if (is<Text>(*child))
-                detachTextRenderer(downcast<Text>(*child));
-            else if (is<Element>(*child))
-                detachRenderTree(downcast<Element>(*child), detachType);
+    if (auto timeline = element.document().existingTimeline()) {
+        auto webAnimations = timeline->animationsForElement(element);
+        if (!webAnimations.isEmpty()) {
+            auto animatedStyle = RenderStyle::clonePtr(*newStyle);
+            for (const auto& animation : webAnimations)
+                animation->resolve(*animatedStyle);
+            newStyle = WTFMove(animatedStyle);
         }
         }
-    } else
-        detachChildren(slot, detachType);
-
-    slot.clearNeedsStyleRecalc();
-    slot.clearChildNeedsStyleRecalc();
-}
-#endif
-
-static void detachRenderTree(Element& current, DetachType detachType)
-{
-    WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
+    }
 
 
-    if (current.hasCustomStyleResolveCallbacks())
-        current.willDetachRenderers();
+    auto& animationController = m_document.frame()->animation();
 
 
-    current.clearStyleDerivedDataBeforeDetachingRenderer();
+    auto animationUpdate = animationController.updateAnimations(element, *newStyle, oldStyle);
 
 
-    // Do not remove the element's hovered and active status
-    // if performing a reattach.
-    if (detachType != ReattachDetach)
-        current.clearHoverAndActiveStatusBeforeDetachingRenderer();
+    if (animationUpdate.style)
+        newStyle = WTFMove(animationUpdate.style);
 
 
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    if (is<HTMLSlotElement>(current))
-        detachSlotAssignees(downcast<HTMLSlotElement>(current), detachType);
-#endif
-    else if (ShadowRoot* shadowRoot = current.shadowRoot())
-        detachShadowRoot(*shadowRoot, detachType);
+    auto change = oldStyle ? determineChange(*oldStyle, *newStyle) : Detach;
 
 
-    detachChildren(current, detachType);
+    auto validity = element.styleValidity();
+    if (validity >= Validity::SubtreeInvalid)
+        change = std::max(change, validity == Validity::SubtreeAndRenderersInvalid ? Detach : Force);
+    if (parentChange >= Force)
+        change = std::max(change, parentChange);
 
 
-    if (current.renderer())
-        current.renderer()->destroyAndCleanupAnonymousWrappers();
-    current.setRenderer(nullptr);
+    bool shouldRecompositeLayer = element.styleResolutionShouldRecompositeLayer() || animationUpdate.stateChanged;
 
 
-    if (current.hasCustomStyleResolveCallbacks())
-        current.didDetachRenderers();
+    return { WTFMove(newStyle), change, shouldRecompositeLayer };
 }
 
 }
 
-static bool pseudoStyleCacheIsInvalid(RenderElement* renderer, RenderStyle* newStyle)
+void TreeResolver::pushParent(Element& element, const RenderStyle& style, Change change)
 {
 {
-    const RenderStyle& currentStyle = renderer->style();
+    scope().selectorFilter.pushParent(&element);
 
 
-    const PseudoStyleCache* pseudoStyleCache = currentStyle.cachedPseudoStyles();
-    if (!pseudoStyleCache)
-        return false;
+    Parent parent(element, style, change);
 
 
-    for (auto& cache : *pseudoStyleCache) {
-        RefPtr<RenderStyle> newPseudoStyle;
-        PseudoId pseudoId = cache->styleType();
-        if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
-            newPseudoStyle = renderer->uncachedFirstLineStyle(newStyle);
-        else
-            newPseudoStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
-        if (!newPseudoStyle)
-            return true;
-        if (*newPseudoStyle != *cache) {
-            if (pseudoId < FIRST_INTERNAL_PSEUDOID)
-                newStyle->setHasPseudoStyle(pseudoId);
-            newStyle->addCachedPseudoStyle(newPseudoStyle);
-            if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
-                // FIXME: We should do an actual diff to determine whether a repaint vs. layout
-                // is needed, but for now just assume a layout will be required. The diff code
-                // in RenderObject::setStyle would need to be factored out so that it could be reused.
-                renderer->setNeedsLayoutAndPrefWidthsRecalc();
-            }
-            return true;
-        }
+    if (auto* shadowRoot = element.shadowRoot()) {
+        pushScope(*shadowRoot);
+        parent.didPushScope = true;
     }
     }
-    return false;
+    else if (is<HTMLSlotElement>(element) && downcast<HTMLSlotElement>(element).assignedNodes()) {
+        pushEnclosingScope();
+        parent.didPushScope = true;
+    }
+
+    m_parentStack.append(WTFMove(parent));
 }
 
 }
 
-Change TreeResolver::resolveLocally(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change inheritedChange)
+void TreeResolver::popParent()
 {
 {
-    Change localChange = Detach;
-    RefPtr<RenderStyle> newStyle;
-    RefPtr<RenderStyle> currentStyle = current.renderStyle();
+    auto& parentElement = *parent().element;
 
 
-    if (currentStyle && current.styleChangeType() != ReconstructRenderTree) {
-        Ref<RenderStyle> style(styleForElement(current, inheritedStyle));
-        newStyle = style.ptr();
-        localChange = determineChange(*currentStyle, style);
-    }
-    if (localChange == Detach) {
-        if (current.renderer() || current.isNamedFlowContentNode())
-            detachRenderTree(current, ReattachDetach);
-        createRenderTreeRecursively(current, inheritedStyle, renderTreePosition, newStyle.release());
-        invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(current);
+    parentElement.setHasValidStyle();
+    parentElement.clearChildNeedsStyleRecalc();
 
 
-        return Detach;
-    }
-
-    if (RenderElement* renderer = current.renderer()) {
-        if (localChange != NoChange || pseudoStyleCacheIsInvalid(renderer, newStyle.get()) || (inheritedChange == Force && renderer->requiresForcedStyleRecalcPropagation()) || current.styleChangeType() == SyntheticStyleChange)
-            renderer->setAnimatableStyle(*newStyle, current.styleChangeType() == SyntheticStyleChange ? StyleDifferenceRecompositeLayer : StyleDifferenceEqual);
-        else if (current.needsStyleRecalc()) {
-            // Although no change occurred, we use the new style so that the cousin style sharing code won't get
-            // fooled into believing this style is the same.
-            renderer->setStyleInternal(*newStyle);
-        }
-    }
+    if (parent().didPushScope)
+        popScope();
 
 
-    // If "rem" units are used anywhere in the document, and if the document element's font size changes, then force font updating
-    // all the way down the tree. This is simpler than having to maintain a cache of objects (and such font size changes should be rare anyway).
-    if (m_document.authorStyleSheets().usesRemUnits() && m_document.documentElement() == &current && localChange != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
-        // Cached RenderStyles may depend on the re units.
-        scope().styleResolver.invalidateMatchedPropertiesCache();
-        return Force;
-    }
-    if (inheritedChange == Force)
-        return Force;
-    if (current.styleChangeType() >= FullStyleChange)
-        return Force;
+    scope().selectorFilter.popParent();
 
 
-    return localChange;
+    m_parentStack.removeLast();
 }
 
 }
 
-void resolveTextNode(Text& text, RenderTreePosition& renderTreePosition)
+void TreeResolver::popParentsToDepth(unsigned depth)
 {
 {
-    text.clearNeedsStyleRecalc();
+    ASSERT(depth);
+    ASSERT(m_parentStack.size() >= depth);
 
 
-    bool hasRenderer = text.renderer();
-    bool needsRenderer = textRendererIsNeeded(text, renderTreePosition);
-    if (hasRenderer) {
-        if (needsRenderer)
-            return;
-        detachTextRenderer(text);
-        invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
-        return;
-    }
-    if (!needsRenderer)
-        return;
-    attachTextRenderer(text, renderTreePosition);
-    invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
+    while (m_parentStack.size() > depth)
+        popParent();
 }
 
 }
 
-void TreeResolver::resolveChildAtShadowBoundary(Node& child, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Style::Change change)
+static bool shouldResolvePseudoElement(const PseudoElement* pseudoElement)
 {
 {
-    if (auto* renderer = child.renderer())
-        renderTreePosition.invalidateNextSibling(*renderer);
+    if (!pseudoElement)
+        return false;
+    return pseudoElement->needsStyleRecalc();
+}
 
 
-    if (is<Text>(child) && child.needsStyleRecalc()) {
-        resolveTextNode(downcast<Text>(child), renderTreePosition);
-        return;
+static bool shouldResolveElement(const Element& element, Style::Change parentChange)
+{
+    if (parentChange >= Inherit)
+        return true;
+    if (parentChange == NoInherit) {
+        auto* existingStyle = renderOrDisplayContentsStyle(element);
+        if (existingStyle && existingStyle->hasExplicitlyInheritedProperties())
+            return true;
     }
     }
-    if (is<Element>(child))
-        resolveRecursively(downcast<Element>(child), inheritedStyle, renderTreePosition, change);
+    if (element.needsStyleRecalc())
+        return true;
+    if (shouldResolvePseudoElement(element.beforePseudoElement()))
+        return true;
+    if (shouldResolvePseudoElement(element.afterPseudoElement()))
+        return true;
+
+    return false;
 }
 
 }
 
-void TreeResolver::resolveShadowTree(Style::Change change, RenderStyle& inheritedStyle)
+static void clearNeedsStyleResolution(Element& element)
 {
 {
-    ASSERT(scope().shadowRoot);
-    auto& host = *scope().shadowRoot->host();
-    ASSERT(host.renderer());
-    if (scope().shadowRoot->styleChangeType() >= FullStyleChange)
-        change = Force;
-    RenderTreePosition renderTreePosition(*host.renderer());
-    for (auto* child = scope().shadowRoot->firstChild(); child; child = child->nextSibling())
-        resolveChildAtShadowBoundary(*child, inheritedStyle, renderTreePosition, change);
-
-    scope().shadowRoot->clearNeedsStyleRecalc();
-    scope().shadowRoot->clearChildNeedsStyleRecalc();
+    element.setHasValidStyle();
+    if (auto* before = element.beforePseudoElement())
+        before->setHasValidStyle();
+    if (auto* after = element.afterPseudoElement())
+        after->setHasValidStyle();
 }
 
 }
 
-void TreeResolver::resolveBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
+static bool hasLoadingStylesheet(const Style::Scope& styleScope, const Element& element, bool checkDescendants)
 {
 {
-    ASSERT(current.renderer());
-    if (PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId)) {
-        if (existingPseudoElement->renderer())
-            renderTreePosition.invalidateNextSibling(*existingPseudoElement->renderer());
+    if (!styleScope.hasPendingSheetsInBody())
+        return false;
+    if (styleScope.hasPendingSheetInBody(element))
+        return true;
+    if (!checkDescendants)
+        return false;
+    for (auto& descendant : descendantsOfType<Element>(element)) {
+        if (styleScope.hasPendingSheetInBody(descendant))
+            return true;
+    };
+    return false;
+}
 
 
-        if (needsPseudoElement(current, pseudoId))
-            resolveRecursively(*existingPseudoElement, current.renderer()->style(), renderTreePosition, current.needsStyleRecalc() ? Force : change);
-        else
-            clearBeforeOrAfterPseudoElement(current, pseudoId);
-        return;
-    }
-    createRenderTreeForBeforeOrAfterPseudoElement(current, pseudoId, renderTreePosition);
+static std::unique_ptr<RenderStyle> createInheritedDisplayContentsStyleIfNeeded(const RenderStyle& parentElementStyle, const RenderStyle* parentBoxStyle)
+{
+    if (parentElementStyle.display() != CONTENTS)
+        return nullptr;
+    if (parentBoxStyle && !parentBoxStyle->inheritedNotEqual(&parentElementStyle))
+        return nullptr;
+    // Compute style for imaginary unstyled <span> around the text node.
+    auto style = RenderStyle::createPtr();
+    style->inheritFrom(parentElementStyle);
+    return style;
 }
 
 }
 
-#if PLATFORM(IOS)
-static EVisibility elementImplicitVisibility(const Element* element)
+void TreeResolver::resolveComposedTree()
 {
 {
-    RenderObject* renderer = element->renderer();
-    if (!renderer)
-        return VISIBLE;
+    ASSERT(m_parentStack.size() == 1);
+    ASSERT(m_scopeStack.size() == 1);
 
 
-    RenderStyle& style = renderer->style();
+    auto descendants = composedTreeDescendants(m_document);
+    auto it = descendants.begin();
+    auto end = descendants.end();
 
 
-    Length width(style.width());
-    Length height(style.height());
-    if ((width.isFixed() && width.value() <= 0) || (height.isFixed() && height.value() <= 0))
-        return HIDDEN;
+    // FIXME: SVG <use> element may cause tree mutations during style recalc.
+    it.dropAssertions();
 
 
-    Length top(style.top());
-    Length left(style.left());
-    if (left.isFixed() && width.isFixed() && -left.value() >= width.value())
-        return HIDDEN;
+    while (it != end) {
+        popParentsToDepth(it.depth());
 
 
-    if (top.isFixed() && height.isFixed() && -top.value() >= height.value())
-        return HIDDEN;
-    return VISIBLE;
-}
+        auto& node = *it;
+        auto& parent = this->parent();
 
 
-class CheckForVisibilityChangeOnRecalcStyle {
-public:
-    CheckForVisibilityChangeOnRecalcStyle(Element* element, RenderStyle* currentStyle)
-        : m_element(element)
-        , m_previousDisplay(currentStyle ? currentStyle->display() : NONE)
-        , m_previousVisibility(currentStyle ? currentStyle->visibility() : HIDDEN)
-        , m_previousImplicitVisibility(WKObservingContentChanges() && WKContentChange() != WKContentVisibilityChange ? elementImplicitVisibility(element) : VISIBLE)
-    {
-    }
-    ~CheckForVisibilityChangeOnRecalcStyle()
-    {
-        if (!WKObservingContentChanges())
-            return;
-        if (m_element->isInUserAgentShadowTree())
-            return;
-        RenderStyle* style = m_element->renderStyle();
-        if (!style)
-            return;
-        if ((m_previousDisplay == NONE && style->display() != NONE) || (m_previousVisibility == HIDDEN && style->visibility() != HIDDEN)
-            || (m_previousImplicitVisibility == HIDDEN && elementImplicitVisibility(m_element.get()) == VISIBLE))
-            WKSetObservedContentChange(WKContentVisibilityChange);
-    }
-private:
-    RefPtr<Element> m_element;
-    EDisplay m_previousDisplay;
-    EVisibility m_previousVisibility;
-    EVisibility m_previousImplicitVisibility;
-};
-#endif // PLATFORM(IOS)
+        ASSERT(node.isConnected());
+        ASSERT(node.containingShadowRoot() == scope().shadowRoot);
+        ASSERT(node.parentElement() == parent.element || is<ShadowRoot>(node.parentNode()) || node.parentElement()->shadowRoot());
 
 
-void TreeResolver::resolveChildren(Element& current, RenderStyle& inheritedStyle, Change change, RenderTreePosition& childRenderTreePosition)
-{
-    SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, current, SelectorFilterPusher::NoPush);
+        if (is<Text>(node)) {
+            auto& text = downcast<Text>(node);
+            
+            if ((text.styleValidity() >= Validity::SubtreeAndRenderersInvalid && parent.change != Detach) || parent.style.display() == CONTENTS) {
+                TextUpdate textUpdate;
+                textUpdate.inheritedDisplayContentsStyle = createInheritedDisplayContentsStyleIfNeeded(parent.style, parentBoxStyle());
 
 
-    bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
-    for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
-        if (RenderObject* childRenderer = child->renderer())
-            childRenderTreePosition.invalidateNextSibling(*childRenderer);
-        if (is<Text>(*child) && child->needsStyleRecalc()) {
-            resolveTextNode(downcast<Text>(*child), childRenderTreePosition);
+                m_update->addText(text, parent.element, WTFMove(textUpdate));
+            }
+
+            text.setHasValidStyle();
+            it.traverseNextSkippingChildren();
             continue;
         }
             continue;
         }
-        if (!is<Element>(*child))
-            continue;
 
 
-        Element& childElement = downcast<Element>(*child);
-        if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
-            if (childElement.styleIsAffectedByPreviousSibling())
-                childElement.setNeedsStyleRecalc();
-            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
-        } else if (childElement.needsStyleRecalc())
-            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
-        if (change >= Inherit || childElement.childNeedsStyleRecalc() || childElement.needsStyleRecalc()) {
-            selectorFilterPusher.push();
-            resolveRecursively(childElement, inheritedStyle, childRenderTreePosition, change);
+        auto& element = downcast<Element>(node);
+
+        if (it.depth() > Settings::defaultMaximumRenderTreeDepth) {
+            resetStyleForNonRenderedDescendants(element);
+            element.clearChildNeedsStyleRecalc();
+            it.traverseNextSkippingChildren();
+            continue;
         }
         }
-    }
-}
 
 
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-void TreeResolver::resolveSlotAssignees(HTMLSlotElement& slot, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change change)
-{
-    if (auto* assignedNodes = slot.assignedNodes()) {
-        pushEnclosingScope();
-        for (auto* child : *assignedNodes)
-            resolveChildAtShadowBoundary(*child, inheritedStyle, renderTreePosition, change);
-        popScope();
-    } else
-        resolveChildren(slot, inheritedStyle, change, renderTreePosition);
+        // FIXME: We should deal with this during style invalidation.
+        bool affectedByPreviousSibling = element.styleIsAffectedByPreviousSibling() && parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
+        if (element.needsStyleRecalc() || parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
+            parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle = element.affectsNextSiblingElementStyle();
 
 
-    slot.clearNeedsStyleRecalc();
-    slot.clearChildNeedsStyleRecalc();
-}
-#endif
+        auto* style = renderOrDisplayContentsStyle(element);
+        auto change = NoChange;
 
 
-void TreeResolver::resolveRecursively(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change change)
-{
-    ASSERT(change != Detach);
+        bool shouldResolve = shouldResolveElement(element, parent.change) || affectedByPreviousSibling;
+        if (shouldResolve) {
+            if (!element.hasDisplayContents())
+                element.resetComputedStyle();
+            element.resetStyleRelations();
 
 
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    if (is<HTMLSlotElement>(current)) {
-        resolveSlotAssignees(downcast<HTMLSlotElement>(current), inheritedStyle, renderTreePosition, change);
-        return;
-    }
-#endif
+            if (element.hasCustomStyleResolveCallbacks())
+                element.willRecalcStyle(parent.change);
 
 
-    if (current.hasCustomStyleResolveCallbacks()) {
-        if (!current.willRecalcStyle(change))
-            return;
-    }
+            auto elementUpdates = resolveElement(element);
 
 
-#if PLATFORM(IOS)
-    CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&current, current.renderStyle());
-#endif
+            if (element.hasCustomStyleResolveCallbacks())
+                element.didRecalcStyle(elementUpdates.update.change);
 
 
-    if (change > NoChange || current.needsStyleRecalc())
-        current.resetComputedStyle();
+            style = elementUpdates.update.style.get();
+            change = elementUpdates.update.change;
 
 
-    if (change >= Inherit || current.needsStyleRecalc())
-        change = resolveLocally(current, inheritedStyle, renderTreePosition, change);
+            if (affectedByPreviousSibling && change != Detach)
+                change = Force;
 
 
-    auto* renderer = current.renderer();
+            if (elementUpdates.update.style)
+                m_update->addElement(element, parent.element, WTFMove(elementUpdates));
 
 
-    if (change != Detach && renderer) {
-        auto* shadowRoot = current.shadowRoot();
-        if (shadowRoot && (change >= Inherit || shadowRoot->childNeedsStyleRecalc() || shadowRoot->needsStyleRecalc())) {
-            SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, current);
+            clearNeedsStyleResolution(element);
+        }
 
 
-            pushScope(*shadowRoot);
-            resolveShadowTree(change, renderer->style());
-            popScope();
+        if (!style) {
+            resetStyleForNonRenderedDescendants(element);
+            element.clearChildNeedsStyleRecalc();
         }
 
         }
 
-        RenderTreePosition childRenderTreePosition(*renderer);
-        resolveBeforeOrAfterPseudoElement(current, change, BEFORE, childRenderTreePosition);
+        bool shouldIterateChildren = style && (element.childNeedsStyleRecalc() || change != NoChange);
+
+        if (!m_didSeePendingStylesheet)
+            m_didSeePendingStylesheet = hasLoadingStylesheet(m_document.styleScope(), element, !shouldIterateChildren);
+
+        if (!shouldIterateChildren) {
+            it.traverseNextSkippingChildren();
+            continue;
+        }
 
 
-        bool skipChildren = shadowRoot;
-        if (!skipChildren)
-            resolveChildren(current, renderer->style(), change, childRenderTreePosition);
+        pushParent(element, *style, change);
 
 
-        resolveBeforeOrAfterPseudoElement(current, change, AFTER, childRenderTreePosition);
+        it.traverseNext();
     }
     }
-    if (change != Detach && !renderer)
-        resetStyleForNonRenderedDescendants(current);
 
 
-    current.clearNeedsStyleRecalc();
-    current.clearChildNeedsStyleRecalc();
-    
-    if (current.hasCustomStyleResolveCallbacks())
-        current.didRecalcStyle(change);
+    popParentsToDepth(1);
 }
 
 }
 
-void TreeResolver::resolve(Change change)
+std::unique_ptr<Update> TreeResolver::resolve()
 {
 {
-    ASSERT(!scope().shadowRoot);
-
     auto& renderView = *m_document.renderView();
 
     Element* documentElement = m_document.documentElement();
     auto& renderView = *m_document.renderView();
 
     Element* documentElement = m_document.documentElement();
-    if (!documentElement)
-        return;
-    if (change != Force && !documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
-        return;
+    if (!documentElement) {
+        m_document.styleScope().resolver();
+        return nullptr;
+    }
+    if (!documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
+        return nullptr;
+
+    m_didSeePendingStylesheet = m_document.styleScope().hasPendingSheetsBeforeBody();
+
+    m_update = std::make_unique<Update>(m_document);
+    m_scopeStack.append(adoptRef(*new Scope(m_document)));
+    m_parentStack.append(Parent(m_document));
 
     // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
     renderView.setUsesFirstLineRules(renderView.usesFirstLineRules() || scope().styleResolver.usesFirstLineRules());
     renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || scope().styleResolver.usesFirstLetterRules());
 
 
     // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
     renderView.setUsesFirstLineRules(renderView.usesFirstLineRules() || scope().styleResolver.usesFirstLineRules());
     renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || scope().styleResolver.usesFirstLetterRules());
 
-    RenderTreePosition renderTreePosition(renderView);
-    resolveRecursively(*documentElement, *m_document.renderStyle(), renderTreePosition, change);
+    resolveComposedTree();
 
     renderView.setUsesFirstLineRules(scope().styleResolver.usesFirstLineRules());
     renderView.setUsesFirstLetterRules(scope().styleResolver.usesFirstLetterRules());
 
     renderView.setUsesFirstLineRules(scope().styleResolver.usesFirstLineRules());
     renderView.setUsesFirstLetterRules(scope().styleResolver.usesFirstLetterRules());
-}
 
 
-void detachRenderTree(Element& element)
-{
-    detachRenderTree(element, NormalDetach);
+    ASSERT(m_scopeStack.size() == 1);
+    ASSERT(m_parentStack.size() == 1);
+    m_parentStack.clear();
+    popScope();
+
+    if (m_update->roots().isEmpty())
+        return { };
+
+    return WTFMove(m_update);
 }
 
 }
 
-static Vector<std::function<void ()>>& postResolutionCallbackQueue()
+static Vector<Function<void ()>>& postResolutionCallbackQueue()
 {
 {
-    static NeverDestroyed<Vector<std::function<void ()>>> vector;
+    static NeverDestroyed<Vector<Function<void ()>>> vector;
     return vector;
 }
 
     return vector;
 }
 
-void queuePostResolutionCallback(std::function<void ()> callback)
+void queuePostResolutionCallback(Function<void ()>&& callback)
 {
 {
-    postResolutionCallbackQueue().append(callback);
+    postResolutionCallbackQueue().append(WTFMove(callback));
 }
 
 static void suspendMemoryCacheClientCalls(Document& document)
 }
 
 static void suspendMemoryCacheClientCalls(Document& document)
@@ -963,8 +562,7 @@ static void suspendMemoryCacheClientCalls(Document& document)
 
     page->setMemoryCacheClientCallsEnabled(false);
 
 
     page->setMemoryCacheClientCallsEnabled(false);
 
-    RefPtr<MainFrame> protectedMainFrame = &page->mainFrame();
-    postResolutionCallbackQueue().append([protectedMainFrame]{
+    postResolutionCallbackQueue().append([protectedMainFrame = Ref<MainFrame>(page->mainFrame())] {
         if (Page* page = protectedMainFrame->page())
             page->setMemoryCacheClientCallsEnabled(true);
     });
         if (Page* page = protectedMainFrame->page())
             page->setMemoryCacheClientCallsEnabled(true);
     });
@@ -1003,10 +601,5 @@ bool postResolutionCallbacksAreSuspended()
     return resolutionNestingDepth;
 }
 
     return resolutionNestingDepth;
 }
 
-bool isPlaceholderStyle(const RenderStyle& style)
-{
-    return &style == placeholderStyle;
-}
-
 }
 }
 }
 }