1d943ac11832b463f374bf75e67ccf5e53c5415c
[WebKit-https.git] / WebCore / khtml / rendering / render_block.cpp
1 /*
2  * This file is part of the render object implementation for KHTML.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  * Copyright (C) 2003 Apple Computer, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  */
24
25 //#define DEBUG
26 //#define DEBUG_LAYOUT
27 //#define BOX_DEBUG
28 //#define FLOAT_DEBUG
29
30 #include <kdebug.h>
31 #include "rendering/render_text.h"
32 #include "rendering/render_table.h"
33 #include "rendering/render_canvas.h"
34 #include "xml/dom_nodeimpl.h"
35 #include "xml/dom_docimpl.h"
36 #include "html/html_formimpl.h"
37 #include "render_block.h"
38
39 #include "khtmlview.h"
40 #include "htmltags.h"
41
42 using namespace DOM;
43
44 namespace khtml {
45
46 RenderBlock::RenderBlock(DOM::NodeImpl* node)
47 :RenderFlow(node)
48 {
49     m_childrenInline = true;
50     m_floatingObjects = 0;
51     m_positionedObjects = 0;
52     m_pre = false;
53     m_firstLine = false;
54     m_clearStatus = CNONE;
55     m_maxTopPosMargin = m_maxTopNegMargin = m_maxBottomPosMargin = m_maxBottomNegMargin = 0;
56     m_topMarginQuirk = m_bottomMarginQuirk = false;
57     m_overflowHeight = 0;
58     m_overflowWidth = 0;
59 }
60
61 RenderBlock::~RenderBlock()
62 {
63     delete m_floatingObjects;
64     delete m_positionedObjects;
65 }
66
67 void RenderBlock::setStyle(RenderStyle* _style)
68 {
69     RenderFlow::setStyle(_style);
70     setReplaced(style()->display()==INLINE_BLOCK);
71     
72     m_pre = false;
73     if (_style->whiteSpace() == PRE)
74         m_pre = true;
75
76     // ### we could save this call when the change only affected
77     // non inherited properties
78     RenderObject *child = firstChild();
79     while (child != 0)
80     {
81         if (child->isAnonymousBox())
82         {
83             RenderStyle* newStyle = new RenderStyle();
84             newStyle->inheritFrom(style());
85             newStyle->setDisplay(BLOCK);
86             child->setStyle(newStyle);
87             child->setIsAnonymousBox(true);
88         }
89         child = child->nextSibling();
90     }
91
92     // Update pseudos for :before and :after now.
93     updatePseudoChild(RenderStyle::BEFORE, firstChild());
94     updatePseudoChild(RenderStyle::AFTER, lastChild());
95 }
96
97 void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild)
98 {
99     // Make sure we don't append things after :after-generated content if we have it.
100     if (!beforeChild && lastChild() && lastChild()->style()->styleType() == RenderStyle::AFTER)
101         beforeChild = lastChild();
102     
103     bool madeBoxesNonInline = FALSE;
104
105     RenderStyle* pseudoStyle=0;
106     if ((!firstChild() || firstChild() == beforeChild) &&
107          (newChild->isInline() || newChild->isText()) &&
108          (pseudoStyle=style()->getPseudoStyle(RenderStyle::FIRST_LETTER)))
109     {
110         // Drill into inlines looking for our first text child.
111         RenderObject* textChild = newChild;
112         while (textChild && !(textChild->isText() && !textChild->isBR()))
113             textChild = textChild->firstChild();
114         
115         if (textChild) {
116             RenderObject* firstLetterContainer = textChild->parent();
117             if (!firstLetterContainer)
118                 firstLetterContainer = this;
119             
120             RenderText* newTextChild = static_cast<RenderText*>(textChild);
121         //kdDebug( 6040 ) << "first letter" << endl;
122
123             // Force inline display (except for floating first-letters)
124             pseudoStyle->setDisplay( pseudoStyle->isFloating() ? BLOCK : INLINE);
125             pseudoStyle->setPosition( STATIC ); // CSS2 says first-letter can't be positioned.
126             
127             RenderObject* firstLetter = RenderFlow::createFlow(0, pseudoStyle, renderArena()); // anonymous box
128             firstLetterContainer->addChild(firstLetter, firstLetterContainer->firstChild());
129
130             DOMStringImpl* oldText = newTextChild->string();
131
132             if(oldText->l >= 1) {
133                 unsigned int length = 0;
134                 while ( length < oldText->l &&
135                         ( (oldText->s+length)->isSpace() || (oldText->s+length)->isPunct() ) )
136                     length++;
137                 length++;
138                 //kdDebug( 6040 ) << "letter= '" << DOMString(oldText->substring(0,length)).string() << "'" << endl;
139                 newTextChild->setText(oldText->substring(length,oldText->l-length));
140
141                 RenderText* letter = new (renderArena()) RenderText(newTextChild->element(), oldText->substring(0,length));
142                 RenderStyle* newStyle = new RenderStyle();
143                 newStyle->inheritFrom(pseudoStyle);
144                 letter->setStyle(newStyle);
145                 firstLetter->addChild(letter);
146             }
147             firstLetter->close();
148         }
149     }
150
151     // If the requested beforeChild is not one of our children, then this is most likely because
152     // there is an anonymous block box within this object that contains the beforeChild. So
153     // just insert the child into the anonymous block box instead of here.
154     if (beforeChild && beforeChild->parent() != this) {
155
156         KHTMLAssert(beforeChild->parent());
157         KHTMLAssert(beforeChild->parent()->isAnonymousBox());
158
159         if (newChild->isInline()) {
160             beforeChild->parent()->addChild(newChild,beforeChild);
161             newChild->setNeedsLayoutAndMinMaxRecalc();
162             return;
163         }
164         else if (beforeChild->parent()->firstChild() != beforeChild)
165             return beforeChild->parent()->addChild(newChild, beforeChild);
166         else
167             return addChildToFlow(newChild, beforeChild->parent());
168     }
169
170     // prevent elements that haven't received a layout yet from getting painted by pushing
171     // them far above the top of the page
172     if (!newChild->isInline())
173         newChild->setPos(newChild->xPos(), -500000);
174
175     if (!newChild->isText() && newChild->style()->position() != STATIC)
176         setOverhangingContents();
177
178     // A block has to either have all of its children inline, or all of its children as blocks.
179     // So, if our children are currently inline and a block child has to be inserted, we move all our
180     // inline children into anonymous block boxes
181     if ( m_childrenInline && !newChild->isInline() && !newChild->isFloatingOrPositioned() )
182     {
183         // This is a block with inline content. Wrap the inline content in anonymous blocks.
184         makeChildrenNonInline(beforeChild);
185         madeBoxesNonInline = true;
186         
187         if (beforeChild && beforeChild->parent() != this) {
188             beforeChild = beforeChild->parent();
189             KHTMLAssert(beforeChild->isAnonymousBox());
190             KHTMLAssert(beforeChild->parent() == this);
191         }
192     }
193     else if (!m_childrenInline && !newChild->isFloatingOrPositioned())
194     {
195         // If we're inserting an inline child but all of our children are blocks, then we have to make sure
196         // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
197         // a new one is created and inserted into our list of children in the appropriate position.
198         if (newChild->isInline()) {
199             if (beforeChild) {
200                 if (beforeChild->previousSibling() && beforeChild->previousSibling()->isAnonymousBox()) {
201                     beforeChild->previousSibling()->addChild(newChild);
202                     newChild->setNeedsLayoutAndMinMaxRecalc();
203                     return;
204                 }
205             }
206             else {
207                 if (m_last && m_last->isAnonymousBox()) {
208                     m_last->addChild(newChild);
209                     newChild->setNeedsLayoutAndMinMaxRecalc();
210                     return;
211                 }
212             }
213
214             // no suitable existing anonymous box - create a new one
215             RenderBlock* newBox = createAnonymousBlock();
216             RenderBox::addChild(newBox,beforeChild);
217             newBox->addChild(newChild);
218             newBox->setPos(newBox->xPos(), -500000);
219             newChild->setNeedsLayoutAndMinMaxRecalc();
220             return;
221         }
222         else {
223             // We are adding another block child... if the current last child is an anonymous box
224             // then it needs to be closed.
225             // ### get rid of the closing thing altogether this will only work during initial parsing
226             if (lastChild() && lastChild()->isAnonymousBox()) {
227                 lastChild()->close();
228             }
229         }
230     }
231
232     RenderBox::addChild(newChild,beforeChild);
233     // ### care about aligned stuff
234
235     newChild->setNeedsLayoutAndMinMaxRecalc();
236     
237     if ( madeBoxesNonInline )
238         removeLeftoverAnonymousBoxes();
239 }
240
241 static void getInlineRun(RenderObject* start, RenderObject* stop,
242                          RenderObject*& inlineRunStart,
243                          RenderObject*& inlineRunEnd)
244 {
245     // Beginning at |start| we find the largest contiguous run of inlines that
246     // we can.  We denote the run with start and end points, |inlineRunStart|
247     // and |inlineRunEnd|.  Note that these two values may be the same if
248     // we encounter only one inline.
249     //
250     // We skip any non-inlines we encounter as long as we haven't found any
251     // inlines yet.
252     //
253     // |stop| indicates a non-inclusive stop point.  Regardless of whether |stop|
254     // is inline or not, we will not include it.  It's as though we encountered
255     // a non-inline.
256     inlineRunStart = inlineRunEnd = 0;
257
258     // Start by skipping as many non-inlines as we can.
259     RenderObject * curr = start;
260     while (curr && !curr->isInline())
261         curr = curr->nextSibling();
262
263     if (!curr)
264         return; // No more inline children to be found.
265
266     inlineRunStart = inlineRunEnd = curr;
267
268     curr = curr->nextSibling();
269     while (curr && curr->isInline() && (curr != stop)) {
270         inlineRunEnd = curr;
271         curr = curr->nextSibling();
272     }
273 }
274
275 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
276 {
277     // makeChildrenNonInline takes a block whose children are *all* inline and it
278     // makes sure that inline children are coalesced under anonymous
279     // blocks.  If |insertionPoint| is defined, then it represents the insertion point for
280     // the new block child that is causing us to have to wrap all the inlines.  This
281     // means that we cannot coalesce inlines before |insertionPoint| with inlines following
282     // |insertionPoint|, because the new child is going to be inserted in between the inlines,
283     // splitting them.
284     KHTMLAssert(isInlineBlockOrInlineTable() || !isInline());
285     KHTMLAssert(!insertionPoint || insertionPoint->parent() == this);
286
287     m_childrenInline = false;
288
289     RenderObject *child = firstChild();
290
291     while (child) {
292         RenderObject *inlineRunStart, *inlineRunEnd;
293         getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
294
295         if (!inlineRunStart)
296             break;
297
298         child = inlineRunEnd->nextSibling();
299
300         RenderBlock* box = createAnonymousBlock();
301         insertChildNode(box, inlineRunStart);
302         RenderObject* o = inlineRunStart;
303         while(o != inlineRunEnd)
304         {
305             RenderObject* no = o;
306             o = no->nextSibling();
307             box->appendChildNode(removeChildNode(no));
308         }
309         box->appendChildNode(removeChildNode(inlineRunEnd));
310         box->close();
311         box->setPos(box->xPos(), -500000);
312     }
313 }
314
315 void RenderBlock::removeChild(RenderObject *oldChild)
316 {
317     // If this child is a block, and if our previous and next siblings are
318     // both anonymous blocks with inline content, then we can go ahead and
319     // fold the inline content back together.
320     RenderObject* prev = oldChild->previousSibling();
321     RenderObject* next = oldChild->nextSibling();
322     bool mergedBlocks = false;
323     if (!isInline() && !oldChild->isInline() && !oldChild->continuation() &&
324         prev && prev->isAnonymousBox() && prev->childrenInline() &&
325         next && next->isAnonymousBox() && next->childrenInline()) {
326         // Take all the children out of the |next| block and put them in
327         // the |prev| block.
328         RenderObject* o = next->firstChild();
329         while (o) {
330             RenderObject* no = o;
331             o = no->nextSibling();
332             prev->appendChildNode(next->removeChildNode(no));
333             no->setNeedsLayoutAndMinMaxRecalc();
334         }
335         prev->setNeedsLayoutAndMinMaxRecalc();
336
337         // Nuke the now-empty block.
338         next->detach(renderArena());
339
340         mergedBlocks = true;
341     }
342
343     RenderFlow::removeChild(oldChild);
344
345     if (mergedBlocks && prev && !prev->previousSibling() && !prev->nextSibling()) {
346         // The remerge has knocked us down to containing only a single anonymous
347         // box.  We can go ahead and pull the content right back up into our
348         // box.
349         RenderObject* anonBlock = removeChildNode(prev);
350         m_childrenInline = true;
351         RenderObject* o = anonBlock->firstChild();
352         while (o) {
353             RenderObject* no = o;
354             o = no->nextSibling();
355             appendChildNode(anonBlock->removeChildNode(no));
356             no->setNeedsLayoutAndMinMaxRecalc();
357         }
358         
359         // Nuke the now-empty block.
360         anonBlock->detach(renderArena());
361     }
362 }
363
364 bool RenderBlock::requiresLayer() {
365     // FIXME: The bogus table cell check is only here until we figure out how to position
366     // table cells properly when they have layers.
367     // Note that we also restrict overflow to blocks for now.
368     return !isTableCell() && (RenderObject::requiresLayer() || (style()->hidesOverflow() && !isBody()));
369 }
370
371 bool RenderBlock::isSelfCollapsingBlock() const
372 {
373     // We are not self-collapsing if we
374     // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
375     // (b) are a table,
376     // (c) have border/padding,
377     // (d) have a min-height
378     if (m_height > 0 ||
379         isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 ||
380         style()->minHeight().value > 0)
381         return false;
382
383     // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
384     // on whether we have content that is all self-collapsing or not.
385     if (style()->height().isVariable() ||
386         (style()->height().isFixed() && style()->height().value == 0)) {
387         // If the block has inline children, see if we generated any line boxes.  If we have any
388         // line boxes, then we can't be self-collapsing, since we have content.
389         if (childrenInline())
390             return !firstLineBox();
391         
392         // Whether or not we collapse is dependent on whether all our normal flow children
393         // are also self-collapsing.
394         for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
395             if (child->isFloatingOrPositioned())
396                 continue;
397             if (!child->isSelfCollapsingBlock())
398                 return false;
399         }
400         return true;
401     }
402     return false;
403 }
404
405 void RenderBlock::layout()
406 {
407     // Table cells call layoutBlock directly, so don't add any logic here.  Put code into
408     // layoutBlock().
409     layoutBlock(false);
410 }
411
412 void RenderBlock::layoutBlock(bool relayoutChildren)
413 {
414     //    kdDebug( 6040 ) << renderName() << " " << this << "::layoutBlock() start" << endl;
415     //     QTime t;
416     //     t.start();
417     KHTMLAssert( needsLayout() );
418     KHTMLAssert( minMaxKnown() );
419
420     if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
421         return;                                      // cause us to come in here.  Just bail. -dwh
422
423     if (!relayoutChildren && posChildNeedsLayout() && !normalChildNeedsLayout() && !selfNeedsLayout()) {
424         // All we have to is lay out our positioned objects.
425         layoutPositionedObjects(relayoutChildren);
426         setNeedsLayout(false);
427         return;
428     }
429
430 #ifdef INCREMENTAL_REPAINTING
431     // FIXME: For now, if we have dirty inline children, we just always repaint.
432     if (normalChildNeedsLayout() && childrenInline())
433         repaint();
434     
435     QRect oldBounds, oldFullBounds;
436     getAbsoluteRepaintRectIncludingDescendants(oldBounds, oldFullBounds);
437 #endif
438
439     int oldWidth = m_width;
440     
441     calcWidth();
442     m_overflowWidth = m_width;
443
444     if ( oldWidth != m_width )
445         relayoutChildren = true;
446
447     //     kdDebug( 6040 ) << floatingObjects << "," << oldWidth << ","
448     //                     << m_width << ","<< needsLayout() << "," << isAnonymousBox() << ","
449     //                     << overhangingContents() << "," << isPositioned() << endl;
450
451 #ifdef DEBUG_LAYOUT
452     kdDebug( 6040 ) << renderName() << "(RenderBlock) " << this << " ::layout() width=" << m_width << ", needsLayout=" << needsLayout() << endl;
453     if(containingBlock() == static_cast<RenderObject *>(this))
454         kdDebug( 6040 ) << renderName() << ": containingBlock == this" << endl;
455 #endif
456
457     clearFloats();
458
459     m_height = 0;
460     m_overflowHeight = 0;
461     m_clearStatus = CNONE;
462
463     // We use four values, maxTopPos, maxPosNeg, maxBottomPos, and maxBottomNeg, to track
464     // our current maximal positive and negative margins.  These values are used when we
465     // are collapsed with adjacent blocks, so for example, if you have block A and B
466     // collapsing together, then you'd take the maximal positive margin from both A and B
467     // and subtract it from the maximal negative margin from both A and B to get the
468     // true collapsed margin.  This algorithm is recursive, so when we finish layout()
469     // our block knows its current maximal positive/negative values.
470     //
471     // Start out by setting our margin values to our current margins.  Table cells have
472     // no margins, so we don't fill in the values for table cells.
473     if (!isTableCell()) {
474         initMaxMarginValues();
475
476         m_topMarginQuirk = style()->marginTop().quirk;
477         m_bottomMarginQuirk = style()->marginBottom().quirk;
478
479         if (element() && element()->id() == ID_FORM && element()->isMalformed())
480             // See if this form is malformed (i.e., unclosed). If so, don't give the form
481             // a bottom margin.
482             m_maxBottomPosMargin = m_maxBottomNegMargin = 0;
483     }
484
485     if (style()->scrollsOverflow() && m_layer) {
486         // For overflow:scroll blocks, ensure we have both scrollbars in place always.
487         if (style()->overflow() == OSCROLL) {
488             m_layer->setHasHorizontalScrollbar(true);
489             m_layer->setHasVerticalScrollbar(true);
490         }
491         
492         // Move the scrollbars aside during layout.  The layer will move them back when it
493         // does painting or event handling.
494         m_layer->moveScrollbarsAside();
495     }
496     
497     //    kdDebug( 6040 ) << "childrenInline()=" << childrenInline() << endl;
498     if (childrenInline())
499         layoutInlineChildren( relayoutChildren );
500     else
501         layoutBlockChildren( relayoutChildren );
502
503     // Expand our intrinsic height to encompass floats.
504     if ( hasOverhangingFloats() && (isFloatingOrPositioned() || style()->hidesOverflow() ||
505                                     (parent() && parent()->isFlexibleBox())) )
506         m_height = floatBottom() + borderBottom() + paddingBottom();
507            
508     int oldHeight = m_height;
509     calcHeight();
510     if (oldHeight != m_height) {
511         relayoutChildren = true;
512
513         // If the block got expanded in size, then increase our overflowheight to match.
514         if (m_overflowHeight > m_height)
515             m_overflowHeight -= paddingBottom() + borderBottom();
516         if (m_overflowHeight < m_height)
517             m_overflowHeight = m_height;
518     }
519
520     if (isTableCell()) {
521         // Table cells need to grow to accommodate both overhanging floats and
522         // blocks that have overflowed content.
523         // Check for an overhanging float first.
524         // FIXME: This needs to look at the last flow, not the last child.
525         if (lastChild() && lastChild()->hasOverhangingFloats()) {
526             KHTMLAssert(lastChild()->isRenderBlock());
527             m_height = lastChild()->yPos() + static_cast<RenderBlock*>(lastChild())->floatBottom();
528             m_height += borderBottom() + paddingBottom();
529         }
530
531         if (m_overflowHeight > m_height && !style()->hidesOverflow())
532             m_height = m_overflowHeight + borderBottom() + paddingBottom();
533     }
534
535     if( hasOverhangingFloats() && (isFloating() || isTableCell())) {
536         m_height = floatBottom();
537         m_height += borderBottom() + paddingBottom();
538     }
539
540     layoutPositionedObjects( relayoutChildren );
541
542     //kdDebug() << renderName() << " layout width=" << m_width << " height=" << m_height << endl;
543
544     // Always ensure our overflow width/height are at least as large as our width/height.
545     if (m_overflowWidth < m_width)
546         m_overflowWidth = m_width;
547     if (m_overflowHeight < m_height)
548         m_overflowHeight = m_height;
549     
550     // Update our scrollbars if we're overflow:auto/scroll now that we know if
551     // we overflow or not.
552     if (style()->scrollsOverflow() && m_layer)
553         m_layer->checkScrollbarsAfterLayout();
554
555 #ifdef INCREMENTAL_REPAINTING
556     // Repaint with our new bounds if they are different from our old bounds.
557     if (!isCanvas())
558         repaintAfterLayoutIfNeeded(oldBounds, oldFullBounds);
559 #endif
560     
561     setNeedsLayout(false);
562 }
563
564 void RenderBlock::layoutBlockChildren( bool relayoutChildren )
565 {
566 #ifdef DEBUG_LAYOUT
567     kdDebug( 6040 ) << renderName() << " layoutBlockChildren( " << this <<" ), relayoutChildren="<< relayoutChildren << endl;
568 #endif
569
570     int xPos = borderLeft() + paddingLeft();
571     if( style()->direction() == RTL )
572         xPos = m_width - paddingRight() - borderRight();
573
574     int toAdd = borderBottom() + paddingBottom();
575     m_height = borderTop() + paddingTop();
576
577     // Fieldsets need to find their legend and position it inside the border of the object.
578     // The legend then gets skipped during normal layout.
579     RenderObject* legend = layoutLegend(relayoutChildren);
580     
581     int minHeight = m_height + toAdd;
582     m_overflowHeight = m_height;
583
584     RenderObject *child = firstChild();
585     RenderBlock *prevFlow = 0;
586
587     // A compact child that needs to be collapsed into the margin of the following block.
588     RenderObject* compactChild = 0;
589     // The block with the open margin that the compact child is going to place itself within.
590     RenderObject* blockForCompactChild = 0;
591     // For compact children that don't fit, we lay them out as though they are blocks.  This
592     // boolean allows us to temporarily treat a compact like a block and lets us know we need
593     // to turn the block back into a compact when we're done laying out.
594     bool treatCompactAsBlock = false;
595     
596     // Whether or not we can collapse our own margins with our children.  We don't do this
597     // if we had any border/padding (obviously), if we're the root or HTML elements, or if
598     // we're positioned, floating, a table cell.
599     // For now we only worry about the top border/padding.  We will update the variable's
600     // value when it comes time to check against the bottom border/padding.
601     bool canCollapseWithChildren = !isCanvas() && !isRoot() && !isPositioned() &&
602         !isFloating() && !isTableCell() && !style()->hidesOverflow();
603     bool canCollapseTopWithChildren = canCollapseWithChildren && (m_height == 0);
604
605     // If any height other than auto is specified in CSS, then we don't collapse our bottom
606     // margins with our children's margins.  To do otherwise would be to risk odd visual
607     // effects when the children overflow out of the parent block and yet still collapse
608     // with it.  We also don't collapse if we had any bottom border/padding (represented by
609     // |toAdd|).
610     bool canCollapseBottomWithChildren = canCollapseWithChildren && (toAdd == 0) &&
611         (style()->height().isVariable() && style()->height().value == 0);
612     
613     // Whether or not we are a quirky container, i.e., do we collapse away top and bottom
614     // margins in our container.
615     bool quirkContainer = isTableCell() || isBody();
616
617     // Sometimes an element will be shoved down away from a previous sibling, e.g., when
618     // clearing to pass beyond a float.  In this case, you don't need to collapse.  This
619     // boolean is updated with each iteration through our child list to reflect whether
620     // that particular child should be collapsed with its previous sibling (or with the top
621     // of the block).
622     bool shouldCollapseChild = true;
623
624     // This flag tracks whether the child should collapse with the top margins of the block.
625     // It can remain set through multiple iterations as long as we keep encountering
626     // self-collapsing blocks.
627     bool topMarginContributor = true;
628
629     // These flags track the previous maximal positive and negative margins.
630     int prevPosMargin = canCollapseTopWithChildren ? maxTopMargin(true) : 0;
631     int prevNegMargin = canCollapseTopWithChildren ? maxTopMargin(false) : 0;
632
633     // Whether or not we encountered an element with clear set that actually had to
634     // be pushed down below a float.
635     bool clearOccurred = false;
636
637     // If our last normal flow child was a self-collapsing block that cleared a float,
638     // we track it in this variable.
639     bool selfCollapsingBlockClearedFloat = false;
640     
641     bool topChildQuirk = false;
642     bool bottomChildQuirk = false;
643     bool determinedTopQuirk = false;
644
645     bool strictMode = !style()->htmlHacks();
646
647     //kdDebug() << "RenderBlock::layoutBlockChildren " << prevMargin << endl;
648
649     //     QTime t;
650     //     t.start();
651
652     while( child != 0 )
653     {
654         int oldTopPosMargin = m_maxTopPosMargin;
655         int oldTopNegMargin = m_maxTopNegMargin;
656
657         if (legend == child) {
658             child = child->nextSibling();
659             continue; // Skip the legend, since it has already been positioned up in the fieldset's border.
660         }
661         
662         // make sure we relayout children if we need it.
663         if (relayoutChildren || floatBottom() > m_y ||
664             (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())) ||
665             (child->isRenderBlock() && child->style()->height().isPercent()))
666             child->setChildNeedsLayout(true);
667
668         //         kdDebug( 6040 ) << "   " << child->renderName() << " loop " << child << ", " << child->isInline() << ", " << child->needsLayout() << endl;
669         //         kdDebug( 6040 ) << t.elapsed() << endl;
670         // ### might be some layouts are done two times... FIX that.
671
672         if (child->isPositioned())
673         {
674             child->containingBlock()->insertPositionedObject(child);
675             if (child->hasStaticX()) {
676                 if (style()->direction() == LTR)
677                     child->setStaticX(xPos);
678                 else
679                     child->setStaticX(borderRight()+paddingRight());
680             }
681             if (child->hasStaticY()) {
682                 int yPosEstimate = m_height + (!topMarginContributor ? (prevPosMargin - prevNegMargin) : 0);
683                 child->setStaticY(yPosEstimate);
684             }
685             child = child->nextSibling();
686             continue;
687         } else if (child->isReplaced())
688             child->layoutIfNeeded();
689         
690         if ( child->isFloating() ) {
691             insertFloatingObject( child );
692
693             // The float should be positioned taking into account the bottom margin
694             // of the previous flow.  We add that margin into the height, get the
695             // float positioned properly, and then subtract the margin out of the
696             // height again.  In the case of self-collapsing blocks, we always just
697             // use the top margins, since the self-collapsing block collapsed its
698             // own bottom margin into its top margin.
699             //
700             // Note also that the previous flow may collapse its margin into the top of
701             // our block.  If this is the case, then we do not add the margin in to our
702             // height when computing the position of the float.   This condition can be tested
703             // for by simply checking the boolean |topMarginContributor| variable.  See
704             // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
705             // an example of this scenario.
706             int marginOffset = !topMarginContributor ? (prevPosMargin - prevNegMargin) : 0;
707             
708             m_height += marginOffset;
709             positionNewFloats();
710             m_height -= marginOffset;
711
712             //kdDebug() << "RenderBlock::layoutBlockChildren inserting float at "<< m_height <<" prevMargin="<<prevMargin << endl;
713             child = child->nextSibling();
714             continue;
715         }
716
717         // See if we have a compact element.  If we do, then try to tuck the compact
718         // element into the margin space of the next block.
719         // FIXME: We only deal with one compact at a time.  It is unclear what should be
720         // done if multiple contiguous compacts are encountered.  For now we assume that
721         // compact A followed by another compact B should simply be treated as block A.
722         if (child->isCompact() && !compactChild && (child->childrenInline() || child->isReplaced())) {
723             // Get the next non-positioned/non-floating RenderBlock.
724             RenderObject* next = child->nextSibling();
725             RenderObject* curr = next;
726             while (curr && curr->isFloatingOrPositioned())
727                 curr = curr->nextSibling();
728             if (curr && curr->isRenderBlock() && !curr->isAnonymousBox() &&
729                 !curr->isCompact() && !curr->isRunIn()) {
730                 curr->calcWidth(); // So that horizontal margins are correct.
731                 // Need to compute margins for the child as though it is a block.
732                 child->style()->setDisplay(BLOCK);
733                 child->calcWidth();
734                 child->style()->setDisplay(COMPACT);
735                 int childMargins = child->marginLeft() + child->marginRight();
736                 int margin = style()->direction() == LTR ? curr->marginLeft() : curr->marginRight();
737                 if (margin < (childMargins + child->maxWidth())) {
738                     // It won't fit. Kill the "compact" boolean and just treat
739                     // the child like a normal block. This is only temporary.
740                     child->style()->setDisplay(BLOCK);
741                     treatCompactAsBlock = true;
742                 }
743                 else {
744                     blockForCompactChild = curr;
745                     compactChild = child;
746                     child->setInline(true);
747                     child->setPos(0,0); // This position will be updated to reflect the compact's
748                                         // desired position and the line box for the compact will
749                                         // pick that position up.
750
751                     // Remove the child.
752                     RenderObject* next = child->nextSibling();
753                     removeChildNode(child);
754
755                     // Now insert the child under |curr|.
756                     curr->insertChildNode(child, curr->firstChild());
757                     child = next;
758                     continue;
759                 }
760             }
761         }
762
763         // See if we have a run-in element with inline children.  If the
764         // children aren't inline, then just treat the run-in as a normal
765         // block.
766         if (child->isRunIn() && (child->childrenInline() || child->isReplaced())) {
767             // Get the next non-positioned/non-floating RenderBlock.
768             RenderObject* curr = child->nextSibling();
769             while (curr && curr->isFloatingOrPositioned())
770                 curr = curr->nextSibling();
771             if (curr && (curr->isRenderBlock() && !curr->isAnonymousBox() && curr->childrenInline() &&
772                          !curr->isCompact() && !curr->isRunIn())) {
773                 // The block acts like an inline, so just null out its
774                 // position.
775                 child->setInline(true);
776                 child->setPos(0,0);
777
778                 // Remove the child.
779                 RenderObject* next = child->nextSibling();
780                 removeChildNode(child);
781
782                 // Now insert the child under |curr|.
783                 curr->insertChildNode(child, curr->firstChild());
784                 child = next;
785                 continue;
786             }
787         }
788         
789         // Note this occurs after the test for positioning and floating above, since
790         // we want to ensure that we don't artificially increase our height because of
791         // a positioned or floating child.
792         if ( (child->style()->hidesOverflow() || child->isFlexibleBox() || child->style()->flowAroundFloats() )
793              && !child->isFloating() &&
794              style()->width().isFixed() && child->minWidth() > lineWidth( m_height ) ) {
795             m_height = QMAX( m_height, floatBottom() );
796             shouldCollapseChild = false;
797             clearOccurred = true;
798         }
799
800         // take care in case we inherited floats
801         if (child && floatBottom() > m_height)
802             child->setChildNeedsLayout(true);
803         
804         child->calcVerticalMargins();
805
806         //kdDebug(0) << "margin = " << margin << " yPos = " << m_height << endl;
807
808 #ifdef INCREMENTAL_REPAINTING
809         int oldChildX = child->xPos();
810         int oldChildY = child->yPos();
811 #endif
812         
813         // Try to guess our correct y position.  In most cases this guess will
814         // be correct.  Only if we're wrong (when we compute the real y position)
815         // will we have to relayout.
816         int yPosEstimate = m_height;
817         if (prevFlow)
818         {
819             yPosEstimate += QMAX(prevFlow->collapsedMarginBottom(), child->marginTop());
820             if (prevFlow->yPos()+prevFlow->floatBottom() > yPosEstimate)
821                 child->setChildNeedsLayout(true);
822             else
823                 prevFlow=0;
824         }
825         else if (!canCollapseTopWithChildren || !topMarginContributor)
826             yPosEstimate += child->marginTop();
827
828         // Go ahead and position the child as though it didn't collapse with the top.
829         child->setPos(child->xPos(), yPosEstimate);
830         child->layoutIfNeeded();
831
832         // Now determine the correct ypos based off examination of collapsing margin
833         // values.
834         if (shouldCollapseChild) {
835             // Get our max pos and neg top margins.
836             int posTop = child->maxTopMargin(true);
837             int negTop = child->maxTopMargin(false);
838
839             // For self-collapsing blocks, collapse our bottom margins into our
840             // top to get new posTop and negTop values.
841             if (child->isSelfCollapsingBlock()) {
842                 if (child->maxBottomMargin(true) > posTop)
843                     posTop = child->maxBottomMargin(true);
844                 if (child->maxBottomMargin(false) > negTop)
845                     negTop = child->maxBottomMargin(false);
846             }
847             
848             // See if the top margin is quirky. We only care if this child has
849             // margins that will collapse with us.
850             bool topQuirk = child->isTopMarginQuirk();
851
852             if (canCollapseTopWithChildren && topMarginContributor && !clearOccurred) {
853                 // This child is collapsing with the top of the
854                 // block.  If it has larger margin values, then we need to update
855                 // our own maximal values.
856                 if (strictMode || !quirkContainer || !topQuirk) {
857                     if (posTop > m_maxTopPosMargin)
858                         m_maxTopPosMargin = posTop;
859
860                     if (negTop > m_maxTopNegMargin)
861                         m_maxTopNegMargin = negTop;
862                 }
863
864                 // The minute any of the margins involved isn't a quirk, don't
865                 // collapse it away, even if the margin is smaller (www.webreference.com
866                 // has an example of this, a <dt> with 0.8em author-specified inside
867                 // a <dl> inside a <td>.
868                 if (!determinedTopQuirk && !topQuirk && (posTop-negTop)) {
869                     m_topMarginQuirk = false;
870                     determinedTopQuirk = true;
871                 }
872
873                 if (!determinedTopQuirk && topQuirk && marginTop() == 0)
874                     // We have no top margin and our top child has a quirky margin.
875                     // We will pick up this quirky margin and pass it through.
876                     // This deals with the <td><div><p> case.
877                     // Don't do this for a block that split two inlines though.  You do
878                     // still apply margins in this case.
879                     m_topMarginQuirk = true;
880             }
881
882             if (quirkContainer && topMarginContributor && (posTop-negTop))
883                 topChildQuirk = topQuirk;
884
885             int ypos = m_height;
886             if (child->isSelfCollapsingBlock()) {
887                 // This child has no height.  We need to compute our
888                 // position before we collapse the child's margins together,
889                 // so that we can get an accurate position for the zero-height block.
890                 int collapsedTopPos = prevPosMargin;
891                 int collapsedTopNeg = prevNegMargin;
892                 if (child->maxTopMargin(true) > prevPosMargin)
893                     collapsedTopPos = prevPosMargin = child->maxTopMargin(true);
894                 if (child->maxTopMargin(false) > prevNegMargin)
895                     collapsedTopNeg = prevNegMargin = child->maxTopMargin(false);
896
897                 // Now collapse the child's margins together, which means examining our
898                 // bottom margin values as well. 
899                 if (child->maxBottomMargin(true) > prevPosMargin)
900                     prevPosMargin = child->maxBottomMargin(true);
901                 if (child->maxBottomMargin(false) > prevNegMargin)
902                     prevNegMargin = child->maxBottomMargin(false);
903
904                 if (!canCollapseTopWithChildren || !topMarginContributor)
905                     // We need to make sure that the position of the self-collapsing block
906                     // is correct, since it could have overflowing content
907                     // that needs to be positioned correctly (e.g., a block that
908                     // had a specified height of 0 but that actually had subcontent).
909                     ypos = m_height + collapsedTopPos - collapsedTopNeg;
910             }
911             else {
912                 if (!topMarginContributor ||
913                     (!canCollapseTopWithChildren
914                      && (strictMode || !quirkContainer || !topChildQuirk)
915                      )) {
916                     // We're collapsing with a previous sibling's margins and not
917                     // with the top of the block.
918                     int absPos = prevPosMargin > posTop ? prevPosMargin : posTop;
919                     int absNeg = prevNegMargin > negTop ? prevNegMargin : negTop;
920                     int collapsedMargin = absPos - absNeg;
921                     m_height += collapsedMargin;
922                     ypos = m_height;
923                 }
924                 prevPosMargin = child->maxBottomMargin(true);
925                 prevNegMargin = child->maxBottomMargin(false);
926
927                 if (prevPosMargin-prevNegMargin) {
928                     bottomChildQuirk = child->isBottomMarginQuirk();
929                 }
930
931                 selfCollapsingBlockClearedFloat = false;
932             }
933
934             child->setPos(child->xPos(), ypos);
935             if (ypos != yPosEstimate) {
936                 if (child->style()->htmlHacks() && child->style()->flowAroundFloats() &&
937                     child->style()->width().isPercent())
938                     // The child's width can be a percentage width and if it has the
939                     // quirky flowAroundFloats
940                     // property set, when the child shifts to clear an item, its width can
941                     // change (because it has more available line width).
942                     // So go ahead and mark the item as dirty.
943                     child->setChildNeedsLayout(true);
944
945                 if (child->containsFloats() || containsFloats())
946                     child->markAllDescendantsWithFloatsForLayout();
947
948                 // Our guess was wrong. Make the child lay itself out again.
949                 child->layoutIfNeeded();
950             }
951         }
952         else
953             selfCollapsingBlockClearedFloat = false;
954
955         // Now check for clear.
956         int heightIncrease = getClearDelta(child);
957         if (heightIncrease) {
958             // The child needs to be lowered.  Move the child so that it just clears the float.
959             child->setPos(child->xPos(), child->yPos()+heightIncrease);
960             clearOccurred = true;
961
962             // Increase our height by the amount we had to clear.
963             if (!child->isSelfCollapsingBlock())
964                 m_height += heightIncrease;
965             else {
966                 // For self-collapsing blocks that clear, they may end up collapsing
967                 // into the bottom of the parent block.  We simulate this behavior by
968                 // setting our positive margin value to compensate for the clear.
969                 prevPosMargin = QMAX(0, child->yPos() - m_height);
970                 prevNegMargin = 0;
971                 selfCollapsingBlockClearedFloat = true;
972             }
973             
974             if (topMarginContributor && canCollapseTopWithChildren) {
975                 // We can no longer collapse with the top of the block since a clear
976                 // occurred.  The empty blocks collapse into the cleared block.
977                 // XXX This isn't quite correct.  Need clarification for what to do
978                 // if the height the cleared block is offset by is smaller than the
979                 // margins involved. -dwh
980                 m_maxTopPosMargin = oldTopPosMargin;
981                 m_maxTopNegMargin = oldTopNegMargin;
982                 topMarginContributor = false;
983             }
984
985             // If our value of clear caused us to be repositioned vertically to be
986             // underneath a float, we might have to do another layout to take into account
987             // the extra space we now have available.
988             if (child->style()->htmlHacks() && child->style()->flowAroundFloats() &&
989                 child->style()->width().isPercent())
990                 // The child's width can be a percentage width and if it has the
991                 // quirky flowAroundFloats
992                 // property set, when the child shifts to clear an item, its width can
993                 // change (because it has more available line width).
994                 // So go ahead an mark the item as dirty.
995                 child->setChildNeedsLayout(true);
996             if (child->containsFloats())
997                 child->markAllDescendantsWithFloatsForLayout();
998             child->layoutIfNeeded();
999         }
1000
1001         // Reset the top margin contributor to false if we encountered
1002         // a non-empty child.  This has to be done after checking for clear,
1003         // so that margins can be reset if a clear occurred.
1004         if (topMarginContributor && !child->isSelfCollapsingBlock())
1005             topMarginContributor = false;
1006
1007         int chPos = xPos; 
1008
1009         if (style()->direction() == LTR) {
1010             // Add in our left margin.
1011             chPos += child->marginLeft();
1012             
1013             // html blocks flow around floats
1014             if (child->style()->hidesOverflow() || child->isFlexibleBox() ||
1015                  (( style()->htmlHacks() || child->isTable() ) && child->style()->flowAroundFloats()))
1016             {
1017                 int leftOff = leftOffset(m_height);
1018                 if (leftOff != xPos) {
1019                     // The object is shifting right. The object might be centered, so we need to
1020                     // recalculate our horizontal margins. Note that the containing block content
1021                     // width computation will take into account the delta between |leftOff| and |xPos|
1022                     // so that we can just pass the content width in directly to the |calcHorizontalMargins|
1023                     // function.
1024                     // -dwh
1025                     int cw = lineWidth( child->yPos() );
1026                     static_cast<RenderBox*>(child)->calcHorizontalMargins
1027                         ( child->style()->marginLeft(), child->style()->marginRight(), cw);
1028                     chPos = leftOff + child->marginLeft();
1029                 }
1030             }
1031         } else {
1032             chPos -= child->width() + child->marginRight();
1033             if (child->style()->hidesOverflow() || child->isFlexibleBox() ||
1034                 ((style()->htmlHacks() || child->isTable()) && child->style()->flowAroundFloats()))
1035                 chPos -= leftOffset(m_height);
1036         }
1037
1038         child->setPos(chPos, child->yPos());
1039
1040         m_height += child->height();
1041         int overflowDelta = child->overflowHeight(false) - child->height();
1042         if (m_height + overflowDelta > m_overflowHeight)
1043             m_overflowHeight = m_height + overflowDelta;
1044
1045         if (child->isRenderBlock())
1046             prevFlow = static_cast<RenderBlock*>(child); 
1047
1048         if (child->hasOverhangingFloats() && !child->style()->hidesOverflow()) {
1049             // need to add the child's floats to our floating objects list, but not in the case where
1050             // overflow is auto/scroll
1051             addOverHangingFloats( static_cast<RenderBlock *>(child), -child->xPos(), -child->yPos(), true );
1052         }
1053
1054         // See if this child has made our overflow need to grow.
1055         // XXXdwh Work with left overflow as well as right overflow.
1056         int rightChildPos = child->xPos() + QMAX(child->overflowWidth(false), child->width());
1057         if (rightChildPos > m_overflowWidth)
1058             m_overflowWidth = rightChildPos;
1059
1060         if (child == blockForCompactChild) {
1061             blockForCompactChild = 0;
1062             if (compactChild) {
1063                 // We have a compact child to squeeze in.
1064                 int compactXPos = xPos+compactChild->marginLeft();
1065                 if (style()->direction() == RTL) {
1066                     compactChild->calcWidth(); // have to do this because of the capped maxwidth
1067                     compactXPos = width() - borderRight() - paddingRight() - marginRight() -
1068                         compactChild->width() - compactChild->marginRight();
1069                 }
1070                 compactXPos -= child->xPos(); // Put compactXPos into the child's coordinate space.
1071                 compactChild->setPos(compactXPos, compactChild->yPos()); // Set the x position.
1072                 compactChild = 0;
1073             }
1074         }
1075
1076         // We did a layout as though the compact child was a block.  Set it back to compact now.
1077         if (treatCompactAsBlock) {
1078             child->style()->setDisplay(COMPACT);
1079             treatCompactAsBlock = false;
1080         }
1081
1082         // If the child moved, we have to repaint it as well as any floating/positioned
1083         // descendants.  An exception is if we need a layout.  In this case, we know we're going to
1084         // repaint ourselves (and the child) anyway.
1085 #ifdef INCREMENTAL_REPAINTING
1086         if (!selfNeedsLayout())
1087             child->repaintIfMoved(oldChildX, oldChildY);
1088 #endif
1089         
1090         child = child->nextSibling();
1091     }
1092
1093     // If our last flow was a self-collapsing block that cleared a float, then we don't
1094     // collapse it with the bottom of the block.
1095     if (selfCollapsingBlockClearedFloat)
1096         canCollapseBottomWithChildren = false;
1097     
1098     // If we can't collapse with children then go ahead and add in the bottom margins.
1099     if (!canCollapseBottomWithChildren
1100         && (strictMode || !quirkContainer || !bottomChildQuirk))
1101         m_height += prevPosMargin - prevNegMargin;
1102
1103     m_height += toAdd;
1104
1105     // Negative margins can cause our height to shrink below our minimal height (border/padding).
1106     // If this happens, ensure that the computed height is increased to the minimal height.
1107     if (m_height < minHeight)
1108         m_height = minHeight;
1109
1110     // Always make sure our overflowheight is at least our height.
1111     if (m_overflowHeight < m_height)
1112         m_overflowHeight = m_height;
1113
1114     if (canCollapseBottomWithChildren && !topMarginContributor) {
1115         // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1116         // with our children.
1117         if (prevPosMargin > m_maxBottomPosMargin)
1118             m_maxBottomPosMargin = prevPosMargin;
1119
1120         if (prevNegMargin > m_maxBottomNegMargin)
1121             m_maxBottomNegMargin = prevNegMargin;
1122
1123         if (!bottomChildQuirk)
1124             m_bottomMarginQuirk = false;
1125
1126         if (bottomChildQuirk && marginBottom() == 0)
1127             // We have no bottom margin and our last child has a quirky margin.
1128             // We will pick up this quirky margin and pass it through.
1129             // This deals with the <td><div><p> case.
1130             m_bottomMarginQuirk = true;
1131     }
1132
1133     setNeedsLayout(false);
1134
1135     // kdDebug( 6040 ) << "needsLayout = " << needsLayout_ << endl;
1136 }
1137
1138 void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
1139 {
1140     if (m_positionedObjects) {
1141         //kdDebug( 6040 ) << renderName() << " " << this << "::layoutPositionedObjects() start" << endl;
1142         RenderObject* r;
1143         QPtrListIterator<RenderObject> it(*m_positionedObjects);
1144         for ( ; (r = it.current()); ++it ) {
1145             //kdDebug(6040) << "   have a positioned object" << endl;
1146             if ( relayoutChildren )
1147                 r->setChildNeedsLayout(true);
1148             r->layoutIfNeeded();
1149         }
1150     }
1151 }
1152
1153 #ifdef INCREMENTAL_REPAINTING
1154 void RenderBlock::getAbsoluteRepaintRectIncludingDescendants(QRect& bounds, QRect& fullBounds)
1155 {
1156     bounds = fullBounds = getAbsoluteRepaintRect();
1157     if (m_positionedObjects) {
1158         RenderObject* r;
1159         QPtrListIterator<RenderObject> it(*m_positionedObjects);
1160         for ( ; (r = it.current()); ++it ) {
1161             QRect childRect, childFullRect;
1162             r->getAbsoluteRepaintRectIncludingDescendants(childRect, childFullRect);
1163             fullBounds = fullBounds.unite(childFullRect);
1164         }
1165     }
1166
1167     // Include any overhanging floats (if we know we're the one to paint them).
1168     if (hasOverhangingFloats()) {
1169         FloatingObject* r;
1170         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1171         for ( ; (r = it.current()); ++it) {
1172             // Only repaint the object if our noPaint flag isn't set.
1173             if (!r->noPaint) {
1174                 QRect childRect, childFullRect;
1175                 r->node->getAbsoluteRepaintRectIncludingDescendants(childRect, childFullRect);
1176                 fullBounds = fullBounds.unite(childFullRect);
1177             }
1178         }
1179     }
1180 }
1181
1182 void RenderBlock::repaintPositionedAndFloatingDescendants()
1183 {
1184     if (m_positionedObjects) {
1185         RenderObject* r;
1186         QPtrListIterator<RenderObject> it(*m_positionedObjects);
1187         for ( ; (r = it.current()); ++it ) {
1188             r->repaint();
1189             r->repaintPositionedAndFloatingDescendants();
1190         }
1191     }
1192
1193     // Repaint any overhanging floats (if we know we're the one to paint them).
1194     if (hasOverhangingFloats()) {
1195         FloatingObject* r;
1196         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1197         for ( ; (r = it.current()); ++it) {
1198             // Only repaint the object if our noPaint flag isn't set.
1199             if (!r->noPaint) {
1200                 r->node->repaint();
1201                 r->node->repaintPositionedAndFloatingDescendants();
1202             }
1203         }
1204     }
1205 }
1206 #endif
1207
1208 void RenderBlock::paint(QPainter* p, int _x, int _y, int _w, int _h, int _tx, int _ty, PaintAction paintAction)
1209 {
1210     _tx += m_x;
1211     _ty += m_y;
1212
1213     // check if we need to do anything at all...
1214     if (!isRoot() && !isInlineFlow() && !overhangingContents() && !isRelPositioned() && !isPositioned() )
1215     {
1216         int h = m_overflowHeight;
1217         int yPos = _ty;
1218         if (m_floatingObjects && floatBottom() > h)
1219             h = floatBottom();
1220
1221         // Sanity check the first line
1222         // to see if it extended a little above our box. Overflow out the bottom is already handled via
1223         // overflowHeight(), so we don't need to check that.
1224         if (m_firstLineBox && m_firstLineBox->topOverflow() < 0)
1225             yPos += m_firstLineBox->topOverflow();
1226         
1227         if( (yPos > _y + _h) || (_ty + h < _y))
1228             return;
1229     }
1230
1231     paintObject(p, _x, _y, _w, _h, _tx, _ty, paintAction);
1232 }
1233
1234 void RenderBlock::paintObject(QPainter *p, int _x, int _y,
1235                               int _w, int _h, int _tx, int _ty, PaintAction paintAction)
1236 {
1237
1238 #ifdef DEBUG_LAYOUT
1239     //    kdDebug( 6040 ) << renderName() << "(RenderBlock) " << this << " ::paintObject() w/h = (" << width() << "/" << height() << ")" << endl;
1240 #endif
1241
1242     // If we're a repositioned run-in, don't paint background/borders.
1243     bool inlineFlow = isInlineFlow();
1244     
1245     // 1. paint background, borders etc
1246     if (!inlineFlow &&
1247         (paintAction == PaintActionElementBackground || paintAction == PaintActionChildBackground) &&
1248         shouldPaintBackgroundOrBorder() && style()->visibility() == VISIBLE) {
1249         paintBoxDecorations(p, _x, _y, _w, _h, _tx, _ty);
1250     }
1251
1252     // We're done.  We don't bother painting any children.
1253     if (paintAction == PaintActionElementBackground)
1254         return;
1255     // We don't paint our own background, but we do let the kids paint their backgrounds.
1256     if (paintAction == PaintActionChildBackgrounds)
1257         paintAction = PaintActionChildBackground;
1258     
1259     paintLineBoxBackgroundBorder(p, _x, _y, _w, _h, _tx, _ty, paintAction);
1260
1261     // 2. paint contents
1262     int scrolledX = _tx;
1263     int scrolledY = _ty;
1264     if (style()->hidesOverflow() && m_layer)
1265         m_layer->subtractScrollOffset(scrolledX, scrolledY);
1266     RenderObject *child = firstChild();
1267     while(child != 0)
1268     {
1269         if(!child->layer() && !child->isFloating())
1270             child->paint(p, _x, _y, _w, _h, scrolledX, scrolledY, paintAction);
1271         child = child->nextSibling();
1272     }
1273     paintLineBoxDecorations(p, _x, _y, _w, _h, scrolledX, scrolledY, paintAction);
1274     
1275     // 3. paint floats.
1276     if (!inlineFlow && (paintAction == PaintActionFloat || paintAction == PaintActionSelection))
1277         paintFloats(p, _x, _y, _w, _h, scrolledX, scrolledY, paintAction == PaintActionSelection);
1278
1279     // 4. paint outline.
1280     if (!inlineFlow && paintAction == PaintActionForeground &&
1281         !childrenInline() && style()->outlineWidth())
1282         paintOutline(p, _tx, _ty, width(), height(), style());
1283
1284 #ifdef BOX_DEBUG
1285     if ( style() && style()->visibility() == VISIBLE ) {
1286         if(isAnonymousBox())
1287             outlineBox(p, _tx, _ty, "green");
1288         if(isFloating())
1289             outlineBox(p, _tx, _ty, "yellow");
1290         else
1291             outlineBox(p, _tx, _ty);
1292     }
1293 #endif
1294 }
1295
1296 void RenderBlock::paintFloats(QPainter *p, int _x, int _y,
1297                               int _w, int _h, int _tx, int _ty, bool paintSelection)
1298 {
1299     if (!m_floatingObjects)
1300         return;
1301
1302     FloatingObject* r;
1303     QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1304     for ( ; (r = it.current()); ++it) {
1305         // Only paint the object if our noPaint flag isn't set.
1306         if (!r->noPaint && !r->node->layer()) {
1307             if (paintSelection) {
1308                 r->node->paint(p, _x, _y, _w, _h,
1309                                _tx + r->left - r->node->xPos() + r->node->marginLeft(),
1310                                _ty + r->startY - r->node->yPos() + r->node->marginTop(),
1311                                PaintActionSelection);
1312             }
1313             else {
1314                 r->node->paint(p, _x, _y, _w, _h,
1315                                _tx + r->left - r->node->xPos() + r->node->marginLeft(),
1316                                _ty + r->startY - r->node->yPos() + r->node->marginTop(),
1317                                PaintActionElementBackground);
1318                 r->node->paint(p, _x, _y, _w, _h,
1319                                _tx + r->left - r->node->xPos() + r->node->marginLeft(),
1320                                _ty + r->startY - r->node->yPos() + r->node->marginTop(),
1321                                PaintActionChildBackgrounds);
1322                 r->node->paint(p, _x, _y, _w, _h,
1323                                _tx + r->left - r->node->xPos() + r->node->marginLeft(),
1324                                _ty + r->startY - r->node->yPos() + r->node->marginTop(),
1325                                PaintActionFloat);
1326                 r->node->paint(p, _x, _y, _w, _h,
1327                                _tx + r->left - r->node->xPos() + r->node->marginLeft(),
1328                                _ty + r->startY - r->node->yPos() + r->node->marginTop(),
1329                                PaintActionForeground);
1330             }
1331         }
1332     }
1333 }
1334
1335 void RenderBlock::insertPositionedObject(RenderObject *o)
1336 {
1337     // Create the list of special objects if we don't aleady have one
1338     if (!m_positionedObjects) {
1339         m_positionedObjects = new QPtrList<RenderObject>;
1340         m_positionedObjects->setAutoDelete(false);
1341     }
1342     else {
1343         // Don't insert the object again if it's already in the list
1344         QPtrListIterator<RenderObject> it(*m_positionedObjects);
1345         RenderObject* f;
1346         while ( (f = it.current()) ) {
1347             if (f == o) return;
1348             ++it;
1349         }
1350     }
1351
1352     // Create the special object entry & append it to the list
1353     setOverhangingContents();
1354     m_positionedObjects->append(o);
1355 }
1356
1357 void RenderBlock::removePositionedObject(RenderObject *o)
1358 {
1359     if (m_positionedObjects) {
1360         QPtrListIterator<RenderObject> it(*m_positionedObjects);
1361         while (it.current()) {
1362             if (it.current() == o)
1363                 m_positionedObjects->removeRef(it.current());
1364             ++it;
1365         }
1366     }
1367 }
1368
1369 void RenderBlock::insertFloatingObject(RenderObject *o)
1370 {
1371     // Create the list of special objects if we don't aleady have one
1372     if (!m_floatingObjects) {
1373         m_floatingObjects = new QPtrList<FloatingObject>;
1374         m_floatingObjects->setAutoDelete(true);
1375     }
1376     else {
1377         // Don't insert the object again if it's already in the list
1378         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1379         FloatingObject* f;
1380         while ( (f = it.current()) ) {
1381             if (f->node == o) return;
1382             ++it;
1383         }
1384     }
1385
1386     // Create the special object entry & append it to the list
1387
1388     FloatingObject *newObj;
1389     if (o->isFloating()) {
1390         // floating object
1391         o->layoutIfNeeded();
1392
1393         if(o->style()->floating() == FLEFT)
1394             newObj = new FloatingObject(FloatingObject::FloatLeft);
1395         else
1396             newObj = new FloatingObject(FloatingObject::FloatRight);
1397
1398         newObj->startY = -1;
1399         newObj->endY = -1;
1400         newObj->width = o->width() + o->marginLeft() + o->marginRight();
1401     }
1402     else {
1403         // We should never get here, as insertFloatingObject() should only ever be called with floating
1404         // objects.
1405         KHTMLAssert(false);
1406         newObj = 0; // keep gcc's uninitialized variable warnings happy
1407     }
1408
1409     newObj->node = o;
1410
1411     m_floatingObjects->append(newObj);
1412 }
1413
1414 void RenderBlock::removeFloatingObject(RenderObject *o)
1415 {
1416     if (m_floatingObjects) {
1417         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1418         while (it.current()) {
1419             if (it.current()->node == o)
1420                 m_floatingObjects->removeRef(it.current());
1421             ++it;
1422         }
1423     }
1424 }
1425
1426 void RenderBlock::positionNewFloats()
1427 {
1428     if(!m_floatingObjects) return;
1429     FloatingObject *f = m_floatingObjects->getLast();
1430     if(!f || f->startY != -1) return;
1431     FloatingObject *lastFloat;
1432     while(1)
1433     {
1434         lastFloat = m_floatingObjects->prev();
1435         if (!lastFloat || lastFloat->startY != -1) {
1436             m_floatingObjects->next();
1437             break;
1438         }
1439         f = lastFloat;
1440     }
1441
1442
1443     int y = m_height;
1444
1445
1446     // the float can not start above the y position of the last positioned float.
1447     if(lastFloat && lastFloat->startY > y)
1448         y = lastFloat->startY;
1449
1450     while(f)
1451     {
1452         //skip elements copied from elsewhere and positioned elements
1453         if (f->node->containingBlock()!=this)
1454         {
1455             f = m_floatingObjects->next();
1456             continue;
1457         }
1458
1459         RenderObject *o = f->node;
1460         int _height = o->height() + o->marginTop() + o->marginBottom();
1461
1462         int ro = rightOffset(); // Constant part of right offset.
1463         int lo = leftOffset(); // Constat part of left offset.
1464         int fwidth = f->width; // The width we look for.
1465                                //kdDebug( 6040 ) << " Object width: " << fwidth << " available width: " << ro - lo << endl;
1466         if (ro - lo < fwidth)
1467             fwidth = ro - lo; // Never look for more than what will be available.
1468         if (o->style()->floating() == FLEFT)
1469         {
1470             if ( o->style()->clear() & CLEFT )
1471                 y = QMAX( leftBottom(), y );
1472             int heightRemainingLeft = 1;
1473             int heightRemainingRight = 1;
1474             int fx = leftRelOffset(y,lo, false, &heightRemainingLeft);
1475             while (rightRelOffset(y,ro, false, &heightRemainingRight)-fx < fwidth)
1476             {
1477                 y += QMIN( heightRemainingLeft, heightRemainingRight );
1478                 fx = leftRelOffset(y,lo, false, &heightRemainingLeft);
1479             }
1480             if (fx<0) fx=0;
1481             f->left = fx;
1482             //kdDebug( 6040 ) << "positioning left aligned float at (" << fx + o->marginLeft()  << "/" << y + o->marginTop() << ") fx=" << fx << endl;
1483             o->setPos(fx + o->marginLeft(), y + o->marginTop());
1484         }
1485         else
1486         {
1487             if ( o->style()->clear() & CRIGHT )
1488                 y = QMAX( rightBottom(), y );
1489             int heightRemainingLeft = 1;
1490             int heightRemainingRight = 1;
1491             int fx = rightRelOffset(y,ro, false, &heightRemainingRight);
1492             while (fx - leftRelOffset(y,lo, false, &heightRemainingLeft) < fwidth)
1493             {
1494                 y += QMIN(heightRemainingLeft, heightRemainingRight);
1495                 fx = rightRelOffset(y,ro, false, &heightRemainingRight);
1496             }
1497             if (fx<f->width) fx=f->width;
1498             f->left = fx - f->width;
1499             //kdDebug( 6040 ) << "positioning right aligned float at (" << fx - o->marginRight() - o->width() << "/" << y + o->marginTop() << ")" << endl;
1500             o->setPos(fx - o->marginRight() - o->width(), y + o->marginTop());
1501         }
1502         f->startY = y;
1503         f->endY = f->startY + _height;
1504
1505
1506         //kdDebug( 6040 ) << "floatingObject x/y= (" << f->left << "/" << f->startY << "-" << f->width << "/" << f->endY - f->startY << ")" << endl;
1507
1508         f = m_floatingObjects->next();
1509     }
1510 }
1511
1512 void RenderBlock::newLine()
1513 {
1514     positionNewFloats();
1515     // set y position
1516     int newY = 0;
1517     switch(m_clearStatus)
1518     {
1519         case CLEFT:
1520             newY = leftBottom();
1521             break;
1522         case CRIGHT:
1523             newY = rightBottom();
1524             break;
1525         case CBOTH:
1526             newY = floatBottom();
1527         default:
1528             break;
1529     }
1530     if(m_height < newY)
1531     {
1532         //      kdDebug( 6040 ) << "adjusting y position" << endl;
1533         m_height = newY;
1534     }
1535     m_clearStatus = CNONE;
1536 }
1537
1538 int
1539 RenderBlock::leftOffset() const
1540 {
1541     return borderLeft()+paddingLeft();
1542 }
1543
1544 int
1545 RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent,
1546                            int *heightRemaining ) const
1547 {
1548     int left = fixedOffset;
1549     if (m_floatingObjects) {
1550         if ( heightRemaining ) *heightRemaining = 1;
1551         FloatingObject* r;
1552         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1553         for ( ; (r = it.current()); ++it )
1554         {
1555             //kdDebug( 6040 ) <<(void *)this << " left: sy, ey, x, w " << r->startY << "," << r->endY << "," << r->left << "," << r->width << " " << endl;
1556             if (r->startY <= y && r->endY > y &&
1557                 r->type == FloatingObject::FloatLeft &&
1558                 r->left + r->width > left) {
1559                 left = r->left + r->width;
1560                 if ( heightRemaining ) *heightRemaining = r->endY - y;
1561             }
1562         }
1563     }
1564
1565     if (applyTextIndent && m_firstLine && style()->direction() == LTR) {
1566         int cw=0;
1567         if (style()->textIndent().isPercent())
1568             cw = containingBlock()->contentWidth();
1569         left += style()->textIndent().minWidth(cw);
1570     }
1571
1572     //kdDebug( 6040 ) << "leftOffset(" << y << ") = " << left << endl;
1573     return left;
1574 }
1575
1576 int
1577 RenderBlock::rightOffset() const
1578 {
1579     int right = m_width - borderRight() - paddingRight();
1580     if (style()->scrollsOverflow() && m_layer)
1581         right -= m_layer->verticalScrollbarWidth();
1582     return right;
1583 }
1584
1585 int
1586 RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent,
1587                             int *heightRemaining ) const
1588 {
1589     int right = fixedOffset;
1590
1591     if (m_floatingObjects) {
1592         if (heightRemaining) *heightRemaining = 1;
1593         FloatingObject* r;
1594         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1595         for ( ; (r = it.current()); ++it )
1596         {
1597             //kdDebug( 6040 ) << "right: sy, ey, x, w " << r->startY << "," << r->endY << "," << r->left << "," << r->width << " " << endl;
1598             if (r->startY <= y && r->endY > y &&
1599                 r->type == FloatingObject::FloatRight &&
1600                 r->left < right) {
1601                 right = r->left;
1602                 if ( heightRemaining ) *heightRemaining = r->endY - y;
1603             }
1604         }
1605     }
1606     
1607     if (applyTextIndent && m_firstLine && style()->direction() == RTL) {
1608         int cw=0;
1609         if (style()->textIndent().isPercent())
1610             cw = containingBlock()->contentWidth();
1611         right += style()->textIndent().minWidth(cw);
1612     }
1613     
1614     //kdDebug( 6040 ) << "rightOffset(" << y << ") = " << right << endl;
1615     return right;
1616 }
1617
1618 unsigned short
1619 RenderBlock::lineWidth(int y) const
1620 {
1621     //kdDebug( 6040 ) << "lineWidth(" << y << ")=" << rightOffset(y) - leftOffset(y) << endl;
1622     int result = rightOffset(y) - leftOffset(y);
1623     return (result < 0) ? 0 : result;
1624 }
1625
1626 int
1627 RenderBlock::nearestFloatBottom(int height) const
1628 {
1629     if (!m_floatingObjects) return 0;
1630     int bottom = 0;
1631     FloatingObject* r;
1632     QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1633     for ( ; (r = it.current()); ++it )
1634         if (r->endY>height && (r->endY<bottom || bottom==0))
1635             bottom=r->endY;
1636     return QMAX(bottom, height);
1637 }
1638
1639 int
1640 RenderBlock::floatBottom() const
1641 {
1642     if (!m_floatingObjects) return 0;
1643     int bottom=0;
1644     FloatingObject* r;
1645     QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1646     for ( ; (r = it.current()); ++it )
1647         if (r->endY>bottom)
1648             bottom=r->endY;
1649     return bottom;
1650 }
1651
1652 int
1653 RenderBlock::lowestPosition(bool includeOverflowInterior) const
1654 {
1655     int bottom = RenderFlow::lowestPosition(includeOverflowInterior);
1656     if (!includeOverflowInterior && style()->hidesOverflow())
1657         return bottom;
1658     if (m_overflowHeight > bottom)
1659         bottom = m_overflowHeight;
1660     
1661     if (m_floatingObjects) {
1662         FloatingObject* r;
1663         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1664         for ( ; (r = it.current()); ++it ) {
1665             if (!r->noPaint) {
1666                 int lp = r->startY + r->node->lowestPosition(false);
1667                 bottom = QMAX(bottom, lp);
1668             }
1669         }
1670     }
1671
1672     // Fixed positioned objects do not scroll and thus should not constitute
1673     // part of the lowest position.
1674     if (m_positionedObjects && !isCanvas()) {
1675         RenderObject* r;
1676         QPtrListIterator<RenderObject> it(*m_positionedObjects);
1677         for ( ; (r = it.current()); ++it ) {
1678             int lp = r->yPos() + r->lowestPosition(false);
1679             bottom = QMAX(bottom, lp);
1680         }
1681     }
1682
1683     return bottom;
1684 }
1685
1686 int RenderBlock::rightmostPosition(bool includeOverflowInterior) const
1687 {
1688     int right = RenderFlow::rightmostPosition(includeOverflowInterior);
1689     if (!includeOverflowInterior && style()->hidesOverflow())
1690         return right;
1691     if (m_overflowWidth > right)
1692         right = m_overflowWidth;
1693     
1694     if (m_floatingObjects) {
1695         FloatingObject* r;
1696         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1697         for ( ; (r = it.current()); ++it ) {
1698             if (!r->noPaint) {
1699                 int rp = r->left + r->node->rightmostPosition(false);
1700                 right = QMAX(right, rp);
1701             }
1702         }
1703     }
1704
1705     if (m_positionedObjects && !isCanvas()) {
1706         RenderObject* r;
1707         QPtrListIterator<RenderObject> it(*m_positionedObjects);
1708         for ( ; (r = it.current()); ++it ) {
1709             int rp = r->xPos() + r->rightmostPosition(false);
1710             right = QMAX(right, rp);
1711         }
1712     }
1713
1714     return right;
1715 }
1716
1717
1718 int
1719 RenderBlock::leftBottom()
1720 {
1721     if (!m_floatingObjects) return 0;
1722     int bottom=0;
1723     FloatingObject* r;
1724     QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1725     for ( ; (r = it.current()); ++it )
1726         if (r->endY>bottom && r->type == FloatingObject::FloatLeft)
1727             bottom=r->endY;
1728
1729     return bottom;
1730 }
1731
1732 int
1733 RenderBlock::rightBottom()
1734 {
1735     if (!m_floatingObjects) return 0;
1736     int bottom=0;
1737     FloatingObject* r;
1738     QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1739     for ( ; (r = it.current()); ++it )
1740         if (r->endY>bottom && r->type == FloatingObject::FloatRight)
1741             bottom=r->endY;
1742
1743     return bottom;
1744 }
1745
1746 void
1747 RenderBlock::clearFloats()
1748 {
1749     if (m_floatingObjects)
1750         m_floatingObjects->clear();
1751
1752     if (isFloating() || isPositioned()) return;
1753     
1754     RenderObject *prev = previousSibling();
1755
1756     // find the element to copy the floats from
1757     // pass non-flows
1758     // pass fAF's unless they contain overhanging stuff
1759     bool parentHasFloats = false;
1760     while (prev) {
1761         if (!prev->isRenderBlock() || prev->isFloating() || prev->isPositioned() ||
1762             prev->style()->hidesOverflow() || prev->isFlexibleBox() ||
1763             (prev->style()->flowAroundFloats() &&
1764              // A <table> or <ul> can have a height of 0, so its ypos may be the same
1765              // as m_y.  That's why we have a <= and not a < here. -dwh
1766              (static_cast<RenderBlock *>(prev)->floatBottom()+prev->yPos() <= m_y ))) {
1767             if ( prev->isFloating() && parent()->isRenderBlock() ) {
1768                 parentHasFloats = true;
1769             }
1770             prev = prev->previousSibling();
1771         } else
1772             break;
1773     }
1774
1775     int offset = m_y;
1776     if (parentHasFloats)
1777         addOverHangingFloats( static_cast<RenderBlock *>( parent() ),
1778                               parent()->borderLeft() + parent()->paddingLeft(), offset, false );
1779
1780     int xoffset = 0;
1781     if (prev) {
1782         if(prev->isTableCell()) return;
1783         offset -= prev->yPos();
1784     } else {
1785         prev = parent();
1786         if(!prev) return;
1787         xoffset += prev->borderLeft() + prev->paddingLeft();
1788     }
1789     //kdDebug() << "RenderBlock::clearFloats found previous "<< (void *)this << " prev=" << (void *)prev<< endl;
1790
1791     // add overhanging special objects from the previous RenderBlock
1792     if(!prev->isRenderBlock()) return;
1793     RenderBlock * flow = static_cast<RenderBlock *>(prev);
1794     if(!flow->m_floatingObjects) return;
1795     if (style()->hidesOverflow() || isFlexibleBox() ||
1796         (( style()->htmlHacks() || isTable()) && style()->flowAroundFloats()))
1797         return; // these elements don't allow floats from previous blocks to intrude into their space.
1798
1799     if(flow->floatBottom() > offset)
1800         addOverHangingFloats( flow, xoffset, offset );
1801 }
1802
1803 void RenderBlock::addOverHangingFloats( RenderBlock *flow, int xoff, int offset, bool child )
1804 {
1805 #ifdef DEBUG_LAYOUT
1806     kdDebug( 6040 ) << (void *)this << ": adding overhanging floats xoff=" << xoff << "  offset=" << offset << " child=" << child << endl;
1807 #endif
1808
1809     // Prevent floats from being added to the canvas by the root element, e.g., <html>.
1810     if ( !flow->m_floatingObjects || (child && flow->isRoot()) )
1811         return;
1812
1813     // we have overhanging floats
1814     if (!m_floatingObjects) {
1815         m_floatingObjects = new QPtrList<FloatingObject>;
1816         m_floatingObjects->setAutoDelete(true);
1817     }
1818
1819     QPtrListIterator<FloatingObject> it(*flow->m_floatingObjects);
1820     FloatingObject *r;
1821     for ( ; (r = it.current()); ++it ) {
1822         if ( ( !child && r->endY > offset ) ||
1823              ( child && flow->yPos() + r->endY > height() ) ) {
1824
1825             if (child && (flow->enclosingLayer() == enclosingLayer()))
1826                 // Set noPaint to true only if we didn't cross layers.
1827                 r->noPaint = true;
1828
1829             FloatingObject* f = 0;
1830             // don't insert it twice!
1831             QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1832             while ( (f = it.current()) ) {
1833                 if (f->node == r->node) break;
1834                 ++it;
1835             }
1836             if ( !f ) {
1837                 FloatingObject *floatingObj = new FloatingObject(r->type);
1838                 floatingObj->startY = r->startY - offset;
1839                 floatingObj->endY = r->endY - offset;
1840                 floatingObj->left = r->left - xoff;
1841                 // Applying the child's margin makes no sense in the case where the child was passed in.
1842                 // since his own margin was added already through the subtraction of the |xoff| variable
1843                 // above.  |xoff| will equal -flow->marginLeft() in this case, so it's already been taken
1844                 // into account.  Only apply this code if |child| is false, since otherwise the left margin
1845                 // will get applied twice. -dwh
1846                 if (!child && flow != parent())
1847                     floatingObj->left += flow->marginLeft();
1848                 if ( !child ) {
1849                     floatingObj->left -= marginLeft();
1850                     floatingObj->noPaint = true;
1851                 }
1852                 else
1853                     // Only paint if |flow| isn't.
1854                     floatingObj->noPaint = !r->noPaint;
1855                 
1856                 floatingObj->width = r->width;
1857                 floatingObj->node = r->node;
1858                 m_floatingObjects->append(floatingObj);
1859 #ifdef DEBUG_LAYOUT
1860                 kdDebug( 6040 ) << "addOverHangingFloats x/y= (" << floatingObj->left << "/" << floatingObj->startY << "-" << floatingObj->width << "/" << floatingObj->endY - floatingObj->startY << ")" << endl;
1861 #endif
1862             }
1863         }
1864     }
1865 }
1866
1867 bool RenderBlock::containsFloat(RenderObject* o)
1868 {
1869     if (m_floatingObjects) {
1870         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1871         while (it.current()) {
1872             if (it.current()->node == o)
1873                 return true;
1874             ++it;
1875         }
1876     }
1877     return false;
1878 }
1879
1880 void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove)
1881 {
1882     setNeedsLayout(true);
1883
1884     if (floatToRemove)
1885         removeFloatingObject(floatToRemove);
1886
1887     // Iterate over our children and mark them as needed.
1888     if (!childrenInline()) {
1889         for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1890             if (isBlockFlow() && !child->isFloatingOrPositioned() &&
1891                 (floatToRemove ? child->containsFloat(floatToRemove) : child->containsFloats()))
1892                 child->markAllDescendantsWithFloatsForLayout(floatToRemove);
1893         }
1894     }
1895 }
1896
1897 int RenderBlock::getClearDelta(RenderObject *child)
1898 {
1899     //kdDebug( 6040 ) << "checkClear oldheight=" << m_height << endl;
1900     int bottom = 0;
1901     switch(child->style()->clear())
1902     {
1903         case CNONE:
1904             return 0;
1905         case CLEFT:
1906             bottom = leftBottom();
1907             break;
1908         case CRIGHT:
1909             bottom = rightBottom();
1910             break;
1911         case CBOTH:
1912             bottom = floatBottom();
1913             break;
1914     }
1915
1916     return QMAX(0, bottom-(child->yPos()));
1917 }
1918
1919 bool RenderBlock::isPointInScrollbar(int _x, int _y, int _tx, int _ty)
1920 {
1921     if (!style()->scrollsOverflow() || !m_layer)
1922         return false;
1923
1924     if (m_layer->verticalScrollbarWidth()) {
1925         QRect vertRect(_tx + width() - borderRight() - m_layer->verticalScrollbarWidth(),
1926                        _ty + borderTop(),
1927                        m_layer->verticalScrollbarWidth(),
1928                        height()-borderTop()-borderBottom());
1929         if (vertRect.contains(_x, _y)) {
1930             RenderLayer::gScrollBar = m_layer->verticalScrollbar();
1931             return true;
1932         }
1933     }
1934
1935     if (m_layer->horizontalScrollbarHeight()) {
1936         QRect horizRect(_tx + borderLeft(),
1937                         _ty + height() - borderBottom() - m_layer->horizontalScrollbarHeight(),
1938                         width()-borderLeft()-borderRight(),
1939                         m_layer->horizontalScrollbarHeight());
1940         if (horizRect.contains(_x, _y)) {
1941             RenderLayer::gScrollBar = m_layer->horizontalScrollbar();
1942             return true;
1943         }
1944     }
1945
1946     return false;    
1947 }
1948
1949 bool RenderBlock::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
1950                               HitTestAction hitTestAction, bool inBox)
1951 {
1952     bool inScrollbar = isPointInScrollbar(_x, _y, _tx+xPos(), _ty+yPos());
1953     if (inScrollbar && hitTestAction != HitTestChildrenOnly)
1954         inBox = true;
1955     
1956     if (hitTestAction != HitTestSelfOnly && m_floatingObjects && !inScrollbar) {
1957         int stx = _tx + xPos();
1958         int sty = _ty + yPos();
1959         if (style()->hidesOverflow() && m_layer)
1960             m_layer->subtractScrollOffset(stx, sty);
1961         if (isCanvas()) {
1962             stx += static_cast<RenderCanvas*>(this)->view()->contentsX();
1963             sty += static_cast<RenderCanvas*>(this)->view()->contentsY();
1964         }
1965         FloatingObject* o;
1966         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
1967         for (it.toLast(); (o = it.current()); --it)
1968             if (!o->noPaint && !o->node->layer())
1969                 inBox |= o->node->nodeAtPoint(info, _x, _y,
1970                                               stx+o->left + o->node->marginLeft() - o->node->xPos(),
1971                                               sty+o->startY + o->node->marginTop() - o->node->yPos());
1972     }
1973
1974     inBox |= RenderFlow::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inBox);
1975     return inBox;
1976 }
1977
1978 void RenderBlock::calcMinMaxWidth()
1979 {
1980     KHTMLAssert( !minMaxKnown() );
1981
1982 #ifdef DEBUG_LAYOUT
1983     kdDebug( 6040 ) << renderName() << "(RenderBlock)::calcMinMaxWidth() this=" << this << endl;
1984 #endif
1985
1986     m_minWidth = 0;
1987     m_maxWidth = 0;
1988
1989     bool preOrNowrap = style()->whiteSpace() != NORMAL;
1990     if (childrenInline())
1991         calcInlineMinMaxWidth();
1992     else
1993         calcBlockMinMaxWidth();
1994
1995     if(m_maxWidth < m_minWidth) m_maxWidth = m_minWidth;
1996
1997     if (preOrNowrap && childrenInline())
1998         m_minWidth = m_maxWidth;
1999
2000     if (style()->width().isFixed() && style()->width().value > 0) {
2001         m_maxWidth = KMAX(m_minWidth,short(style()->width().value));
2002         if (!isTableCell())
2003             m_minWidth = m_maxWidth;
2004     }
2005     // FIXME: also compare with min/max width CSS properties...
2006     
2007     int toAdd = 0;
2008     toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight();
2009
2010     m_minWidth += toAdd;
2011     m_maxWidth += toAdd;
2012
2013     // Scrolling marquees like to use this trick:
2014     // <td><div style="overflow:hidden; width:300px"><nobr>.....[lots of text].....</nobr></div></td>
2015     // We need to sanity-check our m_minWidth, and not let it exceed our clipped boundary. -dwh
2016     // FIXME: For now, punt on trying to apply this fix to table cells.  We don't know an accurate
2017     // width for the cell here, so we can't do a comparison.
2018     if (style()->hidesOverflow() && m_minWidth > m_width && !isTableCell())
2019         m_minWidth = m_width;
2020
2021     setMinMaxKnown();
2022
2023     //kdDebug( 6040 ) << "Text::calcMinMaxWidth(" << this << "): min = " << m_minWidth << " max = " << m_maxWidth << endl;
2024 }
2025
2026 struct InlineMinMaxIterator
2027 {
2028 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
2029    inline min/max width calculations.  Note the following about the way it walks:
2030    (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
2031    (2) We do not drill into the children of floats or replaced elements, since you can't break
2032        in the middle of such an element.
2033    (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
2034        distinct borders/margin/padding that contribute to the min/max width.
2035 */
2036     RenderObject* parent;
2037     RenderObject* current;
2038     bool endOfInline;
2039
2040     InlineMinMaxIterator(RenderObject* p, RenderObject* o, bool end = false)
2041         :parent(p), current(o), endOfInline(end) {}
2042
2043     RenderObject* next();
2044 };
2045
2046 RenderObject* InlineMinMaxIterator::next()
2047 {
2048     RenderObject* result = 0;
2049     bool oldEndOfInline = endOfInline;
2050     endOfInline = false;
2051     while (current != 0 || (current == parent))
2052     {
2053         //kdDebug( 6040 ) << "current = " << current << endl;
2054         if (!oldEndOfInline &&
2055             (current == parent ||
2056              (!current->isFloating() && !current->isReplaced() && !current->isPositioned())))
2057             result = current->firstChild();
2058         if (!result) {
2059             // We hit the end of our inline. (It was empty, e.g., <span></span>.)
2060             if (!oldEndOfInline && current->isInlineFlow()) {
2061                 result = current;
2062                 endOfInline = true;
2063                 break;
2064             }
2065
2066             while (current && current != parent) {
2067                 result = current->nextSibling();
2068                 if (result) break;
2069                 current = current->parent();
2070                 if (current && current != parent && current->isInlineFlow()) {
2071                     result = current;
2072                     endOfInline = true;
2073                     break;
2074                 }
2075             }
2076         }
2077
2078         if (!result) break;
2079
2080         if (result->isText() || result->isBR() ||
2081             result->isFloating() || result->isReplaced() ||
2082             result->isInlineFlow())
2083             break;
2084         
2085         current = result;
2086         result = 0;
2087     }
2088
2089     // Update our position.
2090     current = result;
2091     return current;
2092 }
2093
2094 static int getBPMWidth(int childValue, Length cssUnit)
2095 {
2096     if (cssUnit.type != Variable)
2097         return (cssUnit.type == Fixed ? cssUnit.value : childValue);
2098     return 0;
2099 }
2100
2101 static int getBorderPaddingMargin(RenderObject* child, bool endOfInline)
2102 {
2103     RenderStyle* cstyle = child->style();
2104     int result = 0;
2105     bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline;
2106     result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()),
2107                           (leftSide ? cstyle->marginLeft() :
2108                                       cstyle->marginRight()));
2109     result += getBPMWidth((leftSide ? child->paddingLeft() : child->paddingRight()),
2110                           (leftSide ? cstyle->paddingLeft() :
2111                                       cstyle->paddingRight()));
2112     result += leftSide ? child->borderLeft() : child->borderRight();
2113     return result;
2114 }
2115
2116 static void stripTrailingSpace(bool pre,
2117                                int& inlineMax, int& inlineMin,
2118                                RenderObject* trailingSpaceChild)
2119 {
2120     if (!pre && trailingSpaceChild && trailingSpaceChild->isText()) {
2121         // Collapse away the trailing space at the end of a block.
2122         RenderText* t = static_cast<RenderText *>(trailingSpaceChild);
2123         const Font *f = t->htmlFont( false );
2124         QChar space[1]; space[0] = ' ';
2125         int spaceWidth = f->width(space, 1, 0);
2126         inlineMax -= spaceWidth;
2127         if (inlineMin > inlineMax)
2128             inlineMin = inlineMax;
2129     }
2130 }
2131
2132 void RenderBlock::calcInlineMinMaxWidth()
2133 {
2134     int inlineMax=0;
2135     int inlineMin=0;
2136
2137     int cw = containingBlock()->contentWidth();
2138
2139     // If we are at the start of a line, we want to ignore all white-space.
2140     // Also strip spaces if we previously had text that ended in a trailing space.
2141     bool stripFrontSpaces = true;
2142     RenderObject* trailingSpaceChild = 0;
2143
2144     bool normal, oldnormal;
2145     normal = oldnormal = style()->whiteSpace() == NORMAL;
2146
2147     InlineMinMaxIterator childIterator(this, this);
2148     bool addedTextIndent = false; // Only gets added in once.
2149     while (RenderObject* child = childIterator.next())
2150     {
2151         normal = child->style()->whiteSpace() == NORMAL;
2152
2153         if( !child->isBR() )
2154         {
2155             // Step One: determine whether or not we need to go ahead and
2156             // terminate our current line.  Each discrete chunk can become
2157             // the new min-width, if it is the widest chunk seen so far, and
2158             // it can also become the max-width.
2159
2160             // Children fall into three categories:
2161             // (1) An inline flow object.  These objects always have a min/max of 0,
2162             // and are included in the iteration solely so that their margins can
2163             // be added in.
2164             //
2165             // (2) An inline non-text non-flow object, e.g., an inline replaced element.
2166             // These objects can always be on a line by themselves, so in this situation
2167             // we need to go ahead and break the current line, and then add in our own
2168             // margins and min/max width on its own line, and then terminate the line.
2169             //
2170             // (3) A text object.  Text runs can have breakable characters at the start,
2171             // the middle or the end.  They may also lose whitespace off the front if
2172             // we're already ignoring whitespace.  In order to compute accurate min-width
2173             // information, we need three pieces of information.
2174             // (a) the min-width of the first non-breakable run.  Should be 0 if the text string
2175             // starts with whitespace.
2176             // (b) the min-width of the last non-breakable run. Should be 0 if the text string
2177             // ends with whitespace.
2178             // (c) the min/max width of the string (trimmed for whitespace).
2179             //
2180             // If the text string starts with whitespace, then we need to go ahead and
2181             // terminate our current line (unless we're already in a whitespace stripping
2182             // mode.
2183             //
2184             // If the text string has a breakable character in the middle, but didn't start
2185             // with whitespace, then we add the width of the first non-breakable run and
2186             // then end the current line.  We then need to use the intermediate min/max width
2187             // values (if any of them are larger than our current min/max).  We then look at
2188             // the width of the last non-breakable run and use that to start a new line
2189             // (unless we end in whitespace).
2190             RenderStyle* cstyle = child->style();
2191             short childMin = 0;
2192             short childMax = 0;
2193
2194             if (!child->isText()) {
2195                 // Case (1) and (2).  Inline replaced and inline flow elements.
2196                 if (child->isInlineFlow()) {
2197                     // Add in padding/border/margin from the appropriate side of
2198                     // the element.
2199                     int bpm = getBorderPaddingMargin(child, childIterator.endOfInline);
2200                     childMin += bpm;
2201                     childMax += bpm;
2202
2203                     inlineMin += childMin;
2204                     inlineMax += childMax;
2205                 }
2206                 else {
2207                     // Inline replaced elts add in their margins to their min/max values.
2208                     int margins = 0;
2209                     LengthType type = cstyle->marginLeft().type;
2210                     if ( type != Variable )
2211                         margins += (type == Fixed ? cstyle->marginLeft().value : child->marginLeft());
2212                     type = cstyle->marginRight().type;
2213                     if ( type != Variable )
2214                         margins += (type == Fixed ? cstyle->marginRight().value : child->marginRight());
2215                     childMin += margins;
2216                     childMax += margins;
2217                 }
2218             }
2219
2220             if (!child->isRenderInline() && !child->isText()) {
2221                 // Case (2). Inline replaced elements and floats.
2222                 // Go ahead and terminate the current line as far as
2223                 // minwidth is concerned.
2224                 childMin += child->minWidth();
2225                 childMax += child->maxWidth();
2226
2227                 if (normal || oldnormal) {
2228                     if(m_minWidth < inlineMin) m_minWidth = inlineMin;
2229                     inlineMin = 0;
2230                 }
2231
2232                 // Add in text-indent.  This is added in only once.
2233                 int ti = 0;
2234                 if (!addedTextIndent) {
2235                     addedTextIndent = true;
2236                     ti = style()->textIndent().minWidth(cw);
2237                     childMin+=ti;
2238                     childMax+=ti;
2239                 }
2240                 
2241                 // Add our width to the max.
2242                 inlineMax += childMax;
2243
2244                 if (!normal)
2245                     inlineMin += childMin;
2246                 else {
2247                     // Now check our line.
2248                     inlineMin = childMin;
2249                     if(m_minWidth < inlineMin) m_minWidth = inlineMin;
2250
2251                     // Now start a new line.
2252                     inlineMin = 0;
2253                 }
2254
2255                 // We are no longer stripping whitespace at the start of
2256                 // a line.
2257                 if (!child->isFloating()) {
2258                     stripFrontSpaces = false;
2259                     trailingSpaceChild = 0;
2260                 }
2261             }
2262             else if (child->isText())
2263             {
2264                 // Case (3). Text.
2265                 RenderText* t = static_cast<RenderText *>(child);
2266
2267                 // Determine if we have a breakable character.  Pass in
2268                 // whether or not we should ignore any spaces at the front
2269                 // of the string.  If those are going to be stripped out,
2270                 // then they shouldn't be considered in the breakable char
2271                 // check.
2272                 bool hasBreakableChar, hasBreak;
2273                 short beginMin, endMin;
2274                 bool beginWS, endWS;
2275                 short beginMax, endMax;
2276                 t->trimmedMinMaxWidth(beginMin, beginWS, endMin, endWS, hasBreakableChar,
2277                                       hasBreak, beginMax, endMax,
2278                                       childMin, childMax, stripFrontSpaces);
2279
2280                 // This text object is insignificant and will not be rendered.  Just
2281                 // continue.
2282                 if (!hasBreak && childMax == 0) continue;
2283                 
2284                 if (stripFrontSpaces)
2285                     trailingSpaceChild = child;
2286                 else
2287                     trailingSpaceChild = 0;
2288
2289                 // Add in text-indent.  This is added in only once.
2290                 int ti = 0;
2291                 if (!addedTextIndent) {
2292                     addedTextIndent = true;
2293                     ti = style()->textIndent().minWidth(cw);
2294                     childMin+=ti; beginMin += ti;
2295                     childMax+=ti; beginMax += ti;
2296                 }
2297                 
2298                 // If we have no breakable characters at all,
2299                 // then this is the easy case. We add ourselves to the current
2300                 // min and max and continue.
2301                 if (!hasBreakableChar) {
2302                     inlineMin += childMin;
2303                 }
2304                 else {
2305                     // We have a breakable character.  Now we need to know if
2306                     // we start and end with whitespace.
2307                     if (beginWS) {
2308                         // Go ahead and end the current line.
2309                         if(m_minWidth < inlineMin) m_minWidth = inlineMin;
2310                     }
2311                     else {
2312                         inlineMin += beginMin;
2313                         if(m_minWidth < inlineMin) m_minWidth = inlineMin;
2314                         childMin -= ti;
2315                     }
2316
2317                     inlineMin = childMin;
2318
2319                     if (endWS) {
2320                         // We end in whitespace, which means we can go ahead
2321                         // and end our current line.
2322                         if(m_minWidth < inlineMin) m_minWidth = inlineMin;
2323                         inlineMin = 0;
2324                     }
2325                     else {
2326                         if(m_minWidth < inlineMin) m_minWidth = inlineMin;
2327                         inlineMin = endMin;
2328                     }
2329                 }
2330
2331                 if (hasBreak) {
2332                     inlineMax += beginMax;
2333                     if (m_maxWidth < inlineMax) m_maxWidth = inlineMax;
2334                     if (m_maxWidth < childMax) m_maxWidth = childMax;
2335                     inlineMax = endMax;
2336                 }
2337                 else
2338                     inlineMax += childMax;
2339             }
2340         }
2341         else
2342         {
2343             if(m_minWidth < inlineMin) m_minWidth = inlineMin;
2344             if(m_maxWidth < inlineMax) m_maxWidth = inlineMax;
2345             inlineMin = inlineMax = 0;
2346             stripFrontSpaces = true;
2347             trailingSpaceChild = 0;
2348         }
2349
2350         oldnormal = normal;
2351     }
2352
2353     stripTrailingSpace(m_pre, inlineMax, inlineMin, trailingSpaceChild);
2354     
2355     if(m_minWidth < inlineMin) m_minWidth = inlineMin;
2356     if(m_maxWidth < inlineMax) m_maxWidth = inlineMax;
2357     //         kdDebug( 6040 ) << "m_minWidth=" << m_minWidth
2358     //                  << " m_maxWidth=" << m_maxWidth << endl;
2359 }
2360
2361 // Use a very large value (in effect infinite).
2362 #define BLOCK_MAX_WIDTH 15000
2363
2364 void RenderBlock::calcBlockMinMaxWidth()
2365 {
2366     bool nowrap = style()->whiteSpace() == NOWRAP;
2367
2368     RenderObject *child = firstChild();
2369     while(child != 0)
2370     {
2371         // Positioned children don't affect the min/max width
2372         if (child->isPositioned()) {
2373             child = child->nextSibling();
2374             continue;
2375         }
2376
2377         Length ml = child->style()->marginLeft();
2378         Length mr = child->style()->marginRight();
2379
2380         // Call calcWidth on the child to ensure that our margins are
2381         // up to date.  This method can be called before the child has actually
2382         // calculated its margins (which are computed inside calcWidth).
2383         if (ml.type == Percent || mr.type == Percent)
2384             calcWidth();
2385
2386         // A margin basically has three types: fixed, percentage, and auto (variable).
2387         // Auto margins simply become 0 when computing min/max width.
2388         // Fixed margins can be added in as is.
2389         // Percentage margins are computed as a percentage of the width we calculated in
2390         // the calcWidth call above.  In this case we use the actual cached margin values on
2391         // the RenderObject itself.
2392         int margin = 0;
2393         if (ml.type == Fixed)
2394             margin += ml.value;
2395         else if (ml.type == Percent)
2396             margin += child->marginLeft();
2397
2398         if (mr.type == Fixed)
2399             margin += mr.value;
2400         else if (mr.type == Percent)
2401             margin += child->marginRight();
2402         
2403         if (margin < 0) margin = 0;
2404
2405         int w = child->minWidth() + margin;
2406         if(m_minWidth < w) m_minWidth = w;
2407         // IE ignores tables for calculation of nowrap. Makes some sense.
2408         if ( nowrap && !child->isTable() && m_maxWidth < w )
2409             m_maxWidth = w;
2410
2411         w = child->maxWidth() + margin;
2412
2413         if(m_maxWidth < w) m_maxWidth = w;
2414
2415         // A very specific WinIE quirk.
2416         // Example:
2417         /*
2418            <div style="position:absolute; width:100px; top:50px;">
2419               <div style="position:absolute;left:0px;top:50px;height:50px;background-color:green">
2420                 <table style="width:100%"><tr><td></table>
2421               </div>
2422            </div>
2423         */
2424         // In the above example, the inner absolute positioned block should have a computed width
2425         // of 100px because of the table.
2426         // We can achieve this effect by making the maxwidth of blocks that contain tables
2427         // with percentage widths be infinite (as long as they are not inside a table cell).
2428         if (style()->htmlHacks() && child->style()->width().type == Percent &&
2429             !isTableCell() && child->isTable() && m_maxWidth < BLOCK_MAX_WIDTH) {
2430             RenderBlock* cb = containingBlock();
2431             while (!cb->isCanvas() && !cb->isTableCell())
2432                 cb = cb->containingBlock();
2433             if (!cb->isTableCell())
2434                 m_maxWidth = BLOCK_MAX_WIDTH;
2435         }
2436         
2437         child = child->nextSibling();
2438     }
2439 }
2440
2441 short RenderBlock::lineHeight(bool b, bool isRootLineBox) const
2442 {
2443     // Inline blocks are replaced elements. Otherwise, just pass off to
2444     // the base class.  If we're being queried as though we're the root line
2445     // box, then the fact that we're an inline-block is irrelevant, and we behave
2446     // just like a block.
2447     if (isReplaced() && !isRootLineBox)
2448         return height()+marginTop()+marginBottom();
2449     return RenderFlow::lineHeight(b, isRootLineBox);
2450 }
2451
2452 short RenderBlock::baselinePosition(bool b, bool isRootLineBox) const
2453 {
2454     // Inline blocks are replaced elements. Otherwise, just pass off to
2455     // the base class.  If we're being queried as though we're the root line
2456     // box, then the fact that we're an inline-block is irrelevant, and we behave
2457     // just like a block.
2458     if (isReplaced() && !isRootLineBox)
2459         return height()+marginTop()+marginBottom();
2460     return RenderFlow::baselinePosition(b, isRootLineBox);
2461 }
2462
2463 int RenderBlock::getBaselineOfFirstLineBox()
2464 {
2465     if (m_firstLineBox)
2466         return m_firstLineBox->yPos() + m_firstLineBox->baseline();
2467
2468     if (isInline())
2469         return -1; // We're inline and had no line box, so we have no baseline we can return.
2470
2471     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
2472         int result = curr->getBaselineOfFirstLineBox();
2473         if (result != -1)
2474             return curr->yPos() + result; // Translate to our coordinate space.
2475     }
2476
2477     return -1;
2478 }
2479
2480 InlineFlowBox* RenderBlock::getFirstLineBox()
2481 {
2482     if (m_firstLineBox)
2483         return m_firstLineBox;
2484
2485     if (isInline())
2486         return 0; // We're inline and had no line box, so we have no baseline we can return.
2487
2488     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
2489         InlineFlowBox* result = curr->getFirstLineBox();
2490         if (result)
2491             return result;
2492     }
2493
2494     return 0;    
2495 }
2496
2497 const char *RenderBlock::renderName() const
2498 {
2499     if (isBody())
2500         return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass.
2501     
2502     if (isFloating())
2503         return "RenderBlock (floating)";
2504     if (isPositioned())
2505         return "RenderBlock (positioned)";
2506     if (isAnonymousBox())
2507         return "RenderBlock (anonymous)";
2508     if (isRelPositioned())
2509         return "RenderBlock (relative positioned)";
2510     if (isCompact())
2511         return "RenderBlock (compact)";
2512     if (isRunIn())
2513         return "RenderBlock (run-in)";
2514     return "RenderBlock";
2515 }
2516
2517 #ifndef NDEBUG
2518 void RenderBlock::printTree(int indent) const
2519 {
2520     RenderFlow::printTree(indent);
2521
2522     if (m_floatingObjects)
2523     {
2524         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
2525         FloatingObject *r;
2526         for ( ; (r = it.current()); ++it )
2527         {
2528             QString s;
2529             s.fill(' ', indent);
2530             kdDebug() << s << renderName() << ":  " <<
2531                 (r->type == FloatingObject::FloatLeft ? "FloatLeft" : "FloatRight" )  <<
2532                 "[" << r->node->renderName() << ": " << (void*)r->node << "] (" << r->startY << " - " << r->endY << ")" << "width: " << r->width <<
2533                 endl;
2534         }
2535     }
2536 }
2537
2538 void RenderBlock::dump(QTextStream *stream, QString ind) const
2539 {
2540     if (m_childrenInline) { *stream << " childrenInline"; }
2541     if (m_pre) { *stream << " pre"; }
2542     if (m_firstLine) { *stream << " firstLine"; }
2543
2544     if (m_floatingObjects && !m_floatingObjects->isEmpty())
2545     {
2546         *stream << " special(";
2547         QPtrListIterator<FloatingObject> it(*m_floatingObjects);
2548         FloatingObject *r;
2549         bool first = true;
2550         for ( ; (r = it.current()); ++it )
2551         {
2552             if (!first)
2553                 *stream << ",";
2554             *stream << r->node->renderName();
2555             first = false;
2556         }
2557         *stream << ")";
2558     }
2559
2560     // ### EClear m_clearStatus
2561
2562     RenderFlow::dump(stream,ind);
2563 }
2564 #endif
2565
2566 #undef DEBUG
2567 #undef DEBUG_LAYOUT
2568 #undef BOX_DEBUG
2569
2570 } // namespace khtml
2571