RenderBlock.cpp 185 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 "RenderInline.h"
36
#include "RenderMarquee.h"
hyatt@apple.com's avatar
hyatt@apple.com committed
37
#include "RenderReplica.h"
darin's avatar
darin committed
38
#include "RenderTableCell.h"
darin's avatar
darin committed
39
#include "RenderTextFragment.h"
darin's avatar
darin committed
40
#include "RenderTheme.h"
weinig's avatar
weinig committed
41 42
#include "RenderView.h"
#include "SelectionController.h"
43
#include <wtf/StdLibExtras.h>
44

darin's avatar
darin committed
45
using namespace std;
darin's avatar
darin committed
46 47
using namespace WTF;
using namespace Unicode;
darin's avatar
darin committed
48

darin's avatar
darin committed
49 50
namespace WebCore {

aliceli1's avatar
aliceli1 committed
51 52 53 54
// 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
55
using namespace HTMLNames;
56

antti's avatar
antti committed
57 58 59 60 61 62 63 64 65 66 67 68 69
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
70 71 72 73 74
typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;
static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;

typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
75
    
darin@apple.com's avatar
darin@apple.com committed
76
typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderFlow*>*> ContinuationOutlineTableMap;
mitz@apple.com's avatar
mitz@apple.com committed
77

78 79 80 81 82 83
// 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.
84
    m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned() &&
85 86 87 88 89 90 91 92 93
        !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
94
        (block->style()->height().isAuto() && block->style()->height().value() == 0) && block->style()->marginBottomCollapse() != MSEPARATE;
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    
    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
112
RenderBlock::RenderBlock(Node* node)
antti's avatar
antti committed
113 114 115 116 117 118 119 120 121
      : RenderFlow(node)
      , m_floatingObjects(0)
      , m_positionedObjects(0)
      , m_maxMargin(0)
      , m_overflowHeight(0)
      , m_overflowWidth(0)
      , m_overflowLeft(0)
      , m_overflowTop(0)
{
122 123 124 125
}

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

    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;
        }
    }
151 152
}

153
void RenderBlock::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
154
{
155
    setReplaced(newStyle->isDisplayReplacedType());
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    
    if (style() && parent() && diff == RenderStyle::Layout && style()->position() != newStyle->position()) {
        if (newStyle->position() == StaticPosition)
            // Clear our positioned objects list. Our absolutely positioned descendants will be
            // inserted into our containing block's positioned objects list during layout.
            removePositionedObjects(0);
        else if (style()->position() == StaticPosition) {
            // Remove our absolutely positioned descendants from their current containing block.
            // They will be inserted into our positioned objects list during layout.
            RenderObject* cb = parent();
            while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
                if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
                    cb = cb->containingBlock();
                    break;
                }
                cb = cb->parent();
            }
            
            if (cb->isRenderBlock())
                static_cast<RenderBlock*>(cb)->removePositionedObjects(this);
        }
    }

179 180
    RenderFlow::styleWillChange(diff, newStyle);
}
181

182 183 184
void RenderBlock::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle)
{
    RenderFlow::styleDidChange(diff, oldStyle);
185

186 187 188
    // 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()) {
189
            RefPtr<RenderStyle> newStyle = RenderStyle::create();
190 191
            newStyle->inheritFrom(style());
            newStyle->setDisplay(BLOCK);
192
            child->setStyle(newStyle.release());
193
        }
194 195
    }

196 197
    m_lineHeight = -1;

198
    // Update pseudos for :before and :after now.
199
    if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) {
hyatt's avatar
hyatt committed
200 201 202
        updateBeforeAfterContent(RenderStyle::BEFORE);
        updateBeforeAfterContent(RenderStyle::AFTER);
    }
weinig's avatar
weinig committed
203
    updateFirstLetter();
darin's avatar
darin committed
204 205
}

