RenderBlock.cpp 187 KB
Newer Older
1
/*
2 3
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
dsmith's avatar
dsmith committed
4
 *           (C) 2007 David Smith (catfish.man@gmail.com)
mitz@apple.com's avatar
mitz@apple.com committed
5
 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
ddkilzer's avatar
ddkilzer committed
19 20
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
21 22
 */

mjs's avatar
mjs committed
23
#include "config.h"
24
#include "RenderBlock.h"
25

darin's avatar
darin committed
26
#include "Document.h"
27
#include "Element.h"
mjs's avatar
mjs committed
28
#include "Frame.h"
darin's avatar
darin committed
29
#include "FrameView.h"
darin's avatar
darin committed
30
#include "GraphicsContext.h"
weinig's avatar
weinig committed
31
#include "HTMLNames.h"
bdakin's avatar
bdakin committed
32
#include "HitTestResult.h"
weinig's avatar
weinig committed
33
#include "InlineTextBox.h"
bdakin's avatar
bdakin committed
34
#include "RenderImage.h"
35
#include "RenderMarquee.h"
hyatt@apple.com's avatar
hyatt@apple.com committed
36
#include "RenderReplica.h"
darin's avatar
darin committed
37
#include "RenderTableCell.h"
darin's avatar
darin committed
38
#include "RenderTextFragment.h"
darin's avatar
darin committed
39
#include "RenderTheme.h"
weinig's avatar
weinig committed
40 41
#include "RenderView.h"
#include "SelectionController.h"
42

darin's avatar
darin committed
43
using namespace std;
darin's avatar
darin committed
44 45
using namespace WTF;
using namespace Unicode;
darin's avatar
darin committed
46

darin's avatar
darin committed
47 48
namespace WebCore {

aliceli1's avatar
aliceli1 committed
49 50 51 52
// Number of pixels to allow as a fudge factor when clicking above or below a line.
// clicking up to verticalLineClickFudgeFactor pixels above a line will correspond to the closest point on the line.   
const int verticalLineClickFudgeFactor= 3;

darin's avatar
darin committed
53
using namespace HTMLNames;
54

antti's avatar
antti committed
55 56 57 58 59 60 61 62 63 64 65 66 67
struct ColumnInfo {
    ColumnInfo()
        : m_desiredColumnWidth(0)
        , m_desiredColumnCount(1)
        { }
    int m_desiredColumnWidth;
    unsigned m_desiredColumnCount;
    Vector<IntRect> m_columnRects;
};

typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
static ColumnInfoMap* gColumnInfoMap = 0;

mitz@apple.com's avatar
mitz@apple.com committed
68 69 70 71 72 73
typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;
static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;

typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
static PercentHeightContainerMap* gPercentHeightContainerMap = 0;

74 75 76 77 78 79
// Our MarginInfo state used when laying out block children.
RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom)
{
    // Whether or not we can collapse our own margins with our children.  We don't do this
    // if we had any border/padding (obviously), if we're the root or HTML elements, or if
    // we're positioned, floating, a table cell.
80
    m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned() &&
81 82 83 84 85 86 87 88 89
        !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable();

    m_canCollapseTopWithChildren = m_canCollapseWithChildren && (top == 0) && block->style()->marginTopCollapse() != MSEPARATE;

    // If any height other than auto is specified in CSS, then we don't collapse our bottom
    // margins with our children's margins.  To do otherwise would be to risk odd visual
    // effects when the children overflow out of the parent block and yet still collapse
    // with it.  We also don't collapse if we have any bottom border/padding.
    m_canCollapseBottomWithChildren = m_canCollapseWithChildren && (bottom == 0) &&
darin's avatar
darin committed
90
        (block->style()->height().isAuto() && block->style()->height().value() == 0) && block->style()->marginBottomCollapse() != MSEPARATE;
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
    
    m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginTopCollapse() == MDISCARD || 
        block->style()->marginBottomCollapse() == MDISCARD;

    m_atTopOfBlock = true;
    m_atBottomOfBlock = false;

    m_posMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(true) : 0;
    m_negMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(false) : 0;

    m_selfCollapsingBlockClearedFloat = false;
    
    m_topQuirk = m_bottomQuirk = m_determinedTopQuirk = false;
}

// -------------------------------------------------------------------------------------------------------

darin's avatar
darin committed
108
RenderBlock::RenderBlock(Node* node)
antti's avatar
antti committed
109 110 111 112 113 114 115 116 117
      : RenderFlow(node)
      , m_floatingObjects(0)
      , m_positionedObjects(0)
      , m_maxMargin(0)
      , m_overflowHeight(0)
      , m_overflowWidth(0)
      , m_overflowLeft(0)
      , m_overflowTop(0)
{
118 119 120 121
}

RenderBlock::~RenderBlock()
{
122 123
    delete m_floatingObjects;
    delete m_positionedObjects;
antti's avatar
antti committed
124 125
    delete m_maxMargin;
    
darin@apple.com's avatar
darin@apple.com committed
126 127
    if (m_hasColumns)
        delete gColumnInfoMap->take(this);
mitz@apple.com's avatar
mitz@apple.com committed
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146

    if (gPercentHeightDescendantsMap) {
        if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) {
            HashSet<RenderBox*>::iterator end = descendantSet->end();
            for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
                HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant);
                ASSERT(containerSet);
                if (!containerSet)
                    continue;
                ASSERT(containerSet->contains(this));
                containerSet->remove(this);
                if (containerSet->isEmpty()) {
                    gPercentHeightContainerMap->remove(*descendant);
                    delete containerSet;
                }
            }
            delete descendantSet;
        }
    }
