Changeset 196864 in webkit


Ignore:
Timestamp:
Feb 20, 2016 10:29:40 AM (8 years ago)
Author:
Antti Koivisto
Message:

Resolve style iteratively
https://bugs.webkit.org/show_bug.cgi?id=154355

Reviewed by Andreas Kling.

Instead of a set of recursive functions use ComposedTreeIterator for traversing the DOM
tree in composed tree order.

This, along with maintaining explicit parent stack makes style resolve code more tractable
for future work.

It also makes the ComposedTreeIterator the definite authority for the shape of the composed tree
instead of duplicating it as a set of recursive style resolve functions. This eliminates
a significant source of bugs and confusion.

The render tree building code path remains recursive for now.

  • css/StyleInvalidationAnalysis.cpp:

(WebCore::StyleInvalidationAnalysis::invalidateIfNeeded):

Invalidate the host element instead of the shadow root. This reduces need for special handling for shadow roots.

  • dom/ComposedTreeIterator.cpp:

(WebCore::ComposedTreeIterator::initializeContextStack):
(WebCore::ComposedTreeIterator::dropAssertions):

Add support for dropping DOM mutation assertions.

(WebCore::ComposedTreeIterator::traverseShadowRoot):

  • dom/ComposedTreeIterator.h:

(WebCore::ComposedTreeIterator::context):
(WebCore::ComposedTreeIterator::current):

  • dom/PseudoElement.h:
  • style/StyleTreeResolver.cpp:

(WebCore::Style::TreeResolver::TreeResolver):
(WebCore::Style::TreeResolver::Scope::Scope):
(WebCore::Style::TreeResolver::Parent::Parent):
(WebCore::Style::TreeResolver::pushScope):
(WebCore::Style::resetStyleForNonRenderedDescendants):
(WebCore::Style::pseudoStyleCacheIsInvalid):
(WebCore::Style::TreeResolver::resolveElement):
(WebCore::Style::resolveTextNode):
(WebCore::Style::TreeResolver::resolveBeforeOrAfterPseudoElement):
(WebCore::Style::TreeResolver::pushParent):
(WebCore::Style::TreeResolver::popParent):
(WebCore::Style::TreeResolver::popParentsToDepth):

Maintain explicit parent stack.

(WebCore::Style::TreeResolver::resolveComposedTree):

The main loop that iterates over the composed tree and computes style for dirty elements.

(WebCore::Style::TreeResolver::resolve):
(WebCore::Style::detachRenderTree):
(WebCore::Style::TreeResolver::resolveLocally): Deleted.
(WebCore::Style::TreeResolver::resolveChildAtShadowBoundary): Deleted.
(WebCore::Style::TreeResolver::resolveShadowTree): Deleted.
(WebCore::Style::TreeResolver::resolveChildren): Deleted.
(WebCore::Style::TreeResolver::resolveSlotAssignees): Deleted.
(WebCore::Style::TreeResolver::resolveRecursively): Deleted.

Recursive functions go away.

  • style/StyleTreeResolver.h:

