Changeset 81802 in webkit


Ignore:
Timestamp:
Mar 23, 2011 1:39:53 PM (13 years ago)
Author:
hyatt@apple.com
Message:

https://bugs.webkit.org/show_bug.cgi?id=56909

Reviewed by Dan Bernstein.

Add a simplified normal flow layout path optimization for overflow recomputation
and for positioned objects inside relative positioned containers.

Currently there is an optimized code path for positioned objects, but as soon as
we encounter a normal flow object in the containing block chain, we lose the
optimization.

This patch adds a new type of style difference called SimplifiedLayout that is
returned when only overflow needs to be recomputed. Whenever opacity changes or
a transform changes, this is the hint returned now instead of a full layout.

In addition, when positioned objects need layout and start marking up the
containing block chain, we now propagate the fact that the layout is simplified
all the way up to the root, even when we encounter normal flow containing
blocks.

The layoutOnlyPositionedObjects function has been renamed to simplifiedLayout()
and is now used for all of these cases (in addition to what it handled before).

No new tests, since existing tests covered this very well (especially the opacity
and transforms repaint tests in fast/repaint).

  • rendering/RenderBlock.cpp:

(WebCore::RenderBlock::layoutBlock):
(WebCore::RenderBlock::simplifiedNormalFlowLayout):
(WebCore::RenderBlock::simplifiedLayout):

  • rendering/RenderBlock.h:
  • rendering/RenderBox.cpp:

(WebCore::RenderBox::styleDidChange):

  • rendering/RenderBoxModelObject.cpp:

(WebCore::RenderBoxModelObject::styleWillChange):

  • rendering/RenderFlexibleBox.cpp:

(WebCore::RenderFlexibleBox::layoutBlock):

  • rendering/RenderObject.cpp:

(WebCore::RenderObject::RenderObject):
(WebCore::RenderObject::adjustStyleDifference):
(WebCore::RenderObject::setStyle):
(WebCore::RenderObject::styleDidChange):

  • rendering/RenderObject.h:

(WebCore::RenderObject::needsLayout):
(WebCore::RenderObject::needsPositionedMovementLayoutOnly):
(WebCore::RenderObject::needsSimplifiedNormalFlowLayout):
(WebCore::RenderObject::setNeedsLayout):
(WebCore::RenderObject::setChildNeedsLayout):
(WebCore::RenderObject::setNeedsSimplifiedNormalFlowLayout):
(WebCore::RenderObject::markContainingBlocksForLayout):

  • rendering/RenderTable.cpp:

(WebCore::RenderTable::layout):

  • rendering/style/RenderStyle.cpp:

(WebCore::RenderStyle::diff):

  • rendering/style/RenderStyleConstants.h:
  • rendering/svg/RenderSVGText.cpp:

(WebCore::RenderSVGText::layout):

