diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2009-06-15 09:06:43 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-06-15 09:31:31 (GMT) |
commit | c411f16870f112c3407c28c22b617f613a82cff4 (patch) | |
tree | 29a1bcd590c8b31af2aab445bfe8a978dc5bf582 /src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp | |
parent | 3d77b56b32a0c53ec0bbfaa07236fedb900ff336 (diff) | |
download | Qt-c411f16870f112c3407c28c22b617f613a82cff4.zip Qt-c411f16870f112c3407c28c22b617f613a82cff4.tar.gz Qt-c411f16870f112c3407c28c22b617f613a82cff4.tar.bz2 |
Updated WebKit from /home/shausman/src/webkit/trunk to qtwebkit-4.6-snapshot-15062009 ( 65232bf00dc494ebfd978f998c88f58d18ecce1e )
Diffstat (limited to 'src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp')
-rw-r--r-- | src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp | 2006 |
1 files changed, 1202 insertions, 804 deletions
diff --git a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp index 0aa58da..89cf112 100644 --- a/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp +++ b/src/3rdparty/webkit/WebCore/rendering/RenderBlock.cpp @@ -25,13 +25,16 @@ #include "Document.h" #include "Element.h" +#include "FloatQuad.h" #include "Frame.h" #include "FrameView.h" #include "GraphicsContext.h" +#include "HTMLFormElement.h" #include "HTMLNames.h" #include "HitTestResult.h" #include "InlineTextBox.h" #include "RenderImage.h" +#include "RenderInline.h" #include "RenderMarquee.h" #include "RenderReplica.h" #include "RenderTableCell.h" @@ -39,6 +42,7 @@ #include "RenderTheme.h" #include "RenderView.h" #include "SelectionController.h" +#include "Settings.h" #include <wtf/StdLibExtras.h> using namespace std; @@ -49,10 +53,16 @@ namespace WebCore { // 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; +static const int verticalLineClickFudgeFactor = 3; using namespace HTMLNames; +static void moveChild(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* from, RenderObjectChildList* fromChildList, RenderObject* child) +{ + ASSERT(from == child->parent()); + toChildList->appendChildNode(to, fromChildList->removeChildNode(from, child, false), false); +} + struct ColumnInfo { ColumnInfo() : m_desiredColumnWidth(0) @@ -72,7 +82,7 @@ static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0; typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap; static PercentHeightContainerMap* gPercentHeightContainerMap = 0; -typedef WTF::HashMap<RenderBlock*, RenderFlowSequencedSet*> ContinuationOutlineTableMap; +typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap; // Our MarginInfo state used when laying out block children. RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom) @@ -109,15 +119,18 @@ RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom) // ------------------------------------------------------------------------------------------------------- RenderBlock::RenderBlock(Node* node) - : RenderFlow(node) + : RenderBox(node) , m_floatingObjects(0) , m_positionedObjects(0) + , m_inlineContinuation(0) , m_maxMargin(0) , m_overflowHeight(0) , m_overflowWidth(0) , m_overflowLeft(0) , m_overflowTop(0) + , m_lineHeight(-1) { + setChildrenInline(true); } RenderBlock::~RenderBlock() @@ -126,7 +139,7 @@ RenderBlock::~RenderBlock() delete m_positionedObjects; delete m_maxMargin; - if (m_hasColumns) + if (hasColumns()) delete gColumnInfoMap->take(this); if (gPercentHeightDescendantsMap) { @@ -149,15 +162,76 @@ RenderBlock::~RenderBlock() } } -void RenderBlock::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle) +void RenderBlock::destroy() +{ + // Detach our continuation first. + if (m_inlineContinuation) + m_inlineContinuation->destroy(); + m_inlineContinuation = 0; + + // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will + // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. + children()->destroyLeftoverChildren(); + + if (!documentBeingDestroyed()) { + if (firstLineBox()) { + // We can't wait for RenderBox::destroy to clear the selection, + // because by then we will have nuked the line boxes. + // FIXME: The SelectionController should be responsible for this when it + // is notified of DOM mutations. + if (isSelectionBorder()) + view()->clearSelection(); + + // If we are an anonymous block, then our line boxes might have children + // that will outlast this block. In the non-anonymous block case those + // children will be destroyed by the time we return from this function. + if (isAnonymousBlock()) { + for (InlineFlowBox* box = firstLineBox(); box; box = box->nextFlowBox()) { + while (InlineBox* childBox = box->firstChild()) + childBox->remove(); + } + } + } else if (isInline() && parent()) + parent()->dirtyLinesFromChangedChild(this); + } + + m_lineBoxes.deleteLineBoxes(renderArena()); + + RenderBox::destroy(); +} + +void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) { setReplaced(newStyle->isDisplayReplacedType()); - RenderFlow::styleWillChange(diff, newStyle); + + if (style() && parent() && diff == StyleDifferenceLayout && 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()) + toRenderBlock(cb)->removePositionedObjects(this); + } + } + + RenderBox::styleWillChange(diff, newStyle); } -void RenderBlock::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldStyle) +void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { - RenderFlow::styleDidChange(diff, oldStyle); + RenderBox::styleDidChange(diff, oldStyle); // FIXME: We could save this call when the change only affected non-inherited properties for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { @@ -172,14 +246,22 @@ void RenderBlock::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldS m_lineHeight = -1; // Update pseudos for :before and :after now. - if (!isAnonymous() && canHaveChildren()) { - updateBeforeAfterContent(RenderStyle::BEFORE); - updateBeforeAfterContent(RenderStyle::AFTER); + if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) { + updateBeforeAfterContent(BEFORE); + updateBeforeAfterContent(AFTER); } updateFirstLetter(); } -void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChild) +void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId) +{ + // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it. + if (parent() && parent()->createsAnonymousWrapper()) + return; + return children()->updateBeforeAfterContent(this, pseudoId); +} + +void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild) { // Make sure we don't append things after :after-generated content if we have it. if (!beforeChild && isAfterContent(lastChild())) @@ -203,13 +285,13 @@ void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChi if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild) beforeChild->parent()->addChild(newChild, beforeChild); else - addChildToFlow(newChild, beforeChild->parent()); + addChild(newChild, beforeChild->parent()); return; } ASSERT(anonymousChild->isTable()); - if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP - || newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION + if ((newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP) + || (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION) || newChild->isTableSection() || newChild->isTableRow() || newChild->isTableCell()) { @@ -225,7 +307,7 @@ void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChi // 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 // inline children into anonymous block boxes. - if (m_childrenInline && !newChild->isInline() && !newChild->isFloatingOrPositioned()) { + if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrPositioned()) { // This is a block with inline content. Wrap the inline content in anonymous blocks. makeChildrenNonInline(beforeChild); madeBoxesNonInline = true; @@ -235,7 +317,7 @@ void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChi ASSERT(beforeChild->isAnonymousBlock()); ASSERT(beforeChild->parent() == this); } - } else if (!m_childrenInline && (newChild->isFloatingOrPositioned() || newChild->isInline())) { + } else if (!childrenInline() && (newChild->isFloatingOrPositioned() || newChild->isInline())) { // 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. @@ -249,17 +331,16 @@ void RenderBlock::addChildToFlow(RenderObject* newChild, RenderObject* beforeChi if (newChild->isInline()) { // No suitable existing anonymous box - create a new one. RenderBlock* newBox = createAnonymousBlock(); - RenderContainer::addChild(newBox, beforeChild); + RenderBox::addChild(newBox, beforeChild); newBox->addChild(newChild); return; } } - RenderContainer::addChild(newChild, beforeChild); - // ### care about aligned stuff + RenderBox::addChild(newChild, beforeChild); - if (madeBoxesNonInline && parent() && isAnonymousBlock()) - parent()->removeLeftoverAnonymousBlock(this); + if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock()) + toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); // this object may be dead here } @@ -305,14 +386,19 @@ static void getInlineRun(RenderObject* start, RenderObject* boundary, void RenderBlock::deleteLineBoxTree() { - InlineFlowBox* line = m_firstLineBox; - InlineFlowBox* nextLine; - while (line) { - nextLine = line->nextFlowBox(); - line->deleteLine(renderArena()); - line = nextLine; - } - m_firstLineBox = m_lastLineBox = 0; + m_lineBoxes.deleteLineBoxTree(renderArena()); +} + +RootInlineBox* RenderBlock::createRootBox() +{ + return new (renderArena()) RootInlineBox(this); +} + +RootInlineBox* RenderBlock::createRootInlineBox() +{ + RootInlineBox* rootBox = createRootBox(); + m_lineBoxes.appendLineBox(rootBox); + return rootBox; } void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) @@ -327,7 +413,7 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) ASSERT(isInlineBlockOrInlineTable() || !isInline()); ASSERT(!insertionPoint || insertionPoint->parent() == this); - m_childrenInline = false; + setChildrenInline(false); RenderObject *child = firstChild(); if (!child) @@ -344,16 +430,16 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) child = inlineRunEnd->nextSibling(); - RenderBlock* box = createAnonymousBlock(); - insertChildNode(box, inlineRunStart); + RenderBlock* block = createAnonymousBlock(); + children()->insertChildNode(this, block, inlineRunStart); RenderObject* o = inlineRunStart; - while(o != inlineRunEnd) - { + while (o != inlineRunEnd) { RenderObject* no = o; o = no->nextSibling(); - box->moveChildNode(no); + + moveChild(block, block->children(), this, children(), no); } - box->moveChildNode(inlineRunEnd); + moveChild(block, block->children(), this, children(), inlineRunEnd); } #ifndef NDEBUG @@ -364,7 +450,49 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) repaint(); } -void RenderBlock::removeChild(RenderObject *oldChild) +void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child) +{ + ASSERT(child->isAnonymousBlock()); + ASSERT(!child->childrenInline()); + + if (child->inlineContinuation()) + return; + + RenderObject* firstAnChild = child->m_children.firstChild(); + RenderObject* lastAnChild = child->m_children.lastChild(); + if (firstAnChild) { + RenderObject* o = firstAnChild; + while (o) { + o->setParent(this); + o = o->nextSibling(); + } + firstAnChild->setPreviousSibling(child->previousSibling()); + lastAnChild->setNextSibling(child->nextSibling()); + if (child->previousSibling()) + child->previousSibling()->setNextSibling(firstAnChild); + if (child->nextSibling()) + child->nextSibling()->setPreviousSibling(lastAnChild); + } else { + if (child->previousSibling()) + child->previousSibling()->setNextSibling(child->nextSibling()); + if (child->nextSibling()) + child->nextSibling()->setPreviousSibling(child->previousSibling()); + } + if (child == m_children.firstChild()) + m_children.setFirstChild(firstAnChild); + if (child == m_children.lastChild()) + m_children.setLastChild(lastAnChild); + child->setParent(0); + child->setPreviousSibling(0); + child->setNextSibling(0); + + child->children()->setFirstChild(0); + child->m_next = 0; + + child->destroy(); +} + +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 @@ -372,7 +500,7 @@ void RenderBlock::removeChild(RenderObject *oldChild) RenderObject* prev = oldChild->previousSibling(); RenderObject* next = oldChild->nextSibling(); bool canDeleteAnonymousBlocks = !documentBeingDestroyed() && !isInline() && !oldChild->isInline() && - !oldChild->continuation() && + (!oldChild->isRenderBlock() || !toRenderBlock(oldChild)->inlineContinuation()) && (!prev || (prev->isAnonymousBlock() && prev->childrenInline())) && (!next || (next->isAnonymousBlock() && next->childrenInline())); if (canDeleteAnonymousBlocks && prev && next) { @@ -380,20 +508,22 @@ void RenderBlock::removeChild(RenderObject *oldChild) // the |prev| block. prev->setNeedsLayoutAndPrefWidthsRecalc(); RenderObject* o = next->firstChild(); + + RenderBlock* nextBlock = toRenderBlock(next); + RenderBlock* prevBlock = toRenderBlock(prev); while (o) { RenderObject* no = o; o = no->nextSibling(); - prev->moveChildNode(no); + moveChild(prevBlock, prevBlock->children(), nextBlock, nextBlock->children(), no); } - RenderBlock* nextBlock = static_cast<RenderBlock*>(next); nextBlock->deleteLineBoxTree(); // Nuke the now-empty block. next->destroy(); } - RenderFlow::removeChild(oldChild); + RenderBox::removeChild(oldChild); RenderObject* child = prev ? prev : next; if (canDeleteAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) { @@ -401,13 +531,13 @@ void RenderBlock::removeChild(RenderObject *oldChild) // box. We can go ahead and pull the content right back up into our // box. setNeedsLayoutAndPrefWidthsRecalc(); - RenderBlock* anonBlock = static_cast<RenderBlock*>(removeChildNode(child, false)); - m_childrenInline = true; + RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, false)); + setChildrenInline(true); RenderObject* o = anonBlock->firstChild(); while (o) { RenderObject* no = o; o = no->nextSibling(); - moveChildNode(no); + moveChild(this, children(), anonBlock, anonBlock->children(), no); } // Delete the now-empty block's lines and nuke it. @@ -422,10 +552,10 @@ int RenderBlock::overflowHeight(bool includeInterior) const int shadowHeight = 0; for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) shadowHeight = max(boxShadow->y + boxShadow->blur, shadowHeight); - int height = m_height + shadowHeight; + int inflatedHeight = height() + shadowHeight; if (hasReflection()) - height = max(height, reflectionBox().bottom()); - return height; + inflatedHeight = max(inflatedHeight, reflectionBox().bottom()); + return inflatedHeight; } return m_overflowHeight; } @@ -436,10 +566,10 @@ int RenderBlock::overflowWidth(bool includeInterior) const int shadowWidth = 0; for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) shadowWidth = max(boxShadow->x + boxShadow->blur, shadowWidth); - int width = m_width + shadowWidth; + int inflatedWidth = width() + shadowWidth; if (hasReflection()) - width = max(width, reflectionBox().right()); - return width; + inflatedWidth = max(inflatedWidth, reflectionBox().right()); + return inflatedWidth; } return m_overflowWidth; } @@ -475,7 +605,7 @@ int RenderBlock::overflowTop(bool includeInterior) const IntRect RenderBlock::overflowRect(bool includeInterior) const { if (!includeInterior && hasOverflowClip()) { - IntRect box = borderBox(); + IntRect box = borderBoxRect(); int shadowLeft = 0; int shadowRight = 0; int shadowTop = 0; @@ -508,10 +638,10 @@ IntRect RenderBlock::overflowRect(bool includeInterior) const } if (!includeInterior && hasOverflowClip()) - return borderBox(); + return borderBoxRect(); int l = overflowLeft(includeInterior); - int t = min(overflowTop(includeInterior), -borderTopExtra()); - return IntRect(l, t, overflowWidth(includeInterior) - l, max(overflowHeight(includeInterior), height() + borderBottomExtra()) - t); + int t = overflowTop(includeInterior); + return IntRect(l, t, overflowWidth(includeInterior) - l, max(overflowHeight(includeInterior), height()) - t); } bool RenderBlock::isSelfCollapsingBlock() const @@ -522,7 +652,7 @@ bool RenderBlock::isSelfCollapsingBlock() const // (c) have border/padding, // (d) have a min-height // (e) have specified that one of our margins can't collapse using a CSS extension - if (m_height > 0 || + if (height() > 0 || isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 || style()->minHeight().isPositive() || style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE) @@ -547,7 +677,7 @@ bool RenderBlock::isSelfCollapsingBlock() const // 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()) { + for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { if (child->isFloatingOrPositioned()) continue; if (!child->isSelfCollapsingBlock()) @@ -570,8 +700,8 @@ void RenderBlock::layout() // 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_overflowWidth = width(); + m_overflowHeight = height(); m_overflowLeft = 0; m_overflowTop = 0; } @@ -587,35 +717,29 @@ void RenderBlock::layoutBlock(bool relayoutChildren) if (!relayoutChildren && layoutOnlyPositionedObjects()) return; - IntRect oldBounds; - IntRect oldOutlineBox; - bool checkForRepaint = m_everHadLayout && checkForRepaintDuringLayout(); - if (checkForRepaint) { - oldBounds = absoluteClippedOverflowRect(); - oldOutlineBox = absoluteOutlineBounds(); - } - - LayoutStateMaintainer statePusher(view(), this, IntSize(xPos(), yPos()), !m_hasColumns && !hasReflection()); + LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection()); - int oldWidth = m_width; + int oldWidth = width(); int oldColumnWidth = desiredColumnWidth(); calcWidth(); calcColumnWidth(); - m_overflowWidth = m_width; + m_overflowWidth = width(); m_overflowLeft = 0; - if (oldWidth != m_width || oldColumnWidth != desiredColumnWidth()) + if (oldWidth != width() || oldColumnWidth != desiredColumnWidth()) relayoutChildren = true; clearFloats(); - int previousHeight = m_height; - m_height = 0; + int previousHeight = height(); + setHeight(0); + m_overflowHeight = 0; - // We use four values, maxTopPos, maxPosNeg, maxBottomPos, and maxBottomNeg, to track + // We use four values, maxTopPos, maxTopNeg, 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 @@ -629,11 +753,11 @@ void RenderBlock::layoutBlock(bool relayoutChildren) if (!isCell) { initMaxMarginValues(); - m_topMarginQuirk = style()->marginTop().quirk(); - m_bottomMarginQuirk = style()->marginBottom().quirk(); + setTopMarginQuirk(style()->marginTop().quirk()); + setBottomMarginQuirk(style()->marginBottom().quirk()); - Node* node = element(); - if (node && node->hasTagName(formTag) && static_cast<HTMLFormElement*>(node)->isMalformed()) { + Node* n = node(); + if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) { // See if this form is malformed (i.e., unclosed). If so, don't give the form // a bottom margin. setMaxBottomMargins(0, 0); @@ -643,9 +767,9 @@ void RenderBlock::layoutBlock(bool relayoutChildren) // For overflow:scroll blocks, ensure we have both scrollbars in place always. if (scrollsOverflow()) { if (style()->overflowX() == OSCROLL) - m_layer->setHasHorizontalScrollbar(true); + layer()->setHasHorizontalScrollbar(true); if (style()->overflowY() == OSCROLL) - m_layer->setHasVerticalScrollbar(true); + layer()->setHasVerticalScrollbar(true); } int repaintTop = 0; @@ -658,25 +782,24 @@ void RenderBlock::layoutBlock(bool relayoutChildren) // Expand our intrinsic height to encompass floats. int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); - if (floatBottom() > (m_height - toAdd) && (isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || - (parent() && parent()->isFlexibleBox() || m_hasColumns))) - m_height = floatBottom() + toAdd; + if (floatBottom() > (height() - toAdd) && expandsToEncloseOverhangingFloats()) + setHeight(floatBottom() + toAdd); // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as // we adjust for clean column breaks. int singleColumnBottom = layoutColumns(); // Calculate our new height. - int oldHeight = m_height; + int oldHeight = height(); calcHeight(); - if (oldHeight != m_height) { - if (oldHeight > m_height && maxFloatBottom > m_height && !childrenInline()) { + if (oldHeight != height()) { + if (oldHeight > height() && maxFloatBottom > 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) - addOverhangingFloats(block, -block->xPos(), -block->yPos(), false); + RenderBlock* block = toRenderBlock(child); + if (block->floatBottom() + block->y() > height()) + addOverhangingFloats(block, -block->x(), -block->y(), false); } } } @@ -684,21 +807,14 @@ void RenderBlock::layoutBlock(bool relayoutChildren) layoutColumns(singleColumnBottom); // If the block got expanded in size, then increase our overflowheight to match. - if (m_overflowHeight > m_height) + if (m_overflowHeight > height()) m_overflowHeight -= toAdd; - if (m_overflowHeight < m_height) - m_overflowHeight = m_height; + if (m_overflowHeight < height()) + m_overflowHeight = height(); } - if (previousHeight != m_height) + if (previousHeight != height()) relayoutChildren = true; - // Some classes of objects (floats and fieldsets with no specified heights and table cells) expand to encompass - // overhanging floats. - if (hasOverhangingFloats() && expandsToEncloseOverhangingFloats()) { - m_height = floatBottom(); - m_height += borderBottom() + paddingBottom(); - } - if ((isCell || isInline() || isFloatingOrPositioned() || isRoot()) && !hasOverflowClip() && !hasControlClip()) addVisualOverflow(floatRect()); @@ -707,15 +823,15 @@ void RenderBlock::layoutBlock(bool relayoutChildren) positionListMarker(); // Always ensure our overflow width/height are at least as large as our width/height. - m_overflowWidth = max(m_overflowWidth, m_width); - m_overflowHeight = max(m_overflowHeight, m_height); + m_overflowWidth = max(m_overflowWidth, width()); + m_overflowHeight = max(m_overflowHeight, height()); if (!hasOverflowClip()) { for (ShadowData* boxShadow = style()->boxShadow(); boxShadow; boxShadow = boxShadow->next) { m_overflowLeft = min(m_overflowLeft, boxShadow->x - boxShadow->blur); - m_overflowWidth = max(m_overflowWidth, m_width + boxShadow->x + boxShadow->blur); + m_overflowWidth = max(m_overflowWidth, 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); + m_overflowHeight = max(m_overflowHeight, height() + boxShadow->y + boxShadow->blur); } if (hasReflection()) { @@ -729,12 +845,10 @@ void RenderBlock::layoutBlock(bool relayoutChildren) // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. if (hasOverflowClip()) - m_layer->updateScrollInfoAfterLayout(); + layer()->updateScrollInfoAfterLayout(); // Repaint with our new bounds if they are different from our old bounds. - bool didFullRepaint = false; - if (checkForRepaint) - didFullRepaint = repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox); + bool didFullRepaint = repainter.repaintAfterLayout(); if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) { IntRect repaintRect(m_overflowLeft, repaintTop, m_overflowWidth - m_overflowLeft, repaintBottom - repaintTop); @@ -752,30 +866,35 @@ void RenderBlock::layoutBlock(bool relayoutChildren) repaintRect.setY(y); // Don't allow this rect to spill out of our overflow box. - repaintRect.intersect(IntRect(0, 0, m_width, m_height)); + repaintRect.intersect(IntRect(0, 0, width(), height())); } // Make sure the rect is still non-empty after intersecting for overflow above if (!repaintRect.isEmpty()) { repaintRectangle(repaintRect); // We need to do a partial repaint of our content. if (hasReflection()) - layer()->reflection()->repaintRectangle(repaintRect); + repaintRectangle(reflectedRect(repaintRect)); } } setNeedsLayout(false); } -void RenderBlock::adjustPositionedBlock(RenderObject* child, const MarginInfo& marginInfo) +bool RenderBlock::expandsToEncloseOverhangingFloats() const +{ + return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) || hasColumns() || isTableCell() || isFieldset(); +} + +void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo) { - if (child->hasStaticX()) { + if (child->style()->hasStaticX()) { if (style()->direction() == LTR) - child->setStaticX(borderLeft() + paddingLeft()); + child->layer()->setStaticX(borderLeft() + paddingLeft()); else - child->setStaticX(borderRight() + paddingRight()); + child->layer()->setStaticX(borderRight() + paddingRight()); } - if (child->hasStaticY()) { - int y = m_height; + if (child->style()->hasStaticY()) { + int y = height(); if (!marginInfo.canCollapseWithTop()) { child->calcVerticalMargins(); int marginTop = child->marginTop(); @@ -790,7 +909,7 @@ void RenderBlock::adjustPositionedBlock(RenderObject* child, const MarginInfo& m } y += (collapsedTopPos - collapsedTopNeg) - marginTop; } - child->setStaticY(y); + child->layer()->setStaticY(y); } } @@ -810,143 +929,95 @@ void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo) // 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; + setHeight(height() + marginOffset); positionNewFloats(); - m_height -= marginOffset; + setHeight(height() - marginOffset); } -RenderObject* RenderBlock::handleSpecialChild(RenderObject* child, const MarginInfo& marginInfo, CompactInfo& compactInfo, bool& handled) +bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo) { - // Handle positioned children first. - RenderObject* next = handlePositionedChild(child, marginInfo, handled); - if (handled) return next; - - // Handle floating children next. - next = handleFloatingChild(child, marginInfo, handled); - if (handled) return next; - - // 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; - - // Finally, see if we have a run-in element. - return handleRunInChild(child, handled); + // Handle in the given order + return handlePositionedChild(child, marginInfo) + || handleFloatingChild(child, marginInfo) + || handleRunInChild(child); } -RenderObject* RenderBlock::handlePositionedChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled) +bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo) { if (child->isPositioned()) { - handled = true; child->containingBlock()->insertPositionedObject(child); adjustPositionedBlock(child, marginInfo); - return child->nextSibling(); + return true; } - - return 0; + return false; } -RenderObject* RenderBlock::handleFloatingChild(RenderObject* child, const MarginInfo& marginInfo, bool& handled) +bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo) { if (child->isFloating()) { - handled = true; insertFloatingObject(child); adjustFloatingBlock(marginInfo); - return child->nextSibling(); - } - - return 0; -} - -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(); - if (margin >= (childMargins + child->maxPrefWidth())) { - // 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; -} - -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(); + return true; } + return false; } -RenderObject* RenderBlock::handleRunInChild(RenderObject* child, bool& handled) +bool RenderBlock::handleRunInChild(RenderBox* child) { // 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; + if (!child->isRunIn() || !child->childrenInline() && !child->isReplaced()) + return false; + + RenderBlock* blockRunIn = toRenderBlock(child); + // Get the next non-positioned/non-floating RenderBlock. + RenderObject* curr = blockRunIn->nextSibling(); + while (curr && curr->isFloatingOrPositioned()) + curr = curr->nextSibling(); + + if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn()) + return false; + + RenderBlock* currBlock = toRenderBlock(curr); + + // Remove the old child. + children()->removeChildNode(this, blockRunIn); + + // Create an inline. + Node* runInNode = blockRunIn->node(); + RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document()); + inlineRunIn->setStyle(blockRunIn->style()); + + bool runInIsGenerated = child->style()->styleType() == BEFORE || child->style()->styleType() == AFTER; + + // Move the nodes from the old child to the new child, but skip any :before/:after content. It has already + // been regenerated by the new inline. + for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild; runInChild = runInChild->nextSibling()) { + if (runInIsGenerated || runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER) { + blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false); + inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content. } } - return 0; + + // Now insert the new child under |currBlock|. + currBlock->children()->insertChildNode(currBlock, inlineRunIn, currBlock->firstChild()); + + // If the run-in had an element, we need to set the new renderer. + if (runInNode) + runInNode->setRenderer(inlineRunIn); + + // Destroy the block run-in. + blockRunIn->destroy(); + + // The block acts like an inline, so just null out its + // position. + + return true; } -void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, int yPosEstimate) +int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) { // Get our max pos and neg top margins. int posTop = child->maxTopMargin(true); @@ -975,7 +1046,7 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i // 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; + setTopMarginQuirk(false); marginInfo.setDeterminedTopQuirk(true); } @@ -985,13 +1056,13 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i // This deals with the <td><div><p> case. // Don't do this for a block that split two inlines though. You do // still apply margins in this case. - m_topMarginQuirk = true; + setTopMarginQuirk(true); } if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop)) marginInfo.setTopQuirk(topQuirk); - int ypos = m_height; + int ypos = height(); if (child->isSelfCollapsingBlock()) { // This child has no height. We need to compute our // position before we collapse the child's margins together, @@ -1010,20 +1081,20 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i // is correct, since it could have overflowing content // that needs to be positioned correctly (e.g., a block that // had a specified height of 0 but that actually had subcontent). - ypos = m_height + collapsedTopPos - collapsedTopNeg; + ypos = height() + collapsedTopPos - collapsedTopNeg; } else { if (child->style()->marginTopCollapse() == MSEPARATE) { - m_height += marginInfo.margin() + child->marginTop(); - ypos = m_height; + setHeight(height() + marginInfo.margin() + child->marginTop()); + ypos = height(); } else if (!marginInfo.atTopOfBlock() || (!marginInfo.canCollapseTopWithChildren() && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) { // We're collapsing with a previous sibling's margins and not // with the top of the block. - m_height += max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop); - ypos = m_height; + setHeight(height() + max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop)); + ypos = height(); } marginInfo.setPosMargin(child->maxBottomMargin(true)); @@ -1034,34 +1105,15 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i marginInfo.setSelfCollapsingBlockClearedFloat(false); } - - view()->addLayoutDelta(IntSize(0, yPosEstimate - ypos)); - child->setPos(child->xPos(), ypos); - if (ypos != yPosEstimate) { - if (child->shrinkToAvoidFloats()) - // The child's width depends on the line width. - // When the child shifts to clear an item, its width can - // change (because it has more available line width). - // So go ahead and mark the item as dirty. - child->setChildNeedsLayout(true, false); - - if (!child->avoidsFloats() && child->containsFloats()) - child->markAllDescendantsWithFloatsForLayout(); - - // Our guess was wrong. Make the child lay itself out again. - child->layoutIfNeeded(); - } + + return ypos; } -void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin) +int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos) { - int heightIncrease = getClearDelta(child); + int heightIncrease = getClearDelta(child, yPos); if (!heightIncrease) - return; - - // The child needs to be lowered. Move the child so that it just clears the float. - view()->addLayoutDelta(IntSize(0, -heightIncrease)); - child->setPos(child->xPos(), child->yPos() + heightIncrease); + return yPos; if (child->isSelfCollapsingBlock()) { // For self-collapsing blocks that clear, they can still collapse their @@ -1071,7 +1123,7 @@ void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInf marginInfo.setNegMargin(max(child->maxTopMargin(false), child->maxBottomMargin(false))); // Adjust our height such that we are ready to be collapsed with subsequent siblings. - m_height = child->yPos() - max(0, marginInfo.margin()); + setHeight(child->y() - max(0, marginInfo.margin())); // Set a flag that we cleared a float so that we know both to increase the height of the block // to compensate for the clear and to avoid collapsing our margins with the parent block's @@ -1079,7 +1131,7 @@ void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInf marginInfo.setSelfCollapsingBlockClearedFloat(true); } else // Increase our height by the amount we had to clear. - m_height += heightIncrease; + setHeight(height() + heightIncrease); if (marginInfo.canCollapseWithTop()) { // We can no longer collapse with the top of the block since a clear @@ -1090,34 +1142,24 @@ void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInf setMaxTopMargins(oldTopPosMargin, oldTopNegMargin); marginInfo.setAtTopOfBlock(false); } - - // If our value of clear caused us to be repositioned vertically to be - // underneath a float, we might have to do another layout to take into account - // the extra space we now have available. - if (child->shrinkToAvoidFloats()) - // The child's width depends on the line width. - // When the child shifts to clear an item, its width can - // change (because it has more available line width). - // So go ahead and mark the item as dirty. - child->setChildNeedsLayout(true, false); - if (!child->avoidsFloats() && child->containsFloats()) - child->markAllDescendantsWithFloatsForLayout(); - child->layoutIfNeeded(); + + return yPos + heightIncrease; } -int RenderBlock::estimateVerticalPosition(RenderObject* child, const MarginInfo& marginInfo) +int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& marginInfo) { // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological // relayout if there are intruding floats. - int yPosEstimate = m_height; + int yPosEstimate = height(); if (!marginInfo.canCollapseWithTop()) { int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop(); yPosEstimate += max(marginInfo.margin(), childMarginTop); } + yPosEstimate += getClearDelta(child, yPosEstimate); return yPosEstimate; } -void RenderBlock::determineHorizontalPosition(RenderObject* child) +void RenderBlock::determineHorizontalPosition(RenderBox* child) { if (style()->direction() == LTR) { int xPos = borderLeft() + paddingLeft(); @@ -1128,7 +1170,7 @@ void RenderBlock::determineHorizontalPosition(RenderObject* child) // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need // to shift over as necessary to dodge any floats that might get in the way. if (child->avoidsFloats()) { - int leftOff = leftOffset(m_height); + int leftOff = leftOffset(height(), false); if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) { if (child->marginLeft() < 0) leftOff += child->marginLeft(); @@ -1140,17 +1182,17 @@ void RenderBlock::determineHorizontalPosition(RenderObject* child) // width computation will take into account the delta between |leftOff| and |xPos| // so that we can just pass the content width in directly to the |calcHorizontalMargins| // function. - static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos())); + child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false)); chPos = leftOff + child->marginLeft(); } } - view()->addLayoutDelta(IntSize(child->xPos() - chPos, 0)); - child->setPos(chPos, child->yPos()); + view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); + child->setLocation(chPos, child->y()); } else { - int xPos = m_width - borderRight() - paddingRight() - verticalScrollbarWidth(); + int xPos = width() - borderRight() - paddingRight() - verticalScrollbarWidth(); int chPos = xPos - (child->width() + child->marginRight()); if (child->avoidsFloats()) { - int rightOff = rightOffset(m_height); + int rightOff = rightOffset(height(), false); if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) { if (child->marginRight() < 0) rightOff -= child->marginRight(); @@ -1161,12 +1203,12 @@ void RenderBlock::determineHorizontalPosition(RenderObject* child) // width computation will take into account the delta between |rightOff| and |xPos| // so that we can just pass the content width in directly to the |calcHorizontalMargins| // function. - static_cast<RenderBox*>(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->yPos())); + child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false)); chPos = rightOff - child->marginRight() - child->width(); } } - view()->addLayoutDelta(IntSize(child->xPos() - chPos, 0)); - child->setPos(chPos, child->yPos()); + view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); + child->setLocation(chPos, child->y()); } } @@ -1178,13 +1220,13 @@ void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo) setMaxBottomMargins(max(maxBottomPosMargin(), marginInfo.posMargin()), max(maxBottomNegMargin(), marginInfo.negMargin())); if (!marginInfo.bottomQuirk()) - m_bottomMarginQuirk = false; + setBottomMarginQuirk(false); if (marginInfo.bottomQuirk() && marginBottom() == 0) // We have no bottom margin and our last child has a quirky margin. // We will pick up this quirky margin and pass it through. // This deals with the <td><div><p> case. - m_bottomMarginQuirk = true; + setBottomMarginQuirk(true); } } @@ -1205,17 +1247,17 @@ void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInf // If we can't collapse with children then go ahead and add in the bottom margin. if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop() && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk())) - m_height += marginInfo.margin(); + setHeight(height() + marginInfo.margin()); // Now add in our bottom border/padding. - m_height += bottom; + setHeight(height() + bottom); // Negative margins can cause our height to shrink below our minimal height (border/padding). // If this happens, ensure that the computed height is increased to the minimal height. - m_height = max(m_height, top + bottom); + setHeight(max(height(), top + bottom)); // Always make sure our overflow height is at least our height. - m_overflowHeight = max(m_height, m_overflowHeight); + m_overflowHeight = max(height(), m_overflowHeight); // Update our bottom collapsed margin info. setCollapsedBottomMargin(marginInfo); @@ -1244,11 +1286,11 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom int top = borderTop() + paddingTop(); int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); - m_height = m_overflowHeight = top; + m_overflowHeight = top; + setHeight(m_overflowHeight); // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, MarginInfo marginInfo(this, top, bottom); - CompactInfo compactInfo; // Fieldsets need to find their legend and position it inside the border of the object. // The legend then gets skipped during normal layout. @@ -1257,12 +1299,14 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom int previousFloatBottom = 0; maxFloatBottom = 0; - RenderObject* child = firstChild(); - while (child) { - if (legend == child) { - child = child->nextSibling(); + RenderBox* next = firstChildBox(); + + while (next) { + RenderBox* child = next; + next = child->nextSiblingBox(); + + if (legend == child) continue; // Skip the legend, since it has already been positioned up in the fieldset's border. - } int oldTopPosMargin = maxTopPosMargin(); int oldTopNegMargin = maxTopNegMargin(); @@ -1279,12 +1323,8 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom // Handle the four types of special elements first. These include positioned content, floating content, compacts and // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks. - bool handled = false; - RenderObject* next = handleSpecialChild(child, marginInfo, compactInfo, handled); - if (handled) { - child = next; + if (handleSpecialChild(child, marginInfo)) continue; - } // The child is a normal flow object. Compute its vertical margins now. child->calcVerticalMargins(); @@ -1301,28 +1341,31 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom int yPosEstimate = estimateVerticalPosition(child, marginInfo); // Cache our old rect so that we can dirty the proper repaint rects if the child moves. - IntRect oldRect(child->xPos(), child->yPos() , child->width(), child->height()); - + IntRect oldRect(child->x(), child->y() , child->width(), child->height()); +#ifndef NDEBUG + IntSize oldLayoutDelta = view()->layoutDelta(); +#endif // Go ahead and position the child as though it didn't collapse with the top. - view()->addLayoutDelta(IntSize(0, child->yPos() - yPosEstimate)); - child->setPos(child->xPos(), yPosEstimate); + view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate)); + child->setLocation(child->x(), yPosEstimate); bool markDescendantsWithFloats = false; - if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->containsFloats()) + if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) markDescendantsWithFloats = true; else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) { // If an element might be affected by the presence of floats, then always mark it for // layout. int fb = max(previousFloatBottom, floatBottom()); - if (fb > m_height || fb > yPosEstimate) + if (fb > yPosEstimate) markDescendantsWithFloats = true; } - if (markDescendantsWithFloats) - child->markAllDescendantsWithFloatsForLayout(); + if (child->isRenderBlock()) { + if (markDescendantsWithFloats) + toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); - if (child->isRenderBlock()) - previousFloatBottom = max(previousFloatBottom, oldRect.y() + static_cast<RenderBlock*>(child)->floatBottom()); + previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom()); + } bool childHadLayout = child->m_everHadLayout; bool childNeededLayout = child->needsLayout(); @@ -1331,10 +1374,28 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom // Now determine the correct ypos based off examination of collapsing margin // values. - collapseMargins(child, marginInfo, yPosEstimate); + int yBeforeClear = collapseMargins(child, marginInfo); // Now check for clear. - clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin); + int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear); + + view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear)); + child->setLocation(child->x(), yAfterClear); + + // Now we have a final y position. See if it really does end up being different from our estimate. + if (yAfterClear != yPosEstimate) { + if (child->shrinkToAvoidFloats()) { + // The child's width depends on the line width. + // When the child shifts to clear an item, its width can + // change (because it has more available line width). + // So go ahead and mark the item as dirty. + child->setChildNeedsLayout(true, false); + } + if (!child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) + toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); + // Our guess was wrong. Make the child lay itself out again. + child->layoutIfNeeded(); + } // We are no longer at the top of the block if we encounter a non-empty child. // This has to be done after checking for clear, so that margins can be reset if a clear occurred. @@ -1345,25 +1406,26 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom determineHorizontalPosition(child); // Update our height now that the child has been placed in the correct position. - m_height += child->height(); + setHeight(height() + child->height()); if (child->style()->marginBottomCollapse() == MSEPARATE) { - m_height += child->marginBottom(); + setHeight(height() + child->marginBottom()); marginInfo.clearMargin(); } // If the child has overhanging floats that intrude into following siblings (or possibly out // of this block), then the parent gets notified of the floats now. - maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(static_cast<RenderBlock *>(child), -child->xPos(), -child->yPos(), !childNeededLayout)); - - // Update our overflow in case the child spills out the block. - m_overflowTop = min(m_overflowTop, child->yPos() + child->overflowTop(false)); - m_overflowHeight = max(m_overflowHeight, m_height + child->overflowHeight(false) - child->height()); - m_overflowWidth = max(child->xPos() + child->overflowWidth(false), m_overflowWidth); - m_overflowLeft = min(child->xPos() + child->overflowLeft(false), m_overflowLeft); - - // Insert our compact into the block margin if we have one. - insertCompactIfNeeded(child, compactInfo); + if (child->isBlockFlow() && toRenderBlock(child)->containsFloats()) + maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout)); + + // Update our visual overflow in case the child spills out the block, but only if we were going to paint + // the child block ourselves. + if (!child->hasSelfPaintingLayer()) { + m_overflowTop = min(m_overflowTop, child->y() + child->overflowTop(false)); + m_overflowHeight = max(m_overflowHeight, height() + child->overflowHeight(false) - child->height()); + m_overflowWidth = max(child->x() + child->overflowWidth(false), m_overflowWidth); + m_overflowLeft = min(child->x() + child->overflowLeft(false), m_overflowLeft); + } - IntSize childOffset(child->xPos() - oldRect.x(), child->yPos() - oldRect.y()); + IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y()); if (childOffset.width() || childOffset.height()) { view()->addLayoutDelta(childOffset); @@ -1377,7 +1439,7 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom if (!childHadLayout && child->checkForRepaintDuringLayout()) child->repaint(); - child = child->nextSibling(); + ASSERT(oldLayoutDelta == view()->layoutDelta()); } // Now do the handling of the bottom of the block, adding in our bottom border/padding and @@ -1390,7 +1452,7 @@ bool RenderBlock::layoutOnlyPositionedObjects() if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout()) return false; - LayoutStateMaintainer statePusher(view(), this, IntSize(xPos(), yPos()), !m_hasColumns); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection()); if (needsPositionedMovementLayout()) { tryLayoutDoingPositionedMovementOnly(); @@ -1404,7 +1466,7 @@ bool RenderBlock::layoutOnlyPositionedObjects() statePusher.pop(); if (hasOverflowClip()) - m_layer->updateScrollInfoAfterLayout(); + layer()->updateScrollInfoAfterLayout(); setNeedsLayout(false); return true; @@ -1413,7 +1475,7 @@ bool RenderBlock::layoutOnlyPositionedObjects() void RenderBlock::layoutPositionedObjects(bool relayoutChildren) { if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -1421,11 +1483,11 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren) // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is // positioned explicitly) this should not incur a performance penalty. - if (relayoutChildren || (r->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow())) + if (relayoutChildren || (r->style()->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow())) r->setChildNeedsLayout(true, false); // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. - if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent())) + //if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent())) r->setPrefWidthsDirty(true, false); // We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width @@ -1440,7 +1502,7 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren) void RenderBlock::markPositionedObjectsForLayout() { if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -1469,7 +1531,7 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) // Only repaint the object if it is overhanging, is not in its own layer, and // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter // condition is replaced with being a descendant of us. - if (r->m_bottom > m_height && (paintAllDescendants && r->m_renderer->isDescendantOf(this) || r->m_shouldPaint) && !r->m_renderer->hasLayer()) { + if (r->m_bottom > height() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) { r->m_renderer->repaint(); r->m_renderer->repaintOverhangingFloats(); } @@ -1477,18 +1539,18 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) view()->enableLayoutState(); } } - + void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty) { - tx += m_x; - ty += m_y; + tx += x(); + ty += y(); PaintPhase phase = paintInfo.phase; // Check if we need to do anything at all. // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView // paints the root's background. - if (!isInlineFlow() && !isRoot()) { + if (!isRoot()) { IntRect overflowBox = overflowRect(false); overflowBox.inflate(maximalOutlineSize(paintInfo.phase)); overflowBox.move(tx, ty); @@ -1496,52 +1558,69 @@ void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty) return; } - bool useControlClip = phase != PaintPhaseBlockBackground && phase != PaintPhaseSelfOutline && phase != PaintPhaseMask && hasControlClip(); + bool pushedClip = pushContentsClip(paintInfo, tx, ty); + paintObject(paintInfo, tx, ty); + if (pushedClip) + popContentsClip(paintInfo, phase, tx, ty); - // Push a clip. - if (useControlClip) { - if (phase == PaintPhaseOutline) - paintInfo.phase = PaintPhaseChildOutlines; - else if (phase == PaintPhaseChildBlockBackground) { - paintInfo.phase = PaintPhaseBlockBackground; - paintObject(paintInfo, tx, ty); - paintInfo.phase = PaintPhaseChildBlockBackgrounds; - } - IntRect clipRect(controlClipRect(tx, ty)); - if (clipRect.isEmpty()) - return; - paintInfo.context->save(); - paintInfo.context->clip(clipRect); - } + // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with + // z-index. We paint after we painted the background/border, so that the scrollbars will + // sit above the background/border. + if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground)) + layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect); +} - paintObject(paintInfo, tx, ty); - - // Pop the clip. - if (useControlClip) { - paintInfo.context->restore(); - if (phase == PaintPhaseOutline) { - paintInfo.phase = PaintPhaseSelfOutline; - paintObject(paintInfo, tx, ty); - paintInfo.phase = phase; - } else if (phase == PaintPhaseChildBlockBackground) - paintInfo.phase = phase; +void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty) +{ + const Color& ruleColor = style()->columnRuleColor(); + bool ruleTransparent = style()->columnRuleIsTransparent(); + EBorderStyle ruleStyle = style()->columnRuleStyle(); + int ruleWidth = style()->columnRuleWidth(); + int colGap = columnGap(); + bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap; + if (!renderRule) + return; + + // We need to do multiple passes, breaking up our child painting into strips. + int currXOffset = 0; + int ruleAdd = borderLeft() + paddingLeft(); + int ruleX = 0; + Vector<IntRect>* colRects = columnRects(); + unsigned colCount = colRects->size(); + for (unsigned i = 0; i < colCount; i++) { + // For each rect, we clip to the rect, and then we adjust our coords. + IntRect colRect = colRects->at(i); + + // Move to the next position. + if (style()->direction() == LTR) { + ruleX += colRect.width() + colGap / 2; + currXOffset += colRect.width() + colGap; + } else { + ruleX -= (colRect.width() + colGap / 2); + currXOffset -= (colRect.width() + colGap); + } + + // Now paint the column rule. + if (i < colCount - 1) { + int ruleStart = tx + ruleX - ruleWidth / 2 + ruleAdd; + int ruleEnd = ruleStart + ruleWidth; + int ruleTop = ty + borderTop() + paddingTop(); + int ruleBottom = ruleTop + contentHeight(); + drawLineForBoxSide(paintInfo.context, ruleStart, ruleTop, ruleEnd, ruleBottom, + style()->direction() == LTR ? BSLeft : BSRight, ruleColor, style()->color(), ruleStyle, 0, 0); + } + + ruleX = currXOffset; } } -void RenderBlock::paintColumns(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats) +void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats) { // We need to do multiple passes, breaking up our child painting into strips. GraphicsContext* context = paintInfo.context; int currXOffset = 0; int currYOffset = 0; - int ruleAdd = borderLeft() + paddingLeft(); - int ruleX = 0; int colGap = columnGap(); - const Color& ruleColor = style()->columnRuleColor(); - bool ruleTransparent = style()->columnRuleIsTransparent(); - EBorderStyle ruleStyle = style()->columnRuleStyle(); - int ruleWidth = style()->columnRuleWidth(); - bool renderRule = !paintingFloats && ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap; Vector<IntRect>* colRects = columnRects(); unsigned colCount = colRects->size(); for (unsigned i = 0; i < colCount; i++) { @@ -1567,27 +1646,14 @@ void RenderBlock::paintColumns(PaintInfo& paintInfo, int tx, int ty, bool painti paintContents(info, finalX, finalY); // Move to the next position. - if (style()->direction() == LTR) { - ruleX += colRect.width() + colGap / 2; + if (style()->direction() == LTR) currXOffset += colRect.width() + colGap; - } else { - ruleX -= (colRect.width() + colGap / 2); + else currXOffset -= (colRect.width() + colGap); - } - + currYOffset -= colRect.height(); context->restore(); - - // Now paint the column rule. - if (renderRule && paintInfo.phase == PaintPhaseForeground && i < colCount - 1) { - int ruleStart = ruleX - ruleWidth / 2 + ruleAdd; - int ruleEnd = ruleStart + ruleWidth; - drawBorder(paintInfo.context, tx + ruleStart, ty + borderTop() + paddingTop(), tx + ruleEnd, ty + borderTop() + paddingTop() + contentHeight(), - style()->direction() == LTR ? BSLeft : BSRight, ruleColor, style()->color(), ruleStyle, 0, 0); - } - - ruleX = currXOffset; } } @@ -1600,7 +1666,7 @@ void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty) return; if (childrenInline()) - paintLines(paintInfo, tx, ty); + m_lineBoxes.paint(this, paintInfo, tx, ty); else paintChildren(paintInfo, tx, ty); } @@ -1616,23 +1682,23 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) info.paintingRoot = paintingRootForChildren(paintInfo); bool isPrinting = document()->printing(); - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { + for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { // Check for page-break-before: always, and if it's set, break and bail. if (isPrinting && !childrenInline() && child->style()->pageBreakBefore() == PBALWAYS && - inRootBlockContext() && (ty + child->yPos()) > paintInfo.rect.y() && - (ty + child->yPos()) < paintInfo.rect.bottom()) { - view()->setBestTruncatedAt(ty + child->yPos(), this, true); + inRootBlockContext() && (ty + child->y()) > paintInfo.rect.y() && + (ty + child->y()) < paintInfo.rect.bottom()) { + view()->setBestTruncatedAt(ty + child->y(), this, true); return; } - if (!child->hasLayer() && !child->isFloating()) + if (!child->hasSelfPaintingLayer() && !child->isFloating()) child->paint(info, tx, ty); // Check for page-break-after: always, and if it's set, break and bail. if (isPrinting && !childrenInline() && child->style()->pageBreakAfter() == PBALWAYS && - inRootBlockContext() && (ty + child->yPos() + child->height()) > paintInfo.rect.y() && - (ty + child->yPos() + child->height()) < paintInfo.rect.bottom()) { - view()->setBestTruncatedAt(ty + child->yPos() + child->height() + max(0, child->collapsedMarginBottom()), this, true); + inRootBlockContext() && (ty + child->y() + child->height()) > paintInfo.rect.y() && + (ty + child->y() + child->height()) < paintInfo.rect.bottom()) { + view()->setBestTruncatedAt(ty + child->y() + child->height() + max(0, child->collapsedMarginBottom()), this, true); return; } } @@ -1642,9 +1708,10 @@ void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType typ { SelectionController* selection = type == CursorCaret ? document()->frame()->selection() : document()->frame()->dragCaretController(); - // Ask the SelectionController if the caret should be painted by this block + // Paint the caret if the SelectionController says so or if caret browsing is enabled + bool caretBrowsing = document()->frame()->settings() && document()->frame()->settings()->caretBrowsingEnabled(); RenderObject* caretPainter = selection->caretRenderer(); - if (caretPainter == this && selection->isContentEditable()) { + if (caretPainter == this && (selection->isContentEditable() || caretBrowsing)) { // Convert the painting offset into the local coordinate system of this renderer, // to match the localCaretRect computed by the SelectionController offsetForContents(tx, ty); @@ -1660,14 +1727,12 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) { PaintPhase paintPhase = paintInfo.phase; - // If we're a repositioned run-in or a compact, don't paint background/borders. - bool inlineFlow = isInlineFlow(); - // 1. paint background, borders etc - if (!inlineFlow && - (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && - hasBoxDecorations() && style()->visibility() == VISIBLE) { - paintBoxDecorations(paintInfo, tx, ty); + if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) { + if (hasBoxDecorations()) + paintBoxDecorations(paintInfo, tx, ty); + if (hasColumns()) + paintColumnRules(paintInfo, tx, ty); } if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) { @@ -1683,12 +1748,12 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) int scrolledX = tx; int scrolledY = ty; if (hasOverflowClip()) - m_layer->subtractScrolledContentOffset(scrolledX, scrolledY); + layer()->subtractScrolledContentOffset(scrolledX, scrolledY); // 2. paint contents if (paintPhase != PaintPhaseSelfOutline) { - if (m_hasColumns) - paintColumns(paintInfo, scrolledX, scrolledY); + if (hasColumns()) + paintColumnContents(paintInfo, scrolledX, scrolledY); else paintContents(paintInfo, scrolledX, scrolledY); } @@ -1696,30 +1761,30 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) // 3. paint selection // FIXME: Make this work with multi column layouts. For now don't fill gaps. bool isPrinting = document()->printing(); - if (!inlineFlow && !isPrinting && !m_hasColumns) + if (!isPrinting && !hasColumns()) paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks. // 4. paint floats. - if (!inlineFlow && (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip)) { - if (m_hasColumns) - paintColumns(paintInfo, scrolledX, scrolledY, true); + if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) { + if (hasColumns()) + paintColumnContents(paintInfo, scrolledX, scrolledY, true); else paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip); } // 5. paint outline. - if (!inlineFlow && (paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) - RenderObject::paintOutline(paintInfo.context, tx, ty, width(), height(), style()); + if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) + paintOutline(paintInfo.context, tx, ty, width(), height(), style()); // 6. paint continuation outlines. - if (!inlineFlow && (paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { - if (continuation() && continuation()->hasOutline() && continuation()->style()->visibility() == VISIBLE) { - RenderFlow* inlineFlow = static_cast<RenderFlow*>(continuation()->element()->renderer()); - if (!inlineFlow->hasLayer()) - containingBlock()->addContinuationWithOutline(inlineFlow); - else if (!inlineFlow->firstLineBox()) - inlineFlow->paintOutline(paintInfo.context, tx - xPos() + inlineFlow->containingBlock()->xPos(), - ty - yPos() + inlineFlow->containingBlock()->yPos()); + if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { + if (inlineContinuation() && inlineContinuation()->hasOutline() && inlineContinuation()->style()->visibility() == VISIBLE) { + RenderInline* inlineRenderer = toRenderInline(inlineContinuation()->node()->renderer()); + if (!inlineRenderer->hasSelfPaintingLayer()) + containingBlock()->addContinuationWithOutline(inlineRenderer); + else if (!inlineRenderer->firstLineBox()) + inlineRenderer->paintOutline(paintInfo.context, tx - x() + inlineRenderer->containingBlock()->x(), + ty - y() + inlineRenderer->containingBlock()->y()); } paintContinuationOutlines(paintInfo, tx, ty); } @@ -1727,7 +1792,7 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) // 7. paint caret. // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground, // then paint the caret. - if (!inlineFlow && paintPhase == PaintPhaseForeground) { + if (paintPhase == PaintPhaseForeground) { paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret); paintCaret(paintInfo, scrolledX, scrolledY, DragCaret); } @@ -1742,11 +1807,11 @@ void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preserv DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for (; (r = it.current()); ++it) { // Only paint the object if our m_shouldPaint flag is set. - if (r->m_shouldPaint && !r->m_renderer->hasLayer()) { + if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { PaintInfo currentPaintInfo(paintInfo); currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; - int currentTX = tx + r->m_left - r->m_renderer->xPos() + r->m_renderer->marginLeft(); - int currentTY = ty + r->m_top - r->m_renderer->yPos() + r->m_renderer->marginTop(); + int currentTX = tx + r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); + int currentTY = ty + r->m_top - r->m_renderer->y() + r->m_renderer->marginTop(); r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); if (!preservePhase) { currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds; @@ -1770,8 +1835,8 @@ void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) { // We can check the first box and last box and avoid painting if we don't // intersect. - int yPos = ty + firstLineBox()->yPos(); - int h = lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos(); + int yPos = ty + firstLineBox()->y(); + int h = lastLineBox()->y() + lastLineBox()->height() - firstLineBox()->y(); if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y()) return; @@ -1779,7 +1844,7 @@ void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) // them. Note that boxes can easily overlap, so we can't make any assumptions // based off positions of our first line box or our last line box. for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { - yPos = ty + curr->yPos(); + yPos = ty + curr->y(); h = curr->height(); if (curr->ellipsisBox() && yPos < paintInfo.rect.bottom() && yPos + h > paintInfo.rect.y()) curr->paintEllipsisBox(paintInfo, tx, ty); @@ -1787,22 +1852,22 @@ void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) } } -ContinuationOutlineTableMap* continuationOutlineTable() +static ContinuationOutlineTableMap* continuationOutlineTable() { DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ()); return &table; } -void RenderBlock::addContinuationWithOutline(RenderFlow* flow) +void RenderBlock::addContinuationWithOutline(RenderInline* flow) { // We can't make this work if the inline is in a layer. We'll just rely on the broken // way of painting. - ASSERT(!flow->layer()); + ASSERT(!flow->layer() && !flow->isInlineContinuation()); ContinuationOutlineTableMap* table = continuationOutlineTable(); - RenderFlowSequencedSet* continuations = table->get(this); + ListHashSet<RenderInline*>* continuations = table->get(this); if (!continuations) { - continuations = new RenderFlowSequencedSet; + continuations = new ListHashSet<RenderInline*>; table->set(this, continuations); } @@ -1815,19 +1880,19 @@ void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty) if (table->isEmpty()) return; - RenderFlowSequencedSet* continuations = table->get(this); + ListHashSet<RenderInline*>* continuations = table->get(this); if (!continuations) return; // Paint each continuation outline. - RenderFlowSequencedSet::iterator end = continuations->end(); - for (RenderFlowSequencedSet::iterator it = continuations->begin(); it != end; ++it) { + ListHashSet<RenderInline*>::iterator end = continuations->end(); + for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) { // Need to add in the coordinates of the intervening blocks. - RenderFlow* flow = *it; + RenderInline* flow = *it; RenderBlock* block = flow->containingBlock(); for ( ; block && block != this; block = block->containingBlock()) { - tx += block->xPos(); - ty += block->yPos(); + tx += block->x(); + ty += block->y(); } ASSERT(block); flow->paintOutline(info.context, tx, ty); @@ -1848,9 +1913,9 @@ void RenderBlock::setSelectionState(SelectionState s) if ((s == SelectionStart && selectionState() == SelectionEnd) || (s == SelectionEnd && selectionState() == SelectionStart)) - m_selectionState = SelectionBoth; + RenderBox::setSelectionState(SelectionBoth); else - m_selectionState = s; + RenderBox::setSelectionState(s); RenderBlock* cb = containingBlock(); if (cb && !cb->isRenderView()) @@ -1859,12 +1924,12 @@ void RenderBlock::setSelectionState(SelectionState s) bool RenderBlock::shouldPaintSelectionGaps() const { - return m_selectionState != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot(); + return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot(); } bool RenderBlock::isSelectionRoot() const { - if (!element()) + if (!node()) return false; // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases. @@ -1877,27 +1942,27 @@ bool RenderBlock::isSelectionRoot() const return true; if (view() && view()->selectionStart()) { - Node* startElement = view()->selectionStart()->element(); - if (startElement && startElement->rootEditableElement() == element()) + Node* startElement = view()->selectionStart()->node(); + if (startElement && startElement->rootEditableElement() == node()) return true; } return false; } -GapRects RenderBlock::selectionGapRects() +GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* /*repaintContainer*/) { ASSERT(!needsLayout()); if (!shouldPaintSelectionGaps()) return GapRects(); - // FIXME: this is broken with transforms - FloatPoint absContentPoint = localToAbsoluteForContent(FloatPoint()); + // FIXME: this is broken with transforms and a non-null repaintContainer + FloatPoint absContentPoint = localToAbsolute(FloatPoint()); if (hasOverflowClip()) absContentPoint -= layer()->scrolledContentOffset(); - int lastTop = -borderTopExtra(); + int lastTop = 0; int lastLeft = leftSelectionOffset(this, lastTop); int lastRight = rightSelectionOffset(this, lastTop); @@ -1907,7 +1972,7 @@ GapRects RenderBlock::selectionGapRects() void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) { if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) { - int lastTop = -borderTopExtra(); + int lastTop = 0; int lastLeft = leftSelectionOffset(this, lastTop); int lastRight = rightSelectionOffset(this, lastTop); paintInfo.context->save(); @@ -1916,21 +1981,24 @@ void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) } } -static void clipOutPositionedObjects(const RenderObject::PaintInfo* paintInfo, int tx, int ty, ListHashSet<RenderObject*>* positionedObjects) +#ifndef BUILDING_ON_TIGER +static void clipOutPositionedObjects(const RenderObject::PaintInfo* paintInfo, int tx, int ty, ListHashSet<RenderBox*>* positionedObjects) { if (!positionedObjects) return; - ListHashSet<RenderObject*>::const_iterator end = positionedObjects->end(); - for (ListHashSet<RenderObject*>::const_iterator it = positionedObjects->begin(); it != end; ++it) { - RenderObject* r = *it; - paintInfo->context->clipOut(IntRect(tx + r->xPos(), ty + r->yPos(), r->width(), r->height())); + ListHashSet<RenderBox*>::const_iterator end = positionedObjects->end(); + for (ListHashSet<RenderBox*>::const_iterator it = positionedObjects->begin(); it != end; ++it) { + RenderBox* r = *it; + paintInfo->context->clipOut(IntRect(tx + r->x(), ty + r->y(), r->width(), r->height())); } } +#endif GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo) { +#ifndef BUILDING_ON_TIGER // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore. // Clip out floating and positioned objects when painting selection gaps. if (paintInfo) { @@ -1938,7 +2006,7 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int clipOutPositionedObjects(paintInfo, tx, ty, m_positionedObjects); if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects. for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock()) - clipOutPositionedObjects(paintInfo, cb->xPos(), cb->yPos(), cb->m_positionedObjects); + clipOutPositionedObjects(paintInfo, cb->x(), cb->y(), cb->m_positionedObjects); if (m_floatingObjects) { for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) { FloatingObject* r = it.current(); @@ -1948,6 +2016,7 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int } } } +#endif // FIXME: overflow: auto/scroll regions need more math here, since painting in the border box is different from painting in the padding box (one is scrolled, the other is // fixed). @@ -1955,7 +2024,7 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday. return result; - if (m_hasColumns || hasTransform()) { + if (hasColumns() || hasTransform()) { // FIXME: We should learn how to gap fill multiple columns and transforms eventually. lastTop = (ty - blockY) + height(); lastLeft = leftSelectionOffset(rootBlock, height()); @@ -1969,8 +2038,8 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int result = fillBlockSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo); // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block. - if (rootBlock == this && (m_selectionState != SelectionBoth && m_selectionState != SelectionEnd)) - result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height() + borderBottomExtra(), + if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd)) + result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height(), rootBlock, blockX, blockY, paintInfo)); return result; } @@ -2007,14 +2076,14 @@ GapRects RenderBlock::fillInlineSelectionGaps(RenderBlock* rootBlock, int blockX result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + selTop, rootBlock, blockX, blockY, paintInfo)); - if (!paintInfo || ty + selTop < paintInfo->rect.bottom() && ty + selTop + selHeight > paintInfo->rect.y()) + if (!paintInfo || (ty + selTop < paintInfo->rect.bottom() && ty + selTop + selHeight > paintInfo->rect.y())) result.unite(curr->fillLineSelectionGap(selTop, selHeight, rootBlock, blockX, blockY, tx, ty, paintInfo)); lastSelectedLine = curr; } if (containsStart && !lastSelectedLine) - // Selection must start just after our last line. + // VisibleSelection must start just after our last line. lastSelectedLine = lastRootBox(); if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) { @@ -2032,10 +2101,10 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, GapRects result; // Go ahead and jump right to the first block child that contains some selected objects. - RenderObject* curr; - for (curr = firstChild(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSibling()) { } + RenderBox* curr; + for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { } - for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSibling()) { + for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) { SelectionState childState = curr->selectionState(); if (childState == SelectionBoth || childState == SelectionEnd) sawSelectionEnd = true; @@ -2058,7 +2127,7 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, if (childState == SelectionEnd || childState == SelectionInside) // Fill the gap above the object. result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, - ty + curr->yPos(), rootBlock, blockX, blockY, paintInfo)); + ty + curr->y(), rootBlock, blockX, blockY, paintInfo)); // Only fill side gaps for objects that paint their own selection if we know for sure the selection is going to extend all the way *past* // our object. We know this if the selection did not end inside our object. @@ -2070,19 +2139,19 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, getHorizontalSelectionGapInfo(childState, leftGap, rightGap); if (leftGap) - result.uniteLeft(fillLeftSelectionGap(this, curr->xPos(), curr->yPos(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); + result.uniteLeft(fillLeftSelectionGap(this, curr->x(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); if (rightGap) - result.uniteRight(fillRightSelectionGap(this, curr->xPos() + curr->width(), curr->yPos(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); + result.uniteRight(fillRightSelectionGap(this, curr->x() + curr->width(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); // Update lastTop to be just underneath the object. lastLeft and lastRight extend as far as // they can without bumping into floating or positioned objects. Ideally they will go right up // to the border of the root selection block. - lastTop = (ty - blockY) + (curr->yPos() + curr->height()); - lastLeft = leftSelectionOffset(rootBlock, curr->yPos() + curr->height()); - lastRight = rightSelectionOffset(rootBlock, curr->yPos() + curr->height()); + lastTop = (ty - blockY) + (curr->y() + curr->height()); + lastLeft = leftSelectionOffset(rootBlock, curr->y() + curr->height()); + lastRight = rightSelectionOffset(rootBlock, curr->y() + curr->height()); } else if (childState != SelectionNone) // We must be a block that has some selected object inside it. Go ahead and recur. - result.unite(static_cast<RenderBlock*>(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->xPos(), ty + curr->yPos(), + result.unite(toRenderBlock(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->x(), ty + curr->y(), lastTop, lastLeft, lastRight, paintInfo)); } return result; @@ -2162,19 +2231,19 @@ void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& left (state == RenderObject::SelectionEnd && !ltr); } -int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int y) +int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int yPos) { - int left = leftOffset(y); + int left = leftOffset(yPos, false); if (left == borderLeft() + paddingLeft()) { if (rootBlock != this) // The border can potentially be further extended by our containingBlock(). - return containingBlock()->leftSelectionOffset(rootBlock, y + yPos()); + return containingBlock()->leftSelectionOffset(rootBlock, yPos + y()); return left; } else { RenderBlock* cb = this; while (cb != rootBlock) { - left += cb->xPos(); + left += cb->x(); cb = cb->containingBlock(); } } @@ -2182,35 +2251,35 @@ int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int y) return left; } -int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int y) +int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int yPos) { - int right = rightOffset(y); + int right = rightOffset(yPos, false); if (right == (contentWidth() + (borderLeft() + paddingLeft()))) { if (rootBlock != this) // The border can potentially be further extended by our containingBlock(). - return containingBlock()->rightSelectionOffset(rootBlock, y + yPos()); + return containingBlock()->rightSelectionOffset(rootBlock, yPos + y()); return right; } else { RenderBlock* cb = this; while (cb != rootBlock) { - right += cb->xPos(); + right += cb->x(); cb = cb->containingBlock(); } } return right; } -void RenderBlock::insertPositionedObject(RenderObject *o) +void RenderBlock::insertPositionedObject(RenderBox* o) { // Create the list of special objects if we don't aleady have one if (!m_positionedObjects) - m_positionedObjects = new ListHashSet<RenderObject*>; + m_positionedObjects = new ListHashSet<RenderBox*>; m_positionedObjects->add(o); } -void RenderBlock::removePositionedObject(RenderObject *o) +void RenderBlock::removePositionedObject(RenderBox* o) { if (m_positionedObjects) m_positionedObjects->remove(o); @@ -2221,11 +2290,11 @@ void RenderBlock::removePositionedObjects(RenderBlock* o) if (!m_positionedObjects) return; - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); - Vector<RenderObject*, 16> deadObjects; + Vector<RenderBox*, 16> deadObjects; for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -2249,7 +2318,7 @@ void RenderBlock::removePositionedObjects(RenderBlock* o) m_positionedObjects->remove(deadObjects.at(i)); } -void RenderBlock::insertFloatingObject(RenderObject *o) +void RenderBlock::insertFloatingObject(RenderBox* o) { ASSERT(o->isFloating()); @@ -2276,14 +2345,14 @@ void RenderBlock::insertFloatingObject(RenderObject *o) newObj->m_top = -1; newObj->m_bottom = -1; newObj->m_width = o->width() + o->marginLeft() + o->marginRight(); - newObj->m_shouldPaint = !o->hasLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will. + newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will. newObj->m_isDescendant = true; newObj->m_renderer = o; m_floatingObjects->append(newObj); } -void RenderBlock::removeFloatingObject(RenderObject *o) +void RenderBlock::removeFloatingObject(RenderBox* o) { if (m_floatingObjects) { DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); @@ -2318,7 +2387,7 @@ bool RenderBlock::positionNewFloats() lastFloat = m_floatingObjects->getPrev(); } - int y = m_height; + int y = height(); // The float cannot start above the y position of the last positioned float. if (lastFloat) @@ -2333,7 +2402,7 @@ bool RenderBlock::positionNewFloats() continue; } - RenderObject* o = f->m_renderer; + RenderBox* o = f->m_renderer; int _height = o->height() + o->marginTop() + o->marginBottom(); int ro = rightOffset(); // Constant part of right offset. @@ -2342,7 +2411,7 @@ bool RenderBlock::positionNewFloats() if (ro - lo < fwidth) fwidth = ro - lo; // Never look for more than what will be available. - IntRect oldRect(o->xPos(), o->yPos() , o->width(), o->height()); + IntRect oldRect(o->x(), o->y() , o->width(), o->height()); if (o->style()->clear() & CLEFT) y = max(leftBottom(), y); @@ -2359,7 +2428,7 @@ bool RenderBlock::positionNewFloats() } fx = max(0, fx); f->m_left = fx; - o->setPos(fx + o->marginLeft(), y + o->marginTop()); + o->setLocation(fx + o->marginLeft(), y + o->marginTop()); } else { int heightRemainingLeft = 1; int heightRemainingRight = 1; @@ -2369,7 +2438,7 @@ bool RenderBlock::positionNewFloats() fx = rightRelOffset(y, ro, false, &heightRemainingRight); } f->m_left = fx - f->m_width; - o->setPos(fx - o->marginRight() - o->width(), y + o->marginTop()); + o->setLocation(fx - o->marginRight() - o->width(), y + o->marginTop()); } f->m_top = y; @@ -2402,8 +2471,8 @@ void RenderBlock::newLine(EClear clear) default: break; } - if (m_height < newY) - m_height = newY; + if (height() < newY) + setHeight(newY); } void RenderBlock::addPercentHeightDescendant(RenderBox* descendant) @@ -2461,15 +2530,17 @@ void RenderBlock::removePercentHeightDescendant(RenderBox* descendant) delete containerSet; } -int -RenderBlock::leftOffset() const +HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const { - return borderLeft()+paddingLeft(); + return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0; } -int -RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, - int *heightRemaining ) const +int RenderBlock::leftOffset() const +{ + return borderLeft() + paddingLeft(); +} + +int RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const { int left = fixedOffset; if (m_floatingObjects) { @@ -2487,7 +2558,7 @@ RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, } } - if (applyTextIndent && m_firstLine && style()->direction() == LTR) { + if (applyTextIndent && style()->direction() == LTR) { int cw = 0; if (style()->textIndent().isPercent()) cw = containingBlock()->availableWidth(); @@ -2497,15 +2568,12 @@ RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, return left; } -int -RenderBlock::rightOffset() const +int RenderBlock::rightOffset() const { return borderLeft() + paddingLeft() + availableWidth(); } -int -RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, - int *heightRemaining ) const +int RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const { int right = fixedOffset; @@ -2524,7 +2592,7 @@ RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, } } - if (applyTextIndent && m_firstLine && style()->direction() == RTL) { + if (applyTextIndent && style()->direction() == RTL) { int cw = 0; if (style()->textIndent().isPercent()) cw = containingBlock()->availableWidth(); @@ -2535,9 +2603,9 @@ RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, } int -RenderBlock::lineWidth(int y) const +RenderBlock::lineWidth(int y, bool firstLine) const { - int result = rightOffset(y) - leftOffset(y); + int result = rightOffset(y, firstLine) - leftOffset(y, firstLine); return (result < 0) ? 0 : result; } @@ -2578,7 +2646,7 @@ IntRect RenderBlock::floatRect() const FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for (; (r = it.current()); ++it) { - if (r->m_shouldPaint && !r->m_renderer->hasLayer()) { + if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { IntRect childRect = r->m_renderer->overflowRect(false); childRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()); result.unite(childRect); @@ -2590,7 +2658,27 @@ IntRect RenderBlock::floatRect() const int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const { - int bottom = RenderFlow::lowestPosition(includeOverflowInterior, includeSelf); + if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) + return includeSelf && width() > 0 ? overflowHeight(false) : 0; + + int bottom = includeSelf && width() > 0 ? height() : 0; + if (!hasColumns()) { + // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. + // For now, we have to descend into all the children, since we may have a huge abs div inside + // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to + // the abs div. + // See the last test case in https://bugs.webkit.org/show_bug.cgi?id=9314 for why this is a problem. + // For inline children, we miss relative positioned boxes that might be buried inside <span>s. + for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { + if (!c->isFloatingOrPositioned() && c->isBox()) { + RenderBox* childBox = toRenderBox(c); + bottom = max(bottom, childBox->y() + childBox->lowestPosition(false)); + } + } + } + + if (includeSelf && isRelPositioned()) + bottom += relativePositionOffsetY(); if (!includeOverflowInterior && hasOverflowClip()) return bottom; @@ -2600,7 +2688,7 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) bottom = max(bottom, m_overflowHeight + relativeOffset); if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -2610,15 +2698,15 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) // FIXME: Should work for overflow sections too. // If a positioned object lies completely to the left of the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the lowest position. - if (!isRenderView() || r->xPos() + r->width() > 0 || r->xPos() + r->rightmostPosition(false) > 0) { - int lp = r->yPos() + r->lowestPosition(false); + if (!isRenderView() || r->x() + r->width() > 0 || r->x() + r->rightmostPosition(false) > 0) { + int lp = r->y() + r->lowestPosition(false); bottom = max(bottom, lp + relativeOffset); } } } } - if (m_hasColumns) { + if (hasColumns()) { Vector<IntRect>* colRects = columnRects(); for (unsigned i = 0; i < colRects->size(); i++) bottom = max(bottom, colRects->at(i).bottom() + relativeOffset); @@ -2629,17 +2717,30 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) { - if (r->m_shouldPaint || r->m_renderer->hasLayer()) { + if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { int lp = r->m_top + r->m_renderer->marginTop() + r->m_renderer->lowestPosition(false); bottom = max(bottom, lp + relativeOffset); } } } - - if (!includeSelf && lastLineBox()) { - int lp = lastLineBox()->yPos() + lastLineBox()->height(); - bottom = max(bottom, lp); + if (!includeSelf) { + bottom = max(bottom, borderTop() + paddingTop() + paddingBottom() + relativeOffset); + if (childrenInline()) { + if (lastLineBox()) { + int childBottomEdge = lastLineBox()->y() + lastLineBox()->height(); + bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset); + } + } else { + // Find the last normal flow child. + RenderBox* currBox = lastChildBox(); + while (currBox && currBox->isFloatingOrPositioned()) + currBox = currBox->previousSiblingBox(); + if (currBox) { + int childBottomEdge = currBox->y() + currBox->height() + currBox->collapsedMarginBottom(); + bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset); + } + } } return bottom; @@ -2647,7 +2748,27 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const { - int right = RenderFlow::rightmostPosition(includeOverflowInterior, includeSelf); + if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) + return includeSelf && height() > 0 ? overflowWidth(false) : 0; + + int right = includeSelf && height() > 0 ? width() : 0; + + if (!hasColumns()) { + // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. + // For now, we have to descend into all the children, since we may have a huge abs div inside + // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to + // the abs div. + for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { + if (!c->isFloatingOrPositioned() && c->isBox()) { + RenderBox* childBox = toRenderBox(c); + right = max(right, childBox->x() + childBox->rightmostPosition(false)); + } + } + } + + if (includeSelf && isRelPositioned()) + right += relativePositionOffsetX(); + if (!includeOverflowInterior && hasOverflowClip()) return right; @@ -2657,7 +2778,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel right = max(right, m_overflowWidth + relativeOffset); if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin() ; it != end; ++it) { r = *it; @@ -2667,15 +2788,15 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel // FIXME: Should work for overflow sections too. // If a positioned object lies completely above the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the rightmost position. - if (!isRenderView() || r->yPos() + r->height() > 0 || r->yPos() + r->lowestPosition(false) > 0) { - int rp = r->xPos() + r->rightmostPosition(false); + if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { + int rp = r->x() + r->rightmostPosition(false); right = max(right, rp + relativeOffset); } } } } - if (m_hasColumns) { + if (hasColumns()) { // This only matters for LTR if (style()->direction() == LTR) right = max(columnRects()->last().right() + relativeOffset, right); @@ -2686,21 +2807,33 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) { - if (r->m_shouldPaint || r->m_renderer->hasLayer()) { + if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { int rp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->rightmostPosition(false); right = max(right, rp + relativeOffset); } } } - if (!includeSelf && firstLineBox()) { - for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) { - int rp = currBox->xPos() + currBox->width(); - // If this node is a root editable element, then the rightmostPosition should account for a caret at the end. - // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to. - if (node()->isContentEditable() && node() == node()->rootEditableElement() && style()->direction() == LTR) - rp += 1; - right = max(right, rp); + if (!includeSelf) { + right = max(right, borderLeft() + paddingLeft() + paddingRight() + relativeOffset); + if (childrenInline()) { + for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) { + int childRightEdge = currBox->x() + currBox->width(); + + // If this node is a root editable element, then the rightmostPosition should account for a caret at the end. + // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to. + if (node() && node()->isContentEditable() && node() == node()->rootEditableElement() && style()->direction() == LTR && !paddingRight()) + childRightEdge += 1; + right = max(right, childRightEdge + paddingRight() + relativeOffset); + } + } else { + // Walk all normal flow children. + for (RenderBox* currBox = firstChildBox(); currBox; currBox = currBox->nextSiblingBox()) { + if (currBox->isFloatingOrPositioned()) + continue; + int childRightEdge = currBox->x() + currBox->width() + currBox->marginRight(); + right = max(right, childRightEdge + paddingRight() + relativeOffset); + } } } @@ -2709,7 +2842,26 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const { - int left = RenderFlow::leftmostPosition(includeOverflowInterior, includeSelf); + if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) + return includeSelf && height() > 0 ? overflowLeft(false) : width(); + + int left = includeSelf && height() > 0 ? 0 : width(); + if (!hasColumns()) { + // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. + // For now, we have to descend into all the children, since we may have a huge abs div inside + // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to + // the abs div. + for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { + if (!c->isFloatingOrPositioned() && c->isBox()) { + RenderBox* childBox = toRenderBox(c); + left = min(left, childBox->x() + childBox->leftmostPosition(false)); + } + } + } + + if (includeSelf && isRelPositioned()) + left += relativePositionOffsetX(); + if (!includeOverflowInterior && hasOverflowClip()) return left; @@ -2719,7 +2871,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf left = min(left, m_overflowLeft + relativeOffset); if (m_positionedObjects) { - RenderObject* r; + RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { r = *it; @@ -2729,15 +2881,15 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf // FIXME: Should work for overflow sections too. // If a positioned object lies completely above the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the leftmost position. - if (!isRenderView() || r->yPos() + r->height() > 0 || r->yPos() + r->lowestPosition(false) > 0) { - int lp = r->xPos() + r->leftmostPosition(false); + if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { + int lp = r->x() + r->leftmostPosition(false); left = min(left, lp + relativeOffset); } } } } - if (m_hasColumns) { + if (hasColumns()) { // This only matters for RTL if (style()->direction() == RTL) left = min(columnRects()->last().x() + relativeOffset, left); @@ -2748,7 +2900,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) { - if (r->m_shouldPaint || r->m_renderer->hasLayer()) { + if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { int lp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->leftmostPosition(false); left = min(left, lp + relativeOffset); } @@ -2757,7 +2909,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf if (!includeSelf && firstLineBox()) { for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) - left = min(left, (int)currBox->xPos()); + left = min(left, (int)currBox->x() + relativeOffset); } return left; @@ -2834,31 +2986,33 @@ void RenderBlock::clearFloats() // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted // to avoid floats. bool parentHasFloats = false; - RenderObject *prev = previousSibling(); - while (prev && (!prev->isRenderBlock() || prev->avoidsFloats() || prev->isFloatingOrPositioned())) { + RenderObject* prev = previousSibling(); + while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) { if (prev->isFloating()) parentHasFloats = true; prev = prev->previousSibling(); } // First add in floats from the parent. - int offset = m_y; - if (parentHasFloats) - addIntrudingFloats(static_cast<RenderBlock *>(parent()), - parent()->borderLeft() + parent()->paddingLeft(), offset); - + int offset = y(); + if (parentHasFloats) { + RenderBlock* parentBlock = toRenderBlock(parent()); + addIntrudingFloats(parentBlock, parentBlock->borderLeft() + parentBlock->paddingLeft(), offset); + } + int xoffset = 0; if (prev) - offset -= prev->yPos(); - else { + offset -= toRenderBox(prev)->y(); + else if (parent()->isBox()) { prev = parent(); - xoffset += prev->borderLeft() + prev->paddingLeft(); + xoffset += toRenderBox(prev)->borderLeft() + toRenderBox(prev)->paddingLeft(); } // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space. - if (!prev->isRenderBlock()) return; - RenderBlock* block = static_cast<RenderBlock *>(prev); - + if (!prev || !prev->isRenderBlock()) + return; + + RenderBlock* block = toRenderBlock(prev); if (block->m_floatingObjects && block->floatBottom() > offset) addIntrudingFloats(block, xoffset, offset); @@ -2913,7 +3067,7 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo IntRect floatsOverflowRect; DeprecatedPtrListIterator<FloatingObject> it(*child->m_floatingObjects); for (FloatingObject* r; (r = it.current()); ++it) { - int bottom = child->yPos() + r->m_bottom; + int bottom = child->y() + r->m_bottom; lowestFloatBottom = max(lowestFloatBottom, bottom); if (bottom > height()) { @@ -2929,8 +3083,8 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo // The nearest enclosing layer always paints the float (so that zindex and stacking // behaves properly). We always want to propagate the desire to paint the float as // far out as we can, to the outermost block that overlaps the float, stopping only - // if we hit a layer boundary. - if (r->m_renderer->enclosingLayer() == enclosingLayer()) + // if we hit a self-painting layer boundary. + if (r->m_renderer->enclosingSelfPaintingLayer() == enclosingSelfPaintingLayer()) r->m_shouldPaint = false; else floatingObj->m_shouldPaint = false; @@ -2942,7 +3096,8 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo } m_floatingObjects->append(floatingObj); } - } else if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasLayer() && r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingLayer() == child->enclosingLayer()) + } else if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer() && + r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingLayer() == child->enclosingLayer()) // The float is not overhanging from this block, so if it is a descendant of the child, the child should // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing // layer. @@ -2950,7 +3105,7 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo // it should paint. r->m_shouldPaint = true; - if (r->m_shouldPaint && !r->m_renderer->hasLayer()) { + if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { IntRect floatOverflowRect = r->m_renderer->overflowRect(false); floatOverflowRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()); floatsOverflowRect.unite(floatOverflowRect); @@ -3010,7 +3165,7 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, int xoff, int yoff) bool RenderBlock::avoidsFloats() const { // Floats can't intrude into our box if we have a non-auto column count or width. - return RenderFlow::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth(); + return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth(); } bool RenderBlock::containsFloat(RenderObject* o) @@ -3026,9 +3181,9 @@ bool RenderBlock::containsFloat(RenderObject* o) return false; } -void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderObject* floatToRemove) +void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout) { - setChildNeedsLayout(true); + setChildNeedsLayout(true, !inLayout); if (floatToRemove) removeFloatingObject(floatToRemove); @@ -3036,14 +3191,16 @@ void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderObject* floatToRem // Iterate over our children and mark them as needed. if (!childrenInline()) { for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (isBlockFlow() && !child->isFloatingOrPositioned() && - ((floatToRemove ? child->containsFloat(floatToRemove) : child->containsFloats()) || child->shrinkToAvoidFloats())) - child->markAllDescendantsWithFloatsForLayout(floatToRemove); + if ((!floatToRemove && child->isFloatingOrPositioned()) || !child->isRenderBlock()) + continue; + RenderBlock* childBlock = toRenderBlock(child); + if ((floatToRemove ? childBlock->containsFloat(floatToRemove) : childBlock->containsFloats()) || childBlock->shrinkToAvoidFloats()) + childBlock->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout); } } } -int RenderBlock::getClearDelta(RenderObject *child) +int RenderBlock::getClearDelta(RenderBox* child, int yPos) { // There is no need to compute clearance if we have no floats. if (!containsFloats()) @@ -3071,11 +3228,11 @@ int RenderBlock::getClearDelta(RenderObject *child) // to fit) and not all (we should be using nextFloatBottomBelow and looping). // Do not allow tables to wrap in quirks or even in almost strict mode // (ebay on the PLT, finance.yahoo.com in the real world, versiontracker.com forces even almost strict mode not to work) - int result = clearSet ? max(0, bottom - child->yPos()) : 0; + int result = clearSet ? max(0, bottom - yPos) : 0; if (!result && child->avoidsFloats() && child->style()->width().isFixed() && - child->minPrefWidth() > lineWidth(child->yPos()) && child->minPrefWidth() <= availableWidth() && + child->minPrefWidth() > lineWidth(yPos, false) && child->minPrefWidth() <= availableWidth() && document()->inStrictMode()) - result = max(0, floatBottom() - child->yPos()); + result = max(0, floatBottom() - yPos); return result; } @@ -3099,12 +3256,10 @@ bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int, int, int, bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) { - bool inlineFlow = isInlineFlow(); - - int tx = _tx + m_x; - int ty = _ty + m_y + borderTopExtra(); + int tx = _tx + x(); + int ty = _ty + y(); - if (!inlineFlow && !isRenderView()) { + if (!isRenderView()) { // Check if we need to do anything at all. IntRect overflowBox = overflowRect(false); overflowBox.move(tx, ty); @@ -3112,43 +3267,43 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu return false; } - if (isPointInOverflowControl(result, _x, _y, tx, ty)) { - if (hitTestAction == HitTestBlockBackground) { - updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); - return true; - } - return false; + if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, _x, _y, tx, ty)) { + updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); + return true; } - // If we have lightweight control clipping, then we can't have any spillout. - if (!hasControlClip() || controlClipRect(tx, ty).contains(_x, _y)) { + // If we have clipping, then we can't have any spillout. + bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer(); + bool useClip = (hasControlClip() || useOverflowClip); + bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).contains(_x, _y) : overflowClipRect(tx, ty).contains(_x, _y)); + if (checkChildren) { // Hit test descendants first. int scrolledX = tx; int scrolledY = ty; if (hasOverflowClip()) - m_layer->subtractScrolledContentOffset(scrolledX, scrolledY); + layer()->subtractScrolledContentOffset(scrolledX, scrolledY); // Hit test contents if we don't have columns. - if (!m_hasColumns && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) + if (!hasColumns() && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) return true; // Hit test our columns if we do have them. - if (m_hasColumns && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) + if (hasColumns() && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) return true; // Hit test floats. if (hitTestAction == HitTestFloat && m_floatingObjects) { if (isRenderView()) { - scrolledX += static_cast<RenderView*>(this)->frameView()->scrollX(); - scrolledY += static_cast<RenderView*>(this)->frameView()->scrollY(); + scrolledX += toRenderView(this)->frameView()->scrollX(); + scrolledY += toRenderView(this)->frameView()->scrollY(); } FloatingObject* o; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for (it.toLast(); (o = it.current()); --it) { - if (o->m_shouldPaint && !o->m_renderer->hasLayer()) { - int xoffset = scrolledX + o->m_left + o->m_renderer->marginLeft() - o->m_renderer->xPos(); - int yoffset = scrolledY + o->m_top + o->m_renderer->marginTop() - o->m_renderer->yPos(); + if (o->m_shouldPaint && !o->m_renderer->hasSelfPaintingLayer()) { + int xoffset = scrolledX + o->m_left + o->m_renderer->marginLeft() - o->m_renderer->x(); + int yoffset = scrolledY + o->m_top + o->m_renderer->marginTop() - o->m_renderer->y(); if (o->m_renderer->hitTest(request, result, IntPoint(_x, _y), xoffset, yoffset)) { updateHitTestResult(result, IntPoint(_x - xoffset, _y - yoffset)); return true; @@ -3159,11 +3314,10 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu } // Now hit test our background - if (!inlineFlow && (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground)) { - int topExtra = borderTopExtra(); - IntRect boundsRect(tx, ty - topExtra, m_width, m_height + topExtra + borderBottomExtra()); + if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) { + IntRect boundsRect(tx, ty, width(), height()); if (visibleToHitTesting() && boundsRect.contains(_x, _y)) { - updateHitTestResult(result, IntPoint(_x - tx, _y - ty + topExtra)); + updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); return true; } } @@ -3209,7 +3363,7 @@ bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& { if (childrenInline() && !isTable()) { // We have to hit-test our line boxes. - if (hitTestLines(request, result, x, y, tx, ty, hitTestAction)) { + if (m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction)) { updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } @@ -3218,10 +3372,8 @@ bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& HitTestAction childHitTest = hitTestAction; if (hitTestAction == HitTestChildBlockBackgrounds) childHitTest = HitTestChildBlockBackground; - for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { - // FIXME: We have to skip over inline flows, since they can show up inside RenderTables at the moment (a demoted inline <form> for example). If we ever implement a - // table-specific hit-test method (which we should do for performance reasons anyway), then we can remove this check. - if (!child->hasLayer() && !child->isFloating() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, childHitTest)) { + for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) { + if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, x, y, tx, ty, childHitTest)) { updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } @@ -3236,158 +3388,178 @@ Position RenderBlock::positionForBox(InlineBox *box, bool start) const if (!box) return Position(); - if (!box->object()->element()) - return Position(element(), start ? caretMinOffset() : caretMaxOffset()); + if (!box->renderer()->node()) + return Position(node(), start ? caretMinOffset() : caretMaxOffset()); if (!box->isInlineTextBox()) - return Position(box->object()->element(), start ? box->object()->caretMinOffset() : box->object()->caretMaxOffset()); + return Position(box->renderer()->node(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset()); InlineTextBox *textBox = static_cast<InlineTextBox *>(box); - return Position(box->object()->element(), start ? textBox->start() : textBox->start() + textBox->len()); + return Position(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len()); } Position RenderBlock::positionForRenderer(RenderObject* renderer, bool start) const { if (!renderer) - return Position(element(), 0); + return Position(node(), 0); - Node* node = renderer->element() ? renderer->element() : element(); - if (!node) + Node* n = renderer->node() ? renderer->node() : node(); + if (!n) return Position(); - ASSERT(renderer == node->renderer()); + ASSERT(renderer == n->renderer()); int offset = start ? renderer->caretMinOffset() : renderer->caretMaxOffset(); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now. - ASSERT(!node->isCharacterDataNode() || renderer->isText()); + ASSERT(!n->isCharacterDataNode() || renderer->isText()); - return Position(node, offset); + return Position(n, offset); } -VisiblePosition RenderBlock::positionForCoordinates(int x, int y) +// FIXME: This function should go on RenderObject as an instance method. Then +// all cases in which positionForPoint recurs could call this instead to +// prevent crossing editable boundaries. This would require many tests. +static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBox* parent, RenderBox* child, const IntPoint& pointInParentCoordinates) { - if (isTable()) - return RenderFlow::positionForCoordinates(x, y); + IntPoint pointInChildCoordinates(pointInParentCoordinates - child->location()); - int top = borderTop(); - int bottom = top + borderTopExtra() + paddingTop() + contentHeight() + paddingBottom() + borderBottomExtra(); + // If this is an anonymous renderer, we just recur normally + Node* childNode = child->node(); + if (!childNode) + return child->positionForPoint(pointInChildCoordinates); - int left = borderLeft(); - int right = left + paddingLeft() + contentWidth() + paddingRight(); + // Otherwise, first make sure that the editability of the parent and child agree. + // If they don't agree, then we return a visible position just before or after the child + RenderObject* ancestor = parent; + while (ancestor && !ancestor->node()) + ancestor = ancestor->parent(); - Node* n = element(); - - int contentsX = x; - int contentsY = y; - offsetForContents(contentsX, contentsY); + // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal + if (!ancestor || ancestor->node()->isContentEditable() == childNode->isContentEditable()) + return child->positionForPoint(pointInChildCoordinates); - if (isReplaced()) { - if (y < 0 || y < height() && x < 0) - return VisiblePosition(n, caretMinOffset(), DOWNSTREAM); - if (y >= height() || y >= 0 && x >= width()) - return VisiblePosition(n, caretMaxOffset(), DOWNSTREAM); - } + // Otherwise return before or after the child, depending on if the click was left or right of the child + int childMidX = child->width() / 2; + if (pointInChildCoordinates.x() < childMidX) + return ancestor->createVisiblePosition(childNode->nodeIndex(), DOWNSTREAM); + return ancestor->createVisiblePosition(childNode->nodeIndex() + 1, UPSTREAM); +} - // If we start inside the shadow tree, we will stay inside (even if the point is above or below). - if (!(n && n->isShadowNode()) && !childrenInline()) { - // Don't return positions inside editable roots for coordinates outside those roots, except for coordinates outside - // a document that is entirely editable. - bool isEditableRoot = n && n->rootEditableElement() == n && !n->hasTagName(bodyTag) && !n->hasTagName(htmlTag); - - if (y < top || (isEditableRoot && (y < bottom && x < left))) { - if (!isEditableRoot) - if (RenderObject* c = firstChild()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float or a compact, etc. - VisiblePosition p = c->positionForCoordinates(contentsX - c->xPos(), contentsY - c->yPos()); - if (p.isNotNull()) - return p; - } - if (n) { - if (Node* sp = n->shadowParentNode()) - n = sp; - if (Node* p = n->parent()) - return VisiblePosition(p, n->nodeIndex(), DOWNSTREAM); - } - return VisiblePosition(n, 0, DOWNSTREAM); - } +VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint& pointInContents) +{ + ASSERT(childrenInline()); - if (y >= bottom || (isEditableRoot && (y >= top && x >= right))) { - if (!isEditableRoot) - if (RenderObject* c = lastChild()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float or a compact, ect. - VisiblePosition p = c->positionForCoordinates(contentsX - c->xPos(), contentsY - c->yPos()); - if (p.isNotNull()) - return p; - } - if (n) { - if (Node* sp = n->shadowParentNode()) - n = sp; - if (Node* p = n->parent()) - return VisiblePosition(p, n->nodeIndex() + 1, DOWNSTREAM); - } - return VisiblePosition(n, 0, DOWNSTREAM); + if (!firstRootBox()) + return createVisiblePosition(0, DOWNSTREAM); + + // look for the closest line box in the root box which is at the passed-in y coordinate + InlineBox* closestBox = 0; + RootInlineBox* firstRootBoxWithChildren = 0; + RootInlineBox* lastRootBoxWithChildren = 0; + for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { + if (!root->firstChild()) + continue; + if (!firstRootBoxWithChildren) + firstRootBoxWithChildren = root; + lastRootBoxWithChildren = root; + + // set the bottom based on whether there is a next root box + // FIXME: This will consider nextRootBox even if it has no children, and maybe it shouldn't. + int bottom; + if (root->nextRootBox()) { + // FIXME: We would prefer to make the break point halfway between the bottom + // of the previous root box and the top of the next root box. + bottom = root->nextRootBox()->topOverflow(); + } else + bottom = root->bottomOverflow() + verticalLineClickFudgeFactor; + + // check if this root line box is located at this y coordinate + if (pointInContents.y() < bottom) { + closestBox = root->closestLeafChildForXPos(pointInContents.x()); + if (closestBox) + break; } } - if (childrenInline()) { - if (!firstRootBox()) - return VisiblePosition(n, 0, DOWNSTREAM); + Settings* settings = document()->settings(); + bool useWindowsBehavior = settings && settings->editingBehavior() == EditingWindowsBehavior; - if (contentsY < firstRootBox()->topOverflow() - verticalLineClickFudgeFactor) - // y coordinate is above first root line box - return VisiblePosition(positionForBox(firstRootBox()->firstLeafChild(), true), DOWNSTREAM); - - // look for the closest line box in the root box which is at the passed-in y coordinate - for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { - // set the bottom based on whether there is a next root box - if (root->nextRootBox()) - // FIXME: make the break point halfway between the bottom of the previous root box and the top of the next root box - bottom = root->nextRootBox()->topOverflow(); - else - bottom = root->bottomOverflow() + verticalLineClickFudgeFactor; - // check if this root line box is located at this y coordinate - if (contentsY < bottom && root->firstChild()) { - InlineBox* closestBox = root->closestLeafChildForXPos(x); - if (closestBox) - // pass the box a y position that is inside it - return closestBox->object()->positionForCoordinates(contentsX, closestBox->m_y); - } + if (useWindowsBehavior && !closestBox && lastRootBoxWithChildren) { + // y coordinate is below last root line box, pretend we hit it + closestBox = lastRootBoxWithChildren->closestLeafChildForXPos(pointInContents.x()); + } + + if (closestBox) { + if (!useWindowsBehavior && pointInContents.y() < firstRootBoxWithChildren->topOverflow() - verticalLineClickFudgeFactor) { + // y coordinate is above first root line box, so return the start of the first + return VisiblePosition(positionForBox(firstRootBoxWithChildren->firstLeafChild(), true), DOWNSTREAM); } - if (lastRootBox()) - // y coordinate is below last root line box - return VisiblePosition(positionForBox(lastRootBox()->lastLeafChild(), false), DOWNSTREAM); + // pass the box a y position that is inside it + return closestBox->renderer()->positionForPoint(IntPoint(pointInContents.x(), closestBox->m_y)); + } - return VisiblePosition(n, 0, DOWNSTREAM); + if (lastRootBoxWithChildren) { + // We hit this case for Mac behavior when the Y coordinate is below the last box. + ASSERT(!useWindowsBehavior); + return VisiblePosition(positionForBox(lastRootBoxWithChildren->lastLeafChild(), false), DOWNSTREAM); } - - // See if any child blocks exist at this y coordinate. - if (firstChild() && contentsY < firstChild()->yPos()) - return VisiblePosition(n, 0, DOWNSTREAM); - for (RenderObject* renderer = firstChild(); renderer; renderer = renderer->nextSibling()) { - if (renderer->height() == 0 || renderer->style()->visibility() != VISIBLE || renderer->isFloatingOrPositioned()) - continue; - RenderObject* next = renderer->nextSibling(); - while (next && next->isFloatingOrPositioned()) - next = next->nextSibling(); - if (next) - bottom = next->yPos(); - else - bottom = top + scrollHeight(); - if (contentsY >= renderer->yPos() && contentsY < bottom) - return renderer->positionForCoordinates(contentsX - renderer->xPos(), contentsY - renderer->yPos()); + + // Can't reach this. We have a root line box, but it has no kids. + // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text + // seems to hit this code path. + return createVisiblePosition(0, DOWNSTREAM); +} + +static inline bool isChildHitTestCandidate(RenderBox* box) +{ + return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrPositioned(); +} + +VisiblePosition RenderBlock::positionForPoint(const IntPoint& point) +{ + if (isTable()) + return RenderBox::positionForPoint(point); + + if (isReplaced()) { + if (point.y() < 0 || (point.y() < height() && point.x() < 0)) + return createVisiblePosition(caretMinOffset(), DOWNSTREAM); + if (point.y() >= height() || (point.y() >= 0 && point.x() >= width())) + return createVisiblePosition(caretMaxOffset(), DOWNSTREAM); + } + + int contentsX = point.x(); + int contentsY = point.y(); + offsetForContents(contentsX, contentsY); + IntPoint pointInContents(contentsX, contentsY); + + if (childrenInline()) + return positionForPointWithInlineChildren(pointInContents); + + if (lastChildBox() && contentsY > lastChildBox()->y()) { + for (RenderBox* childBox = lastChildBox(); childBox; childBox = childBox->previousSiblingBox()) { + if (isChildHitTestCandidate(childBox)) + return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents); + } + } else { + for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) { + // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3). + if (isChildHitTestCandidate(childBox) && contentsY < childBox->frameRect().bottom()) + return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents); + } } - - return RenderFlow::positionForCoordinates(x, y); + + // We only get here if there are no hit test candidate children below the click. + return RenderBox::positionForPoint(point); } void RenderBlock::offsetForContents(int& tx, int& ty) const { - ty -= borderTopExtra(); - if (hasOverflowClip()) - m_layer->addScrolledContentOffset(tx, ty); + layer()->addScrolledContentOffset(tx, ty); - if (m_hasColumns) { + if (hasColumns()) { IntPoint contentsPoint(tx, ty); adjustPointToColumnContents(contentsPoint); tx = contentsPoint.x(); @@ -3398,7 +3570,7 @@ void RenderBlock::offsetForContents(int& tx, int& ty) const int RenderBlock::availableWidth() const { // If we have multiple columns, then the available width is reduced to our column width. - if (m_hasColumns) + if (hasColumns()) return desiredColumnWidth(); return contentWidth(); } @@ -3456,20 +3628,20 @@ void RenderBlock::calcColumnWidth() void RenderBlock::setDesiredColumnCountAndWidth(int count, int width) { if (count == 1) { - if (m_hasColumns) { + if (hasColumns()) { delete gColumnInfoMap->take(this); - m_hasColumns = false; + setHasColumns(false); } } else { ColumnInfo* info; - if (m_hasColumns) + if (hasColumns()) info = gColumnInfoMap->get(this); else { if (!gColumnInfoMap) gColumnInfoMap = new ColumnInfoMap; info = new ColumnInfo; gColumnInfoMap->add(this, info); - m_hasColumns = true; + setHasColumns(true); } info->m_desiredColumnCount = count; info->m_desiredColumnWidth = width; @@ -3478,21 +3650,21 @@ void RenderBlock::setDesiredColumnCountAndWidth(int count, int width) int RenderBlock::desiredColumnWidth() const { - if (!m_hasColumns) + if (!hasColumns()) return contentWidth(); return gColumnInfoMap->get(this)->m_desiredColumnWidth; } unsigned RenderBlock::desiredColumnCount() const { - if (!m_hasColumns) + if (!hasColumns()) return 1; return gColumnInfoMap->get(this)->m_desiredColumnCount; } Vector<IntRect>* RenderBlock::columnRects() const { - if (!m_hasColumns) + if (!hasColumns()) return 0; return &gColumnInfoMap->get(this)->m_columnRects; } @@ -3500,7 +3672,7 @@ Vector<IntRect>* RenderBlock::columnRects() const int RenderBlock::layoutColumns(int endOfContent) { // Don't do anything if we have no columns - if (!m_hasColumns) + if (!hasColumns()) return -1; ColumnInfo* info = gColumnInfoMap->get(this); @@ -3552,9 +3724,9 @@ int RenderBlock::layoutColumns(int endOfContent) GraphicsContext context((PlatformGraphicsContext*)0); RenderObject::PaintInfo paintInfo(&context, pageRect, PaintPhaseForeground, false, 0, 0); - m_hasColumns = false; + setHasColumns(false); paintObject(paintInfo, 0, 0); - m_hasColumns = true; + setHasColumns(true); int adjustedBottom = v->bestTruncatedAt(); if (adjustedBottom <= currY) @@ -3592,14 +3764,14 @@ int RenderBlock::layoutColumns(int endOfContent) colCount++; } - m_overflowWidth = max(m_width, currX - colGap); + m_overflowWidth = max(width(), currX - colGap); m_overflowLeft = min(0, currX + desiredColumnWidth + colGap); m_overflowHeight = maxColBottom; int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); if (computeIntrinsicHeight) - m_height = m_overflowHeight + toAdd; + setHeight(m_overflowHeight + toAdd); v->setPrintRect(IntRect()); v->setTruncatedAt(0); @@ -3612,7 +3784,7 @@ int RenderBlock::layoutColumns(int endOfContent) void RenderBlock::adjustPointToColumnContents(IntPoint& point) const { // Just bail if we have no columns. - if (!m_hasColumns) + if (!hasColumns()) return; Vector<IntRect>* colRects = columnRects(); @@ -3641,7 +3813,7 @@ void RenderBlock::adjustPointToColumnContents(IntPoint& point) const void RenderBlock::adjustRectForColumns(IntRect& r) const { // Just bail if we have no columns. - if (!m_hasColumns) + if (!hasColumns()) return; Vector<IntRect>* colRects = columnRects(); @@ -3698,7 +3870,7 @@ void RenderBlock::calcPrefWidths() m_minPrefWidth = m_maxPrefWidth; // A horizontal marquee with inline children has no minimum width. - if (m_layer && m_layer->marquee() && m_layer->marquee()->isHorizontal()) + if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal()) m_minPrefWidth = 0; } @@ -3760,7 +3932,7 @@ RenderObject* InlineMinMaxIterator::next() result = current->firstChild(); if (!result) { // We hit the end of our inline. (It was empty, e.g., <span></span>.) - if (!oldEndOfInline && current->isInlineFlow()) { + if (!oldEndOfInline && current->isRenderInline()) { result = current; endOfInline = true; break; @@ -3770,7 +3942,7 @@ RenderObject* InlineMinMaxIterator::next() result = current->nextSibling(); if (result) break; current = current->parent(); - if (current && current != parent && current->isInlineFlow()) { + if (current && current != parent && current->isRenderInline()) { result = current; endOfInline = true; break; @@ -3781,7 +3953,7 @@ RenderObject* InlineMinMaxIterator::next() if (!result) break; - if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isInlineFlow())) + if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline())) break; current = result; @@ -3800,7 +3972,7 @@ static int getBPMWidth(int childValue, Length cssUnit) return 0; } -static int getBorderPaddingMargin(const RenderObject* child, bool endOfInline) +static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline) { RenderStyle* cstyle = child->style(); int result = 0; @@ -3820,7 +3992,7 @@ static inline void stripTrailingSpace(int& inlineMax, int& inlineMin, { if (trailingSpaceChild && trailingSpaceChild->isText()) { // Collapse away the trailing space at the end of a block. - RenderText* t = static_cast<RenderText*>(trailingSpaceChild); + RenderText* t = toRenderText(trailingSpaceChild); const UChar space = ' '; const Font& font = t->style()->font(); // FIXME: This ignores first-line. int spaceWidth = font.width(TextRun(&space, 1)); @@ -3900,10 +4072,10 @@ void RenderBlock::calcInlinePrefWidths() if (!child->isText()) { // Case (1) and (2). Inline replaced and inline flow elements. - if (child->isInlineFlow()) { + if (child->isRenderInline()) { // Add in padding/border/margin from the appropriate side of // the element. - int bpm = getBorderPaddingMargin(child, childIterator.endOfInline); + int bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline); childMin += bpm; childMax += bpm; @@ -3935,14 +4107,14 @@ void RenderBlock::calcInlinePrefWidths() bool clearPreviousFloat; if (child->isFloating()) { clearPreviousFloat = (prevFloat - && (prevFloat->style()->floating() == FLEFT && (child->style()->clear() & CLEFT) - || prevFloat->style()->floating() == FRIGHT && (child->style()->clear() & CRIGHT))); + && ((prevFloat->style()->floating() == FLEFT && (child->style()->clear() & CLEFT)) + || (prevFloat->style()->floating() == FRIGHT && (child->style()->clear() & CRIGHT)))); prevFloat = child; } else clearPreviousFloat = false; bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak; - if (canBreakReplacedElement && (autoWrap || oldAutoWrap) || clearPreviousFloat) { + if ((canBreakReplacedElement && (autoWrap || oldAutoWrap)) || clearPreviousFloat) { m_minPrefWidth = max(inlineMin, m_minPrefWidth); inlineMin = 0; } @@ -3986,7 +4158,7 @@ void RenderBlock::calcInlinePrefWidths() } } else if (child->isText()) { // Case (3). Text. - RenderText* t = static_cast<RenderText *>(child); + RenderText* t = toRenderText(child); if (t->isWordBreak()) { m_minPrefWidth = max(inlineMin, m_minPrefWidth); @@ -4077,7 +4249,7 @@ void RenderBlock::calcInlinePrefWidths() } oldAutoWrap = autoWrap; - if (!child->isInlineFlow()) + if (!child->isRenderInline()) previousLeaf = child; } @@ -4104,7 +4276,7 @@ void RenderBlock::calcBlockPrefWidths() continue; } - if (child->isFloating() || child->avoidsFloats()) { + if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) { int floatTotalWidth = floatLeftWidth + floatRightWidth; if (child->style()->clear() & CLEFT) { m_maxPrefWidth = max(floatTotalWidth, m_maxPrefWidth); @@ -4138,7 +4310,7 @@ void RenderBlock::calcBlockPrefWidths() w = child->maxPrefWidth() + margin; if (!child->isFloating()) { - if (child->avoidsFloats()) { + if (child->isBox() && toRenderBox(child)->avoidsFloats()) { // Determine a left and right max value based off whether or not the floats can fit in the // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin // is smaller than the float width. @@ -4194,11 +4366,11 @@ void RenderBlock::calcBlockPrefWidths() bool RenderBlock::hasLineIfEmpty() const { - return element() && (element()->isContentEditable() && element()->rootEditableElement() == element() || - element()->isShadowNode() && element()->shadowParentNode()->hasTagName(inputTag)); + return node() && ((node()->isContentEditable() && node()->rootEditableElement() == node()) || + (node()->isShadowNode() && node()->shadowParentNode()->hasTagName(inputTag))); } -int RenderBlock::lineHeight(bool b, bool isRootLineBox) const +int RenderBlock::lineHeight(bool firstLine, bool isRootLineBox) const { // Inline blocks are replaced elements. Otherwise, just pass off to // the base class. If we're being queried as though we're the root line @@ -4206,7 +4378,17 @@ int RenderBlock::lineHeight(bool b, bool isRootLineBox) const // just like a block. if (isReplaced() && !isRootLineBox) return height() + marginTop() + marginBottom(); - return RenderFlow::lineHeight(b, isRootLineBox); + + if (firstLine && document()->usesFirstLineRules()) { + RenderStyle* s = style(firstLine); + if (s != style()) + return s->computedLineHeight(); + } + + if (m_lineHeight == -1) + m_lineHeight = style()->computedLineHeight(); + + return m_lineHeight; } int RenderBlock::baselinePosition(bool b, bool isRootLineBox) const @@ -4228,31 +4410,31 @@ int RenderBlock::baselinePosition(bool b, bool isRootLineBox) const // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled // vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside // of our content box. - int baselinePos = (m_layer && (m_layer->marquee() || m_layer->verticalScrollbar() || m_layer->scrollYOffset() != 0)) ? -1 : getBaselineOfLastLineBox(); + int baselinePos = (layer() && (layer()->marquee() || layer()->verticalScrollbar() || layer()->scrollYOffset() != 0)) ? -1 : lastLineBoxBaseline(); if (baselinePos != -1 && baselinePos <= borderTop() + paddingTop() + contentHeight()) return marginTop() + baselinePos; return height() + marginTop() + marginBottom(); } - return RenderFlow::baselinePosition(b, isRootLineBox); + return RenderBox::baselinePosition(b, isRootLineBox); } -int RenderBlock::getBaselineOfFirstLineBox() const +int RenderBlock::firstLineBoxBaseline() const { if (!isBlockFlow()) - return RenderFlow::getBaselineOfFirstLineBox(); + return -1; if (childrenInline()) { if (firstLineBox()) - return firstLineBox()->yPos() + firstLineBox()->baseline(); + return firstLineBox()->y() + style(true)->font().ascent(); else return -1; } else { - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) { if (!curr->isFloatingOrPositioned()) { - int result = curr->getBaselineOfFirstLineBox(); + int result = curr->firstLineBoxBaseline(); if (result != -1) - return curr->yPos() + result; // Translate to our coordinate space. + return curr->y() + result; // Translate to our coordinate space. } } } @@ -4260,30 +4442,30 @@ int RenderBlock::getBaselineOfFirstLineBox() const return -1; } -int RenderBlock::getBaselineOfLastLineBox() const +int RenderBlock::lastLineBoxBaseline() const { if (!isBlockFlow()) - return RenderFlow::getBaselineOfLastLineBox(); + return -1; if (childrenInline()) { if (!firstLineBox() && hasLineIfEmpty()) - return RenderFlow::baselinePosition(true, true) + borderTop() + paddingTop(); + return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop(); if (lastLineBox()) - return lastLineBox()->yPos() + lastLineBox()->baseline(); + return lastLineBox()->y() + style(lastLineBox() == firstLineBox())->font().ascent(); return -1; } else { bool haveNormalFlowChild = false; - for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) { + for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) { if (!curr->isFloatingOrPositioned()) { haveNormalFlowChild = true; - int result = curr->getBaselineOfLastLineBox(); + int result = curr->lastLineBoxBaseline(); if (result != -1) - return curr->yPos() + result; // Translate to our coordinate space. + return curr->y() + result; // Translate to our coordinate space. } } if (!haveNormalFlowChild && hasLineIfEmpty()) - return RenderFlow::baselinePosition(true, true) + borderTop() + paddingTop(); + return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop(); } return -1; @@ -4302,31 +4484,32 @@ bool RenderBlock::containsNonZeroBidiLevel() const RenderBlock* RenderBlock::firstLineBlock() const { - const RenderObject* firstLineBlock = this; + RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this); bool hasPseudo = false; while (true) { - hasPseudo = firstLineBlock->style()->hasPseudoStyle(RenderStyle::FIRST_LINE); + hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE); if (hasPseudo) break; RenderObject* parentBlock = firstLineBlock->parent(); if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() || !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow()) break; - firstLineBlock = parentBlock; + ASSERT(parentBlock->isRenderBlock()); + firstLineBlock = toRenderBlock(parentBlock); } if (!hasPseudo) return 0; - return (RenderBlock*)(firstLineBlock); + return firstLineBlock; } void RenderBlock::updateFirstLetter() { if (!document()->usesFirstLetterRules()) return; - // Don't recurse - if (style()->styleType() == RenderStyle::FIRST_LETTER) + // Don't recur + if (style()->styleType() == FIRST_LETTER) return; // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find @@ -4336,7 +4519,7 @@ void RenderBlock::updateFirstLetter() while (true) { // We only honor first-letter if the firstLetterBlock can have children in the DOM. This correctly // prevents form controls from honoring first-letter. - hasPseudoStyle = firstLetterBlock->style()->hasPseudoStyle(RenderStyle::FIRST_LETTER) + hasPseudoStyle = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER) && firstLetterBlock->canHaveChildren(); if (hasPseudoStyle) break; @@ -4354,7 +4537,7 @@ void RenderBlock::updateFirstLetter() RenderObject* currChild = firstLetterBlock->firstChild(); while (currChild && currChild->needsLayout() && (!currChild->isReplaced() || currChild->isFloatingOrPositioned()) && !currChild->isText()) { if (currChild->isFloatingOrPositioned()) { - if (currChild->style()->styleType() == RenderStyle::FIRST_LETTER) + if (currChild->style()->styleType() == FIRST_LETTER) break; currChild = currChild->nextSibling(); } else @@ -4372,8 +4555,8 @@ void RenderBlock::updateFirstLetter() // If the child already has style, then it has already been created, so we just want // to update it. - if (currChild->style()->styleType() == RenderStyle::FIRST_LETTER) { - RenderStyle* pseudo = firstLetterBlock->getCachedPseudoStyle(RenderStyle::FIRST_LETTER, + if (currChild->style()->styleType() == FIRST_LETTER) { + RenderStyle* pseudo = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle()); currChild->setStyle(pseudo); for (RenderObject* genChild = currChild->firstChild(); genChild; genChild = genChild->nextSibling()) { @@ -4384,22 +4567,27 @@ void RenderBlock::updateFirstLetter() } // If the child does not already have style, we create it here. - if (currChild->isText() && !currChild->isBR() && currChild->parent()->style()->styleType() != RenderStyle::FIRST_LETTER) { + if (currChild->isText() && !currChild->isBR() && currChild->parent()->style()->styleType() != FIRST_LETTER) { // Our layout state is not valid for the repaints we are going to trigger by // adding and removing children of firstLetterContainer. view()->disableLayoutState(); - RenderText* textObj = static_cast<RenderText*>(currChild); + RenderText* textObj = toRenderText(currChild); // Create our pseudo style now that we have our firstLetterContainer determined. - RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(RenderStyle::FIRST_LETTER, + RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle()); // Force inline display (except for floating first-letters) - pseudoStyle->setDisplay( pseudoStyle->isFloating() ? BLOCK : INLINE); - pseudoStyle->setPosition( StaticPosition ); // CSS2 says first-letter can't be positioned. + pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE); + pseudoStyle->setPosition(StaticPosition); // CSS2 says first-letter can't be positioned. - RenderObject* firstLetter = RenderFlow::createAnonymousFlow(document(), pseudoStyle); // anonymous box + RenderObject* firstLetter = 0; + if (pseudoStyle->display() == INLINE) + firstLetter = new (renderArena()) RenderInline(document()); + else + firstLetter = new (renderArena()) RenderBlock(document()); + firstLetter->setStyle(pseudoStyle); firstLetterContainer->addChild(firstLetter, currChild); // The original string is going to be either a generated content string or a DOM node's @@ -4421,10 +4609,10 @@ void RenderBlock::updateFirstLetter() // construct text fragment for the text after the first letter // NOTE: this might empty RenderTextFragment* remainingText = - new (renderArena()) RenderTextFragment(textObj->node(), oldText.get(), length, oldText->length() - length); + new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length); remainingText->setStyle(textObj->style()); - if (remainingText->element()) - remainingText->element()->setRenderer(remainingText); + if (remainingText->node()) + remainingText->node()->setRenderer(remainingText); RenderObject* nextObj = textObj->nextSibling(); firstLetterContainer->removeChild(textObj); @@ -4433,7 +4621,7 @@ void RenderBlock::updateFirstLetter() // construct text fragment for the first letter RenderTextFragment* letter = - new (renderArena()) RenderTextFragment(remainingText->node(), oldText.get(), 0, length); + new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length); RefPtr<RenderStyle> newStyle = RenderStyle::create(); newStyle->inheritFrom(pseudoStyle); letter->setStyle(newStyle.release()); @@ -4460,7 +4648,7 @@ bool RenderBlock::inRootBlockContext() const // (crawling into blocks). static bool shouldCheckLines(RenderObject* obj) { - return !obj->isFloatingOrPositioned() && !obj->isCompact() && !obj->isRunIn() && + return !obj->isFloatingOrPositioned() && !obj->isRunIn() && obj->isBlockFlow() && obj->style()->height().isAuto() && (!obj->isFlexibleBox() || obj->style()->boxOrient() == VERTICAL); } @@ -4477,7 +4665,7 @@ static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count) else { for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) { if (shouldCheckLines(obj)) { - RootInlineBox *box = getLineAtIndex(static_cast<RenderBlock*>(obj), i, count); + RootInlineBox *box = getLineAtIndex(toRenderBlock(obj), i, count); if (box) return box; } @@ -4487,7 +4675,7 @@ static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count) return 0; } -int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count) +static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count) { if (block->style()->visibility() == VISIBLE) { if (block->childrenInline()) { @@ -4497,18 +4685,18 @@ int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& co } } else { - RenderObject* normalFlowChildWithoutLines = 0; - for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) { + RenderBox* normalFlowChildWithoutLines = 0; + for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) { if (shouldCheckLines(obj)) { - int result = getHeightForLineCount(static_cast<RenderBlock*>(obj), l, false, count); + int result = getHeightForLineCount(toRenderBlock(obj), l, false, count); if (result != -1) - return result + obj->yPos() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0); + return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0); } - else if (!obj->isFloatingOrPositioned() && !obj->isCompact() && !obj->isRunIn()) + else if (!obj->isFloatingOrPositioned() && !obj->isRunIn()) normalFlowChildWithoutLines = obj; } if (normalFlowChildWithoutLines && l == 0) - return normalFlowChildWithoutLines->yPos() + normalFlowChildWithoutLines->height(); + return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height(); } } @@ -4531,7 +4719,7 @@ int RenderBlock::lineCount() else for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) if (shouldCheckLines(obj)) - count += static_cast<RenderBlock*>(obj)->lineCount(); + count += toRenderBlock(obj)->lineCount(); } return count; } @@ -4550,20 +4738,20 @@ void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const if (childrenInline()) { for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) { if (box->firstChild()) - left = min(left, x + box->firstChild()->xPos()); + left = min(left, x + box->firstChild()->x()); if (box->lastChild()) - right = max(right, x + box->lastChild()->xPos() + box->lastChild()->width()); + right = max(right, x + box->lastChild()->x() + box->lastChild()->width()); } } else { - for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) { + for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) { if (!obj->isFloatingOrPositioned()) { if (obj->isBlockFlow() && !obj->hasOverflowClip()) - static_cast<RenderBlock*>(obj)->adjustForBorderFit(x + obj->xPos(), left, right); + toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right); else if (obj->style()->visibility() == VISIBLE) { // We are a replaced element or some kind of non-block-flow object. - left = min(left, x + obj->xPos()); - right = max(right, x + obj->xPos() + obj->width()); + left = min(left, x + obj->x()); + right = max(right, x + obj->x() + obj->width()); } } } @@ -4575,7 +4763,7 @@ void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const for (; (r = it.current()); ++it) { // Only examine the object if our m_shouldPaint flag is set. if (r->m_shouldPaint) { - int floatLeft = r->m_left - r->m_renderer->xPos() + r->m_renderer->marginLeft(); + int floatLeft = r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); int floatRight = floatLeft + r->m_renderer->width(); left = min(left, floatLeft); right = max(right, floatRight); @@ -4620,7 +4808,7 @@ void RenderBlock::clearTruncation() else for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) if (shouldCheckLines(obj)) - static_cast<RenderBlock*>(obj)->clearTruncation(); + toRenderBlock(obj)->clearTruncation(); } } @@ -4646,6 +4834,218 @@ void RenderBlock::setMaxBottomMargins(int pos, int neg) m_maxMargin->m_bottomNeg = neg; } +void RenderBlock::absoluteRects(Vector<IntRect>& rects, int tx, int ty) +{ + // For blocks inside inlines, we go ahead and include margins so that we run right up to the + // inline boxes above and below us (thus getting merged with them to form a single irregular + // shape). + if (inlineContinuation()) { + rects.append(IntRect(tx, ty - collapsedMarginTop(), + width(), height() + collapsedMarginTop() + collapsedMarginBottom())); + inlineContinuation()->absoluteRects(rects, + tx - x() + inlineContinuation()->containingBlock()->x(), + ty - y() + inlineContinuation()->containingBlock()->y()); + } else + rects.append(IntRect(tx, ty, width(), height())); +} + +void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads) +{ + // For blocks inside inlines, we go ahead and include margins so that we run right up to the + // inline boxes above and below us (thus getting merged with them to form a single irregular + // shape). + if (inlineContinuation()) { + FloatRect localRect(0, -collapsedMarginTop(), + width(), height() + collapsedMarginTop() + collapsedMarginBottom()); + quads.append(localToAbsoluteQuad(localRect)); + inlineContinuation()->absoluteQuads(quads); + } else + quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()))); +} + +IntRect RenderBlock::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth) +{ + IntRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth)); + if (inlineContinuation()) + r.inflateY(collapsedMarginTop()); + return r; +} + +RenderObject* RenderBlock::hoverAncestor() const +{ + return inlineContinuation() ? inlineContinuation() : RenderBox::hoverAncestor(); +} + +void RenderBlock::updateDragState(bool dragOn) +{ + RenderBox::updateDragState(dragOn); + if (inlineContinuation()) + inlineContinuation()->updateDragState(dragOn); +} + +RenderStyle* RenderBlock::outlineStyleForRepaint() const +{ + return inlineContinuation() ? inlineContinuation()->style() : style(); +} + +void RenderBlock::childBecameNonInline(RenderObject*) +{ + makeChildrenNonInline(); + if (isAnonymousBlock() && parent() && parent()->isRenderBlock()) + toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); + // |this| may be dead here +} + +void RenderBlock::updateHitTestResult(HitTestResult& result, const IntPoint& point) +{ + if (result.innerNode()) + return; + + Node* n = node(); + if (inlineContinuation()) + // We are in the margins of block elements that are part of a continuation. In + // this case we're actually still inside the enclosing inline element that was + // split. Go ahead and set our inner node accordingly. + n = inlineContinuation()->node(); + + if (n) { + result.setInnerNode(n); + if (!result.innerNonSharedNode()) + result.setInnerNonSharedNode(n); + result.setLocalPoint(point); + } +} + +IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) +{ + // Do the normal calculation in most cases. + if (firstChild()) + return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine); + + // This is a special case: + // The element is not an inline element, and it's empty. So we have to + // calculate a fake position to indicate where objects are to be inserted. + + // FIXME: This does not take into account either :first-line or :first-letter + // However, as soon as some content is entered, the line boxes will be + // constructed and this kludge is not called any more. So only the caret size + // of an empty :first-line'd block is wrong. I think we can live with that. + RenderStyle* currentStyle = firstLineStyle(); + int height = lineHeight(true); + + enum CaretAlignment { alignLeft, alignRight, alignCenter }; + + CaretAlignment alignment = alignLeft; + + switch (currentStyle->textAlign()) { + case TAAUTO: + case JUSTIFY: + if (currentStyle->direction() == RTL) + alignment = alignRight; + break; + case LEFT: + case WEBKIT_LEFT: + break; + case CENTER: + case WEBKIT_CENTER: + alignment = alignCenter; + break; + case RIGHT: + case WEBKIT_RIGHT: + alignment = alignRight; + break; + } + + int x = borderLeft() + paddingLeft(); + int w = width(); + + switch (alignment) { + case alignLeft: + break; + case alignCenter: + x = (x + w - (borderRight() + paddingRight())) / 2; + break; + case alignRight: + x = w - (borderRight() + paddingRight()) - caretWidth; + break; + } + + if (extraWidthToEndOfLine) { + if (isRenderBlock()) { + *extraWidthToEndOfLine = w - (x + caretWidth); + } else { + // FIXME: This code looks wrong. + // myRight and containerRight are set up, but then clobbered. + // So *extraWidthToEndOfLine will always be 0 here. + + int myRight = x + caretWidth; + // FIXME: why call localToAbsoluteForContent() twice here, too? + FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0)); + + int containerRight = containingBlock()->x() + containingBlockWidthForContent(); + FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0)); + + *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x(); + } + } + + int y = paddingTop() + borderTop(); + + return IntRect(x, y, caretWidth, height); +} + +void RenderBlock::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty) +{ + // For blocks inside inlines, we go ahead and include margins so that we run right up to the + // inline boxes above and below us (thus getting merged with them to form a single irregular + // shape). + if (inlineContinuation()) { + // FIXME: This check really isn't accurate. + bool nextInlineHasLineBox = inlineContinuation()->firstLineBox(); + // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block. + bool prevInlineHasLineBox = toRenderInline(inlineContinuation()->node()->renderer())->firstLineBox(); + int topMargin = prevInlineHasLineBox ? collapsedMarginTop() : 0; + int bottomMargin = nextInlineHasLineBox ? collapsedMarginBottom() : 0; + graphicsContext->addFocusRingRect(IntRect(tx, ty - topMargin, + width(), height() + topMargin + bottomMargin)); + } else + graphicsContext->addFocusRingRect(IntRect(tx, ty, width(), height())); + + if (!hasOverflowClip() && !hasControlClip()) { + for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) + graphicsContext->addFocusRingRect(IntRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height())); + + for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { + if (!curr->isText() && !curr->isListMarker() && curr->isBox()) { + RenderBox* box = toRenderBox(curr); + FloatPoint pos; + // FIXME: This doesn't work correctly with transforms. + if (box->layer()) + pos = curr->localToAbsolute(); + else + pos = FloatPoint(tx + box->x(), ty + box->y()); + box->addFocusRingRects(graphicsContext, pos.x(), pos.y()); + } + } + } + + if (inlineContinuation()) + inlineContinuation()->addFocusRingRects(graphicsContext, + tx - x() + inlineContinuation()->containingBlock()->x(), + ty - y() + inlineContinuation()->containingBlock()->y()); +} + +RenderBlock* RenderBlock::createAnonymousBlock() const +{ + RefPtr<RenderStyle> newStyle = RenderStyle::create(); + newStyle->inheritFrom(style()); + newStyle->setDisplay(BLOCK); + + RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */); + newBox->setStyle(newStyle.release()); + return newBox; +} + const char* RenderBlock::renderName() const { if (isBody()) @@ -4661,8 +5061,6 @@ const char* RenderBlock::renderName() const return "RenderBlock (generated)"; if (isRelPositioned()) return "RenderBlock (relative positioned)"; - if (isCompact()) - return "RenderBlock (compact)"; if (isRunIn()) return "RenderBlock (run-in)"; return "RenderBlock"; |