147 148
}

149
void RenderBlock::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
150
{
151
    setReplaced(newStyle->isDisplayReplacedType());
152 153
    RenderFlow::styleWillChange(diff, newStyle);
}
154

155 156 157
void RenderBlock::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
{
    RenderFlow::styleDidChange(diff, oldStyle);
158

159 160 161
    // FIXME: We could save this call when the change only affected non-inherited properties
    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
        if (child->isAnonymousBlock()) {
162
            RefPtr<RenderStyle> newStyle = RenderStyle::create();
163 164
            newStyle->inheritFrom(style());
            newStyle->setDisplay(BLOCK);
165
            child->setStyle(newStyle.release());
166
        }
167 168
    }

169 170
    m_lineHeight = -1;

171
    // Update pseudos for :before and :after now.
172
    if (!isAnonymous() && canHaveChildren()) {
hyatt's avatar
hyatt committed
173 174 175
        updateBeforeAfterContent(RenderStyle::BEFORE);
        updateBeforeAfterContent(RenderStyle::AFTER);
    }
weinig's avatar
weinig committed
176
    updateFirstLetter();
darin's avatar
darin committed
177 178
}

179 180
void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild)
{
181
    // Make sure we don't append things after :after-generated content if we have it.
darin's avatar
darin committed
182
    if (!beforeChild && isAfterContent(lastChild()))
183
        beforeChild = lastChild();
mitz@apple.com's avatar
mitz@apple.com committed
184

185
    bool madeBoxesNonInline = false;
186

mitz@apple.com's avatar
mitz@apple.com committed
187 188
    // If the requested beforeChild is not one of our children, then this is because
    // there is an anonymous container within this object that contains the beforeChild.
189
    if (beforeChild && beforeChild->parent() != this) {
mitz@apple.com's avatar
mitz@apple.com committed
190 191
        RenderObject* anonymousChild = beforeChild->parent();
        ASSERT(anonymousChild);
192

mitz@apple.com's avatar
mitz@apple.com committed
193 194
        while (anonymousChild->parent() != this)
            anonymousChild = anonymousChild->parent();
mitz@apple.com's avatar
mitz@apple.com committed
195

mitz@apple.com's avatar
mitz@apple.com committed
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
        ASSERT(anonymousChild->isAnonymous());

        if (anonymousChild->isAnonymousBlock()) {
            // Insert the child into the anonymous block box instead of here.
            if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
                beforeChild->parent()->addChild(newChild, beforeChild);
            else
                addChildToFlow(newChild, beforeChild->parent());
            return;
        }

        ASSERT(anonymousChild->isTable());
        if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP
                || newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION
                || newChild->isTableSection()
                || newChild->isTableRow()
                || newChild->isTableCell()) {
            // Insert into the anonymous table.
            anonymousChild->addChild(newChild, beforeChild);
            return;
        }

        // Go on to insert before the anonymous table.
        beforeChild = anonymousChild;
220 221 222 223
    }

    // A block has to either have all of its children inline, or all of its children as blocks.
    // So, if our children are currently inline and a block child has to be inserted, we move all our
mitz@apple.com's avatar
mitz@apple.com committed
224 225
    // inline children into anonymous block boxes.
    if (m_childrenInline && !newChild->isInline() && !newChild->isFloatingOrPositioned()) {
226 227 228
        // This is a block with inline content. Wrap the inline content in anonymous blocks.
        makeChildrenNonInline(beforeChild);
        madeBoxesNonInline = true;
mitz@apple.com's avatar
mitz@apple.com committed
229

230 231
        if (beforeChild && beforeChild->parent() != this) {
            beforeChild = beforeChild->parent();
darin's avatar
darin committed
232 233
            ASSERT(beforeChild->isAnonymousBlock());
            ASSERT(beforeChild->parent() == this);
234
        }
mitz@apple.com's avatar
mitz@apple.com committed
235
    } else if (!m_childrenInline && (newChild->isFloatingOrPositioned() || newChild->isInline())) {
236 237 238
        // If we're inserting an inline child but all of our children are blocks, then we have to make sure
        // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
        // a new one is created and inserted into our list of children in the appropriate position.
mitz@apple.com's avatar
mitz@apple.com committed
239 240 241 242 243 244 245
        RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();

        if (afterChild && afterChild->isAnonymousBlock()) {
            afterChild->addChild(newChild);
            return;
        }

246
        if (newChild->isInline()) {
mitz@apple.com's avatar
mitz@apple.com committed
247
            // No suitable existing anonymous box - create a new one.
248
            RenderBlock* newBox = createAnonymousBlock();
mitz@apple.com's avatar
mitz@apple.com committed
249
            RenderContainer::addChild(newBox, beforeChild);
250 251 252 253 254
            newBox->addChild(newChild);
            return;
        }
    }

mitz@apple.com's avatar
mitz@apple.com committed
255
    RenderContainer::addChild(newChild, beforeChild);