206 207
void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild)
{
208
    // Make sure we don't append things after :after-generated content if we have it.
darin's avatar
darin committed
209
    if (!beforeChild && isAfterContent(lastChild()))
210
        beforeChild = lastChild();
mitz@apple.com's avatar
mitz@apple.com committed
211

212
    bool madeBoxesNonInline = false;
213

mitz@apple.com's avatar
mitz@apple.com committed
214 215
    // 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.
216
    if (beforeChild && beforeChild->parent() != this) {
mitz@apple.com's avatar
mitz@apple.com committed
217 218
        RenderObject* anonymousChild = beforeChild->parent();
        ASSERT(anonymousChild);
219

mitz@apple.com's avatar
mitz@apple.com committed
220 221
        while (anonymousChild->parent() != this)
            anonymousChild = anonymousChild->parent();
mitz@apple.com's avatar
mitz@apple.com committed
222

mitz@apple.com's avatar
mitz@apple.com committed
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
        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;
247 248 249 250
    }

    // 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
251 252
    // inline children into anonymous block boxes.
    if (m_childrenInline && !newChild->isInline() && !newChild->isFloatingOrPositioned()) {
253 254 255
        // 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
256

257 258
        if (beforeChild && beforeChild->parent() != this) {
            beforeChild = beforeChild->parent();
darin's avatar
darin committed
259 260
            ASSERT(beforeChild->isAnonymousBlock());
            ASSERT(beforeChild->parent() == this);
261
        }
mitz@apple.com's avatar
mitz@apple.com committed
262
    } else if (!m_childrenInline && (newChild->isFloatingOrPositioned() || newChild->isInline())) {
263 264 265
        // 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
266 267 268 269 270 271 272
        RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();

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

273
        if (newChild->isInline()) {
mitz@apple.com's avatar
mitz@apple.com committed
274
            // No suitable existing anonymous box - create a new one.
275
            RenderBlock* newBox = createAnonymousBlock();
mitz@apple.com's avatar
mitz@apple.com committed
276
            RenderContainer::addChild(newBox, beforeChild);
277 278 279 280 281
            newBox->addChild(newChild);
            return;
        }
    }

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

antti's avatar
antti committed
285 286 287
    if (madeBoxesNonInline && parent() && isAnonymousBlock())
        parent()->removeLeftoverAnonymousBlock(this);
    // this object may be dead here
288 289
}

hyatt's avatar
hyatt committed
290
static void getInlineRun(RenderObject* start, RenderObject* boundary,
291 292 293 294 295 296 297 298 299 300 301
                         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
302 303
    // |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
304
    // a non-inline.
hyatt's avatar
hyatt committed
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
    
    // 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
322
            inlineRunEnd = curr;
hyatt's avatar
hyatt committed
323 324 325 326 327
            if (curr->isInline())
                sawInline = true;
            curr = curr->nextSibling();
        }
    } while (!sawInline);
328 329
}

bdakin's avatar
bdakin committed
330 331 332 333 334 335 336 337 338 339 340 341
void RenderBlock::deleteLineBoxTree()
{
    InlineFlowBox* line = m_firstLineBox;
    InlineFlowBox* nextLine;
    while (line) {
        nextLine = line->nextFlowBox();
        line->deleteLine(renderArena());
        line = nextLine;
    }
    m_firstLineBox = m_lastLineBox = 0;
}

342
void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
hyatt's avatar
hyatt committed
343
{    
344 345 346 347 348 349 350
    // 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
351 352
    ASSERT(isInlineBlockOrInlineTable() || !isInline());
    ASSERT(!insertionPoint || insertionPoint->parent() == this);
353 354 355 356

    m_childrenInline = false;

    RenderObject *child = firstChild();
mitz@apple.com's avatar
mitz@apple.com committed
357 358 359 360
    if (!child)
        return;

    deleteLineBoxTree();
361 362 363 364 365 366 367 368 369 370

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

        if (!inlineRunStart)
            break;

        child = inlineRunEnd->nextSibling();

371
        RenderBlock* box = createAnonymousBlock();
372 373 374 375 376 377
        insertChildNode(box, inlineRunStart);
        RenderObject* o = inlineRunStart;
        while(o != inlineRunEnd)
        {
            RenderObject* no = o;
            o = no->nextSibling();
378
            box->moveChildNode(no);
379
        }
380
        box->moveChildNode(inlineRunEnd);
381
    }
