Rework block layout to clean it up and simplify it (r=kocienda).
authorhyatt <hyatt@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 13 Oct 2004 08:04:38 +0000 (08:04 +0000)
committerhyatt <hyatt@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 13 Oct 2004 08:04:38 +0000 (08:04 +0000)
Also fixing the style sharing bug (r=mjs).

        * khtml/rendering/render_block.cpp:
        (khtml::RenderBlock::MarginInfo::MarginInfo):
        (khtml::RenderBlock::layoutBlock):
        (khtml::RenderBlock::adjustPositionedBlock):
        (khtml::RenderBlock::adjustFloatingBlock):
        (khtml::RenderBlock::handleSpecialChild):
        (khtml::RenderBlock::handleFloatingOrPositionedChild):
        (khtml::RenderBlock::handleCompactChild):
        (khtml::RenderBlock::insertCompactIfNeeded):
        (khtml::RenderBlock::handleRunInChild):
        (khtml::RenderBlock::collapseMargins):
        (khtml::RenderBlock::clearFloatsIfNeeded):
        (khtml::RenderBlock::estimateVerticalPosition):
        (khtml::RenderBlock::determineHorizontalPosition):
        (khtml::RenderBlock::setCollapsedBottomMargin):
        (khtml::RenderBlock::adjustChildIfOverhangingFloatsExist):
        (khtml::RenderBlock::handleBottomOfBlock):
        (khtml::RenderBlock::layoutBlockChildren):
        (khtml::RenderBlock::getAbsoluteRepaintRectIncludingFloats):
        (khtml::RenderBlock::addOverHangingFloats):
        * khtml/rendering/render_block.h:
        (khtml::RenderBlock::maxTopMargin):
        (khtml::RenderBlock::maxBottomMargin):
        (khtml::RenderBlock::CompactInfo::compact):
        (khtml::RenderBlock::CompactInfo::block):
        (khtml::RenderBlock::CompactInfo::matches):
        (khtml::RenderBlock::CompactInfo::clear):
        (khtml::RenderBlock::CompactInfo::set):
        (khtml::RenderBlock::CompactInfo::CompactInfo):
        (khtml::RenderBlock::MarginInfo::setAtTopOfBlock):
        (khtml::RenderBlock::MarginInfo::setAtBottomOfBlock):
        (khtml::RenderBlock::MarginInfo::clearMargin):
        (khtml::RenderBlock::MarginInfo::setSelfCollapsingBlockClearedFloat):
        (khtml::RenderBlock::MarginInfo::setTopQuirk):
        (khtml::RenderBlock::MarginInfo::setBottomQuirk):
        (khtml::RenderBlock::MarginInfo::setDeterminedTopQuirk):
        (khtml::RenderBlock::MarginInfo::setPosMargin):
        (khtml::RenderBlock::MarginInfo::setNegMargin):
        (khtml::RenderBlock::MarginInfo::setPosMarginIfLarger):
        (khtml::RenderBlock::MarginInfo::setNegMarginIfLarger):
        (khtml::RenderBlock::MarginInfo::setMargin):
        (khtml::RenderBlock::MarginInfo::atTopOfBlock):
        (khtml::RenderBlock::MarginInfo::canCollapseWithTop):
        (khtml::RenderBlock::MarginInfo::canCollapseWithBottom):
        (khtml::RenderBlock::MarginInfo::canCollapseTopWithChildren):
        (khtml::RenderBlock::MarginInfo::canCollapseBottomWithChildren):
        (khtml::RenderBlock::MarginInfo::selfCollapsingBlockClearedFloat):
        (khtml::RenderBlock::MarginInfo::quirkContainer):
        (khtml::RenderBlock::MarginInfo::determinedTopQuirk):
        (khtml::RenderBlock::MarginInfo::topQuirk):
        (khtml::RenderBlock::MarginInfo::bottomQuirk):
        (khtml::RenderBlock::MarginInfo::posMargin):
        (khtml::RenderBlock::MarginInfo::negMargin):
        (khtml::RenderBlock::MarginInfo::margin):
        * khtml/rendering/render_box.cpp:
        (RenderBox::calcAbsoluteVertical):
        * khtml/rendering/render_box.h:
        (khtml::RenderBox::marginTop):
        (khtml::RenderBox::marginBottom):
        (khtml::RenderBox::marginLeft):
        (khtml::RenderBox::marginRight):
        * khtml/rendering/render_image.cpp:
        (RenderImage::setImage):
        * khtml/rendering/render_object.cpp:
        (RenderObject::sizesToMaxWidth):
        * khtml/rendering/render_object.h:
        (khtml::RenderObject::collapsedMarginTop):
        (khtml::RenderObject::collapsedMarginBottom):
        (khtml::RenderObject::maxTopMargin):
        (khtml::RenderObject::maxBottomMargin):
        (khtml::RenderObject::marginTop):
        (khtml::RenderObject::marginBottom):
        (khtml::RenderObject::marginLeft):
        (khtml::RenderObject::marginRight):
        * khtml/rendering/render_text.h:
        (khtml::RenderText::marginLeft):
        (khtml::RenderText::marginRight):
        * khtml/xml/dom_elementimpl.cpp:
        (ElementImpl::recalcStyle):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@7824 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
LayoutTests/fast/compact/001-expected.txt
LayoutTests/fast/compact/002-expected.txt
LayoutTests/fast/compact/003-expected.txt
WebCore/ChangeLog-2005-08-23
WebCore/khtml/rendering/render_block.cpp
WebCore/khtml/rendering/render_block.h
WebCore/khtml/rendering/render_box.cpp
WebCore/khtml/rendering/render_box.h
WebCore/khtml/rendering/render_image.cpp
WebCore/khtml/rendering/render_object.cpp
WebCore/khtml/rendering/render_object.h
WebCore/khtml/rendering/render_text.h
WebCore/khtml/xml/dom_elementimpl.cpp