256 257
    // ### care about aligned stuff

antti's avatar
antti committed
258 259 260
    if (madeBoxesNonInline && parent() && isAnonymousBlock())
        parent()->removeLeftoverAnonymousBlock(this);
    // this object may be dead here
261 262
}

hyatt's avatar
hyatt committed
263
static void getInlineRun(RenderObject* start, RenderObject* boundary,
264 265 266 267 268 269 270 271 272 273 274
                         RenderObject*& inlineRunStart,
                         RenderObject*& inlineRunEnd)
{
    // Beginning at |start| we find the largest contiguous run of inlines that
    // we can.  We denote the run with start and end points, |inlineRunStart|
    // and |inlineRunEnd|.  Note that these two values may be the same if
    // we encounter only one inline.
    //
    // We skip any non-inlines we encounter as long as we haven't found any
    // inlines yet.
    //
hyatt's avatar
hyatt committed
275 276
    // |boundary| indicates a non-inclusive boundary point.  Regardless of whether |boundary|
    // is inline or not, we will not include it in a run with inlines before it.  It's as though we encountered
277
    // a non-inline.
hyatt's avatar
hyatt committed
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
    
    // Start by skipping as many non-inlines as we can.
    RenderObject * curr = start;
    bool sawInline;
    do {
        while (curr && !(curr->isInline() || curr->isFloatingOrPositioned()))
            curr = curr->nextSibling();
        
        inlineRunStart = inlineRunEnd = curr;
        
        if (!curr)
            return; // No more inline children to be found.
        
        sawInline = curr->isInline();
        
        curr = curr->nextSibling();
        while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != boundary)) {
hyatt's avatar
hyatt committed
295
            inlineRunEnd = curr;
hyatt's avatar
hyatt committed
296 297 298 299 300
            if (curr->isInline())
                sawInline = true;
            curr = curr->nextSibling();
        }
    } while (!sawInline);
301 302
}

bdakin's avatar
bdakin committed
303 304 305 306 307 308 309 310 311 312 313 314
void RenderBlock::deleteLineBoxTree()
{
    InlineFlowBox* line = m_firstLineBox;
    InlineFlowBox* nextLine;
    while (line) {
        nextLine = line->nextFlowBox();
        line->deleteLine(renderArena());
        line = nextLine;
    }
    m_firstLineBox = m_lastLineBox = 0;
}

315
void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
hyatt's avatar
hyatt committed
316
{    
317 318 319 320 321 322 323
    // makeChildrenNonInline takes a block whose children are *all* inline and it
    // makes sure that inline children are coalesced under anonymous
    // blocks.  If |insertionPoint| is defined, then it represents the insertion point for
    // the new block child that is causing us to have to wrap all the inlines.  This
    // means that we cannot coalesce inlines before |insertionPoint| with inlines following
    // |insertionPoint|, because the new child is going to be inserted in between the inlines,
    // splitting them.
darin's avatar
darin committed
324 325
    ASSERT(isInlineBlockOrInlineTable() || !isInline());
    ASSERT(!insertionPoint || insertionPoint->parent() == this);
326 327 328 329

    m_childrenInline = false;

    RenderObject *child = firstChild();
mitz@apple.com's avatar
mitz@apple.com committed
330 331 332 333
    if (!child)
        return;

    deleteLineBoxTree();
334 335 336 337 338 339 340 341 342 343

    while (child) {
        RenderObject *inlineRunStart, *inlineRunEnd;
        getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);

        if (!inlineRunStart)
            break;

        child = inlineRunEnd->nextSibling();

344
        RenderBlock* box = createAnonymousBlock();
345 346 347 348 349 350
        insertChildNode(box, inlineRunStart);
        RenderObject* o = inlineRunStart;
        while(o != inlineRunEnd)
        {
            RenderObject* no = o;
            o = no->nextSibling();
351
            box->moveChildNode(no);
352
        }
353
        box->moveChildNode(inlineRunEnd);
354
    }
hyatt's avatar
hyatt committed
355 356 357

#ifndef NDEBUG
    for (RenderObject *c = firstChild(); c; c = c->nextSibling())
darin's avatar
darin committed
358
        ASSERT(!c->isInline());
hyatt's avatar
hyatt committed
359
#endif
mitz@apple.com's avatar
mitz@apple.com committed
360 361

    repaint();
362 363 364 365 366 367 368 369 370
}