hyatt's avatar
hyatt committed
382 383 384

#ifndef NDEBUG
    for (RenderObject *c = firstChild(); c; c = c->nextSibling())
darin's avatar
darin committed
385
        ASSERT(!c->isInline());
hyatt's avatar
hyatt committed
386
#endif
mitz@apple.com's avatar
mitz@apple.com committed
387 388

    repaint();
389 390 391 392 393 394 395 396 397
}

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();
398
    bool canDeleteAnonymousBlocks = !documentBeingDestroyed() && !isInline() && !oldChild->isInline() && 
399
                                    !oldChild->virtualContinuation() && 
400 401
                                    (!prev || (prev->isAnonymousBlock() && prev->childrenInline())) &&
                                    (!next || (next->isAnonymousBlock() && next->childrenInline()));
402
    if (canDeleteAnonymousBlocks && prev && next) {
403 404
        // Take all the children out of the |next| block and put them in
        // the |prev| block.
darin's avatar
darin committed
405
        prev->setNeedsLayoutAndPrefWidthsRecalc();
406 407 408 409
        RenderObject* o = next->firstChild();
        while (o) {
            RenderObject* no = o;
            o = no->nextSibling();
410
            prev->moveChildNode(no);
411
        }
bdakin's avatar
bdakin committed
412
 
weinig's avatar
weinig committed
413
        RenderBlock* nextBlock = static_cast<RenderBlock*>(next);
bdakin's avatar
bdakin committed
414
        nextBlock->deleteLineBoxTree();
weinig's avatar
weinig committed
415
        
416
        // Nuke the now-empty block.
harrison's avatar
harrison committed
417
        next->destroy();
418 419 420 421
    }

    RenderFlow::removeChild(oldChild);

422
    RenderObject* child = prev ? prev : next;
antti's avatar
antti committed
423
    if (canDeleteAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) {
424
        // The removal has knocked us down to containing only a single anonymous
425 426
        // box.  We can go ahead and pull the content right back up into our
        // box.
darin's avatar
darin committed
427
        setNeedsLayoutAndPrefWidthsRecalc();
darin's avatar
darin committed
428
        RenderBlock* anonBlock = static_cast<RenderBlock*>(removeChildNode(child, false));
429 430 431 432 433
        m_childrenInline = true;
        RenderObject* o = anonBlock->firstChild();
        while (o) {
            RenderObject* no = o;
            o = no->nextSibling();
434
            moveChildNode(no);
435
        }
436

bdakin's avatar
bdakin committed
437 438
        // Delete the now-empty block's lines and nuke it.
        anonBlock->deleteLineBoxTree();
harrison's avatar
harrison committed
439
        anonBlock->destroy();
440 441 442
    }
}

443 444
int RenderBlock::overflowHeight(bool includeInterior) const
{
445
    if (!includeInterior && hasOverflowClip()) {
mitz@apple.com's avatar
mitz@apple.com committed
446 447 448
        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
449
        int inflatedHeight = height() + shadowHeight;
hyatt@apple.com's avatar
hyatt@apple.com committed
450
        if (hasReflection())
hyatt@apple.com's avatar
hyatt@apple.com committed
451 452
            inflatedHeight = max(inflatedHeight, reflectionBox().bottom());
        return inflatedHeight;
453 454
    }
    return m_overflowHeight;
455 456 457 458
}