index 9193c3e0f71f049e102d894a12ab5e644732d9f6..d73d1e85057f3702b7fbe4fe7310945d0004d513 100644 (file)
@@ -7,7 +7,7 @@ layer at (0,0) size 800x76
         RenderText {TEXT} at (0,0) size 193x18
           text run at (0,0) width 193: "There should be no red below."
       RenderBlock {DIV} at (160,34) size 624x18 [color=#FF0000] [bgcolor=#00FF00]
-        RenderBlock (compact) {DIV} at (-160,0) size 769x0 [color=#000000]
+        RenderBlock (compact) {DIV} at (-160,0) size 0x0 [color=#000000]
           RenderText {TEXT} at (0,0) size 31x18
             text run at (0,0) width 31: "Test:"
         RenderInline {SPAN} at (0,0) size 299x18 [color=#000000]
index 5e42b6d8b5526fa4901971066f98587ce21923d3..27ecff2365cd900c56ad0d62c78b15b05da17dcc 100644 (file)
@@ -13,7 +13,7 @@ layer at (0,0) size 800x116
           text run at (0,0) width 346: "There should be a single green rectangle square below."
       RenderBlock {DIV} at (0,68) size 64x32 [color=#008000] [bgcolor=#FF0000]
         RenderBlock {DIV} at (32,0) size 32x32
-          RenderBlock (compact) {DIV} at (-32,0) size 64x0
+          RenderBlock (compact) {DIV} at (-32,0) size 0x0
             RenderText {TEXT} at (0,0) size 32x32
               text run at (0,0) width 32: "X"
           RenderText {TEXT} at (0,0) size 32x32
index 10fb1983985187c2302db6c219e0cb0ddab8e7fe..20558eb346383375a64d36c3b3a76022bed33dbc 100644 (file)
@@ -4,10 +4,10 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x576
       RenderBlock {DL} at (0,0) size 784x36
-        RenderBlock (compact) {DT} at (0,0) size 60x18
+        RenderBlock (compact) {DT} at (0,0) size 784x18
           RenderText {TEXT} at (0,0) size 60x18
             text run at (0,0) width 60: "Line One"
-        RenderBlock (compact) {DT} at (0,18) size 63x18
+        RenderBlock (compact) {DT} at (0,18) size 784x18
           RenderText {TEXT} at (0,0) size 33x18
             text run at (0,0) width 33: "Line "
           RenderInline {SPAN} at (0,0) size 30x18
index 90183daacd0d571c7ab8af5574b030adee92cf59..ca5318f408440e58e75d9c59bfe58255db9413a8 100644 (file)
@@ -1,3 +1,89 @@
+2004-10-13  David Hyatt  <hyatt@apple.com>
+
+       Rework block layout to clean it up and simplify it (r=kocienda).  
+
+       Also fixing the style sharing bug (r=mjs).
+       
+        * khtml/rendering/render_block.cpp:
+        (khtml::RenderBlock::MarginInfo::MarginInfo):
+        (khtml::RenderBlock::layoutBlock):
+        (khtml::RenderBlock::adjustPositionedBlock):
+        (khtml::RenderBlock::adjustFloatingBlock):
+        (khtml::RenderBlock::handleSpecialChild):
+        (khtml::RenderBlock::handleFloatingOrPositionedChild):
+        (khtml::RenderBlock::handleCompactChild):
+        (khtml::RenderBlock::insertCompactIfNeeded):
+        (khtml::RenderBlock::handleRunInChild):
+        (khtml::RenderBlock::collapseMargins):
+        (khtml::RenderBlock::clearFloatsIfNeeded):
+        (khtml::RenderBlock::estimateVerticalPosition):
+        (khtml::RenderBlock::determineHorizontalPosition):
+        (khtml::RenderBlock::setCollapsedBottomMargin):
+        (khtml::RenderBlock::adjustChildIfOverhangingFloatsExist):
+        (khtml::RenderBlock::handleBottomOfBlock):
+        (khtml::RenderBlock::layoutBlockChildren):
+        (khtml::RenderBlock::getAbsoluteRepaintRectIncludingFloats):
+        (khtml::RenderBlock::addOverHangingFloats):
+        * khtml/rendering/render_block.h:
+        (khtml::RenderBlock::maxTopMargin):
+        (khtml::RenderBlock::maxBottomMargin):
+        (khtml::RenderBlock::CompactInfo::compact):
+        (khtml::RenderBlock::CompactInfo::block):
+        (khtml::RenderBlock::CompactInfo::matches):
+        (khtml::RenderBlock::CompactInfo::clear):
+        (khtml::RenderBlock::CompactInfo::set):
+        (khtml::RenderBlock::CompactInfo::CompactInfo):
+        (khtml::RenderBlock::MarginInfo::setAtTopOfBlock):
+        (khtml::RenderBlock::MarginInfo::setAtBottomOfBlock):
+        (khtml::RenderBlock::MarginInfo::clearMargin):
+        (khtml::RenderBlock::MarginInfo::setSelfCollapsingBlockClearedFloat):
+        (khtml::RenderBlock::MarginInfo::setTopQuirk):
+        (khtml::RenderBlock::MarginInfo::setBottomQuirk):
+        (khtml::RenderBlock::MarginInfo::setDeterminedTopQuirk):
+        (khtml::RenderBlock::MarginInfo::setPosMargin):
+        (khtml::RenderBlock::MarginInfo::setNegMargin):
+        (khtml::RenderBlock::MarginInfo::setPosMarginIfLarger):
+        (khtml::RenderBlock::MarginInfo::setNegMarginIfLarger):
+        (khtml::RenderBlock::MarginInfo::setMargin):
+        (khtml::RenderBlock::MarginInfo::atTopOfBlock):
+        (khtml::RenderBlock::MarginInfo::canCollapseWithTop):
+        (khtml::RenderBlock::MarginInfo::canCollapseWithBottom):
+        (khtml::RenderBlock::MarginInfo::canCollapseTopWithChildren):
+        (khtml::RenderBlock::MarginInfo::canCollapseBottomWithChildren):
+        (khtml::RenderBlock::MarginInfo::selfCollapsingBlockClearedFloat):
+        (khtml::RenderBlock::MarginInfo::quirkContainer):
+        (khtml::RenderBlock::MarginInfo::determinedTopQuirk):
+        (khtml::RenderBlock::MarginInfo::topQuirk):
+        (khtml::RenderBlock::MarginInfo::bottomQuirk):
+        (khtml::RenderBlock::MarginInfo::posMargin):
+        (khtml::RenderBlock::MarginInfo::negMargin):
+        (khtml::RenderBlock::MarginInfo::margin):
+        * khtml/rendering/render_box.cpp:
+        (RenderBox::calcAbsoluteVertical):
+        * khtml/rendering/render_box.h:
+        (khtml::RenderBox::marginTop):
+        (khtml::RenderBox::marginBottom):
+        (khtml::RenderBox::marginLeft):
+        (khtml::RenderBox::marginRight):
+        * khtml/rendering/render_image.cpp:
+        (RenderImage::setImage):
+        * khtml/rendering/render_object.cpp:
+        (RenderObject::sizesToMaxWidth):
+        * khtml/rendering/render_object.h:
+        (khtml::RenderObject::collapsedMarginTop):
+        (khtml::RenderObject::collapsedMarginBottom):
+        (khtml::RenderObject::maxTopMargin):
+        (khtml::RenderObject::maxBottomMargin):
+        (khtml::RenderObject::marginTop):
+        (khtml::RenderObject::marginBottom):
+        (khtml::RenderObject::marginLeft):
+        (khtml::RenderObject::marginRight):
+        * khtml/rendering/render_text.h:
+        (khtml::RenderText::marginLeft):
+        (khtml::RenderText::marginRight):
+        * khtml/xml/dom_elementimpl.cpp:
+        (ElementImpl::recalcStyle):
+
 2004-10-12  Ken Kocienda  <kocienda@apple.com>
 
         Reviewed by John
index 93720d898ec8844dc2dc795b05c634691252282a..a5f906149092927bf63a42cd1487966922cbc458 100644 (file)
@@ -46,6 +46,42 @@ using namespace DOM;
 
 namespace khtml {
 
+// -------------------------------------------------------------------------------------------------------
+
+// Our MarginInfo state used when laying out block children.
+RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom)
+{
+    // Whether or not we can collapse our own margins with our children.  We don't do this
+    // if we had any border/padding (obviously), if we're the root or HTML elements, or if
+    // we're positioned, floating, a table cell.
+    m_canCollapseWithChildren = !block->isCanvas() && !block->isRoot() && !block->isPositioned() &&
+        !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable();
+
+    m_canCollapseTopWithChildren = m_canCollapseWithChildren && (top == 0) && block->style()->marginTopCollapse() != MSEPARATE;
+
+    // If any height other than auto is specified in CSS, then we don't collapse our bottom
+    // margins with our children's margins.  To do otherwise would be to risk odd visual
+    // effects when the children overflow out of the parent block and yet still collapse
+    // with it.  We also don't collapse if we have any bottom border/padding.
+    m_canCollapseBottomWithChildren = m_canCollapseWithChildren && (bottom == 0) &&
+        (block->style()->height().isVariable() && block->style()->height().value == 0) && block->style()->marginBottomCollapse() != MSEPARATE;
+    
+    m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginTopCollapse() == MDISCARD || 
+        block->style()->marginBottomCollapse() == MDISCARD;
+
+    m_atTopOfBlock = true;
+    m_atBottomOfBlock = false;
+
+    m_posMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(true) : 0;
+    m_negMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(false) : 0;
+
+    m_selfCollapsingBlockClearedFloat = false;
+    
+    m_topQuirk = m_bottomQuirk = m_determinedTopQuirk = false;
+}
+
+// -------------------------------------------------------------------------------------------------------
+
 RenderBlock::RenderBlock(DOM::NodeImpl* node)
 :RenderFlow(node)
 {
@@ -352,14 +388,11 @@ void RenderBlock::layout()
 
 void RenderBlock::layoutBlock(bool relayoutChildren)
 {
-    //    kdDebug( 6040 ) << renderName() << " " << this << "::layoutBlock() start" << endl;
-    //     QTime t;
-    //     t.start();
-    KHTMLAssert( needsLayout() );
-    KHTMLAssert( minMaxKnown() );
+    KHTMLAssert(needsLayout());
+    KHTMLAssert(minMaxKnown());
 
     if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
-        return;                                             // cause us to come in here.  Just bail. -dwh
+        return;                                             // cause us to come in here.  Just bail.
 
     if (!relayoutChildren && posChildNeedsLayout() && !normalChildNeedsLayout() && !selfNeedsLayout()) {
         // All we have to is lay out our positioned objects.
@@ -380,19 +413,9 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
     calcWidth();
     m_overflowWidth = m_width;
 
-    if ( oldWidth != m_width )
+    if (oldWidth != m_width)
         relayoutChildren = true;
 
-    //     kdDebug( 6040 ) << floatingObjects << "," << oldWidth << ","
-    //                     << m_width << ","<< needsLayout() << "," << isAnonymous() << ","
-    //                     << "," << isPositioned() << endl;
-
-#ifdef DEBUG_LAYOUT
-    kdDebug( 6040 ) << renderName() << "(RenderBlock) " << this << " ::layout() width=" << m_width << ", needsLayout=" << needsLayout() << endl;
-    if(containingBlock() == static_cast<RenderObject *>(this))
-        kdDebug( 6040 ) << renderName() << ": containingBlock == this" << endl;
-#endif
-
     clearFloats();
 
     m_height = 0;
@@ -432,9 +455,8 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
         // does painting or event handling.
         m_layer->moveScrollbarsAside();
     }
-    
-    //    kdDebug( 6040 ) << "childrenInline()=" << childrenInline() << endl;
-    QRect repaintRect(0,0,0,0);
+   
+    QRect repaintRect;
     if (childrenInline())
         repaintRect = layoutInlineChildren( relayoutChildren );
     else
@@ -475,15 +497,13 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
             m_height = m_overflowHeight + borderBottom() + paddingBottom();
     }
 
-    ifhasOverhangingFloats() && (isFloating() || isTableCell())) {
+    if (hasOverhangingFloats() && (isFloating() || isTableCell())) {
         m_height = floatBottom();
         m_height += borderBottom() + paddingBottom();
     }
 
     layoutPositionedObjects( relayoutChildren );
 
-    //kdDebug() << renderName() << " layout width=" << m_width << " height=" << m_height << endl;
-
     // Always ensure our overflow width/height are at least as large as our width/height.
     if (m_overflowWidth < m_width)
         m_overflowWidth = m_width;
@@ -507,625 +527,588 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
     setNeedsLayout(false);
 }
 
-void RenderBlock::layoutBlockChildren( bool relayoutChildren )
+void RenderBlock::adjustPositionedBlock(RenderObject* child, const MarginInfo& marginInfo)
 {
-#ifdef DEBUG_LAYOUT
-    kdDebug( 6040 ) << renderName() << " layoutBlockChildren( " << this <<" ), relayoutChildren="<< relayoutChildren << endl;
-#endif
+    if (child->hasStaticX()) {
+        if (style()->direction() == LTR)
+            child->setStaticX(borderLeft() + paddingLeft());
+        else
+            child->setStaticX(borderRight() + paddingRight());
+    }
 
-    int xPos = borderLeft() + paddingLeft();
-    if( style()->direction() == RTL )
-        xPos = m_width - paddingRight() - borderRight();
+    if (child->hasStaticY()) {
+        int marginOffset = 0;
+        if (!marginInfo.canCollapseWithTop()) {
+            int collapsedTopPos = marginInfo.posMargin();
+            int collapsedTopNeg = marginInfo.negMargin();
+            bool posMargin = child->marginTop() >= 0;
+            if (posMargin && child->marginTop() > collapsedTopPos)
+                collapsedTopPos = child->marginTop();
+            else if (!posMargin && child->marginTop() > collapsedTopNeg)
+                collapsedTopNeg = child->marginTop();
+            marginOffset += (collapsedTopPos - collapsedTopNeg) - child->marginTop();
+        }
+        
+        child->setStaticY(m_height + marginOffset);
+    }
+}
 
-    int toAdd = borderBottom() + paddingBottom();
-    if (includeScrollbarSize())
-        toAdd += m_layer->horizontalScrollbarHeight();
-    
-    m_height = borderTop() + paddingTop();
+void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
+{
+    // The float should be positioned taking into account the bottom margin
+    // of the previous flow.  We add that margin into the height, get the
+    // float positioned properly, and then subtract the margin out of the
+    // height again.  In the case of self-collapsing blocks, we always just
+    // use the top margins, since the self-collapsing block collapsed its
+    // own bottom margin into its top margin.
+    //
+    // Note also that the previous flow may collapse its margin into the top of
+    // our block.  If this is the case, then we do not add the margin in to our
+    // height when computing the position of the float.   This condition can be tested
+    // for by simply checking the boolean |addPreviousMargins| variable.  See
+    // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
+    // an example of this scenario.
+    int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin();
+    m_height += marginOffset;
+    positionNewFloats();
+    m_height -= marginOffset;
+}
 
-    // Fieldsets need to find their legend and position it inside the border of the object.
-    // The legend then gets skipped during normal layout.
-    RenderObject* legend = layoutLegend(relayoutChildren);
+RenderObject* RenderBlock::handleSpecialChild(RenderObject* child, const MarginInfo& marginInfo, CompactInfo& compactInfo, bool& handled)
+{
+    // Handle floating/positioned children first.
+    RenderObject* next = handleFloatingOrPositionedChild(child, marginInfo, handled);
+    if (handled) return next;
     
-    int minHeight = m_height + toAdd;
-    m_overflowHeight = m_height;
+    // See if we have a compact element.  If we do, then try to tuck the compact element into the margin space of the next block.
+    next = handleCompactChild(child, compactInfo, handled);
+    if (handled) return next;
 
-    RenderObject* child = firstChild();
-    RenderBlock* prevFlow = 0;
-    RenderObject* prevBlock = 0;
-    
-    // A compact child that needs to be collapsed into the margin of the following block.
-    RenderObject* compactChild = 0;
-    // The block with the open margin that the compact child is going to place itself within.
-    RenderObject* blockForCompactChild = 0;
-    // For compact children that don't fit, we lay them out as though they are blocks.  This
-    // boolean allows us to temporarily treat a compact like a block and lets us know we need
-    // to turn the block back into a compact when we're done laying out.
-    bool treatCompactAsBlock = false;
-    
-    // Whether or not we can collapse our own margins with our children.  We don't do this
-    // if we had any border/padding (obviously), if we're the root or HTML elements, or if
-    // we're positioned, floating, a table cell.
-    // For now we only worry about the top border/padding.  We will update the variable's
-    // value when it comes time to check against the bottom border/padding.
-    bool canCollapseWithChildren = !isCanvas() && !isRoot() && !isPositioned() &&
-        !isFloating() && !isTableCell() && !hasOverflowClip() && !isInlineBlockOrInlineTable();
-    bool canCollapseTopWithChildren = canCollapseWithChildren && (m_height == 0) && style()->marginTopCollapse() != MSEPARATE;
+    // Finally, see if we have a run-in element.
+    return handleRunInChild(child, handled);
+}
 
-    // If any height other than auto is specified in CSS, then we don't collapse our bottom
-    // margins with our children's margins.  To do otherwise would be to risk odd visual
-    // effects when the children overflow out of the parent block and yet still collapse
-    // with it.  We also don't collapse if we had any bottom border/padding (represented by
-    // |toAdd|).
-    bool canCollapseBottomWithChildren = canCollapseWithChildren && (toAdd == 0) &&
-        (style()->height().isVariable() && style()->height().value == 0) && style()->marginBottomCollapse() != MSEPARATE;
+
+RenderObject* RenderBlock::handleFloatingOrPositionedChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled)
+{
+    if (child->isPositioned()) {
+        handled = true;
+        child->containingBlock()->insertPositionedObject(child);
+        adjustPositionedBlock(child, marginInfo);
+        return child->nextSibling();
+    }
+
+    if (child->isFloating()) {
+        handled = true;
+        insertFloatingObject(child);
+        adjustFloatingBlock(marginInfo);
+        return child->nextSibling();
+    }
     
-    // Whether or not we are a quirky container, i.e., do we collapse away top and bottom
-    // margins in our container.
-    bool quirkContainer = isTableCell() || isBody() || style()->marginTopCollapse() == MDISCARD ||
-                          style()->marginBottomCollapse() == MDISCARD;
-
-    // This flag tracks whether the child should collapse with the top margins of the block.
-    // It can remain set through multiple iterations as long as we keep encountering
-    // self-collapsing blocks.
-    bool topMarginContributor = true;
-
-    // These flags track the previous maximal positive and negative margins.
-    int prevPosMargin = canCollapseTopWithChildren ? maxTopMargin(true) : 0;
-    int prevNegMargin = canCollapseTopWithChildren ? maxTopMargin(false) : 0;
-
-    // Whether or not we encountered an element with clear set that actually had to
-    // be pushed down below a float.
-    bool clearOccurred = false;
-
-    // If our last normal flow child was a self-collapsing block that cleared a float,
-    // we track it in this variable.
-    bool selfCollapsingBlockClearedFloat = false;
+    return 0;
+}
+
+RenderObject* RenderBlock::handleCompactChild(RenderObject* child, CompactInfo& compactInfo, bool& handled)
+{
+    // FIXME: We only deal with one compact at a time.  It is unclear what should be
+    // done if multiple contiguous compacts are encountered.  For now we assume that
+    // compact A followed by another compact B should simply be treated as block A.
+    if (child->isCompact() && !compactInfo.compact() && (child->childrenInline() || child->isReplaced())) {
+        // Get the next non-positioned/non-floating RenderBlock.
+        RenderObject* next = child->nextSibling();
+        RenderObject* curr = next;
+        while (curr && curr->isFloatingOrPositioned())
+            curr = curr->nextSibling();
+        if (curr && curr->isRenderBlock() && !curr->isCompact() && !curr->isRunIn()) {
+            curr->calcWidth(); // So that horizontal margins are correct.
+                               
+            child->setInline(true); // Need to compute the margins/width for the child as though it is an inline, so that it won't try to puff up the margins to
+                                    // fill the containing block width.
+            child->calcWidth();
+            int childMargins = child->marginLeft() + child->marginRight();
+            int margin = style()->direction() == LTR ? curr->marginLeft() : curr->marginRight();
+            if (margin >= (childMargins + child->maxWidth())) {
+                // The compact will fit in the margin.
+                handled = true;
+                compactInfo.set(child, curr);
+                child->setInline(true);
+                child->setPos(0,0); // This position will be updated to reflect the compact's
+                                    // desired position and the line box for the compact will
+                                    // pick that position up.
+                
+                // Remove the child.
+                RenderObject* next = child->nextSibling();
+                removeChildNode(child);
+                
+                // Now insert the child under |curr|.
+                curr->insertChildNode(child, curr->firstChild());
+                return next;
+            }
+            else
+                child->setInline(false); // We didn't fit, so we remain a block-level element.
+        }
+    }
+    return 0;
+}
+
+void RenderBlock::insertCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo)
+{
+    if (compactInfo.matches(child)) {
+        // We have a compact child to squeeze in.
+        RenderObject* compactChild = compactInfo.compact();
+        int compactXPos = borderLeft() + paddingLeft() + compactChild->marginLeft();
+        if (style()->direction() == RTL) {
+            compactChild->calcWidth(); // have to do this because of the capped maxwidth
+            compactXPos = width() - borderRight() - paddingRight() - marginRight() -
+                compactChild->width() - compactChild->marginRight();
+        }
+        compactXPos -= child->xPos(); // Put compactXPos into the child's coordinate space.
+        compactChild->setPos(compactXPos, compactChild->yPos()); // Set the x position.
+        compactInfo.clear();
+    }
+}
+
+RenderObject* RenderBlock::handleRunInChild(RenderObject* child, bool& handled)
+{
+    // See if we have a run-in element with inline children.  If the
+    // children aren't inline, then just treat the run-in as a normal
+    // block.
+    if (child->isRunIn() && (child->childrenInline() || child->isReplaced())) {
+        // Get the next non-positioned/non-floating RenderBlock.
+        RenderObject* curr = child->nextSibling();
+        while (curr && curr->isFloatingOrPositioned())
+            curr = curr->nextSibling();
+        if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isCompact() && !curr->isRunIn())) {
+            // The block acts like an inline, so just null out its
+            // position.
+            handled = true;
+            child->setInline(true);
+            child->setPos(0,0);
+            
+            // Remove the child.
+            RenderObject* next = child->nextSibling();
+            removeChildNode(child);
+            
+            // Now insert the child under |curr|.
+            curr->insertChildNode(child, curr->firstChild());
+            return next;
+        }
+    }
+    return 0;
+}
+
+void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, int yPosEstimate)
+{
+    // Get our max pos and neg top margins.
+    int posTop = child->maxTopMargin(true);
+    int negTop = child->maxTopMargin(false);
+
+    // For self-collapsing blocks, collapse our bottom margins into our
+    // top to get new posTop and negTop values.
+    if (child->isSelfCollapsingBlock()) {
+        posTop = kMax(posTop, child->maxBottomMargin(true));
+        negTop = kMax(negTop, child->maxBottomMargin(false));
+    }
     
-    bool topChildQuirk = false;
-    bool bottomChildQuirk = false;
-    bool determinedTopQuirk = false;
+    // See if the top margin is quirky. We only care if this child has
+    // margins that will collapse with us.
+    bool topQuirk = child->isTopMarginQuirk() || style()->marginTopCollapse() == MDISCARD;
+
+    if (marginInfo.canCollapseWithTop()) {
+        // This child is collapsing with the top of the
+        // block.  If it has larger margin values, then we need to update
+        // our own maximal values.
+        if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk) {
+            m_maxTopPosMargin = kMax(posTop, m_maxTopPosMargin);
+            m_maxTopNegMargin = kMax(negTop, m_maxTopNegMargin);
+        }
+
+        // The minute any of the margins involved isn't a quirk, don't
+        // collapse it away, even if the margin is smaller (www.webreference.com
+        // has an example of this, a <dt> with 0.8em author-specified inside
+        // a <dl> inside a <td>.
+        if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop-negTop)) {
+            m_topMarginQuirk = false;
+            marginInfo.setDeterminedTopQuirk(true);
+        }
+
+        if (!marginInfo.determinedTopQuirk() && topQuirk && marginTop() == 0)
+            // We have no top margin and our top child has a quirky margin.
+            // We will pick up this quirky margin and pass it through.
+            // This deals with the <td><div><p> case.
+            // Don't do this for a block that split two inlines though.  You do
+            // still apply margins in this case.
+            m_topMarginQuirk = true;
+    }
+
+    if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop))
+        marginInfo.setTopQuirk(topQuirk);
+
+    int ypos = m_height;
+    if (child->isSelfCollapsingBlock()) {
+        // This child has no height.  We need to compute our
+        // position before we collapse the child's margins together,
+        // so that we can get an accurate position for the zero-height block.
+        int collapsedTopPos = kMax(marginInfo.posMargin(), child->maxTopMargin(true));
+        int collapsedTopNeg = kMax(marginInfo.negMargin(), child->maxTopMargin(false));
+        marginInfo.setMargin(collapsedTopPos, collapsedTopNeg);
+        
+        // Now collapse the child's margins together, which means examining our
+        // bottom margin values as well. 
+        marginInfo.setPosMarginIfLarger(child->maxBottomMargin(true));
+        marginInfo.setNegMarginIfLarger(child->maxBottomMargin(false));
+
+        if (!marginInfo.canCollapseWithTop())
+            // We need to make sure that the position of the self-collapsing block
+            // is correct, since it could have overflowing content
+            // that needs to be positioned correctly (e.g., a block that
+            // had a specified height of 0 but that actually had subcontent).
+            ypos = m_height + collapsedTopPos - collapsedTopNeg;
+    }
+    else {
+        if (child->style()->marginTopCollapse() == MSEPARATE) {
+            m_height += marginInfo.margin() + child->marginTop();
+            ypos = m_height;
+        }
+        else if (!marginInfo.atTopOfBlock() ||
+            (!marginInfo.canCollapseTopWithChildren()
+             && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) {
+            // We're collapsing with a previous sibling's margins and not
+            // with the top of the block.
+            m_height += kMax(marginInfo.posMargin(), posTop) - kMax(marginInfo.negMargin(), negTop);
+            ypos = m_height;
+        }
 
-    bool strictMode = !style()->htmlHacks();
+        marginInfo.setPosMargin(child->maxBottomMargin(true));
+        marginInfo.setNegMargin(child->maxBottomMargin(false));
 
-    //kdDebug() << "RenderBlock::layoutBlockChildren " << prevMargin << endl;
+        if (marginInfo.margin())
+            marginInfo.setBottomQuirk(child->isBottomMarginQuirk() || style()->marginBottomCollapse() == MDISCARD);
 
-    //     QTime t;
-    //     t.start();
+        marginInfo.setSelfCollapsingBlockClearedFloat(false);
+    }
 
-    while( child != 0 )
-    {
-        // Sometimes an element will be shoved down away from a previous sibling, e.g., when
-        // clearing to pass beyond a float.  In this case, you don't need to collapse.  This
-        // boolean is updated with each iteration through our child list to reflect whether
-        // that particular child should be collapsed with its previous sibling (or with the top
-        // of the block).
-        bool shouldCollapseChild = true;
-                
-        int oldTopPosMargin = m_maxTopPosMargin;
-        int oldTopNegMargin = m_maxTopNegMargin;
+    child->setPos(child->xPos(), ypos);
+    if (ypos != yPosEstimate) {
+        if (child->style()->width().isPercent() && child->usesLineWidth())
+            // The child's width is a percentage of the line width.
+            // When the child shifts to clear an item, its width can
+            // change (because it has more available line width).
+            // So go ahead and mark the item as dirty.
+            child->setChildNeedsLayout(true);
 
-        if (legend == child) {
-            child = child->nextSibling();
-            continue; // Skip the legend, since it has already been positioned up in the fieldset's border.
+        if (child->containsFloats() || containsFloats())
+            child->markAllDescendantsWithFloatsForLayout();
+
+        // Our guess was wrong. Make the child lay itself out again.
+        child->layoutIfNeeded();
+    }
+}
+
+void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin)
+{
+    int heightIncrease = getClearDelta(child);
+    if (heightIncrease) {
+        // The child needs to be lowered.  Move the child so that it just clears the float.
+        child->setPos(child->xPos(), child->yPos() + heightIncrease);
+
+        // Increase our height by the amount we had to clear.
+        if (!child->isSelfCollapsingBlock())
+            m_height += heightIncrease;
+        else {
+            // For self-collapsing blocks that clear, they may end up collapsing
+            // into the bottom of the parent block.  We simulate this behavior by
+            // setting our positive margin value to compensate for the clear.
+            marginInfo.setPosMargin(kMax(0, child->yPos() - m_height));
+            marginInfo.setNegMargin(0);
+            marginInfo.setSelfCollapsingBlockClearedFloat(true);
         }
         
-        // make sure we relayout children if we need it.
-        if (relayoutChildren || floatBottom() > m_y ||
-            (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())) ||
-            (child->isRenderBlock() && child->style()->height().isPercent()))
+        if (marginInfo.canCollapseWithTop()) {
+            // We can no longer collapse with the top of the block since a clear
+            // occurred.  The empty blocks collapse into the cleared block.
+            // FIXME: This isn't quite correct.  Need clarification for what to do
+            // if the height the cleared block is offset by is smaller than the
+            // margins involved.
+            m_maxTopPosMargin = oldTopPosMargin;
+            m_maxTopNegMargin = oldTopNegMargin;
+            marginInfo.setAtTopOfBlock(false);
+        }
+
+        // If our value of clear caused us to be repositioned vertically to be
+        // underneath a float, we might have to do another layout to take into account
+        // the extra space we now have available.
+        if (child->style()->width().isPercent() && child->usesLineWidth())
+            // The child's width is a percentage of the line width.
+            // When the child shifts to clear an item, its width can
+            // change (because it has more available line width).
+            // So go ahead and mark the item as dirty.
             child->setChildNeedsLayout(true);
+        if (child->containsFloats())
+            child->markAllDescendantsWithFloatsForLayout();
+        child->layoutIfNeeded();
+    }
+}
 