(WebCore::Style::TreeResolver::scope):
(WebCore::Style::TreeResolver::parent):

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r196862 r196864  
     12016-02-20  Antti Koivisto  <antti@apple.com>
     2
     3        Resolve style iteratively
     4        https://bugs.webkit.org/show_bug.cgi?id=154355
     5
     6        Reviewed by Andreas Kling.
     7
     8        Instead of a set of recursive functions use ComposedTreeIterator for traversing the DOM
     9        tree in composed tree order.
     10
     11        This, along with maintaining explicit parent stack makes style resolve code more tractable
     12        for future work.
     13
     14        It also makes the ComposedTreeIterator the definite authority for the shape of the composed tree
     15        instead of duplicating it as a set of recursive style resolve functions. This eliminates
     16        a significant source of bugs and confusion.
     17
     18        The render tree building code path remains recursive for now.
     19
     20        * css/StyleInvalidationAnalysis.cpp:
     21        (WebCore::StyleInvalidationAnalysis::invalidateIfNeeded):
     22
     23            Invalidate the host element instead of the shadow root. This reduces need for special handling for shadow roots.
     24
     25        * dom/ComposedTreeIterator.cpp:
     26        (WebCore::ComposedTreeIterator::initializeContextStack):
     27        (WebCore::ComposedTreeIterator::dropAssertions):
     28
     29            Add support for dropping DOM mutation assertions.
     30
     31        (WebCore::ComposedTreeIterator::traverseShadowRoot):
     32        * dom/ComposedTreeIterator.h:
     33        (WebCore::ComposedTreeIterator::context):
     34        (WebCore::ComposedTreeIterator::current):
     35        * dom/PseudoElement.h:
     36        * style/StyleTreeResolver.cpp:
     37        (WebCore::Style::TreeResolver::TreeResolver):
     38        (WebCore::Style::TreeResolver::Scope::Scope):
     39        (WebCore::Style::TreeResolver::Parent::Parent):
     40        (WebCore::Style::TreeResolver::pushScope):
     41        (WebCore::Style::resetStyleForNonRenderedDescendants):
     42        (WebCore::Style::pseudoStyleCacheIsInvalid):
     43        (WebCore::Style::TreeResolver::resolveElement):
     44        (WebCore::Style::resolveTextNode):
     45        (WebCore::Style::TreeResolver::resolveBeforeOrAfterPseudoElement):
     46        (WebCore::Style::TreeResolver::pushParent):
     47        (WebCore::Style::TreeResolver::popParent):
     48        (WebCore::Style::TreeResolver::popParentsToDepth):
     49
     50            Maintain explicit parent stack.
     51
     52        (WebCore::Style::TreeResolver::resolveComposedTree):
     53
     54            The main loop that iterates over the composed tree and computes style for dirty elements.
     55
     56        (WebCore::Style::TreeResolver::resolve):
     57        (WebCore::Style::detachRenderTree):
     58        (WebCore::Style::TreeResolver::resolveLocally): Deleted.
     59        (WebCore::Style::TreeResolver::resolveChildAtShadowBoundary): Deleted.
     60        (WebCore::Style::TreeResolver::resolveShadowTree): Deleted.
     61        (WebCore::Style::TreeResolver::resolveChildren): Deleted.
     62        (WebCore::Style::TreeResolver::resolveSlotAssignees): Deleted.
     63        (WebCore::Style::TreeResolver::resolveRecursively): Deleted.
     64
     65            Recursive functions go away.
     66
     67        * style/StyleTreeResolver.h:
     68        (WebCore::Style::TreeResolver::scope):
     69        (WebCore::Style::TreeResolver::parent):
     70
    1712016-02-20  Andreas Kling  <akling@apple.com>
    272
  • trunk/Source/WebCore/css/StyleInvalidationAnalysis.cpp

    r196383 r196864  
    100100    if (m_hasShadowPseudoElementRulesInAuthorSheet) {
    101101        // FIXME: This could do actual rule matching too.
    102         if (auto* shadowRoot = element.shadowRoot())
    103             shadowRoot->setNeedsStyleRecalc();
     102        if (element.shadowRoot())
     103            element.setNeedsStyleRecalc();
    104104    }
    105105
  • trunk/Source/WebCore/dom/ComposedTreeIterator.cpp

    r196833 r196864  
    107107}
    108108
     109void ComposedTreeIterator::dropAssertions()
     110{
     111    for (auto& context : m_contextStack)
     112        context.iterator.dropAssertions();
     113    m_didDropAssertions = true;
     114}
     115
    109116void ComposedTreeIterator::traverseShadowRoot(ShadowRoot& shadowRoot)
    110117{
     
    115122        return;
    116123    }
     124
     125    if (m_didDropAssertions)
     126        shadowContext.iterator.dropAssertions();
    117127
    118128    m_contextStack.append(WTFMove(shadowContext));
  • trunk/Source/WebCore/dom/ComposedTreeIterator.h

    r196833 r196864  
    5555    unsigned depth() const;
    5656
     57    void dropAssertions();
     58
    5759private:
    5860    void initializeContextStack(ContainerNode& root, Node& current);
     
    8284    Node& current() { return *context().iterator; }
    8385
     86    bool m_didDropAssertions { false };
    8487    Vector<Context, 4> m_contextStack;
    8588};
  • trunk/Source/WebCore/dom/PseudoElement.h

    r187496 r196864  
    4848    virtual RefPtr<RenderStyle> customStyleForRenderer(RenderStyle& parentStyle) override;
    4949    virtual void didAttachRenderers() override;
     50    virtual void didRecalcStyle(Style::Change) override;
    5051    virtual bool rendererIsNeeded(const RenderStyle&) override;
    5152
     
    6465    PseudoElement(Element&, PseudoId);
    6566
    66     virtual void didRecalcStyle(Style::Change) override;
    6767    virtual PseudoId customPseudoId() const override { return m_pseudoId; }
    6868
  • trunk/Source/WebCore/style/StyleTreeResolver.cpp

    r196717 r196864  
    113113{
    114114    ensurePlaceholderStyle(document);
    115 
    116     m_scopeStack.append(adoptRef(*new Scope(document)));
    117115}
    118116
     
    128126    , shadowRoot(&shadowRoot)
    129127    , enclosingScope(&enclosingScope)
     128{
     129}
     130
     131TreeResolver::Parent::Parent(Document& document, Change change)
     132    : element(nullptr)
     133    , style(*document.renderStyle())
     134    , renderTreePosition(*document.renderView())
     135    , change(change)
     136{
     137}
     138
     139TreeResolver::Parent::Parent(Element& element, RenderStyle& style, RenderTreePosition renderTreePosition, Change change)
     140    : element(&element)
     141    , style(style)
     142    , renderTreePosition(renderTreePosition)
     143    , change(change)
    130144{
    131145}
     
    426440static void resetStyleForNonRenderedDescendants(Element& current)
    427441{
     442    // FIXME: This is not correct with shadow trees. This should be done with ComposedTreeIterator.
    428443    ASSERT(!current.renderer());
    429444    bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
    430445    for (auto& child : childrenOfType<Element>(current)) {
    431446        ASSERT(!child.renderer());
    432         if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
    433             if (child.styleIsAffectedByPreviousSibling())
    434                 child.setNeedsStyleRecalc();
     447        bool affectedByPreviousSibling = child.styleIsAffectedByPreviousSibling() && elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
     448        if (child.needsStyleRecalc() || elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
    435449            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
    436         }
    437 
    438         if (child.needsStyleRecalc()) {
     450
     451        if (child.needsStyleRecalc() || affectedByPreviousSibling) {
    439452            child.resetComputedStyle();
    440453            child.clearNeedsStyleRecalc();
    441             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
    442454        }
    443455
     
    653665}
    654666
    655 Change TreeResolver::resolveLocally(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change inheritedChange)
     667Change TreeResolver::resolveElement(Element& current)
    656668{
    657669    Change localChange = Detach;
     
    660672
    661673    if (currentStyle && current.styleChangeType() != ReconstructRenderTree) {
    662         Ref<RenderStyle> style(styleForElement(current, inheritedStyle));
     674        Ref<RenderStyle> style(styleForElement(current, parent().style));
    663675        newStyle = style.ptr();
    664676        localChange = determineChange(*currentStyle, style);
     
    667679        if (current.renderer() || current.isNamedFlowContentNode())
    668680            detachRenderTree(current, ReattachDetach);
    669         createRenderTreeRecursively(current, inheritedStyle, renderTreePosition, newStyle.release());
     681#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
     682        else if (is<HTMLSlotElement>(current))
     683            detachRenderTree(current, ReattachDetach);
     684#endif
     685        createRenderTreeRecursively(current, parent().style, parent().renderTreePosition, newStyle.release());
    670686        invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(current);
    671687
     
    674690
    675691    if (RenderElement* renderer = current.renderer()) {
    676         if (localChange != NoChange || pseudoStyleCacheIsInvalid(renderer, newStyle.get()) || (inheritedChange == Force && renderer->requiresForcedStyleRecalcPropagation()) || current.styleChangeType() == SyntheticStyleChange)
     692        if (localChange != NoChange || pseudoStyleCacheIsInvalid(renderer, newStyle.get()) || (parent().change == Force && renderer->requiresForcedStyleRecalcPropagation()) || current.styleChangeType() == SyntheticStyleChange)
    677693            renderer->setAnimatableStyle(*newStyle, current.styleChangeType() == SyntheticStyleChange ? StyleDifferenceRecompositeLayer : StyleDifferenceEqual);
    678694        else if (current.needsStyleRecalc()) {
     
    690706        return Force;
    691707    }
    692     if (inheritedChange == Force)
    693         return Force;
    694     if (current.styleChangeType() >= FullStyleChange)
     708    if (parent().change == Force || current.styleChangeType() >= FullStyleChange)
    695709        return Force;
    696710
     
    717731}
    718732
    719 void TreeResolver::resolveChildAtShadowBoundary(Node& child, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Style::Change change)
    720 {
    721     if (auto* renderer = child.renderer())
    722         renderTreePosition.invalidateNextSibling(*renderer);
    723 
    724     if (is<Text>(child) && child.needsStyleRecalc()) {
    725         resolveTextNode(downcast<Text>(child), renderTreePosition);
    726         return;
    727     }
    728     if (is<Element>(child))
    729         resolveRecursively(downcast<Element>(child), inheritedStyle, renderTreePosition, change);
    730 }
    731 
    732 void TreeResolver::resolveShadowTree(Style::Change change, RenderStyle& inheritedStyle)
    733 {
    734     ASSERT(scope().shadowRoot);
    735     auto& host = *scope().shadowRoot->host();
    736     ASSERT(host.renderer());
    737     if (scope().shadowRoot->styleChangeType() >= FullStyleChange)
    738         change = Force;
    739     RenderTreePosition renderTreePosition(*host.renderer());
    740     for (auto* child = scope().shadowRoot->firstChild(); child; child = child->nextSibling())
    741         resolveChildAtShadowBoundary(*child, inheritedStyle, renderTreePosition, change);
    742 
    743     scope().shadowRoot->clearNeedsStyleRecalc();
    744     scope().shadowRoot->clearChildNeedsStyleRecalc();
    745 }
    746 
    747733void TreeResolver::resolveBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
    748734{
    749     ASSERT(current.renderer());
    750     if (PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId)) {
    751         if (existingPseudoElement->renderer())
    752             renderTreePosition.invalidateNextSibling(*existingPseudoElement->renderer());
    753 
    754         if (needsPseudoElement(current, pseudoId))
    755             resolveRecursively(*existingPseudoElement, current.renderer()->style(), renderTreePosition, current.needsStyleRecalc() ? Force : change);
    756         else
    757             clearBeforeOrAfterPseudoElement(current, pseudoId);
    758         return;
    759     }
    760     createRenderTreeForBeforeOrAfterPseudoElement(current, pseudoId, renderTreePosition);
     735    if (!current.renderer())
     736        return;
     737    PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId);
     738    if (!existingPseudoElement) {
     739        createRenderTreeForBeforeOrAfterPseudoElement(current, pseudoId, renderTreePosition);
     740        return;
     741    }
     742
     743    if (existingPseudoElement->renderer())
     744        renderTreePosition.invalidateNextSibling(*existingPseudoElement->renderer());
     745
     746    if (change == NoChange && !existingPseudoElement->needsStyleRecalc())
     747        return;
     748
     749    if (needsPseudoElement(current, pseudoId)) {
     750        auto change = resolveElement(*existingPseudoElement);
     751        existingPseudoElement->didRecalcStyle(change);
     752        existingPseudoElement->clearNeedsStyleRecalc();
     753    } else
     754        clearBeforeOrAfterPseudoElement(current, pseudoId);
    761755}
    762756
     
    815809#endif // PLATFORM(IOS)
    816810
    817 void TreeResolver::resolveChildren(Element& current, RenderStyle& inheritedStyle, Change change, RenderTreePosition& childRenderTreePosition)
    818 {
    819     SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, current, SelectorFilterPusher::NoPush);
    820 
    821     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
    822     for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
    823         if (RenderObject* childRenderer = child->renderer())
    824             childRenderTreePosition.invalidateNextSibling(*childRenderer);
    825         if (is<Text>(*child) && child->needsStyleRecalc()) {
    826             resolveTextNode(downcast<Text>(*child), childRenderTreePosition);
     811void TreeResolver::pushParent(Element& element, RenderStyle& style, RenderTreePosition renderTreePosition, Change change)
     812{
     813    scope().selectorFilter.pushParent(&element);
     814
     815    Parent parent(element, style, renderTreePosition, change);
     816
     817    if (auto* shadowRoot = element.shadowRoot()) {
     818        pushScope(*shadowRoot);
     819        parent.didPushScope = true;
     820    }
     821#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
     822    else if (is<HTMLSlotElement>(element) && downcast<HTMLSlotElement>(element).assignedNodes()) {
     823        pushEnclosingScope();
     824        parent.didPushScope = true;
     825    }
     826#endif
     827
     828    m_parentStack.append(WTFMove(parent));
     829
     830    resolveBeforeOrAfterPseudoElement(element, change, BEFORE, renderTreePosition);
     831}
     832
     833void TreeResolver::popParent()
     834{
     835    auto& parentElement = *parent().element;
     836
     837    resolveBeforeOrAfterPseudoElement(parentElement, parent().change, AFTER, parent().renderTreePosition);
     838
     839    parentElement.clearNeedsStyleRecalc();
     840    parentElement.clearChildNeedsStyleRecalc();
     841
     842    if (parent().didPushScope)
     843        popScope();
     844
     845    scope().selectorFilter.popParent();
     846
     847    m_parentStack.removeLast();
     848}
     849
     850void TreeResolver::popParentsToDepth(unsigned depth)
     851{
     852    ASSERT(depth);
     853    ASSERT(m_parentStack.size() >= depth);
     854
     855    while (m_parentStack.size() > depth)
     856        popParent();
     857}
     858
     859void TreeResolver::resolveComposedTree()
     860{
     861    ASSERT(m_parentStack.size() == 1);
     862    ASSERT(m_scopeStack.size() == 1);
     863
     864    auto descendants = composedTreeDescendants(m_document);
     865    auto it = descendants.begin();
     866    auto end = descendants.end();
     867
     868    // FIXME: SVG <use> element may cause tree mutations during style recalc.
     869    it.dropAssertions();
     870
     871    while (it != end) {
     872        popParentsToDepth(it.depth());
     873
     874        auto& node = *it;
     875        auto& parent = this->parent();
     876
     877        ASSERT(node.containingShadowRoot() == scope().shadowRoot);
     878        ASSERT(node.parentElement() == parent.element || is<ShadowRoot>(node.parentNode()) || node.parentElement()->shadowRoot());
     879
     880        if (auto* existingRenderer = node.renderer())
     881            parent.renderTreePosition.invalidateNextSibling(*existingRenderer);
     882
     883        if (is<Text>(node)) {
     884            if (node.needsStyleRecalc())
     885                resolveTextNode(downcast<Text>(node), parent.renderTreePosition);
     886            it.traverseNextSkippingChildren();
    827887            continue;
    828888        }
    829         if (!is<Element>(*child))
     889
     890        auto& element = downcast<Element>(node);
     891
     892        // FIXME: We should deal with this during style invalidation.
     893        bool affectedByPreviousSibling = element.styleIsAffectedByPreviousSibling() && parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
     894        if (element.needsStyleRecalc() || parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
     895            parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle = element.affectsNextSiblingElementStyle();
     896
     897        Change change = NoChange;
     898
     899        bool shouldResolve = parent.change >= Inherit || element.needsStyleRecalc() || affectedByPreviousSibling;
     900        if (shouldResolve) {
     901#if PLATFORM(IOS)
     902            CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&element, element.renderStyle());
     903#endif
     904            element.resetComputedStyle();
     905
     906            if (element.hasCustomStyleResolveCallbacks()) {
     907                if (!element.willRecalcStyle(parent.change)) {
     908                    it.traverseNextSkippingChildren();
     909                    continue;
     910                }
     911            }
     912            change = resolveElement(element);
     913
     914            element.clearNeedsStyleRecalc();
     915
     916            if (element.hasCustomStyleResolveCallbacks())
     917                element.didRecalcStyle(change);
     918
     919            if (change == Detach) {
     920                it.traverseNextSkippingChildren();
     921                continue;
     922            }
     923
     924            if (affectedByPreviousSibling)
     925                change = Force;
     926        }
     927
     928#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
     929        if (is<HTMLSlotElement>(element)) {
     930            // FIXME: We should compute style for the slot and use it as parent style.
     931            // FIXME: This should be display:contents check.
     932            // Duplicate the style and render tree position from the current context.
     933            pushParent(element, parent.style.get(), parent.renderTreePosition, change);
     934            it.traverseNext();
    830935            continue;
    831 
    832         Element& childElement = downcast<Element>(*child);
    833         if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
    834             if (childElement.styleIsAffectedByPreviousSibling())
    835                 childElement.setNeedsStyleRecalc();
    836             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
    837         } else if (childElement.needsStyleRecalc())
    838             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
    839         if (change >= Inherit || childElement.childNeedsStyleRecalc() || childElement.needsStyleRecalc()) {
    840             selectorFilterPusher.push();
    841             resolveRecursively(childElement, inheritedStyle, childRenderTreePosition, change);
    842         }
    843     }
    844 }
    845 
    846 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    847 void TreeResolver::resolveSlotAssignees(HTMLSlotElement& slot, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change change)
    848 {
    849     if (auto* assignedNodes = slot.assignedNodes()) {
    850         pushEnclosingScope();
    851         for (auto* child : *assignedNodes)
    852             resolveChildAtShadowBoundary(*child, inheritedStyle, renderTreePosition, change);
    853         popScope();
    854     } else
    855         resolveChildren(slot, inheritedStyle, change, renderTreePosition);
    856 
    857     slot.clearNeedsStyleRecalc();
    858     slot.clearChildNeedsStyleRecalc();
    859 }
    860 #endif
    861 
    862 void TreeResolver::resolveRecursively(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change change)
    863 {
    864     ASSERT(change != Detach);
    865 
    866 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    867     if (is<HTMLSlotElement>(current)) {
    868         resolveSlotAssignees(downcast<HTMLSlotElement>(current), inheritedStyle, renderTreePosition, change);
    869         return;
    870     }
    871 #endif
    872 
    873     if (current.hasCustomStyleResolveCallbacks()) {
    874         if (!current.willRecalcStyle(change))
    875             return;
    876     }
    877 
    878 #if PLATFORM(IOS)
    879     CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&current, current.renderStyle());
    880 #endif
    881 
    882     if (change > NoChange || current.needsStyleRecalc())
    883         current.resetComputedStyle();
    884 
    885     if (change >= Inherit || current.needsStyleRecalc())
    886         change = resolveLocally(current, inheritedStyle, renderTreePosition, change);
    887 
    888     auto* renderer = current.renderer();
    889 
    890     if (change != Detach && renderer) {
    891         auto* shadowRoot = current.shadowRoot();
    892         if (shadowRoot && (change >= Inherit || shadowRoot->childNeedsStyleRecalc() || shadowRoot->needsStyleRecalc())) {
    893             SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, current);
    894 
    895             pushScope(*shadowRoot);
    896             resolveShadowTree(change, renderer->style());
    897             popScope();
    898         }
    899 
    900         RenderTreePosition childRenderTreePosition(*renderer);
    901         resolveBeforeOrAfterPseudoElement(current, change, BEFORE, childRenderTreePosition);
    902 
    903         bool skipChildren = shadowRoot;
    904         if (!skipChildren)
    905             resolveChildren(current, renderer->style(), change, childRenderTreePosition);
    906 
    907         resolveBeforeOrAfterPseudoElement(current, change, AFTER, childRenderTreePosition);
    908     }
    909     if (change != Detach && !renderer)
    910         resetStyleForNonRenderedDescendants(current);
    911 
    912     current.clearNeedsStyleRecalc();
    913     current.clearChildNeedsStyleRecalc();
    914    
    915     if (current.hasCustomStyleResolveCallbacks())
    916         current.didRecalcStyle(change);
     936        }
     937#endif
     938        auto* renderer = element.renderer();
     939        if (!renderer) {
     940            resetStyleForNonRenderedDescendants(element);
     941            element.clearChildNeedsStyleRecalc();
     942        }
     943
     944        bool shouldIterateChildren = renderer && (element.childNeedsStyleRecalc() || change != NoChange);
     945        if (!shouldIterateChildren) {
     946            it.traverseNextSkippingChildren();
     947            continue;
     948        }
     949
     950        pushParent(element, renderer->style(), RenderTreePosition(*renderer), change);
     951
     952        it.traverseNext();
     953    }
     954
     955    popParentsToDepth(1);
    917956}
    918957
    919958void TreeResolver::resolve(Change change)
    920959{
    921     ASSERT(!scope().shadowRoot);
    922 
    923960    auto& renderView = *m_document.renderView();
    924961
     
    928965    if (change != Force && !documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
    929966        return;
     967
     968    m_scopeStack.append(adoptRef(*new Scope(m_document)));
    930969
    931970    // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
     
    933972    renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || scope().styleResolver.usesFirstLetterRules());
    934973
    935     RenderTreePosition renderTreePosition(renderView);
    936     resolveRecursively(*documentElement, *m_document.renderStyle(), renderTreePosition, change);
     974    m_parentStack.append(Parent(m_document, change));
     975
     976    resolveComposedTree();
    937977
    938978    renderView.setUsesFirstLineRules(scope().styleResolver.usesFirstLineRules());
    939979    renderView.setUsesFirstLetterRules(scope().styleResolver.usesFirstLetterRules());
     980
     981    m_parentStack.clear();
     982    m_scopeStack.clear();
    940983}
    941984
  • trunk/Source/WebCore/style/StyleTreeResolver.h

    r196669 r196864  
    2828
    2929#include "RenderStyleConstants.h"
     30#include "RenderTreePosition.h"
    3031#include "SelectorFilter.h"
    3132#include "StyleChange.h"
     
    4243class Node;
    4344class RenderStyle;
    44 class RenderTreePosition;
    4545class Settings;
    4646class ShadowRoot;
     
    5757
    5858private:
    59     void resolveShadowTree(Change, RenderStyle& inheritedStyle);
    60 
    6159    Ref<RenderStyle> styleForElement(Element&, RenderStyle& inheritedStyle);
    6260
    63     void resolveRecursively(Element&, RenderStyle& inheritedStyle, RenderTreePosition&, Change);
    64     Change resolveLocally(Element&, RenderStyle& inheritedStyle, RenderTreePosition&, Change inheritedChange);
    65     void resolveChildren(Element&, RenderStyle&, Change, RenderTreePosition&);
    66     void resolveChildAtShadowBoundary(Node&, RenderStyle& inheritedStyle, RenderTreePosition&, Change);
     61    void resolveComposedTree();
     62    Change resolveElement(Element&);
    6763    void resolveBeforeOrAfterPseudoElement(Element&, Change, PseudoId, RenderTreePosition&);
    6864
     
    7470
    7571#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    76     void resolveSlotAssignees(HTMLSlotElement&, RenderStyle& inheritedStyle, RenderTreePosition&, Change);
    7772    void createRenderTreeForSlotAssignees(HTMLSlotElement&, RenderStyle& inheritedStyle, RenderTreePosition&);
    7873#endif
     
    8883        Scope(ShadowRoot&, Scope& enclosingScope);
    8984    };
     85
     86    struct Parent {
     87        Element* element;
     88        Ref<RenderStyle> style;
     89        RenderTreePosition renderTreePosition;
     90        Change change;
     91        bool didPushScope { false };
     92        bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle { false };
     93
     94        Parent(Document&, Change);
     95        Parent(Element&, RenderStyle&, RenderTreePosition, Change);
     96    };
     97
    9098    Scope& scope() { return m_scopeStack.last(); }
     99    Parent& parent() { return m_parentStack.last(); }
     100
    91101    void pushScope(ShadowRoot&);
    92102    void pushEnclosingScope();
    93103    void popScope();
    94104
     105    void pushParent(Element&, RenderStyle&, RenderTreePosition, Change);
     106    void popParent();
     107    void popParentsToDepth(unsigned depth);
     108
    95109    Document& m_document;
    96110    Vector<Ref<Scope>, 4> m_scopeStack;
     111    Vector<Parent, 32> m_parentStack;
    97112};
    98113
Note: See TracChangeset for help on using the changeset viewer.