int RenderBlock::overflowWidth(bool includeInterior) const
{
459
    if (!includeInterior && hasOverflowClip()) {
mitz@apple.com's avatar
mitz@apple.com committed
460 461 462
        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
463
        int inflatedWidth = width() + shadowWidth;
hyatt@apple.com's avatar
hyatt@apple.com committed
464
        if (hasReflection())
hyatt@apple.com's avatar
hyatt@apple.com committed
465 466
            inflatedWidth = max(inflatedWidth, reflectionBox().right());
        return inflatedWidth;
467 468
    }
    return m_overflowWidth;
469
}
470

471 472
int RenderBlock::overflowLeft(bool includeInterior) const
{
473
    if (!includeInterior && hasOverflowClip()) {
mitz@apple.com's avatar
mitz@apple.com committed
474 475 476
        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
477 478 479 480
        int left = shadowLeft;
        if (hasReflection())
            left = min(left, reflectionBox().x());
        return left;
481 482
    }
    return m_overflowLeft;
483 484 485 486
}

int RenderBlock::overflowTop(bool includeInterior) const
{
487
    if (!includeInterior && hasOverflowClip()) {
mitz@apple.com's avatar
mitz@apple.com committed
488 489 490
        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
491 492 493 494
        int top = shadowTop;
        if (hasReflection())
            top = min(top, reflectionBox().y());
        return top;
495 496
    }
    return m_overflowTop;
497 498
}

499
IntRect RenderBlock::overflowRect(bool includeInterior) const
500
{
501
    if (!includeInterior && hasOverflowClip()) {
hyatt@apple.com's avatar
hyatt@apple.com committed
502
        IntRect box = borderBoxRect();
mitz@apple.com's avatar
mitz@apple.com committed
503 504 505 506 507 508 509 510 511 512
        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);
513
        }
mitz@apple.com's avatar
mitz@apple.com committed
514 515 516 517

        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
518 519 520 521 522 523 524 525 526 527 528 529 530

        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);
        }
531 532 533
        return box;
    }

534
    if (!includeInterior && hasOverflowClip())
hyatt@apple.com's avatar
hyatt@apple.com committed
535
        return borderBoxRect();
536
    int l = overflowLeft(includeInterior);
537 538
    int t = overflowTop(includeInterior);
    return IntRect(l, t, overflowWidth(includeInterior) - l, max(overflowHeight(includeInterior), height()) - t);
539 540
}

541 542 543 544 545 546 547
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
548
    // (e) have specified that one of our margins can't collapse using a CSS extension
hyatt@apple.com's avatar
hyatt@apple.com committed
549
    if (height() > 0 ||
550
        isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 ||
ddkilzer's avatar
ddkilzer committed
551
        style()->minHeight().isPositive() || 
552
        style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE)
553 554
        return false;

555
    bool hasAutoHeight = style()->height().isAuto();
556 557
    if (style()->height().isPercent() && !style()->htmlHacks()) {
        hasAutoHeight = true;
558
        for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
559 560 561 562 563
            if (cb->style()->height().isFixed() || cb->isTableCell())
                hasAutoHeight = false;
        }
    }

564 565
    // 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
566
    if (hasAutoHeight || ((style()->height().isFixed() || style()->height().isPercent()) && style()->height().isZero())) {
567 568 569 570 571 572 573
        // 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.
574
        for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
575 576 577 578 579 580 581 582 583 584
            if (child->isFloatingOrPositioned())
                continue;
            if (!child->isSelfCollapsingBlock())
                return false;
        }
        return true;
    }
    return false;
}

585 586
void RenderBlock::layout()
{
587 588 589
    // Update our first letter info now.
    updateFirstLetter();

590 591 592
    // Table cells call layoutBlock directly, so don't add any logic here.  Put code into
    // layoutBlock().
    layoutBlock(false);
593 594 595 596
    
    // 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.
hyatt@apple.com's avatar
hyatt@apple.com committed
597 598
        m_overflowWidth = width();
        m_overflowHeight = height();
599 600 601
        m_overflowLeft = 0;
        m_overflowTop = 0;
    }
602 603 604 605
}

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

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

weinig's avatar
weinig committed
611
    if (!relayoutChildren && layoutOnlyPositionedObjects())