-        //         kdDebug( 6040 ) << "   " << child->renderName() << " loop " << child << ", " << child->isInline() << ", " << child->needsLayout() << endl;
-        //         kdDebug( 6040 ) << t.elapsed() << endl;
-        // ### might be some layouts are done two times... FIX that.
+int RenderBlock::estimateVerticalPosition(RenderObject* child, const MarginInfo& marginInfo, RenderObject* prevBlock)
+{
+    // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we trigger a pathological
+    // relayout if there are intruding floats.
+    int yPosEstimate = m_height;
+    if (!marginInfo.canCollapseWithTop()) {
+        if (prevBlock)
+            yPosEstimate += kMax(prevBlock->collapsedMarginBottom(), child->marginTop());
+        else
+            yPosEstimate += child->marginTop();
+    }
+    return yPosEstimate;
+}
 
-        if (child->isPositioned())
-        {
-            child->containingBlock()->insertPositionedObject(child);
-            if (child->hasStaticX()) {
-                if (style()->direction() == LTR)
-                    child->setStaticX(xPos);
-                else
-                    child->setStaticX(borderRight()+paddingRight());
+void RenderBlock::determineHorizontalPosition(RenderObject* child)
+{
+    if (style()->direction() == LTR) {
+        int xPos = borderLeft() + paddingLeft();
+        
+        // Add in our left margin.
+        int chPos = xPos + child->marginLeft();
+        
+        // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats.  They need
+        // to shift over as necessary to dodge any floats that might get in the way.
+        if (child->avoidsFloats()) {
+            int leftOff = leftOffset(m_height);
+            if (style()->textAlign() != KHTML_CENTER && child->style()->marginLeft().type != Variable) {
+                if (child->marginLeft() < 0)
+                    leftOff += child->marginLeft();
+                chPos = kMax(chPos, leftOff); // Let the float sit in the child's margin if it can fit.
             }
-            if (child->hasStaticY()) {
-                int marginOffset = 0;
-                bool shouldSynthesizeCollapse = (!topMarginContributor || !canCollapseTopWithChildren);
-                if (shouldSynthesizeCollapse) {
-                    int collapsedTopPos = prevPosMargin;
-                    int collapsedTopNeg = prevNegMargin;
-                    bool posMargin = child->marginTop() >= 0;
-                    if (posMargin && child->marginTop() > collapsedTopPos)
-                        collapsedTopPos = child->marginTop();
-                    else if (!posMargin && child->marginTop() > collapsedTopNeg)
-                        collapsedTopNeg = child->marginTop();
-                    marginOffset += (collapsedTopPos - collapsedTopNeg) - child->marginTop();
-                }
-                
-                int yPosEstimate = m_height + marginOffset;
-                child->setStaticY(yPosEstimate);
+            else if (leftOff != xPos) {
+                // The object is shifting right. The object might be centered, so we need to
+                // recalculate our horizontal margins. Note that the containing block content
+                // width computation will take into account the delta between |leftOff| and |xPos|
+                // so that we can just pass the content width in directly to the |calcHorizontalMargins|
+                // function.
+                static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos()));
+                chPos = leftOff + child->marginLeft();
             }
-            child = child->nextSibling();
-            continue;
-        } else if (child->isReplaced())
-            child->layoutIfNeeded();
-        
-        if ( child->isFloating() ) {
-            insertFloatingObject( child );
-
-            // The float should be positioned taking into account the bottom margin
-            // of the previous flow.  We add that margin into the height, get the
-            // float positioned properly, and then subtract the margin out of the
-            // height again.  In the case of self-collapsing blocks, we always just
-            // use the top margins, since the self-collapsing block collapsed its
-            // own bottom margin into its top margin.
-            //
-            // Note also that the previous flow may collapse its margin into the top of
-            // our block.  If this is the case, then we do not add the margin in to our
-            // height when computing the position of the float.   This condition can be tested
-            // for by simply checking the boolean |topMarginContributor| variable.  See
-            // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
-            // an example of this scenario.
-            int marginOffset = (!topMarginContributor || !canCollapseTopWithChildren) ? (prevPosMargin - prevNegMargin) : 0;
-            
-            m_height += marginOffset;
-            positionNewFloats();
-            m_height -= marginOffset;
-
-            //kdDebug() << "RenderBlock::layoutBlockChildren inserting float at "<< m_height <<" prevMargin="<<prevMargin << endl;
-            child = child->nextSibling();
-            continue;
         }
-
-        // See if we have a compact element.  If we do, then try to tuck the compact
-        // element into the margin space of the next block.
-        // FIXME: We only deal with one compact at a time.  It is unclear what should be
-        // done if multiple contiguous compacts are encountered.  For now we assume that
-        // compact A followed by another compact B should simply be treated as block A.
-        if (child->isCompact() && !compactChild && (child->childrenInline() || child->isReplaced())) {
-            // Get the next non-positioned/non-floating RenderBlock.
-            RenderObject* next = child->nextSibling();
-            RenderObject* curr = next;
-            while (curr && curr->isFloatingOrPositioned())
-                curr = curr->nextSibling();
-            if (curr && curr->isRenderBlock() && !curr->isCompact() && !curr->isRunIn()) {
-                curr->calcWidth(); // So that horizontal margins are correct.
-                // Need to compute margins for the child as though it is a block.
-                child->style()->setDisplay(BLOCK);
-                child->calcWidth();
-                child->style()->setDisplay(COMPACT);
-                int childMargins = child->marginLeft() + child->marginRight();
-                int margin = style()->direction() == LTR ? curr->marginLeft() : curr->marginRight();
-                if (margin < (childMargins + child->maxWidth())) {
-                    // It won't fit. Kill the "compact" boolean and just treat
-                    // the child like a normal block. This is only temporary.
-                    child->style()->setDisplay(BLOCK);
-                    treatCompactAsBlock = true;
-                }
-                else {
-                    blockForCompactChild = curr;
-                    compactChild = child;
-                    child->setInline(true);
-                    child->setPos(0,0); // This position will be updated to reflect the compact's
-                                        // desired position and the line box for the compact will
-                                        // pick that position up.
-
-                    // Remove the child.
-                    RenderObject* next = child->nextSibling();
-                    removeChildNode(child);
-
-                    // Now insert the child under |curr|.
-                    curr->insertChildNode(child, curr->firstChild());
-                    child = next;
-                    continue;
-                }
+        child->setPos(chPos, child->yPos());
+    } else {
+        int xPos = m_width - borderRight() - paddingRight() - (includeScrollbarSize() ? m_layer->verticalScrollbarWidth() : 0);
+        int chPos = xPos - (child->width() + child->marginRight());
+        if (child->avoidsFloats()) {
+            int rightOff = rightOffset(m_height);
+            if (style()->textAlign() != KHTML_CENTER && child->style()->marginRight().type != Variable) {
+                if (child->marginRight() < 0)
+                    rightOff -= child->marginRight();
+                chPos = kMin(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit.
+            } else if (rightOff != xPos) {
+                // The object is shifting left. The object might be centered, so we need to
+                // recalculate our horizontal margins. Note that the containing block content
+                // width computation will take into account the delta between |rightOff| and |xPos|
+                // so that we can just pass the content width in directly to the |calcHorizontalMargins|
+                // function.
+                static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos()));
+                chPos = rightOff - child->marginRight() - child->width();
             }
         }
+        child->setPos(chPos, child->yPos());
+    }
+}
 
-        // See if we have a run-in element with inline children.  If the
-        // children aren't inline, then just treat the run-in as a normal
-        // block.
-        if (child->isRunIn() && (child->childrenInline() || child->isReplaced())) {
-            // Get the next non-positioned/non-floating RenderBlock.
-            RenderObject* curr = child->nextSibling();
-            while (curr && curr->isFloatingOrPositioned())
-                curr = curr->nextSibling();
-            if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isCompact() && !curr->isRunIn())) {
-                // The block acts like an inline, so just null out its
-                // position.
-                child->setInline(true);
-                child->setPos(0,0);
+void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
+{
+    if (marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()) {
+        // Update our max pos/neg bottom margins, since we collapsed our bottom margins
+        // with our children.
+        m_maxBottomPosMargin = kMax(m_maxBottomPosMargin, marginInfo.posMargin());
+        m_maxBottomNegMargin = kMax(m_maxBottomNegMargin, marginInfo.negMargin());
 
-                // Remove the child.
-                RenderObject* next = child->nextSibling();
-                removeChildNode(child);
+        if (!marginInfo.bottomQuirk())
+            m_bottomMarginQuirk = false;
 
-                // Now insert the child under |curr|.
-                curr->insertChildNode(child, curr->firstChild());
-                child = next;
-                continue;
-            }
-        }
-        
-        child->calcVerticalMargins();
+        if (marginInfo.bottomQuirk() && marginBottom() == 0)
+            // We have no bottom margin and our last child has a quirky margin.
+            // We will pick up this quirky margin and pass it through.
+            // This deals with the <td><div><p> case.
+            m_bottomMarginQuirk = true;
+    }
+}
 