void RenderBlock::removeChild(RenderObject *oldChild)
{
    // If this child is a block, and if our previous and next siblings are
    // both anonymous blocks with inline content, then we can go ahead and
    // fold the inline content back together.
    RenderObject* prev = oldChild->previousSibling();
    RenderObject* next = oldChild->nextSibling();
371
    bool canDeleteAnonymousBlocks = !documentBeingDestroyed() && !isInline() && !oldChild->isInline() && 
372 373 374
                                    !oldChild->continuation() && 
                                    (!prev || (prev->isAnonymousBlock() && prev->childrenInline())) &&
                                    (!next || (next->isAnonymousBlock() && next->childrenInline()));
375
    if (canDeleteAnonymousBlocks && prev && next) {
376 377
        // Take all the children out of the |next| block and put them in
        // the |prev| block.
darin's avatar
darin committed
378
        prev->setNeedsLayoutAndPrefWidthsRecalc();
379 380 381 382
        RenderObject* o = next->firstChild();
        while (o) {
            RenderObject* no = o;
            o = no->nextSibling();
383
            prev->moveChildNode(no);
384
        }
bdakin's avatar
bdakin committed
385
 
weinig's avatar
weinig committed
386
        RenderBlock* nextBlock = static_cast<RenderBlock*>(next);
bdakin's avatar
bdakin committed
387
        nextBlock->deleteLineBoxTree();
weinig's avatar
weinig committed
388
        
389
        // Nuke the now-empty block.
harrison's avatar
harrison committed
390
        next->destroy();
391 392 393 394
    }

    RenderFlow::removeChild(oldChild);

395
    RenderObject* child = prev ? prev : next;
antti's avatar
antti committed
396
    if (canDeleteAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) {
397
        // The removal has knocked us down to containing only a single anonymous
398 399
        // box.  We can go ahead and pull the content right back up into our
        // box.
darin's avatar
darin committed
400
        setNeedsLayoutAndPrefWidthsRecalc();
darin's avatar
darin committed
401
        RenderBlock* anonBlock = static_cast<RenderBlock*>(removeChildNode(child, false));
402 403 404 405 406
        m_childrenInline = true;
        RenderObject* o = anonBlock->firstChild();
        while (o) {
            RenderObject* no = o;
            o = no->nextSibling();
407
            moveChildNode(no);
408
        }
409

bdakin's avatar
bdakin committed
410 411
        // Delete the now-empty block's lines and nuke it.
        anonBlock->deleteLineBoxTree();
harrison's avatar
harrison committed
412
        anonBlock->destroy();
413 414 415
    }
}

416 417
int RenderBlock::overflowHeight(bool includeInterior) const
{
418
    if (!includeInterior && hasOverflowClip()) {
mitz@apple.com's avatar
mitz@apple.com committed
419 420 421
        int shadowHeight = 0;
        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
            shadowHeight = max(boxShadow->y + boxShadow->blur, shadowHeight);
hyatt@apple.com's avatar
hyatt@apple.com committed
422 423 424 425
        int height = m_height + shadowHeight;
        if (hasReflection())
            height = max(height, reflectionBox().bottom());
        return height;
426 427
    }
    return m_overflowHeight;
428 429 430 431
}

int RenderBlock::overflowWidth(bool includeInterior) const
{
432
    if (!includeInterior && hasOverflowClip()) {
mitz@apple.com's avatar
mitz@apple.com committed
433 434 435
        int shadowWidth = 0;
        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
            shadowWidth = max(boxShadow->x + boxShadow->blur, shadowWidth);
hyatt@apple.com's avatar
hyatt@apple.com committed
436 437 438 439
        int width = m_width + shadowWidth;
        if (hasReflection())
            width = max(width, reflectionBox().right());
        return width;
440 441
    }
    return m_overflowWidth;
442
}
443

444 445
int RenderBlock::overflowLeft(bool includeInterior) const
{
446
    if (!includeInterior && hasOverflowClip()) {
mitz@apple.com's avatar
mitz@apple.com committed
447 448 449
        int shadowLeft = 0;
        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
            shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft);
hyatt@apple.com's avatar
hyatt@apple.com committed
450 451 452 453
        int left = shadowLeft;
        if (hasReflection())
            left = min(left, reflectionBox().x());
        return left;
454 455
    }
    return m_overflowLeft;
456 457 458 459
}

int RenderBlock::overflowTop(bool includeInterior) const
{
460
    if (!includeInterior && hasOverflowClip()) {
mitz@apple.com's avatar
mitz@apple.com committed
461 462 463
        int shadowTop = 0;
        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next)
            shadowTop = min(boxShadow->y - boxShadow->blur, shadowTop);
hyatt@apple.com's avatar
hyatt@apple.com committed
464 465 466 467
        int top = shadowTop;
        if (hasReflection())
            top = min(top, reflectionBox().y());
        return top;
468 469
    }
    return m_overflowTop;
470 471
}

472
IntRect RenderBlock::overflowRect(bool includeInterior) const
473
{
474 475
    if (!includeInterior && hasOverflowClip()) {
        IntRect box = borderBox();
mitz@apple.com's avatar
mitz@apple.com committed
476 477 478 479 480 481 482 483 484 485
        int shadowLeft = 0;
        int shadowRight = 0;
        int shadowTop = 0;
        int shadowBottom = 0;

        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
            shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft);
            shadowRight = max(boxShadow->x + boxShadow->blur, shadowRight);
            shadowTop = min(boxShadow->y - boxShadow->blur, shadowTop);
            shadowBottom = max(boxShadow->y + boxShadow->blur, shadowBottom);
486
        }
mitz@apple.com's avatar
mitz@apple.com committed
487 488 489 490

        box.move(shadowLeft, shadowTop);
        box.setWidth(box.width() - shadowLeft + shadowRight);
        box.setHeight(box.height() - shadowTop + shadowBottom);