Location:
trunk/Source/WebCore
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r81799 r81802  
     12011-03-23  David Hyatt  <hyatt@apple.com>
     2
     3        Reviewed by Dan Bernstein.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=56909
     6       
     7        Add a simplified normal flow layout path optimization for overflow recomputation
     8        and for positioned objects inside relative positioned containers.
     9
     10        Currently there is an optimized code path for positioned objects, but as soon as
     11        we encounter a normal flow object in the containing block chain, we lose the
     12        optimization.
     13
     14        This patch adds a new type of style difference called SimplifiedLayout that is
     15        returned when only overflow needs to be recomputed. Whenever opacity changes or
     16        a transform changes, this is the hint returned now instead of a full layout.
     17       
     18        In addition, when positioned objects need layout and start marking up the
     19        containing block chain, we now propagate the fact that the layout is simplified
     20        all the way up to the root, even when we encounter normal flow containing
     21        blocks.
     22       
     23        The layoutOnlyPositionedObjects function has been renamed to simplifiedLayout()
     24        and is now used for all of these cases (in addition to what it handled before).
     25       
     26        No new tests, since existing tests covered this very well (especially the opacity
     27        and transforms repaint tests in fast/repaint).
     28
     29        * rendering/RenderBlock.cpp:
     30        (WebCore::RenderBlock::layoutBlock):
     31        (WebCore::RenderBlock::simplifiedNormalFlowLayout):
     32        (WebCore::RenderBlock::simplifiedLayout):
     33        * rendering/RenderBlock.h:
     34        * rendering/RenderBox.cpp:
     35        (WebCore::RenderBox::styleDidChange):
     36        * rendering/RenderBoxModelObject.cpp:
     37        (WebCore::RenderBoxModelObject::styleWillChange):
     38        * rendering/RenderFlexibleBox.cpp:
     39        (WebCore::RenderFlexibleBox::layoutBlock):
     40        * rendering/RenderObject.cpp:
     41        (WebCore::RenderObject::RenderObject):
     42        (WebCore::RenderObject::adjustStyleDifference):
     43        (WebCore::RenderObject::setStyle):
     44        (WebCore::RenderObject::styleDidChange):
     45        * rendering/RenderObject.h:
     46        (WebCore::RenderObject::needsLayout):
     47        (WebCore::RenderObject::needsPositionedMovementLayoutOnly):
     48        (WebCore::RenderObject::needsSimplifiedNormalFlowLayout):
     49        (WebCore::RenderObject::setNeedsLayout):
     50        (WebCore::RenderObject::setChildNeedsLayout):
     51        (WebCore::RenderObject::setNeedsSimplifiedNormalFlowLayout):
     52        (WebCore::RenderObject::markContainingBlocksForLayout):
     53        * rendering/RenderTable.cpp:
     54        (WebCore::RenderTable::layout):
     55        * rendering/style/RenderStyle.cpp:
     56        (WebCore::RenderStyle::diff):
     57        * rendering/style/RenderStyleConstants.h:
     58        * rendering/svg/RenderSVGText.cpp:
     59        (WebCore::RenderSVGText::layout):
     60
    1612011-03-23  Tyler Close  <tjclose@chromium.org>
    262
  • trunk/Source/WebCore/rendering/RenderBlock.cpp

    r81794 r81802  
    3535#include "HTMLNames.h"
    3636#include "HitTestResult.h"
     37#include "InlineIterator.h"
    3738#include "InlineTextBox.h"
    3839#include "PaintInfo.h"
     
    11331134        return;                                      // cause us to come in here.  Just bail.
    11341135
    1135     if (!relayoutChildren && layoutOnlyPositionedObjects())
     1136    if (!relayoutChildren && simplifiedLayout())
    11361137        return;
    11371138
     
    20772078}
    20782079
    2079 bool RenderBlock::layoutOnlyPositionedObjects()
    2080 {
    2081     if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout())
     2080void RenderBlock::simplifiedNormalFlowLayout()
     2081{
     2082    if (childrenInline()) {
     2083        ListHashSet<RootInlineBox*> lineBoxes;
     2084        bool endOfInline = false;
     2085        RenderObject* o = bidiFirst(this, 0, false);
     2086        while (o) {
     2087            if (!o->isPositioned() && (o->isReplaced() || o->isFloating())) {
     2088                o->layoutIfNeeded();
     2089                if (toRenderBox(o)->inlineBoxWrapper()) {
     2090                    RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
     2091                    lineBoxes.add(box);
     2092                }
     2093            } else if (o->isText() || (o->isRenderInline() && !endOfInline))
     2094                o->setNeedsLayout(false);
     2095            o = bidiNext(this, o, 0, false, &endOfInline);
     2096        }
     2097
     2098        // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
     2099        GlyphOverflowAndFallbackFontsMap textBoxDataMap;                 
     2100        for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
     2101            RootInlineBox* box = *it;
     2102            box->computeOverflow(box->lineTop(), box->lineBottom(), document()->inNoQuirksMode(), textBoxDataMap);
     2103        }
     2104    } else {
     2105        for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
     2106            if (!box->isPositioned())
     2107                box->layoutIfNeeded();
     2108        }
     2109    }
     2110}
     2111
     2112bool RenderBlock::simplifiedLayout()
     2113{
     2114    if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
    20822115        return false;
    20832116
    20842117    LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
    2085 
     2118   
    20862119    if (needsPositionedMovementLayout()) {
    20872120        tryLayoutDoingPositionedMovementOnly();
     
    20902123    }
    20912124
    2092     // All we have to is lay out our positioned objects.
    2093     layoutPositionedObjects(false);
     2125    // Lay out positioned descendants or objects that just need to recompute overflow.
     2126    if (needsSimplifiedNormalFlowLayout())
     2127        simplifiedNormalFlowLayout();
     2128
     2129    // Lay out our positioned objects if our positioned child bit is set.
     2130    if (posChildNeedsLayout())
     2131        layoutPositionedObjects(false);
    20942132
    20952133    // Recompute our overflow information.
  • trunk/Source/WebCore/rendering/RenderBlock.h

    r81746 r81802  
    298298
    299299    virtual bool hasLineIfEmpty() const;
    300     bool layoutOnlyPositionedObjects();
     300   
     301    bool simplifiedLayout();
     302    void simplifiedNormalFlowLayout();
    301303
    302304    void computeOverflow(int oldClientAfterEdge, bool recomputeFloats = false);
  • trunk/Source/WebCore/rendering/RenderBox.cpp

    r81786 r81802  
    289289    RenderBoxModelObject::styleDidChange(diff, oldStyle);
    290290
    291     if (needsLayout() && oldStyle && (oldStyle->logicalHeight().isPercent() || oldStyle->logicalMinHeight().isPercent() || oldStyle->logicalMaxHeight().isPercent()))
    292         RenderBlock::removePercentHeightDescendant(this);
     291    if (needsLayout() && oldStyle) {
     292        if (oldStyle && (oldStyle->logicalHeight().isPercent() || oldStyle->logicalMinHeight().isPercent() || oldStyle->logicalMaxHeight().isPercent()))
     293            RenderBlock::removePercentHeightDescendant(this);
     294
     295        // Normally we can do optimized positioning layout for absolute/fixed positioned objects. There is one special case, however, which is
     296        // when the positioned object's margin-before is changed. In this case the parent has to get a layout in order to run margin collapsing
     297        // to determine the new static position.
     298        if (isPositioned() && style()->hasStaticBlockPosition(isHorizontalWritingMode()) && oldStyle->marginBefore() != style()->marginBefore()
     299            && parent() && !parent()->normalChildNeedsLayout())
     300            parent()->setChildNeedsLayout(true);
     301    }
    293302
    294303    // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
  • trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp

    r81716 r81802  
    304304        }
    305305       
    306         if (diff == StyleDifferenceLayout) {
     306        if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) {
    307307            // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could
    308308            // end up being destroyed.
  • trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp

    r79930 r81802  
    210210    ASSERT(needsLayout());
    211211
    212     if (!relayoutChildren && layoutOnlyPositionedObjects())
     212    if (!relayoutChildren && simplifiedLayout())
    213213        return;
    214214
  • trunk/Source/WebCore/rendering/RenderObject.cpp

    r81747 r81802  
    192192    , m_normalChildNeedsLayout(false)
    193193    , m_posChildNeedsLayout(false)
     194    , m_needsSimplifiedNormalFlowLayout(false)
    194195    , m_preferredLogicalWidthsDirty(false)
    195196    , m_floating(false)
     
    16871688        // hence the !isText() check.
    16881689        // FIXME: when transforms are taken into account for overflow, we will need to do a layout.
    1689         if (!isText() && (!hasLayer() || !toRenderBoxModelObject(this)->layer()->isComposited()))
    1690             diff = StyleDifferenceLayout;
    1691         else if (diff < StyleDifferenceRecompositeLayer)
     1690        if (!isText() && (!hasLayer() || !toRenderBoxModelObject(this)->layer()->isComposited())) {
     1691            if (!hasLayer())
     1692                diff = StyleDifferenceLayout; // FIXME: Do this for now since SimplifiedLayout cannot handle updating floating objects lists.
     1693            else if (diff < StyleDifferenceSimplifiedLayout)
     1694                diff = StyleDifferenceSimplifiedLayout;
     1695        } else if (diff < StyleDifferenceRecompositeLayer)
    16921696            diff = StyleDifferenceRecompositeLayer;
    16931697    }
     
    17681772        else if (updatedDiff == StyleDifferenceLayoutPositionedMovementOnly)
    17691773            setNeedsPositionedMovementLayout();
     1774        else if (updatedDiff == StyleDifferenceSimplifiedLayout)
     1775            setNeedsSimplifiedNormalFlowLayout();
    17701776    }
    17711777   
     
    18811887        return;
    18821888   
    1883     if (diff == StyleDifferenceLayout) {
     1889    if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) {
    18841890        RenderCounter::rendererStyleChanged(this, oldStyle, m_style.get());
    18851891
     
    18921898            markContainingBlocksForLayout();
    18931899
    1894         setNeedsLayoutAndPrefWidthsRecalc();
     1900        if (diff == StyleDifferenceLayout)
     1901            setNeedsLayoutAndPrefWidthsRecalc();
     1902        else
     1903            setNeedsSimplifiedNormalFlowLayout();
    18951904    } else if (diff == StyleDifferenceLayoutPositionedMovementOnly)
    18961905        setNeedsPositionedMovementLayout();
  • trunk/Source/WebCore/rendering/RenderObject.h

    r81747 r81802  
    416416    bool mustRepaintBackgroundOrBorder() const;
    417417    bool hasBackground() const { return style()->hasBackground(); }
    418     bool needsLayout() const { return m_needsLayout || m_normalChildNeedsLayout || m_posChildNeedsLayout || m_needsPositionedMovementLayout; }
     418    bool needsLayout() const { return m_needsLayout || m_normalChildNeedsLayout || m_posChildNeedsLayout || m_needsSimplifiedNormalFlowLayout || m_needsPositionedMovementLayout; }
    419419    bool selfNeedsLayout() const { return m_needsLayout; }
    420420    bool needsPositionedMovementLayout() const { return m_needsPositionedMovementLayout; }
    421     bool needsPositionedMovementLayoutOnly() const { return m_needsPositionedMovementLayout && !m_needsLayout && !m_normalChildNeedsLayout && !m_posChildNeedsLayout; }
     421    bool needsPositionedMovementLayoutOnly() const { return m_needsPositionedMovementLayout && !m_needsLayout && !m_normalChildNeedsLayout && !m_posChildNeedsLayout && !m_needsSimplifiedNormalFlowLayout; }
    422422    bool posChildNeedsLayout() const { return m_posChildNeedsLayout; }
     423    bool needsSimplifiedNormalFlowLayout() const { return m_needsSimplifiedNormalFlowLayout; }
    423424    bool normalChildNeedsLayout() const { return m_normalChildNeedsLayout; }
    424425   
     
    489490    void setChildNeedsLayout(bool b, bool markParents = true);
    490491    void setNeedsPositionedMovementLayout();
     492    void setNeedsSimplifiedNormalFlowLayout();
    491493    void setPreferredLogicalWidthsDirty(bool, bool markParents = true);
    492494    void invalidateContainerPreferredLogicalWidths();
     
    847849    bool m_normalChildNeedsLayout    : 1;
    848850    bool m_posChildNeedsLayout       : 1;
     851    bool m_needsSimplifiedNormalFlowLayout  : 1;
    849852    bool m_preferredLogicalWidthsDirty           : 1;
    850853    bool m_floating                  : 1;
     
    932935        m_everHadLayout = true;
    933936        m_posChildNeedsLayout = false;
     937        m_needsSimplifiedNormalFlowLayout = false;
    934938        m_normalChildNeedsLayout = false;
    935939        m_needsPositionedMovementLayout = false;
     
    947951    } else {
    948952        m_posChildNeedsLayout = false;
     953        m_needsSimplifiedNormalFlowLayout = false;
    949954        m_normalChildNeedsLayout = false;
    950955        m_needsPositionedMovementLayout = false;
     
    956961    bool alreadyNeededLayout = needsLayout();
    957962    m_needsPositionedMovementLayout = true;
     963    if (!alreadyNeededLayout) {
     964        markContainingBlocksForLayout();
     965        if (hasLayer())
     966            setLayerNeedsFullRepaint();
     967    }
     968}
     969
     970inline void RenderObject::setNeedsSimplifiedNormalFlowLayout()
     971{
     972    bool alreadyNeededLayout = needsLayout();
     973    m_needsSimplifiedNormalFlowLayout = true;
    958974    if (!alreadyNeededLayout) {
    959975        markContainingBlocksForLayout();
     
    983999    RenderObject* last = this;
    9841000
     1001    bool simplifiedNormalFlowLayout = needsSimplifiedNormalFlowLayout() && !selfNeedsLayout() && !normalChildNeedsLayout();
     1002
    9851003    while (o) {
    9861004        // Don't mark the outermost object of an unrooted subtree. That object will be
     
    9901008            return;
    9911009        if (!last->isText() && (last->style()->position() == FixedPosition || last->style()->position() == AbsolutePosition)) {
    992             if (last->style()->top().isAuto() && last->style()->bottom().isAuto()) {
    993                 RenderObject* parent = last->parent();
    994                 if (!parent->normalChildNeedsLayout()) {
    995                     parent->setChildNeedsLayout(true, false);
    996                     if (parent != newRoot)
    997                         parent->markContainingBlocksForLayout(scheduleRelayout, newRoot);
    998                 }
    999             }
    10001010            if (o->m_posChildNeedsLayout)
    10011011                return;
    10021012            o->m_posChildNeedsLayout = true;
     1013            simplifiedNormalFlowLayout = true;
     1014            ASSERT(!o->isSetNeedsLayoutForbidden());
     1015        } else if (simplifiedNormalFlowLayout) {
     1016            if (o->m_needsSimplifiedNormalFlowLayout)
     1017                return;
     1018            o->m_needsSimplifiedNormalFlowLayout = true;
    10031019            ASSERT(!o->isSetNeedsLayoutForbidden());
    10041020        } else {
  • trunk/Source/WebCore/rendering/RenderTable.cpp

    r81304 r81802  
    262262    ASSERT(needsLayout());
    263263
    264     if (layoutOnlyPositionedObjects())
     264    if (simplifiedLayout())
    265265        return;
    266266
  • trunk/Source/WebCore/rendering/style/RenderStyle.cpp

    r81684 r81802  
    486486        return StyleDifferenceLayout;
    487487
     488    if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE))
     489        return StyleDifferenceLayout;
     490
    488491    if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1) ||
    489492        (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) {
    490         // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
     493        // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet.
     494        // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
     495        // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
     496        // In addition we need to solve the floating object issue when layers come and go. Right now
     497        // a full layout is necessary to keep floating object lists sane.
    491498        return StyleDifferenceLayout;
    492499    }
    493500
    494     if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE))
    495         return StyleDifferenceLayout;
    496                    
    497501#if ENABLE(SVG)
    498502    // SVGRenderStyle::diff() might have returned StyleDifferenceRepaint, eg. if fill changes.
     
    512516                return StyleDifferenceLayoutPositionedMovementOnly;
    513517
    514             // FIXME: We will need to do a bit of work in RenderObject/Box::setStyle before we
    515             // can stop doing a layout when relative positioned objects move.  In particular, we'll need
    516             // to update scrolling positions and figure out how to do a repaint properly of the updated layer.
    517             //if (other->position() == RelativePosition)
    518             //    return RepaintLayer;
    519             //else
    520                 return StyleDifferenceLayout;
     518            // FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet.
     519            // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
     520            // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
     521            return StyleDifferenceLayout;
    521522        } else if (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex() ||
    522523                 visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip)
  • trunk/Source/WebCore/rendering/style/RenderStyleConstants.h

    r80151 r81802  
    5252    StyleDifferenceRepaintLayer,
    5353    StyleDifferenceLayoutPositionedMovementOnly,
     54    StyleDifferenceSimplifiedLayout,
    5455    StyleDifferenceLayout
    5556};
  • trunk/Source/WebCore/rendering/svg/RenderSVGText.cpp

    r77485 r81802  
    135135    // All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions.
    136136    ASSERT(!isInline());
    137     ASSERT(!layoutOnlyPositionedObjects());
     137    ASSERT(!simplifiedLayout());
    138138    ASSERT(!scrollsOverflow());
    139139    ASSERT(!hasControlClip());
Note: See TracChangeset for help on using the changeset viewer.