-        // Try to guess our correct y position.  In most cases this guess will
-        // be correct.  Only if we're wrong (when we compute the real y position)
-        // will we have to relayout.
-        if (child->style()->marginTopCollapse() == MSEPARATE) {
-            topMarginContributor = false;
-            prevPosMargin = prevNegMargin = 0;
-        }
-        int yPosEstimate = m_height;
-        if (prevBlock) {
-            yPosEstimate += kMax(prevBlock->collapsedMarginBottom(), child->marginTop());
-            if (prevFlow) {
-                if (prevFlow->yPos() + prevFlow->floatBottom() > yPosEstimate)
-                    child->setChildNeedsLayout(true);
-                else
-                    prevFlow = 0;
-            }
-        }
-        else if (!canCollapseTopWithChildren || !topMarginContributor)
-            yPosEstimate += child->marginTop();
-        
-        // Note this occurs after the test for positioning and floating above, since
-        // we want to ensure that we don't artificially increase our height because of
-        // a positioned or floating child.
-        int fb = floatBottom();
-        if (child->avoidsFloats() && style()->width().isFixed() && child->minWidth() > lineWidth(m_height)) {
-            if (fb > m_height) {
+bool RenderBlock::adjustChildIfOverhangingFloatsExist(RenderObject* child, MarginInfo& marginInfo, int& yPosEstimate)
+{
+    bool shouldCollapse = true;
+    int fb = floatBottom();
+    if (fb > m_height) {
+        if (child->avoidsFloats()) {
+            if (style()->width().isFixed() && child->minWidth() > lineWidth(m_height)) {
                 m_height = yPosEstimate = fb;
-                shouldCollapseChild = false;
-                clearOccurred = true;
-                prevFlow = 0;
-                prevBlock = 0;
+                marginInfo.setAtTopOfBlock(false);
+                shouldCollapse = false;
             }
         }
-
-        // take care in case we inherited floats
-        if (fb > m_height)
+        else // If a float is going to intrude into our space then mark the child as needing layout so that lines inside the child can
+             // properly adjust to flow around the float.
             child->setChildNeedsLayout(true);
+    }
 
-        //kdDebug(0) << "margin = " << margin << " yPos = " << m_height << endl;
+    if (fb > yPosEstimate && !child->avoidsFloats())
+        child->setChildNeedsLayout(true);
+        
+    return shouldCollapse;
+}
 
-        int oldChildX = child->xPos();
-        int oldChildY = child->yPos();
+void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo)
+{
+     // If our last flow was a self-collapsing block that cleared a float, then we don't
+    // collapse it with the bottom of the block.
+    if (!marginInfo.selfCollapsingBlockClearedFloat())
+        marginInfo.setAtBottomOfBlock(true);
+
+    // If we can't collapse with children then go ahead and add in the bottom margin.
+    if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()
+        && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk()))
+        m_height += marginInfo.margin();
         
