File indexing completed on 2024-04-28 15:23:55

0001 /*
0002  * This file is part of the render object implementation for KHTML.
0003  *
0004  * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
0005  *           (C) 1999-2003 Antti Koivisto (koivisto@kde.org)
0006  *           (C) 2002-2003 Dirk Mueller (mueller@kde.org)
0007  *           (C) 2003-2009 Apple Computer, Inc.
0008  *           (C) 2004-2009 Germain Garand (germain@ebooksfrance.org)
0009  *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
0010  *           (C) 2006 Charles Samuels (charles@kde.org)
0011  *
0012  * This library is free software; you can redistribute it and/or
0013  * modify it under the terms of the GNU Library General Public
0014  * License as published by the Free Software Foundation; either
0015  * version 2 of the License, or (at your option) any later version.
0016  *
0017  * This library is distributed in the hope that it will be useful,
0018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0020  * Library General Public License for more details.
0021  *
0022  * You should have received a copy of the GNU Library General Public License
0023  * along with this library; see the file COPYING.LIB.  If not, write to
0024  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0025  * Boston, MA 02110-1301, USA.
0026  *
0027  */
0028 
0029 //#define DEBUG
0030 //#define DEBUG_LAYOUT
0031 //#define BOX_DEBUG
0032 //#define FLOAT_DEBUG
0033 //#define PAGE_DEBUG
0034 
0035 #include "render_block.h"
0036 
0037 #include "khtml_debug.h"
0038 #include <limits.h>
0039 #include "render_text.h"
0040 #include "render_table.h"
0041 #include "render_canvas.h"
0042 #include "render_layer.h"
0043 #include "rendering/render_position.h"
0044 
0045 #include <xml/dom_nodeimpl.h>
0046 #include <xml/dom_docimpl.h>
0047 #include <xml/dom_selection.h>
0048 #include <html/html_formimpl.h>
0049 
0050 #include <khtmlview.h>
0051 #include <khtml_part.h>
0052 
0053 using namespace DOM;
0054 
0055 namespace khtml
0056 {
0057 
0058 // -------------------------------------------------------------------------------------------------------
0059 
0060 // Our MarginInfo state used when laying out block children.
0061 RenderBlock::MarginInfo::MarginInfo(RenderBlock *block, int top, int bottom)
0062 {
0063     // Whether or not we can collapse our own margins with our children.  We don't do this
0064     // if we had any border/padding (obviously), if we're the root or HTML elements, or if
0065     // we're positioned, floating, a table cell.
0066     m_canCollapseWithChildren = !block->isCanvas() && !block->isRoot() && !block->isPositioned() &&
0067                                 !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable();
0068 
0069     m_canCollapseTopWithChildren = m_canCollapseWithChildren && (top == 0) /*&& block->style()->marginTopCollapse() != MSEPARATE */;
0070 
0071     // If any height other than auto is specified in CSS, then we don't collapse our bottom
0072     // margins with our children's margins.  To do otherwise would be to risk odd visual
0073     // effects when the children overflow out of the parent block and yet still collapse
0074     // with it.  We also don't collapse if we have any bottom border/padding.
0075     m_canCollapseBottomWithChildren = m_canCollapseWithChildren && (bottom == 0) &&
0076                                       (block->style()->height().isAuto() && block->style()->height().isZero()) /*&& block->style()->marginBottomCollapse() != MSEPARATE*/;
0077 
0078     m_quirkContainer = block->isTableCell() || block->isBody() /*|| block->style()->marginTopCollapse() == MDISCARD ||
0079         block->style()->marginBottomCollapse() == MDISCARD*/;
0080 
0081     m_atTopOfBlock = true;
0082     m_atBottomOfBlock = false;
0083 
0084     m_posMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(true) : 0;
0085     m_negMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(false) : 0;
0086 
0087     m_selfCollapsingBlockClearedFloat = false;
0088 
0089     m_topQuirk = m_bottomQuirk = m_determinedTopQuirk = false;
0090 }
0091 
0092 // -------------------------------------------------------------------------------------------------------
0093 
0094 RenderBlock::RenderBlock(DOM::NodeImpl *node)
0095     : RenderFlow(node)
0096 {
0097     m_childrenInline = true;
0098     m_floatingObjects = nullptr;
0099     m_positionedObjects = nullptr;
0100     m_firstLine = false;
0101     m_avoidPageBreak = false;
0102     m_clearStatus = CNONE;
0103     m_maxTopPosMargin = m_maxTopNegMargin = m_maxBottomPosMargin = m_maxBottomNegMargin = 0;
0104     m_topMarginQuirk = m_bottomMarginQuirk = false;
0105     m_overflowHeight = m_overflowWidth = 0;
0106     m_overflowLeft = m_overflowTop = 0;
0107 }
0108 
0109 RenderBlock::~RenderBlock()
0110 {
0111     if (m_floatingObjects) {
0112         QListIterator<FloatingObject *> it(*m_floatingObjects);
0113         while (it.hasNext()) {
0114             delete it.next();
0115         }
0116     }
0117     delete m_floatingObjects;
0118     delete m_positionedObjects;
0119 }
0120 
0121 void RenderBlock::setStyle(RenderStyle *_style)
0122 {
0123     setReplaced(_style->isDisplayReplacedType());
0124 
0125     RenderFlow::setStyle(_style);
0126 
0127     // ### we could save this call when the change only affected
0128     // non inherited properties
0129     RenderObject *child = firstChild();
0130     while (child != nullptr) {
0131         if (child->isAnonymousBlock()) {
0132             RenderStyle *newStyle = new RenderStyle();
0133             newStyle->inheritFrom(style());
0134             newStyle->setDisplay(BLOCK);
0135             child->setStyle(newStyle);
0136         }
0137         child = child->nextSibling();
0138     }
0139 
0140     if (attached()) {
0141         // Update generated content and ::inside
0142         updateReplacedContent();
0143         // Update pseudos for :before and :after
0144         updatePseudoChildren();
0145     }
0146 
0147     // handled by close() during parsing
0148     // ### remove close move upto updatePseudo
0149     if (!document()->parsing()) {
0150         updateFirstLetter();
0151     }
0152 }
0153 
0154 // Attach handles initial setStyle that requires parent nodes
0155 void RenderBlock::attach()
0156 {
0157     RenderFlow::attach();
0158 
0159     updateReplacedContent();
0160     updatePseudoChildren();
0161 }
0162 
0163 static inline bool isFirstLetterPunct(const QChar *c)
0164 {
0165     // CSS2.1/3 definition for ::first-letter doesn't include Pc or Pd.
0166     if (c->isPunct()) {
0167         QChar::Category cat = c->category();
0168         return cat != QChar::Punctuation_Connector &&
0169                cat != QChar::Punctuation_Dash;
0170     }
0171     return false;
0172 }
0173 
0174 void RenderBlock::updateFirstLetter()
0175 {
0176     // Only blocks with inline-children can generate a first-letter
0177     if (!childrenInline() || !firstChild()) {
0178         return;
0179     }
0180 
0181     // Don't recurse
0182     if (style()->styleType() == RenderStyle::FIRST_LETTER) {
0183         return;
0184     }
0185 
0186     // The first-letter style is inheritable.
0187     RenderStyle *pseudoStyle = style()->getPseudoStyle(RenderStyle::FIRST_LETTER);
0188     RenderObject *o = this;
0189     while (o && !pseudoStyle) {
0190         // ### We should ignore empty preceding siblings
0191         if (o->parent() && o->parent()->firstChild() == this) {
0192             o = o->parent();
0193         } else {
0194             break;
0195         }
0196         pseudoStyle = o->style()->getPseudoStyle(RenderStyle::FIRST_LETTER);
0197     };
0198 
0199     // FIXME: Currently we don't delete first-letters, this is
0200     // handled instead in NodeImpl::diff by issuing Detach on first-letter changes.
0201     if (!pseudoStyle) {
0202         return;
0203     }
0204 
0205     // Drill into inlines looking for our first text child.
0206     RenderObject *firstText = firstChild();
0207     while (firstText && firstText->needsLayout() && !firstText->isFloating() && !firstText->isRenderBlock() && !firstText->isReplaced() && !firstText->isText())
0208         // ### We should skip first children with only white-space and punctuation
0209     {
0210         firstText = firstText->firstChild();
0211     }
0212 
0213     if (firstText && firstText->isText() && !firstText->isBR()) {
0214         RenderObject *firstLetterObject = nullptr;
0215         // Find the old first-letter
0216         if (firstText->parent()->style()->styleType() == RenderStyle::FIRST_LETTER) {
0217             firstLetterObject = firstText->parent();
0218         }
0219 
0220         // Force inline display (except for floating first-letters)
0221         pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
0222         pseudoStyle->setPosition(PSTATIC);   // CSS2 says first-letter can't be positioned.
0223 
0224         if (firstLetterObject != nullptr) {
0225             firstLetterObject->setStyle(pseudoStyle);
0226             RenderStyle *newStyle = new RenderStyle();
0227             newStyle->inheritFrom(pseudoStyle);
0228             firstText->setStyle(newStyle);
0229             return;
0230         }
0231 
0232         RenderText *textObj = static_cast<RenderText *>(firstText);
0233         RenderObject *firstLetterContainer = firstText->parent();
0234 
0235         firstLetterObject = RenderFlow::createFlow(node(), pseudoStyle, renderArena());
0236         firstLetterObject->setIsAnonymous(true);
0237         firstLetterContainer->addChild(firstLetterObject, firstLetterContainer->firstChild());
0238 
0239         // if this object is the result of a :begin, then the text may have not been
0240         // generated yet if it is a counter
0241         if (textObj->recalcMinMax()) {
0242             textObj->recalcMinMaxWidths();
0243         }
0244 
0245         // The original string is going to be either a generated content string or a DOM node's
0246         // string.  We want the original string before it got transformed in case first-letter has
0247         // no text-transform or a different text-transform applied to it.
0248         DOMStringImpl *oldText = textObj->originalString();
0249         if (!oldText) {
0250             oldText = textObj->string();
0251         }
0252         // ### In theory a first-letter can stretch across multiple text objects, if they only contain
0253         // punctuation and white-space
0254         if (oldText->l >= 1) {
0255             oldText->ref();
0256             // begin: we need skip leading whitespace so that RenderBlock::findNextLineBreak
0257             // won't think we're continuing from a previous run
0258             unsigned int begin = 0; // the position that first-letter begins
0259             unsigned int length = 0; // the position that "the rest" begins
0260             while (length < oldText->l && (oldText->s + length)->isSpace()) {
0261                 length++;
0262             }
0263             begin = length;
0264             while (length < oldText->l &&
0265                     (isFirstLetterPunct(oldText->s + length) || (oldText->s + length)->isSpace())) {
0266                 length++;
0267             }
0268             if (length < oldText->l &&
0269                     !((oldText->s + length)->isSpace() || isFirstLetterPunct(oldText->s + length))) {
0270                 length++;
0271             }
0272             while (length < oldText->l && isFirstLetterPunct(oldText->s + length)) {
0273                 length++;
0274             }
0275 
0276             // we need to generated a remainingText object even if no text is left
0277             // because it holds the place and style for the old textObj
0278             RenderTextFragment *remainingText =
0279                 new(renderArena()) RenderTextFragment(textObj->node(), oldText, length, oldText->l - length);
0280             remainingText->setIsAnonymous(textObj->isAnonymous());
0281             remainingText->setStyle(textObj->style());
0282             if (remainingText->element()) {
0283                 remainingText->element()->setRenderer(remainingText);
0284             }
0285 
0286             RenderObject *nextObj = textObj->nextSibling();
0287             textObj->detach();
0288             firstLetterContainer->addChild(remainingText, nextObj);
0289 
0290             RenderTextFragment *letter =
0291                 new(renderArena()) RenderTextFragment(remainingText->node(), oldText, begin, length - begin);
0292             letter->setIsAnonymous(remainingText->isAnonymous());
0293             RenderStyle *newStyle = new RenderStyle();
0294             newStyle->inheritFrom(pseudoStyle);
0295             letter->setStyle(newStyle);
0296             firstLetterObject->addChild(letter);
0297             oldText->deref();
0298 
0299             remainingText->setFirstLetter(letter);
0300         }
0301         firstLetterObject->close();
0302     }
0303 }
0304 
0305 void RenderBlock::addChildToFlow(RenderObject *newChild, RenderObject *beforeChild)
0306 {
0307     // Make sure we don't append things after :after-generated content if we have it.
0308     if (!beforeChild && lastChild() && lastChild()->style()->styleType() == RenderStyle::AFTER) {
0309         beforeChild = lastChild();
0310     }
0311 
0312     bool madeBoxesNonInline = false;
0313 
0314     // If the requested beforeChild is not one of our children, then this is most likely because
0315     // there is an anonymous block box within this object that contains the beforeChild. So
0316     // just insert the child into the anonymous block box instead of here. This may also be
0317     // needed in cases of things like anonymous tables.
0318     if (beforeChild && beforeChild->parent() != this) {
0319 
0320         KHTMLAssert(beforeChild->parent());
0321 
0322         // In the special case where we are prepending a block-level element before
0323         // something contained inside an anonymous block, we can just prepend it before
0324         // the anonymous block.
0325         if (!newChild->isInline() && beforeChild->parent()->isAnonymousBlock() &&
0326                 beforeChild->parent()->parent() == this &&
0327                 beforeChild->parent()->firstChild() == beforeChild) {
0328             return addChildToFlow(newChild, beforeChild->parent());
0329         }
0330 
0331         // Otherwise find our kid inside which the beforeChild is, and delegate to it.
0332         // This may be many levels deep due to anonymous tables, table sections, etc.
0333         RenderObject *responsible = beforeChild->parent();
0334         while (responsible->parent() != this) {
0335             responsible = responsible->parent();
0336         }
0337 
0338         return responsible->addChild(newChild, beforeChild);
0339     }
0340 
0341     // prevent elements that haven't received a layout yet from getting painted by pushing
0342     // them far above the top of the page
0343     if (!newChild->isInline()) {
0344         newChild->setPos(newChild->xPos(), -500000);
0345     }
0346 
0347     // A block has to either have all of its children inline, or all of its children as blocks.
0348     // So, if our children are currently inline and a block child has to be inserted, we move all our
0349     // inline children into anonymous block boxes
0350     if (m_childrenInline && !newChild->isInline() && !newChild->isFloatingOrPositioned()) {
0351         // This is a block with inline content. Wrap the inline content in anonymous blocks.
0352         makeChildrenNonInline(beforeChild);
0353         madeBoxesNonInline = true;
0354 
0355         if (beforeChild && beforeChild->parent() != this) {
0356             beforeChild = beforeChild->parent();
0357             KHTMLAssert(beforeChild->isAnonymousBlock());
0358             KHTMLAssert(beforeChild->parent() == this);
0359         }
0360     } else if (!m_childrenInline && !newChild->isFloatingOrPositioned()) {
0361         // If we're inserting an inline child but all of our children are blocks, then we have to make sure
0362         // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
0363         // a new one is created and inserted into our list of children in the appropriate position.
0364         if (newChild->isInline()) {
0365             if (beforeChild) {
0366                 if (beforeChild->previousSibling() && beforeChild->previousSibling()->isAnonymousBlock()) {
0367                     beforeChild->previousSibling()->addChild(newChild);
0368                     return;
0369                 }
0370             } else {
0371                 if (m_last && m_last->isAnonymousBlock()) {
0372                     m_last->addChild(newChild);
0373                     return;
0374                 }
0375             }
0376 
0377             // no suitable existing anonymous box - create a new one
0378             RenderBlock *newBox = createAnonymousBlock();
0379             RenderBox::addChild(newBox, beforeChild);
0380             newBox->addChild(newChild);
0381 
0382             //the above may actually destroy newBox in case an anonymous
0383             //table got created, and made the anonymous block redundant.
0384             //so look up what to hide indirectly.
0385             RenderObject *toHide = newChild;
0386             while (toHide->parent() != this) {
0387                 toHide = toHide->parent();
0388             }
0389 
0390             toHide->setPos(toHide->xPos(), -500000);
0391             return;
0392         } else {
0393             // We are adding another block child... if the current last child is an anonymous box
0394             // then it needs to be closed.
0395             // ### get rid of the closing thing altogether this will only work during initial parsing
0396             if (lastChild() && lastChild()->isAnonymous()) {
0397                 lastChild()->close();
0398             }
0399         }
0400     }
0401 
0402     RenderBox::addChild(newChild, beforeChild);
0403     // ### care about aligned stuff
0404 
0405     if (madeBoxesNonInline && isAnonymousBlock()) {
0406         parent()->removeSuperfluousAnonymousBlockChild(this);
0407     }
0408     // we might be deleted now
0409 }
0410 
0411 static void getInlineRun(RenderObject *start, RenderObject *stop,
0412                          RenderObject *&inlineRunStart,
0413                          RenderObject *&inlineRunEnd)
0414 {
0415     // Beginning at |start| we find the largest contiguous run of inlines that
0416     // we can.  We denote the run with start and end points, |inlineRunStart|
0417     // and |inlineRunEnd|.  Note that these two values may be the same if
0418     // we encounter only one inline.
0419     //
0420     // We skip any non-inlines we encounter as long as we haven't found any
0421     // inlines yet.
0422     //
0423     //
0424     // |stop| indicates a non-inclusive stop point.  Regardless of whether |stop|
0425     // is inline or not, we will not include it in a run with inlines before it.  It's as though we encountered
0426     // a non-inline.
0427 
0428     RenderObject *curr = start;
0429     bool sawInline;
0430     do {
0431         while (curr && !(curr->isInline() || curr->isFloatingOrPositioned())) {
0432             curr = curr->nextSibling();
0433         }
0434 
0435         inlineRunStart = inlineRunEnd = curr;
0436 
0437         if (!curr) {
0438             return;    // No more inline children to be found.
0439         }
0440 
0441         sawInline = curr->isInline();
0442 
0443         curr = curr->nextSibling();
0444         while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != stop)) {
0445             inlineRunEnd = curr;
0446             if (curr->isInline()) {
0447                 sawInline = true;
0448             }
0449             curr = curr->nextSibling();
0450         }
0451     } while (!sawInline);
0452 
0453 }
0454 
0455 void RenderBlock::deleteLineBoxTree()
0456 {
0457     InlineFlowBox *line = m_firstLineBox;
0458     InlineFlowBox *nextLine;
0459     while (line) {
0460         nextLine = line->nextFlowBox();
0461         line->deleteLine(renderArena());
0462         line = nextLine;
0463     }
0464     m_firstLineBox = m_lastLineBox = nullptr;
0465 }
0466 
0467 short RenderBlock::baselinePosition(bool firstLine) const
0468 {
0469     // CSS2.1-10.8.1 "The baseline of an 'inline-block' is the baseline of its last line box
0470     // in the normal flow, unless it has either no in-flow line boxes or if its 'overflow'
0471     // property has a computed value other than 'visible', in which case the baseline is the bottom margin edge."
0472 
0473     if (isReplaced() && !hasOverflowClip() && !needsLayout()) {
0474         int res = getBaselineOfLastLineBox();
0475         if (res != -1) {
0476             return  res + marginTop();
0477         }
0478     }
0479     return RenderBox::baselinePosition(firstLine);
0480 }
0481 
0482 int RenderBlock::getBaselineOfLastLineBox() const
0483 {
0484     if (!isBlockFlow()) {
0485         return -1;
0486     }
0487 
0488     if (childrenInline()) {
0489 //       if (!firstLineBox() && hasLineIfEmpty())
0490 //            return RenderFlow::baselinePosition(true) + borderTop() + paddingTop();
0491         if (lastLineBox()) {
0492             return lastLineBox()->yPos() + lastLineBox()->baseline();
0493         }
0494         return -1;
0495     } else {
0496 //        bool haveNormalFlowChild = false;
0497         for (RenderObject *curr = lastChild(); curr; curr = curr->previousSibling()) {
0498             if (!curr->isFloatingOrPositioned() && curr->isBlockFlow()) {
0499 //                haveNormalFlowChild = true;
0500                 int result = static_cast<RenderBlock *>(curr)->getBaselineOfLastLineBox();
0501                 if (result != -1) {
0502                     return curr->yPos() + result;    // Translate to our coordinate space.
0503                 }
0504             }
0505         }
0506 //        if (!haveNormalFlowChild && isRenderButton()) // hasLineIfEmpty()
0507 //            return RenderFlow::baselinePosition(true) + borderTop() + paddingTop();
0508     }
0509 
0510     return -1;
0511 }
0512 
0513 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
0514 {
0515     // makeChildrenNonInline takes a block whose children are *all* inline and it
0516     // makes sure that inline children are coalesced under anonymous
0517     // blocks.  If |insertionPoint| is defined, then it represents the insertion point for
0518     // the new block child that is causing us to have to wrap all the inlines.  This
0519     // means that we cannot coalesce inlines before |insertionPoint| with inlines following
0520     // |insertionPoint|, because the new child is going to be inserted in between the inlines,
0521     // splitting them.
0522     KHTMLAssert(isReplacedBlock() || !isInline());
0523     KHTMLAssert(!insertionPoint || insertionPoint->parent() == this);
0524 
0525     deleteLineBoxTree();
0526 
0527     m_childrenInline = false;
0528 
0529     RenderObject *child = firstChild();
0530 
0531     while (child) {
0532         RenderObject *inlineRunStart, *inlineRunEnd;
0533         getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
0534 
0535         if (!inlineRunStart) {
0536             break;
0537         }
0538 
0539         child = inlineRunEnd->nextSibling();
0540 
0541         RenderBlock *box = createAnonymousBlock();
0542         insertChildNode(box, inlineRunStart);
0543         RenderObject *o = inlineRunStart;
0544         while (o != inlineRunEnd) {
0545             RenderObject *no = o;
0546             o = no->nextSibling();
0547             box->appendChildNode(removeChildNode(no));
0548         }
0549         box->appendChildNode(removeChildNode(inlineRunEnd));
0550         box->close();
0551         box->setPos(box->xPos(), -500000);
0552     }
0553 }
0554 
0555 void RenderBlock::makePageBreakAvoidBlocks()
0556 {
0557     KHTMLAssert(!childrenInline());
0558     KHTMLAssert(canvas()->pagedMode());
0559 
0560     RenderObject *breakAfter = firstChild();
0561     RenderObject *breakBefore = breakAfter ? breakAfter->nextSibling() : nullptr;
0562 
0563     RenderBlock *pageRun = nullptr;
0564 
0565     // ### Should follow margin-collapsing rules, skipping self-collapsing blocks
0566     // and exporting page-breaks from first/last child when collapsing with parent margin.
0567     while (breakAfter) {
0568         if (breakAfter->isRenderBlock() && !breakAfter->childrenInline()) {
0569             static_cast<RenderBlock *>(breakAfter)->makePageBreakAvoidBlocks();
0570         }
0571         EPageBreak pbafter = breakAfter->style()->pageBreakAfter();
0572         EPageBreak pbbefore = breakBefore ? breakBefore->style()->pageBreakBefore() : PBALWAYS;
0573         if ((pbafter == PBAVOID && pbbefore == PBAVOID) ||
0574                 (pbafter == PBAVOID && pbbefore == PBAUTO) ||
0575                 (pbafter == PBAUTO && pbbefore == PBAVOID)) {
0576             if (!pageRun) {
0577                 pageRun = createAnonymousBlock();
0578                 pageRun->m_avoidPageBreak = true;
0579                 pageRun->setChildrenInline(false);
0580             }
0581             pageRun->appendChildNode(removeChildNode(breakAfter));
0582         } else {
0583             if (pageRun) {
0584                 pageRun->appendChildNode(removeChildNode(breakAfter));
0585                 pageRun->close();
0586                 insertChildNode(pageRun, breakBefore);
0587                 pageRun = nullptr;
0588             }
0589         }
0590         breakAfter = breakBefore;
0591         breakBefore = breakBefore ? breakBefore->nextSibling() : nullptr;
0592     }
0593 
0594     // recurse into positioned block children as well.
0595     if (m_positionedObjects) {
0596         RenderObject *obj;
0597         QListIterator<RenderObject *> it(*m_positionedObjects);
0598         while (it.hasNext()) {
0599             obj = it.next();
0600             if (obj->isRenderBlock() && !obj->childrenInline()) {
0601                 static_cast<RenderBlock *>(obj)->makePageBreakAvoidBlocks();
0602             }
0603         }
0604     }
0605 
0606     // recurse into floating block children.
0607     if (m_floatingObjects) {
0608         FloatingObject *obj;
0609         QListIterator<FloatingObject *> it(*m_floatingObjects);
0610         while (it.hasNext()) {
0611             obj = it.next();
0612             if (obj->node->isRenderBlock() && !obj->node->childrenInline()) {
0613                 static_cast<RenderBlock *>(obj->node)->makePageBreakAvoidBlocks();
0614             }
0615         }
0616     }
0617 }
0618 
0619 void RenderBlock::removeChild(RenderObject *oldChild)
0620 {
0621     // If this child is a block, and if our previous and next siblings are
0622     // both anonymous blocks with inline content, then we can go ahead and
0623     // fold the inline content back together.
0624     RenderObject *prev = oldChild->previousSibling();
0625     RenderObject *next = oldChild->nextSibling();
0626     RenderObject *lc = nullptr;
0627     bool mergedBlocks = false;
0628     bool checkContinuationMerge = false;
0629     if (!documentBeingDestroyed() && !isInline() && !oldChild->isInline() && !oldChild->continuation()) {
0630         if (prev && prev->isAnonymousBlock() && prev->childrenInline() &&
0631                 next && next->isAnonymousBlock() && next->childrenInline()) {
0632             // Take all the children out of the |next| block and put them in
0633             // the |prev| block.
0634             RenderObject *o = next->firstChild();
0635             while (o) {
0636                 RenderObject *no = o;
0637                 o = no->nextSibling();
0638                 prev->appendChildNode(next->removeChildNode(no));
0639             }
0640 
0641             // Detach the now-empty block.
0642             static_cast<RenderBlock *>(next)->deleteLineBoxTree();
0643             next->detach();
0644 
0645             mergedBlocks = true;
0646         }
0647 
0648         // Check if there are continuations we could merge
0649         checkContinuationMerge = (mergedBlocks || (!prev && !next)) && continuation() && isAnonymousBlock() && continuation()->isRenderInline() &&
0650                                  previousSibling() && previousSibling()->isAnonymousBlock() && (lc = previousSibling()->lastChild());
0651 
0652         if (checkContinuationMerge) {
0653             while (lc->lastChild() && lc->continuation()) {
0654                 lc = lc->lastChild();
0655             }
0656             checkContinuationMerge = lc->isRenderInline() && lc->continuation() && (lc->continuation() == this);
0657         }
0658         if (checkContinuationMerge) {
0659             RenderObject *prev = lc->parent();
0660             RenderObject *cont = continuation()->parent();
0661             while (prev && cont) {
0662                 if (prev == previousSibling() && cont == nextSibling() && cont->isAnonymousBlock()) {
0663                     break;
0664                 }
0665                 if (!prev->continuation() || prev->continuation() != cont) {
0666                     checkContinuationMerge = false;
0667                     break;
0668                 }
0669                 prev = prev->parent();
0670                 cont = cont->parent();
0671             }
0672         }
0673     }
0674 
0675     RenderFlow::removeChild(oldChild);
0676 
0677     if (mergedBlocks && prev && !prev->previousSibling() && !prev->nextSibling()) {
0678         // The remerge has knocked us down to containing only a single anonymous
0679         // box.  We can go ahead and pull the content right back up into our
0680         // box.
0681         RenderBlock *anonBlock = static_cast<RenderBlock *>(prev);
0682         m_childrenInline = true;
0683         RenderObject *o = anonBlock->firstChild();
0684         while (o) {
0685             RenderObject *no = o;
0686             o = no->nextSibling();
0687             appendChildNode(anonBlock->removeChildNode(no));
0688         }
0689 
0690         // Detach the now-empty block.
0691         anonBlock->deleteLineBoxTree();
0692         anonBlock->detach();
0693     }
0694     if (checkContinuationMerge && ((!prev && !next) || m_childrenInline)) {
0695         // |oldChild| was a block that split an inline into continuations.
0696         // Now that we only have inline content left, we may merge back those continuations
0697         // into a single inline.
0698         assert(lc->isRenderInline());
0699         RenderFlow *prev = static_cast<RenderFlow *>(lc);
0700         while (RenderFlow *next = prev->continuation()) {
0701             RenderObject *o = next->firstChild();
0702             while (o) {
0703                 RenderObject *no = o;
0704                 o = no->nextSibling();
0705                 prev->appendChildNode(next->removeChildNode(no));
0706             }
0707             prev->setContinuation(next->continuation());
0708             next->setContinuation(nullptr);
0709             if (next != this) {
0710                 next->detach();
0711                 prev = static_cast<RenderFlow *>(prev->parent());
0712                 assert(!prev || prev->isRenderInline() || prev->isRenderBlock());
0713             }
0714         }
0715         assert(nextSibling() && nextSibling()->isAnonymousBlock());
0716         if (!nextSibling()->firstChild()) {
0717             static_cast<RenderBlock *>(nextSibling())->deleteLineBoxTree();
0718             nextSibling()->detach();
0719         }
0720         deleteLineBoxTree();
0721         detach();
0722     }
0723 }
0724 
0725 bool RenderBlock::isSelfCollapsingBlock() const
0726 {
0727     // We are not self-collapsing if we
0728     // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
0729     // (b) are a table,
0730     // (c) have border/padding,
0731     // (d) have a min-height
0732     if (m_height > 0 ||
0733             isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 ||
0734             style()->minHeight().isPositive()) {
0735         return false;
0736     }
0737 
0738     bool hasAutoHeight = style()->height().isAuto();
0739     if (style()->height().isPercent() && !style()->htmlHacks()) {
0740         hasAutoHeight = true;
0741         for (RenderBlock *cb = containingBlock(); !cb->isCanvas(); cb = cb->containingBlock()) {
0742             if (cb->style()->height().isFixed() || cb->isTableCell()) {
0743                 hasAutoHeight = false;
0744             }
0745         }
0746     }
0747 
0748     // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
0749     // on whether we have content that is all self-collapsing or not.
0750     if (hasAutoHeight || ((style()->height().isFixed() || style()->height().isPercent()) && style()->height().isZero())) {
0751         // If the block has inline children, see if we generated any line boxes.  If we have any
0752         // line boxes, then we can't be self-collapsing, since we have content.
0753         if (childrenInline()) {
0754             return !firstLineBox();
0755         }
0756 
0757         // Whether or not we collapse is dependent on whether all our normal flow children
0758         // are also self-collapsing.
0759         for (RenderObject *child = firstChild(); child; child = child->nextSibling()) {
0760             if (child->isFloatingOrPositioned()) {
0761                 continue;
0762             }
0763             if (!child->isSelfCollapsingBlock()) {
0764                 return false;
0765             }
0766         }
0767         return true;
0768     }
0769     return false;
0770 }
0771 
0772 void RenderBlock::layout()
0773 {
0774     // Table cells call layoutBlock directly, so don't add any logic here.  Put code into
0775     // layoutBlock().
0776     layoutBlock(false);
0777 }
0778 
0779 void RenderBlock::layoutBlock(bool relayoutChildren)
0780 {
0781     if (isInline() && !isReplacedBlock()) {
0782         setNeedsLayout(false);
0783         return;
0784     }
0785     //    qCDebug(KHTML_LOG) << renderName() << " " << this << "::layoutBlock() start";
0786     //     QTime t;
0787     //     t.start();
0788     KHTMLAssert(needsLayout());
0789     KHTMLAssert(minMaxKnown());
0790 
0791     if (canvas()->pagedMode()) {
0792         relayoutChildren = true;
0793     }
0794 
0795     if (markedForRepaint()) {
0796         repaintDuringLayout();
0797         setMarkedForRepaint(false);
0798     }
0799 
0800     if (!relayoutChildren && posChildNeedsLayout() && !normalChildNeedsLayout() && !selfNeedsLayout()) {
0801         // All we have to is lay out our positioned objects.
0802         layoutPositionedObjects(relayoutChildren);
0803         if (hasOverflowClip()) {
0804             m_layer->checkScrollbarsAfterLayout();
0805         }
0806         setNeedsLayout(false);
0807         return;
0808     }
0809 
0810     int oldWidth = m_width;
0811 
0812     calcWidth();
0813     m_overflowWidth = m_width;
0814     m_overflowLeft = 0;
0815     if (style()->direction() == LTR) {
0816         int cw = 0;
0817         if (style()->textIndent().isPercent()) {
0818             cw = containingBlock()->contentWidth();
0819         }
0820         m_overflowLeft = qMin(0, style()->textIndent().minWidth(cw));
0821     }
0822 
0823     if (oldWidth != m_width) {
0824         relayoutChildren = true;
0825     }
0826 
0827     //     qCDebug(KHTML_LOG) << floatingObjects << "," << oldWidth << ","
0828     //                     << m_width << ","<< needsLayout() << "," << isAnonymousBox() << ","
0829     //                     << isPositioned();
0830 
0831 #ifdef DEBUG_LAYOUT
0832     qCDebug(KHTML_LOG) << renderName() << "(RenderBlock) " << this << " ::layout() width=" << m_width << ", needsLayout=" << needsLayout();
0833     if (containingBlock() == static_cast<RenderObject *>(this)) {
0834         qCDebug(KHTML_LOG) << renderName() << ": containingBlock == this";
0835     }
0836 #endif
0837 
0838     clearFloats();
0839 
0840     int previousHeight = m_height;
0841     m_height = 0;
0842     m_overflowHeight = 0;
0843     m_clearStatus = CNONE;
0844 
0845     // We use four values, maxTopPos, maxPosNeg, maxBottomPos, and maxBottomNeg, to track
0846     // our current maximal positive and negative margins.  These values are used when we
0847     // are collapsed with adjacent blocks, so for example, if you have block A and B
0848     // collapsing together, then you'd take the maximal positive margin from both A and B
0849     // and subtract it from the maximal negative margin from both A and B to get the
0850     // true collapsed margin.  This algorithm is recursive, so when we finish layout()
0851     // our block knows its current maximal positive/negative values.
0852     //
0853     // Start out by setting our margin values to our current margins.  Table cells have
0854     // no margins, so we don't fill in the values for table cells.
0855     if (!isTableCell()) {
0856         initMaxMarginValues();
0857 
0858         m_topMarginQuirk = style()->marginTop().isQuirk();
0859         m_bottomMarginQuirk = style()->marginBottom().isQuirk();
0860 
0861         if (element() && element()->id() == ID_FORM && static_cast<HTMLFormElementImpl *>(element())->isMalformed())
0862             // See if this form is malformed (i.e., unclosed). If so, don't give the form
0863             // a bottom margin.
0864         {
0865             m_maxBottomPosMargin = m_maxBottomNegMargin = 0;
0866         }
0867     }
0868 
0869     if (scrollsOverflow() && m_layer) {
0870         // For overflow:scroll blocks, ensure we have both scrollbars in place always.
0871         if (style()->overflowX() == OSCROLL) {
0872             m_layer->showScrollbar(Qt::Horizontal, true);
0873         }
0874         if (style()->overflowY() == OSCROLL) {
0875             m_layer->showScrollbar(Qt::Vertical, true);
0876         }
0877     }
0878 
0879     setContainsPageBreak(false);
0880 
0881     if (childrenInline()) {
0882         layoutInlineChildren(relayoutChildren);
0883     } else {
0884         layoutBlockChildren(relayoutChildren);
0885     }
0886 
0887     // Expand our intrinsic height to encompass floats.
0888     int toAdd = borderBottom() + paddingBottom();
0889     if (m_layer && scrollsOverflowX() && style()->height().isAuto()) {
0890         toAdd += m_layer->horizontalScrollbarHeight();
0891     }
0892     if (floatBottom() + toAdd > m_height && (isFloatingOrPositioned() || flowAroundFloats())) {
0893         m_overflowHeight = m_height = floatBottom() + toAdd;
0894     }
0895 
0896     int oldHeight = m_height;
0897     calcHeight();
0898     if (oldHeight != m_height) {
0899         m_overflowHeight -= toAdd;
0900         if (m_layer && scrollsOverflowY()) {
0901             // overflow-height only includes padding-bottom when it scrolls
0902             m_overflowHeight += paddingBottom();
0903         }
0904         // If the block got expanded in size, then increase our overflowheight to match.
0905         if (m_overflowHeight < m_height) {
0906             m_overflowHeight = m_height;
0907         }
0908     }
0909     if (previousHeight != m_height) {
0910         relayoutChildren = true;
0911     }
0912 
0913     if (isTableCell()) {
0914         // Table cells need to grow to accommodate both overhanging floats and
0915         // blocks that have overflowed content.
0916         // Check for an overhanging float first.
0917         // FIXME: This needs to look at the last flow, not the last child.
0918         if (lastChild() && lastChild()->hasOverhangingFloats() && !lastChild()->hasOverflowClip()) {
0919             KHTMLAssert(lastChild()->isRenderBlock());
0920             m_height = lastChild()->yPos() + static_cast<RenderBlock *>(lastChild())->floatBottom();
0921             m_height += borderBottom() + paddingBottom();
0922         }
0923 
0924         if (m_overflowHeight > m_height && !hasOverflowClip()) {
0925             m_height = m_overflowHeight + borderBottom() + paddingBottom();
0926         }
0927     }
0928 
0929     if (hasOverhangingFloats() && ((isFloating() && style()->height().isAuto()) || isTableCell())) {
0930         m_height = floatBottom();
0931         m_height += borderBottom() + paddingBottom();
0932     }
0933 
0934     if (canvas()->pagedMode()) {
0935 #ifdef PAGE_DEBUG
0936         qCDebug(KHTML_LOG) << renderName() << " Page Bottom: " << pageTopAfter(0);
0937         qCDebug(KHTML_LOG) << renderName() << " Bottom: " << m_height;
0938 #endif
0939         bool needsPageBreak = false;
0940         int xpage = crossesPageBreak(0, m_height);
0941         if (xpage) {
0942             needsPageBreak = true;
0943 #ifdef PAGE_DEBUG
0944             qCDebug(KHTML_LOG) << renderName() << " crosses to page " << xpage;
0945 #endif
0946         }
0947         if (needsPageBreak && !containsPageBreak()) {
0948             setNeedsPageClear(true);
0949 #ifdef PAGE_DEBUG
0950             qCDebug(KHTML_LOG) << renderName() << " marked for page-clear";
0951 #endif
0952         }
0953     }
0954 
0955     layoutPositionedObjects(relayoutChildren);
0956 
0957     // Always ensure our overflow width/height are at least as large as our width/height.
0958     m_overflowWidth = qMax(m_overflowWidth, (int)m_width);
0959     m_overflowHeight = qMax(m_overflowHeight, m_height);
0960 
0961     // Update our scrollbars if we're overflow:auto/scroll now that we know if
0962     // we overflow or not.
0963     if (hasOverflowClip() && m_layer) {
0964         m_layer->checkScrollbarsAfterLayout();
0965     }
0966 
0967     setNeedsLayout(false);
0968 }
0969 
0970 void RenderBlock::adjustPositionedBlock(RenderObject *child, const MarginInfo &marginInfo)
0971 {
0972     if (child->isBox() && child->hasStaticX()) {
0973         if (style()->direction() == LTR) {
0974             static_cast<RenderBox *>(child)->setStaticX(borderLeft() + paddingLeft());
0975         } else {
0976             static_cast<RenderBox *>(child)->setStaticX(borderRight() + paddingRight());
0977         }
0978     }
0979 
0980     if (child->isBox() && child->hasStaticY()) {
0981         int y = m_height;
0982         if (!marginInfo.canCollapseWithTop()) {
0983             child->calcVerticalMargins();
0984             int marginTop = child->marginTop();
0985             int collapsedTopPos = marginInfo.posMargin();
0986             int collapsedTopNeg = marginInfo.negMargin();
0987             if (marginTop > 0) {
0988                 if (marginTop > collapsedTopPos) {
0989                     collapsedTopPos = marginTop;
0990                 }
0991             } else {
0992                 if (-marginTop > collapsedTopNeg) {
0993                     collapsedTopNeg = -marginTop;
0994                 }
0995             }
0996             y += (collapsedTopPos - collapsedTopNeg) - marginTop;
0997         }
0998         static_cast<RenderBox *>(child)->setStaticY(y);
0999     }
1000 }
1001 
1002 void RenderBlock::adjustFloatingBlock(const MarginInfo &marginInfo)
1003 {
1004     // The float should be positioned taking into account the bottom margin
1005     // of the previous flow.  We add that margin into the height, get the
1006     // float positioned properly, and then subtract the margin out of the
1007     // height again.  In the case of self-collapsing blocks, we always just
1008     // use the top margins, since the self-collapsing block collapsed its
1009     // own bottom margin into its top margin.
1010     //
1011     // Note also that the previous flow may collapse its margin into the top of
1012     // our block.  If this is the case, then we do not add the margin in to our
1013     // height when computing the position of the float.   This condition can be tested
1014     // for by simply calling canCollapseWithTop.  See
1015     // https://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
1016     // an example of this scenario.
1017     int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin();
1018     m_height += marginOffset;
1019     positionNewFloats();
1020     m_height -= marginOffset;
1021 }
1022 
1023 RenderObject *RenderBlock::handleSpecialChild(RenderObject *child, const MarginInfo &marginInfo, CompactInfo &compactInfo, bool &handled)
1024 {
1025     // Handle positioned children first.
1026     RenderObject *next = handlePositionedChild(child, marginInfo, handled);
1027     if (handled) {
1028         return next;
1029     }
1030 
1031     // Handle floating children next.
1032     next = handleFloatingChild(child, marginInfo, handled);
1033     if (handled) {
1034         return next;
1035     }
1036 
1037     // See if we have a compact element.  If we do, then try to tuck the compact element into the margin space of the next block.
1038     next = handleCompactChild(child, compactInfo, marginInfo, handled);
1039     if (handled) {
1040         return next;
1041     }
1042 
1043     // Finally, see if we have a run-in element.
1044     return handleRunInChild(child, handled);
1045 }
1046 
1047 RenderObject *RenderBlock::handlePositionedChild(RenderObject *child, const MarginInfo &marginInfo, bool &handled)
1048 {
1049     if (child->isPositioned()) {
1050         handled = true;
1051         if (!child->inPosObjectList()) {
1052             child->containingBlock()->insertPositionedObject(child);
1053         }
1054         adjustPositionedBlock(child, marginInfo);
1055         return child->nextSibling();
1056     }
1057     return nullptr;
1058 }
1059 
1060 RenderObject *RenderBlock::handleFloatingChild(RenderObject *child, const MarginInfo &marginInfo, bool &handled)
1061 {
1062     if (child->isFloating()) {
1063         handled = true;
1064         insertFloatingObject(child);
1065         adjustFloatingBlock(marginInfo);
1066         return child->nextSibling();
1067     }
1068     return nullptr;
1069 }
1070 
1071 static inline bool isAnonymousWhitespace(RenderObject *o)
1072 {
1073     if (!o->isAnonymous()) {
1074         return false;
1075     }
1076     RenderObject *fc = o->firstChild();
1077     return fc && fc == o->lastChild() && fc->isText() && static_cast<RenderText *>(fc)->stringLength() == 1 &&
1078            static_cast<RenderText *>(fc)->text()[0].unicode() == ' ';
1079 }
1080 
1081 RenderObject *RenderBlock::handleCompactChild(RenderObject *child, CompactInfo &compactInfo, const MarginInfo &marginInfo, bool &handled)
1082 {
1083     if (!child->isCompact()) {
1084         return nullptr;
1085     }
1086     // FIXME: We only deal with one compact at a time.  It is unclear what should be
1087     // done if multiple contiguous compacts are encountered.  For now we assume that
1088     // compact A followed by another compact B should simply be treated as block A.
1089     if (!compactInfo.compact() && (child->childrenInline() || child->isReplaced())) {
1090         // Get the next non-positioned/non-floating RenderBlock.
1091         RenderObject *next = child->nextSibling();
1092         RenderObject *curr = next;
1093         while (curr && (curr->isFloatingOrPositioned() || isAnonymousWhitespace(curr) || curr->isAnonymousBlock())) {
1094             curr = curr->nextSibling();
1095         }
1096         if (curr && curr->isRenderBlock() && !curr->isCompact() && !curr->isRunIn()) {
1097             curr->calcWidth(); // So that horizontal margins are correct.
1098             // Need to compute margins for the child as though it is a block.
1099             child->style()->setDisplay(BLOCK);
1100             child->calcWidth();
1101             child->style()->setDisplay(COMPACT);
1102 
1103             int childMargins = child->marginLeft() + child->marginRight();
1104             int margin = style()->direction() == LTR ? curr->marginLeft() : curr->marginRight();
1105             if (margin >= (childMargins + child->maxWidth())) {
1106                 // The compact will fit in the margin.
1107                 handled = true;
1108                 compactInfo.set(child, curr);
1109                 child->layoutIfNeeded();
1110                 int off = marginInfo.margin();
1111                 m_height += off + curr->marginTop() < child->marginTop() ?
1112                             child->marginTop() - curr->marginTop() - off : 0;
1113 
1114                 child->setPos(0, 0); // This position will be updated to reflect the compact's
1115                 // desired position and the line box for the compact will
1116                 // pick that position up.
1117                 return next;
1118             }
1119         }
1120     }
1121     child->style()->setDisplay(BLOCK);
1122     child->layoutIfNeeded();
1123     child->style()->setDisplay(COMPACT);
1124     return nullptr;
1125 }
1126 
1127 void RenderBlock::adjustSizeForCompactIfNeeded(RenderObject *child, CompactInfo &compactInfo)
1128 {
1129     // if the compact is bigger than the block it was run into
1130     // then "this" block should take the height of the compact
1131     if (compactInfo.matches(child)) {
1132         // We have a compact child to squeeze in.
1133         RenderObject *compactChild = compactInfo.compact();
1134         if (compactChild->height() > child->height()) {
1135             m_height += compactChild->height() - child->height();
1136         }
1137     }
1138 }
1139 
1140 void RenderBlock::insertCompactIfNeeded(RenderObject *child, CompactInfo &compactInfo)
1141 {
1142     if (compactInfo.matches(child)) {
1143         // We have a compact child to squeeze in.
1144         RenderObject *compactChild = compactInfo.compact();
1145         int compactXPos = borderLeft() + paddingLeft() + compactChild->marginLeft();
1146         if (style()->direction() == RTL) {
1147             compactChild->calcWidth(); // have to do this because of the capped maxwidth
1148             compactXPos = width() - borderRight() - paddingRight() -
1149                           compactChild->width() - compactChild->marginRight();
1150         }
1151 
1152         int compactYPos = child->yPos() + child->borderTop() + child->paddingTop()
1153                           - compactChild->paddingTop() - compactChild->borderTop();
1154         int adj = 0;
1155         KHTMLAssert(child->isRenderBlock());
1156         InlineRunBox *b = static_cast<RenderBlock *>(child)->firstLineBox();
1157         InlineRunBox *c = static_cast<RenderBlock *>(compactChild)->firstLineBox();
1158         if (b && c) {
1159             // adjust our vertical position
1160             int vpos = compactChild->getVerticalPosition(true, child);
1161             if (vpos == PositionBottom) {
1162                 adj = b->height() > c->height() ? (b->height() + b->yPos() - c->height() - c->yPos()) : 0;
1163             } else if (vpos == PositionTop) {
1164                 adj = b->yPos() - c->yPos();
1165             } else {
1166                 adj = vpos;
1167             }
1168             compactYPos += adj;
1169         }
1170         Length newLineHeight(qMax(compactChild->lineHeight(true) + adj, (int)child->lineHeight(true)), khtml::Fixed);
1171         child->style()->setLineHeight(newLineHeight);
1172         child->setNeedsLayout(true, false);
1173         child->layout();
1174 
1175         compactChild->setPos(compactXPos, compactYPos); // Set the x position.
1176         compactInfo.clear();
1177     }
1178 }
1179 
1180 RenderObject *RenderBlock::handleRunInChild(RenderObject *child, bool &handled)
1181 {
1182     if (!child->isRunIn()) {
1183         return nullptr;
1184     }
1185     // See if we have a run-in element with inline children.  If the
1186     // children aren't inline, then just treat the run-in as a normal
1187     // block.
1188     if (child->childrenInline() || child->isReplaced()) {
1189         // Get the next non-positioned/non-floating RenderBlock.
1190         RenderObject *curr = child->nextSibling();
1191         while (curr && (curr->isFloatingOrPositioned() || isAnonymousWhitespace(curr) || curr->isAnonymousBlock())) {
1192             curr = curr->nextSibling();
1193         }
1194         if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isCompact() && !curr->isRunIn())) {
1195             // The block acts like an inline, so just null out its
1196             // position.
1197             handled = true;
1198             child->setInline(true);
1199             child->setPos(0, 0);
1200 
1201             // Remove the child.
1202             RenderObject *next = child->nextSibling();
1203             removeChildNode(child);
1204 
1205             // Now insert the child under |curr|.
1206             curr->insertChildNode(child, curr->firstChild());
1207             return next;
1208         }
1209     }
1210     return nullptr;
1211 }
1212 
1213 int RenderBlock::collapseMargins(RenderObject *child, MarginInfo &marginInfo, int yPosEstimate)
1214 {
1215     Q_UNUSED(yPosEstimate);
1216     // Get our max pos and neg top margins.
1217     int posTop = child->maxTopMargin(true);
1218     int negTop = child->maxTopMargin(false);
1219 
1220     // For self-collapsing blocks, collapse our bottom margins into our
1221     // top to get new posTop and negTop values.
1222     if (child->isSelfCollapsingBlock()) {
1223         posTop = qMax(posTop, (int)child->maxBottomMargin(true));
1224         negTop = qMax(negTop, (int)child->maxBottomMargin(false));
1225     }
1226 
1227     // See if the top margin is quirky. We only care if this child has
1228     // margins that will collapse with us.
1229     bool topQuirk = child->isTopMarginQuirk() /*|| style()->marginTopCollapse() == MDISCARD*/;
1230 
1231     if (marginInfo.canCollapseWithTop()) {
1232         // This child is collapsing with the top of the
1233         // block.  If it has larger margin values, then we need to update
1234         // our own maximal values.
1235         if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk) {
1236             m_maxTopPosMargin = qMax(posTop, (int)m_maxTopPosMargin);
1237             m_maxTopNegMargin = qMax(negTop, (int)m_maxTopNegMargin);
1238         }
1239 
1240         // The minute any of the margins involved isn't a quirk, don't
1241         // collapse it away, even if the margin is smaller (www.webreference.com
1242         // has an example of this, a <dt> with 0.8em author-specified inside
1243         // a <dl> inside a <td>.
1244         if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop - negTop)) {
1245             m_topMarginQuirk = false;
1246             marginInfo.setDeterminedTopQuirk(true);
1247         }
1248 
1249         if (!marginInfo.determinedTopQuirk() && topQuirk && marginTop() == 0)
1250             // We have no top margin and our top child has a quirky margin.
1251             // We will pick up this quirky margin and pass it through.
1252             // This deals with the <td><div><p> case.
1253             // Don't do this for a block that split two inlines though.  You do
1254             // still apply margins in this case.
1255         {
1256             m_topMarginQuirk = true;
1257         }
1258     }
1259 
1260     if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop)) {
1261         marginInfo.setTopQuirk(topQuirk);
1262     }
1263 
1264     int ypos = m_height;
1265     if (child->isSelfCollapsingBlock()) {
1266         // This child has no height.  We need to compute our
1267         // position before we collapse the child's margins together,
1268         // so that we can get an accurate position for the zero-height block.
1269         int collapsedTopPos = qMax(marginInfo.posMargin(), (int)child->maxTopMargin(true));
1270         int collapsedTopNeg = qMax(marginInfo.negMargin(), (int)child->maxTopMargin(false));
1271         marginInfo.setMargin(collapsedTopPos, collapsedTopNeg);
1272 
1273         // Now collapse the child's margins together, which means examining our
1274         // bottom margin values as well.
1275         marginInfo.setPosMarginIfLarger(child->maxBottomMargin(true));
1276         marginInfo.setNegMarginIfLarger(child->maxBottomMargin(false));
1277 
1278         if (!marginInfo.canCollapseWithTop())
1279             // We need to make sure that the position of the self-collapsing block
1280             // is correct, since it could have overflowing content
1281             // that needs to be positioned correctly (e.g., a block that
1282             // had a specified height of 0 but that actually had subcontent).
1283         {
1284             ypos = m_height + collapsedTopPos - collapsedTopNeg;
1285         }
1286     } else {
1287 #ifdef APPLE_CHANGES
1288         if (child->style()->marginTopCollapse() == MSEPARATE) {
1289             m_height += marginInfo.margin() + child->marginTop();
1290             ypos = m_height;
1291         } else
1292 #endif
1293             if (!marginInfo.atTopOfBlock() ||
1294                     (!marginInfo.canCollapseTopWithChildren()
1295                      && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) {
1296                 // We're collapsing with a previous sibling's margins and not
1297                 // with the top of the block.
1298                 m_height += qMax(marginInfo.posMargin(), posTop) - qMax(marginInfo.negMargin(), negTop);
1299                 ypos = m_height;
1300             }
1301 
1302         marginInfo.setPosMargin(child->maxBottomMargin(true));
1303         marginInfo.setNegMargin(child->maxBottomMargin(false));
1304 
1305         if (marginInfo.margin()) {
1306             marginInfo.setBottomQuirk(child->isBottomMarginQuirk() /*|| style()->marginBottomCollapse() == MDISCARD*/);
1307         }
1308 
1309         marginInfo.setSelfCollapsingBlockClearedFloat(false);
1310     }
1311     return ypos;
1312 }
1313 
1314 int RenderBlock::clearFloatsIfNeeded(RenderObject *child, MarginInfo &marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos)
1315 {
1316     int heightIncrease = getClearDelta(child, yPos);
1317     if (heightIncrease) {
1318 
1319         // Increase our height by the amount we had to clear.
1320         bool selfCollapsing = child->isSelfCollapsingBlock();
1321         if (!selfCollapsing) {
1322             m_height += heightIncrease;
1323         } else {
1324             // For self-collapsing blocks that clear, they may end up collapsing
1325             // into the bottom of the parent block.  We simulate this behavior by
1326             // setting our positive margin value to compensate for the clear.
1327             marginInfo.setPosMargin(qMax(0, child->yPos() - m_height));
1328             marginInfo.setNegMargin(0);
1329             marginInfo.setSelfCollapsingBlockClearedFloat(true);
1330         }
1331 
1332         if (marginInfo.canCollapseWithTop()) {
1333             // We can no longer collapse with the top of the block since a clear
1334             // occurred.  The empty blocks collapse into the cleared block.
1335             // FIXME: This isn't quite correct.  Need clarification for what to do
1336             // if the height the cleared block is offset by is smaller than the
1337             // margins involved.
1338             m_maxTopPosMargin = oldTopPosMargin;
1339             m_maxTopNegMargin = oldTopNegMargin;
1340             marginInfo.setAtTopOfBlock(false);
1341         }
1342         /*
1343                 // If our value of clear caused us to be repositioned vertically to be
1344                 // underneath a float, we might have to do another layout to take into account
1345                 // the extra space we now have available.
1346                 if (!selfCollapsing && !child->style()->width().isFixed() && child->usesLineWidth())
1347                     // The child's width is a percentage of the line width.
1348                     // When the child shifts to clear an item, its width can
1349                     // change (because it has more available line width).
1350                     // So go ahead and mark the item as dirty.
1351                     child->setChildNeedsLayout(true);
1352                 if (!child->flowAroundFloats() && child->hasFloats())
1353                     child->markAllDescendantsWithFloatsForLayout();
1354                 child->layoutIfNeeded();
1355         */
1356         return yPos + heightIncrease;
1357     }
1358     return yPos;
1359 }
1360 
1361 bool RenderBlock::canClear(RenderObject *child, PageBreakLevel level)
1362 {
1363     KHTMLAssert(child->parent() && child->parent() == this);
1364     KHTMLAssert(canvas()->pagedMode());
1365 
1366     // Positioned elements cannot be moved. Only normal flow and floating.
1367     if (child->isPositioned() || child->isRelPositioned()) {
1368         return false;
1369     }
1370 
1371     switch (level) {
1372     case PageBreakNormal:
1373         // check page-break-inside: avoid
1374         if (!style()->pageBreakInside())
1375             // we cannot, but can our parent?
1376             if (!parent()->canClear(this, level)) {
1377                 return false;
1378             }
1379     case PageBreakHarder:
1380         // check page-break-after/before: avoid
1381         if (m_avoidPageBreak)
1382             // we cannot, but can our parent?
1383             if (!parent()->canClear(this, level)) {
1384                 return false;
1385             }
1386     case PageBreakForced:
1387         // child is larger than page-height and is forced to break
1388         if (child->height() > canvas()->pageHeight()) {
1389             return false;
1390         }
1391         return true;
1392     }
1393     assert(false);
1394     return false;
1395 }
1396 
1397 void RenderBlock::clearPageBreak(RenderObject *child, int pageBottom)
1398 {
1399     KHTMLAssert(child->parent() && child->parent() == this);
1400     KHTMLAssert(canvas()->pagedMode());
1401 
1402     if (child->yPos() >= pageBottom) {
1403         return;
1404     }
1405 
1406     int heightIncrease = 0;
1407 
1408     heightIncrease = pageBottom - child->yPos();
1409 
1410     // ### should never happen, canClear should have been called to detect it.
1411     if (child->height() > canvas()->pageHeight()) {
1412         // qCDebug(KHTML_LOG) << "### child is too large to clear: " << child->height() << " > " << canvas()->pageHeight();
1413         return;
1414     }
1415 
1416     // The child needs to be lowered.  Move the child so that it just clears the break.
1417     child->setPos(child->xPos(), pageBottom);
1418 
1419 #ifdef PAGE_DEBUG
1420     qCDebug(KHTML_LOG) << "Cleared block " << heightIncrease << "px";
1421 #endif
1422 
1423     // Increase our height by the amount we had to clear.
1424     m_height += heightIncrease;
1425 
1426     // We might have to do another layout to take into account
1427     // the extra space we now have available.
1428     if (!child->style()->width().isFixed()  && child->usesLineWidth())
1429         // The child's width is a percentage of the line width.
1430         // When the child shifts to clear a page-break, its width can
1431         // change (because it has more available line width).
1432         // So go ahead and mark the item as dirty.
1433     {
1434         child->setChildNeedsLayout(true);
1435     }
1436     if (!child->flowAroundFloats() && child->hasFloats()) {
1437         child->markAllDescendantsWithFloatsForLayout();
1438     }
1439     if (child->containsPageBreak()) {
1440         child->setNeedsLayout(true);
1441     }
1442     child->layoutIfNeeded();
1443 
1444     child->setAfterPageBreak(true);
1445 }
1446 
1447 int RenderBlock::estimateVerticalPosition(RenderObject *child, const MarginInfo &marginInfo)
1448 {
1449     // FIXME: We need to eliminate the estimation of vertical position, because
1450     // when it's wrong we sometimes trigger a pathological relayout if there are
1451     // intruding floats.
1452     int yPosEstimate = m_height;
1453     if (!marginInfo.canCollapseWithTop()) {
1454         int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop();
1455         yPosEstimate += qMax(marginInfo.margin(), childMarginTop);
1456     }
1457     yPosEstimate += getClearDelta(child, yPosEstimate);
1458     return yPosEstimate;
1459 }
1460 
1461 void RenderBlock::determineHorizontalPosition(RenderObject *child)
1462 {
1463     if (style()->direction() == LTR) {
1464         int xPos = borderLeft() + paddingLeft();
1465 
1466         if (m_layer && scrollsOverflowY() && m_layer->hasReversedScrollbar()) {
1467             xPos += m_layer->verticalScrollbarWidth();
1468         }
1469 
1470         // Add in our left margin.
1471         int chPos = xPos + child->marginLeft();
1472 
1473         // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats.  They need
1474         // to shift over as necessary to dodge any floats that might get in the way.
1475         if (child->flowAroundFloats()) {
1476             int leftOff = leftOffset(m_height);
1477             if (style()->textAlign() != KHTML_CENTER && !child->style()->marginLeft().isAuto()) {
1478                 if (child->marginLeft() < 0) {
1479                     leftOff += child->marginLeft();
1480                 }
1481                 chPos = qMax(chPos, leftOff); // Let the float sit in the child's margin if it can fit.
1482             } else if (leftOff != xPos) {
1483                 // The object is shifting right. The object might be centered, so we need to
1484                 // recalculate our horizontal margins. Note that the containing block content
1485                 // width computation will take into account the delta between |leftOff| and |xPos|
1486                 // so that we can just pass the content width in directly to the |calcHorizontalMargins|
1487                 // function.
1488                 static_cast<RenderBox *>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos()));
1489                 chPos = leftOff + child->marginLeft();
1490             }
1491         }
1492 
1493         child->setPos(chPos, child->yPos());
1494     } else {
1495         int xPos = m_width - borderRight() - paddingRight();
1496         if (m_layer && scrollsOverflowY() && !m_layer->hasReversedScrollbar()) {
1497             xPos -= m_layer->verticalScrollbarWidth();
1498         }
1499         int chPos = xPos - (child->width() + child->marginRight());
1500         if (child->flowAroundFloats()) {
1501             int rightOff = rightOffset(m_height);
1502             if (style()->textAlign() != KHTML_CENTER && !child->style()->marginRight().isAuto()) {
1503                 if (child->marginRight() < 0) {
1504                     rightOff -= child->marginRight();
1505                 }
1506                 chPos = qMin(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit.
1507             } else if (rightOff != xPos) {
1508                 // The object is shifting left. The object might be centered, so we need to
1509                 // recalculate our horizontal margins. Note that the containing block content
1510                 // width computation will take into account the delta between |rightOff| and |xPos|
1511                 // so that we can just pass the content width in directly to the |calcHorizontalMargins|
1512                 // function.
1513                 static_cast<RenderBox *>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos()));
1514                 chPos = rightOff - child->marginRight() - child->width();
1515             }
1516         }
1517         child->setPos(chPos, child->yPos());
1518     }
1519 }
1520 
1521 void RenderBlock::setCollapsedBottomMargin(const MarginInfo &marginInfo)
1522 {
1523     if (marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()) {
1524         // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1525         // with our children.
1526         m_maxBottomPosMargin = qMax((int)m_maxBottomPosMargin, marginInfo.posMargin());
1527         m_maxBottomNegMargin = qMax((int)m_maxBottomNegMargin, marginInfo.negMargin());
1528 
1529         if (!marginInfo.bottomQuirk()) {
1530             m_bottomMarginQuirk = false;
1531         }
1532 
1533         if (marginInfo.bottomQuirk() && marginBottom() == 0)
1534             // We have no bottom margin and our last child has a quirky margin.
1535             // We will pick up this quirky margin and pass it through.
1536             // This deals with the <td><div><p> case.
1537         {
1538             m_bottomMarginQuirk = true;
1539         }
1540     }
1541 }
1542 
1543 void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo &marginInfo)
1544 {
1545     // If our last flow was a self-collapsing block that cleared a float, then we don't
1546     // collapse it with the bottom of the block.
1547     if (!marginInfo.selfCollapsingBlockClearedFloat()) {
1548         marginInfo.setAtBottomOfBlock(true);
1549     }
1550 
1551     // If we can't collapse with children then go ahead and add in the bottom margin.
1552     if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()
1553             && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk())) {
1554         m_height += marginInfo.margin();
1555     }
1556 
1557     // Now add in our bottom border/padding.
1558     m_height += bottom;
1559 
1560     // Negative margins can cause our height to shrink below our minimal height (border/padding).
1561     // If this happens, ensure that the computed height is increased to the minimal height.
1562     m_height = qMax(m_height, top + bottom);
1563 
1564     // Always make sure our overflow height is at least our height.
1565     m_overflowHeight = qMax(m_height, m_overflowHeight);
1566 
1567     // Update our bottom collapsed margin info.
1568     setCollapsedBottomMargin(marginInfo);
1569 }
1570 
1571 void RenderBlock::layoutBlockChildren(bool relayoutChildren)
1572 {
1573 #ifdef DEBUG_LAYOUT
1574     qCDebug(KHTML_LOG) << renderName() << " layoutBlockChildren( " << this << " ), relayoutChildren=" << relayoutChildren;
1575 #endif
1576 
1577     int top = borderTop() + paddingTop();
1578     int bottom = borderBottom() + paddingBottom();
1579     if (m_layer && scrollsOverflowX() && style()->height().isAuto()) {
1580         bottom += m_layer->horizontalScrollbarHeight();
1581     }
1582 
1583     m_height = m_overflowHeight = top;
1584 
1585     // The margin struct caches all our current margin collapsing state.
1586     // The compact struct caches state when we encounter compacts.
1587     MarginInfo marginInfo(this, top, bottom);
1588     CompactInfo compactInfo;
1589 
1590     // Fieldsets need to find their legend and position it inside the border of the object.
1591     // The legend then gets skipped during normal layout.
1592     RenderObject *legend = layoutLegend(relayoutChildren);
1593 
1594     PageBreakInfo pageBreakInfo(pageTopAfter(0));
1595 
1596     int previousFloatBottom = 0;
1597     RenderObject *child = firstChild();
1598     while (child != nullptr) {
1599         if (legend == child) {
1600             child = child->nextSibling();
1601             continue; // Skip the legend, since it has already been positioned up in the fieldset's border.
1602         }
1603 
1604         int oldTopPosMargin = m_maxTopPosMargin;
1605         int oldTopNegMargin = m_maxTopNegMargin;
1606 
1607         // make sure we relayout children if we need it.
1608         if ((!child->isPositioned() || child->isPosWithStaticDim()) && (relayoutChildren ||
1609                 (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent())) ||
1610                 (child->isRenderBlock() && child->style()->height().isPercent()) ||
1611                 (child->isBody() && child->style()->htmlHacks()))) {
1612             child->setChildNeedsLayout(true);
1613         }
1614 
1615         // Handle the four types of special elements first.  These include positioned content, floating content, compacts and
1616         // run-ins.  When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
1617         bool handled = false;
1618         RenderObject *next = handleSpecialChild(child, marginInfo, compactInfo, handled);
1619         if (handled) {
1620             child = next;
1621             continue;
1622         }
1623 
1624         // The child is a normal flow object.  Compute its vertical margins now.
1625         child->calcVerticalMargins();
1626 
1627 #ifdef APPLE_CHANGES /* margin-*-collapse not merged yet */
1628         // Do not allow a collapse if the margin top collapse style is set to SEPARATE.
1629         if (child->style()->marginTopCollapse() == MSEPARATE) {
1630             marginInfo.setAtTopOfBlock(false);
1631             marginInfo.clearMargin();
1632         }
1633 #endif
1634 
1635         // Try to guess our correct y position.  In most cases this guess will
1636         // be correct.  Only if we're wrong (when we compute the real y position)
1637         // will we have to potentially relayout.
1638         int yPosEstimate = estimateVerticalPosition(child, marginInfo);
1639         bool markDescendantsWithFloats = false;
1640         if (yPosEstimate != child->yPos() && !child->flowAroundFloats() && child->hasFloats()) {
1641             markDescendantsWithFloats = true;
1642         } else if (!child->flowAroundFloats() || child->usesLineWidth()) {
1643             // If an element might be affected by the presence of floats, then always mark it for
1644             // layout.
1645             int fb = qMax(previousFloatBottom, floatBottom());
1646             if (fb > yPosEstimate) {
1647                 markDescendantsWithFloats = true;
1648             }
1649         }
1650 
1651         if (child->isRenderBlock()) {
1652             if (markDescendantsWithFloats) {
1653                 child->markAllDescendantsWithFloatsForLayout();
1654             }
1655             previousFloatBottom = qMax(previousFloatBottom, child->yPos() + static_cast<RenderBlock *>(child)->floatBottom());
1656         }
1657 
1658         // Go ahead and position the child as though it didn't collapse with the top.
1659         child->setPos(child->xPos(), yPosEstimate);
1660         child->layoutIfNeeded();
1661 
1662         // Now determine the correct ypos based on examination of collapsing margin
1663         // values.
1664         int yBeforeClear = collapseMargins(child, marginInfo, yPosEstimate);
1665 
1666         // Now check for clear.
1667         int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear);
1668 
1669         child->setPos(child->xPos(), yAfterClear);
1670 
1671         // Now we have a final y position.  See if it really does end up being different from our estimate.
1672         if (yAfterClear != yPosEstimate) {
1673             if (child->usesLineWidth()) {
1674                 // The child's width depends on the line width.
1675                 // When the child shifts to clear an item, its width can
1676                 // change (because it has more available line width).
1677                 // So go ahead and mark the item as dirty.
1678                 child->setChildNeedsLayout(true, false);
1679             }
1680 
1681             if (!child->flowAroundFloats() && child->hasFloats()) {
1682                 child->markAllDescendantsWithFloatsForLayout();
1683             }
1684 
1685             // Our guess was wrong. Make the child lay itself out again.
1686             child->layoutIfNeeded();
1687         }
1688 
1689         // We are no longer at the top of the block if we encounter a non-empty child.
1690         // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
1691         if (marginInfo.atTopOfBlock() && !child->isSelfCollapsingBlock()) {
1692             marginInfo.setAtTopOfBlock(false);
1693         }
1694 
1695         // Now place the child in the correct horizontal position
1696         determineHorizontalPosition(child);
1697 
1698         adjustSizeForCompactIfNeeded(child, compactInfo);
1699         // Update our height now that the child has been placed in the correct position.
1700         m_height += child->height();
1701 
1702 #ifdef APPLE_CHANGES
1703         if (child->style()->marginBottomCollapse() == MSEPARATE) {
1704             m_height += child->marginBottom();
1705             marginInfo.clearMargin();
1706         }
1707 #endif
1708 
1709         // Check for page-breaks
1710         if (canvas()->pagedMode()) {
1711             clearChildOfPageBreaks(child, pageBreakInfo, marginInfo);
1712         }
1713 
1714         if (child->hasOverhangingFloats() && !child->flowAroundFloats()) {
1715             // need to add the child's floats to our floating objects list, but not in the case where
1716             // overflow is auto/scroll
1717             addOverHangingFloats(static_cast<RenderBlock *>(child), -child->xPos(), -child->yPos(), true);
1718         }
1719 
1720         // See if this child has made our overflow need to grow.
1721         int effX = child->effectiveXPos();
1722         int effY = child->effectiveYPos();
1723         m_overflowWidth = qMax(effX + child->effectiveWidth(), m_overflowWidth);
1724         m_overflowLeft = qMin(effX, m_overflowLeft);
1725         m_overflowHeight = qMax(effY + child->effectiveHeight(), m_overflowHeight);
1726         m_overflowTop = qMin(effY, m_overflowTop);
1727 
1728         // Insert our compact into the block margin if we have one.
1729         insertCompactIfNeeded(child, compactInfo);
1730 
1731         child = child->nextSibling();
1732     }
1733 
1734     // The last child had forced page-break-after
1735     if (pageBreakInfo.forcePageBreak()) {
1736         m_height = pageBreakInfo.pageBottom();
1737     }
1738 
1739     // Now do the handling of the bottom of the block, adding in our bottom border/padding and
1740     // determining the correct collapsed bottom margin information.
1741     handleBottomOfBlock(top, bottom, marginInfo);
1742 
1743     setNeedsLayout(false);
1744 }
1745 
1746 void RenderBlock::clearChildOfPageBreaks(RenderObject *child, PageBreakInfo &pageBreakInfo, MarginInfo &marginInfo)
1747 {
1748     (void)marginInfo;
1749     int childTop = child->yPos();
1750     int childBottom = child->yPos() + child->height();
1751 #ifdef PAGE_DEBUG
1752     qCDebug(KHTML_LOG) << renderName() << " ChildTop: " << childTop << " ChildBottom: " << childBottom;
1753 #endif
1754 
1755     bool forcePageBreak = pageBreakInfo.forcePageBreak() || child->style()->pageBreakBefore() == PBALWAYS;
1756 #ifdef PAGE_DEBUG
1757     if (forcePageBreak) {
1758         qCDebug(KHTML_LOG) << renderName() << "Forced break required";
1759     }
1760 #endif
1761 
1762     int xpage = crossesPageBreak(childTop, childBottom);
1763     if (xpage || forcePageBreak) {
1764         if (!forcePageBreak && child->containsPageBreak() && !child->needsPageClear()) {
1765 #ifdef PAGE_DEBUG
1766             qCDebug(KHTML_LOG) << renderName() << " Child contains page-break to page " << xpage;
1767 #endif
1768             // ### Actually this assumes floating children are breaking/clearing
1769             // nicely as well.
1770             setContainsPageBreak(true);
1771         } else {
1772             bool doBreak = true;
1773             // don't break before the first child or when page-break-inside is avoid
1774             if (!forcePageBreak && (!style()->pageBreakInside() || m_avoidPageBreak || child == firstChild())) {
1775                 if (parent() && parent()->canClear(this, (m_avoidPageBreak) ? PageBreakHarder : PageBreakNormal)) {
1776 #ifdef PAGE_DEBUG
1777                     qCDebug(KHTML_LOG) << renderName() << "Avoid page-break inside";
1778 #endif
1779                     child->setNeedsPageClear(false);
1780                     setNeedsPageClear(true);
1781                     doBreak = false;
1782                 }
1783 #ifdef PAGE_DEBUG
1784                 else {
1785                     qCDebug(KHTML_LOG) << renderName() << "Ignoring page-break avoid";
1786                 }
1787 #endif
1788             }
1789             if (doBreak) {
1790 #ifdef PAGE_DEBUG
1791                 qCDebug(KHTML_LOG) << renderName() << " Clearing child of page-break";
1792                 qCDebug(KHTML_LOG) << renderName() << " child top of page " << xpage;
1793 #endif
1794                 clearPageBreak(child, pageBreakInfo.pageBottom());
1795                 child->setNeedsPageClear(false);
1796                 setContainsPageBreak(true);
1797             }
1798         }
1799         pageBreakInfo.setPageBottom(pageBreakInfo.pageBottom() + canvas()->pageHeight());
1800     } else if (child->yPos() >= pageBreakInfo.pageBottom()) {
1801         bool doBreak = true;
1802 #ifdef PAGE_DEBUG
1803         qCDebug(KHTML_LOG) << "Page-break between children";
1804 #endif
1805         if (!style()->pageBreakInside() || m_avoidPageBreak) {
1806             if (parent() && parent()->canClear(this, (m_avoidPageBreak) ? PageBreakHarder : PageBreakNormal)) {
1807 #ifdef PAGE_DEBUG
1808                 qCDebug(KHTML_LOG) << "Avoid page-break inside";
1809 #endif
1810                 child->setNeedsPageClear(false);
1811                 setNeedsPageClear(true);
1812                 doBreak = false;
1813             }
1814 #ifdef PAGE_DEBUG
1815             else {
1816                 qCDebug(KHTML_LOG) << "Ignoring page-break avoid";
1817             }
1818 #endif
1819         }
1820         if (doBreak) {
1821             // Break between children
1822             setContainsPageBreak(true);
1823             // ### Should collapse top-margin with page-margin
1824         }
1825         pageBreakInfo.setPageBottom(pageBreakInfo.pageBottom() + canvas()->pageHeight());
1826     }
1827 
1828     // Do we need a forced page-break before next child?
1829     pageBreakInfo.setForcePageBreak(false);
1830     if (child->style()->pageBreakAfter() == PBALWAYS) {
1831         pageBreakInfo.setForcePageBreak(true);
1832     }
1833 }
1834 
1835 void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
1836 {
1837     if (m_positionedObjects) {
1838         for (int i = 0; i < m_positionedObjects->size(); i++) { // size() can grow during loop
1839             RenderObject *const r = m_positionedObjects->at(i);
1840             if (r->markedForRepaint()) {
1841                 r->repaintDuringLayout();
1842                 r->setMarkedForRepaint(false);
1843             }
1844             if (relayoutChildren || (r->isPosWithStaticDim() && r->parent() != this && r->parent()->isBlockFlow())) {
1845                 r->setChildNeedsLayout(true, false);
1846                 r->dirtyFormattingContext(false);
1847             }
1848             r->layoutIfNeeded();
1849         }
1850     }
1851 }
1852 
1853 void RenderBlock::paint(PaintInfo &pI, int _tx, int _ty)
1854 {
1855     _tx += m_x;
1856     _ty += m_y;
1857 
1858     // check if we need to do anything at all...
1859     if (!isRoot() && !isInlineFlow() && !isRelPositioned() && !isPositioned()) {
1860         int h = m_overflowHeight;
1861         int yPos = _ty;
1862         if (m_floatingObjects && floatBottom() > h) {
1863             h = floatBottom();
1864         }
1865 
1866         yPos += overflowTop();
1867 
1868         int os = maximalOutlineSize(pI.phase);
1869         if ((yPos > pI.r.bottom() + os) || (_ty + h <= pI.r.y() - os)) {
1870             return;
1871         }
1872     }
1873 
1874     paintObject(pI, _tx, _ty);
1875 }
1876 
1877 void RenderBlock::paintObject(PaintInfo &pI, int _tx, int _ty, bool shouldPaintOutline)
1878 {
1879 #ifdef DEBUG_LAYOUT
1880     qCDebug(KHTML_LOG) << renderName() << "(RenderBlock) " << this << " ::paintObject() w/h = (" << width() << "/" << height() << ")";
1881 #endif
1882 
1883     // If we're a repositioned run-in, don't paint background/borders.
1884     bool inlineFlow = isInlineFlow();
1885 
1886     // 1. paint background, borders etc
1887     if (!inlineFlow &&
1888             (pI.phase == PaintActionElementBackground || pI.phase == PaintActionChildBackground) &&
1889             shouldPaintBackgroundOrBorder() && style()->visibility() == VISIBLE) {
1890         paintBoxDecorations(pI, _tx, _ty);
1891     }
1892 
1893     if (pI.phase == PaintActionElementBackground) {
1894         return;
1895     }
1896     if (pI.phase == PaintActionChildBackgrounds) {
1897         pI.phase = PaintActionChildBackground;
1898     }
1899 
1900     // 2. paint contents
1901     int scrolledX = _tx;
1902     int scrolledY = _ty;
1903     if (hasOverflowClip() && m_layer) {
1904         m_layer->subtractScrollOffset(scrolledX, scrolledY);
1905     }
1906 
1907     if (childrenInline()) {
1908         paintLines(pI, scrolledX, scrolledY);
1909     } else {
1910         for (RenderObject *child = firstChild(); child; child = child->nextSibling())
1911             if (!child->layer() && !child->isFloating()) {
1912                 child->paint(pI, scrolledX, scrolledY);
1913             }
1914     }
1915 
1916     // 3. paint floats.
1917     if (!inlineFlow && (pI.phase == PaintActionFloat || pI.phase == PaintActionSelection)) {
1918         paintFloats(pI, scrolledX, scrolledY, pI.phase == PaintActionSelection);
1919     }
1920 
1921     // 4. paint outline.
1922     if (shouldPaintOutline && !inlineFlow && pI.phase == PaintActionOutline &&
1923             style()->outlineWidth() && style()->visibility() == VISIBLE) {
1924         paintOutline(pI.p, _tx, _ty, width(), height(), style());
1925     }
1926 
1927     // 5. paint caret.
1928     /*
1929         If the caret's node's render object's containing block is this block,
1930         and the paint action is PaintActionForeground,
1931         then paint the caret.
1932     */
1933     if ((!canvas()->hasSelection() && pI.phase == PaintActionForeground)
1934             || pI.phase == PaintActionSelection) {
1935         KHTMLPart *part = document()->part();
1936         const Selection &s = part->caret();
1937         NodeImpl *baseNode = s.extent().node();
1938         RenderObject *renderer = baseNode ? baseNode->renderer() : nullptr;
1939         if (renderer && renderer->containingBlock() == this && (part->isCaretMode() || baseNode->isContentEditable())) {
1940             part->paintCaret(pI.p, pI.r);
1941             part->paintDragCaret(pI.p, pI.r);
1942         }
1943     }
1944 
1945 #ifdef BOX_DEBUG
1946     if (style() && style()->visibility() == VISIBLE) {
1947         if (isAnonymous()) {
1948             outlineBox(pI.p, _tx, _ty, "green");
1949         }
1950         if (isFloating()) {
1951             outlineBox(pI.p, _tx, _ty, "yellow");
1952         } else {
1953             outlineBox(pI.p, _tx, _ty);
1954         }
1955     }
1956 #endif
1957 }
1958 
1959 QRegion RenderBlock::visibleFloatingRegion(int x, int y) const
1960 {
1961     if (!m_floatingObjects) {
1962         return QRegion();
1963     }
1964     FloatingObject *fo;
1965     QRegion r;
1966     QListIterator<FloatingObject *> it(*m_floatingObjects);
1967     while (it.hasNext()) {
1968         fo = it.next();
1969         if (!fo->noPaint && !fo->node->layer() && fo->node->style()->visibility() == VISIBLE) {
1970             const RenderStyle *s = fo->node->style();
1971             int ow = s->outlineSize();
1972             if (s->backgroundImage() || s->backgroundColor().isValid() || s->hasBorder() || fo->node->isReplaced() || ow) {
1973                 r += QRect(x - ow + fo->left + fo->node->marginLeft(),
1974                            y - ow + fo->startY + fo->node->marginTop(),
1975                            fo->width + ow * 2 - fo->node->marginLeft() - fo->node->marginRight(),
1976                            fo->endY - fo->startY + ow * 2 - fo->node->marginTop() - fo->node->marginBottom());
1977             } else {
1978                 r += fo->node->visibleFlowRegion(x + fo->left + fo->node->marginLeft(), y + fo->startY + fo->node->marginTop());
1979             }
1980         }
1981     }
1982     return r;
1983 }
1984 
1985 void RenderBlock::paintFloats(PaintInfo &pI, int _tx, int _ty, bool paintSelection)
1986 {
1987     if (!m_floatingObjects) {
1988         return;
1989     }
1990 
1991     FloatingObject *r;
1992     QListIterator<FloatingObject *> it(*m_floatingObjects);
1993     while (it.hasNext()) {
1994         r = it.next();
1995         // Only paint the object if our noPaint flag isn't set.
1996         if (r->node->isFloating() && !r->noPaint && !r->node->layer()) {
1997             PaintAction oldphase = pI.phase;
1998             if (paintSelection) {
1999                 pI.phase = PaintActionSelection;
2000                 r->node->paint(pI, _tx + r->left - r->node->xPos() + r->node->marginLeft(),
2001                                _ty + r->startY - r->node->yPos() + r->node->marginTop());
2002             } else {
2003                 pI.phase = PaintActionElementBackground;
2004                 r->node->paint(pI,
2005                                _tx + r->left - r->node->xPos() + r->node->marginLeft(),
2006                                _ty + r->startY - r->node->yPos() + r->node->marginTop());
2007                 pI.phase = PaintActionChildBackgrounds;
2008                 r->node->paint(pI,
2009                                _tx + r->left - r->node->xPos() + r->node->marginLeft(),
2010                                _ty + r->startY - r->node->yPos() + r->node->marginTop());
2011                 pI.phase = PaintActionFloat;
2012                 r->node->paint(pI,
2013                                _tx + r->left - r->node->xPos() + r->node->marginLeft(),
2014                                _ty + r->startY - r->node->yPos() + r->node->marginTop());
2015                 pI.phase = PaintActionForeground;
2016                 r->node->paint(pI,
2017                                _tx + r->left - r->node->xPos() + r->node->marginLeft(),
2018                                _ty + r->startY - r->node->yPos() + r->node->marginTop());
2019                 pI.phase = PaintActionOutline;
2020                 r->node->paint(pI,
2021                                _tx + r->left - r->node->xPos() + r->node->marginLeft(),
2022                                _ty + r->startY - r->node->yPos() + r->node->marginTop());
2023             }
2024             pI.phase = oldphase;
2025         }
2026     }
2027 }
2028 
2029 void RenderBlock::insertPositionedObject(RenderObject *o)
2030 {
2031     // Create the list of special objects if we don't aleady have one
2032     if (!m_positionedObjects) {
2033         m_positionedObjects = new QList<RenderObject *>;
2034     }
2035 
2036     // Create the special object entry & append it to the list
2037     m_positionedObjects->append(o);
2038     o->setInPosObjectList();
2039 }
2040 
2041 void RenderBlock::removePositionedObject(RenderObject *o)
2042 {
2043     if (m_positionedObjects) {
2044         m_positionedObjects->removeAll(o);
2045         if (m_positionedObjects->isEmpty()) {
2046             delete m_positionedObjects;
2047             m_positionedObjects = nullptr;
2048         }
2049     }
2050     o->setInPosObjectList(false);
2051 }
2052 
2053 void RenderBlock::insertFloatingObject(RenderObject *o)
2054 {
2055     // Create the list of special objects if we don't aleady have one
2056     if (!m_floatingObjects) {
2057         m_floatingObjects = new QList<FloatingObject *>;
2058     } else {
2059         // Don't insert the object again if it's already in the list
2060         QListIterator<FloatingObject *> it(*m_floatingObjects);
2061         FloatingObject *f;
2062         while (it.hasNext()) {
2063             f = it.next();
2064             if (f->node == o) {
2065                 return;
2066             }
2067         }
2068     }
2069 
2070     // Create the special object entry & append it to the list
2071 
2072     FloatingObject *newObj;
2073     if (o->isFloating()) {
2074         // floating object
2075         o->layoutIfNeeded();
2076 
2077         if (o->style()->floating() & FLEFT) {
2078             newObj = new FloatingObject(FloatingObject::FloatLeft);
2079         } else {
2080             newObj = new FloatingObject(FloatingObject::FloatRight);
2081         }
2082 
2083         newObj->startY = -500000;
2084         newObj->endY = -500000;
2085         newObj->width = o->width() + o->marginLeft() + o->marginRight();
2086     } else {
2087         // We should never get here, as insertFloatingObject() should only ever be called with floating
2088         // objects.
2089         KHTMLAssert(false);
2090         newObj = nullptr; // keep gcc's uninitialized variable warnings happy
2091     }
2092 
2093     newObj->node = o;
2094 
2095     m_floatingObjects->append(newObj);
2096 }
2097 
2098 void RenderBlock::removeFloatingObject(RenderObject *o)
2099 {
2100     if (m_floatingObjects) {
2101         QMutableListIterator<FloatingObject *> it(*m_floatingObjects);
2102         while (it.hasNext()) {
2103             if (it.next()->node == o) {
2104                 delete it.peekPrevious();
2105                 it.remove();
2106             }
2107         }
2108     }
2109 }
2110 
2111 void RenderBlock::positionNewFloats()
2112 {
2113     if (!m_floatingObjects) {
2114         return;
2115     }
2116     QListIterator<FloatingObject *> it(*m_floatingObjects);
2117     it.toBack();
2118     if (!it.hasPrevious() || it.previous()->startY != -500000) {
2119         return;
2120     }
2121     FloatingObject *lastFloat;
2122     while (1) {
2123         lastFloat = it.hasPrevious() ? it.previous() : nullptr;
2124         if (!lastFloat || lastFloat->startY != -500000) {
2125             if (lastFloat) {
2126                 it.next();
2127             }
2128             break;
2129         }
2130     }
2131     int y = m_height;
2132 
2133     // the float can not start above the y position of the last positioned float.
2134     if (lastFloat && lastFloat->startY > y) {
2135         y = lastFloat->startY;
2136     }
2137 
2138     KHTMLAssert(it.hasNext());
2139     FloatingObject *f = it.next();
2140 
2141     while (f) {
2142         //skip elements copied from elsewhere and positioned elements
2143         if (f->node->containingBlock() != this) {
2144             f = it.hasNext() ? it.next() : nullptr;
2145             continue;
2146         }
2147 
2148         RenderObject *o = f->node;
2149         int _height = o->height() + o->marginTop() + o->marginBottom();
2150 
2151         // floats avoid page-breaks
2152         if (canvas()->pagedMode()) {
2153             int top = y;
2154             int bottom = y + o->height();
2155             if (crossesPageBreak(top, bottom) && o->height() < canvas()->pageHeight()) {
2156                 int newY = pageTopAfter(top);
2157 #ifdef PAGE_DEBUG
2158                 qCDebug(KHTML_LOG) << renderName() << " clearing float " << newY - y << "px";
2159 #endif
2160                 y = newY;
2161             }
2162         }
2163 
2164         int ro = rightOffset(); // Constant part of right offset.
2165         int lo = leftOffset(); // Constant part of left offset.
2166         int fwidth = f->width; // The width we look for.
2167         //qCDebug(KHTML_LOG) << " Object width: " << fwidth << " available width: " << ro - lo;
2168 
2169         // in quirk mode, floated auto-width tables try to fit within remaining linewidth
2170         bool ftQuirk = o->isTable() && style()->htmlHacks() && o->style()->width().isAuto();
2171         if (ftQuirk) {
2172             fwidth = qMin(o->minWidth() + o->marginLeft() + o->marginRight(), fwidth);
2173         }
2174 
2175         if (ro - lo < fwidth) {
2176             fwidth = ro - lo;    // Never look for more than what will be available.
2177         }
2178 
2179         if (o->style()->clear() & CLEFT) {
2180             y = qMax(leftBottom(), y);
2181         }
2182         if (o->style()->clear() & CRIGHT) {
2183             y = qMax(rightBottom(), y);
2184         }
2185 
2186         bool canClearLine;
2187         if (o->style()->floating() & FLEFT) {
2188             int heightRemainingLeft = 1;
2189             int heightRemainingRight = 1;
2190             int fx = leftRelOffset(y, lo, false, &heightRemainingLeft, &canClearLine);
2191             if (canClearLine) {
2192                 while (rightRelOffset(y, ro, false, &heightRemainingRight) - fx < fwidth) {
2193                     y += qMin(heightRemainingLeft, heightRemainingRight);
2194                     fx = leftRelOffset(y, lo, false, &heightRemainingLeft);
2195                 }
2196             }
2197             if (ftQuirk && (rightRelOffset(y, ro, false) - fx < f->width)) {
2198                 o->setPos(o->xPos(), y + o->marginTop());
2199                 o->setChildNeedsLayout(true, false);
2200                 o->layoutIfNeeded();
2201                 _height = o->height() + o->marginTop() + o->marginBottom();
2202                 f->width = o->width() + o->marginLeft() + o->marginRight();
2203             }
2204             f->left = fx;
2205             //qCDebug(KHTML_LOG) << "positioning left aligned float at (" << fx + o->marginLeft()  << "/" << y + o->marginTop() << ") fx=" << fx;
2206             o->setPos(fx + o->marginLeft(), y + o->marginTop());
2207         } else {
2208             int heightRemainingLeft = 1;
2209             int heightRemainingRight = 1;
2210             int fx = rightRelOffset(y, ro, false, &heightRemainingRight, &canClearLine);
2211             if (canClearLine) {
2212                 while (fx - leftRelOffset(y, lo, false, &heightRemainingLeft) < fwidth) {
2213                     y += qMin(heightRemainingLeft, heightRemainingRight);
2214                     fx = rightRelOffset(y, ro, false, &heightRemainingRight);
2215                 }
2216             }
2217             if (ftQuirk && (fx - leftRelOffset(y, lo, false) < f->width)) {
2218                 o->setPos(o->xPos(), y + o->marginTop());
2219                 o->setChildNeedsLayout(true, false);
2220                 o->layoutIfNeeded();
2221                 _height = o->height() + o->marginTop() + o->marginBottom();
2222                 f->width = o->width() + o->marginLeft() + o->marginRight();
2223             }
2224             f->left = fx - f->width;
2225             //qCDebug(KHTML_LOG) << "positioning right aligned float at (" << fx - o->marginRight() - o->width() << "/" << y + o->marginTop() << ")";
2226             o->setPos(fx - o->marginRight() - o->width(), y + o->marginTop());
2227         }
2228 
2229         if (m_layer && hasOverflowClip()) {
2230             if (o->xPos() + o->width() > m_overflowWidth) {
2231                 m_overflowWidth = o->xPos() + o->width();
2232             } else if (o->xPos() < m_overflowLeft) {
2233                 m_overflowLeft = o->xPos();
2234             }
2235         }
2236 
2237         f->startY = y;
2238         f->endY = f->startY + _height;
2239 
2240         //qCDebug(KHTML_LOG) << "floatingObject x/y= (" << f->left << "/" << f->startY << "-" << f->width << "/" << f->endY - f->startY << ")";
2241 
2242         f = it.hasNext() ? it.next() : nullptr;
2243     }
2244 }
2245 
2246 void RenderBlock::newLine()
2247 {
2248     positionNewFloats();
2249     // set y position
2250     int newY = 0;
2251     switch (m_clearStatus) {
2252     case CLEFT:
2253         newY = leftBottom();
2254         break;
2255     case CRIGHT:
2256         newY = rightBottom();
2257         break;
2258     case CBOTH:
2259         newY = floatBottom();
2260     default:
2261         break;
2262     }
2263     if (m_height < newY) {
2264         //      qCDebug(KHTML_LOG) << "adjusting y position";
2265         m_height = newY;
2266     }
2267     m_clearStatus = CNONE;
2268 }
2269 
2270 int
2271 RenderBlock::leftOffset() const
2272 {
2273     int left = borderLeft() + paddingLeft();
2274     if (m_layer && scrollsOverflowY() && m_layer->hasReversedScrollbar()) {
2275         left += m_layer->verticalScrollbarWidth();
2276     }
2277     return left;
2278 }
2279 
2280 int
2281 RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, int *heightRemaining, bool *canClearLine) const
2282 {
2283     int left = fixedOffset;
2284     if (canClearLine) {
2285         *canClearLine = true;
2286     }
2287 
2288     if (m_floatingObjects) {
2289         if (heightRemaining) {
2290             *heightRemaining = 1;
2291         }
2292         FloatingObject *r;
2293         QListIterator<FloatingObject *> it(*m_floatingObjects);
2294         while (it.hasNext()) {
2295             r = it.next();
2296             //qCDebug(KHTML_LOG) <<(void *)this << " left: sy, ey, x, w " << r->startY << "," << r->endY << "," << r->left << "," << r->width << " ";
2297             if (r->startY <= y && r->endY > y &&
2298                     r->type == FloatingObject::FloatLeft &&
2299                     r->left + r->width > left) {
2300                 left = r->left + r->width;
2301                 if (heightRemaining) {
2302                     *heightRemaining = r->endY - y;
2303                 }
2304                 if (canClearLine) {
2305                     *canClearLine = (r->node->style()->floating() != FLEFT_ALIGN);
2306                 }
2307             }
2308         }
2309     }
2310 
2311     if (applyTextIndent && m_firstLine && style()->direction() == LTR) {
2312         int cw = 0;
2313         if (style()->textIndent().isPercent()) {
2314             cw = containingBlock()->contentWidth();
2315         }
2316         left += style()->textIndent().minWidth(cw);
2317     }
2318 
2319     //qCDebug(KHTML_LOG) << "leftOffset(" << y << ") = " << left;
2320     return left;
2321 }
2322 
2323 int
2324 RenderBlock::rightOffset() const
2325 {
2326     int right = m_width - borderRight() - paddingRight();
2327     if (m_layer && scrollsOverflowY() && !m_layer->hasReversedScrollbar()) {
2328         right -= m_layer->verticalScrollbarWidth();
2329     }
2330     return right;
2331 }
2332 
2333 int
2334 RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, int *heightRemaining, bool *canClearLine) const
2335 {
2336     int right = fixedOffset;
2337     if (canClearLine) {
2338         *canClearLine = true;
2339     }
2340 
2341     if (m_floatingObjects) {
2342         if (heightRemaining) {
2343             *heightRemaining = 1;
2344         }
2345         FloatingObject *r;
2346         QListIterator<FloatingObject *> it(*m_floatingObjects);
2347         while (it.hasNext()) {
2348             r = it.next();
2349             //qCDebug(KHTML_LOG) << "right: sy, ey, x, w " << r->startY << "," << r->endY << "," << r->left << "," << r->width << " ";
2350             if (r->startY <= y && r->endY > y &&
2351                     r->type == FloatingObject::FloatRight &&
2352                     r->left < right) {
2353                 right = r->left;
2354                 if (heightRemaining) {
2355                     *heightRemaining = r->endY - y;
2356                 }
2357                 if (canClearLine) {
2358                     *canClearLine = (r->node->style()->floating() != FRIGHT_ALIGN);
2359                 }
2360             }
2361         }
2362     }
2363 
2364     if (applyTextIndent &&  m_firstLine && style()->direction() == RTL) {
2365         int cw = 0;
2366         if (style()->textIndent().isPercent()) {
2367             cw = containingBlock()->contentWidth();
2368         }
2369         right -= style()->textIndent().minWidth(cw);
2370     }
2371 
2372     //qCDebug(KHTML_LOG) << "rightOffset(" << y << ") = " << right;
2373     return right;
2374 }
2375 
2376 unsigned short
2377 RenderBlock::lineWidth(int y, bool *canClearLine) const
2378 {
2379     //qCDebug(KHTML_LOG) << "lineWidth(" << y << ")=" << rightOffset(y) - leftOffset(y);
2380     int result;
2381     if (canClearLine) {
2382         bool rightCanClearLine;
2383         bool leftCanClearLine;
2384         result = rightOffset(y, &rightCanClearLine) - leftOffset(y, &leftCanClearLine);
2385         *canClearLine = rightCanClearLine && leftCanClearLine;
2386     } else {
2387         result = rightOffset(y) - leftOffset(y);
2388     }
2389     return (result < 0) ? 0 : result;
2390 }
2391 
2392 int
2393 RenderBlock::nearestFloatBottom(int height) const
2394 {
2395     if (!m_floatingObjects) {
2396         return 0;
2397     }
2398 
2399     int bottom = INT_MAX;
2400     FloatingObject *r;
2401     QListIterator<FloatingObject *> it(*m_floatingObjects);
2402     while (it.hasNext()) {
2403         r = it.next();
2404         if (r->endY > height) {
2405             bottom = qMin(r->endY, bottom);
2406         }
2407     }
2408 
2409     return bottom == INT_MAX ? 0 : bottom;
2410 }
2411 
2412 int RenderBlock::floatBottom() const
2413 {
2414     if (!m_floatingObjects) {
2415         return 0;
2416     }
2417     int bottom = 0;
2418     FloatingObject *r;
2419     QListIterator<FloatingObject *> it(*m_floatingObjects);
2420     while (it.hasNext()) {
2421         r = it.next();
2422         if (r->endY > bottom) {
2423             bottom = r->endY;
2424         }
2425     }
2426     return bottom;
2427 }
2428 
2429 int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
2430 {
2431     int bottom = RenderFlow::lowestPosition(includeOverflowInterior, includeSelf);
2432     if (!includeOverflowInterior && hasOverflowClip()) {
2433         return bottom;
2434     }
2435     if (includeSelf && m_overflowHeight > bottom) {
2436         bottom = m_overflowHeight;
2437     }
2438 
2439     if (m_floatingObjects) {
2440         FloatingObject *r;
2441         QListIterator<FloatingObject *> it(*m_floatingObjects);
2442         while (it.hasNext()) {
2443             r = it.next();
2444             if (!r->noPaint) {
2445                 int lp = r->startY + r->node->marginTop() + r->node->lowestPosition(false);
2446                 bottom = qMax(bottom, lp);
2447             }
2448         }
2449     }
2450     bottom = qMax(bottom, lowestAbsolutePosition());
2451 
2452     if (!includeSelf && lastLineBox()) {
2453         int lp = lastLineBox()->yPos() + lastLineBox()->height();
2454         bottom = qMax(bottom, lp);
2455     }
2456 
2457     return bottom;
2458 }
2459 
2460 int RenderBlock::lowestAbsolutePosition() const
2461 {
2462     if (!m_positionedObjects) {
2463         return 0;
2464     }
2465 
2466     // Fixed positioned objects do not scroll and thus should not constitute
2467     // part of the lowest position.
2468     int bottom = 0;
2469     RenderObject *r;
2470     QListIterator<RenderObject *> it(*m_positionedObjects);
2471     while (it.hasNext()) {
2472         r = it.next();
2473         if (r->style()->position() == PFIXED) {
2474             continue;
2475         }
2476         int lp = r->yPos() + r->lowestPosition(false);
2477         bottom = qMax(bottom, lp);
2478     }
2479     return bottom;
2480 }
2481 
2482 int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
2483 {
2484     int right = RenderFlow::rightmostPosition(includeOverflowInterior, includeSelf);
2485     if (!includeOverflowInterior && hasOverflowClip()) {
2486         return right;
2487     }
2488     if (includeSelf && m_overflowWidth > right) {
2489         right = m_overflowWidth;
2490     }
2491 
2492     if (m_floatingObjects) {
2493         FloatingObject *r;
2494         QListIterator<FloatingObject *> it(*m_floatingObjects);
2495         while (it.hasNext()) {
2496             r = it.next();
2497             if (!r->noPaint) {
2498                 int rp = r->left + r->node->marginLeft() + r->node->rightmostPosition(false);
2499                 right = qMax(right, rp);
2500             }
2501         }
2502     }
2503     right = qMax(right, rightmostAbsolutePosition());
2504 
2505     if (!includeSelf && firstLineBox()) {
2506         for (InlineRunBox *currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) {
2507             int rp = currBox->xPos() + currBox->width();
2508             right = qMax(right, rp);
2509         }
2510     }
2511 
2512     return right;
2513 }
2514 
2515 int RenderBlock::rightmostAbsolutePosition() const
2516 {
2517     if (!m_positionedObjects) {
2518         return 0;
2519     }
2520     int right = 0;
2521     RenderObject *r;
2522     QListIterator<RenderObject *> it(*m_positionedObjects);
2523     while (it.hasNext()) {
2524         r = it.next();
2525         if (r->style()->position() == PFIXED) {
2526             continue;
2527         }
2528         int rp = r->xPos() + r->rightmostPosition(false);
2529         right = qMax(right, rp);
2530     }
2531     return right;
2532 }
2533 
2534 int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
2535 {
2536     int left = RenderFlow::leftmostPosition(includeOverflowInterior, includeSelf);
2537     if (!includeOverflowInterior && hasOverflowClip()) {
2538         return left;
2539     }
2540 
2541     if (includeSelf && m_overflowLeft < left) {
2542         left = m_overflowLeft;
2543     }
2544 
2545     if (m_floatingObjects) {
2546         FloatingObject *r;
2547         QListIterator<FloatingObject *> it(*m_floatingObjects);
2548         while (it.hasNext()) {
2549             r = it.next();
2550             if (!r->noPaint) {
2551                 int lp = r->left + r->node->marginLeft() + r->node->leftmostPosition(false);
2552                 left = qMin(left, lp);
2553             }
2554         }
2555     }
2556     left = qMin(left, leftmostAbsolutePosition());
2557 
2558     if (!includeSelf && firstLineBox()) {
2559         for (InlineRunBox *currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) {
2560             left = qMin(left, (int)currBox->xPos());
2561         }
2562     }
2563 
2564     return left;
2565 }
2566 
2567 int RenderBlock::leftmostAbsolutePosition() const
2568 {
2569     if (!m_positionedObjects) {
2570         return 0;
2571     }
2572     int  left = 0;
2573     RenderObject *r;
2574     QListIterator<RenderObject *> it(*m_positionedObjects);
2575     while (it.hasNext()) {
2576         r = it.next();
2577         if (r->style()->position() == PFIXED) {
2578             continue;
2579         }
2580         int lp = r->xPos() + r->leftmostPosition(false);
2581         left = qMin(left, lp);
2582     }
2583     return left;
2584 }
2585 
2586 int RenderBlock::highestPosition(bool includeOverflowInterior, bool includeSelf) const
2587 {
2588     int top = RenderFlow::highestPosition(includeOverflowInterior, includeSelf);
2589     if (!includeOverflowInterior && hasOverflowClip()) {
2590         return top;
2591     }
2592 
2593     if (includeSelf && m_overflowTop < top) {
2594         top = m_overflowTop;
2595     }
2596 
2597     if (m_floatingObjects) {
2598         FloatingObject *r;
2599         QListIterator<FloatingObject *> it(*m_floatingObjects);
2600         while (it.hasNext()) {
2601             r = it.next();
2602             if (!r->noPaint) {
2603                 int hp = r->startY + r->node->marginTop() + r->node->highestPosition(false);
2604                 top = qMin(top, hp);
2605             }
2606         }
2607     }
2608     top = qMin(top, highestAbsolutePosition());
2609 
2610     if (!includeSelf && firstLineBox()) {
2611         top = qMin(top, (int)firstLineBox()->yPos());
2612     }
2613 
2614     return top;
2615 }
2616 
2617 int RenderBlock::highestAbsolutePosition() const
2618 {
2619     if (!m_positionedObjects) {
2620         return 0;
2621     }
2622     int  top = 0;
2623     RenderObject *r;
2624     QListIterator<RenderObject *> it(*m_positionedObjects);
2625     while (it.hasNext()) {
2626         r = it.next();
2627         if (r->style()->position() == PFIXED) {
2628             continue;
2629         }
2630         int hp = r->yPos() + r->highestPosition(false);
2631         hp = qMin(top, hp);
2632     }
2633     return top;
2634 }
2635 
2636 int
2637 RenderBlock::leftBottom()
2638 {
2639     if (!m_floatingObjects) {
2640         return 0;
2641     }
2642     int bottom = 0;
2643     FloatingObject *r;
2644     QListIterator<FloatingObject *> it(*m_floatingObjects);
2645     while (it.hasNext()) {
2646         r = it.next();
2647         if (r->endY > bottom && r->type == FloatingObject::FloatLeft) {
2648             bottom = r->endY;
2649         }
2650     }
2651     return bottom;
2652 }
2653 
2654 int
2655 RenderBlock::rightBottom()
2656 {
2657     if (!m_floatingObjects) {
2658         return 0;
2659     }
2660     int bottom = 0;
2661     FloatingObject *r;
2662     QListIterator<FloatingObject *> it(*m_floatingObjects);
2663     while (it.hasNext()) {
2664         r = it.next();
2665         if (r->endY > bottom && r->type == FloatingObject::FloatRight) {
2666             bottom = r->endY;
2667         }
2668     }
2669     return bottom;
2670 }
2671 
2672 void
2673 RenderBlock::clearFloats()
2674 {
2675     if (m_floatingObjects) {
2676         QListIterator<FloatingObject *> it(*m_floatingObjects);
2677         while (it.hasNext()) {
2678             delete it.next();
2679         }
2680         m_floatingObjects->clear();
2681     }
2682 
2683     // we are done if the element defines a new block formatting context
2684     if (flowAroundFloats() || isRoot() || isCanvas() || isFloatingOrPositioned() || isTableCell()) {
2685         return;
2686     }
2687 
2688     RenderObject *prev = previousSibling();
2689 
2690     // find the element to copy the floats from
2691     // pass non-flows
2692     // pass fAF's
2693     bool parentHasFloats = false;
2694     while (prev) {
2695         if (!prev->isRenderBlock() || prev->isFloatingOrPositioned() || prev->flowAroundFloats()) {
2696             if (prev->isFloating() && parent()->isRenderBlock()) {
2697                 parentHasFloats = true;
2698             }
2699             prev = prev->previousSibling();
2700         } else {
2701             break;
2702         }
2703     }
2704 
2705     int offset = m_y;
2706     if (parentHasFloats) {
2707         addOverHangingFloats(static_cast<RenderBlock *>(parent()),
2708                              parent()->borderLeft() + parent()->paddingLeft(), offset, false);
2709     }
2710 
2711     int xoffset = 0;
2712     if (prev) {
2713         if (prev->isTableCell()) {
2714             return;
2715         }
2716         offset -= prev->yPos();
2717     } else {
2718         prev = parent();
2719         if (!prev) {
2720             return;
2721         }
2722         xoffset += prev->borderLeft() + prev->paddingLeft();
2723     }
2724     //qCDebug(KHTML_LOG) << "RenderBlock::clearFloats found previous "<< (void *)this << " prev=" << (void *)prev;
2725 
2726     // add overhanging special objects from the previous RenderBlock
2727     if (!prev->isRenderBlock()) {
2728         return;
2729     }
2730     RenderBlock *flow = static_cast<RenderBlock *>(prev);
2731     if (!flow->m_floatingObjects) {
2732         return;
2733     }
2734     if (flow->floatBottom() > offset) {
2735         addOverHangingFloats(flow, xoffset, offset, false);
2736     }
2737 }
2738 
2739 void RenderBlock::addOverHangingFloats(RenderBlock *flow, int xoff, int offset, bool child)
2740 {
2741 #ifdef DEBUG_LAYOUT
2742     qCDebug(KHTML_LOG) << (void *)this << ": adding overhanging floats xoff=" << xoff << "  offset=" << offset << " child=" << child;
2743 #endif
2744 
2745     // Prevent floats from being added to the canvas by the root element, e.g., <html>.
2746     if (!flow->m_floatingObjects || (child && flow->isRoot())) {
2747         return;
2748     }
2749 
2750     // if I am clear of my floats, don't add them
2751     // the CSS spec also mentions that child floats
2752     // are not cleared.
2753     if (!child && style()->clear() == CBOTH) {
2754         return;
2755     }
2756 
2757     QListIterator<FloatingObject *> it(*flow->m_floatingObjects);
2758     FloatingObject *r;
2759     while (it.hasNext()) {
2760         r = it.next();
2761 
2762         if (!child && r->type == FloatingObject::FloatLeft && style()->clear() == CLEFT) {
2763             continue;
2764         }
2765         if (!child && r->type == FloatingObject::FloatRight && style()->clear() == CRIGHT) {
2766             continue;
2767         }
2768 
2769         if ((!child && r->endY > offset) ||
2770                 (child && flow->yPos() + r->endY > height())) {
2771             if (child && !r->crossedLayer) {
2772                 if (flow->enclosingLayer() == enclosingLayer()) {
2773                     // Set noPaint to true only if we didn't cross layers.
2774                     r->noPaint = true;
2775                 } else {
2776                     r->crossedLayer = true;
2777                 }
2778             }
2779 
2780             // don't insert it twice!
2781             if (!containsFloat(r->node)) {
2782                 FloatingObject *floatingObj = new FloatingObject(KDE_CAST_BF_ENUM(FloatingObject::Type, r->type));
2783                 floatingObj->startY = r->startY - offset;
2784                 floatingObj->endY = r->endY - offset;
2785                 floatingObj->left = r->left - xoff;
2786                 // Applying the child's margin makes no sense in the case where the child was passed in.
2787                 // since his own margin was added already through the subtraction of the |xoff| variable
2788                 // above.  |xoff| will equal -flow->marginLeft() in this case, so it's already been taken
2789                 // into account.  Only apply this code if |child| is false, since otherwise the left margin
2790                 // will get applied twice. -dwh
2791                 if (!child && flow != parent()) {
2792                     floatingObj->left += flow->marginLeft();
2793                 }
2794                 if (!child) {
2795                     floatingObj->left -= marginLeft();
2796                     floatingObj->noPaint = true;
2797                 } else {
2798                     floatingObj->noPaint = (r->crossedLayer || !r->noPaint);
2799                     floatingObj->crossedLayer = r->crossedLayer;
2800                 }
2801 
2802                 floatingObj->width = r->width;
2803                 floatingObj->node = r->node;
2804                 if (!m_floatingObjects) {
2805                     m_floatingObjects = new QList<FloatingObject *>;
2806                 }
2807                 m_floatingObjects->append(floatingObj);
2808 #ifdef DEBUG_LAYOUT
2809                 qCDebug(KHTML_LOG) << "addOverHangingFloats x/y= (" << floatingObj->left << "/" << floatingObj->startY << "-" << floatingObj->width << "/" << floatingObj->endY - floatingObj->startY << ")";
2810 #endif
2811             }
2812         }
2813     }
2814 }
2815 
2816 bool RenderBlock::containsFloat(RenderObject *o) const
2817 {
2818     if (m_floatingObjects) {
2819         QListIterator<FloatingObject *> it(*m_floatingObjects);
2820         while (it.hasNext()) {
2821             if (it.next()->node == o) {
2822                 return true;
2823             }
2824         }
2825     }
2826     return false;
2827 }
2828 
2829 void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderObject *floatToRemove)
2830 {
2831     dirtyFormattingContext(false);
2832     setChildNeedsLayout(true);
2833 
2834     if (floatToRemove) {
2835         removeFloatingObject(floatToRemove);
2836     }
2837 
2838     // Iterate over our children and mark them as needed.
2839     if (!childrenInline()) {
2840         for (RenderObject *child = firstChild(); child; child = child->nextSibling()) {
2841             if (isBlockFlow() && !child->isFloatingOrPositioned() &&
2842                     ((floatToRemove ? child->containsFloat(floatToRemove) : child->hasFloats()) || child->usesLineWidth())) {
2843                 child->markAllDescendantsWithFloatsForLayout(floatToRemove);
2844             }
2845         }
2846     }
2847 }
2848 
2849 int RenderBlock::getClearDelta(RenderObject *child, int yPos)
2850 {
2851     if (!hasFloats()) {
2852         return 0;
2853     }
2854 
2855     //qCDebug(KHTML_LOG) << "getClearDelta on child " << child << " oldheight=" << m_height;
2856     bool clearSet = child->style()->clear() != CNONE;
2857     int bottom = 0;
2858     switch (child->style()->clear()) {
2859     case CNONE:
2860         break;
2861     case CLEFT:
2862         bottom = leftBottom();
2863         break;
2864     case CRIGHT:
2865         bottom = rightBottom();
2866         break;
2867     case CBOTH:
2868         bottom = floatBottom();
2869         break;
2870     }
2871 
2872     // We also clear floats if we are too big to sit on the same line as
2873     // a float, and happen to flow around floats.
2874     int result = clearSet ? qMax(0, bottom - yPos) : 0;
2875     if (!result && child->flowAroundFloats()) {
2876         bool canClear = true;
2877         bool needsRecalc = child->usesLineWidth();
2878         int cury = yPos;
2879         int childw = 0;
2880         int aw = contentWidth();
2881 #if 0
2882         // this is a silly Gecko compatibility hack - enable only if it becomes
2883         // necessary, and then check regularly with new Gecko versions
2884         if (!style()->hasBorder()) {
2885             RenderObject *ps = child;
2886             while ((ps = ps->previousSibling())) {
2887                 if (!ps->isFloating() && !ps->isPositioned()) {
2888                     break;
2889                 }
2890             }
2891             if (!ps) {
2892                 return 0;
2893             }
2894         }
2895 #endif
2896         while (true) {
2897             int curw = lineWidth(cury, &canClear);
2898             if (!canClear || curw == aw) {
2899                 return cury - yPos;
2900             }
2901             if (!childw || needsRecalc) {
2902                 int oy = child->yPos();
2903                 int ow = child->width();
2904                 child->setPos(child->xPos(), cury);
2905                 child->calcWidth();
2906                 childw = child->width();
2907                 child->setPos(child->xPos(), oy);
2908                 child->setWidth(ow);
2909             }
2910             if (childw <= curw) {
2911                 return cury - yPos;
2912             }
2913             if (!(cury = nearestFloatBottom(cury))) {
2914                 return 0;
2915             }
2916         }
2917     }
2918     return result;
2919 }
2920 
2921 bool RenderBlock::isPointInScrollbar(int _x, int _y, int _tx, int _ty)
2922 {
2923     if (!scrollsOverflow() || !m_layer) {
2924         return false;
2925     }
2926 
2927     if (m_layer->verticalScrollbarWidth()) {
2928         bool rtl = QApplication::isRightToLeft();
2929         QRect vertRect(_tx + (rtl ? borderLeft() :  width() - borderRight() - m_layer->verticalScrollbarWidth()),
2930                        _ty + borderTop() - borderTopExtra(),
2931                        m_layer->verticalScrollbarWidth(),
2932                        height() + borderTopExtra() + borderBottomExtra() - borderTop() - borderBottom());
2933         if (vertRect.contains(_x, _y)) {
2934             RenderLayer::gScrollBar = m_layer->verticalScrollbar();
2935             return true;
2936         }
2937     }
2938 
2939     if (m_layer->horizontalScrollbarHeight()) {
2940         QRect horizRect(_tx + borderLeft(),
2941                         _ty + height() - borderBottom() + borderBottomExtra() - m_layer->horizontalScrollbarHeight(),
2942                         width() - borderLeft() - borderRight(),
2943                         m_layer->horizontalScrollbarHeight());
2944         if (horizRect.contains(_x, _y)) {
2945             RenderLayer::gScrollBar = m_layer->horizontalScrollbar();
2946             return true;
2947         }
2948     }
2949 
2950     return false;
2951 }
2952 
2953 bool RenderBlock::nodeAtPoint(NodeInfo &info, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction, bool inBox)
2954 {
2955     bool inScrollbar = isPointInScrollbar(_x, _y, _tx + xPos(), _ty + yPos());
2956     if (inScrollbar && hitTestAction != HitTestChildrenOnly) {
2957         inBox = true;
2958     }
2959 
2960     if (hitTestAction != HitTestSelfOnly && m_floatingObjects && !inScrollbar) {
2961         int stx = _tx + xPos();
2962         int sty = _ty + yPos();
2963         if (hasOverflowClip() && m_layer) {
2964             m_layer->subtractScrollOffset(stx, sty);
2965         }
2966         FloatingObject *o;
2967         QListIterator<FloatingObject *> it(*m_floatingObjects);
2968         it.toBack();
2969         while (it.hasPrevious()) {
2970             o = it.previous();
2971             if (!o->noPaint && !o->node->layer())
2972                 inBox |= o->node->nodeAtPoint(info, _x, _y,
2973                                               stx + o->left + o->node->marginLeft() - o->node->xPos(),
2974                                               sty + o->startY + o->node->marginTop() - o->node->yPos(), HitTestAll);
2975         }
2976     }
2977     inBox |= RenderFlow::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inBox);
2978     return inBox;
2979 }
2980 
2981 RenderPosition RenderBlock::positionForBox(InlineBox *box, bool start) const
2982 {
2983     if (!box) {
2984         return RenderPosition();
2985     }
2986 
2987     if (!box->object()->element()) {
2988         return RenderPosition(element(), start ? caretMinOffset() : caretMaxOffset());
2989     }
2990 
2991     if (!box->isInlineTextBox()) {
2992         return RenderPosition(box->object()->element(), start ? box->object()->caretMinOffset() : box->object()->caretMaxOffset());
2993     }
2994 
2995     InlineTextBox *textBox = static_cast<InlineTextBox *>(box);
2996     return RenderPosition(box->object()->element(), start ? textBox->start() : textBox->start() + textBox->len());
2997 }
2998 
2999 RenderPosition RenderBlock::positionForRenderer(RenderObject *renderer, bool start) const
3000 {
3001     if (!renderer) {
3002         return RenderPosition(element(), 0);
3003     }
3004 
3005     NodeImpl *node = renderer->element() ? renderer->element() : element();
3006     if (!node) {
3007         return RenderPosition();
3008     }
3009 
3010     long offset = start ? node->caretMinOffset() : node->caretMaxOffset();
3011     return RenderPosition(node, offset);
3012 }
3013 
3014 RenderPosition RenderBlock::positionForCoordinates(int _x, int _y)
3015 {
3016     if (isTable()) {
3017         return RenderFlow::positionForCoordinates(_x, _y);
3018     }
3019 
3020     int absx, absy;
3021     absolutePosition(absx, absy);
3022 
3023     int top = absy + borderTop() + paddingTop();
3024     int bottom = top + contentHeight();
3025 
3026     if (_y < top)
3027         // y coordinate is above block
3028     {
3029         return positionForRenderer(firstLeafChild(), true);
3030     }
3031 
3032     if (_y >= bottom)
3033         // y coordinate is below block
3034     {
3035         return positionForRenderer(lastLeafChild(), false);
3036     }
3037 
3038     if (childrenInline()) {
3039         if (!firstRootBox()) {
3040             return Position(element(), 0);
3041         }
3042 
3043         if (_y >= top && _y < absy + firstRootBox()->topOverflow())
3044             // y coordinate is above first root line box
3045         {
3046             return positionForBox(firstRootBox()->firstLeafChild(), true);
3047         }
3048 
3049         // look for the closest line box in the root box which is at the passed-in y coordinate
3050         for (RootInlineBox *root = firstRootBox(); root; root = root->nextRootBox()) {
3051             top = absy + root->topOverflow();
3052             // set the bottom based on whether there is a next root box
3053             if (root->nextRootBox()) {
3054                 bottom = absy + root->nextRootBox()->topOverflow();
3055             } else {
3056                 bottom = absy + root->bottomOverflow();
3057             }
3058             // check if this root line box is located at this y coordinate
3059             if (_y >= top && _y < bottom && root->firstChild()) {
3060                 InlineBox *closestBox = root->closestLeafChildForXPos(_x, absx);
3061                 if (closestBox) {
3062                     // pass the box a y position that is inside it
3063                     return closestBox->object()->positionForCoordinates(_x, absy + closestBox->m_y);
3064                 }
3065             }
3066         }
3067 
3068         if (lastRootBox())
3069             // y coordinate is below last root line box
3070         {
3071             return positionForBox(lastRootBox()->lastLeafChild(), false);
3072         }
3073 
3074         return RenderPosition(element(), 0);
3075     }
3076 
3077     // see if any child blocks exist at this y coordinate
3078     for (RenderObject *renderer = firstChild(); renderer; renderer = renderer->nextSibling()) {
3079         if (renderer->isFloatingOrPositioned()) {
3080             continue;
3081         }
3082         renderer->absolutePosition(absx, top);
3083         RenderObject *next = renderer->nextSibling();
3084         while (next && next->isFloatingOrPositioned()) {
3085             next = next->nextSibling();
3086         }
3087         if (next) {
3088             next->absolutePosition(absx, bottom);
3089         } else {
3090             bottom = top + contentHeight();
3091         }
3092         if (_y >= top && _y < bottom) {
3093             return renderer->positionForCoordinates(_x, _y);
3094         }
3095     }
3096 
3097     // pass along to the first child
3098     if (firstChild()) {
3099         return firstChild()->positionForCoordinates(_x, _y);
3100     }
3101 
3102     // still no luck...return this render object's element and offset 0
3103     return RenderPosition(element(), 0);
3104 }
3105 
3106 void RenderBlock::calcMinMaxWidth()
3107 {
3108     KHTMLAssert(!minMaxKnown());
3109 
3110 #ifdef DEBUG_LAYOUT
3111     qCDebug(KHTML_LOG) << renderName() << "(RenderBlock)::calcMinMaxWidth() this=" << this;
3112 #endif
3113     if (!isTableCell() && style()->width().isFixed() && style()->width().isPositive()) {
3114         m_minWidth = m_maxWidth = calcContentWidth(style()->width().value());
3115     } else {
3116         m_minWidth = 0;
3117         m_maxWidth = 0;
3118 
3119         bool noWrap = !style()->autoWrap();
3120         if (childrenInline()) {
3121             calcInlineMinMaxWidth();
3122         } else {
3123             calcBlockMinMaxWidth();
3124         }
3125 
3126         if (m_maxWidth < m_minWidth) {
3127             m_maxWidth = m_minWidth;
3128         }
3129 
3130         if (noWrap && childrenInline()) {
3131             m_minWidth = m_maxWidth;
3132 
3133             // A horizontal marquee with inline children has no minimum width.
3134             if (style()->overflowX() == OMARQUEE && m_layer && m_layer->marquee() &&
3135                     m_layer->marquee()->isHorizontal() && !m_layer->marquee()->isUnfurlMarquee()) {
3136                 m_minWidth = 0;
3137             }
3138         }
3139 
3140         if (isTableCell()) {
3141             Length w = static_cast<RenderTableCell *>(this)->styleOrColWidth();
3142             if (w.isFixed() && w.isPositive()) {
3143                 m_maxWidth = qMax((int)m_minWidth, calcContentWidth(w.value()));
3144             }
3145         }
3146     }
3147 
3148     if (style()->minWidth().isFixed() && style()->minWidth().isPositive()) {
3149         m_maxWidth = qMax(m_maxWidth, (int)calcContentWidth(style()->minWidth().value()));
3150         m_minWidth = qMax(m_minWidth, (short)calcContentWidth(style()->minWidth().value()));
3151     }
3152 
3153     if (style()->maxWidth().isFixed() && !style()->maxWidth().isUndefined()) {
3154         m_maxWidth = qMin(m_maxWidth, (int)calcContentWidth(style()->maxWidth().value()));
3155         m_minWidth = qMin(m_minWidth, (short)calcContentWidth(style()->maxWidth().value()));
3156     }
3157 
3158     int toAdd = 0;
3159     toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight();
3160 
3161     m_minWidth += toAdd;
3162     m_maxWidth += toAdd;
3163 
3164     setMinMaxKnown();
3165 
3166     //qCDebug(KHTML_LOG) << "Text::calcMinMaxWidth(" << this << "): min = " << m_minWidth << " max = " << m_maxWidth;
3167     // ### compare with min/max width set in style sheet...
3168 }
3169 
3170 // bidi.cpp defines the following functions too.
3171 // Maybe these should not be static, after all...
3172 
3173 static int getBPMWidth(int childValue, Length cssUnit)
3174 {
3175     if (!cssUnit.isAuto()) {
3176         return (cssUnit.isFixed() ? cssUnit.value() : childValue);
3177     }
3178     return 0;
3179 }
3180 
3181 static int getBorderPaddingMargin(RenderObject *child, bool endOfInline)
3182 {
3183     RenderStyle *cstyle = child->style();
3184     int result = 0;
3185     bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline;
3186     result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()),
3187                           (leftSide ? cstyle->marginLeft() :
3188                            cstyle->marginRight()));
3189     result += getBPMWidth((leftSide ? child->paddingLeft() : child->paddingRight()),
3190                           (leftSide ? cstyle->paddingLeft() :
3191                            cstyle->paddingRight()));
3192     result += leftSide ? child->borderLeft() : child->borderRight();
3193     return result;
3194 }
3195 
3196 static void stripTrailingSpace(bool preserveWS,
3197                                int &inlineMax, int &inlineMin,
3198                                RenderObject *trailingSpaceChild)
3199 {
3200     if (!preserveWS && trailingSpaceChild && trailingSpaceChild->isText()) {
3201         // Collapse away the trailing space at the end of a block.
3202         RenderText *t = static_cast<RenderText *>(trailingSpaceChild);
3203         const Font *f = t->htmlFont(false);
3204         QChar space[1]; space[0] = ' ';
3205         int spaceWidth = f->charWidth(space, 1, 0, true/*fast algo*/);
3206         inlineMax -= spaceWidth;
3207         if (inlineMin > inlineMax) {
3208             inlineMin = inlineMax;
3209         }
3210     }
3211 }
3212 
3213 void RenderBlock::calcInlineMinMaxWidth()
3214 {
3215     int inlineMax = 0;
3216     int inlineMin = 0;
3217 
3218     int cw = containingBlock()->contentWidth();
3219 
3220     // If we are at the start of a line, we want to ignore all white-space.
3221     // Also strip spaces if we previously had text that ended in a trailing space.
3222     bool stripFrontSpaces = true;
3223 
3224     bool isTcQuirk = isTableCell() && style()->htmlHacks() && style()->width().isAuto();
3225 
3226     RenderObject *trailingSpaceChild = nullptr;
3227 
3228     bool autoWrap, oldAutoWrap;
3229     autoWrap = oldAutoWrap = style()->autoWrap();
3230 
3231     InlineMinMaxIterator childIterator(this, this);
3232     bool addedTextIndent = false; // Only gets added in once.
3233     RenderObject *prevFloat = nullptr;
3234     while (RenderObject *child = childIterator.next()) {
3235         autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() : child->style()->autoWrap();
3236 
3237         if (!child->isBR()) {
3238             // Step One: determine whether or not we need to go ahead and
3239             // terminate our current line.  Each discrete chunk can become
3240             // the new min-width, if it is the widest chunk seen so far, and
3241             // it can also become the max-width.
3242 
3243             // Children fall into three categories:
3244             // (1) An inline flow object.  These objects always have a min/max of 0,
3245             // and are included in the iteration solely so that their margins can
3246             // be added in.
3247             //
3248             // (2) An inline non-text non-flow object, e.g., an inline replaced element.
3249             // These objects can always be on a line by themselves, so in this situation
3250             // we need to go ahead and break the current line, and then add in our own
3251             // margins and min/max width on its own line, and then terminate the line.
3252             //
3253             // (3) A text object.  Text runs can have breakable characters at the start,
3254             // the middle or the end.  They may also lose whitespace off the front if
3255             // we're already ignoring whitespace.  In order to compute accurate min-width
3256             // information, we need three pieces of information.
3257             // (a) the min-width of the first non-breakable run.  Should be 0 if the text string
3258             // starts with whitespace.
3259             // (b) the min-width of the last non-breakable run. Should be 0 if the text string
3260             // ends with whitespace.
3261             // (c) the min/max width of the string (trimmed for whitespace).
3262             //
3263             // If the text string starts with whitespace, then we need to go ahead and
3264             // terminate our current line (unless we're already in a whitespace stripping
3265             // mode.
3266             //
3267             // If the text string has a breakable character in the middle, but didn't start
3268             // with whitespace, then we add the width of the first non-breakable run and
3269             // then end the current line.  We then need to use the intermediate min/max width
3270             // values (if any of them are larger than our current min/max).  We then look at
3271             // the width of the last non-breakable run and use that to start a new line
3272             // (unless we end in whitespace).
3273             RenderStyle *cstyle = child->style();
3274             int childMin = 0;
3275             int childMax = 0;
3276 
3277             if (!child->isText()) {
3278                 // Case (1) and (2).  Inline replaced and inline flow elements.
3279                 if (child->isInlineFlow()) {
3280                     // Add in padding/border/margin from the appropriate side of
3281                     // the element.
3282                     int bpm = getBorderPaddingMargin(child, childIterator.endOfInline);
3283                     childMin += bpm;
3284                     childMax += bpm;
3285 
3286                     inlineMin += childMin;
3287                     inlineMax += childMax;
3288                     if (child->isWordBreak()) {
3289                         // End a line and start a new line.
3290                         m_minWidth = qMax(inlineMin, (int)m_minWidth);
3291                         inlineMin = 0;
3292                     }
3293                 } else {
3294                     // Inline replaced elements add in their margins to their min/max values.
3295                     int margins = 0;
3296                     LengthType type = cstyle->marginLeft().type();
3297                     if (type == Fixed) {
3298                         margins += cstyle->marginLeft().value();
3299                     }
3300                     type = cstyle->marginRight().type();
3301                     if (type == Fixed) {
3302                         margins += cstyle->marginRight().value();
3303                     }
3304                     childMin += margins;
3305                     childMax += margins;
3306                 }
3307             }
3308 
3309             if (!child->isRenderInline() && !child->isText()) {
3310                 // Case (2). Inline replaced elements and floats.
3311 
3312                 // Common wrapping quirk
3313                 bool qBreak = isTcQuirk && !child->isFloating();
3314 
3315                 childMin += child->minWidth();
3316                 childMax += child->maxWidth();
3317 
3318                 // Check our "clear" setting.
3319                 bool clearPreviousFloat = false;
3320                 if (child->isFloating()) {
3321                     if (prevFloat &&
3322                             (((prevFloat->style()->floating() & FLEFT) && (child->style()->clear() & CLEFT)) ||
3323                              ((prevFloat->style()->floating() & FRIGHT) && (child->style()->clear() & CRIGHT)))) {
3324                         clearPreviousFloat = true;
3325                     }
3326                     prevFloat = child;
3327                 }
3328 
3329                 if ((!qBreak && (autoWrap || oldAutoWrap)) || clearPreviousFloat) {
3330                     if (m_minWidth < inlineMin) {
3331                         m_minWidth = inlineMin;
3332                     }
3333                     inlineMin = 0;
3334                 }
3335 
3336                 // If we're supposed to clear the previous float, then terminate maxwidth as well.
3337                 if (clearPreviousFloat) {
3338                     m_maxWidth = qMax(inlineMax, m_maxWidth);
3339                     inlineMax = 0;
3340                 }
3341 
3342                 // Add in text-indent.  This is added in only once.
3343                 int ti = 0;
3344                 if (!addedTextIndent) {
3345                     addedTextIndent = true;
3346                     ti = style()->textIndent().minWidth(cw);
3347                     childMin += ti;
3348                     childMax += ti;
3349                 }
3350 
3351                 // Add our width to the max.
3352                 inlineMax += childMax;
3353 
3354                 if ((!autoWrap && !child->isFloating()) || qBreak) {
3355                     inlineMin += childMin;
3356                 } else {
3357                     // Now check our line.
3358                     m_minWidth = qMax(childMin, (int)m_minWidth);
3359 
3360                     // Now start a new line.
3361                     inlineMin = 0;
3362                 }
3363 
3364                 // We are no longer stripping whitespace at the start of
3365                 // a line.
3366                 if (!child->isFloating()) {
3367                     stripFrontSpaces = false;
3368                     trailingSpaceChild = nullptr;
3369                 }
3370             } else if (child->isText()) {
3371                 // Case (3). Text.
3372                 RenderText *t = static_cast<RenderText *>(child);
3373 
3374                 // Determine if we have a breakable character.  Pass in
3375                 // whether or not we should ignore any spaces at the front
3376                 // of the string.  If those are going to be stripped out,
3377                 // then they shouldn't be considered in the breakable char
3378                 // check.
3379                 bool hasBreakableChar, hasBreak;
3380                 int beginMin, endMin;
3381                 bool beginWS, endWS;
3382                 int beginMax, endMax;
3383                 t->trimmedMinMaxWidth(beginMin, beginWS, endMin, endWS, hasBreakableChar,
3384                                       hasBreak, beginMax, endMax,
3385                                       childMin, childMax, stripFrontSpaces);
3386 
3387                 // This text object is insignificant and will not be rendered.  Just
3388                 // continue.
3389                 if (!hasBreak && childMax == 0) {
3390                     continue;
3391                 }
3392 
3393                 if (stripFrontSpaces) {
3394                     trailingSpaceChild = child;
3395                 } else {
3396                     trailingSpaceChild = nullptr;
3397                 }
3398 
3399                 // Add in text-indent.  This is added in only once.
3400                 int ti = 0;
3401                 if (!addedTextIndent) {
3402                     addedTextIndent = true;
3403                     ti = style()->textIndent().minWidth(cw);
3404                     childMin += ti; beginMin += ti;
3405                     childMax += ti; beginMax += ti;
3406                 }
3407 
3408                 // If we have no breakable characters at all,
3409                 // then this is the easy case. We add ourselves to the current
3410                 // min and max and continue.
3411                 if (!hasBreakableChar) {
3412                     inlineMin += childMin;
3413                 } else {
3414                     // We have a breakable character.  Now we need to know if
3415                     // we start and end with whitespace.
3416                     if (beginWS) {
3417                         // Go ahead and end the current line.
3418                         if (m_minWidth < inlineMin) {
3419                             m_minWidth = inlineMin;
3420                         }
3421                     } else {
3422                         inlineMin += beginMin;
3423                         if (m_minWidth < inlineMin) {
3424                             m_minWidth = inlineMin;
3425                         }
3426                         childMin -= ti;
3427                     }
3428 
3429                     inlineMin = childMin;
3430 
3431                     if (endWS) {
3432                         // We end in whitespace, which means we can go ahead
3433                         // and end our current line.
3434                         if (m_minWidth < inlineMin) {
3435                             m_minWidth = inlineMin;
3436                         }
3437                         inlineMin = 0;
3438                     } else {
3439                         if (m_minWidth < inlineMin) {
3440                             m_minWidth = inlineMin;
3441                         }
3442                         inlineMin = endMin;
3443                     }
3444                 }
3445 
3446                 if (hasBreak) {
3447                     inlineMax += beginMax;
3448                     if (m_maxWidth < inlineMax) {
3449                         m_maxWidth = inlineMax;
3450                     }
3451                     if (m_maxWidth < childMax) {
3452                         m_maxWidth = childMax;
3453                     }
3454                     inlineMax = endMax;
3455                 } else {
3456                     inlineMax += childMax;
3457                 }
3458             }
3459 
3460             // Ignore spaces after a list marker.
3461             if (child->isListMarker()) {
3462                 stripFrontSpaces = true;
3463             }
3464         } else {
3465             if (m_minWidth < inlineMin) {
3466                 m_minWidth = inlineMin;
3467             }
3468             if (m_maxWidth < inlineMax) {
3469                 m_maxWidth = inlineMax;
3470             }
3471             inlineMin = inlineMax = 0;
3472             stripFrontSpaces = true;
3473             trailingSpaceChild = nullptr;
3474         }
3475 
3476         oldAutoWrap = autoWrap;
3477     }
3478 
3479     stripTrailingSpace(style()->preserveWS(), inlineMax, inlineMin, trailingSpaceChild);
3480 
3481     if (m_minWidth < inlineMin) {
3482         m_minWidth = inlineMin;
3483     }
3484     if (m_maxWidth < inlineMax) {
3485         m_maxWidth = inlineMax;
3486     }
3487     //         qCDebug(KHTML_LOG) << "m_minWidth=" << m_minWidth
3488     //          << " m_maxWidth=" << m_maxWidth;
3489 }
3490 
3491 // Use a very large value (in effect infinite).
3492 #define BLOCK_MAX_WIDTH 15000
3493 
3494 void RenderBlock::calcBlockMinMaxWidth()
3495 {
3496     bool nowrap = !style()->autoWrap();
3497 
3498     RenderObject *child = firstChild();
3499     int floatLeftWidth = 0, floatRightWidth = 0;
3500 
3501     while (child != nullptr) {
3502         // positioned children don't affect the minmaxwidth
3503         if (child->isPositioned()) {
3504             child = child->nextSibling();
3505             continue;
3506         }
3507 
3508         if (child->isFloating() || child->flowAroundFloats()) {
3509             int floatTotalWidth = floatLeftWidth + floatRightWidth;
3510             if (child->style()->clear() & CLEFT) {
3511                 m_maxWidth = qMax(floatTotalWidth, m_maxWidth);
3512                 floatLeftWidth = 0;
3513             }
3514             if (child->style()->clear() & CRIGHT) {
3515                 m_maxWidth = qMax(floatTotalWidth, m_maxWidth);
3516                 floatRightWidth = 0;
3517             }
3518         }
3519 
3520         Length ml = child->style()->marginLeft();
3521         Length mr = child->style()->marginRight();
3522 
3523         // Call calcWidth on the child to ensure that our margins are
3524         // up to date.  This method can be called before the child has actually
3525         // calculated its margins (which are computed inside calcWidth).
3526         if (ml.isPercent() || mr.isPercent()) {
3527             calcWidth();
3528         }
3529 
3530         // A margin basically has three types: fixed, percentage, and auto (variable).
3531         // Auto margins simply become 0 when computing min/max width.
3532         // Fixed margins can be added in as is.
3533         // Percentage margins are computed as a percentage of the width we calculated in
3534         // the calcWidth call above.  In this case we use the actual cached margin values on
3535         // the RenderObject itself.
3536         int margin = 0, marginLeft = 0, marginRight = 0;
3537         if (ml.isFixed()) {
3538             marginLeft += ml.value();
3539         } else if (ml.isPercent()) {
3540             marginLeft += child->marginLeft();
3541         }
3542 
3543         if (mr.isFixed()) {
3544             marginRight += mr.value();
3545         } else if (mr.isPercent()) {
3546             marginRight += child->marginRight();
3547         }
3548 
3549         margin = marginLeft + marginRight;
3550 
3551         int w = child->minWidth() + margin;
3552         if (m_minWidth < w) {
3553             m_minWidth = w;
3554         }
3555 
3556         // IE ignores tables for calculation of nowrap. Makes some sense.
3557         if (nowrap && !child->isTable() && m_maxWidth < w) {
3558             m_maxWidth = w;
3559         }
3560 
3561         w = child->maxWidth() + margin;
3562 
3563         if (!child->isFloating()) {
3564             if (child->flowAroundFloats()) {
3565                 // Determine a left and right max value based on whether or not the floats can fit in the
3566                 // margins of the object.  For negative margins, we will attempt to overlap the float if the negative margin
3567                 // is smaller than the float width.
3568                 int maxLeft = marginLeft > 0 ? qMax(floatLeftWidth, marginLeft) : floatLeftWidth + marginLeft;
3569                 int maxRight = marginRight > 0 ? qMax(floatRightWidth, marginRight) : floatRightWidth + marginRight;
3570                 w = child->maxWidth() + maxLeft + maxRight;
3571                 w = qMax(w, floatLeftWidth + floatRightWidth);
3572             } else {
3573                 m_maxWidth = qMax(floatLeftWidth + floatRightWidth, m_maxWidth);
3574             }
3575             floatLeftWidth = floatRightWidth = 0;
3576         }
3577 
3578         if (child->isFloating()) {
3579             if (style()->floating() & FLEFT) {
3580                 floatLeftWidth += w;
3581             } else {
3582                 floatRightWidth += w;
3583             }
3584         } else if (m_maxWidth < w) {
3585             m_maxWidth = w;
3586         }
3587 
3588         // A very specific WinIE quirk.
3589         // Example:
3590         /*
3591            <div style="position:absolute; width:100px; top:50px;">
3592               <div style="position:absolute;left:0px;top:50px;height:50px;background-color:green">
3593                 <table style="width:100%"><tr><td></table>
3594               </div>
3595            </div>
3596         */
3597         // In the above example, the inner absolute positioned block should have a computed width
3598         // of 100px because of the table.
3599         // We can achieve this effect by making the maxwidth of blocks that contain tables
3600         // with percentage widths be infinite (as long as they are not inside a table cell).
3601         if (style()->htmlHacks() && child->style()->width().isPercent() &&
3602                 !isTableCell() && child->isTable() && m_maxWidth < BLOCK_MAX_WIDTH) {
3603             RenderBlock *cb = containingBlock();
3604             while (!cb->isCanvas() && !cb->isTableCell()) {
3605                 cb = cb->containingBlock();
3606             }
3607             if (!cb->isTableCell()) {
3608                 m_maxWidth = BLOCK_MAX_WIDTH;
3609             }
3610         }
3611         child = child->nextSibling();
3612     }
3613     m_maxWidth = qMax(floatLeftWidth + floatRightWidth, m_maxWidth);
3614 }
3615 
3616 void RenderBlock::close()
3617 {
3618     if (lastChild() && lastChild()->isAnonymousBlock()) {
3619         lastChild()->close();
3620     }
3621     updateFirstLetter();
3622     RenderFlow::close();
3623 }
3624 
3625 int RenderBlock::getBaselineOfFirstLineBox()
3626 {
3627     if (m_firstLineBox) {
3628         return m_firstLineBox->yPos() + m_firstLineBox->baseline();
3629     }
3630 
3631     if (isInline()) {
3632         return -1;    // We're inline and had no line box, so we have no baseline we can return.
3633     }
3634 
3635     for (RenderObject *curr = firstChild(); curr; curr = curr->nextSibling()) {
3636         int result = curr->getBaselineOfFirstLineBox();
3637         if (result != -1) {
3638             return curr->yPos() + result;    // Translate to our coordinate space.
3639         }
3640     }
3641 
3642     return -1;
3643 }
3644 
3645 InlineFlowBox *RenderBlock::getFirstLineBox()
3646 {
3647     if (m_firstLineBox) {
3648         return m_firstLineBox;
3649     }
3650 
3651     if (isInline()) {
3652         return nullptr;    // We're inline and had no line box, so we have no baseline we can return.
3653     }
3654 
3655     for (RenderObject *curr = firstChild(); curr; curr = curr->nextSibling()) {
3656         InlineFlowBox *result = curr->getFirstLineBox();
3657         if (result) {
3658             return result;
3659         }
3660     }
3661 
3662     return nullptr;
3663 }
3664 
3665 bool RenderBlock::inRootBlockContext() const
3666 {
3667     if (isTableCell() || isFloatingOrPositioned() || hasOverflowClip()) {
3668         return false;
3669     }
3670 
3671     if (isRoot() || isCanvas()) {
3672         return true;
3673     }
3674 
3675     return containingBlock()->inRootBlockContext();
3676 }
3677 
3678 const char *RenderBlock::renderName() const
3679 {
3680     if (isFloating()) {
3681         return "RenderBlock (floating)";
3682     }
3683     if (isPositioned()) {
3684         return "RenderBlock (positioned)";
3685     }
3686     if (isAnonymousBlock() && m_avoidPageBreak) {
3687         return "RenderBlock (avoidPageBreak)";
3688     }
3689     if (isAnonymousBlock()) {
3690         return "RenderBlock (anonymous)";
3691     } else if (isAnonymous()) {
3692         return "RenderBlock (generated)";
3693     }
3694     if (isRelPositioned()) {
3695         return "RenderBlock (relative positioned)";
3696     }
3697     if (style() && style()->display() == COMPACT) {
3698         return "RenderBlock (compact)";
3699     }
3700     if (style() && style()->display() == RUN_IN) {
3701         return "RenderBlock (run-in)";
3702     }
3703     return "RenderBlock";
3704 }
3705 
3706 #ifdef ENABLE_DUMP
3707 void RenderBlock::printTree(int indent) const
3708 {
3709     RenderFlow::printTree(indent);
3710 
3711     if (m_floatingObjects) {
3712         QListIterator<FloatingObject *> it(*m_floatingObjects);
3713         FloatingObject *r;
3714         while (it.hasNext()) {
3715             r = it.next();
3716             QString s;
3717             s.fill(' ', indent);
3718             qCDebug(KHTML_LOG) << s << renderName() << ":  " <<
3719                      (r->type == FloatingObject::FloatLeft ? "FloatLeft" : "FloatRight")  <<
3720                      "[" << r->node->renderName() << ": " << (void *)r->node << "] (" << r->startY << " - " << r->endY << ")" << "width: " << r->width;
3721         }
3722     }
3723 }
3724 
3725 void RenderBlock::dump(QTextStream &stream, const QString &ind) const
3726 {
3727     RenderFlow::dump(stream, ind);
3728 
3729     if (m_childrenInline) {
3730         stream << QLatin1String(" childrenInline");
3731     }
3732     // FIXME: currently only print pre to not mess up regression
3733     if (style()->preserveWS()) {
3734         stream << " pre";
3735     }
3736     if (m_firstLine) {
3737         stream << QLatin1String(" firstLine");
3738     }
3739 
3740     if (m_floatingObjects && !m_floatingObjects->isEmpty()) {
3741         stream << QLatin1String(" special(");
3742         QListIterator<FloatingObject *> it(*m_floatingObjects);
3743         FloatingObject *r;
3744         bool first = true;
3745         while (it.hasNext()) {
3746             r = it.next();
3747             if (!first) {
3748                 stream << QLatin1Char(',');
3749             }
3750             stream << r->node->renderName();
3751             first = false;
3752         }
3753         stream << QLatin1Char(')');
3754     }
3755 
3756     // ### EClear m_clearStatus
3757 }
3758 #endif
3759 
3760 #undef DEBUG
3761 #undef DEBUG_LAYOUT
3762 #undef BOX_DEBUG
3763 
3764 } // namespace khtml
3765