Changeset 155555 in webkit


Ignore:
Timestamp:
Sep 11, 2013 12:50:03 PM (11 years ago)
Author:
hyatt@apple.com
Message:

Move all collapsing margin code out of RenderBlock and into RenderBlockFlow.
https://bugs.webkit.org/show_bug.cgi?id=121049

Reviewed by Dean Jackson.

This patch begins the migration of the rare data struct of RenderBlock into
RenderBlockFlow. During this process we will temporarily have rare data structs
in both places, but ultimately all of the members are going to move down into
RenderBlockFlow, and if any don't, they will get forced into a hash.

For this patch, the margin information is being shifted out of RenderBlock and into
RenderBlockFlow. Any functions that refer to MarginValues or to MarginInfo also got
moved down into RenderBlockFlow. Most of block child layout is now in RenderBlockFlow
after this patch.

Note that in many cases the code didn't simply move. There is some type tightening
that happened as well, i.e., places that look for RenderBlock can now look for
RenderBlockFlow instead and let RenderBlock execute the base RenderBox functions.

  • rendering/RenderBlock.cpp:

(WebCore::RenderBlock::RenderBlock):
(WebCore::RenderBlock::setPaginationStrut):
(WebCore::RenderBlock::setPageLogicalOffset):
(WebCore::RenderBlock::setBreakAtLineToAvoidWidow):

  • rendering/RenderBlock.h:

(WebCore::RenderBlock::setLineGridBox):
(WebCore::RenderBlock::setShapeInsideInfo):
(WebCore::RenderBlock::RenderBlockRareData::RenderBlockRareData):

  • rendering/RenderBlockFlow.cpp:

(WebCore::RenderBlockFlow::MarginInfo::MarginInfo):
(WebCore::RenderBlockFlow::RenderBlockFlow):
(WebCore::RenderBlockFlow::layoutBlockChild):
(WebCore::RenderBlockFlow::adjustPositionedBlock):
(WebCore::RenderBlockFlow::adjustFloatingBlock):
(WebCore::RenderBlockFlow::marginValuesForChild):
(WebCore::RenderBlockFlow::collapseMargins):
(WebCore::RenderBlockFlow::clearFloatsIfNeeded):
(WebCore::RenderBlockFlow::marginBeforeEstimateForChild):
(WebCore::RenderBlockFlow::estimateLogicalTopPosition):
(WebCore::RenderBlockFlow::setCollapsedBottomMargin):
(WebCore::RenderBlockFlow::handleAfterSideOfBlock):
(WebCore::RenderBlockFlow::setMaxMarginBeforeValues):
(WebCore::RenderBlockFlow::setMaxMarginAfterValues):
(WebCore::RenderBlockFlow::setMustDiscardMarginBefore):
(WebCore::RenderBlockFlow::setMustDiscardMarginAfter):
(WebCore::RenderBlockFlow::mustDiscardMarginBefore):
(WebCore::RenderBlockFlow::mustDiscardMarginAfter):
(WebCore::RenderBlockFlow::mustDiscardMarginBeforeForChild):
(WebCore::RenderBlockFlow::mustDiscardMarginAfterForChild):
(WebCore::RenderBlockFlow::mustSeparateMarginBeforeForChild):
(WebCore::RenderBlockFlow::mustSeparateMarginAfterForChild):
(WebCore::inNormalFlow):
(WebCore::RenderBlockFlow::applyBeforeBreak):
(WebCore::RenderBlockFlow::applyAfterBreak):
(WebCore::RenderBlockFlow::adjustBlockChildForPagination):

  • rendering/RenderBlockFlow.h:

(WebCore::RenderBlockFlow::MarginValues::MarginValues):
(WebCore::RenderBlockFlow::MarginValues::positiveMarginBefore):
(WebCore::RenderBlockFlow::MarginValues::negativeMarginBefore):
(WebCore::RenderBlockFlow::MarginValues::positiveMarginAfter):
(WebCore::RenderBlockFlow::MarginValues::negativeMarginAfter):
(WebCore::RenderBlockFlow::MarginValues::setPositiveMarginBefore):
(WebCore::RenderBlockFlow::MarginValues::setNegativeMarginBefore):
(WebCore::RenderBlockFlow::MarginValues::setPositiveMarginAfter):
(WebCore::RenderBlockFlow::MarginValues::setNegativeMarginAfter):
(WebCore::RenderBlockFlow::RenderBlockFlowRareData::RenderBlockFlowRareData):
(WebCore::RenderBlockFlow::RenderBlockFlowRareData::positiveMarginBeforeDefault):
(WebCore::RenderBlockFlow::RenderBlockFlowRareData::negativeMarginBeforeDefault):
(WebCore::RenderBlockFlow::RenderBlockFlowRareData::positiveMarginAfterDefault):
(WebCore::RenderBlockFlow::RenderBlockFlowRareData::negativeMarginAfterDefault):
(WebCore::RenderBlockFlow::MarginInfo::setAtBeforeSideOfBlock):
(WebCore::RenderBlockFlow::MarginInfo::setAtAfterSideOfBlock):
(WebCore::RenderBlockFlow::MarginInfo::clearMargin):
(WebCore::RenderBlockFlow::MarginInfo::setHasMarginBeforeQuirk):
(WebCore::RenderBlockFlow::MarginInfo::setHasMarginAfterQuirk):
(WebCore::RenderBlockFlow::MarginInfo::setDeterminedMarginBeforeQuirk):
(WebCore::RenderBlockFlow::MarginInfo::setPositiveMargin):
(WebCore::RenderBlockFlow::MarginInfo::setNegativeMargin):
(WebCore::RenderBlockFlow::MarginInfo::setPositiveMarginIfLarger):
(WebCore::RenderBlockFlow::MarginInfo::setNegativeMarginIfLarger):
(WebCore::RenderBlockFlow::MarginInfo::setMargin):
(WebCore::RenderBlockFlow::MarginInfo::setCanCollapseMarginAfterWithChildren):
(WebCore::RenderBlockFlow::MarginInfo::setDiscardMargin):
(WebCore::RenderBlockFlow::MarginInfo::atBeforeSideOfBlock):
(WebCore::RenderBlockFlow::MarginInfo::canCollapseWithMarginBefore):
(WebCore::RenderBlockFlow::MarginInfo::canCollapseWithMarginAfter):
(WebCore::RenderBlockFlow::MarginInfo::canCollapseMarginBeforeWithChildren):
(WebCore::RenderBlockFlow::MarginInfo::canCollapseMarginAfterWithChildren):
(WebCore::RenderBlockFlow::MarginInfo::quirkContainer):
(WebCore::RenderBlockFlow::MarginInfo::determinedMarginBeforeQuirk):
(WebCore::RenderBlockFlow::MarginInfo::hasMarginBeforeQuirk):
(WebCore::RenderBlockFlow::MarginInfo::hasMarginAfterQuirk):
(WebCore::RenderBlockFlow::MarginInfo::positiveMargin):
(WebCore::RenderBlockFlow::MarginInfo::negativeMargin):
(WebCore::RenderBlockFlow::MarginInfo::discardMargin):
(WebCore::RenderBlockFlow::MarginInfo::margin):
(WebCore::RenderBlockFlow::maxPositiveMarginBefore):
(WebCore::RenderBlockFlow::maxNegativeMarginBefore):
(WebCore::RenderBlockFlow::maxPositiveMarginAfter):
(WebCore::RenderBlockFlow::maxNegativeMarginAfter):
(WebCore::RenderBlockFlow::initMaxMarginValues):

  • rendering/RenderDeprecatedFlexibleBox.cpp:

(WebCore::RenderDeprecatedFlexibleBox::layoutBlock):

  • rendering/RenderTable.cpp:

