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