hyatt@apple.com's avatar
hyatt@apple.com committed
491 492 493 494 495 496 497 498 499 500 501 502 503

        if (hasReflection()) {
            IntRect reflection(reflectionBox());
            int reflectTop = min(box.y(), reflection.y());
            int reflectBottom = max(box.bottom(), reflection.bottom());
            box.setHeight(reflectBottom - reflectTop);
            box.setY(reflectTop);
            
            int reflectLeft = min(box.x(), reflection.x());
            int reflectRight = max(box.right(), reflection.right());
            box.setWidth(reflectRight - reflectLeft);
            box.setX(reflectLeft);
        }
504 505 506
        return box;
    }

507 508 509
    if (!includeInterior && hasOverflowClip())
        return borderBox();
    int l = overflowLeft(includeInterior);
darin's avatar
darin committed
510
    int t = min(overflowTop(includeInterior), -borderTopExtra());
511
    return IntRect(l, t, overflowWidth(includeInterior) - l, max(overflowHeight(includeInterior), height() + borderBottomExtra()) - t);
512 513
}

514 515 516 517 518 519 520
bool RenderBlock::isSelfCollapsingBlock() const
{
    // We are not self-collapsing if we
    // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
    // (b) are a table,
    // (c) have border/padding,
    // (d) have a min-height
521
    // (e) have specified that one of our margins can't collapse using a CSS extension
522 523
    if (m_height > 0 ||
        isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 ||
ddkilzer's avatar
ddkilzer committed
524
        style()->minHeight().isPositive() || 
525
        style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE)
526 527
        return false;

528
    bool hasAutoHeight = style()->height().isAuto();
529 530
    if (style()->height().isPercent() && !style()->htmlHacks()) {
        hasAutoHeight = true;
531
        for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
532 533 534 535 536
            if (cb->style()->height().isFixed() || cb->isTableCell())
                hasAutoHeight = false;
        }
    }

537 538
    // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
    // on whether we have content that is all self-collapsing or not.
ddkilzer's avatar
ddkilzer committed
539
    if (hasAutoHeight || ((style()->height().isFixed() || style()->height().isPercent()) && style()->height().isZero())) {
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
        // If the block has inline children, see if we generated any line boxes.  If we have any
        // line boxes, then we can't be self-collapsing, since we have content.
        if (childrenInline())
            return !firstLineBox();
        
        // Whether or not we collapse is dependent on whether all our normal flow children
        // are also self-collapsing.
        for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
            if (child->isFloatingOrPositioned())
                continue;
            if (!child->isSelfCollapsingBlock())
                return false;
        }
        return true;
    }
    return false;
}

558 559
void RenderBlock::layout()
{
560 561 562
    // Update our first letter info now.
    updateFirstLetter();

563 564 565
    // Table cells call layoutBlock directly, so don't add any logic here.  Put code into
    // layoutBlock().
    layoutBlock(false);
566 567 568 569 570 571 572 573 574
    
    // It's safe to check for control clip here, since controls can never be table cells.
    if (hasControlClip()) {
        // Because of the lightweight clip, there can never be any overflow from children.
        m_overflowWidth = m_width;
        m_overflowHeight = m_height;
        m_overflowLeft = 0;
        m_overflowTop = 0;
    }
575 576 577 578
}

void RenderBlock::layoutBlock(bool relayoutChildren)
{
darin's avatar
darin committed
579
    ASSERT(needsLayout());
580

581
    if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
582
        return;                                      // cause us to come in here.  Just bail.
583

weinig's avatar
weinig committed
584
    if (!relayoutChildren && layoutOnlyPositionedObjects())
585
        return;
weinig's avatar
weinig committed
586

ap's avatar
ap committed
587
    IntRect oldBounds;
588
    IntRect oldOutlineBox;
mitz@apple.com's avatar
mitz@apple.com committed
589
    bool checkForRepaint = m_everHadLayout && checkForRepaintDuringLayout();
590
    if (checkForRepaint) {
591 592
        oldBounds = absoluteClippedOverflowRect();
        oldOutlineBox = absoluteOutlineBox();
593
    }
594

weinig's avatar
weinig committed
595
    bool hadColumns = m_hasColumns;
hyatt@apple.com's avatar
hyatt@apple.com committed
596
    if (!hadColumns && !hasReflection())
weinig's avatar
weinig committed
597 598 599 600
        view()->pushLayoutState(this, IntSize(xPos(), yPos()));
    else
        view()->disableLayoutState();

601
    int oldWidth = m_width;
antti's avatar
antti committed
602
    int oldColumnWidth = desiredColumnWidth();
603

604
    calcWidth();
605 606
    calcColumnWidth();

607
    m_overflowWidth = m_width;
608
    m_overflowLeft = 0;
609

antti's avatar
antti committed
610
    if (oldWidth != m_width || oldColumnWidth != desiredColumnWidth())
611 612 613 614
        relayoutChildren = true;

    clearFloats();

615
    int previousHeight = m_height;
616 617 618 619 620 621 622 623 624 625 626 627 628
    m_height = 0;
    m_overflowHeight = 0;

    // We use four values, maxTopPos, maxPosNeg, maxBottomPos, and maxBottomNeg, to track
    // our current maximal positive and negative margins.  These values are used when we
    // are collapsed with adjacent blocks, so for example, if you have block A and B
    // collapsing together, then you'd take the maximal positive margin from both A and B
    // and subtract it from the maximal negative margin from both A and B to get the
    // true collapsed margin.  This algorithm is recursive, so when we finish layout()
    // our block knows its current maximal positive/negative values.
    //
    // Start out by setting our margin values to our current margins.  Table cells have
    // no margins, so we don't fill in the values for table cells.
darin's avatar
darin committed
629 630
    bool isCell = isTableCell();
    if (!isCell) {
631 632
        initMaxMarginValues();

darin's avatar
darin committed
633 634
        m_topMarginQuirk = style()->marginTop().quirk();
        m_bottomMarginQuirk = style()->marginBottom().quirk();
635

636 637
        Node* node = element();
        if (node && node->hasTagName(formTag) && static_cast<HTMLFormElement*>(node)->isMalformed()) {
638 639
            // See if this form is malformed (i.e., unclosed). If so, don't give the form
            // a bottom margin.
antti's avatar
antti committed
640
            setMaxBottomMargins(0, 0);
641
        }
642 643
    }

644
    // For overflow:scroll blocks, ensure we have both scrollbars in place always.
645
    if (scrollsOverflow()) {
646
        if (style()->overflowX() == OSCROLL)
647
            m_layer->setHasHorizontalScrollbar(true);
648
        if (style()->overflowY() == OSCROLL)
649 650
            m_layer->setHasVerticalScrollbar(true);
    }
651

ap's avatar
ap committed
652 653
    int repaintTop = 0;
    int repaintBottom = 0;
mitz@apple.com's avatar
mitz@apple.com committed
654
    int maxFloatBottom = 0;
655
    if (childrenInline())
ap's avatar
ap committed
656
        layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom);