(WebCore::RenderTable::layout):

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r155554 r155555  
     12013-09-11  David Hyatt  <hyatt@apple.com>
     2
     3        Move all collapsing margin code out of RenderBlock and into RenderBlockFlow.
     4        https://bugs.webkit.org/show_bug.cgi?id=121049
     5
     6        Reviewed by Dean Jackson.
     7
     8        This patch begins the migration of the rare data struct of RenderBlock into
     9        RenderBlockFlow. During this process we will temporarily have rare data structs
     10        in both places, but ultimately all of the members are going to move down into
     11        RenderBlockFlow, and if any don't, they will get forced into a hash.
     12       
     13        For this patch, the margin information is being shifted out of RenderBlock and into
     14        RenderBlockFlow. Any functions that refer to MarginValues or to MarginInfo also got
     15        moved down into RenderBlockFlow. Most of block child layout is now in RenderBlockFlow
     16        after this patch.
     17       
     18        Note that in many cases the code didn't simply move. There is some type tightening
     19        that happened as well, i.e., places that look for RenderBlock can now look for
     20        RenderBlockFlow instead and let RenderBlock execute the base RenderBox functions.
     21
     22        * rendering/RenderBlock.cpp:
     23        (WebCore::RenderBlock::RenderBlock):
     24        (WebCore::RenderBlock::setPaginationStrut):
     25        (WebCore::RenderBlock::setPageLogicalOffset):
     26        (WebCore::RenderBlock::setBreakAtLineToAvoidWidow):
     27        * rendering/RenderBlock.h:
     28        (WebCore::RenderBlock::setLineGridBox):
     29        (WebCore::RenderBlock::setShapeInsideInfo):
     30        (WebCore::RenderBlock::RenderBlockRareData::RenderBlockRareData):
     31        * rendering/RenderBlockFlow.cpp:
     32        (WebCore::RenderBlockFlow::MarginInfo::MarginInfo):
     33        (WebCore::RenderBlockFlow::RenderBlockFlow):
     34        (WebCore::RenderBlockFlow::layoutBlockChild):
     35        (WebCore::RenderBlockFlow::adjustPositionedBlock):
     36        (WebCore::RenderBlockFlow::adjustFloatingBlock):
     37        (WebCore::RenderBlockFlow::marginValuesForChild):
     38        (WebCore::RenderBlockFlow::collapseMargins):
     39        (WebCore::RenderBlockFlow::clearFloatsIfNeeded):
     40        (WebCore::RenderBlockFlow::marginBeforeEstimateForChild):
     41        (WebCore::RenderBlockFlow::estimateLogicalTopPosition):
     42        (WebCore::RenderBlockFlow::setCollapsedBottomMargin):
     43        (WebCore::RenderBlockFlow::handleAfterSideOfBlock):
     44        (WebCore::RenderBlockFlow::setMaxMarginBeforeValues):
     45        (WebCore::RenderBlockFlow::setMaxMarginAfterValues):
     46        (WebCore::RenderBlockFlow::setMustDiscardMarginBefore):
     47        (WebCore::RenderBlockFlow::setMustDiscardMarginAfter):
     48        (WebCore::RenderBlockFlow::mustDiscardMarginBefore):
     49        (WebCore::RenderBlockFlow::mustDiscardMarginAfter):
     50        (WebCore::RenderBlockFlow::mustDiscardMarginBeforeForChild):
     51        (WebCore::RenderBlockFlow::mustDiscardMarginAfterForChild):
     52        (WebCore::RenderBlockFlow::mustSeparateMarginBeforeForChild):
     53        (WebCore::RenderBlockFlow::mustSeparateMarginAfterForChild):
     54        (WebCore::inNormalFlow):
     55        (WebCore::RenderBlockFlow::applyBeforeBreak):
     56        (WebCore::RenderBlockFlow::applyAfterBreak):
     57        (WebCore::RenderBlockFlow::adjustBlockChildForPagination):
     58        * rendering/RenderBlockFlow.h:
     59        (WebCore::RenderBlockFlow::MarginValues::MarginValues):
     60        (WebCore::RenderBlockFlow::MarginValues::positiveMarginBefore):
     61        (WebCore::RenderBlockFlow::MarginValues::negativeMarginBefore):
     62        (WebCore::RenderBlockFlow::MarginValues::positiveMarginAfter):
     63        (WebCore::RenderBlockFlow::MarginValues::negativeMarginAfter):
     64        (WebCore::RenderBlockFlow::MarginValues::setPositiveMarginBefore):
     65        (WebCore::RenderBlockFlow::MarginValues::setNegativeMarginBefore):
     66        (WebCore::RenderBlockFlow::MarginValues::setPositiveMarginAfter):
     67        (WebCore::RenderBlockFlow::MarginValues::setNegativeMarginAfter):
     68        (WebCore::RenderBlockFlow::RenderBlockFlowRareData::RenderBlockFlowRareData):
     69        (WebCore::RenderBlockFlow::RenderBlockFlowRareData::positiveMarginBeforeDefault):
     70        (WebCore::RenderBlockFlow::RenderBlockFlowRareData::negativeMarginBeforeDefault):
     71        (WebCore::RenderBlockFlow::RenderBlockFlowRareData::positiveMarginAfterDefault):
     72        (WebCore::RenderBlockFlow::RenderBlockFlowRareData::negativeMarginAfterDefault):
     73        (WebCore::RenderBlockFlow::MarginInfo::setAtBeforeSideOfBlock):
     74        (WebCore::RenderBlockFlow::MarginInfo::setAtAfterSideOfBlock):
     75        (WebCore::RenderBlockFlow::MarginInfo::clearMargin):
     76        (WebCore::RenderBlockFlow::MarginInfo::setHasMarginBeforeQuirk):
     77        (WebCore::RenderBlockFlow::MarginInfo::setHasMarginAfterQuirk):
     78        (WebCore::RenderBlockFlow::MarginInfo::setDeterminedMarginBeforeQuirk):
     79        (WebCore::RenderBlockFlow::MarginInfo::setPositiveMargin):
     80        (WebCore::RenderBlockFlow::MarginInfo::setNegativeMargin):
     81        (WebCore::RenderBlockFlow::MarginInfo::setPositiveMarginIfLarger):
     82        (WebCore::RenderBlockFlow::MarginInfo::setNegativeMarginIfLarger):
     83        (WebCore::RenderBlockFlow::MarginInfo::setMargin):
     84        (WebCore::RenderBlockFlow::MarginInfo::setCanCollapseMarginAfterWithChildren):
     85        (WebCore::RenderBlockFlow::MarginInfo::setDiscardMargin):
     86        (WebCore::RenderBlockFlow::MarginInfo::atBeforeSideOfBlock):
     87        (WebCore::RenderBlockFlow::MarginInfo::canCollapseWithMarginBefore):
     88        (WebCore::RenderBlockFlow::MarginInfo::canCollapseWithMarginAfter):
     89        (WebCore::RenderBlockFlow::MarginInfo::canCollapseMarginBeforeWithChildren):
     90        (WebCore::RenderBlockFlow::MarginInfo::canCollapseMarginAfterWithChildren):
     91        (WebCore::RenderBlockFlow::MarginInfo::quirkContainer):
     92        (WebCore::RenderBlockFlow::MarginInfo::determinedMarginBeforeQuirk):
     93        (WebCore::RenderBlockFlow::MarginInfo::hasMarginBeforeQuirk):
     94        (WebCore::RenderBlockFlow::MarginInfo::hasMarginAfterQuirk):
     95        (WebCore::RenderBlockFlow::MarginInfo::positiveMargin):
     96        (WebCore::RenderBlockFlow::MarginInfo::negativeMargin):
     97        (WebCore::RenderBlockFlow::MarginInfo::discardMargin):
     98        (WebCore::RenderBlockFlow::MarginInfo::margin):
     99        (WebCore::RenderBlockFlow::maxPositiveMarginBefore):
     100        (WebCore::RenderBlockFlow::maxNegativeMarginBefore):
     101        (WebCore::RenderBlockFlow::maxPositiveMarginAfter):
     102        (WebCore::RenderBlockFlow::maxNegativeMarginAfter):
     103        (WebCore::RenderBlockFlow::initMaxMarginValues):
     104        * rendering/RenderDeprecatedFlexibleBox.cpp:
     105        (WebCore::RenderDeprecatedFlexibleBox::layoutBlock):
     106        * rendering/RenderTable.cpp:
     107        (WebCore::RenderTable::layout):
     108
    11092013-09-11  Myles C. Maxfield  <mmaxfield@apple.com>
    2110
  • trunk/Source/WebCore/rendering/RenderBlock.cpp

    r155546 r155555  
    9292COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small);
    9393
    94 COMPILE_ASSERT(sizeof(RenderBlock::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
    95 
    96 struct SameSizeAsMarginInfo {
    97     uint32_t bitfields : 16;
    98     LayoutUnit margins[2];
    99 };
    100 
    10194typedef WTF::HashMap<const RenderBox*, OwnPtr<ColumnInfo> > ColumnInfoMap;
    10295static ColumnInfoMap* gColumnInfoMap = 0;
     
    156149};
    157150
    158 // Our MarginInfo state used when laying out block children.
    159 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
    160     : m_atBeforeSideOfBlock(true)
    161     , m_atAfterSideOfBlock(false)
    162     , m_hasMarginBeforeQuirk(false)
    163     , m_hasMarginAfterQuirk(false)
    164     , m_determinedMarginBeforeQuirk(false)
    165     , m_discardMargin(false)
    166 {
    167     RenderStyle* blockStyle = block->style();
    168     ASSERT(block->isRenderView() || block->parent());
    169     m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isOutOfFlowPositioned()
    170         && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
    171         && !block->isRenderFlowThread() && !block->isWritingModeRoot() && !block->parent()->isFlexibleBox()
    172         && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth() && !blockStyle->columnSpan();
    173 
    174     m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE;
    175 
    176     // If any height other than auto is specified in CSS, then we don't collapse our bottom
    177     // margins with our children's margins.  To do otherwise would be to risk odd visual
    178     // effects when the children overflow out of the parent block and yet still collapse
    179     // with it.  We also don't collapse if we have any bottom border/padding.
    180     m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && (afterBorderPadding == 0) &&
    181         (blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE;
    182    
    183     m_quirkContainer = block->isTableCell() || block->isBody();
    184 
    185     m_discardMargin = m_canCollapseMarginBeforeWithChildren && block->mustDiscardMarginBefore();
    186 
    187     m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxPositiveMarginBefore() : LayoutUnit();
    188     m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxNegativeMarginBefore() : LayoutUnit();
    189 }
    190 
    191151// -------------------------------------------------------------------------------------------------------
    192152
     
    205165{
    206166    setChildrenInline(true);
    207     COMPILE_ASSERT(sizeof(RenderBlock::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
    208167}
    209168
     
    17691728}
    17701729
    1771 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
    1772 {
    1773     bool isHorizontal = isHorizontalWritingMode();
    1774     bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
    1775    
    1776     LayoutUnit logicalTop = logicalHeight();
    1777     updateStaticInlinePositionForChild(child, logicalTop);
    1778 
    1779     if (!marginInfo.canCollapseWithMarginBefore()) {
    1780         // Positioned blocks don't collapse margins, so add the margin provided by
    1781         // the container now. The child's own margin is added later when calculating its logical top.
    1782         LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
    1783         LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
    1784         logicalTop += collapsedBeforePos - collapsedBeforeNeg;
    1785     }
    1786    
    1787     RenderLayer* childLayer = child->layer();
    1788     if (childLayer->staticBlockPosition() != logicalTop) {
    1789         childLayer->setStaticBlockPosition(logicalTop);
    1790         if (hasStaticBlockPosition)
    1791             child->setChildNeedsLayout(true, MarkOnlyThis);
    1792     }
    1793 }
    1794 
    1795 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
    1796 {
    1797     // The float should be positioned taking into account the bottom margin
    1798     // of the previous flow.  We add that margin into the height, get the
    1799     // float positioned properly, and then subtract the margin out of the
    1800     // height again.  In the case of self-collapsing blocks, we always just
    1801     // use the top margins, since the self-collapsing block collapsed its
    1802     // own bottom margin into its top margin.
    1803     //
    1804     // Note also that the previous flow may collapse its margin into the top of
    1805     // our block.  If this is the case, then we do not add the margin in to our
    1806     // height when computing the position of the float.   This condition can be tested
    1807     // for by simply calling canCollapseWithMarginBefore.  See
    1808     // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
    1809     // an example of this scenario.
    1810     LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
    1811     setLogicalHeight(logicalHeight() + marginOffset);
    1812     positionNewFloats();
    1813     setLogicalHeight(logicalHeight() - marginOffset);
    1814 }
    1815 
    18161730static void destroyRunIn(RenderBoxModelObject* runIn)
    18171731{
     
    19521866}
    19531867
    1954 LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
    1955 {
    1956     bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
    1957     bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
    1958     bool childIsSelfCollapsing = child->isSelfCollapsingBlock();
    1959 
    1960     // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
    1961     childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
    1962 
    1963     // Get the four margin values for the child and cache them.
    1964     const MarginValues childMargins = marginValuesForChild(child);
    1965 
    1966     // Get our max pos and neg top margins.
    1967     LayoutUnit posTop = childMargins.positiveMarginBefore();
    1968     LayoutUnit negTop = childMargins.negativeMarginBefore();
    1969 
    1970     // For self-collapsing blocks, collapse our bottom margins into our
    1971     // top to get new posTop and negTop values.
    1972     if (childIsSelfCollapsing) {
    1973         posTop = max(posTop, childMargins.positiveMarginAfter());
    1974         negTop = max(negTop, childMargins.negativeMarginAfter());
    1975     }
    1976    
    1977     // See if the top margin is quirky. We only care if this child has
    1978     // margins that will collapse with us.
    1979     bool topQuirk = hasMarginBeforeQuirk(child);
    1980 
    1981     if (marginInfo.canCollapseWithMarginBefore()) {
    1982         if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
    1983             // This child is collapsing with the top of the
    1984             // block. If it has larger margin values, then we need to update
    1985             // our own maximal values.
    1986             if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
    1987                 setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
    1988 
    1989             // The minute any of the margins involved isn't a quirk, don't
    1990             // collapse it away, even if the margin is smaller (www.webreference.com
    1991             // has an example of this, a <dt> with 0.8em author-specified inside
    1992             // a <dl> inside a <td>.
    1993             if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
    1994                 setHasMarginBeforeQuirk(false);
    1995                 marginInfo.setDeterminedMarginBeforeQuirk(true);
    1996             }
    1997 
    1998             if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
    1999                 // We have no top margin and our top child has a quirky margin.
    2000                 // We will pick up this quirky margin and pass it through.
    2001                 // This deals with the <td><div><p> case.
    2002                 // Don't do this for a block that split two inlines though. You do
    2003                 // still apply margins in this case.
    2004                 setHasMarginBeforeQuirk(true);
    2005         } else
    2006             // The before margin of the container will also discard all the margins it is collapsing with.
    2007             setMustDiscardMarginBefore();
    2008     }
    2009 
    2010     // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
    2011     if (childDiscardMarginBefore) {
    2012         marginInfo.setDiscardMargin(true);
    2013         marginInfo.clearMargin();
    2014     }
    2015 
    2016     if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
    2017         marginInfo.setHasMarginBeforeQuirk(topQuirk);
    2018 
    2019     LayoutUnit beforeCollapseLogicalTop = logicalHeight();
    2020     LayoutUnit logicalTop = beforeCollapseLogicalTop;
    2021     if (childIsSelfCollapsing) {
    2022         // For a self collapsing block both the before and after margins get discarded. The block doesn't contribute anything to the height of the block.
    2023         // Also, the child's top position equals the logical height of the container.
    2024         if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
    2025             // This child has no height. We need to compute our
    2026             // position before we collapse the child's margins together,
    2027             // so that we can get an accurate position for the zero-height block.
    2028             LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
    2029             LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
    2030             marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
    2031            
    2032             // Now collapse the child's margins together, which means examining our
    2033             // bottom margin values as well.
    2034             marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
    2035             marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
    2036 
    2037             if (!marginInfo.canCollapseWithMarginBefore())
    2038                 // We need to make sure that the position of the self-collapsing block
    2039                 // is correct, since it could have overflowing content
    2040                 // that needs to be positioned correctly (e.g., a block that
    2041                 // had a specified height of 0 but that actually had subcontent).
    2042                 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
    2043         }
    2044     } else {
    2045         if (mustSeparateMarginBeforeForChild(child)) {
    2046             ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
    2047             // If we are at the before side of the block and we collapse, ignore the computed margin
    2048             // and just add the child margin to the container height. This will correctly position
    2049             // the child inside the container.
    2050             LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit(0);
    2051             setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child));
    2052             logicalTop = logicalHeight();
    2053         } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
    2054             || (!marginInfo.canCollapseMarginBeforeWithChildren()
    2055             && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
    2056             // We're collapsing with a previous sibling's margins and not
    2057             // with the top of the block.
    2058             setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
    2059             logicalTop = logicalHeight();
    2060         }
    2061 
    2062         marginInfo.setDiscardMargin(childDiscardMarginAfter);
    2063        
    2064         if (!marginInfo.discardMargin()) {
    2065             marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
    2066             marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
    2067         } else
    2068             marginInfo.clearMargin();
    2069 
    2070         if (marginInfo.margin())
    2071             marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
    2072     }
    2073    
    2074     // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
    2075     // collapsed into the page edge.
    2076     LayoutState* layoutState = view().layoutState();
    2077     if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
    2078         && hasNextPage(beforeCollapseLogicalTop)) {
    2079         LayoutUnit oldLogicalTop = logicalTop;
    2080         logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
    2081         setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
    2082     }
    2083 
    2084     // If we have collapsed into a previous sibling and so reduced the height of the parent, ensure any floats that now
    2085     // overhang from the previous sibling are added to our parent. If the child's previous sibling itself is a float the child will avoid
    2086     // or clear it anyway, so don't worry about any floating children it may contain.
    2087     LayoutUnit oldLogicalHeight = logicalHeight();
    2088     setLogicalHeight(logicalTop);
    2089     RenderObject* prev = child->previousSibling();
    2090     if (prev && prev->isRenderBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned()) {
    2091         RenderBlock* block = toRenderBlock(prev);
    2092         if (block->containsFloats() && !block->avoidsFloats() && (block->logicalTop() + block->lowestFloatLogicalBottom()) > logicalTop)
    2093             addOverhangingFloats(block, false);
    2094     }
    2095     setLogicalHeight(oldLogicalHeight);
    2096 
    2097     return logicalTop;
    2098 }
    2099 
    2100 LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
    2101 {
    2102     LayoutUnit heightIncrease = getClearDelta(child, yPos);
    2103     if (!heightIncrease)
    2104         return yPos;
    2105 
    2106     if (child->isSelfCollapsingBlock()) {
    2107         bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
    2108 
    2109         // For self-collapsing blocks that clear, they can still collapse their
    2110         // margins with following siblings.  Reset the current margins to represent
    2111         // the self-collapsing block's margins only.
    2112         // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
    2113         if (!childDiscardMargin) {
    2114             MarginValues childMargins = marginValuesForChild(child);
    2115             marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
    2116             marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
    2117         } else
    2118             marginInfo.clearMargin();
    2119         marginInfo.setDiscardMargin(childDiscardMargin);
    2120 
    2121         // CSS2.1 states:
    2122         // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
    2123         // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
    2124         // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
    2125         // for a block with height - if none is found then don't allow the margins to collapse with the parent.
    2126         bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
    2127         for (RenderBox* curr = child->nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
    2128             if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
    2129                 wouldCollapseMarginsWithParent = false;
    2130         }
    2131         if (wouldCollapseMarginsWithParent)
    2132             marginInfo.setCanCollapseMarginAfterWithChildren(false);
    2133 
    2134         // CSS2.1: "the amount of clearance is set so that clearance + margin-top = [height of float], i.e., clearance = [height of float] - margin-top"
    2135         // Move the top of the child box to the bottom of the float ignoring the child's top margin.
    2136         LayoutUnit collapsedMargin = collapsedMarginBeforeForChild(child);
    2137         setLogicalHeight(child->logicalTop() - collapsedMargin);
    2138         // A negative collapsed margin-top value cancels itself out as it has already been factored into |yPos| above.
    2139         heightIncrease -= max(LayoutUnit(), collapsedMargin);
    2140     } else
    2141         // Increase our height by the amount we had to clear.
    2142         setLogicalHeight(logicalHeight() + heightIncrease);
    2143    
    2144     if (marginInfo.canCollapseWithMarginBefore()) {
    2145         // We can no longer collapse with the top of the block since a clear
    2146         // occurred.  The empty blocks collapse into the cleared block.
    2147         // FIXME: This isn't quite correct.  Need clarification for what to do
    2148         // if the height the cleared block is offset by is smaller than the
    2149         // margins involved.
    2150         setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
    2151         marginInfo.setAtBeforeSideOfBlock(false);
    2152 
    2153         // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value.
    2154         setMustDiscardMarginBefore(style()->marginBeforeCollapse() == MDISCARD);
    2155     }
    2156 
    2157     LayoutUnit logicalTop = yPos + heightIncrease;
    2158     // After margin collapsing, one of our floats may now intrude into the child. If the child doesn't contain floats of its own it
    2159     // won't get picked up for relayout even though the logical top estimate was wrong - so add the newly intruding float now.
    2160     if (containsFloats() && child->isRenderBlock() && !toRenderBlock(child)->containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
    2161         toRenderBlock(child)->addIntrudingFloats(this, logicalLeftOffsetForContent(), logicalTop);
    2162 
    2163     return logicalTop;
    2164 }
    2165 
    2166 void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
    2167 {
    2168     // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
    2169     // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
    2170     // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
    2171     if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child->style()->marginBeforeCollapse() == MSEPARATE)
    2172         return;
    2173 
    2174     // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
    2175     // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
    2176     if (child->style()->marginBeforeCollapse() == MDISCARD) {
    2177         positiveMarginBefore = 0;
    2178         negativeMarginBefore = 0;
    2179         discardMarginBefore = true;
    2180         return;
    2181     }
    2182 
    2183     LayoutUnit beforeChildMargin = marginBeforeForChild(child);
    2184     positiveMarginBefore = max(positiveMarginBefore, beforeChildMargin);
    2185     negativeMarginBefore = max(negativeMarginBefore, -beforeChildMargin);
    2186 
    2187     if (!child->isRenderBlock())
    2188         return;
    2189    
    2190     RenderBlock* childBlock = toRenderBlock(child);
    2191     if (childBlock->childrenInline() || childBlock->isWritingModeRoot())
    2192         return;
    2193 
    2194     MarginInfo childMarginInfo(childBlock, childBlock->borderAndPaddingBefore(), childBlock->borderAndPaddingAfter());
    2195     if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
    2196         return;
    2197 
    2198     RenderBox* grandchildBox = childBlock->firstChildBox();
    2199     for ( ; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
    2200         if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
    2201             break;
    2202     }
    2203    
    2204     // Give up if there is clearance on the box, since it probably won't collapse into us.
    2205     if (!grandchildBox || grandchildBox->style()->clear() != CNONE)
    2206         return;
    2207 
    2208     // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
    2209     if (grandchildBox->needsLayout()) {
    2210         grandchildBox->computeAndSetBlockDirectionMargins(this);
    2211         if (grandchildBox->isRenderBlock()) {
    2212             RenderBlock* grandchildBlock = toRenderBlock(grandchildBox);
    2213             grandchildBlock->setHasMarginBeforeQuirk(grandchildBox->style()->hasMarginBeforeQuirk());
    2214             grandchildBlock->setHasMarginAfterQuirk(grandchildBox->style()->hasMarginAfterQuirk());
    2215         }
    2216     }
    2217 
    2218     // Collapse the margin of the grandchild box with our own to produce an estimate.
    2219     childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
    2220 }
    2221 
    2222 LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
    2223 {
    2224     // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
    2225     // relayout if there are intruding floats.
    2226     LayoutUnit logicalTopEstimate = logicalHeight();
    2227     if (!marginInfo.canCollapseWithMarginBefore()) {
    2228         LayoutUnit positiveMarginBefore = 0;
    2229         LayoutUnit negativeMarginBefore = 0;
    2230         bool discardMarginBefore = false;
    2231         if (child->selfNeedsLayout()) {
    2232             // Try to do a basic estimation of how the collapse is going to go.
    2233             marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
    2234         } else {
    2235             // Use the cached collapsed margin values from a previous layout. Most of the time they
    2236             // will be right.
    2237             MarginValues marginValues = marginValuesForChild(child);
    2238             positiveMarginBefore = max(positiveMarginBefore, marginValues.positiveMarginBefore());
    2239             negativeMarginBefore = max(negativeMarginBefore, marginValues.negativeMarginBefore());
    2240             discardMarginBefore = mustDiscardMarginBeforeForChild(child);
    2241         }
    2242 
    2243         // Collapse the result with our current margins.
    2244         if (!discardMarginBefore)
    2245             logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
    2246     }
    2247 
    2248     // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
    2249     // page.
    2250     LayoutState* layoutState = view().layoutState();
    2251     if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
    2252         && hasNextPage(logicalHeight()))
    2253         logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
    2254 
    2255     logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
    2256    
    2257     estimateWithoutPagination = logicalTopEstimate;
    2258 
    2259     if (layoutState->isPaginated()) {
    2260         // If the object has a page or column break value of "before", then we should shift to the top of the next page.
    2261         logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
    2262    
    2263         // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
    2264         logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
    2265        
    2266         if (!child->selfNeedsLayout() && child->isRenderBlock())
    2267             logicalTopEstimate += toRenderBlock(child)->paginationStrut();
    2268     }
    2269 
    2270     return logicalTopEstimate;
    2271 }
    2272 
    22731868LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, RenderRegion* region)
    22741869{
     
    23121907
    23131908    setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
    2314 }
    2315 
    2316 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
    2317 {
    2318     if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
    2319         // Update the after side margin of the container to discard if the after margin of the last child also discards and we collapse with it.
    2320         // Don't update the max margin values because we won't need them anyway.
    2321         if (marginInfo.discardMargin()) {
    2322             setMustDiscardMarginAfter();
    2323             return;
    2324         }
    2325 
    2326         // Update our max pos/neg bottom margins, since we collapsed our bottom margins
    2327         // with our children.
    2328         setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
    2329 
    2330         if (!marginInfo.hasMarginAfterQuirk())
    2331             setHasMarginAfterQuirk(false);
    2332 
    2333         if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
    2334             // We have no bottom margin and our last child has a quirky margin.
    2335             // We will pick up this quirky margin and pass it through.
    2336             // This deals with the <td><div><p> case.
    2337             setHasMarginAfterQuirk(true);
    2338     }
    2339 }
    2340 
    2341 void RenderBlock::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
    2342 {
    2343     marginInfo.setAtAfterSideOfBlock(true);
    2344 
    2345     // If we can't collapse with children then go ahead and add in the bottom margin.
    2346     if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
    2347         && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
    2348         setLogicalHeight(logicalHeight() + marginInfo.margin());
    2349        
    2350     // Now add in our bottom border/padding.
    2351     setLogicalHeight(logicalHeight() + afterSide);
    2352 
    2353     // Negative margins can cause our height to shrink below our minimal height (border/padding).
    2354     // If this happens, ensure that the computed height is increased to the minimal height.
    2355     setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
    2356 
    2357     // Update our bottom collapsed margin info.
    2358     setCollapsedBottomMargin(marginInfo);
    23591909}
    23601910
     
    24261976        }
    24271977    }
    2428 }
    2429 
    2430 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
    2431 {
    2432     LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
    2433     LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
    2434 
    2435     // The child is a normal flow object.  Compute the margins we will use for collapsing now.
    2436     child->computeAndSetBlockDirectionMargins(this);
    2437 
    2438     // Try to guess our correct logical top position.  In most cases this guess will
    2439     // be correct.  Only if we're wrong (when we compute the real logical top position)
    2440     // will we have to potentially relayout.
    2441     LayoutUnit estimateWithoutPagination;
    2442     LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
    2443 
    2444     // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
    2445     LayoutRect oldRect = child->frameRect();
    2446     LayoutUnit oldLogicalTop = logicalTopForChild(child);
    2447 
    2448 #if !ASSERT_DISABLED
    2449     LayoutSize oldLayoutDelta = view().layoutDelta();
    2450 #endif
    2451     // Go ahead and position the child as though it didn't collapse with the top.
    2452     setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
    2453     estimateRegionRangeForBoxChild(child);
    2454 
    2455     RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
    2456     bool markDescendantsWithFloats = false;
    2457     if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
    2458         markDescendantsWithFloats = true;
    2459 #if ENABLE(SUBPIXEL_LAYOUT)
    2460     else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
    2461         // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
    2462         // very large elements. If it does the comparison with oldLogicalTop might yield a
    2463         // false negative as adding and removing margins, borders etc from a saturated number
    2464         // might yield incorrect results. If this is the case always mark for layout.
    2465         markDescendantsWithFloats = true;
    2466 #endif
    2467     else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
    2468         // If an element might be affected by the presence of floats, then always mark it for
    2469         // layout.
    2470         LayoutUnit fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
    2471         if (fb > logicalTopEstimate)
    2472             markDescendantsWithFloats = true;
    2473     }
    2474 
    2475     if (childRenderBlock) {
    2476         if (markDescendantsWithFloats)
    2477             childRenderBlock->markAllDescendantsWithFloatsForLayout();
    2478         if (!child->isWritingModeRoot())
    2479             previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom());
    2480     }
    2481 
    2482     if (!child->needsLayout())
    2483         child->markForPaginationRelayoutIfNeeded();
    2484 
    2485     bool childHadLayout = child->everHadLayout();
    2486     bool childNeededLayout = child->needsLayout();
    2487     if (childNeededLayout)
    2488         child->layout();
    2489 
    2490     // Cache if we are at the top of the block right now.
    2491     bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
    2492 
    2493     // Now determine the correct ypos based off examination of collapsing margin
    2494     // values.
    2495     LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
    2496 
    2497     // Now check for clear.
    2498     LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
    2499    
    2500     bool paginated = view().layoutState()->isPaginated();
    2501     if (paginated)
    2502         logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child,
    2503             atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
    2504 
    2505     setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
    2506 
    2507     // Now we have a final top position.  See if it really does end up being different from our estimate.
    2508     // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
    2509     // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
    2510     if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout() || (paginated && childRenderBlock && childRenderBlock->shouldBreakAtLineToAvoidWidow())) {
    2511         if (child->shrinkToAvoidFloats()) {
    2512             // The child's width depends on the line width.
    2513             // When the child shifts to clear an item, its width can
    2514             // change (because it has more available line width).
    2515             // So go ahead and mark the item as dirty.
    2516             child->setChildNeedsLayout(true, MarkOnlyThis);
    2517         }
    2518        
    2519         if (childRenderBlock) {
    2520             if (!child->avoidsFloats() && childRenderBlock->containsFloats())
    2521                 childRenderBlock->markAllDescendantsWithFloatsForLayout();
    2522             if (!child->needsLayout())
    2523                 child->markForPaginationRelayoutIfNeeded();
    2524         }
    2525 
    2526         // Our guess was wrong. Make the child lay itself out again.
    2527         child->layoutIfNeeded();
    2528     }
    2529 
    2530     if (updateRegionRangeForBoxChild(child)) {
    2531         child->setNeedsLayout(true, MarkOnlyThis);
    2532         child->layoutIfNeeded();
    2533     }
    2534 
    2535     // We are no longer at the top of the block if we encounter a non-empty child. 
    2536     // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
    2537     if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
    2538         marginInfo.setAtBeforeSideOfBlock(false);
    2539 
    2540     // Now place the child in the correct left position
    2541     determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
    2542 
    2543     LayoutSize childOffset = child->location() - oldRect.location();
    2544 #if ENABLE(CSS_SHAPES)
    2545     relayoutShapeDescendantIfMoved(childRenderBlock, childOffset);
    2546 #endif
    2547 
    2548     // Update our height now that the child has been placed in the correct position.
    2549     setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
    2550     if (mustSeparateMarginAfterForChild(child)) {
    2551         setLogicalHeight(logicalHeight() + marginAfterForChild(child));
    2552         marginInfo.clearMargin();
    2553     }
    2554     // If the child has overhanging floats that intrude into following siblings (or possibly out
    2555     // of this block), then the parent gets notified of the floats now.
    2556     if (childRenderBlock && childRenderBlock->containsFloats())
    2557         maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), !childNeededLayout));
    2558 
    2559     if (childOffset.width() || childOffset.height()) {
    2560         view().addLayoutDelta(childOffset);
    2561 
    2562         // If the child moved, we have to repaint it as well as any floating/positioned
    2563         // descendants.  An exception is if we need a layout.  In this case, we know we're going to
    2564         // repaint ourselves (and the child) anyway.
    2565         if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
    2566             child->repaintDuringLayoutIfMoved(oldRect);
    2567     }
    2568 
    2569     if (!childHadLayout && child->checkForRepaintDuringLayout()) {
    2570         child->repaint();
    2571         child->repaintOverhangingFloats(true);
    2572     }
    2573 
    2574     if (paginated) {
    2575         // Check for an after page/column break.
    2576         LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
    2577         if (newHeight != height())
    2578             setLogicalHeight(newHeight);
    2579     }
    2580 
    2581     ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
    25821978}
    25831979
     
    67856181}
    67866182
    6787 void RenderBlock::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
    6788 {
    6789     if (!m_rareData) {
    6790         if (pos == RenderBlockRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockRareData::negativeMarginBeforeDefault(this))
    6791             return;
    6792         m_rareData = adoptPtr(new RenderBlockRareData(this));
    6793     }
    6794     m_rareData->m_margins.setPositiveMarginBefore(pos);
    6795     m_rareData->m_margins.setNegativeMarginBefore(neg);
    6796 }
    6797 
    6798 void RenderBlock::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
    6799 {
    6800     if (!m_rareData) {
    6801         if (pos == RenderBlockRareData::positiveMarginAfterDefault(this) && neg == RenderBlockRareData::negativeMarginAfterDefault(this))
    6802             return;
    6803         m_rareData = adoptPtr(new RenderBlockRareData(this));
    6804     }
    6805     m_rareData->m_margins.setPositiveMarginAfter(pos);
    6806     m_rareData->m_margins.setNegativeMarginAfter(neg);
    6807 }
    6808 
    6809 void RenderBlock::setMustDiscardMarginBefore(bool value)
    6810 {
    6811     if (style()->marginBeforeCollapse() == MDISCARD) {
    6812         ASSERT(value);
    6813         return;
    6814     }
    6815    
    6816     if (!m_rareData && !value)
    6817         return;
    6818 
    6819     if (!m_rareData)
    6820         m_rareData = adoptPtr(new RenderBlockRareData(this));
    6821 
    6822     m_rareData->m_discardMarginBefore = value;
    6823 }
    6824 
    6825 void RenderBlock::setMustDiscardMarginAfter(bool value)
    6826 {
    6827     if (style()->marginAfterCollapse() == MDISCARD) {
    6828         ASSERT(value);
    6829         return;
    6830     }
    6831 
    6832     if (!m_rareData && !value)
    6833         return;
    6834 
    6835     if (!m_rareData)
    6836         m_rareData = adoptPtr(new RenderBlockRareData(this));
    6837 
    6838     m_rareData->m_discardMarginAfter = value;
    6839 }
    6840 
    6841 bool RenderBlock::mustDiscardMarginBefore() const
    6842 {
    6843     return style()->marginBeforeCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginBefore);
    6844 }
    6845 
    6846 bool RenderBlock::mustDiscardMarginAfter() const
    6847 {
    6848     return style()->marginAfterCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginAfter);
    6849 }
    6850 
    6851 bool RenderBlock::mustDiscardMarginBeforeForChild(const RenderBox* child) const
    6852 {
    6853     ASSERT(!child->selfNeedsLayout());
    6854     if (!child->isWritingModeRoot())
    6855         return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
    6856     if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
    6857         return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
    6858 
    6859     // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
    6860     // In case the boxes are perpendicular we assume the property is not specified.
    6861     return false;
    6862 }
    6863 
    6864 bool RenderBlock::mustDiscardMarginAfterForChild(const RenderBox* child) const
    6865 {
    6866     ASSERT(!child->selfNeedsLayout());
    6867     if (!child->isWritingModeRoot())
    6868         return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
    6869     if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
    6870         return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
    6871 
    6872     // FIXME: See |mustDiscardMarginBeforeForChild| above.
    6873     return false;
    6874 }
    6875 
    6876 bool RenderBlock::mustSeparateMarginBeforeForChild(const RenderBox* child) const
    6877 {
    6878     ASSERT(!child->selfNeedsLayout());
    6879     const RenderStyle* childStyle = child->style();
    6880     if (!child->isWritingModeRoot())
    6881         return childStyle->marginBeforeCollapse() == MSEPARATE;
    6882     if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
    6883         return childStyle->marginAfterCollapse() == MSEPARATE;
    6884 
    6885     // FIXME: See |mustDiscardMarginBeforeForChild| above.
    6886     return false;
    6887 }
    6888 
    6889 bool RenderBlock::mustSeparateMarginAfterForChild(const RenderBox* child) const
    6890 {
    6891     ASSERT(!child->selfNeedsLayout());
    6892     const RenderStyle* childStyle = child->style();
    6893     if (!child->isWritingModeRoot())
    6894         return childStyle->marginAfterCollapse() == MSEPARATE;
    6895     if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
    6896         return childStyle->marginBeforeCollapse() == MSEPARATE;
    6897 
    6898     // FIXME: See |mustDiscardMarginBeforeForChild| above.
    6899     return false;
    6900 }
    6901 
    69026183void RenderBlock::setPaginationStrut(LayoutUnit strut)
    69036184{
     
    69056186        if (!strut)
    69066187            return;
    6907         m_rareData = adoptPtr(new RenderBlockRareData(this));
     6188        m_rareData = adoptPtr(new RenderBlockRareData());
    69086189    }
    69096190    m_rareData->m_paginationStrut = strut;
     
    69156196        if (!logicalOffset)
    69166197            return;
    6917         m_rareData = adoptPtr(new RenderBlockRareData(this));
     6198        m_rareData = adoptPtr(new RenderBlockRareData());
    69186199    }
    69196200    m_rareData->m_pageLogicalOffset = logicalOffset;
     
    69246205    ASSERT(lineToBreak);
    69256206    if (!m_rareData)
    6926         m_rareData = adoptPtr(new RenderBlockRareData(this));
     6207        m_rareData = adoptPtr(new RenderBlockRareData());
    69276208    m_rareData->m_shouldBreakAtLineToAvoidWidow = true;
    69286209    m_rareData->m_lineBreakToAvoidWidow = lineToBreak;
     
    71186399}
    71196400
    7120 static bool inNormalFlow(RenderBox* child)
    7121 {
    7122     RenderBlock* curr = child->containingBlock();
    7123     while (curr && curr != &child->view()) {
    7124         if (curr->hasColumns() || curr->isRenderFlowThread())
    7125             return true;
    7126         if (curr->isFloatingOrOutOfFlowPositioned())
    7127             return false;
    7128         curr = curr->containingBlock();
    7129     }
    7130     return true;
    7131 }
    7132 
    71336401ColumnInfo::PaginationUnit RenderBlock::paginationUnit() const
    71346402{
    71356403    return ColumnInfo::Column;
    7136 }
    7137 
    7138 LayoutUnit RenderBlock::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset)
    7139 {
    7140     // FIXME: Add page break checking here when we support printing.
    7141     bool checkColumnBreaks = view().layoutState()->isPaginatingColumns();
    7142     bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
    7143     RenderFlowThread* flowThread = flowThreadContainingBlock();
    7144     bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
    7145     bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS)
    7146                              || (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS);
    7147     if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
    7148         if (checkColumnBreaks)
    7149             view().layoutState()->addForcedColumnBreak(child, logicalOffset);
    7150         if (checkRegionBreaks) {
    7151             LayoutUnit offsetBreakAdjustment = 0;
    7152             if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment))
    7153                 return logicalOffset + offsetBreakAdjustment;
    7154         }
    7155         return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
    7156     }
    7157     return logicalOffset;
    7158 }
    7159 
    7160 LayoutUnit RenderBlock::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
    7161 {
    7162     // FIXME: Add page break checking here when we support printing.
    7163     bool checkColumnBreaks = view().layoutState()->isPaginatingColumns();
    7164     bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
    7165     RenderFlowThread* flowThread = flowThreadContainingBlock();
    7166     bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
    7167     bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS)
    7168                             || (checkRegionBreaks && child->style()->regionBreakAfter() == PBALWAYS);
    7169     if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
    7170         LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
    7171 
    7172         // So our margin doesn't participate in the next collapsing steps.
    7173         marginInfo.clearMargin();
    7174 
    7175         if (checkColumnBreaks)
    7176             view().layoutState()->addForcedColumnBreak(child, logicalOffset);
    7177         if (checkRegionBreaks) {
    7178             LayoutUnit offsetBreakAdjustment = 0;
    7179             if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment))
    7180                 return logicalOffset + marginOffset + offsetBreakAdjustment;
    7181         }
    7182         return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
    7183     }
    7184     return logicalOffset;
    71856404}
    71866405
     
    73666585}
    73676586
    7368 LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock)
    7369 {
    7370     RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
    7371 
    7372     if (estimateWithoutPagination != logicalTopAfterClear) {
    7373         // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
    7374         // position.
    7375         setLogicalHeight(logicalTopAfterClear);
    7376         setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
    7377 
    7378         if (child->shrinkToAvoidFloats()) {
    7379             // The child's width depends on the line width.
    7380             // When the child shifts to clear an item, its width can
    7381             // change (because it has more available line width).
    7382             // So go ahead and mark the item as dirty.
    7383             child->setChildNeedsLayout(true, MarkOnlyThis);
    7384         }
    7385        
    7386         if (childRenderBlock) {
    7387             if (!child->avoidsFloats() && childRenderBlock->containsFloats())
    7388                 childRenderBlock->markAllDescendantsWithFloatsForLayout();
    7389             if (!child->needsLayout())
    7390                 child->markForPaginationRelayoutIfNeeded();
    7391         }
    7392 
    7393         // Our guess was wrong. Make the child lay itself out again.
    7394         child->layoutIfNeeded();
    7395     }
    7396 
    7397     LayoutUnit oldTop = logicalTopAfterClear;
    7398 
    7399     // If the object has a page or column break value of "before", then we should shift to the top of the next page.
    7400     LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
    7401 
    7402     if (pageLogicalHeightForOffset(result)) {
    7403         LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
    7404         LayoutUnit spaceShortage = child->logicalHeight() - remainingLogicalHeight;
    7405         if (spaceShortage > 0) {
    7406             // If the child crosses a column boundary, report a break, in case nothing inside it has already
    7407             // done so. The column balancer needs to know how much it has to stretch the columns to make more
    7408             // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
    7409             // This should be improved, though, because here we just pretend that the child is
    7410             // unsplittable. A splittable child, on the other hand, has break opportunities at every position
    7411             // where there's no child content, border or padding. In other words, we risk stretching more
    7412             // than necessary.
    7413             setPageBreak(result, spaceShortage);
    7414         }
    7415     }
    7416 
    7417     // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
    7418     LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
    7419     LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
    7420    
    7421     LayoutUnit paginationStrut = 0;
    7422     LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
    7423     if (unsplittableAdjustmentDelta)
    7424         paginationStrut = unsplittableAdjustmentDelta;
    7425     else if (childRenderBlock && childRenderBlock->paginationStrut())
    7426         paginationStrut = childRenderBlock->paginationStrut();
    7427 
    7428     if (paginationStrut) {
    7429         // We are willing to propagate out to our parent block as long as we were at the top of the block prior
    7430         // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
    7431         if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
    7432             // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
    7433             // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
    7434             // and pushes to the next page anyway, so not too concerned about it.
    7435             setPaginationStrut(result + paginationStrut);
    7436             if (childRenderBlock)
    7437                 childRenderBlock->setPaginationStrut(0);
    7438         } else
    7439             result += paginationStrut;
    7440     }
    7441 
    7442     // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
    7443     setLogicalHeight(logicalHeight() + (result - oldTop));
    7444    
    7445     // Return the final adjusted logical top.
    7446     return result;
    7447 }
    7448 
    74496587bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta, RenderFlowThread* flowThread) const
    74506588{
     
    76456783    // whether or not authors specified quirky ems, since they're an implementation detail.
    76466784    return false;
    7647 }
    7648 
    7649 RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child) const
    7650 {
    7651     LayoutUnit childBeforePositive = 0;
    7652     LayoutUnit childBeforeNegative = 0;
    7653     LayoutUnit childAfterPositive = 0;
    7654     LayoutUnit childAfterNegative = 0;
    7655 
    7656     LayoutUnit beforeMargin = 0;
    7657     LayoutUnit afterMargin = 0;
    7658 
    7659     RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
    7660    
    7661     // If the child has the same directionality as we do, then we can just return its
    7662     // margins in the same direction.
    7663     if (!child->isWritingModeRoot()) {
    7664         if (childRenderBlock) {
    7665             childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
    7666             childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
    7667             childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
    7668             childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
    7669         } else {
    7670             beforeMargin = child->marginBefore();
    7671             afterMargin = child->marginAfter();
    7672         }
    7673     } else if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) {
    7674         // The child has a different directionality.  If the child is parallel, then it's just
    7675         // flipped relative to us.  We can use the margins for the opposite edges.
    7676         if (childRenderBlock) {
    7677             childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
    7678             childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
    7679             childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
    7680             childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
    7681         } else {
    7682             beforeMargin = child->marginAfter();
    7683             afterMargin = child->marginBefore();
    7684         }
    7685     } else {
    7686         // The child is perpendicular to us, which means its margins don't collapse but are on the
    7687         // "logical left/right" sides of the child box.  We can just return the raw margin in this case.
    7688         beforeMargin = marginBeforeForChild(child);
    7689         afterMargin = marginAfterForChild(child);
    7690     }
    7691 
    7692     // Resolve uncollapsing margins into their positive/negative buckets.
    7693     if (beforeMargin) {
    7694         if (beforeMargin > 0)
    7695             childBeforePositive = beforeMargin;
    7696         else
    7697             childBeforeNegative = -beforeMargin;
    7698     }
    7699     if (afterMargin) {
    7700         if (afterMargin > 0)
    7701             childAfterPositive = afterMargin;
    7702         else
    7703             childAfterNegative = -afterMargin;
    7704     }
    7705 
    7706     return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
    77076785}
    77086786
  • trunk/Source/WebCore/rendering/RenderBlock.h

    r155496 r155555  
    350350    {
    351351        if (!m_rareData)
    352             m_rareData = adoptPtr(new RenderBlockRareData(this));
     352            m_rareData = adoptPtr(new RenderBlockRareData());
    353353        if (m_rareData->m_lineGridBox)
    354354            m_rareData->m_lineGridBox->destroy(renderArena());
     
    379379    virtual void updateFirstLetter();
    380380
    381     class MarginValues {
    382     public:
    383         MarginValues(LayoutUnit beforePos, LayoutUnit beforeNeg, LayoutUnit afterPos, LayoutUnit afterNeg)
    384             : m_positiveMarginBefore(beforePos)
    385             , m_negativeMarginBefore(beforeNeg)
    386             , m_positiveMarginAfter(afterPos)
    387             , m_negativeMarginAfter(afterNeg)
    388         { }
    389        
    390         LayoutUnit positiveMarginBefore() const { return m_positiveMarginBefore; }
    391         LayoutUnit negativeMarginBefore() const { return m_negativeMarginBefore; }
    392         LayoutUnit positiveMarginAfter() const { return m_positiveMarginAfter; }
    393         LayoutUnit negativeMarginAfter() const { return m_negativeMarginAfter; }
    394        
    395         void setPositiveMarginBefore(LayoutUnit pos) { m_positiveMarginBefore = pos; }
    396         void setNegativeMarginBefore(LayoutUnit neg) { m_negativeMarginBefore = neg; }
    397         void setPositiveMarginAfter(LayoutUnit pos) { m_positiveMarginAfter = pos; }
    398         void setNegativeMarginAfter(LayoutUnit neg) { m_negativeMarginAfter = neg; }
    399    
    400     private:
    401         LayoutUnit m_positiveMarginBefore;
    402         LayoutUnit m_negativeMarginBefore;
    403         LayoutUnit m_positiveMarginAfter;
    404         LayoutUnit m_negativeMarginAfter;
    405     };
    406     MarginValues marginValuesForChild(RenderBox* child) const;
    407 
    408381    virtual void scrollbarsChanged(bool /*horizontalScrollbarChanged*/, bool /*verticalScrollbarChanged*/) { };
    409382
     
    486459    {
    487460        if (!m_rareData)
    488             m_rareData = adoptPtr(new RenderBlockRareData(this));
     461            m_rareData = adoptPtr(new RenderBlockRareData());
    489462        m_rareData->m_shapeInsideInfo = value;
    490463    }
     
    497470protected:
    498471    virtual void willBeDestroyed();
    499 
    500     LayoutUnit maxPositiveMarginBefore() const { return m_rareData ? m_rareData->m_margins.positiveMarginBefore() : RenderBlockRareData::positiveMarginBeforeDefault(this); }
    501     LayoutUnit maxNegativeMarginBefore() const { return m_rareData ? m_rareData->m_margins.negativeMarginBefore() : RenderBlockRareData::negativeMarginBeforeDefault(this); }
    502     LayoutUnit maxPositiveMarginAfter() const { return m_rareData ? m_rareData->m_margins.positiveMarginAfter() : RenderBlockRareData::positiveMarginAfterDefault(this); }
    503     LayoutUnit maxNegativeMarginAfter() const { return m_rareData ? m_rareData->m_margins.negativeMarginAfter() : RenderBlockRareData::negativeMarginAfterDefault(this); }
    504    
    505     void setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg);
    506     void setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg);
    507 
    508     void setMustDiscardMarginBefore(bool = true);
    509     void setMustDiscardMarginAfter(bool = true);
    510 
    511     bool mustDiscardMarginBefore() const;
    512     bool mustDiscardMarginAfter() const;
    513 
    514     bool mustDiscardMarginBeforeForChild(const RenderBox*) const;
    515     bool mustDiscardMarginAfterForChild(const RenderBox*) const;
    516 
    517     bool mustSeparateMarginBeforeForChild(const RenderBox*) const;
    518     bool mustSeparateMarginAfterForChild(const RenderBox*) const;
    519 
    520     void initMaxMarginValues()
    521     {
    522         if (m_rareData) {
    523             m_rareData->m_margins = MarginValues(RenderBlockRareData::positiveMarginBeforeDefault(this) , RenderBlockRareData::negativeMarginBeforeDefault(this),
    524                                                  RenderBlockRareData::positiveMarginAfterDefault(this), RenderBlockRareData::negativeMarginAfterDefault(this));
    525             m_rareData->m_paginationStrut = 0;
    526 
    527             m_rareData->m_discardMarginBefore = false;
    528             m_rareData->m_discardMarginAfter = false;
    529         }
    530     }
    531472
    532473    virtual void layout();
     
    650591   
    651592    virtual bool isSelfCollapsingBlock() const OVERRIDE FINAL;
    652 
    653     virtual LayoutUnit collapsedMarginBefore() const OVERRIDE FINAL { return maxPositiveMarginBefore() - maxNegativeMarginBefore(); }
    654     virtual LayoutUnit collapsedMarginAfter() const OVERRIDE FINAL { return maxPositiveMarginAfter() - maxNegativeMarginAfter(); }
    655593
    656594    virtual void repaintOverhangingFloats(bool paintAllDescendants) OVERRIDE FINAL;
     
    877815    RenderBlock* columnsBlockForSpanningElement(RenderObject* newChild);
    878816
    879     class MarginInfo {
    880         // Collapsing flags for whether we can collapse our margins with our children's margins.
    881         bool m_canCollapseWithChildren : 1;
    882         bool m_canCollapseMarginBeforeWithChildren : 1;
    883         bool m_canCollapseMarginAfterWithChildren : 1;
    884 
    885         // Whether or not we are a quirky container, i.e., do we collapse away top and bottom
    886         // margins in our container.  Table cells and the body are the common examples. We
    887         // also have a custom style property for Safari RSS to deal with TypePad blog articles.
    888         bool m_quirkContainer : 1;
    889 
    890         // This flag tracks whether we are still looking at child margins that can all collapse together at the beginning of a block. 
    891         // They may or may not collapse with the top margin of the block (|m_canCollapseTopWithChildren| tells us that), but they will
    892         // always be collapsing with one another.  This variable can remain set to true through multiple iterations
    893         // as long as we keep encountering self-collapsing blocks.
    894         bool m_atBeforeSideOfBlock : 1;
    895 
    896         // This flag is set when we know we're examining bottom margins and we know we're at the bottom of the block.
    897         bool m_atAfterSideOfBlock : 1;
    898 
    899         // These variables are used to detect quirky margins that we need to collapse away (in table cells
    900         // and in the body element).
    901         bool m_hasMarginBeforeQuirk : 1;
    902         bool m_hasMarginAfterQuirk : 1;
    903         bool m_determinedMarginBeforeQuirk : 1;
    904 
    905         bool m_discardMargin : 1;
    906 
    907         // These flags track the previous maximal positive and negative margins.
    908         LayoutUnit m_positiveMargin;
    909         LayoutUnit m_negativeMargin;
    910 
    911     public:
    912         MarginInfo(RenderBlock*, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding);
    913 
    914         void setAtBeforeSideOfBlock(bool b) { m_atBeforeSideOfBlock = b; }
    915         void setAtAfterSideOfBlock(bool b) { m_atAfterSideOfBlock = b; }
    916         void clearMargin()
    917         {
    918             m_positiveMargin = 0;
    919             m_negativeMargin = 0;
    920         }
    921         void setHasMarginBeforeQuirk(bool b) { m_hasMarginBeforeQuirk = b; }
    922         void setHasMarginAfterQuirk(bool b) { m_hasMarginAfterQuirk = b; }
    923         void setDeterminedMarginBeforeQuirk(bool b) { m_determinedMarginBeforeQuirk = b; }
    924         void setPositiveMargin(LayoutUnit p) { ASSERT(!m_discardMargin); m_positiveMargin = p; }
    925         void setNegativeMargin(LayoutUnit n) { ASSERT(!m_discardMargin); m_negativeMargin = n; }
    926         void setPositiveMarginIfLarger(LayoutUnit p)
    927         {
    928             ASSERT(!m_discardMargin);
    929             if (p > m_positiveMargin)
    930                 m_positiveMargin = p;
    931         }
    932         void setNegativeMarginIfLarger(LayoutUnit n)
    933         {
    934             ASSERT(!m_discardMargin);
    935             if (n > m_negativeMargin)
    936                 m_negativeMargin = n;
    937         }
    938 
    939         void setMargin(LayoutUnit p, LayoutUnit n) { ASSERT(!m_discardMargin); m_positiveMargin = p; m_negativeMargin = n; }
    940         void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMarginAfterWithChildren = collapse; }
    941         void setDiscardMargin(bool value) { m_discardMargin = value; }
    942 
    943         bool atBeforeSideOfBlock() const { return m_atBeforeSideOfBlock; }
    944         bool canCollapseWithMarginBefore() const { return m_atBeforeSideOfBlock && m_canCollapseMarginBeforeWithChildren; }
    945         bool canCollapseWithMarginAfter() const { return m_atAfterSideOfBlock && m_canCollapseMarginAfterWithChildren; }
    946         bool canCollapseMarginBeforeWithChildren() const { return m_canCollapseMarginBeforeWithChildren; }
    947         bool canCollapseMarginAfterWithChildren() const { return m_canCollapseMarginAfterWithChildren; }
    948         bool quirkContainer() const { return m_quirkContainer; }
    949         bool determinedMarginBeforeQuirk() const { return m_determinedMarginBeforeQuirk; }
    950         bool hasMarginBeforeQuirk() const { return m_hasMarginBeforeQuirk; }
    951         bool hasMarginAfterQuirk() const { return m_hasMarginAfterQuirk; }
    952         LayoutUnit positiveMargin() const { return m_positiveMargin; }
    953         LayoutUnit negativeMargin() const { return m_negativeMargin; }
    954         bool discardMargin() const { return m_discardMargin; }
    955         LayoutUnit margin() const { return m_positiveMargin - m_negativeMargin; }
    956     };
    957 
    958     void layoutBlockChild(RenderBox* child, MarginInfo&, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom);
    959     void adjustPositionedBlock(RenderBox* child, const MarginInfo&);
    960     void adjustFloatingBlock(const MarginInfo&);
    961 
    962817    RenderBoxModelObject* createReplacementRunIn(RenderBoxModelObject* runIn);
    963818    void moveRunInUnderSiblingBlockIfNeeded(RenderObject* runIn);
    964819    void moveRunInToOriginalPosition(RenderObject* runIn);
    965 
    966     LayoutUnit collapseMargins(RenderBox* child, MarginInfo&);
    967     LayoutUnit clearFloatsIfNeeded(RenderBox* child, MarginInfo&, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos);
    968     LayoutUnit estimateLogicalTopPosition(RenderBox* child, const MarginInfo&, LayoutUnit& estimateWithoutPagination);
    969     void marginBeforeEstimateForChild(RenderBox*, LayoutUnit&, LayoutUnit&, bool&) const;
    970     void handleAfterSideOfBlock(LayoutUnit top, LayoutUnit bottom, MarginInfo&);
    971     void setCollapsedBottomMargin(const MarginInfo&);
    972     // End helper functions and structs used by layoutBlockChildren.
    973820
    974821    // Helper function for layoutInlineChildren()
     
    1004851    virtual ColumnInfo::PaginationUnit paginationUnit() const;
    1005852
    1006     LayoutUnit applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset); // If the child has a before break, then return a new yPos that shifts to the top of the next page/column.
    1007     LayoutUnit applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo&); // If the child has an after break, then return a new offset that shifts to the top of the next page/column.
    1008 
    1009853public:
    1010854    LayoutUnit pageLogicalTopForOffset(LayoutUnit offset) const;
     
    1025869    LayoutUnit adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins = false); // If the child is unsplittable and can't fit on the current page, return the top of the next page/column.
    1026870    void adjustLinePositionForPagination(RootInlineBox*, LayoutUnit& deltaOffset, RenderFlowThread*); // Computes a deltaOffset value that put a line at the top of the next page if it doesn't fit on the current page.
    1027     LayoutUnit adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock);
    1028871
    1029872    // Adjust from painting offsets to the local coords of this renderer
     
    1059902        WTF_MAKE_NONCOPYABLE(RenderBlockRareData); WTF_MAKE_FAST_ALLOCATED;
    1060903    public:
    1061         RenderBlockRareData(const RenderBlock* block)
    1062             : m_margins(positiveMarginBeforeDefault(block), negativeMarginBeforeDefault(block), positiveMarginAfterDefault(block), negativeMarginAfterDefault(block))
    1063             , m_paginationStrut(0)
     904        RenderBlockRareData()
     905            : m_paginationStrut(0)
    1064906            , m_pageLogicalOffset(0)
    1065907            , m_lineGridBox(0)
    1066908            , m_lineBreakToAvoidWidow(-1)
    1067909            , m_shouldBreakAtLineToAvoidWidow(false)
    1068             , m_discardMarginBefore(false)
    1069             , m_discardMarginAfter(false)
    1070910        {
    1071911        }
    1072912
    1073         static LayoutUnit positiveMarginBeforeDefault(const RenderBlock* block)
    1074         {
    1075             return std::max<LayoutUnit>(block->marginBefore(), 0);
    1076         }
    1077         static LayoutUnit negativeMarginBeforeDefault(const RenderBlock* block)
    1078         {
    1079             return std::max<LayoutUnit>(-block->marginBefore(), 0);
    1080         }
    1081         static LayoutUnit positiveMarginAfterDefault(const RenderBlock* block)
    1082         {
    1083             return std::max<LayoutUnit>(block->marginAfter(), 0);
    1084         }
    1085         static LayoutUnit negativeMarginAfterDefault(const RenderBlock* block)
    1086         {
    1087             return std::max<LayoutUnit>(-block->marginAfter(), 0);
    1088         }
    1089        
    1090         MarginValues m_margins;
    1091913        LayoutUnit m_paginationStrut;
    1092914        LayoutUnit m_pageLogicalOffset;
     
    1099921#endif
    1100922        bool m_shouldBreakAtLineToAvoidWidow : 1;
    1101         bool m_discardMarginBefore : 1;
    1102         bool m_discardMarginAfter : 1;
    1103923     };
    1104924
  • trunk/Source/WebCore/rendering/RenderBlockFlow.cpp

    r155391 r155555  
    3535namespace WebCore {
    3636
     37struct SameSizeAsMarginInfo {
     38    uint32_t bitfields : 16;
     39    LayoutUnit margins[2];
     40};
     41
     42COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
     43
     44// Our MarginInfo state used when laying out block children.
     45RenderBlockFlow::MarginInfo::MarginInfo(RenderBlockFlow* block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
     46    : m_atBeforeSideOfBlock(true)
     47    , m_atAfterSideOfBlock(false)
     48    , m_hasMarginBeforeQuirk(false)
     49    , m_hasMarginAfterQuirk(false)
     50    , m_determinedMarginBeforeQuirk(false)
     51    , m_discardMargin(false)
     52{
     53    RenderStyle* blockStyle = block->style();
     54    ASSERT(block->isRenderView() || block->parent());
     55    m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isOutOfFlowPositioned()
     56        && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
     57        && !block->isRenderFlowThread() && !block->isWritingModeRoot() && !block->parent()->isFlexibleBox()
     58        && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth() && !blockStyle->columnSpan();
     59
     60    m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE;
     61
     62    // If any height other than auto is specified in CSS, then we don't collapse our bottom
     63    // margins with our children's margins. To do otherwise would be to risk odd visual
     64    // effects when the children overflow out of the parent block and yet still collapse
     65    // with it. We also don't collapse if we have any bottom border/padding.
     66    m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
     67        && (blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE;
     68   
     69    m_quirkContainer = block->isTableCell() || block->isBody();
     70
     71    m_discardMargin = m_canCollapseMarginBeforeWithChildren && block->mustDiscardMarginBefore();
     72
     73    m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxPositiveMarginBefore() : LayoutUnit();
     74    m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxNegativeMarginBefore() : LayoutUnit();
     75}
     76
    3777RenderBlockFlow::RenderBlockFlow(Element* element)
    3878    : RenderBlock(element)
    3979{
     80    COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
    4081}
    4182
     
    412453}
    413454
     455void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
     456{
     457    LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
     458    LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
     459
     460    // The child is a normal flow object. Compute the margins we will use for collapsing now.
     461    child->computeAndSetBlockDirectionMargins(this);
     462
     463    // Try to guess our correct logical top position. In most cases this guess will
     464    // be correct. Only if we're wrong (when we compute the real logical top position)
     465    // will we have to potentially relayout.
     466    LayoutUnit estimateWithoutPagination;
     467    LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
     468
     469    // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
     470    LayoutRect oldRect = child->frameRect();
     471    LayoutUnit oldLogicalTop = logicalTopForChild(child);
     472
     473#if !ASSERT_DISABLED
     474    LayoutSize oldLayoutDelta = view().layoutDelta();
     475#endif
     476    // Go ahead and position the child as though it didn't collapse with the top.
     477    setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
     478    estimateRegionRangeForBoxChild(child);
     479
     480    RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
     481    bool markDescendantsWithFloats = false;
     482    if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
     483        markDescendantsWithFloats = true;
     484#if ENABLE(SUBPIXEL_LAYOUT)
     485    else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
     486        // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
     487        // very large elements. If it does the comparison with oldLogicalTop might yield a
     488        // false negative as adding and removing margins, borders etc from a saturated number
     489        // might yield incorrect results. If this is the case always mark for layout.
     490        markDescendantsWithFloats = true;
     491#endif
     492    else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
     493        // If an element might be affected by the presence of floats, then always mark it for
     494        // layout.
     495        LayoutUnit fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
     496        if (fb > logicalTopEstimate)
     497            markDescendantsWithFloats = true;
     498    }
     499
     500    if (childRenderBlock) {
     501        if (markDescendantsWithFloats)
     502            childRenderBlock->markAllDescendantsWithFloatsForLayout();
     503        if (!child->isWritingModeRoot())
     504            previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom());
     505    }
     506
     507    if (!child->needsLayout())
     508        child->markForPaginationRelayoutIfNeeded();
     509
     510    bool childHadLayout = child->everHadLayout();
     511    bool childNeededLayout = child->needsLayout();
     512    if (childNeededLayout)
     513        child->layout();
     514
     515    // Cache if we are at the top of the block right now.
     516    bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
     517
     518    // Now determine the correct ypos based off examination of collapsing margin
     519    // values.
     520    LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
     521
     522    // Now check for clear.
     523    LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
     524   
     525    bool paginated = view().layoutState()->isPaginated();
     526    if (paginated)
     527        logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child,
     528            atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
     529
     530    setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
     531
     532    // Now we have a final top position. See if it really does end up being different from our estimate.
     533    // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
     534    // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
     535    if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout() || (paginated && childRenderBlock && childRenderBlock->shouldBreakAtLineToAvoidWidow())) {
     536        if (child->shrinkToAvoidFloats()) {
     537            // The child's width depends on the line width.
     538            // When the child shifts to clear an item, its width can
     539            // change (because it has more available line width).
     540            // So go ahead and mark the item as dirty.
     541            child->setChildNeedsLayout(true, MarkOnlyThis);
     542        }
     543       
     544        if (childRenderBlock) {
     545            if (!child->avoidsFloats() && childRenderBlock->containsFloats())
     546                childRenderBlock->markAllDescendantsWithFloatsForLayout();
     547            if (!child->needsLayout())
     548                child->markForPaginationRelayoutIfNeeded();
     549        }
     550
     551        // Our guess was wrong. Make the child lay itself out again.
     552        child->layoutIfNeeded();
     553    }
     554
     555    if (updateRegionRangeForBoxChild(child)) {
     556        child->setNeedsLayout(true, MarkOnlyThis);
     557        child->layoutIfNeeded();
     558    }
     559
     560    // We are no longer at the top of the block if we encounter a non-empty child. 
     561    // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
     562    if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
     563        marginInfo.setAtBeforeSideOfBlock(false);
     564
     565    // Now place the child in the correct left position
     566    determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
     567
     568    LayoutSize childOffset = child->location() - oldRect.location();
     569#if ENABLE(CSS_SHAPES)
     570    relayoutShapeDescendantIfMoved(childRenderBlock, childOffset);
     571#endif
     572
     573    // Update our height now that the child has been placed in the correct position.
     574    setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
     575    if (mustSeparateMarginAfterForChild(child)) {
     576        setLogicalHeight(logicalHeight() + marginAfterForChild(child));
     577        marginInfo.clearMargin();
     578    }
     579    // If the child has overhanging floats that intrude into following siblings (or possibly out
     580    // of this block), then the parent gets notified of the floats now.
     581    if (childRenderBlock && childRenderBlock->containsFloats())
     582        maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), !childNeededLayout));
     583
     584    if (childOffset.width() || childOffset.height()) {
     585        view().addLayoutDelta(childOffset);
     586
     587        // If the child moved, we have to repaint it as well as any floating/positioned
     588        // descendants. An exception is if we need a layout. In this case, we know we're going to
     589        // repaint ourselves (and the child) anyway.
     590        if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
     591            child->repaintDuringLayoutIfMoved(oldRect);
     592    }
     593
     594    if (!childHadLayout && child->checkForRepaintDuringLayout()) {
     595        child->repaint();
     596        child->repaintOverhangingFloats(true);
     597    }
     598
     599    if (paginated) {
     600        // Check for an after page/column break.
     601        LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
     602        if (newHeight != height())
     603            setLogicalHeight(newHeight);
     604    }
     605
     606    ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
     607}
     608
     609void RenderBlockFlow::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
     610{
     611    bool isHorizontal = isHorizontalWritingMode();
     612    bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
     613   
     614    LayoutUnit logicalTop = logicalHeight();
     615    updateStaticInlinePositionForChild(child, logicalTop);
     616
     617    if (!marginInfo.canCollapseWithMarginBefore()) {
     618        // Positioned blocks don't collapse margins, so add the margin provided by
     619        // the container now. The child's own margin is added later when calculating its logical top.
     620        LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
     621        LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
     622        logicalTop += collapsedBeforePos - collapsedBeforeNeg;
     623    }
     624   
     625    RenderLayer* childLayer = child->layer();
     626    if (childLayer->staticBlockPosition() != logicalTop) {
     627        childLayer->setStaticBlockPosition(logicalTop);
     628        if (hasStaticBlockPosition)
     629            child->setChildNeedsLayout(true, MarkOnlyThis);
     630    }
     631}
     632
     633void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
     634{
     635    // The float should be positioned taking into account the bottom margin
     636    // of the previous flow. We add that margin into the height, get the
     637    // float positioned properly, and then subtract the margin out of the
     638    // height again. In the case of self-collapsing blocks, we always just
     639    // use the top margins, since the self-collapsing block collapsed its
     640    // own bottom margin into its top margin.
     641    //
     642    // Note also that the previous flow may collapse its margin into the top of
     643    // our block. If this is the case, then we do not add the margin in to our
     644    // height when computing the position of the float. This condition can be tested
     645    // for by simply calling canCollapseWithMarginBefore. See
     646    // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
     647    // an example of this scenario.
     648    LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
     649    setLogicalHeight(logicalHeight() + marginOffset);
     650    positionNewFloats();
     651    setLogicalHeight(logicalHeight() - marginOffset);
     652}
     653
     654RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox* child) const
     655{
     656    LayoutUnit childBeforePositive = 0;
     657    LayoutUnit childBeforeNegative = 0;
     658    LayoutUnit childAfterPositive = 0;
     659    LayoutUnit childAfterNegative = 0;
     660
     661    LayoutUnit beforeMargin = 0;
     662    LayoutUnit afterMargin = 0;
     663
     664    RenderBlockFlow* childRenderBlock = child->isRenderBlockFlow() ? toRenderBlockFlow(child) : 0;
     665   
     666    // If the child has the same directionality as we do, then we can just return its
     667    // margins in the same direction.
     668    if (!child->isWritingModeRoot()) {
     669        if (childRenderBlock) {
     670            childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
     671            childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
     672            childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
     673            childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
     674        } else {
     675            beforeMargin = child->marginBefore();
     676            afterMargin = child->marginAfter();
     677        }
     678    } else if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) {
     679        // The child has a different directionality. If the child is parallel, then it's just
     680        // flipped relative to us. We can use the margins for the opposite edges.
     681        if (childRenderBlock) {
     682            childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
     683            childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
     684            childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
     685            childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
     686        } else {
     687            beforeMargin = child->marginAfter();
     688            afterMargin = child->marginBefore();
     689        }
     690    } else {
     691        // The child is perpendicular to us, which means its margins don't collapse but are on the
     692        // "logical left/right" sides of the child box. We can just return the raw margin in this case.
     693        beforeMargin = marginBeforeForChild(child);
     694        afterMargin = marginAfterForChild(child);
     695    }
     696
     697    // Resolve uncollapsing margins into their positive/negative buckets.
     698    if (beforeMargin) {
     699        if (beforeMargin > 0)
     700            childBeforePositive = beforeMargin;
     701        else
     702            childBeforeNegative = -beforeMargin;
     703    }
     704    if (afterMargin) {
     705        if (afterMargin > 0)
     706            childAfterPositive = afterMargin;
     707        else
     708            childAfterNegative = -afterMargin;
     709    }
     710
     711    return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
     712}
     713
     714LayoutUnit RenderBlockFlow::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
     715{
     716    bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
     717    bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
     718    bool childIsSelfCollapsing = child->isSelfCollapsingBlock();
     719
     720    // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
     721    childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
     722
     723    // Get the four margin values for the child and cache them.
     724    const MarginValues childMargins = marginValuesForChild(child);
     725
     726    // Get our max pos and neg top margins.
     727    LayoutUnit posTop = childMargins.positiveMarginBefore();
     728    LayoutUnit negTop = childMargins.negativeMarginBefore();
     729
     730    // For self-collapsing blocks, collapse our bottom margins into our
     731    // top to get new posTop and negTop values.
     732    if (childIsSelfCollapsing) {
     733        posTop = max(posTop, childMargins.positiveMarginAfter());
     734        negTop = max(negTop, childMargins.negativeMarginAfter());
     735    }
     736   
     737    // See if the top margin is quirky. We only care if this child has
     738    // margins that will collapse with us.
     739    bool topQuirk = hasMarginBeforeQuirk(child);
     740
     741    if (marginInfo.canCollapseWithMarginBefore()) {
     742        if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
     743            // This child is collapsing with the top of the
     744            // block. If it has larger margin values, then we need to update
     745            // our own maximal values.
     746            if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
     747                setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
     748
     749            // The minute any of the margins involved isn't a quirk, don't
     750            // collapse it away, even if the margin is smaller (www.webreference.com
     751            // has an example of this, a <dt> with 0.8em author-specified inside
     752            // a <dl> inside a <td>.
     753            if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
     754                setHasMarginBeforeQuirk(false);
     755                marginInfo.setDeterminedMarginBeforeQuirk(true);
     756            }
     757
     758            if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
     759                // We have no top margin and our top child has a quirky margin.
     760                // We will pick up this quirky margin and pass it through.
     761                // This deals with the <td><div><p> case.
     762                // Don't do this for a block that split two inlines though. You do
     763                // still apply margins in this case.
     764                setHasMarginBeforeQuirk(true);
     765        } else
     766            // The before margin of the container will also discard all the margins it is collapsing with.
     767            setMustDiscardMarginBefore();
     768    }
     769
     770    // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
     771    if (childDiscardMarginBefore) {
     772        marginInfo.setDiscardMargin(true);
     773        marginInfo.clearMargin();
     774    }
     775
     776    if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
     777        marginInfo.setHasMarginBeforeQuirk(topQuirk);
     778
     779    LayoutUnit beforeCollapseLogicalTop = logicalHeight();
     780    LayoutUnit logicalTop = beforeCollapseLogicalTop;
     781    if (childIsSelfCollapsing) {
     782        // For a self collapsing block both the before and after margins get discarded. The block doesn't contribute anything to the height of the block.
     783        // Also, the child's top position equals the logical height of the container.
     784        if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
     785            // This child has no height. We need to compute our
     786            // position before we collapse the child's margins together,
     787            // so that we can get an accurate position for the zero-height block.
     788            LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
     789            LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
     790            marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
     791           
     792            // Now collapse the child's margins together, which means examining our
     793            // bottom margin values as well.
     794            marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
     795            marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
     796
     797            if (!marginInfo.canCollapseWithMarginBefore())
     798                // We need to make sure that the position of the self-collapsing block
     799                // is correct, since it could have overflowing content
     800                // that needs to be positioned correctly (e.g., a block that
     801                // had a specified height of 0 but that actually had subcontent).
     802                logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
     803        }
     804    } else {
     805        if (mustSeparateMarginBeforeForChild(child)) {
     806            ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
     807            // If we are at the before side of the block and we collapse, ignore the computed margin
     808            // and just add the child margin to the container height. This will correctly position
     809            // the child inside the container.
     810            LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit(0);
     811            setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child));
     812            logicalTop = logicalHeight();
     813        } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
     814            || (!marginInfo.canCollapseMarginBeforeWithChildren()
     815            && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
     816            // We're collapsing with a previous sibling's margins and not
     817            // with the top of the block.
     818            setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
     819            logicalTop = logicalHeight();
     820        }
     821
     822        marginInfo.setDiscardMargin(childDiscardMarginAfter);
     823       
     824        if (!marginInfo.discardMargin()) {
     825            marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
     826            marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
     827        } else
     828            marginInfo.clearMargin();
     829
     830        if (marginInfo.margin())
     831            marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
     832    }
     833   
     834    // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
     835    // collapsed into the page edge.
     836    LayoutState* layoutState = view().layoutState();
     837    if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
     838        && hasNextPage(beforeCollapseLogicalTop)) {
     839        LayoutUnit oldLogicalTop = logicalTop;
     840        logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
     841        setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
     842    }
     843
     844    // If we have collapsed into a previous sibling and so reduced the height of the parent, ensure any floats that now
     845    // overhang from the previous sibling are added to our parent. If the child's previous sibling itself is a float the child will avoid
     846    // or clear it anyway, so don't worry about any floating children it may contain.
     847    LayoutUnit oldLogicalHeight = logicalHeight();
     848    setLogicalHeight(logicalTop);
     849    RenderObject* prev = child->previousSibling();
     850    if (prev && prev->isRenderBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned()) {
     851        RenderBlock* block = toRenderBlock(prev);
     852        if (block->containsFloats() && !block->avoidsFloats() && (block->logicalTop() + block->lowestFloatLogicalBottom()) > logicalTop)
     853            addOverhangingFloats(block, false);
     854    }
     855    setLogicalHeight(oldLogicalHeight);
     856
     857    return logicalTop;
     858}
     859
     860LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
     861{
     862    LayoutUnit heightIncrease = getClearDelta(child, yPos);
     863    if (!heightIncrease)
     864        return yPos;
     865
     866    if (child->isSelfCollapsingBlock()) {
     867        bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
     868
     869        // For self-collapsing blocks that clear, they can still collapse their
     870        // margins with following siblings. Reset the current margins to represent
     871        // the self-collapsing block's margins only.
     872        // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
     873        if (!childDiscardMargin) {
     874            MarginValues childMargins = marginValuesForChild(child);
     875            marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
     876            marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
     877        } else
     878            marginInfo.clearMargin();
     879        marginInfo.setDiscardMargin(childDiscardMargin);
     880
     881        // CSS2.1 states:
     882        // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
     883        // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
     884        // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
     885        // for a block with height - if none is found then don't allow the margins to collapse with the parent.
     886        bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
     887        for (RenderBox* curr = child->nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
     888            if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
     889                wouldCollapseMarginsWithParent = false;
     890        }
     891        if (wouldCollapseMarginsWithParent)
     892            marginInfo.setCanCollapseMarginAfterWithChildren(false);
     893
     894        // CSS2.1: "the amount of clearance is set so that clearance + margin-top = [height of float], i.e., clearance = [height of float] - margin-top"
     895        // Move the top of the child box to the bottom of the float ignoring the child's top margin.
     896        LayoutUnit collapsedMargin = collapsedMarginBeforeForChild(child);
     897        setLogicalHeight(child->logicalTop() - collapsedMargin);
     898        // A negative collapsed margin-top value cancels itself out as it has already been factored into |yPos| above.
     899        heightIncrease -= max(LayoutUnit(), collapsedMargin);
     900    } else
     901        // Increase our height by the amount we had to clear.
     902        setLogicalHeight(logicalHeight() + heightIncrease);
     903   
     904    if (marginInfo.canCollapseWithMarginBefore()) {
     905        // We can no longer collapse with the top of the block since a clear
     906        // occurred. The empty blocks collapse into the cleared block.
     907        // FIXME: This isn't quite correct. Need clarification for what to do
     908        // if the height the cleared block is offset by is smaller than the
     909        // margins involved.
     910        setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
     911        marginInfo.setAtBeforeSideOfBlock(false);
     912
     913        // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value.
     914        setMustDiscardMarginBefore(style()->marginBeforeCollapse() == MDISCARD);
     915    }
     916
     917    LayoutUnit logicalTop = yPos + heightIncrease;
     918    // After margin collapsing, one of our floats may now intrude into the child. If the child doesn't contain floats of its own it
     919    // won't get picked up for relayout even though the logical top estimate was wrong - so add the newly intruding float now.
     920    if (containsFloats() && child->isRenderBlock() && !toRenderBlock(child)->containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
     921        toRenderBlock(child)->addIntrudingFloats(this, logicalLeftOffsetForContent(), logicalTop);
     922
     923    return logicalTop;
     924}
     925
     926void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
     927{
     928    // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
     929    // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
     930    // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
     931    if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child->style()->marginBeforeCollapse() == MSEPARATE)
     932        return;
     933
     934    // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
     935    // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
     936    if (child->style()->marginBeforeCollapse() == MDISCARD) {
     937        positiveMarginBefore = 0;
     938        negativeMarginBefore = 0;
     939        discardMarginBefore = true;
     940        return;
     941    }
     942
     943    LayoutUnit beforeChildMargin = marginBeforeForChild(child);
     944    positiveMarginBefore = max(positiveMarginBefore, beforeChildMargin);
     945    negativeMarginBefore = max(negativeMarginBefore, -beforeChildMargin);
     946
     947    if (!child->isRenderBlockFlow())
     948        return;
     949   
     950    RenderBlockFlow* childBlock = toRenderBlockFlow(child);
     951    if (childBlock->childrenInline() || childBlock->isWritingModeRoot())
     952        return;
     953
     954    MarginInfo childMarginInfo(childBlock, childBlock->borderAndPaddingBefore(), childBlock->borderAndPaddingAfter());
     955    if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
     956        return;
     957
     958    RenderBox* grandchildBox = childBlock->firstChildBox();
     959    for ( ; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
     960        if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
     961            break;
     962    }
     963   
     964    // Give up if there is clearance on the box, since it probably won't collapse into us.
     965    if (!grandchildBox || grandchildBox->style()->clear() != CNONE)
     966        return;
     967
     968    // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
     969    if (grandchildBox->needsLayout()) {
     970        grandchildBox->computeAndSetBlockDirectionMargins(this);
     971        if (grandchildBox->isRenderBlock()) {
     972            RenderBlock* grandchildBlock = toRenderBlock(grandchildBox);
     973            grandchildBlock->setHasMarginBeforeQuirk(grandchildBox->style()->hasMarginBeforeQuirk());
     974            grandchildBlock->setHasMarginAfterQuirk(grandchildBox->style()->hasMarginAfterQuirk());
     975        }
     976    }
     977
     978    // Collapse the margin of the grandchild box with our own to produce an estimate.
     979    childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
     980}
     981
     982LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
     983{
     984    // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
     985    // relayout if there are intruding floats.
     986    LayoutUnit logicalTopEstimate = logicalHeight();
     987    if (!marginInfo.canCollapseWithMarginBefore()) {
     988        LayoutUnit positiveMarginBefore = 0;
     989        LayoutUnit negativeMarginBefore = 0;
     990        bool discardMarginBefore = false;
     991        if (child->selfNeedsLayout()) {
     992            // Try to do a basic estimation of how the collapse is going to go.
     993            marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
     994        } else {
     995            // Use the cached collapsed margin values from a previous layout. Most of the time they
     996            // will be right.
     997            MarginValues marginValues = marginValuesForChild(child);
     998            positiveMarginBefore = max(positiveMarginBefore, marginValues.positiveMarginBefore());
     999            negativeMarginBefore = max(negativeMarginBefore, marginValues.negativeMarginBefore());
     1000            discardMarginBefore = mustDiscardMarginBeforeForChild(child);
     1001        }
     1002
     1003        // Collapse the result with our current margins.
     1004        if (!discardMarginBefore)
     1005            logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
     1006    }
     1007
     1008    // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
     1009    // page.
     1010    LayoutState* layoutState = view().layoutState();
     1011    if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
     1012        && hasNextPage(logicalHeight()))
     1013        logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
     1014
     1015    logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
     1016   
     1017    estimateWithoutPagination = logicalTopEstimate;
     1018
     1019    if (layoutState->isPaginated()) {
     1020        // If the object has a page or column break value of "before", then we should shift to the top of the next page.
     1021        logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
     1022   
     1023        // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
     1024        logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
     1025       
     1026        if (!child->selfNeedsLayout() && child->isRenderBlock())
     1027            logicalTopEstimate += toRenderBlock(child)->paginationStrut();
     1028    }
     1029
     1030    return logicalTopEstimate;
     1031}
     1032
     1033void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
     1034{
     1035    if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
     1036        // Update the after side margin of the container to discard if the after margin of the last child also discards and we collapse with it.
     1037        // Don't update the max margin values because we won't need them anyway.
     1038        if (marginInfo.discardMargin()) {
     1039            setMustDiscardMarginAfter();
     1040            return;
     1041        }
     1042
     1043        // Update our max pos/neg bottom margins, since we collapsed our bottom margins
     1044        // with our children.
     1045        setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
     1046
     1047        if (!marginInfo.hasMarginAfterQuirk())
     1048            setHasMarginAfterQuirk(false);
     1049
     1050        if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
     1051            // We have no bottom margin and our last child has a quirky margin.
     1052            // We will pick up this quirky margin and pass it through.
     1053            // This deals with the <td><div><p> case.
     1054            setHasMarginAfterQuirk(true);
     1055    }
     1056}
     1057
     1058void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
     1059{
     1060    marginInfo.setAtAfterSideOfBlock(true);
     1061
     1062    // If we can't collapse with children then go ahead and add in the bottom margin.
     1063    if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
     1064        && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
     1065        setLogicalHeight(logicalHeight() + marginInfo.margin());
     1066       
     1067    // Now add in our bottom border/padding.
     1068    setLogicalHeight(logicalHeight() + afterSide);
     1069
     1070    // Negative margins can cause our height to shrink below our minimal height (border/padding).
     1071    // If this happens, ensure that the computed height is increased to the minimal height.
     1072    setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
     1073
     1074    // Update our bottom collapsed margin info.
     1075    setCollapsedBottomMargin(marginInfo);
     1076}
     1077
     1078void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
     1079{
     1080    if (!m_rareData) {
     1081        if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(this))
     1082            return;
     1083        m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
     1084    }
     1085    m_rareData->m_margins.setPositiveMarginBefore(pos);
     1086    m_rareData->m_margins.setNegativeMarginBefore(neg);
     1087}
     1088
     1089void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
     1090{
     1091    if (!m_rareData) {
     1092        if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(this))
     1093            return;
     1094        m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
     1095    }
     1096    m_rareData->m_margins.setPositiveMarginAfter(pos);
     1097    m_rareData->m_margins.setNegativeMarginAfter(neg);
     1098}
     1099
     1100void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
     1101{
     1102    if (style()->marginBeforeCollapse() == MDISCARD) {
     1103        ASSERT(value);
     1104        return;
     1105    }
     1106   
     1107    if (!m_rareData && !value)
     1108        return;
     1109
     1110    if (!m_rareData)
     1111        m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
     1112
     1113    m_rareData->m_discardMarginBefore = value;
     1114}
     1115
     1116void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
     1117{
     1118    if (style()->marginAfterCollapse() == MDISCARD) {
     1119        ASSERT(value);
     1120        return;
     1121    }
     1122
     1123    if (!m_rareData && !value)
     1124        return;
     1125
     1126    if (!m_rareData)
     1127        m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
     1128
     1129    m_rareData->m_discardMarginAfter = value;
     1130}
     1131
     1132bool RenderBlockFlow::mustDiscardMarginBefore() const
     1133{
     1134    return style()->marginBeforeCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginBefore);
     1135}
     1136
     1137bool RenderBlockFlow::mustDiscardMarginAfter() const
     1138{
     1139    return style()->marginAfterCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginAfter);
     1140}
     1141
     1142bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox* child) const
     1143{
     1144    ASSERT(!child->selfNeedsLayout());
     1145    if (!child->isWritingModeRoot())
     1146        return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
     1147    if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
     1148        return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
     1149
     1150    // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
     1151    // In case the boxes are perpendicular we assume the property is not specified.
     1152    return false;
     1153}
     1154
     1155bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox* child) const
     1156{
     1157    ASSERT(!child->selfNeedsLayout());
     1158    if (!child->isWritingModeRoot())
     1159        return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
     1160    if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
     1161        return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
     1162
     1163    // FIXME: See |mustDiscardMarginBeforeForChild| above.
     1164    return false;
     1165}
     1166
     1167bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox* child) const
     1168{
     1169    ASSERT(!child->selfNeedsLayout());
     1170    const RenderStyle* childStyle = child->style();
     1171    if (!child->isWritingModeRoot())
     1172        return childStyle->marginBeforeCollapse() == MSEPARATE;
     1173    if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
     1174        return childStyle->marginAfterCollapse() == MSEPARATE;
     1175
     1176    // FIXME: See |mustDiscardMarginBeforeForChild| above.
     1177    return false;
     1178}
     1179
     1180bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox* child) const
     1181{
     1182    ASSERT(!child->selfNeedsLayout());
     1183    const RenderStyle* childStyle = child->style();
     1184    if (!child->isWritingModeRoot())
     1185        return childStyle->marginAfterCollapse() == MSEPARATE;
     1186    if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
     1187        return childStyle->marginBeforeCollapse() == MSEPARATE;
     1188
     1189    // FIXME: See |mustDiscardMarginBeforeForChild| above.
     1190    return false;
     1191}
     1192
     1193static bool inNormalFlow(RenderBox* child)
     1194{
     1195    RenderBlock* curr = child->containingBlock();
     1196    while (curr && curr != &child->view()) {
     1197        if (curr->hasColumns() || curr->isRenderFlowThread())
     1198            return true;
     1199        if (curr->isFloatingOrOutOfFlowPositioned())
     1200            return false;
     1201        curr = curr->containingBlock();
     1202    }
     1203    return true;
     1204}
     1205
     1206LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset)
     1207{
     1208    // FIXME: Add page break checking here when we support printing.
     1209    bool checkColumnBreaks = view().layoutState()->isPaginatingColumns();
     1210    bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
     1211    RenderFlowThread* flowThread = flowThreadContainingBlock();
     1212    bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
     1213    bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS)
     1214        || (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS);
     1215    if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
     1216        if (checkColumnBreaks)
     1217            view().layoutState()->addForcedColumnBreak(child, logicalOffset);
     1218        if (checkRegionBreaks) {
     1219            LayoutUnit offsetBreakAdjustment = 0;
     1220            if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment))
     1221                return logicalOffset + offsetBreakAdjustment;
     1222        }
     1223        return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
     1224    }
     1225    return logicalOffset;
     1226}
     1227
     1228LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
     1229{
     1230    // FIXME: Add page break checking here when we support printing.
     1231    bool checkColumnBreaks = view().layoutState()->isPaginatingColumns();
     1232    bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
     1233    RenderFlowThread* flowThread = flowThreadContainingBlock();
     1234    bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
     1235    bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS)
     1236        || (checkRegionBreaks && child->style()->regionBreakAfter() == PBALWAYS);
     1237    if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
     1238        LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
     1239
     1240        // So our margin doesn't participate in the next collapsing steps.
     1241        marginInfo.clearMargin();
     1242
     1243        if (checkColumnBreaks)
     1244            view().layoutState()->addForcedColumnBreak(child, logicalOffset);
     1245        if (checkRegionBreaks) {
     1246            LayoutUnit offsetBreakAdjustment = 0;
     1247            if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment))
     1248                return logicalOffset + marginOffset + offsetBreakAdjustment;
     1249        }
     1250        return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
     1251    }
     1252    return logicalOffset;
     1253}
     1254
     1255LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock)
     1256{
     1257    RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
     1258
     1259    if (estimateWithoutPagination != logicalTopAfterClear) {
     1260        // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
     1261        // position.
     1262        setLogicalHeight(logicalTopAfterClear);
     1263        setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
     1264
     1265        if (child->shrinkToAvoidFloats()) {
     1266            // The child's width depends on the line width.
     1267            // When the child shifts to clear an item, its width can
     1268            // change (because it has more available line width).
     1269            // So go ahead and mark the item as dirty.
     1270            child->setChildNeedsLayout(true, MarkOnlyThis);
     1271        }
     1272       
     1273        if (childRenderBlock) {
     1274            if (!child->avoidsFloats() && childRenderBlock->containsFloats())
     1275                childRenderBlock->markAllDescendantsWithFloatsForLayout();
     1276            if (!child->needsLayout())
     1277                child->markForPaginationRelayoutIfNeeded();
     1278        }
     1279
     1280        // Our guess was wrong. Make the child lay itself out again.
     1281        child->layoutIfNeeded();
     1282    }
     1283
     1284    LayoutUnit oldTop = logicalTopAfterClear;
     1285
     1286    // If the object has a page or column break value of "before", then we should shift to the top of the next page.
     1287    LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
     1288
     1289    if (pageLogicalHeightForOffset(result)) {
     1290        LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
     1291        LayoutUnit spaceShortage = child->logicalHeight() - remainingLogicalHeight;
     1292        if (spaceShortage > 0) {
     1293            // If the child crosses a column boundary, report a break, in case nothing inside it has already
     1294            // done so. The column balancer needs to know how much it has to stretch the columns to make more
     1295            // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
     1296            // This should be improved, though, because here we just pretend that the child is
     1297            // unsplittable. A splittable child, on the other hand, has break opportunities at every position
     1298            // where there's no child content, border or padding. In other words, we risk stretching more
     1299            // than necessary.
     1300            setPageBreak(result, spaceShortage);
     1301        }
     1302    }
     1303
     1304    // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
     1305    LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
     1306    LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
     1307   
     1308    LayoutUnit paginationStrut = 0;
     1309    LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
     1310    if (unsplittableAdjustmentDelta)
     1311        paginationStrut = unsplittableAdjustmentDelta;
     1312    else if (childRenderBlock && childRenderBlock->paginationStrut())
     1313        paginationStrut = childRenderBlock->paginationStrut();
     1314
     1315    if (paginationStrut) {
     1316        // We are willing to propagate out to our parent block as long as we were at the top of the block prior
     1317        // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
     1318        if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
     1319            // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
     1320            // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
     1321            // and pushes to the next page anyway, so not too concerned about it.
     1322            setPaginationStrut(result + paginationStrut);
     1323            if (childRenderBlock)
     1324                childRenderBlock->setPaginationStrut(0);
     1325        } else
     1326            result += paginationStrut;
     1327    }
     1328
     1329    // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
     1330    setLogicalHeight(logicalHeight() + (result - oldTop));
     1331   
     1332    // Return the final adjusted logical top.
     1333    return result;
     1334}
     1335
    4141336} // namespace WebCore
  • trunk/Source/WebCore/rendering/RenderBlockFlow.h

    r155377 r155555  
    4848    void layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom);
    4949    void layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom);
     50   
     51    // RenderBlockFlows override these methods, since they are the only class that supports margin collapsing.
     52    virtual LayoutUnit collapsedMarginBefore() const OVERRIDE FINAL { return maxPositiveMarginBefore() - maxNegativeMarginBefore(); }
     53    virtual LayoutUnit collapsedMarginAfter() const OVERRIDE FINAL { return maxPositiveMarginAfter() - maxNegativeMarginAfter(); }
     54
     55public:
     56    class MarginValues {
     57    public:
     58        MarginValues(LayoutUnit beforePos, LayoutUnit beforeNeg, LayoutUnit afterPos, LayoutUnit afterNeg)
     59            : m_positiveMarginBefore(beforePos)
     60            , m_negativeMarginBefore(beforeNeg)
     61            , m_positiveMarginAfter(afterPos)
     62            , m_negativeMarginAfter(afterNeg)
     63        { }
     64       
     65        LayoutUnit positiveMarginBefore() const { return m_positiveMarginBefore; }
     66        LayoutUnit negativeMarginBefore() const { return m_negativeMarginBefore; }
     67        LayoutUnit positiveMarginAfter() const { return m_positiveMarginAfter; }
     68        LayoutUnit negativeMarginAfter() const { return m_negativeMarginAfter; }
     69       
     70        void setPositiveMarginBefore(LayoutUnit pos) { m_positiveMarginBefore = pos; }
     71        void setNegativeMarginBefore(LayoutUnit neg) { m_negativeMarginBefore = neg; }
     72        void setPositiveMarginAfter(LayoutUnit pos) { m_positiveMarginAfter = pos; }
     73        void setNegativeMarginAfter(LayoutUnit neg) { m_negativeMarginAfter = neg; }
     74   
     75    private:
     76        LayoutUnit m_positiveMarginBefore;
     77        LayoutUnit m_negativeMarginBefore;
     78        LayoutUnit m_positiveMarginAfter;
     79        LayoutUnit m_negativeMarginAfter;
     80    };
     81    MarginValues marginValuesForChild(RenderBox* child) const;
     82
     83    // Allocated only when some of these fields have non-default values
     84    struct RenderBlockFlowRareData {
     85        WTF_MAKE_NONCOPYABLE(RenderBlockFlowRareData); WTF_MAKE_FAST_ALLOCATED;
     86    public:
     87        RenderBlockFlowRareData(const RenderBlockFlow* block)
     88            : m_margins(positiveMarginBeforeDefault(block), negativeMarginBeforeDefault(block), positiveMarginAfterDefault(block), negativeMarginAfterDefault(block))
     89            , m_discardMarginBefore(false)
     90            , m_discardMarginAfter(false)
     91        {
     92        }
     93
     94        static LayoutUnit positiveMarginBeforeDefault(const RenderBlock* block)
     95        {
     96            return std::max<LayoutUnit>(block->marginBefore(), 0);
     97        }
     98        static LayoutUnit negativeMarginBeforeDefault(const RenderBlock* block)
     99        {
     100            return std::max<LayoutUnit>(-block->marginBefore(), 0);
     101        }
     102        static LayoutUnit positiveMarginAfterDefault(const RenderBlock* block)
     103        {
     104            return std::max<LayoutUnit>(block->marginAfter(), 0);
     105        }
     106        static LayoutUnit negativeMarginAfterDefault(const RenderBlock* block)
     107        {
     108            return std::max<LayoutUnit>(-block->marginAfter(), 0);
     109        }
     110       
     111        MarginValues m_margins;
     112        bool m_discardMarginBefore : 1;
     113        bool m_discardMarginAfter : 1;
     114    };
     115
     116    class MarginInfo {
     117        // Collapsing flags for whether we can collapse our margins with our children's margins.
     118        bool m_canCollapseWithChildren : 1;
     119        bool m_canCollapseMarginBeforeWithChildren : 1;
     120        bool m_canCollapseMarginAfterWithChildren : 1;
     121
     122        // Whether or not we are a quirky container, i.e., do we collapse away top and bottom
     123        // margins in our container. Table cells and the body are the common examples. We
     124        // also have a custom style property for Safari RSS to deal with TypePad blog articles.
     125        bool m_quirkContainer : 1;
     126
     127        // This flag tracks whether we are still looking at child margins that can all collapse together at the beginning of a block. 
     128        // They may or may not collapse with the top margin of the block (|m_canCollapseTopWithChildren| tells us that), but they will
     129        // always be collapsing with one another. This variable can remain set to true through multiple iterations
     130        // as long as we keep encountering self-collapsing blocks.
     131        bool m_atBeforeSideOfBlock : 1;
     132
     133        // This flag is set when we know we're examining bottom margins and we know we're at the bottom of the block.
     134        bool m_atAfterSideOfBlock : 1;
     135
     136        // These variables are used to detect quirky margins that we need to collapse away (in table cells
     137        // and in the body element).
     138        bool m_hasMarginBeforeQuirk : 1;
     139        bool m_hasMarginAfterQuirk : 1;
     140        bool m_determinedMarginBeforeQuirk : 1;
     141
     142        bool m_discardMargin : 1;
     143
     144        // These flags track the previous maximal positive and negative margins.
     145        LayoutUnit m_positiveMargin;
     146        LayoutUnit m_negativeMargin;
     147
     148    public:
     149        MarginInfo(RenderBlockFlow*, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding);
     150
     151        void setAtBeforeSideOfBlock(bool b) { m_atBeforeSideOfBlock = b; }
     152        void setAtAfterSideOfBlock(bool b) { m_atAfterSideOfBlock = b; }
     153        void clearMargin()
     154        {
     155            m_positiveMargin = 0;
     156            m_negativeMargin = 0;
     157        }
     158        void setHasMarginBeforeQuirk(bool b) { m_hasMarginBeforeQuirk = b; }
     159        void setHasMarginAfterQuirk(bool b) { m_hasMarginAfterQuirk = b; }
     160        void setDeterminedMarginBeforeQuirk(bool b) { m_determinedMarginBeforeQuirk = b; }
     161        void setPositiveMargin(LayoutUnit p) { ASSERT(!m_discardMargin); m_positiveMargin = p; }
     162        void setNegativeMargin(LayoutUnit n) { ASSERT(!m_discardMargin); m_negativeMargin = n; }
     163        void setPositiveMarginIfLarger(LayoutUnit p)
     164        {
     165            ASSERT(!m_discardMargin);
     166            if (p > m_positiveMargin)
     167                m_positiveMargin = p;
     168        }
     169        void setNegativeMarginIfLarger(LayoutUnit n)
     170        {
     171            ASSERT(!m_discardMargin);
     172            if (n > m_negativeMargin)
     173                m_negativeMargin = n;
     174        }
     175
     176        void setMargin(LayoutUnit p, LayoutUnit n) { ASSERT(!m_discardMargin); m_positiveMargin = p; m_negativeMargin = n; }
     177        void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMarginAfterWithChildren = collapse; }
     178        void setDiscardMargin(bool value) { m_discardMargin = value; }
     179
     180        bool atBeforeSideOfBlock() const { return m_atBeforeSideOfBlock; }
     181        bool canCollapseWithMarginBefore() const { return m_atBeforeSideOfBlock && m_canCollapseMarginBeforeWithChildren; }
     182        bool canCollapseWithMarginAfter() const { return m_atAfterSideOfBlock && m_canCollapseMarginAfterWithChildren; }
     183        bool canCollapseMarginBeforeWithChildren() const { return m_canCollapseMarginBeforeWithChildren; }
     184        bool canCollapseMarginAfterWithChildren() const { return m_canCollapseMarginAfterWithChildren; }
     185        bool quirkContainer() const { return m_quirkContainer; }
     186        bool determinedMarginBeforeQuirk() const { return m_determinedMarginBeforeQuirk; }
     187        bool hasMarginBeforeQuirk() const { return m_hasMarginBeforeQuirk; }
     188        bool hasMarginAfterQuirk() const { return m_hasMarginAfterQuirk; }
     189        LayoutUnit positiveMargin() const { return m_positiveMargin; }
     190        LayoutUnit negativeMargin() const { return m_negativeMargin; }
     191        bool discardMargin() const { return m_discardMargin; }
     192        LayoutUnit margin() const { return m_positiveMargin - m_negativeMargin; }
     193    };
     194
     195    void layoutBlockChild(RenderBox* child, MarginInfo&, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom);
     196    void adjustPositionedBlock(RenderBox* child, const MarginInfo&);
     197    void adjustFloatingBlock(const MarginInfo&);
     198
     199    LayoutUnit collapseMargins(RenderBox* child, MarginInfo&);
     200    LayoutUnit clearFloatsIfNeeded(RenderBox* child, MarginInfo&, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos);
     201    LayoutUnit estimateLogicalTopPosition(RenderBox* child, const MarginInfo&, LayoutUnit& estimateWithoutPagination);
     202    void marginBeforeEstimateForChild(RenderBox*, LayoutUnit&, LayoutUnit&, bool&) const;
     203    void handleAfterSideOfBlock(LayoutUnit top, LayoutUnit bottom, MarginInfo&);
     204    void setCollapsedBottomMargin(const MarginInfo&);
     205
     206protected:
     207    LayoutUnit maxPositiveMarginBefore() const { return m_rareData ? m_rareData->m_margins.positiveMarginBefore() : RenderBlockFlowRareData::positiveMarginBeforeDefault(this); }
     208    LayoutUnit maxNegativeMarginBefore() const { return m_rareData ? m_rareData->m_margins.negativeMarginBefore() : RenderBlockFlowRareData::negativeMarginBeforeDefault(this); }
     209    LayoutUnit maxPositiveMarginAfter() const { return m_rareData ? m_rareData->m_margins.positiveMarginAfter() : RenderBlockFlowRareData::positiveMarginAfterDefault(this); }
     210    LayoutUnit maxNegativeMarginAfter() const { return m_rareData ? m_rareData->m_margins.negativeMarginAfter() : RenderBlockFlowRareData::negativeMarginAfterDefault(this); }
     211   
     212    void initMaxMarginValues()
     213    {
     214        if (!m_rareData)
     215            return;
     216        m_rareData->m_margins = MarginValues(RenderBlockFlowRareData::positiveMarginBeforeDefault(this) , RenderBlockFlowRareData::negativeMarginBeforeDefault(this),
     217            RenderBlockFlowRareData::positiveMarginAfterDefault(this), RenderBlockFlowRareData::negativeMarginAfterDefault(this));
     218        m_rareData->m_discardMarginBefore = false;
     219        m_rareData->m_discardMarginAfter = false;
     220    }
     221   
     222    void setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg);
     223    void setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg);
     224
     225    void setMustDiscardMarginBefore(bool = true);
     226    void setMustDiscardMarginAfter(bool = true);
     227
     228    bool mustDiscardMarginBefore() const;
     229    bool mustDiscardMarginAfter() const;
     230
     231    bool mustDiscardMarginBeforeForChild(const RenderBox*) const;
     232    bool mustDiscardMarginAfterForChild(const RenderBox*) const;
     233
     234    bool mustSeparateMarginBeforeForChild(const RenderBox*) const;
     235    bool mustSeparateMarginAfterForChild(const RenderBox*) const;
     236
     237    LayoutUnit applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset); // If the child has a before break, then return a new yPos that shifts to the top of the next page/column.
     238    LayoutUnit applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo&); // If the child has an after break, then return a new offset that shifts to the top of the next page/column.
     239    LayoutUnit adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock);
     240
     241protected:
     242    OwnPtr<RenderBlockFlowRareData> m_rareData;
    50243};
    51244
  • trunk/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp

    r155211 r155555  
    323323    m_stretchingChildren = false;
    324324
    325     initMaxMarginValues();
    326 
    327325#if !ASSERT_DISABLED
    328326    LayoutSize oldLayoutDelta = view().layoutDelta();
     
    351349
    352350    updateShapesAfterBlockLayout();
    353 
    354     if (!isFloatingOrOutOfFlowPositioned() && height() == 0) {
    355         // We are a block with no border and padding and a computed height
    356         // of 0.  The CSS spec states that zero-height blocks collapse their margins
    357         // together.
    358         // When blocks are self-collapsing, we just use the top margin values and set the
    359         // bottom margin max values to 0.  This way we don't factor in the values
    360         // twice when we collapse with our previous vertically adjacent and
    361         // following vertically adjacent blocks.
    362         LayoutUnit pos = maxPositiveMarginBefore();
    363         LayoutUnit neg = maxNegativeMarginBefore();
    364         if (maxPositiveMarginAfter() > pos)
    365             pos = maxPositiveMarginAfter();
    366         if (maxNegativeMarginAfter() > neg)
    367             neg = maxNegativeMarginAfter();
    368         setMaxMarginBeforeValues(pos, neg);
    369         setMaxMarginAfterValues(0, 0);
    370     }
    371351
    372352    computeOverflow(oldClientAfterEdge);
  • trunk/Source/WebCore/rendering/RenderTable.cpp

    r155374 r155555  
    409409
    410410    setLogicalHeight(0);
    411 
    412     initMaxMarginValues();
    413411   
    414412    LayoutUnit oldLogicalWidth = logicalWidth();
Note: See TracChangeset for help on using the changeset viewer.