612
        return;
weinig's avatar
weinig committed
613

ap's avatar
ap committed
614
    IntRect oldBounds;
615
    IntRect oldOutlineBox;
mitz@apple.com's avatar
mitz@apple.com committed
616
    bool checkForRepaint = m_everHadLayout && checkForRepaintDuringLayout();
617
    if (checkForRepaint) {
618
        oldBounds = absoluteClippedOverflowRect();
619
        oldOutlineBox = absoluteOutlineBounds();
620
    }
621

hyatt@apple.com's avatar
hyatt@apple.com committed
622
    LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), m_hasColumns || hasTransform() || hasReflection());
weinig's avatar
weinig committed
623

hyatt@apple.com's avatar
hyatt@apple.com committed
624
    int oldWidth = width();
antti's avatar
antti committed
625
    int oldColumnWidth = desiredColumnWidth();
626

627
    calcWidth();
628 629
    calcColumnWidth();

hyatt@apple.com's avatar
hyatt@apple.com committed
630
    m_overflowWidth = width();
631
    m_overflowLeft = 0;
632

hyatt@apple.com's avatar
hyatt@apple.com committed
633
    if (oldWidth != width() || oldColumnWidth != desiredColumnWidth())
634 635 636 637
        relayoutChildren = true;

    clearFloats();

hyatt@apple.com's avatar
hyatt@apple.com committed
638 639 640
    int previousHeight = height();
    setHeight(0);

641 642 643 644 645 646 647 648 649 650 651 652
    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
653 654
    bool isCell = isTableCell();
    if (!isCell) {
655 656
        initMaxMarginValues();

darin's avatar
darin committed
657 658
        m_topMarginQuirk = style()->marginTop().quirk();
        m_bottomMarginQuirk = style()->marginBottom().quirk();
659

660 661
        Node* node = element();
        if (node && node->hasTagName(formTag) && static_cast<HTMLFormElement*>(node)->isMalformed()) {
662 663
            // See if this form is malformed (i.e., unclosed). If so, don't give the form
            // a bottom margin.
antti's avatar
antti committed
664
            setMaxBottomMargins(0, 0);
665
        }
666 667
    }

668
    // For overflow:scroll blocks, ensure we have both scrollbars in place always.
669
    if (scrollsOverflow()) {
670
        if (style()->overflowX() == OSCROLL)
671
            m_layer->setHasHorizontalScrollbar(true);
672
        if (style()->overflowY() == OSCROLL)
673 674
            m_layer->setHasVerticalScrollbar(true);
    }
675

ap's avatar
ap committed
676 677
    int repaintTop = 0;
    int repaintBottom = 0;
mitz@apple.com's avatar
mitz@apple.com committed
678
    int maxFloatBottom = 0;
679
    if (childrenInline())
ap's avatar
ap committed
680
        layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom);
681
    else
mitz@apple.com's avatar
mitz@apple.com committed
682
        layoutBlockChildren(relayoutChildren, maxFloatBottom);
683

684
    // Expand our intrinsic height to encompass floats.
685
    int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
686
    if (floatBottom() > (height() - toAdd) && expandsToEncloseOverhangingFloats())
hyatt@apple.com's avatar
hyatt@apple.com committed
687
        setHeight(floatBottom() + toAdd);
688
    
689 690
    // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as
    // we adjust for clean column breaks.
691
    int singleColumnBottom = layoutColumns();
692 693

    // Calculate our new height.
hyatt@apple.com's avatar
hyatt@apple.com committed
694
    int oldHeight = height();
695
    calcHeight();
hyatt@apple.com's avatar
hyatt@apple.com committed
696 697
    if (oldHeight != height()) {
        if (oldHeight > height() && maxFloatBottom > height() && !childrenInline()) {
mitz@apple.com's avatar
mitz@apple.com committed
698 699 700 701
            // 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);
hyatt@apple.com's avatar
hyatt@apple.com committed
702 703
                    if (block->floatBottom() + block->y() > height())
                        addOverhangingFloats(block, -block->x(), -block->y(), false);
mitz@apple.com's avatar
mitz@apple.com committed
704 705 706
                }
            }
        }