-        // Go ahead and position the child as though it didn't collapse with the top.
-        child->setPos(child->xPos(), yPosEstimate);
-        child->layoutIfNeeded();
+    // Now add in our bottom border/padding.
+    m_height += bottom;
 
-        // Now determine the correct ypos based off examination of collapsing margin
-        // values.
-        if (shouldCollapseChild) {
-            // Get our max pos and neg top margins.
-            int posTop = child->maxTopMargin(true);
-            int negTop = child->maxTopMargin(false);
-
-            // For self-collapsing blocks, collapse our bottom margins into our
-            // top to get new posTop and negTop values.
-            if (child->isSelfCollapsingBlock()) {
-                if (child->maxBottomMargin(true) > posTop)
-                    posTop = child->maxBottomMargin(true);
-                if (child->maxBottomMargin(false) > negTop)
-                    negTop = child->maxBottomMargin(false);
-            }
-            
-            // See if the top margin is quirky. We only care if this child has
-            // margins that will collapse with us.
-            bool topQuirk = child->isTopMarginQuirk() || style()->marginTopCollapse() == MDISCARD;
-
-            if (canCollapseTopWithChildren && topMarginContributor && !clearOccurred) {
-                // This child is collapsing with the top of the
-                // block.  If it has larger margin values, then we need to update
-                // our own maximal values.
-                if (strictMode || !quirkContainer || !topQuirk) {
-                    if (posTop > m_maxTopPosMargin)
-                        m_maxTopPosMargin = posTop;
-
-                    if (negTop > m_maxTopNegMargin)
-                        m_maxTopNegMargin = negTop;
-                }
+    // Negative margins can cause our height to shrink below our minimal height (border/padding).
+    // If this happens, ensure that the computed height is increased to the minimal height.
+    m_height = kMax(m_height, top + bottom);
 
-                // The minute any of the margins involved isn't a quirk, don't
-                // collapse it away, even if the margin is smaller (www.webreference.com
-                // has an example of this, a <dt> with 0.8em author-specified inside
-                // a <dl> inside a <td>.
-                if (!determinedTopQuirk && !topQuirk && (posTop-negTop)) {
-                    m_topMarginQuirk = false;
-                    determinedTopQuirk = true;
-                }
+    // Always make sure our overflow height is at least our height.
+    m_overflowHeight = kMax(m_height, m_overflowHeight);
 
-                if (!determinedTopQuirk && topQuirk && marginTop() == 0)
-                    // We have no top margin and our top child has a quirky margin.
-                    // We will pick up this quirky margin and pass it through.
-                    // This deals with the <td><div><p> case.
-                    // Don't do this for a block that split two inlines though.  You do
-                    // still apply margins in this case.
-                    m_topMarginQuirk = true;
-            }
+    // Update our bottom collapsed margin info.
+    setCollapsedBottomMargin(marginInfo);
+}
 
