summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering/RenderBlock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/rendering/RenderBlock.cpp')
-rw-r--r--WebCore/rendering/RenderBlock.cpp1326
1 files changed, 833 insertions, 493 deletions
diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp
index 0d73961..5b45501 100644
--- a/WebCore/rendering/RenderBlock.cpp
+++ b/WebCore/rendering/RenderBlock.cpp
@@ -25,6 +25,7 @@
#include "Document.h"
#include "Element.h"
+#include "FloatQuad.h"
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
@@ -58,6 +59,12 @@ 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)
@@ -77,7 +84,7 @@ static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;
typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
-typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderFlow*>*> 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)
@@ -114,15 +121,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()
@@ -131,7 +141,7 @@ RenderBlock::~RenderBlock()
delete m_positionedObjects;
delete m_maxMargin;
- if (m_hasColumns)
+ if (hasColumns())
delete gColumnInfoMap->take(this);
if (gPercentHeightDescendantsMap) {
@@ -154,11 +164,49 @@ 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());
- if (style() && parent() && diff == RenderStyle::Layout && style()->position() != newStyle->position()) {
+ 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.
@@ -176,16 +224,16 @@ void RenderBlock::styleWillChange(RenderStyle::Diff diff, const RenderStyle* new
}
if (cb->isRenderBlock())
- static_cast<RenderBlock*>(cb)->removePositionedObjects(this);
+ toRenderBlock(cb)->removePositionedObjects(this);
}
}
- RenderFlow::styleWillChange(diff, newStyle);
+ 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()) {
@@ -201,13 +249,21 @@ void RenderBlock::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldS
// Update pseudos for :before and :after now.
if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) {
- updateBeforeAfterContent(RenderStyle::BEFORE);
- updateBeforeAfterContent(RenderStyle::AFTER);
+ 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()))
@@ -231,13 +287,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()) {
@@ -253,7 +309,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;
@@ -263,7 +319,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.
@@ -277,17 +333,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
}
@@ -333,14 +388,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)
@@ -355,7 +415,7 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
ASSERT(isInlineBlockOrInlineTable() || !isInline());
ASSERT(!insertionPoint || insertionPoint->parent() == this);
- m_childrenInline = false;
+ setChildrenInline(false);
RenderObject *child = firstChild();
if (!child)
@@ -372,16 +432,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
@@ -392,7 +452,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
@@ -400,7 +502,7 @@ void RenderBlock::removeChild(RenderObject *oldChild)
RenderObject* prev = oldChild->previousSibling();
RenderObject* next = oldChild->nextSibling();
bool canDeleteAnonymousBlocks = !documentBeingDestroyed() && !isInline() && !oldChild->isInline() &&
- !oldChild->virtualContinuation() &&
+ (!oldChild->isRenderBlock() || !toRenderBlock(oldChild)->inlineContinuation()) &&
(!prev || (prev->isAnonymousBlock() && prev->childrenInline())) &&
(!next || (next->isAnonymousBlock() && next->childrenInline()));
if (canDeleteAnonymousBlocks && prev && next) {
@@ -408,20 +510,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()) {
@@ -429,13 +533,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.
@@ -615,15 +719,8 @@ 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(x(), y()), m_hasColumns || hasTransform() || hasReflection());
+ LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout());
+ LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection());
int oldWidth = width();
int oldColumnWidth = desiredColumnWidth();
@@ -670,11 +767,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);
@@ -684,9 +781,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;
@@ -714,7 +811,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
// 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);
+ RenderBlock* block = toRenderBlock(child);
if (block->floatBottom() + block->y() > height())
addOverhangingFloats(block, -block->x(), -block->y(), false);
}
@@ -762,12 +859,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);
@@ -800,19 +895,19 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
bool RenderBlock::expandsToEncloseOverhangingFloats() const
{
- return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) || m_hasColumns || isTableCell() || isFieldset();
+ 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()) {
+ if (child->style()->hasStaticY()) {
int y = height();
if (!marginInfo.canCollapseWithTop()) {
child->calcVerticalMargins();
@@ -828,7 +923,7 @@ void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marg
}
y += (collapsedTopPos - collapsedTopNeg) - marginTop;
}
- child->setStaticY(y);
+ child->layer()->setStaticY(y);
}
}
@@ -892,24 +987,27 @@ RenderBox* RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo&
return 0;
}
-RenderBox* RenderBlock::handleRunInChild(RenderBox* blockRunIn, bool& handled)
+RenderBox* RenderBlock::handleRunInChild(RenderBox* child, bool& handled)
{
// See if we have a run-in element with inline children. If the
// children aren't inline, then just treat the run-in as a normal
// block.
- if (blockRunIn->isRunIn() && (blockRunIn->childrenInline() || blockRunIn->isReplaced())) {
+ if (child->isRunIn() && (child->childrenInline() || child->isReplaced())) {
+ 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())) {
+ RenderBlock* currBlock = toRenderBlock(curr);
+
// The block acts like an inline, so just null out its
// position.
handled = true;
// Remove the old child.
RenderBox* next = blockRunIn->nextSiblingBox();
- removeChildNode(blockRunIn);
+ children()->removeChildNode(this, blockRunIn);
// Create an inline.
RenderInline* inlineRunIn = new (renderArena()) RenderInline(blockRunIn->node());
@@ -918,18 +1016,18 @@ RenderBox* RenderBlock::handleRunInChild(RenderBox* blockRunIn, bool& handled)
// 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 (runInChild->style()->styleType() != RenderStyle::BEFORE && runInChild->style()->styleType() != RenderStyle::AFTER) {
- blockRunIn->removeChildNode(runInChild, false);
+ if (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.
}
}
- // Now insert the new child under |curr|.
- curr->insertChildNode(inlineRunIn, curr->firstChild());
+ // 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 (blockRunIn->element())
- blockRunIn->element()->setRenderer(inlineRunIn);
+ if (blockRunIn->node())
+ blockRunIn->node()->setRenderer(inlineRunIn);
// Destroy the block run-in.
blockRunIn->destroy();
@@ -940,7 +1038,7 @@ RenderBox* RenderBlock::handleRunInChild(RenderBox* blockRunIn, bool& handled)
return 0;
}
-void RenderBlock::collapseMargins(RenderBox* 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);
@@ -969,7 +1067,7 @@ void RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo, int
// 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);
}
@@ -979,7 +1077,7 @@ void RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo, int
// 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))
@@ -1028,34 +1126,15 @@ void RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo, int
marginInfo.setSelfCollapsingBlockClearedFloat(false);
}
-
- view()->addLayoutDelta(IntSize(0, yPosEstimate - ypos));
- child->setLocation(child->x(), 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())
- static_cast<RenderBlock*>(child)->markAllDescendantsWithFloatsForLayout();
-
- // Our guess was wrong. Make the child lay itself out again.
- child->layoutIfNeeded();
- }
+
+ return ypos;
}
-void RenderBlock::clearFloatsIfNeeded(RenderBox* 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->setLocation(child->x(), child->y() + heightIncrease);
+ return yPos;
if (child->isSelfCollapsingBlock()) {
// For self-collapsing blocks that clear, they can still collapse their
@@ -1084,19 +1163,8 @@ void RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo,
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())
- static_cast<RenderBlock*>(child)->markAllDescendantsWithFloatsForLayout();
- child->layoutIfNeeded();
+
+ return yPos + heightIncrease;
}
int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& marginInfo)
@@ -1108,6 +1176,7 @@ int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& ma
int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop();
yPosEstimate += max(marginInfo.margin(), childMarginTop);
}
+ yPosEstimate += getClearDelta(child, yPosEstimate);
return yPosEstimate;
}
@@ -1122,7 +1191,7 @@ void RenderBlock::determineHorizontalPosition(RenderBox* 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(height());
+ int leftOff = leftOffset(height(), false);
if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) {
if (child->marginLeft() < 0)
leftOff += child->marginLeft();
@@ -1134,7 +1203,7 @@ void RenderBlock::determineHorizontalPosition(RenderBox* 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.
- child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y()));
+ child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false));
chPos = leftOff + child->marginLeft();
}
}
@@ -1144,7 +1213,7 @@ void RenderBlock::determineHorizontalPosition(RenderBox* child)
int xPos = width() - borderRight() - paddingRight() - verticalScrollbarWidth();
int chPos = xPos - (child->width() + child->marginRight());
if (child->avoidsFloats()) {
- int rightOff = rightOffset(height());
+ int rightOff = rightOffset(height(), false);
if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) {
if (child->marginRight() < 0)
rightOff -= child->marginRight();
@@ -1155,7 +1224,7 @@ void RenderBlock::determineHorizontalPosition(RenderBox* 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.
- toRenderBox(child)->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y()));
+ child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false));
chPos = rightOff - child->marginRight() - child->width();
}
}
@@ -1172,13 +1241,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);
}
}
@@ -1304,21 +1373,22 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom
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 > height() || fb > yPosEstimate)
+ if (fb > yPosEstimate)
markDescendantsWithFloats = true;
}
- if (markDescendantsWithFloats)
- static_cast<RenderBlock*>(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();
@@ -1327,10 +1397,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.
@@ -1348,7 +1436,8 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom
}
// 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->x(), -child->y(), !childNeededLayout));
+ if (child->isBlockFlow() && toRenderBlock(child)->containsFloats())
+ maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout));
// Update our overflow in case the child spills out the block.
m_overflowTop = min(m_overflowTop, child->y() + child->overflowTop(false));
@@ -1384,7 +1473,7 @@ bool RenderBlock::layoutOnlyPositionedObjects()
if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout())
return false;
- LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), m_hasColumns || hasTransform() || hasReflection());
+ LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection());
if (needsPositionedMovementLayout()) {
tryLayoutDoingPositionedMovementOnly();
@@ -1398,7 +1487,7 @@ bool RenderBlock::layoutOnlyPositionedObjects()
statePusher.pop();
if (hasOverflowClip())
- m_layer->updateScrollInfoAfterLayout();
+ layer()->updateScrollInfoAfterLayout();
#ifdef ANDROID_FIX
// iframe flatten will call FrameView::layout() which calls performPostLayoutTasks,
@@ -1422,11 +1511,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
@@ -1470,7 +1559,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 > 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();
}
@@ -1478,7 +1567,7 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
view()->enableLayoutState();
}
}
-
+
void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty)
{
tx += x();
@@ -1497,52 +1586,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++) {
@@ -1568,27 +1674,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;
}
}
@@ -1601,7 +1694,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);
}
@@ -1626,7 +1719,7 @@ void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty)
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.
@@ -1662,9 +1755,11 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty)
PaintPhase paintPhase = paintInfo.phase;
// 1. paint background, borders etc
- if ((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) {
@@ -1680,12 +1775,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);
}
@@ -1693,30 +1788,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 (!isPrinting && !m_hasColumns)
+ if (!isPrinting && !hasColumns())
paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks.
// 4. paint floats.
if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
- if (m_hasColumns)
- paintColumns(paintInfo, scrolledX, scrolledY, true);
+ if (hasColumns())
+ paintColumnContents(paintInfo, scrolledX, scrolledY, true);
else
paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
}
// 5. paint outline.
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
- RenderBox::paintOutline(paintInfo.context, tx, ty, width(), height(), style());
+ paintOutline(paintInfo.context, tx, ty, width(), height(), style());
// 6. paint continuation outlines.
if ((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 - x() + inlineFlow->containingBlock()->x(),
- ty - y() + inlineFlow->containingBlock()->y());
+ 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);
}
@@ -1739,7 +1834,7 @@ 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->x() + r->m_renderer->marginLeft();
@@ -1767,8 +1862,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;
@@ -1776,7 +1871,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);
@@ -1790,16 +1885,16 @@ static ContinuationOutlineTableMap* continuationOutlineTable()
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();
- ListHashSet<RenderFlow*>* continuations = table->get(this);
+ ListHashSet<RenderInline*>* continuations = table->get(this);
if (!continuations) {
- continuations = new ListHashSet<RenderFlow*>;
+ continuations = new ListHashSet<RenderInline*>;
table->set(this, continuations);
}
@@ -1812,15 +1907,15 @@ void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty)
if (table->isEmpty())
return;
- ListHashSet<RenderFlow*>* continuations = table->get(this);
+ ListHashSet<RenderInline*>* continuations = table->get(this);
if (!continuations)
return;
// Paint each continuation outline.
- ListHashSet<RenderFlow*>::iterator end = continuations->end();
- for (ListHashSet<RenderFlow*>::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->x();
@@ -1845,9 +1940,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())
@@ -1856,12 +1951,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.
@@ -1874,22 +1969,22 @@ 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
+ // FIXME: this is broken with transforms and a non-null repaintContainer
FloatPoint absContentPoint = localToAbsolute(FloatPoint());
if (hasOverflowClip())
absContentPoint -= layer()->scrolledContentOffset();
@@ -1949,21 +2044,10 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int
// 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).
GapRects result;
-#ifdef ANDROID_DO_NOT_DRAW_TEXTFIELD_SELECTION
- Node* node = element();
- if (node) {
- Node* ancestor = node->shadowAncestorNode();
- if (ancestor && ancestor->renderer()) {
- RenderObject* renderer = ancestor->renderer();
- if (renderer->isTextField() || renderer->isTextArea())
- return result;
- }
- }
-#endif
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());
@@ -1977,7 +2061,7 @@ 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))
+ if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height(),
rootBlock, blockX, blockY, paintInfo));
return result;
@@ -2015,14 +2099,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) {
@@ -2090,7 +2174,7 @@ GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX,
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->x(), ty + curr->y(),
+ result.unite(toRenderBlock(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->x(), ty + curr->y(),
lastTop, lastLeft, lastRight, paintInfo));
}
return result;
@@ -2172,7 +2256,7 @@ void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& left
int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int yPos)
{
- int left = leftOffset(yPos);
+ int left = leftOffset(yPos, false);
if (left == borderLeft() + paddingLeft()) {
if (rootBlock != this)
// The border can potentially be further extended by our containingBlock().
@@ -2192,7 +2276,7 @@ int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int yPos)
int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int yPos)
{
- int right = rightOffset(yPos);
+ int right = rightOffset(yPos, false);
if (right == (contentWidth() + (borderLeft() + paddingLeft()))) {
if (rootBlock != this)
// The border can potentially be further extended by our containingBlock().
@@ -2284,7 +2368,7 @@ void RenderBlock::insertFloatingObject(RenderBox* 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;
@@ -2469,15 +2553,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) {
@@ -2495,7 +2581,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();
@@ -2505,15 +2591,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;
@@ -2532,7 +2615,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();
@@ -2543,9 +2626,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;
}
@@ -2586,7 +2669,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);
@@ -2608,8 +2691,10 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
// 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->isText() && !c->isRenderInline())
- bottom = max(bottom, toRenderBox(c)->y() + c->lowestPosition(false));
+ if (!c->isFloatingOrPositioned() && c->isBox()) {
+ RenderBox* childBox = toRenderBox(c);
+ bottom = max(bottom, childBox->y() + childBox->lowestPosition(false));
+ }
}
}
@@ -2642,7 +2727,7 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
}
}
- 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);
@@ -2653,16 +2738,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());
+ if (childrenInline()) {
+ if (lastLineBox()) {
+ int childBottomEdge = lastLineBox()->y() + lastLineBox()->height();
+ bottom = max(bottom, childBottomEdge + paddingBottom());
+ }
+ } 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());
+ }
+ }
}
return bottom;
@@ -2681,8 +2780,10 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
// 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() && !c->isRenderInline())
- right = max(right, toRenderBox(c)->x() + c->rightmostPosition(false));
+ if (!c->isFloatingOrPositioned() && c->isBox()) {
+ RenderBox* childBox = toRenderBox(c);
+ right = max(right, childBox->x() + childBox->rightmostPosition(false));
+ }
}
}
@@ -2716,7 +2817,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
}
}
- if (m_hasColumns) {
+ if (hasColumns()) {
// This only matters for LTR
if (style()->direction() == LTR)
right = max(columnRects()->last().right() + relativeOffset, right);
@@ -2727,21 +2828,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());
+ 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());
+ }
+ } 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());
+ }
}
}
@@ -2760,8 +2873,10 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
// 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() && !c->isRenderInline())
- left = min(left, toRenderBox(c)->x() + c->leftmostPosition(false));
+ if (!c->isFloatingOrPositioned() && c->isBox()) {
+ RenderBox* childBox = toRenderBox(c);
+ left = min(left, childBox->x() + childBox->leftmostPosition(false));
+ }
}
}
@@ -2795,7 +2910,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
}
}
- if (m_hasColumns) {
+ if (hasColumns()) {
// This only matters for RTL
if (style()->direction() == RTL)
left = min(columnRects()->last().x() + relativeOffset, left);
@@ -2806,7 +2921,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);
}
@@ -2815,7 +2930,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());
}
return left;
@@ -2893,7 +3008,7 @@ void RenderBlock::clearFloats()
// to avoid floats.
bool parentHasFloats = false;
RenderObject* prev = previousSibling();
- while (prev && (!prev->isBox() || !prev->isRenderBlock() || prev->avoidsFloats() || prev->isFloatingOrPositioned())) {
+ while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) {
if (prev->isFloating())
parentHasFloats = true;
prev = prev->previousSibling();
@@ -2902,7 +3017,7 @@ void RenderBlock::clearFloats()
// First add in floats from the parent.
int offset = y();
if (parentHasFloats) {
- RenderBlock* parentBlock = static_cast<RenderBlock *>(parent());
+ RenderBlock* parentBlock = toRenderBlock(parent());
addIntrudingFloats(parentBlock, parentBlock->borderLeft() + parentBlock->paddingLeft(), offset);
}
@@ -2918,7 +3033,7 @@ void RenderBlock::clearFloats()
if (!prev || !prev->isRenderBlock())
return;
- RenderBlock* block = static_cast<RenderBlock *>(prev);
+ RenderBlock* block = toRenderBlock(prev);
if (block->m_floatingObjects && block->floatBottom() > offset)
addIntrudingFloats(block, xoffset, offset);
@@ -2989,8 +3104,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;
@@ -3002,7 +3117,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.
@@ -3010,7 +3126,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);
@@ -3070,7 +3186,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)
@@ -3096,14 +3212,16 @@ void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove
// Iterate over our children and mark them as needed.
if (!childrenInline()) {
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- if (child->isRenderBlock() && !child->isFloatingOrPositioned() &&
- ((floatToRemove ? child->containsFloat(floatToRemove) : child->containsFloats()) || child->shrinkToAvoidFloats()))
- static_cast<RenderBlock*>(child)->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
+ 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(RenderBox* child)
+int RenderBlock::getClearDelta(RenderBox* child, int yPos)
{
// There is no need to compute clearance if we have no floats.
if (!containsFloats())
@@ -3131,11 +3249,11 @@ int RenderBlock::getClearDelta(RenderBox* 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->y()) : 0;
+ int result = clearSet ? max(0, bottom - yPos) : 0;
if (!result && child->avoidsFloats() && child->style()->width().isFixed() &&
- child->minPrefWidth() > lineWidth(child->y()) && child->minPrefWidth() <= availableWidth() &&
+ child->minPrefWidth() > lineWidth(yPos, false) && child->minPrefWidth() <= availableWidth() &&
document()->inStrictMode())
- result = max(0, floatBottom() - child->y());
+ result = max(0, floatBottom() - yPos);
return result;
}
@@ -3170,41 +3288,41 @@ 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()) {
+ 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)) {
@@ -3266,7 +3384,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;
}
@@ -3275,10 +3393,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->isRenderInline() && 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;
}
@@ -3293,156 +3409,153 @@ 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 positionForCoordinates recurs could call this instead to
+// prevent crossing editable boundaries. This would require many tests.
+static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBox* parent, RenderBox* child, const IntPoint& parentCoords)
{
- if (isTable())
- return RenderFlow::positionForCoordinates(x, y);
+ int xInChildCoords = parentCoords.x() - child->x();
+ int yInChildCoords = parentCoords.y() - child->y();
- int top = borderTop();
- int bottom = top + paddingTop() + contentHeight() + paddingBottom();
+ // If this is an anonymous renderer, we just recur normally
+ Node* childNode = child->node();
+ if (!childNode)
+ return child->positionForCoordinates(xInChildCoords, yInChildCoords);
- 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->positionForCoordinates(xInChildCoords, yInChildCoords);
- 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 (xInChildCoords < 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 (RenderBox* c = firstChildBox()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float, etc.
- VisiblePosition p = c->positionForCoordinates(contentsX - c->x(), contentsY - c->y());
- 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);
- }
+static VisiblePosition positionForPointWithInlineChildren(RenderBlock* block, const IntPoint& pointInContents)
+{
+ ASSERT(block->childrenInline());
- if (y >= bottom || (isEditableRoot && (y >= top && x >= right))) {
- if (!isEditableRoot)
- if (RenderBox* c = lastChildBox()) { // FIXME: This code doesn't make any sense. This child could be an inline or a positioned element or a float, etc.
- VisiblePosition p = c->positionForCoordinates(contentsX - c->x(), contentsY - c->y());
- 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 (!block->firstRootBox())
+ return block->createVisiblePosition(0, DOWNSTREAM);
+
+ InlineBox* closestBox = 0;
+ // look for the closest line box in the root box which is at the passed-in y coordinate
+ for (RootInlineBox* root = block->firstRootBox(); root; root = root->nextRootBox()) {
+ int bottom;
+ // 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 (pointInContents.y() < bottom && root->firstChild()) {
+ closestBox = root->closestLeafChildForXPos(pointInContents.x());
+ if (closestBox)
+ // pass the box a y position that is inside it
+ break;
}
}
- if (childrenInline()) {
- if (!firstRootBox())
- return VisiblePosition(n, 0, DOWNSTREAM);
+ // y coordinate is below last root line box, pretend we hit it
+ if (!closestBox)
+ closestBox = block->lastRootBox()->closestLeafChildForXPos(pointInContents.x());
- 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 (closestBox) {
+ // pass the box a y position that is inside it
+ return closestBox->renderer()->positionForCoordinates(pointInContents.x(), closestBox->m_y);
+ }
+
+ // 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 codepath.
+ return block->createVisiblePosition(0, DOWNSTREAM);
+}
- if (lastRootBox())
- // y coordinate is below last root line box
- return VisiblePosition(positionForBox(lastRootBox()->lastLeafChild(), false), DOWNSTREAM);
+VisiblePosition RenderBlock::positionForPoint(const IntPoint& point)
+{
+ if (isTable())
+ return RenderBox::positionForPoint(point);
+
+ int contentsX = point.x();
+ int contentsY = point.y();
+ offsetForContents(contentsX, contentsY);
+ IntPoint pointInContents(contentsX, contentsY);
- return VisiblePosition(n, 0, DOWNSTREAM);
+ 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);
+ }
+
+ if (childrenInline()) {
+ return positionForPointWithInlineChildren(this, pointInContents);
}
-
- // See if any child blocks exist at this y coordinate.
+
+ // Check top/bottom child-margin/parent-padding for clicks and place them in the first/last child
+ // FIXME: This will not correctly handle first or last children being positioned or non-visible
if (firstChildBox() && contentsY < firstChildBox()->y())
- return VisiblePosition(n, 0, DOWNSTREAM);
- for (RenderBox* renderer = firstChildBox(); renderer; renderer = renderer->nextSiblingBox()) {
- if (renderer->height() == 0 || renderer->style()->visibility() != VISIBLE || renderer->isFloatingOrPositioned())
+ return positionForPointRespectingEditingBoundaries(this, firstChildBox(), pointInContents);
+ if (lastChildBox() && contentsY > lastChildBox()->y())
+ return positionForPointRespectingEditingBoundaries(this, lastChildBox(), pointInContents);
+
+ for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
+ if (childBox->height() == 0 || childBox->style()->visibility() != VISIBLE || childBox->isFloatingOrPositioned())
continue;
- RenderBox* next = renderer->nextSiblingBox();
- while (next && next->isFloatingOrPositioned())
- next = next->nextSiblingBox();
- if (next)
- bottom = next->y();
- else
- bottom = top + scrollHeight();
- if (contentsY >= renderer->y() && contentsY < bottom)
- return renderer->positionForCoordinates(contentsX - renderer->x(), contentsY - renderer->y());
+ // We hit this child if our click was above the bottom of its padding box (like IE6/7 and FF3)
+ if (contentsY < childBox->y() + childBox->height())
+ return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
}
-
- return RenderFlow::positionForCoordinates(x, y);
+
+ // We only get here if there are no, or only floated/positioned, or only
+ // non-visible block children below the click.
+ return RenderBox::positionForPoint(point);
}
void RenderBlock::offsetForContents(int& tx, int& ty) const
{
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();
@@ -3453,7 +3566,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();
}
@@ -3511,20 +3624,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;
@@ -3533,21 +3646,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;
}
@@ -3555,7 +3668,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);
@@ -3607,9 +3720,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)
@@ -3667,7 +3780,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();
@@ -3696,7 +3809,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();
@@ -3753,7 +3866,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;
}
@@ -3855,7 +3968,7 @@ static int getBPMWidth(int childValue, Length cssUnit)
return 0;
}
-static int getBorderPaddingMargin(const RenderBox* child, bool endOfInline)
+static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline)
{
RenderStyle* cstyle = child->style();
int result = 0;
@@ -3958,7 +4071,7 @@ void RenderBlock::calcInlinePrefWidths()
if (child->isRenderInline()) {
// Add in padding/border/margin from the appropriate side of
// the element.
- int bpm = getBorderPaddingMargin(static_cast<RenderFlow*>(child), childIterator.endOfInline);
+ int bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline);
childMin += bpm;
childMax += bpm;
@@ -3990,14 +4103,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;
}
@@ -4163,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);
@@ -4197,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.
@@ -4253,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
@@ -4265,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
@@ -4287,29 +4410,29 @@ 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 (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
if (!curr->isFloatingOrPositioned()) {
- int result = curr->getBaselineOfFirstLineBox();
+ int result = curr->firstLineBoxBaseline();
if (result != -1)
return curr->y() + result; // Translate to our coordinate space.
}
@@ -4319,16 +4442,16 @@ 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 {
@@ -4336,13 +4459,13 @@ int RenderBlock::getBaselineOfLastLineBox() const
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->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;
@@ -4364,7 +4487,7 @@ RenderBlock* RenderBlock::firstLineBlock() const
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();
@@ -4372,7 +4495,7 @@ RenderBlock* RenderBlock::firstLineBlock() const
!parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow())
break;
ASSERT(parentBlock->isRenderBlock());
- firstLineBlock = static_cast<RenderBlock*>(parentBlock);
+ firstLineBlock = toRenderBlock(parentBlock);
}
if (!hasPseudo)
@@ -4385,8 +4508,8 @@ 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
@@ -4396,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;
@@ -4414,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
@@ -4432,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()) {
@@ -4444,7 +4567,7 @@ 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();
@@ -4452,14 +4575,19 @@ void RenderBlock::updateFirstLetter()
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
@@ -4481,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);
@@ -4493,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());
@@ -4537,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;
}
@@ -4560,7 +4688,7 @@ static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom,
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->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
}
@@ -4591,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;
}
@@ -4610,16 +4738,16 @@ 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 (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
if (!obj->isFloatingOrPositioned()) {
if (obj->isBlockFlow() && !obj->hasOverflowClip())
- static_cast<RenderBlock*>(obj)->adjustForBorderFit(x + obj->x(), 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->x());
@@ -4680,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();
}
}
@@ -4706,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, bool topLevel)
+{
+ // 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 (topLevel && inlineContinuation()) {
+ rects.append(IntRect(tx, ty - collapsedMarginTop(),
+ width(), height() + collapsedMarginTop() + collapsedMarginBottom()));
+ inlineContinuation()->absoluteRects(rects,
+ tx - x() + inlineContinuation()->containingBlock()->x(),
+ ty - y() + inlineContinuation()->containingBlock()->y(), topLevel);
+ } else
+ rects.append(IntRect(tx, ty, width(), height()));
+}
+
+void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads, bool topLevel)
+{
+ // 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 (topLevel && inlineContinuation()) {
+ FloatRect localRect(0, -collapsedMarginTop(),
+ width(), height() + collapsedMarginTop() + collapsedMarginBottom());
+ quads.append(localToAbsoluteQuad(localRect));
+ inlineContinuation()->absoluteQuads(quads, topLevel);
+ } 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());
+ 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())