657
    else
mitz@apple.com's avatar
mitz@apple.com committed
658
        layoutBlockChildren(relayoutChildren, maxFloatBottom);
659

660
    // Expand our intrinsic height to encompass floats.
661
    int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
bdakin's avatar
Bug #:  
bdakin committed
662
    if (floatBottom() > (m_height - toAdd) && (isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() ||
antti's avatar
antti committed
663
                                    (parent() && parent()->isFlexibleBox() || m_hasColumns)))
664
        m_height = floatBottom() + toAdd;
665
    
666 667
    // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as
    // we adjust for clean column breaks.
668
    int singleColumnBottom = layoutColumns();
669 670

    // Calculate our new height.
671 672 673
    int oldHeight = m_height;
    calcHeight();
    if (oldHeight != m_height) {
mitz@apple.com's avatar
mitz@apple.com committed
674 675 676 677 678 679
        if (oldHeight > m_height && maxFloatBottom > m_height && !childrenInline()) {
            // One of our children's floats may have become an overhanging float for us. We need to look for it.
            for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
                if (child->isBlockFlow() && !child->isFloatingOrPositioned()) {
                    RenderBlock* block = static_cast<RenderBlock*>(child);
                    if (block->floatBottom() + block->yPos() > m_height)
mitz@apple.com's avatar
mitz@apple.com committed
680
                        addOverhangingFloats(block, -block->xPos(), -block->yPos(), false);
mitz@apple.com's avatar
mitz@apple.com committed
681 682 683
                }
            }
        }
684 685 686
        // We have to rebalance columns to the new height.
        layoutColumns(singleColumnBottom);

687 688
        // If the block got expanded in size, then increase our overflowheight to match.
        if (m_overflowHeight > m_height)
689
            m_overflowHeight -= toAdd;
690 691 692
        if (m_overflowHeight < m_height)
            m_overflowHeight = m_height;
    }
693 694
    if (previousHeight != m_height)
        relayoutChildren = true;
695

696 697 698
    // Some classes of objects (floats and fieldsets with no specified heights and table cells) expand to encompass
    // overhanging floats.
    if (hasOverhangingFloats() && expandsToEncloseOverhangingFloats()) {
699 700 701 702
        m_height = floatBottom();
        m_height += borderBottom() + paddingBottom();
    }

darin's avatar
darin committed
703
    if ((isCell || isInline() || isFloatingOrPositioned() || isRoot()) && !hasOverflowClip() && !hasControlClip())
ap's avatar
ap committed
704 705
        addVisualOverflow(floatRect());

706
    layoutPositionedObjects(relayoutChildren || isRoot());
707

justing's avatar
justing committed
708 709
    positionListMarker();

710
    // Always ensure our overflow width/height are at least as large as our width/height.
darin's avatar
darin committed
711 712
    m_overflowWidth = max(m_overflowWidth, m_width);
    m_overflowHeight = max(m_overflowHeight, m_height);
713

714
    if (!hasOverflowClip()) {
mitz@apple.com's avatar
mitz@apple.com committed
715
        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
716 717 718 719 720
            m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur);
            m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur);
            m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur);
            m_overflowHeight = max(m_overflowHeight, m_height + boxShadow->y + boxShadow->blur);
        }
hyatt@apple.com's avatar
hyatt@apple.com committed
721 722 723 724 725
        
        if (hasReflection()) {
            m_overflowTop = min(m_overflowTop, reflectionBox().y());
            m_overflowHeight = max(m_overflowHeight, reflectionBox().bottom());
        }
726 727
    }

hyatt@apple.com's avatar
hyatt@apple.com committed
728
    if (!hadColumns && !hasReflection())
weinig's avatar
weinig committed
729 730 731 732
        view()->popLayoutState();
    else
        view()->enableLayoutState();

733
    // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
734
    // we overflow or not.