-            if (quirkContainer && topMarginContributor && (posTop-negTop))
-                topChildQuirk = topQuirk;
-
-            int ypos = m_height;
-            if (child->isSelfCollapsingBlock()) {
-                // This child has no height.  We need to compute our
-                // position before we collapse the child's margins together,
-                // so that we can get an accurate position for the zero-height block.
-                int collapsedTopPos = prevPosMargin;
-                int collapsedTopNeg = prevNegMargin;
-                if (child->maxTopMargin(true) > prevPosMargin)
-                    collapsedTopPos = prevPosMargin = child->maxTopMargin(true);
-                if (child->maxTopMargin(false) > prevNegMargin)
-                    collapsedTopNeg = prevNegMargin = child->maxTopMargin(false);
-
-                // Now collapse the child's margins together, which means examining our
-                // bottom margin values as well. 
-                if (child->maxBottomMargin(true) > prevPosMargin)
-                    prevPosMargin = child->maxBottomMargin(true);
-                if (child->maxBottomMargin(false) > prevNegMargin)
-                    prevNegMargin = child->maxBottomMargin(false);
-
-                if (!canCollapseTopWithChildren || !topMarginContributor)
-                    // We need to make sure that the position of the self-collapsing block
-                    // is correct, since it could have overflowing content
-                    // that needs to be positioned correctly (e.g., a block that
-                    // had a specified height of 0 but that actually had subcontent).
-                    ypos = m_height + collapsedTopPos - collapsedTopNeg;
-            }
-            else {
-                if (child->style()->marginTopCollapse() == MSEPARATE) {
-                    m_height += (prevPosMargin - prevNegMargin) + child->marginTop();
-                    ypos = m_height;
-                }
-                else if (!topMarginContributor ||
-                    (!canCollapseTopWithChildren
-                     && (strictMode || !quirkContainer || !topChildQuirk))) {
-                    // We're collapsing with a previous sibling's margins and not
-                    // with the top of the block.
-                    int absPos = prevPosMargin > posTop ? prevPosMargin : posTop;
-                    int absNeg = prevNegMargin > negTop ? prevNegMargin : negTop;
-                    int collapsedMargin = absPos - absNeg;
-                    m_height += collapsedMargin;
-                    ypos = m_height;
-                }
+void RenderBlock::layoutBlockChildren(bool relayoutChildren)
+{
+    int top = borderTop() + paddingTop();
+    int bottom = borderBottom() + paddingBottom() + (includeScrollbarSize() ? m_layer->horizontalScrollbarHeight() : 0);
 
-                prevPosMargin = child->maxBottomMargin(true);
-                prevNegMargin = child->maxBottomMargin(false);
+    m_height = m_overflowHeight = top;
 
-                if (prevPosMargin-prevNegMargin) {
-                    bottomChildQuirk = child->isBottomMarginQuirk() || style()->marginBottomCollapse() == MDISCARD;
-                }
+    // Track our previous normal flow block.
+    RenderObject* prevBlock = 0;
 
-                selfCollapsingBlockClearedFloat = false;
-            }
+    // The margin struct caches all our current margin collapsing state.  The compact struct caches state when we encounter compacts,
+    MarginInfo marginInfo(this, top, bottom);
+    CompactInfo compactInfo;
 
-            child->setPos(child->xPos(), ypos);
-            if (ypos != yPosEstimate) {
-                if (child->style()->width().isPercent() && child->usesLineWidth())
-                    // The child's width is a percentage of the line width.
-                    // When the child shifts to clear an item, its width can
-                    // change (because it has more available line width).
-                    // So go ahead and mark the item as dirty.
-                    child->setChildNeedsLayout(true);
+    // Fieldsets need to find their legend and position it inside the border of the object.
+    // The legend then gets skipped during normal layout.
+    RenderObject* legend = layoutLegend(relayoutChildren);
 
-                if (child->containsFloats() || containsFloats())
-                    child->markAllDescendantsWithFloatsForLayout();
+    RenderObject* child = firstChild();
+    while (child) {
+        if (legend == child) {
+            child = child->nextSibling();
+            continue; // Skip the legend, since it has already been positioned up in the fieldset's border.
+        }
 
-                // Our guess was wrong. Make the child lay itself out again.
-                child->layoutIfNeeded();
-            }
+        int oldTopPosMargin = m_maxTopPosMargin;
+        int oldTopNegMargin = m_maxTopNegMargin;
+
+        // Make sure we layout children if they need it.
+        // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
+        // an auto value.  Add a method to determine this, so that we can avoid the relayout.
+        if (relayoutChildren || child->style()->height().isPercent())
+            child->setChildNeedsLayout(true);
+
+        // Handle the four types of special elements first.  These include positioned content, floating content, compacts and
+        // run-ins.  When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
+        bool handled = false;
+        RenderObject* next = handleSpecialChild(child, marginInfo, compactInfo, handled);
+        if (handled) { child = next; continue; }
+
+        // The child is a normal flow object.  Compute its vertical margins now.
+        child->calcVerticalMargins();
+
+        // Do not allow a collapse if the margin top collapse style is set to SEPARATE.
+        if (child->style()->marginTopCollapse() == MSEPARATE) {
+            marginInfo.setAtTopOfBlock(false);
+            marginInfo.clearMargin();
         }
+
+        // Try to guess our correct y position.  In most cases this guess will
+        // be correct.  Only if we're wrong (when we compute the real y position)
+        // will we have to relayout.
+        int yPosEstimate = estimateVerticalPosition(child, marginInfo, prevBlock);
+        
+        // Sometimes an element will be shoved down away from a previous sibling, e.g., when
+        // clearing to pass beyond a float.  In this case, you don't need to collapse.
+        bool shouldCollapseChild = adjustChildIfOverhangingFloatsExist(child, marginInfo, yPosEstimate);
+
+        // Cache our old position so that we can dirty the proper repaint rects if the child moves.
+        int oldChildX = child->xPos();
+        int oldChildY = child->yPos();
+        
+        // Go ahead and position the child as though it didn't collapse with the top.
+        child->setPos(child->xPos(), yPosEstimate);
+        child->layoutIfNeeded();
+
+        // Now determine the correct ypos based off examination of collapsing margin
+        // values.
+        if (shouldCollapseChild)
+            collapseMargins(child, marginInfo, yPosEstimate);
         else
-            selfCollapsingBlockClearedFloat = false;
+            marginInfo.setSelfCollapsingBlockClearedFloat(false);
 
         // Now check for clear.
-        int heightIncrease = getClearDelta(child);
-        if (heightIncrease) {
-            // The child needs to be lowered.  Move the child so that it just clears the float.
-            child->setPos(child->xPos(), child->yPos()+heightIncrease);
-            clearOccurred = true;
+        clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin);
 
-            // Increase our height by the amount we had to clear.
-            if (!child->isSelfCollapsingBlock())
-                m_height += heightIncrease;
-            else {
-                // For self-collapsing blocks that clear, they may end up collapsing
-                // into the bottom of the parent block.  We simulate this behavior by
-                // setting our positive margin value to compensate for the clear.
-                prevPosMargin = QMAX(0, child->yPos() - m_height);
-                prevNegMargin = 0;
-                selfCollapsingBlockClearedFloat = true;
-            }
-            
-            if (topMarginContributor && canCollapseTopWithChildren) {
-                // We can no longer collapse with the top of the block since a clear
-                // occurred.  The empty blocks collapse into the cleared block.
-                // XXX This isn't quite correct.  Need clarification for what to do
-                // if the height the cleared block is offset by is smaller than the
-                // margins involved. -dwh
-                m_maxTopPosMargin = oldTopPosMargin;
-                m_maxTopNegMargin = oldTopNegMargin;
-                topMarginContributor = false;
-            }
-
-            // If our value of clear caused us to be repositioned vertically to be
-            // underneath a float, we might have to do another layout to take into account
-            // the extra space we now have available.
-            if (child->style()->width().isPercent() && child->usesLineWidth())
-                // The child's width is a percentage of the line width.
-                // When the child shifts to clear an item, its width can
-                // change (because it has more available line width).
-                // So go ahead and mark the item as dirty.
-                child->setChildNeedsLayout(true);
-            if (child->containsFloats())
-                child->markAllDescendantsWithFloatsForLayout();
-            child->layoutIfNeeded();
-        }
-
-        // Reset the top margin contributor to false if we encountered
-        // a non-empty child.  This has to be done after checking for clear,
-        // so that margins can be reset if a clear occurred.
-        if (topMarginContributor && !child->isSelfCollapsingBlock())
-            topMarginContributor = false;
-
-        int chPos = xPos; 
-
-        if (style()->direction() == LTR) {
-            // Add in our left margin.
-            chPos += child->marginLeft();
-            
-            // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats.  They need
-            // to shift over as necessary to dodge any floats that might get in the way.
-            if (child->avoidsFloats()) {
-                int leftOff = leftOffset(m_height);
-                if (style()->textAlign() != KHTML_CENTER && child->style()->marginLeft().type != Variable) {
-                    if (child->marginLeft() < 0)
-                        leftOff += child->marginLeft();
-                    chPos = kMax(chPos, leftOff); // Let the float sit in the child's margin if it can fit.
-                }
-                else if (leftOff != xPos) {
-                    // The object is shifting right. The object might be centered, so we need to
-                    // recalculate our horizontal margins. Note that the containing block content
-                    // width computation will take into account the delta between |leftOff| and |xPos|
-                    // so that we can just pass the content width in directly to the |calcHorizontalMargins|
-                    // function.
-                    // -dwh
-                    int cw = lineWidth( child->yPos() );
-                    static_cast<RenderBox*>(child)->calcHorizontalMargins
-                        ( child->style()->marginLeft(), child->style()->marginRight(), cw);
-                    chPos = leftOff + child->marginLeft();
-                }
-            }
-        } else {
-            chPos -= child->width() + child->marginRight();
-            if (child->avoidsFloats()) {
-                int rightOff = rightOffset(m_height);
-                if (style()->textAlign() != KHTML_CENTER && child->style()->marginRight().type != Variable) {
-                    if (child->marginRight() < 0)
-                        rightOff -= child->marginRight();
-                    chPos = kMin(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit.
-                } else if (rightOff != xPos) {
-                    // The object is shifting left. The object might be centered, so we need to
-                    // recalculate our horizontal margins. Note that the containing block content
-                    // width computation will take into account the delta between |rightOff| and |xPos|
-                    // so that we can just pass the content width in directly to the |calcHorizontalMargins|
-                    // function.
-                    // -dwh
-                    int cw = lineWidth( child->yPos() );
-                    static_cast<RenderBox*>(child)->calcHorizontalMargins
-                        ( child->style()->marginLeft(), child->style()->marginRight(), cw);
-                    chPos = rightOff - child->marginRight() - child->width();
-                }
-            }
-        }
+        // We are no longer at the top of the block if we encounter a non-empty child.  
+        // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
+        if (marginInfo.atTopOfBlock() && !child->isSelfCollapsingBlock())
+            marginInfo.setAtTopOfBlock(false);
 
-        child->setPos(chPos, child->yPos());
+        // Now place the child in the correct horizontal position
+        determineHorizontalPosition(child);
 
+        // Update our height now that the child has been placed in the correct position.
         m_height += child->height();
-        
         if (child->style()->marginBottomCollapse() == MSEPARATE) {
             m_height += child->marginBottom();
-            prevPosMargin = prevNegMargin = 0;
+            marginInfo.clearMargin();
         }
-        
         int overflowDelta = child->overflowHeight(false) - child->height();
         if (m_height + overflowDelta > m_overflowHeight)
             m_overflowHeight = m_height + overflowDelta;
 
+        // Track the previous block so that we can check its collapsed bottom margin in the next loop iteration.
         prevBlock = child;
-        if (child->isRenderBlock() && !child->avoidsFloats())
-            prevFlow = static_cast<RenderBlock*>(child);
 
-        if (child->hasOverhangingFloats() && !child->hasOverflowClip()) {
+        if (child->hasOverhangingFloats() && !child->hasOverflowClip())
             // need to add the child's floats to our floating objects list, but not in the case where
             // overflow is auto/scroll
-            addOverHangingFloats( static_cast<RenderBlock *>(child), -child->xPos(), -child->yPos(), true );
-        }
+            addOverHangingFloats(static_cast<RenderBlock *>(child), -child->xPos(), -child->yPos(), true);
 
         // See if this child has made our overflow need to grow.
-        // XXXdwh Work with left overflow as well as right overflow.
-        int rightChildPos = child->xPos() + QMAX(child->overflowWidth(false), child->width());
+        // FIXME: Work with left overflow as well as right overflow.
+        int rightChildPos = child->xPos() + kMax(child->overflowWidth(false), child->width());
         if (rightChildPos > m_overflowWidth)
             m_overflowWidth = rightChildPos;
 
-        if (child == blockForCompactChild) {
-            blockForCompactChild = 0;
-            if (compactChild) {
-                // We have a compact child to squeeze in.
-                int compactXPos = xPos+compactChild->marginLeft();
-                if (style()->direction() == RTL) {
-                    compactChild->calcWidth(); // have to do this because of the capped maxwidth
-                    compactXPos = width() - borderRight() - paddingRight() - marginRight() -
-                        compactChild->width() - compactChild->marginRight();
-                }
-                compactXPos -= child->xPos(); // Put compactXPos into the child's coordinate space.
-                compactChild->setPos(compactXPos, compactChild->yPos()); // Set the x position.
-                compactChild = 0;
-            }
-        }
-
-        // We did a layout as though the compact child was a block.  Set it back to compact now.
-        if (treatCompactAsBlock) {
-            child->style()->setDisplay(COMPACT);
-            treatCompactAsBlock = false;
-        }
+        // Insert our compact into the block margin if we have one.
+        insertCompactIfNeeded(child, compactInfo);
 
         // If the child moved, we have to repaint it as well as any floating/positioned
         // descendants.  An exception is if we need a layout.  In this case, we know we're going to
         // repaint ourselves (and the child) anyway.
         if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
             child->repaintDuringLayoutIfMoved(oldChildX, oldChildY);
-        
+
         child = child->nextSibling();
     }
 
-    // If our last flow was a self-collapsing block that cleared a float, then we don't
-    // collapse it with the bottom of the block.
-    if (selfCollapsingBlockClearedFloat)
-        canCollapseBottomWithChildren = false;
-    
-    // If we can't collapse with children then go ahead and add in the bottom margins.
-    if (!canCollapseBottomWithChildren && (!topMarginContributor || !canCollapseTopWithChildren)
-        && (strictMode || !quirkContainer || !bottomChildQuirk))
-        m_height += prevPosMargin - prevNegMargin;
-
-    m_height += toAdd;
-
-    // Negative margins can cause our height to shrink below our minimal height (border/padding).
-    // If this happens, ensure that the computed height is increased to the minimal height.
-    if (m_height < minHeight)
-        m_height = minHeight;
-
-    // Always make sure our overflowheight is at least our height.
-    if (m_overflowHeight < m_height)
-        m_overflowHeight = m_height;
-
-    if (canCollapseBottomWithChildren && (!topMarginContributor || !canCollapseTopWithChildren)) {
-        // Update our max pos/neg bottom margins, since we collapsed our bottom margins
-        // with our children.
-        if (prevPosMargin > m_maxBottomPosMargin)
-            m_maxBottomPosMargin = prevPosMargin;
-
-        if (prevNegMargin > m_maxBottomNegMargin)
-            m_maxBottomNegMargin = prevNegMargin;
-
-        if (!bottomChildQuirk)
-            m_bottomMarginQuirk = false;
-
-        if (bottomChildQuirk && marginBottom() == 0)
-            // We have no bottom margin and our last child has a quirky margin.
-            // We will pick up this quirky margin and pass it through.
-            // This deals with the <td><div><p> case.
-            m_bottomMarginQuirk = true;
-    }
+    // Now do the handling of the bottom of the block, adding in our bottom border/padding and
+    // determining the correct collapsed bottom margin information.
+    handleBottomOfBlock(top, bottom, marginInfo);
 
+    // Finished. Clear the dirty layout bits.
     setNeedsLayout(false);
-
-    // kdDebug( 6040 ) << "needsLayout = " << needsLayout_ << endl;
 }
 
 void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