707 708 709
        // We have to rebalance columns to the new height.
        layoutColumns(singleColumnBottom);

710
        // If the block got expanded in size, then increase our overflowheight to match.
hyatt@apple.com's avatar
hyatt@apple.com committed
711
        if (m_overflowHeight > height())
712
            m_overflowHeight -= toAdd;
hyatt@apple.com's avatar
hyatt@apple.com committed
713 714
        if (m_overflowHeight < height())
            m_overflowHeight = height();
715
    }
hyatt@apple.com's avatar
hyatt@apple.com committed
716
    if (previousHeight != height())
717
        relayoutChildren = true;
718

darin's avatar
darin committed
719
    if ((isCell || isInline() || isFloatingOrPositioned() || isRoot()) && !hasOverflowClip() && !hasControlClip())
ap's avatar
ap committed
720 721
        addVisualOverflow(floatRect());

722
    layoutPositionedObjects(relayoutChildren || isRoot());
723

justing's avatar
justing committed
724 725
    positionListMarker();

726
    // Always ensure our overflow width/height are at least as large as our width/height.
hyatt@apple.com's avatar
hyatt@apple.com committed
727 728
    m_overflowWidth = max(m_overflowWidth, width());
    m_overflowHeight = max(m_overflowHeight, height());
729

730
    if (!hasOverflowClip()) {
mitz@apple.com's avatar
mitz@apple.com committed
731
        for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) {
732
            m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur);
hyatt@apple.com's avatar
hyatt@apple.com committed
733
            m_overflowWidth = max(m_overflowWidth, width() + boxShadow->x + boxShadow->blur);
734
            m_overflowTop = min(m_overflowTop, boxShadow->y - boxShadow->blur);
hyatt@apple.com's avatar
hyatt@apple.com committed
735
            m_overflowHeight = max(m_overflowHeight, height() + boxShadow->y + boxShadow->blur);
736
        }
hyatt@apple.com's avatar
hyatt@apple.com committed
737 738 739 740 741
        
        if (hasReflection()) {
            m_overflowTop = min(m_overflowTop, reflectionBox().y());
            m_overflowHeight = max(m_overflowHeight, reflectionBox().bottom());
        }
742 743
    }

744
    statePusher.pop();
weinig's avatar
weinig committed
745

746
    // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
747
    // we overflow or not.
748
    if (hasOverflowClip())
749
        m_layer->updateScrollInfoAfterLayout();
750 751

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

758 759 760
        // 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
761 762 763 764 765 766
        repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
        
        if (hasOverflowClip()) {
            // Adjust repaint rect for scroll offset
            int x = repaintRect.x();
            int y = repaintRect.y();
767
            layer()->subtractScrolledContentOffset(x, y);
adele's avatar
adele committed
768 769 770 771
            repaintRect.setX(x);
            repaintRect.setY(y);

            // Don't allow this rect to spill out of our overflow box.
hyatt@apple.com's avatar
hyatt@apple.com committed
772
            repaintRect.intersect(IntRect(0, 0, width(), height()));
adele's avatar
adele committed
773
        }
mitz@apple.com's avatar
mitz@apple.com committed
774

adele's avatar
adele committed
775
        // Make sure the rect is still non-empty after intersecting for overflow above
hyatt@apple.com's avatar
hyatt@apple.com committed
776
        if (!repaintRect.isEmpty()) {
mitz@apple.com's avatar
mitz@apple.com committed
777
            repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
hyatt@apple.com's avatar
hyatt@apple.com committed
778 779 780
            if (hasReflection())
                layer()->reflection()->repaintRectangle(repaintRect);
        }
781
    }
782
    setNeedsLayout(false);
783 784
}