735
    if (hasOverflowClip())
736
        m_layer->updateScrollInfoAfterLayout();
737 738

    // Repaint with our new bounds if they are different from our old bounds.
739
    bool didFullRepaint = false;
740
    if (checkForRepaint)
741
        didFullRepaint = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);
mitz@apple.com's avatar
mitz@apple.com committed
742
    if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
ap's avatar
ap committed
743 744
        IntRect repaintRect(m_overflowLeft, repaintTop, m_overflowWidth - m_overflowLeft, repaintBottom - repaintTop);

745 746 747
        // FIXME: Deal with multiple column repainting.  We have to split the repaint
        // rect up into multiple rects if it spans columns.

adele's avatar
adele committed
748 749 750 751 752 753
        repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
        
        if (hasOverflowClip()) {
            // Adjust repaint rect for scroll offset
            int x = repaintRect.x();
            int y = repaintRect.y();
754
            layer()->subtractScrolledContentOffset(x, y);
adele's avatar
adele committed
755 756 757 758 759 760
            repaintRect.setX(x);
            repaintRect.setY(y);

            // Don't allow this rect to spill out of our overflow box.
            repaintRect.intersect(IntRect(0, 0, m_width, m_height));
        }
mitz@apple.com's avatar
mitz@apple.com committed
761

adele's avatar
adele committed
762
        // Make sure the rect is still non-empty after intersecting for overflow above
hyatt@apple.com's avatar
hyatt@apple.com committed
763
        if (!repaintRect.isEmpty()) {
mitz@apple.com's avatar
mitz@apple.com committed
764
            repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
hyatt@apple.com's avatar
hyatt@apple.com committed
765 766 767
            if (hasReflection())
                layer()->reflection()->repaintRectangle(repaintRect);
        }
768
    }
769
    setNeedsLayout(false);
770 771
}

772
void RenderBlock::adjustPositionedBlock(RenderObject* child, const MarginInfo& marginInfo)
773
{
774 775 776 777 778 779 780 781
    if (child->hasStaticX()) {
        if (style()->direction() == LTR)
            child->setStaticX(borderLeft() + paddingLeft());
        else
            child->setStaticX(borderRight() + paddingRight());
    }

    if (child->hasStaticY()) {
darin's avatar
darin committed
782
        int y = m_height;
783
        if (!marginInfo.canCollapseWithTop()) {
darin's avatar
darin committed
784 785
            child->calcVerticalMargins();
            int marginTop = child->marginTop();
786 787
            int collapsedTopPos = marginInfo.posMargin();
            int collapsedTopNeg = marginInfo.negMargin();
darin's avatar
darin committed
788 789 790 791 792 793 794 795
            if (marginTop > 0) {
                if (marginTop > collapsedTopPos)
                    collapsedTopPos = marginTop;
            } else {
                if (-marginTop > collapsedTopNeg)
                    collapsedTopNeg = -marginTop;
            }
            y += (collapsedTopPos - collapsedTopNeg) - marginTop;
796
        }
darin's avatar
darin committed
797
        child->setStaticY(y);
798 799
    }
}
800

801 802 803 804 805 806 807 808 809 810 811 812
void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
{
    // The float should be positioned taking into account the bottom margin
    // of the previous flow.  We add that margin into the height, get the
    // float positioned properly, and then subtract the margin out of the
    // height again.  In the case of self-collapsing blocks, we always just
    // use the top margins, since the self-collapsing block collapsed its
    // own bottom margin into its top margin.
    //
    // Note also that the previous flow may collapse its margin into the top of
    // our block.  If this is the case, then we do not add the margin in to our
    // height when computing the position of the float.   This condition can be tested
hyatt's avatar
hyatt committed
813
    // for by simply calling canCollapseWithTop.  See
814 815 816 817 818 819 820
    // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
    // an example of this scenario.
    int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin();
    m_height += marginOffset;
    positionNewFloats();
    m_height -= marginOffset;
}
821

822 823
RenderObject* RenderBlock::handleSpecialChild(RenderObject* child, const MarginInfo& marginInfo, CompactInfo& compactInfo, bool& handled)
{
824 825
    // Handle positioned children first.
    RenderObject* next = handlePositionedChild(child, marginInfo, handled);
826
    if (handled) return next;
827
    
828 829 830 831
    // Handle floating children next.
    next = handleFloatingChild(child, marginInfo, handled);
    if (handled) return next;

832 833 834
    // See if we have a compact element.  If we do, then try to tuck the compact element into the margin space of the next block.
    next = handleCompactChild(child, compactInfo, handled);
    if (handled) return next;
835

836 837 838
    // Finally, see if we have a run-in element.
    return handleRunInChild(child, handled);
}
839

840

841
RenderObject* RenderBlock::handlePositionedChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled)
842 843 844 845 846 847 848 849
{
    if (child->isPositioned()) {
        handled = true;
        child->containingBlock()->insertPositionedObject(child);
        adjustPositionedBlock(child, marginInfo);
        return child->nextSibling();
    }

850 851 852 853 854
    return 0;
}

RenderObject* RenderBlock::handleFloatingChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled)
{
855 856 857 858 859 860
    if (child->isFloating()) {
        handled = true;
        insertFloatingObject(child);
        adjustFloatingBlock(marginInfo);
        return child->nextSibling();
    }
861
    
862 863
    return 0;
}
864