@@ -1160,7 +1143,7 @@ void RenderBlock::getAbsoluteRepaintRectIncludingFloats(QRect& bounds, QRect& fu
     // Include any overhanging floats (if we know we're the one to paint them).
     // We null-check m_floatingObjects here to catch any cases where m_height ends up negative
     // for some reason.  I think I've caught all those cases, but this way we stay robust and don't
-    // crash. -dwh
+    // crash.
     if (hasOverhangingFloats() && m_floatingObjects) {
         FloatingObject* r;
         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
@@ -2249,7 +2232,7 @@ void RenderBlock::addOverHangingFloats( RenderBlock *flow, int xoff, int offset,
                 // since his own margin was added already through the subtraction of the |xoff| variable
                 // above.  |xoff| will equal -flow->marginLeft() in this case, so it's already been taken
                 // into account.  Only apply this code if |child| is false, since otherwise the left margin
-                // will get applied twice. -dwh
+                // will get applied twice.
                 if (!child && flow != parent())
                     floatingObj->left += flow->marginLeft();
                 if ( !child ) {
index 236d4e1d4b69efe0a6c367478dd2fb3dd18fea40..a01cc7c25f8e8349c57aacf0a3b97bb09240816a 100644 (file)
@@ -70,13 +70,13 @@ public:
     virtual bool isTopMarginQuirk() const { return m_topMarginQuirk; }
     virtual bool isBottomMarginQuirk() const { return m_bottomMarginQuirk; }
 
-    virtual short maxTopMargin(bool positive) const {
+    virtual int maxTopMargin(bool positive) const {
         if (positive)
             return m_maxTopPosMargin;
         else
             return m_maxTopNegMargin;
     }
-    virtual short maxBottomMargin(bool positive) const {
+    virtual int maxBottomMargin(bool positive) const {
         if (positive)
             return m_maxBottomPosMargin;
         else
@@ -287,24 +287,125 @@ protected:
         bool noPaint : 1;
     };
     
+    // The following helper functions and structs are used by layoutBlockChildren.
+    class CompactInfo {
+        // A compact child that needs to be collapsed into the margin of the following block.
+        RenderObject* m_compact;
+        
+        // The block with the open margin that the compact child is going to place itself within.
+        RenderObject* m_block;
+
+    public:
+        RenderObject* compact() const { return m_compact; }
+        RenderObject* block() const { return m_block; }
+        bool matches(RenderObject* child) const { return m_compact && m_block == child; }
+        
+        void clear() { set(0, 0);  }
+        void set(RenderObject* c, RenderObject* b) { m_compact = c; m_block = b; }
+        
+        CompactInfo() { clear(); }
+    };
+
+    class MarginInfo {
+        // Collapsing flags for whether we can collapse our margins with our children's margins.
+        bool m_canCollapseWithChildren : 1;
+        bool m_canCollapseTopWithChildren : 1;
+        bool m_canCollapseBottomWithChildren : 1;
+        
+        // Whether or not we are a quirky container, i.e., do we collapse away top and bottom
+        // margins in our container.  Table cells and the body are the common examples. We
+        // also have a custom style property for Safari RSS to deal with TypePad blog articles.
+        bool m_quirkContainer : 1;
+
+        // This flag tracks whether we are still looking at child margins that can all collapse together at the beginning of a block.  
+        // They may or may not collapse with the top margin of the block (|m_canCollapseTopWithChildren| tells us that), but they will
+        // always be collapsing with one another.  This variable can remain set to true through multiple iterations 
+        // as long as we keep encountering self-collapsing blocks.
+        bool m_atTopOfBlock : 1;
+
+        // This flag is set when we know we're examining bottom margins and we know we're at the bottom of the block.
+        bool m_atBottomOfBlock : 1;
+
+        // If our last normal flow child was a self-collapsing block that cleared a float,
+        // we track it in this variable.
+        bool m_selfCollapsingBlockClearedFloat : 1;
+    
+        // These variables are used to detect quirky margins that we need to collapse away (in table cells
+        // and in the body element).
+        bool m_topQuirk : 1;
+        bool m_bottomQuirk : 1;
+        bool m_determinedTopQuirk : 1;
+
+        // These flags track the previous maximal positive and negative margins.
+        int m_posMargin;
+        int m_negMargin;
+
+    public:
+        MarginInfo(RenderBlock* b, int top, int bottom);
+        
+        void setAtTopOfBlock(bool b) { m_atTopOfBlock = b; }
+        void setAtBottomOfBlock(bool b) { m_atBottomOfBlock = b; }
+        void clearMargin() { m_posMargin = m_negMargin = 0; }
+        void setSelfCollapsingBlockClearedFloat(bool b) { m_selfCollapsingBlockClearedFloat = false; }
+        void setTopQuirk(bool b) { m_topQuirk = b; }
+        void setBottomQuirk(bool b) { m_bottomQuirk = b; }
+        void setDeterminedTopQuirk(bool b) { m_determinedTopQuirk = b; }
+        void setPosMargin(int p) { m_posMargin = p; }
+        void setNegMargin(int n) { m_negMargin = n; }
+        void setPosMarginIfLarger(int p) { if (p > m_posMargin) m_posMargin = p; }
+        void setNegMarginIfLarger(int n) { if (n > m_negMargin) m_negMargin = n; }
+
+        void setMargin(int p, int n) { m_posMargin = p; m_negMargin = n; }
+
+        bool atTopOfBlock() const { return m_atTopOfBlock; }
+        bool canCollapseWithTop() const { return m_atTopOfBlock && m_canCollapseTopWithChildren; }
+        bool canCollapseWithBottom() const { return m_atBottomOfBlock && m_canCollapseBottomWithChildren; }
+        bool canCollapseTopWithChildren() const { return m_canCollapseTopWithChildren; }
+        bool canCollapseBottomWithChildren() const { return m_canCollapseBottomWithChildren; }
+        bool selfCollapsingBlockClearedFloat() const { return m_selfCollapsingBlockClearedFloat; }
+        bool quirkContainer() const { return m_quirkContainer; }
+        bool determinedTopQuirk() const { return m_determinedTopQuirk; }
+        bool topQuirk() const { return m_topQuirk; }
+        bool bottomQuirk() const { return m_bottomQuirk; }
+        int posMargin() const { return m_posMargin; }
+        int negMargin() const { return m_negMargin; }
+        int margin() const { return m_posMargin - m_negMargin; }
+    };
+    
+    void adjustPositionedBlock(RenderObject* child, const MarginInfo& marginInfo);
+    void adjustFloatingBlock(const MarginInfo& marginInfo);
+    RenderObject* handleSpecialChild(RenderObject* child, const MarginInfo& marginInfo, CompactInfo& compactInfo, bool& handled);
+    RenderObject* handleFloatingOrPositionedChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled);
+    RenderObject* handleCompactChild(RenderObject* child, CompactInfo& compactInfo, bool& handled);
+    RenderObject* handleRunInChild(RenderObject* child, bool& handled);
+    void collapseMargins(RenderObject* child, MarginInfo& marginInfo, int yPosEstimate);
+    void clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin);
+    void insertCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo);
+    int estimateVerticalPosition(RenderObject* child, const MarginInfo& info, RenderObject* prevBlock);
+    void determineHorizontalPosition(RenderObject* child);
+    void handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo);
+    void setCollapsedBottomMargin(const MarginInfo& marginInfo);
+    bool adjustChildIfOverhangingFloatsExist(RenderObject* child, MarginInfo& marginInfo, int& yPosEstimate);
+    // End helper functions and structs used by layoutBlockChildren.
+
 protected:
     QPtrList<FloatingObject>* m_floatingObjects;
     QPtrList<RenderObject>* m_positionedObjects;
     
     bool m_childrenInline : 1;
     bool m_pre            : 1;
-    bool m_firstLine      : 1; // used in inline layouting
-    EClear m_clearStatus  : 2; // used during layuting of paragraphs
+    bool m_firstLine      : 1;
+    EClear m_clearStatus  : 2;
     bool m_topMarginQuirk : 1;
     bool m_bottomMarginQuirk : 1;
     bool m_linesAppended : 1; // Whether or not a block with inline children has had lines appended.
     bool m_hasMarkupTruncation : 1;
     SelectionState m_selectionState : 3;
 
-    short m_maxTopPosMargin;
-    short m_maxTopNegMargin;
-    short m_maxBottomPosMargin;
-    short m_maxBottomNegMargin;
+    int m_maxTopPosMargin;
+    int m_maxTopNegMargin;
+    int m_maxBottomPosMargin;
+    int m_maxBottomNegMargin;
 
     // How much content overflows out of our block vertically or horizontally (all we support
     // for now is spillage out of the bottom and the right, which are the common cases).
index fe2bdf91f9935e8f5e4e7dbd7f91a9a7a0629670..63ec06aa4c913fe4bb882d9023aacb7ebb1054d3 100644 (file)
@@ -1346,10 +1346,8 @@ void RenderBox::calcAbsoluteVertical()
 
     // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
     RenderObject* cb = container();
-    Length hl = cb->style()->height();
-    if (hl.isFixed())
-        ch = hl.value + cb->paddingTop() + cb->paddingBottom();
-    else if (cb->isRoot())
+    if (cb->isRoot()) // Even in strict mode (where we don't grow the root to fill the viewport) other browsers
+                      // position as though the root fills the viewport.
         ch = cb->availableHeight();
     else
         ch = cb->height() - cb->borderTop() - cb->borderBottom();
index 69f035aad355c2b167ca6b8a8539ec81ca5eabae..70115778c52f1b75baab8cf1fcba0aca50d6b587 100644 (file)
@@ -72,10 +72,10 @@ public:
     virtual int width() const;
     virtual int height() const;
 
-    virtual short marginTop() const { return m_marginTop; }
-    virtual short marginBottom() const { return m_marginBottom; }
-    virtual short marginLeft() const { return m_marginLeft; }
-    virtual short marginRight() const { return m_marginRight; }
+    virtual int marginTop() const { return m_marginTop; }
+    virtual int marginBottom() const { return m_marginBottom; }
+    virtual int marginLeft() const { return m_marginLeft; }
+    virtual int marginRight() const { return m_marginRight; }
 
     virtual void setWidth( int width ) { m_width = width; }
     virtual void setHeight( int height ) { m_height = height; }
@@ -163,11 +163,11 @@ protected:
     int m_x;
     int m_width;
 
-    short m_marginTop;
-    short m_marginBottom;
+    int m_marginTop;
+    int m_marginBottom;
 
-    short m_marginLeft;
-    short m_marginRight;
+    int m_marginLeft;
+    int m_marginRight;
 
     /*
      * the minimum width the element needs, to be able to render
index dbe2a320cdb8c0a6deda454c2fbb6fc2615c696a..059bec1c879559544bbb97d414abd8055c1f9a98 100644 (file)
@@ -86,11 +86,15 @@ void RenderImage::setContentObject(CachedObject* co)
 
 void RenderImage::setImage(CachedImage* newImage)
 {
-    if (image)
-        image->deref(this);
-    image = newImage;
-    if (image)
-        image->ref(this);
+    if (image != newImage) {
+        if (image)
+            image->deref(this);
+        image = newImage;
+        if (image)
+            image->ref(this);
+        if (image->isErrorImage())
+            setPixmap(image->pixmap(), QRect(0,0,16,16), image);
+    }
 }
 
 void RenderImage::setPixmap( const QPixmap &p, const QRect& r, CachedImage *o)
index ec1da91a2a12afa5637426ee9e12891d4a381860..0fb4b0acfbfacdcccf2cd655efc1c293c6d6c56d 100644 (file)
@@ -735,7 +735,7 @@ bool RenderObject::sizesToMaxWidth() const
 {
     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
     // but they allow text to sit on the same line as the marquee.
-    if (isFloating() || isCompact() || 
+    if (isFloating() || (isCompact() && isInline()) || 
         (isInlineBlockOrInlineTable() && !isHTMLMarquee()) ||
         (element() && (element()->id() == ID_BUTTON || element()->id() == ID_LEGEND)))
         return true;
index 68793da68ad91708bf22a889e027e481367da639..5a378bc4a440b0920c5608b3595f315915208eb2 100644 (file)
@@ -590,13 +590,13 @@ public:
     // the margin of the element.  Blocks override the maxTopMargin and maxBottomMargin
     // methods.
     virtual bool isSelfCollapsingBlock() const { return false; }
-    virtual short collapsedMarginTop() const 
+    virtual int collapsedMarginTop() const 
         { return maxTopMargin(true)-maxTopMargin(false); }
-    virtual short collapsedMarginBottom() const 
+    virtual int collapsedMarginBottom() const 
         { return maxBottomMargin(true)-maxBottomMargin(false); }
     virtual bool isTopMarginQuirk() const { return false; }
     virtual bool isBottomMarginQuirk() const { return false; }
-    virtual short maxTopMargin(bool positive) const {
+    virtual int maxTopMargin(bool positive) const {
         if (positive)
             if (marginTop() > 0)
                 return marginTop();
@@ -608,7 +608,7 @@ public:
             else
                 return 0;
     }
-    virtual short maxBottomMargin(bool positive) const {
+    virtual int maxBottomMargin(bool positive) const {
         if (positive)
             if (marginBottom() > 0)
                 return marginBottom();
@@ -621,10 +621,10 @@ public:
                 return 0;
     }
 
-    virtual short marginTop() const { return 0; }
-    virtual short marginBottom() const { return 0; }
-    virtual short marginLeft() const { return 0; }
-    virtual short marginRight() const { return 0; }
+    virtual int marginTop() const { return 0; }
+    virtual int marginBottom() const { return 0; }
+    virtual int marginLeft() const { return 0; }
+    virtual int marginRight() const { return 0; }
 
     // Virtual since table cells override 
     virtual int paddingTop() const;
index 0bc145a23798217758b8080596d533ea1e5f9f85..61b6a7e6aed1d54c067a072505767a8d452b15b8 100644 (file)
@@ -228,8 +228,8 @@ public:
     virtual QRect caretRect(int offset, EAffinity affinity);
     void posOfChar(int ch, int &x, int &y);
 
-    virtual short marginLeft() const { return style()->marginLeft().minWidth(0); }
-    virtual short marginRight() const { return style()->marginRight().minWidth(0); }
+    virtual int marginLeft() const { return style()->marginLeft().minWidth(0); }
+    virtual int marginRight() const { return style()->marginRight().minWidth(0); }
 
     virtual QRect getAbsoluteRepaintRect();
 
index 70044f3e7e3b3135f43a0df944a12b84577a0466..67fb2a4fcbd834b298a5f1362f46cc24741c0d66 100644 (file)
@@ -462,14 +462,13 @@ void ElementImpl::recalcStyle( StyleChange change )
                 m_render->setStyle(newStyle);
             }
         }
-        /* FIXME: Back this out for now.
-        else if (m_render && newStyle && (getDocument()->usesSiblingRules() || getDocument()->usesDescendantRules())) {
+        else if (changed() && m_render && newStyle && (getDocument()->usesSiblingRules() || getDocument()->usesDescendantRules())) {
             // Although no change occurred, we use the new style so that the cousin style sharing code won't get
             // fooled into believing this style is the same.  This is only necessary if the document actually uses
             // sibling/descendant rules, since otherwise it isn't possible for ancestor styles to affect sharing of
             // descendants.
             m_render->setStyleInternal(newStyle);
-        }*/
+        }
 
         newStyle->deref(getDocument()->renderArena());