785 786 787 788 789
bool RenderBlock::expandsToEncloseOverhangingFloats() const
{
    return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) || m_hasColumns || isTableCell() || isFieldset();
}

790
void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
791
{
792 793 794 795 796 797 798 799
    if (child->hasStaticX()) {
        if (style()->direction() == LTR)
            child->setStaticX(borderLeft() + paddingLeft());
        else
            child->setStaticX(borderRight() + paddingRight());
    }

    if (child->hasStaticY()) {
hyatt@apple.com's avatar
hyatt@apple.com committed
800
        int y = height();
801
        if (!marginInfo.canCollapseWithTop()) {
darin's avatar
darin committed
802 803
            child->calcVerticalMargins();
            int marginTop = child->marginTop();
804 805
            int collapsedTopPos = marginInfo.posMargin();
            int collapsedTopNeg = marginInfo.negMargin();
darin's avatar
darin committed
806 807 808 809 810 811 812 813
            if (marginTop > 0) {
                if (marginTop > collapsedTopPos)
                    collapsedTopPos = marginTop;
            } else {
                if (-marginTop > collapsedTopNeg)
                    collapsedTopNeg = -marginTop;
            }
            y += (collapsedTopPos - collapsedTopNeg) - marginTop;
814
        }
darin's avatar
darin committed
815
        child->setStaticY(y);
816 817
    }
}
818

819 820 821 822 823 824 825 826 827 828 829 830
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
831
    // for by simply calling canCollapseWithTop.  See
832 833 834
    // 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();
hyatt@apple.com's avatar
hyatt@apple.com committed
835
    setHeight(height() + marginOffset);
836
    positionNewFloats();
hyatt@apple.com's avatar
hyatt@apple.com committed
837
    setHeight(height() - marginOffset);
838
}
839

840
RenderBox* RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo, bool& handled)
841
{
842
    // Handle positioned children first.
hyatt@apple.com's avatar
hyatt@apple.com committed
843
    RenderBox* next = handlePositionedChild(child, marginInfo, handled);
844
    if (handled) return next;
845
    
846 847 848 849
    // Handle floating children next.
    next = handleFloatingChild(child, marginInfo, handled);
    if (handled) return next;

850 851 852
    // Finally, see if we have a run-in element.
    return handleRunInChild(child, handled);
}
853

854

hyatt@apple.com's avatar
hyatt@apple.com committed
855
RenderBox* RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo, bool& handled)
856 857 858 859 860
{
    if (child->isPositioned()) {
        handled = true;
        child->containingBlock()->insertPositionedObject(child);
        adjustPositionedBlock(child, marginInfo);
hyatt@apple.com's avatar
hyatt@apple.com committed
861
        return child->nextSiblingBox();
862 863
    }

864 865 866
    return 0;
}

hyatt@apple.com's avatar
hyatt@apple.com committed
867
RenderBox* RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo, bool& handled)
868
{
869 870 871 872
    if (child->isFloating()) {
        handled = true;
        insertFloatingObject(child);
        adjustFloatingBlock(marginInfo);
hyatt@apple.com's avatar
hyatt@apple.com committed
873
        return child->nextSiblingBox();
874
    }
875
    
876 877
    return 0;
}
878

879
RenderBox* RenderBlock::handleRunInChild(RenderBox* blockRunIn, bool& handled)
880 881 882 883
{
    // 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.
884
    if (blockRunIn->isRunIn() && (blockRunIn->childrenInline() || blockRunIn->isReplaced())) {
885
        // Get the next non-positioned/non-floating RenderBlock.
886
        RenderObject* curr = blockRunIn->nextSibling();
887 888
        while (curr && curr->isFloatingOrPositioned())
            curr = curr->nextSibling();
889
        if (curr && (curr->isRenderBlock() && curr->childrenInline() && !curr->isRunIn())) {
890 891 892 893
            // The block acts like an inline, so just null out its
            // position.
            handled = true;
            
894 895 896 897 898