865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
RenderObject* RenderBlock::handleCompactChild(RenderObject* child, CompactInfo& compactInfo, bool& handled)
{
    // FIXME: We only deal with one compact at a time.  It is unclear what should be
    // done if multiple contiguous compacts are encountered.  For now we assume that
    // compact A followed by another compact B should simply be treated as block A.
    if (child->isCompact() && !compactInfo.compact() && (child->childrenInline() || child->isReplaced())) {
        // Get the next non-positioned/non-floating RenderBlock.
        RenderObject* next = child->nextSibling();
        RenderObject* curr = next;
        while (curr && curr->isFloatingOrPositioned())
            curr = curr->nextSibling();
        if (curr && curr->isRenderBlock() && !curr->isCompact() && !curr->isRunIn()) {
            curr->calcWidth(); // So that horizontal margins are correct.
                               
            child->setInline(true); // Need to compute the margins/width for the child as though it is an inline, so that it won't try to puff up the margins to
                                    // fill the containing block width.
            child->calcWidth();
            int childMargins = child->marginLeft() + child->marginRight();
            int margin = style()->direction() == LTR ? curr->marginLeft() : curr->marginRight();
darin's avatar
darin committed
884
            if (margin >= (childMargins + child->maxPrefWidth())) {
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
                // The compact will fit in the margin.
                handled = true;
                compactInfo.set(child, curr);
                child->setPos(0,0); // This position will be updated to reflect the compact's
                                    // desired position and the line box for the compact will
                                    // pick that position up.
                
                // Remove the child.
                RenderObject* next = child->nextSibling();
                removeChildNode(child);
                
                // Now insert the child under |curr|.
                curr->insertChildNode(child, curr->firstChild());
                return next;
            }
            else
                child->setInline(false); // We didn't fit, so we remain a block-level element.
        }
    }
    return 0;
}
906

907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922
void RenderBlock::insertCompactIfNeeded(RenderObject* child, CompactInfo& compactInfo)
{
    if (compactInfo.matches(child)) {
        // We have a compact child to squeeze in.
        RenderObject* compactChild = compactInfo.compact();
        int compactXPos = borderLeft() + paddingLeft() + compactChild->marginLeft();
        if (style()->direction() == RTL) {
            compactChild->calcWidth(); // have to do this because of the capped maxwidth
            compactXPos = width() - borderRight() - paddingRight() - marginRight() -
                compactChild->width() - compactChild->marginRight();
        }
        compactXPos -= child->xPos(); // Put compactXPos into the child's coordinate space.
        compactChild->setPos(compactXPos, compactChild->yPos()); // Set the x position.
        compactInfo.clear();
    }
}
923

924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951
RenderObject* RenderBlock::handleRunInChild(RenderObject* child, bool& handled)
{
    // See if we have a run-in element with inline children.  If the
    // children aren't inline, then just treat the run-in as a normal
    // block.
    if (child->isRunIn() && (child->childrenInline() || child->isReplaced())) {
        // Get the next non-positioned/non-floating RenderBlock.
        RenderObject* curr = child->nextSibling();
        while (curr && curr->isFloatingOrPositioned())
            curr = curr->nextSibling();
        if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isCompact() && !curr->isRunIn())) {
            // The block acts like an inline, so just null out its
            // position.
            handled = true;
            child->setInline(true);
            child->setPos(0,0);
            
            // Remove the child.
            RenderObject* next = child->nextSibling();
            removeChildNode(child);
            
            // Now insert the child under |curr|.
            curr->insertChildNode(child, curr->firstChild());
            return next;
        }
    }
    return 0;
}
952

953 954 955 956 957
void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, int yPosEstimate)
{
    // Get our max pos and neg top margins.
    int posTop = child->maxTopMargin(true);
    int negTop = child->maxTopMargin(false);
958

959 960 961
    // For self-collapsing blocks, collapse our bottom margins into our
    // top to get new posTop and negTop values.
    if (child->isSelfCollapsingBlock()) {
darin's avatar
darin committed
962 963
        posTop = max(posTop, child->maxBottomMargin(true));
        negTop = max(negTop, child->maxBottomMargin(false));
964 965 966 967 968 969 970 971 972 973
    }
    
    // See if the top margin is quirky. We only care if this child has
    // margins that will collapse with us.
    bool topQuirk = child->isTopMarginQuirk() || style()->marginTopCollapse() == MDISCARD;

    if (marginInfo.canCollapseWithTop()) {
        // This child is collapsing with the top of the
        // block.  If it has larger margin values, then we need to update
        // our own maximal values.
antti's avatar
antti committed
974 975
        if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk)
            setMaxTopMargins(max(posTop, maxTopPosMargin()), max(negTop, maxTopNegMargin()));
976

977 978 979 980 981 982 983 984
        // The minute any of the margins involved isn't a quirk, don't
        // collapse it away, even if the margin is smaller (www.webreference.com
        // has an example of this, a <dt> with 0.8em author-specified inside
        // a <dl> inside a <td>.
        if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop-negTop)) {
            m_topMarginQuirk = false;
            marginInfo.setDeterminedTopQuirk(true);
        }
985

986 987 988 989 990 991 992 993 994 995 996