summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderBlock.cpp
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2013-09-13 12:51:20 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-19 20:50:05 +0200
commitd441d6f39bb846989d95bcf5caf387b42414718d (patch)
treee367e64a75991c554930278175d403c072de6bb8 /Source/WebCore/rendering/RenderBlock.cpp
parent0060b2994c07842f4c59de64b5e3e430525c4b90 (diff)
downloadqtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit. Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebCore/rendering/RenderBlock.cpp')
-rw-r--r--Source/WebCore/rendering/RenderBlock.cpp2107
1 files changed, 1321 insertions, 786 deletions
diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp
index 058e90431..c1b3fe154 100644
--- a/Source/WebCore/rendering/RenderBlock.cpp
+++ b/Source/WebCore/rendering/RenderBlock.cpp
@@ -27,43 +27,47 @@
#include "AXObjectCache.h"
#include "ColumnInfo.h"
#include "Document.h"
+#include "Editor.h"
#include "Element.h"
#include "FloatQuad.h"
#include "Frame.h"
#include "FrameSelection.h"
#include "FrameView.h"
#include "GraphicsContext.h"
-#include "HTMLFormElement.h"
+#include "HTMLInputElement.h"
#include "HTMLNames.h"
+#include "HitTestLocation.h"
#include "HitTestResult.h"
#include "InlineIterator.h"
#include "InlineTextBox.h"
#include "LayoutRepainter.h"
+#include "LogicalSelectionOffsetCaches.h"
#include "OverflowEvent.h"
-#include "PODFreeListArena.h"
#include "Page.h"
#include "PaintInfo.h"
#include "RenderBoxRegionInfo.h"
#include "RenderCombineText.h"
#include "RenderDeprecatedFlexibleBox.h"
-#include "RenderImage.h"
+#include "RenderFlexibleBox.h"
#include "RenderInline.h"
#include "RenderLayer.h"
#include "RenderMarquee.h"
#include "RenderNamedFlowThread.h"
#include "RenderRegion.h"
-#include "RenderReplica.h"
#include "RenderTableCell.h"
#include "RenderTextFragment.h"
#include "RenderTheme.h"
#include "RenderView.h"
-#include "Settings.h"
#include "SVGTextRunRenderingContext.h"
+#include "Settings.h"
#include "ShadowRoot.h"
#include "TransformState.h"
-#include <wtf/StdLibExtras.h>
-#if ENABLE(CSS_EXCLUSIONS)
-#include "ExclusionShapeInsideInfo.h"
+#include <wtf/StackStats.h>
+#include <wtf/TemporaryChange.h>
+
+#if ENABLE(CSS_SHAPES)
+#include "ShapeInsideInfo.h"
+#include "ShapeOutsideInfo.h"
#endif
using namespace std;
@@ -97,7 +101,7 @@ struct SameSizeAsMarginInfo {
LayoutUnit margins[2];
};
-typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
+typedef WTF::HashMap<const RenderBox*, OwnPtr<ColumnInfo> > ColumnInfoMap;
static ColumnInfoMap* gColumnInfoMap = 0;
static TrackedDescendantsMap* gPositionedDescendantsMap = 0;
@@ -106,12 +110,14 @@ static TrackedDescendantsMap* gPercentHeightDescendantsMap = 0;
static TrackedContainerMap* gPositionedContainerMap = 0;
static TrackedContainerMap* gPercentHeightContainerMap = 0;
-typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap;
+typedef WTF::HashMap<RenderBlock*, OwnPtr<ListHashSet<RenderInline*> > > ContinuationOutlineTableMap;
typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
static int gDelayUpdateScrollInfo = 0;
static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
+static bool gColumnFlowSplitEnabled = true;
+
bool RenderBlock::s_canPropagateFloatIntoSibling = false;
// This class helps dispatching the 'overflow' event on layout change. overflow can be set on RenderBoxes, yet the existing code
@@ -158,16 +164,17 @@ private:
RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
: m_atBeforeSideOfBlock(true)
, m_atAfterSideOfBlock(false)
- , m_marginBeforeQuirk(false)
- , m_marginAfterQuirk(false)
+ , m_hasMarginBeforeQuirk(false)
+ , m_hasMarginAfterQuirk(false)
, m_determinedMarginBeforeQuirk(false)
+ , m_discardMargin(false)
{
RenderStyle* blockStyle = block->style();
ASSERT(block->isRenderView() || block->parent());
m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isOutOfFlowPositioned()
&& !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
- && !block->isWritingModeRoot() && !block->parent()->isFlexibleBox() && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth()
- && !blockStyle->columnSpan();
+ && !block->isRenderFlowThread() && !block->isWritingModeRoot() && !block->parent()->isFlexibleBox()
+ && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth() && !blockStyle->columnSpan();
m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE;
@@ -178,20 +185,24 @@ RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderP
m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && (afterBorderPadding == 0) &&
(blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE;
- m_quirkContainer = block->isTableCell() || block->isBody() || blockStyle->marginBeforeCollapse() == MDISCARD
- || blockStyle->marginAfterCollapse() == MDISCARD;
+ m_quirkContainer = block->isTableCell() || block->isBody();
+
+ m_discardMargin = m_canCollapseMarginBeforeWithChildren && block->mustDiscardMarginBefore();
- m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : LayoutUnit();
- m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : LayoutUnit();
+ m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxPositiveMarginBefore() : LayoutUnit();
+ m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxNegativeMarginBefore() : LayoutUnit();
}
// -------------------------------------------------------------------------------------------------------
-RenderBlock::RenderBlock(Node* node)
- : RenderBox(node)
- , m_lineHeight(-1)
- , m_beingDestroyed(false)
- , m_hasMarkupTruncation(false)
+RenderBlock::RenderBlock(ContainerNode* node)
+ : RenderBox(node)
+ , m_lineHeight(-1)
+ , m_hasMarginBeforeQuirk(false)
+ , m_hasMarginAfterQuirk(false)
+ , m_beingDestroyed(false)
+ , m_hasMarkupTruncation(false)
+ , m_hasBorderOrPaddingLogicalWidthChanged(false)
{
setChildrenInline(true);
COMPILE_ASSERT(sizeof(RenderBlock::FloatingObject) == sizeof(SameSizeAsFloatingObject), FloatingObject_should_stay_small);
@@ -200,21 +211,19 @@ RenderBlock::RenderBlock(Node* node)
static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap)
{
- if (TrackedRendererListHashSet* descendantSet = descendantMap->take(block)) {
+ if (OwnPtr<TrackedRendererListHashSet> descendantSet = descendantMap->take(block)) {
TrackedRendererListHashSet::iterator end = descendantSet->end();
for (TrackedRendererListHashSet::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
- HashSet<RenderBlock*>* containerSet = containerMap->get(*descendant);
- ASSERT(containerSet);
- if (!containerSet)
+ TrackedContainerMap::iterator it = containerMap->find(*descendant);
+ ASSERT(it != containerMap->end());
+ if (it == containerMap->end())
continue;
+ HashSet<RenderBlock*>* containerSet = it->value.get();
ASSERT(containerSet->contains(block));
containerSet->remove(block);
- if (containerSet->isEmpty()) {
- containerMap->remove(*descendant);
- delete containerSet;
- }
+ if (containerSet->isEmpty())
+ containerMap->remove(it);
}
- delete descendantSet;
}
}
@@ -224,7 +233,7 @@ RenderBlock::~RenderBlock()
deleteAllValues(m_floatingObjects->set());
if (hasColumns())
- delete gColumnInfoMap->take(this);
+ gColumnInfoMap->take(this);
if (gPercentHeightDescendantsMap)
removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
@@ -232,11 +241,23 @@ RenderBlock::~RenderBlock()
removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap);
}
+RenderBlock* RenderBlock::createAnonymous(Document* document)
+{
+ RenderBlock* renderer = new (document->renderArena()) RenderBlock(0);
+ renderer->setDocumentForAnonymous(document);
+ return renderer;
+}
+
void RenderBlock::willBeDestroyed()
{
// Mark as being destroyed to avoid trouble with merges in removeChild().
m_beingDestroyed = true;
+ if (!documentBeingDestroyed()) {
+ if (firstChild() && firstChild()->isRunIn())
+ moveRunInToOriginalPosition(firstChild());
+ }
+
// 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();
@@ -277,10 +298,6 @@ void RenderBlock::willBeDestroyed()
if (lineGridBox())
lineGridBox()->destroy(renderArena());
-#if ENABLE(CSS_EXCLUSIONS)
- ExclusionShapeInsideInfo::removeExclusionShapeInsideInfoForRenderBlock(this);
-#endif
-
if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
gDelayedUpdateScrollInfoSet->remove(this);
@@ -322,14 +339,28 @@ void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newSt
RenderBox::styleWillChange(diff, newStyle);
}
+static bool borderOrPaddingLogicalWidthChanged(const RenderStyle* oldStyle, const RenderStyle* newStyle)
+{
+ if (newStyle->isHorizontalWritingMode())
+ return oldStyle->borderLeftWidth() != newStyle->borderLeftWidth()
+ || oldStyle->borderRightWidth() != newStyle->borderRightWidth()
+ || oldStyle->paddingLeft() != newStyle->paddingLeft()
+ || oldStyle->paddingRight() != newStyle->paddingRight();
+
+ return oldStyle->borderTopWidth() != newStyle->borderTopWidth()
+ || oldStyle->borderBottomWidth() != newStyle->borderBottomWidth()
+ || oldStyle->paddingTop() != newStyle->paddingTop()
+ || oldStyle->paddingBottom() != newStyle->paddingBottom();
+}
+
void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderBox::styleDidChange(diff, oldStyle);
-
-#if ENABLE(CSS_EXCLUSIONS)
- // FIXME: Bug 89993: Style changes should affect the ExclusionShapeInsideInfos for other render blocks that
- // share the same ExclusionShapeInsideInfo
- updateExclusionShapeInsideInfoAfterStyleChange(style()->shapeInside(), oldStyle ? oldStyle->shapeInside() : 0);
+
+ RenderStyle* newStyle = style();
+
+#if ENABLE(CSS_SHAPES)
+ updateShapeInsideInfoAfterStyleChange(newStyle->resolvedShapeInside(), oldStyle ? oldStyle->resolvedShapeInside() : 0);
#endif
if (!isAnonymousBlock()) {
@@ -337,7 +368,7 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
RenderBoxModelObject* nextCont = currCont->continuation();
currCont->setContinuation(0);
- currCont->setStyle(style());
+ currCont->setStyle(newStyle);
currCont->setContinuation(nextCont);
}
}
@@ -345,12 +376,6 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
propagateStyleToAnonymousChildren(true);
m_lineHeight = -1;
- // Update pseudos for :before and :after now.
- if (!isAnonymous() && document()->styleSheetCollection()->usesBeforeAfterRules() && canHaveGeneratedChildren()) {
- updateBeforeAfterContent(BEFORE);
- updateBeforeAfterContent(AFTER);
- }
-
// After our style changed, if we lose our ability to propagate floats into next sibling
// blocks, then we need to find the top most parent containing that overhanging float and
// then mark its descendants with floats for layout and clear all floats from its next
@@ -380,14 +405,10 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
parentBlock->markAllDescendantsWithFloatsForLayout();
parentBlock->markSiblingsWithFloatsForLayout();
}
-}
-
-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;
- children()->updateBeforeAfterContent(this, pseudoId);
+
+ // It's possible for our border/padding to change, but for the overall logical width of the block to
+ // end up being the same. We keep track of this change so in layoutBlock, we can know to set relayoutChildren=true.
+ m_hasBorderOrPaddingLogicalWidthChanged = oldStyle && diff == StyleDifferenceLayout && needsLayout() && borderOrPaddingLogicalWidthChanged(oldStyle, newStyle);
}
RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
@@ -566,7 +587,7 @@ RenderBlock* RenderBlock::clone() const
// generated content added yet.
cloneBlock->setChildrenInline(cloneBlock->firstChild() ? cloneBlock->firstChild()->isInline() : childrenInline());
}
- cloneBlock->setInRenderFlowThread(inRenderFlowThread());
+ cloneBlock->setFlowThreadState(flowThreadState());
return cloneBlock;
}
@@ -601,15 +622,9 @@ void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
RenderBoxModelObject* currChild = this;
RenderObject* currChildNextSibling = currChild->nextSibling();
- bool documentUsesBeforeAfterRules = document()->styleSheetCollection()->usesBeforeAfterRules();
- // Note: |this| can be destroyed inside this loop if it is an empty anonymous
- // block and we try to call updateBeforeAfterContent inside which removes the
- // generated content and additionally cleans up |this| empty anonymous block.
- // See RenderBlock::removeChild(). DO NOT reference any local variables to |this|
- // after this point.
while (curr && curr != fromBlock) {
- ASSERT(curr->isRenderBlock());
+ ASSERT_WITH_SECURITY_IMPLICATION(curr->isRenderBlock());
RenderBlock* blockCurr = toRenderBlock(curr);
@@ -630,16 +645,6 @@ void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
cloneBlock->setContinuation(oldCont);
}
- // Someone may have indirectly caused a <q> to split. When this happens, the :after content
- // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
- // content gets properly destroyed.
- bool isLastChild = (currChildNextSibling == blockCurr->lastChild());
- if (documentUsesBeforeAfterRules)
- blockCurr->children()->updateBeforeAfterContent(blockCurr, AFTER);
- if (isLastChild && currChildNextSibling != blockCurr->lastChild())
- currChildNextSibling = 0; // We destroyed the last child, so now we need to update
- // the value of currChildNextSibling.
-
// Now we need to take all of the children starting from the first child
// *after* currChild and append them all to the clone.
blockCurr->moveChildrenTo(cloneBlock, currChildNextSibling, 0, true);
@@ -798,10 +803,6 @@ RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
{
- // Make sure we don't append things after :after-generated content if we have it.
- if (!beforeChild)
- beforeChild = afterPseudoElementRenderer();
-
if (beforeChild && beforeChild->parent() != this) {
RenderObject* beforeChildContainer = beforeChild->parent();
while (beforeChildContainer->parent() != this)
@@ -857,47 +858,33 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild,
beforeChild = beforeChild->nextSibling();
// Check for a spanning element in columns.
- RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
- if (columnsBlockAncestor) {
- // We are placing a column-span element inside a block.
- RenderBlock* newBox = createAnonymousColumnSpanBlock();
+ if (gColumnFlowSplitEnabled) {
+ RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
+ if (columnsBlockAncestor) {
+ TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false);
+ // We are placing a column-span element inside a block.
+ RenderBlock* newBox = createAnonymousColumnSpanBlock();
- if (columnsBlockAncestor != this) {
- // We are nested inside a multi-column element and are being split by the span. We have to break up
- // our block into continuations.
- RenderBoxModelObject* oldContinuation = continuation();
-
- // When we split an anonymous block, there's no need to do any continuation hookup,
- // since we haven't actually split a real element.
- if (!isAnonymousBlock())
- setContinuation(newBox);
-
- // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
- // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
- // content gets properly destroyed.
- bool isFirstChild = (beforeChild == firstChild());
- bool isLastChild = (beforeChild == lastChild());
- if (document()->styleSheetCollection()->usesBeforeAfterRules())
- children()->updateBeforeAfterContent(this, AFTER);
- if (isLastChild && beforeChild != lastChild()) {
- // We destroyed the last child, so now we need to update our insertion
- // point to be 0. It's just a straight append now.
- beforeChild = 0;
- } else if (isFirstChild && beforeChild != firstChild()) {
- // If beforeChild was the last anonymous block that collapsed,
- // then we need to update its value.
- beforeChild = firstChild();
+ if (columnsBlockAncestor != this && !isRenderFlowThread()) {
+ // We are nested inside a multi-column element and are being split by the span. We have to break up
+ // our block into continuations.
+ RenderBoxModelObject* oldContinuation = continuation();
+
+ // When we split an anonymous block, there's no need to do any continuation hookup,
+ // since we haven't actually split a real element.
+ if (!isAnonymousBlock())
+ setContinuation(newBox);
+
+ splitFlow(beforeChild, newBox, newChild, oldContinuation);
+ return;
}
- splitFlow(beforeChild, newBox, newChild, oldContinuation);
+ // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
+ // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
+ // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
+ makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
return;
}
-
- // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
- // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
- // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
- makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
- return;
}
bool madeBoxesNonInline = false;
@@ -938,7 +925,7 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild,
RenderBox::addChild(newChild, beforeChild);
// Handle placement of run-ins.
- placeRunInIfNeeded(newChild, DoNotPlaceGeneratedRunIn);
+ placeRunInIfNeeded(newChild);
if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
@@ -1013,11 +1000,12 @@ void RenderBlock::deleteLineBoxTree()
}
}
m_lineBoxes.deleteLineBoxTree(renderArena());
- if (UNLIKELY(AXObjectCache::accessibilityEnabled()))
- document()->axObjectCache()->recomputeIsIgnored(this);
+
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->recomputeIsIgnored(this);
}
-RootInlineBox* RenderBlock::createRootInlineBox()
+RootInlineBox* RenderBlock::createRootInlineBox()
{
return new (renderArena()) RootInlineBox(this);
}
@@ -1027,8 +1015,10 @@ RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
RootInlineBox* rootBox = createRootInlineBox();
m_lineBoxes.appendLineBox(rootBox);
- if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox)
- document()->axObjectCache()->recomputeIsIgnored(this);
+ if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox) {
+ if (AXObjectCache* cache = document()->existingAXObjectCache())
+ cache->recomputeIsIgnored(this);
+ }
return rootBox;
}
@@ -1120,12 +1110,16 @@ void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
if (child->nextSibling())
child->nextSibling()->setPreviousSibling(child->previousSibling());
}
+
+ child->children()->setFirstChild(0);
+ child->m_next = 0;
+
+ // Remove all the information in the flow thread associated with the leftover anonymous block.
+ child->removeFromRenderFlowThread();
+
child->setParent(0);
child->setPreviousSibling(0);
child->setNextSibling(0);
-
- child->children()->setFirstChild(0);
- child->m_next = 0;
child->destroy();
}
@@ -1161,7 +1155,7 @@ void RenderBlock::collapseAnonymousBoxChild(RenderBlock* parent, RenderObject* c
parent->setChildrenInline(child->childrenInline());
RenderObject* nextSibling = child->nextSibling();
- RenderFlowThread* childFlowThread = child->enclosingRenderFlowThread();
+ RenderFlowThread* childFlowThread = child->flowThreadContainingBlock();
CurrentRenderFlowThreadMaintainer flowThreadMaintainer(childFlowThread);
RenderBlock* anonBlock = toRenderBlock(parent->children()->removeChildNode(parent, child, child->hasLayer()));
@@ -1173,6 +1167,46 @@ void RenderBlock::collapseAnonymousBoxChild(RenderBlock* parent, RenderObject* c
anonBlock->destroy();
}
+void RenderBlock::moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert)
+{
+ moveAllChildrenTo(toBlock, fullRemoveInsert);
+
+ // When a portion of the render tree is being detached, anonymous blocks
+ // will be combined as their children are deleted. In this process, the
+ // anonymous block later in the tree is merged into the one preceeding it.
+ // It can happen that the later block (this) contains floats that the
+ // previous block (toBlock) did not contain, and thus are not in the
+ // floating objects list for toBlock. This can result in toBlock containing
+ // floats that are not in it's floating objects list, but are in the
+ // floating objects lists of siblings and parents. This can cause problems
+ // when the float itself is deleted, since the deletion code assumes that
+ // if a float is not in it's containing block's floating objects list, it
+ // isn't in any floating objects list. In order to preserve this condition
+ // (removing it has serious performance implications), we need to copy the
+ // floating objects from the old block (this) to the new block (toBlock).
+ // The float's metrics will likely all be wrong, but since toBlock is
+ // already marked for layout, this will get fixed before anything gets
+ // displayed.
+ // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
+ if (m_floatingObjects) {
+ if (!toBlock->m_floatingObjects)
+ toBlock->createFloatingObjects();
+
+ const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
+ FloatingObjectSetIterator end = fromFloatingObjectSet.end();
+
+ for (FloatingObjectSetIterator it = fromFloatingObjectSet.begin(); it != end; ++it) {
+ FloatingObject* floatingObject = *it;
+
+ // Don't insert the object again if it's already in the list
+ if (toBlock->containsFloat(floatingObject->renderer()))
+ continue;
+
+ toBlock->m_floatingObjects->add(floatingObject->clone());
+ }
+ }
+}
+
void RenderBlock::removeChild(RenderObject* oldChild)
{
// No need to waste time in merging or removing empty anonymous blocks.
@@ -1182,6 +1216,9 @@ void RenderBlock::removeChild(RenderObject* oldChild)
return;
}
+ // This protects against column split flows when anonymous blocks are getting merged.
+ TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false);
+
// If this child is a block, and if our previous and next siblings are
// both anonymous blocks with inline content, then we can go ahead and
// fold the inline content back together.
@@ -1222,7 +1259,7 @@ void RenderBlock::removeChild(RenderObject* oldChild)
} else {
// Take all the children out of the |next| block and put them in
// the |prev| block.
- nextBlock->moveAllChildrenTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
+ nextBlock->moveAllChildrenIncludingFloatsTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
// Delete the now-empty block's lines and nuke it.
nextBlock->deleteLineBoxTree();
@@ -1353,6 +1390,7 @@ void RenderBlock::finishDelayUpdateScrollInfo()
RenderBlock* block = *it;
if (block->hasOverflowClip()) {
block->layer()->updateScrollInfoAfterLayout();
+ block->clearLayoutOverflow();
}
}
}
@@ -1391,69 +1429,118 @@ void RenderBlock::layout()
// It's safe to check for control clip here, since controls can never be table cells.
// If we have a lightweight clip, there can never be any overflow from children.
- if (hasControlClip() && m_overflow)
+ if (hasControlClip() && m_overflow && !gDelayUpdateScrollInfo)
clearLayoutOverflow();
+
+ invalidateBackgroundObscurationStatus();
}
-#if ENABLE(CSS_EXCLUSIONS)
-void RenderBlock::updateExclusionShapeInsideInfoAfterStyleChange(const ExclusionShapeValue* shapeInside, const ExclusionShapeValue* oldShapeInside)
+#if ENABLE(CSS_SHAPES)
+void RenderBlock::updateShapeInsideInfoAfterStyleChange(const ShapeValue* shapeInside, const ShapeValue* oldShapeInside)
{
// FIXME: A future optimization would do a deep comparison for equality.
if (shapeInside == oldShapeInside)
return;
if (shapeInside) {
- ExclusionShapeInsideInfo* exclusionShapeInsideInfo = ExclusionShapeInsideInfo::ensureExclusionShapeInsideInfoForRenderBlock(this);
- exclusionShapeInsideInfo->dirtyShapeSize();
- } else
- ExclusionShapeInsideInfo::removeExclusionShapeInsideInfoForRenderBlock(this);
+ ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo();
+ shapeInsideInfo->dirtyShapeSize();
+ } else {
+ setShapeInsideInfo(nullptr);
+ markShapeInsideDescendantsForLayout();
+ }
+}
+
+void RenderBlock::markShapeInsideDescendantsForLayout()
+{
+ if (!everHadLayout())
+ return;
+ if (childrenInline()) {
+ setNeedsLayout(true);
+ return;
+ }
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (!child->isRenderBlock())
+ continue;
+ RenderBlock* childBlock = toRenderBlock(child);
+ childBlock->markShapeInsideDescendantsForLayout();
+ }
}
#endif
-void RenderBlock::updateRegionsAndExclusionsLogicalSize()
+static inline bool shapeInfoRequiresRelayout(const RenderBlock* block)
{
-#if ENABLE(CSS_EXCLUSIONS)
- if (!inRenderFlowThread() && !exclusionShapeInsideInfo())
+#if !ENABLE(CSS_SHAPES)
+ return false;
#else
- if (!inRenderFlowThread())
+ ShapeInsideInfo* info = block->shapeInsideInfo();
+ if (info)
+ info->setNeedsLayout(info->shapeSizeDirty());
+ else
+ info = block->layoutShapeInsideInfo();
+ return info && info->needsLayout();
#endif
- return;
+}
+
+bool RenderBlock::updateRegionsAndShapesBeforeChildLayout(RenderFlowThread* flowThread)
+{
+#if ENABLE(CSS_SHAPES)
+ if (!flowThread && !shapeInsideInfo())
+#else
+ if (!flowThread)
+#endif
+ return shapeInfoRequiresRelayout(this);
LayoutUnit oldHeight = logicalHeight();
LayoutUnit oldTop = logicalTop();
// Compute the maximum logical height content may cause this block to expand to
// FIXME: These should eventually use the const computeLogicalHeight rather than updateLogicalHeight
- setLogicalHeight(LayoutUnit::max() / 2);
+ setLogicalHeight(RenderFlowThread::maxLogicalHeight());
updateLogicalHeight();
-#if ENABLE(CSS_EXCLUSIONS)
- computeExclusionShapeSize();
+#if ENABLE(CSS_SHAPES)
+ computeShapeSize();
#endif
// Set our start and end regions. No regions above or below us will be considered by our children. They are
// effectively clamped to our region range.
- computeRegionRangeForBlock();
+ computeRegionRangeForBlock(flowThread);
setLogicalHeight(oldHeight);
setLogicalTop(oldTop);
+
+ return shapeInfoRequiresRelayout(this);
}
-#if ENABLE(CSS_EXCLUSIONS)
-void RenderBlock::computeExclusionShapeSize()
+#if ENABLE(CSS_SHAPES)
+void RenderBlock::computeShapeSize()
{
- ExclusionShapeInsideInfo* exclusionShapeInsideInfo = this->exclusionShapeInsideInfo();
- if (exclusionShapeInsideInfo) {
+ ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo();
+ if (shapeInsideInfo) {
bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false);
- exclusionShapeInsideInfo->computeShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit());
+ shapeInsideInfo->setShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit());
}
}
#endif
-void RenderBlock::computeRegionRangeForBlock()
+void RenderBlock::updateRegionsAndShapesAfterChildLayout(RenderFlowThread* flowThread, bool heightChanged)
+{
+#if ENABLE(CSS_SHAPES)
+ // A previous sibling has changed dimension, so we need to relayout the shape with the content
+ ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
+ if (heightChanged && shapeInsideInfo)
+ shapeInsideInfo->dirtyShapeSize();
+#else
+ UNUSED_PARAM(heightChanged);
+#endif
+ computeRegionRangeForBlock(flowThread);
+}
+
+void RenderBlock::computeRegionRangeForBlock(RenderFlowThread* flowThread)
{
- if (inRenderFlowThread())
- enclosingRenderFlowThread()->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
+ if (flowThread)
+ flowThread->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
}
bool RenderBlock::updateLogicalWidthAndColumnWidth()
@@ -1464,7 +1551,10 @@ bool RenderBlock::updateLogicalWidthAndColumnWidth()
updateLogicalWidth();
calcColumnWidth();
- return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth();
+ bool hasBorderOrPaddingLogicalWidthChanged = m_hasBorderOrPaddingLogicalWidthChanged;
+ m_hasBorderOrPaddingLogicalWidthChanged = false;
+
+ return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth() || hasBorderOrPaddingLogicalWidthChanged;
}
void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight)
@@ -1475,17 +1565,18 @@ void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalH
// We need to go ahead and set our explicit page height if one exists, so that we can
// avoid doing two layout passes.
updateLogicalHeight();
- LayoutUnit columnHeight = contentLogicalHeight();
+ LayoutUnit columnHeight = isRenderView() ? view()->pageOrViewLogicalHeight() : contentLogicalHeight();
if (columnHeight > 0) {
pageLogicalHeight = columnHeight;
hasSpecifiedPageLogicalHeight = true;
}
setLogicalHeight(0);
}
- if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) {
- colInfo->setColumnHeight(pageLogicalHeight);
+
+ if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout())
pageLogicalHeightChanged = true;
- }
+
+ colInfo->setColumnHeight(pageLogicalHeight);
if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
colInfo->clearForcedBreaks();
@@ -1493,7 +1584,7 @@ void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalH
colInfo->setPaginationUnit(paginationUnit());
} else if (isRenderFlowThread()) {
pageLogicalHeight = 1; // This is just a hack to always make sure we have a page logical height.
- pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalHeightChanged();
+ pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalSizeChanged();
}
}
@@ -1512,11 +1603,11 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
if (updateLogicalWidthAndColumnWidth())
relayoutChildren = true;
- m_overflow.clear();
-
clearFloats();
LayoutUnit previousHeight = logicalHeight();
+ // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
+ // for consistency with other render classes?
setLogicalHeight(0);
bool pageLogicalHeightChanged = false;
@@ -1527,12 +1618,12 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
RenderStyle* styleToUse = style();
LayoutStateMaintainer statePusher(renderView, this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || styleToUse->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, columnInfo());
- if (inRenderFlowThread()) {
- // Regions changing widths can force us to relayout our children.
- if (logicalWidthChangedInRegions())
- relayoutChildren = true;
- }
- updateRegionsAndExclusionsLogicalSize();
+ // Regions changing widths can force us to relayout our children.
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (logicalWidthChangedInRegions(flowThread))
+ relayoutChildren = true;
+ if (updateRegionsAndShapesBeforeChildLayout(flowThread))
+ relayoutChildren = true;
// We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
// our current maximal positive and negative margins. These values are used when we
@@ -1548,8 +1639,8 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
if (!isCell) {
initMaxMarginValues();
- setMarginBeforeQuirk(styleToUse->marginBefore().quirk());
- setMarginAfterQuirk(styleToUse->marginAfter().quirk());
+ setHasMarginBeforeQuirk(styleToUse->hasMarginBeforeQuirk());
+ setHasMarginAfterQuirk(styleToUse->hasMarginAfterQuirk());
setPaginationStrut(0);
}
@@ -1564,16 +1655,22 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
// Expand our intrinsic height to encompass floats.
- LayoutUnit toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
+ LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
if (relayoutForPagination(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher))
return;
-
+
// Calculate our new height.
LayoutUnit oldHeight = logicalHeight();
LayoutUnit oldClientAfterEdge = clientLogicalBottom();
+
+ // Before updating the final size of the flow thread make sure a forced break is applied after the content.
+ // This ensures the size information is correctly computed for the last auto-height region receiving content.
+ if (isRenderFlowThread())
+ toRenderFlowThread(this)->applyBreakAfterContent(oldClientAfterEdge);
+
updateLogicalHeight();
LayoutUnit newHeight = logicalHeight();
if (oldHeight != newHeight) {
@@ -1589,18 +1686,21 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
}
}
- if (previousHeight != newHeight)
+ bool heightChanged = (previousHeight != newHeight);
+ if (heightChanged)
relayoutChildren = true;
layoutPositionedObjects(relayoutChildren || isRoot());
- computeRegionRangeForBlock();
+ updateRegionsAndShapesAfterChildLayout(flowThread, heightChanged);
// Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
computeOverflow(oldClientAfterEdge);
statePusher.pop();
+ fitBorderToLinesIfNeeded();
+
if (renderView->layoutState()->m_pageLogicalHeight)
setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(this, logicalTop()));
@@ -1652,7 +1752,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh
repaintRectangle(reflectedRect(repaintRect));
}
}
-
+
setNeedsLayout(false);
}
@@ -1676,6 +1776,8 @@ void RenderBlock::addOverflowFromChildren()
void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
{
+ m_overflow.clear();
+
// Add overflow from children.
addOverflowFromChildren();
@@ -1696,16 +1798,39 @@ void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeF
else
rectToApply = LayoutRect(clientRect.x(), clientRect.y(), max<LayoutUnit>(0, oldClientAfterEdge - clientRect.x()), 1);
addLayoutOverflow(rectToApply);
+ if (hasRenderOverflow())
+ m_overflow->setLayoutClientAfterEdge(oldClientAfterEdge);
}
+ // Allow our overflow to catch cases where the caret in an empty editable element with negative text indent needs to get painted.
+ LayoutUnit textIndent = textIndentOffset();
+ if (textIndent < 0) {
+ LayoutRect clientRect(clientBoxRect());
+ LayoutRect rectToApply = LayoutRect(clientRect.x() + min<LayoutUnit>(0, textIndent), clientRect.y(), clientRect.width() - min<LayoutUnit>(0, textIndent), clientRect.height());
+ addVisualOverflow(rectToApply);
+ }
+
// Add visual overflow from box-shadow and border-image-outset.
addVisualEffectOverflow();
// Add visual overflow from theme.
addVisualOverflowFromTheme();
- if (isRenderFlowThread())
- enclosingRenderFlowThread()->computeOverflowStateForRegions(oldClientAfterEdge);
+ if (isRenderNamedFlowThread())
+ toRenderNamedFlowThread(this)->computeOversetStateForRegions(oldClientAfterEdge);
+}
+
+void RenderBlock::clearLayoutOverflow()
+{
+ if (!m_overflow)
+ return;
+
+ if (visualOverflowRect() == borderBoxRect()) {
+ m_overflow.clear();
+ return;
+ }
+
+ m_overflow->setLayoutOverflow(borderBoxRect());
}
void RenderBlock::addOverflowFromBlockChildren()
@@ -1728,7 +1853,6 @@ void RenderBlock::addOverflowFromFloats()
if (r->isDescendant())
addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
}
- return;
}
void RenderBlock::addOverflowFromPositionedObjects()
@@ -1764,7 +1888,7 @@ void RenderBlock::addVisualOverflowFromTheme()
bool RenderBlock::expandsToEncloseOverhangingFloats() const
{
- return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isDeprecatedFlexibleBox())
+ return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBoxIncludingDeprecated())
|| hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot();
}
@@ -1774,7 +1898,7 @@ void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marg
bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
LayoutUnit logicalTop = logicalHeight();
- setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
+ updateStaticInlinePositionForChild(child, logicalTop);
if (!marginInfo.canCollapseWithMarginBefore()) {
// Positioned blocks don't collapse margins, so add the margin provided by
@@ -1813,34 +1937,6 @@ void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
setLogicalHeight(logicalHeight() - marginOffset);
}
-bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo)
-{
- // Handle in the given order
- return handlePositionedChild(child, marginInfo)
- || handleFloatingChild(child, marginInfo);
-}
-
-
-bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo)
-{
- if (child->isOutOfFlowPositioned()) {
- child->containingBlock()->insertPositionedObject(child);
- adjustPositionedBlock(child, marginInfo);
- return true;
- }
- return false;
-}
-
-bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo)
-{
- if (child->isFloating()) {
- insertFloatingObject(child);
- adjustFloatingBlock(marginInfo);
- return true;
- }
- return false;
-}
-
static void destroyRunIn(RenderBoxModelObject* runIn)
{
ASSERT(runIn->isRunIn());
@@ -1858,12 +1954,12 @@ static void destroyRunIn(RenderBoxModelObject* runIn)
runIn->destroy();
}
-void RenderBlock::placeRunInIfNeeded(RenderObject* newChild, PlaceGeneratedRunInFlag flag)
+void RenderBlock::placeRunInIfNeeded(RenderObject* newChild)
{
- if (newChild->isRunIn() && (flag == PlaceGeneratedRunIn || !newChild->isBeforeOrAfterContent()))
+ if (newChild->isRunIn())
moveRunInUnderSiblingBlockIfNeeded(newChild);
else if (RenderObject* prevSibling = newChild->previousSibling()) {
- if (prevSibling->isRunIn() && (flag == PlaceGeneratedRunIn || !newChild->isBeforeOrAfterContent()))
+ if (prevSibling->isRunIn())
moveRunInUnderSiblingBlockIfNeeded(prevSibling);
}
}
@@ -1871,31 +1967,18 @@ void RenderBlock::placeRunInIfNeeded(RenderObject* newChild, PlaceGeneratedRunIn
RenderBoxModelObject* RenderBlock::createReplacementRunIn(RenderBoxModelObject* runIn)
{
ASSERT(runIn->isRunIn());
+ ASSERT(runIn->node());
- // First we destroy any :before/:after content. It will be regenerated by the new run-in.
- // Exception is if the run-in itself is generated.
- if (runIn->style()->styleType() != BEFORE && runIn->style()->styleType() != AFTER) {
- RenderObject* generatedContent;
- if (runIn->getCachedPseudoStyle(BEFORE) && (generatedContent = runIn->beforePseudoElementRenderer()))
- generatedContent->destroy();
- if (runIn->getCachedPseudoStyle(AFTER) && (generatedContent = runIn->afterPseudoElementRenderer()))
- generatedContent->destroy();
- }
-
- bool newRunInShouldBeBlock = !runIn->isRenderBlock();
- Node* runInNode = runIn->node();
RenderBoxModelObject* newRunIn = 0;
- if (newRunInShouldBeBlock)
- newRunIn = new (renderArena()) RenderBlock(runInNode ? runInNode : document());
+ if (!runIn->isRenderBlock())
+ newRunIn = new (renderArena()) RenderBlock(runIn->node());
else
- newRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document());
+ newRunIn = new (renderArena()) RenderInline(toElement(runIn->node()));
+
+ runIn->node()->setRenderer(newRunIn);
newRunIn->setStyle(runIn->style());
-
- runIn->moveAllChildrenTo(newRunIn, true);
- // If the run-in had an element, we need to set the new renderer.
- if (runInNode)
- runInNode->setRenderer(newRunIn);
+ runIn->moveAllChildrenTo(newRunIn, true);
return newRunIn;
}
@@ -1927,6 +2010,9 @@ void RenderBlock::moveRunInUnderSiblingBlockIfNeeded(RenderObject* runIn)
if (!curr || !curr->isRenderBlock() || !curr->childrenInline())
return;
+ if (toRenderBlock(curr)->beingDestroyed())
+ return;
+
// Per CSS3, "A run-in cannot run in to a block that already starts with a
// run-in or that itself is a run-in".
if (curr->isRunIn() || (curr->firstChild() && curr->firstChild()->isRunIn()))
@@ -1991,6 +2077,13 @@ void RenderBlock::moveRunInToOriginalPosition(RenderObject* runIn)
LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
{
+ bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
+ bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
+ bool childIsSelfCollapsing = child->isSelfCollapsingBlock();
+
+ // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
+ childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
+
// Get the four margin values for the child and cache them.
const MarginValues childMargins = marginValuesForChild(child);
@@ -2000,84 +2093,106 @@ LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo
// For self-collapsing blocks, collapse our bottom margins into our
// top to get new posTop and negTop values.
- if (child->isSelfCollapsingBlock()) {
+ if (childIsSelfCollapsing) {
posTop = max(posTop, childMargins.positiveMarginAfter());
negTop = max(negTop, childMargins.negativeMarginAfter());
}
// See if the top margin is quirky. We only care if this child has
// margins that will collapse with us.
- bool topQuirk = child->isMarginBeforeQuirk() || style()->marginBeforeCollapse() == MDISCARD;
+ bool topQuirk = hasMarginBeforeQuirk(child);
if (marginInfo.canCollapseWithMarginBefore()) {
- // This child is collapsing with the top of the
- // block. If it has larger margin values, then we need to update
- // our own maximal values.
- if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
- setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
-
- // The minute any of the margins involved isn't a quirk, don't
- // collapse it away, even if the margin is smaller (www.webreference.com
- // has an example of this, a <dt> with 0.8em author-specified inside
- // a <dl> inside a <td>.
- if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
- setMarginBeforeQuirk(false);
- marginInfo.setDeterminedMarginBeforeQuirk(true);
- }
-
- if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
- // We have no top margin and our top child has a quirky margin.
- // We will pick up this quirky margin and pass it through.
- // 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.
- setMarginBeforeQuirk(true);
+ if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
+ // This child is collapsing with the top of the
+ // block. If it has larger margin values, then we need to update
+ // our own maximal values.
+ if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
+ setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
+
+ // The minute any of the margins involved isn't a quirk, don't
+ // collapse it away, even if the margin is smaller (www.webreference.com
+ // has an example of this, a <dt> with 0.8em author-specified inside
+ // a <dl> inside a <td>.
+ if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
+ setHasMarginBeforeQuirk(false);
+ marginInfo.setDeterminedMarginBeforeQuirk(true);
+ }
+
+ if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
+ // We have no top margin and our top child has a quirky margin.
+ // We will pick up this quirky margin and pass it through.
+ // 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.
+ setHasMarginBeforeQuirk(true);
+ } else
+ // The before margin of the container will also discard all the margins it is collapsing with.
+ setMustDiscardMarginBefore();
+ }
+
+ // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
+ if (childDiscardMarginBefore) {
+ marginInfo.setDiscardMargin(true);
+ marginInfo.clearMargin();
}
if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
- marginInfo.setMarginBeforeQuirk(topQuirk);
+ marginInfo.setHasMarginBeforeQuirk(topQuirk);
LayoutUnit beforeCollapseLogicalTop = logicalHeight();
LayoutUnit logicalTop = beforeCollapseLogicalTop;
- if (child->isSelfCollapsingBlock()) {
- // This child has no height. We need to compute our
- // position before we collapse the child's margins together,
- // so that we can get an accurate position for the zero-height block.
- LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
- LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
- marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
-
- // Now collapse the child's margins together, which means examining our
- // bottom margin values as well.
- marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
- marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
-
- if (!marginInfo.canCollapseWithMarginBefore())
- // We need to make sure that the position of the self-collapsing block
- // is correct, since it could have overflowing content
- // that needs to be positioned correctly (e.g., a block that
- // had a specified height of 0 but that actually had subcontent).
- logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
- }
- else {
- if (child->style()->marginBeforeCollapse() == MSEPARATE) {
- setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child));
- logicalTop = logicalHeight();
+ if (childIsSelfCollapsing) {
+ // For a self collapsing block both the before and after margins get discarded. The block doesn't contribute anything to the height of the block.
+ // Also, the child's top position equals the logical height of the container.
+ if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
+ // This child has no height. We need to compute our
+ // position before we collapse the child's margins together,
+ // so that we can get an accurate position for the zero-height block.
+ LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
+ LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
+ marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
+
+ // Now collapse the child's margins together, which means examining our
+ // bottom margin values as well.
+ marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
+ marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
+
+ if (!marginInfo.canCollapseWithMarginBefore())
+ // We need to make sure that the position of the self-collapsing block
+ // is correct, since it could have overflowing content
+ // that needs to be positioned correctly (e.g., a block that
+ // had a specified height of 0 but that actually had subcontent).
+ logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
}
- else if (!marginInfo.atBeforeSideOfBlock() ||
- (!marginInfo.canCollapseMarginBeforeWithChildren()
- && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) {
+ } else {
+ if (mustSeparateMarginBeforeForChild(child)) {
+ ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
+ // If we are at the before side of the block and we collapse, ignore the computed margin
+ // and just add the child margin to the container height. This will correctly position
+ // the child inside the container.
+ LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit(0);
+ setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child));
+ logicalTop = logicalHeight();
+ } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
+ || (!marginInfo.canCollapseMarginBeforeWithChildren()
+ && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
// We're collapsing with a previous sibling's margins and not
// with the top of the block.
setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
logicalTop = logicalHeight();
}
- marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
- marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
+ marginInfo.setDiscardMargin(childDiscardMarginAfter);
+
+ if (!marginInfo.discardMargin()) {
+ marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
+ marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
+ } else
+ marginInfo.clearMargin();
if (marginInfo.margin())
- marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD);
+ marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
}
// If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
@@ -2093,12 +2208,15 @@ LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo
// If we have collapsed into a previous sibling and so reduced the height of the parent, ensure any floats that now
// overhang from the previous sibling are added to our parent. If the child's previous sibling itself is a float the child will avoid
// or clear it anyway, so don't worry about any floating children it may contain.
+ LayoutUnit oldLogicalHeight = logicalHeight();
+ setLogicalHeight(logicalTop);
RenderObject* prev = child->previousSibling();
if (prev && prev->isBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned()) {
RenderBlock* block = toRenderBlock(prev);
if (block->containsFloats() && !block->avoidsFloats() && (block->logicalTop() + block->lowestFloatLogicalBottom()) > logicalTop)
addOverhangingFloats(block, false);
}
+ setLogicalHeight(oldLogicalHeight);
return logicalTop;
}
@@ -2110,12 +2228,19 @@ LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& margin
return yPos;
if (child->isSelfCollapsingBlock()) {
+ bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
+
// For self-collapsing blocks that clear, they can still collapse their
// margins with following siblings. Reset the current margins to represent
// the self-collapsing block's margins only.
- MarginValues childMargins = marginValuesForChild(child);
- marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
- marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
+ // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
+ if (!childDiscardMargin) {
+ MarginValues childMargins = marginValuesForChild(child);
+ marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
+ marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
+ } else
+ marginInfo.clearMargin();
+ marginInfo.setDiscardMargin(childDiscardMargin);
// CSS2.1 states:
// "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
@@ -2134,7 +2259,8 @@ LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& margin
// Move the top of the child box to the bottom of the float ignoring the child's top margin.
LayoutUnit collapsedMargin = collapsedMarginBeforeForChild(child);
setLogicalHeight(child->logicalTop() - collapsedMargin);
- heightIncrease -= collapsedMargin;
+ // A negative collapsed margin-top value cancels itself out as it has already been factored into |yPos| above.
+ heightIncrease -= max(LayoutUnit(), collapsedMargin);
} else
// Increase our height by the amount we had to clear.
setLogicalHeight(logicalHeight() + heightIncrease);
@@ -2147,6 +2273,9 @@ LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& margin
// margins involved.
setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
marginInfo.setAtBeforeSideOfBlock(false);
+
+ // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value.
+ setMustDiscardMarginBefore(style()->marginBeforeCollapse() == MDISCARD);
}
LayoutUnit logicalTop = yPos + heightIncrease;
@@ -2158,12 +2287,22 @@ LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& margin
return logicalTop;
}
-void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore) const
+void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
{
- // FIXME: We should deal with the margin-collapse-* style extensions that prevent collapsing and that discard margins.
// Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
- if (document()->inQuirksMode() && child->isMarginBeforeQuirk() && (isTableCell() || isBody()))
+ // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
+ // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
+ if ((document()->inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child->style()->marginBeforeCollapse() == MSEPARATE)
+ return;
+
+ // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
+ // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
+ if (child->style()->marginBeforeCollapse() == MDISCARD) {
+ positiveMarginBefore = 0;
+ negativeMarginBefore = 0;
+ discardMarginBefore = true;
return;
+ }
LayoutUnit beforeChildMargin = marginBeforeForChild(child);
positiveMarginBefore = max(positiveMarginBefore, beforeChildMargin);
@@ -2176,7 +2315,7 @@ void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& pos
if (childBlock->childrenInline() || childBlock->isWritingModeRoot())
return;
- MarginInfo childMarginInfo(childBlock, childBlock->borderBefore() + childBlock->paddingBefore(), childBlock->borderAfter() + childBlock->paddingAfter());
+ MarginInfo childMarginInfo(childBlock, childBlock->borderAndPaddingBefore(), childBlock->borderAndPaddingAfter());
if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
return;
@@ -2193,12 +2332,15 @@ void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& pos
// Make sure to update the block margins now for the grandchild box so that we're looking at current values.
if (grandchildBox->needsLayout()) {
grandchildBox->computeAndSetBlockDirectionMargins(this);
- grandchildBox->setMarginBeforeQuirk(grandchildBox->style()->marginBefore().quirk());
- grandchildBox->setMarginAfterQuirk(grandchildBox->style()->marginAfter().quirk());
+ if (grandchildBox->isRenderBlock()) {
+ RenderBlock* grandchildBlock = toRenderBlock(grandchildBox);
+ grandchildBlock->setHasMarginBeforeQuirk(grandchildBox->style()->hasMarginBeforeQuirk());
+ grandchildBlock->setHasMarginAfterQuirk(grandchildBox->style()->hasMarginAfterQuirk());
+ }
}
// Collapse the margin of the grandchild box with our own to produce an estimate.
- childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore);
+ childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
}
LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
@@ -2209,19 +2351,22 @@ LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const Margi
if (!marginInfo.canCollapseWithMarginBefore()) {
LayoutUnit positiveMarginBefore = 0;
LayoutUnit negativeMarginBefore = 0;
+ bool discardMarginBefore = false;
if (child->selfNeedsLayout()) {
// Try to do a basic estimation of how the collapse is going to go.
- marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore);
+ marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
} else {
// Use the cached collapsed margin values from a previous layout. Most of the time they
// will be right.
MarginValues marginValues = marginValuesForChild(child);
positiveMarginBefore = max(positiveMarginBefore, marginValues.positiveMarginBefore());
negativeMarginBefore = max(negativeMarginBefore, marginValues.negativeMarginBefore());
+ discardMarginBefore = mustDiscardMarginBeforeForChild(child);
}
// Collapse the result with our current margins.
- logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
+ if (!discardMarginBefore)
+ logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
}
// Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
@@ -2249,10 +2394,9 @@ LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const Margi
return logicalTopEstimate;
}
-LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart,
- RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage)
+LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, RenderRegion* region)
{
- LayoutUnit startPosition = startOffsetForContent(region, offsetFromLogicalTopOfFirstPage);
+ LayoutUnit startPosition = startOffsetForContent(region);
// Add in our start margin.
LayoutUnit oldPosition = startPosition + childMarginStart;
@@ -2260,9 +2404,9 @@ LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const Re
LayoutUnit blockOffset = logicalTopForChild(child);
if (region)
- blockOffset = max(blockOffset, blockOffset + (region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage));
+ blockOffset = max(blockOffset, blockOffset + (region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage()));
- LayoutUnit startOff = startOffsetForLine(blockOffset, false, region, offsetFromLogicalTopOfFirstPage, logicalHeightForChild(child));
+ LayoutUnit startOff = startOffsetForLine(blockOffset, false, region, logicalHeightForChild(child));
if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
if (childMarginStart < 0)
@@ -2274,7 +2418,7 @@ LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const Re
return newPosition - oldPosition;
}
-void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child)
+void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode applyDelta)
{
LayoutUnit startPosition = borderStart() + paddingStart();
if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
@@ -2287,27 +2431,34 @@ void RenderBlock::determineLogicalLeftPositionForChild(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() && containsFloats() && !inRenderFlowThread())
+ if (child->avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
- setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta);
+ setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
}
void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
{
if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
+ // Update the after side margin of the container to discard if the after margin of the last child also discards and we collapse with it.
+ // Don't update the max margin values because we won't need them anyway.
+ if (marginInfo.discardMargin()) {
+ setMustDiscardMarginAfter();
+ return;
+ }
+
// Update our max pos/neg bottom margins, since we collapsed our bottom margins
// with our children.
setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
- if (!marginInfo.marginAfterQuirk())
- setMarginAfterQuirk(false);
+ if (!marginInfo.hasMarginAfterQuirk())
+ setHasMarginAfterQuirk(false);
- if (marginInfo.marginAfterQuirk() && marginAfter() == 0)
+ if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
// 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.
- setMarginAfterQuirk(true);
+ setHasMarginAfterQuirk(true);
}
}
@@ -2316,11 +2467,8 @@ void RenderBlock::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit after
marginInfo.setAtAfterSideOfBlock(true);
// If we can't collapse with children then go ahead and add in the bottom margin.
- // Don't do this for ordinary anonymous blocks as only the enclosing box should add in
- // its margin.
- if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
- && (!isAnonymousBlock() || isAnonymousColumnsBlock() || isAnonymousColumnSpanBlock())
- && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk()))
+ if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
+ && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
setLogicalHeight(logicalHeight() + marginInfo.margin());
// Now add in our bottom border/padding.
@@ -2360,28 +2508,55 @@ void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop,
}
}
-void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
+void RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, RenderBox* child)
{
- if (gPercentHeightDescendantsMap) {
- if (TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this)) {
- TrackedRendererListHashSet::iterator end = descendants->end();
- for (TrackedRendererListHashSet::iterator it = descendants->begin(); it != end; ++it) {
- RenderBox* box = *it;
- while (box != this) {
- if (box->normalChildNeedsLayout())
- break;
- box->setChildNeedsLayout(true, MarkOnlyThis);
- box = box->containingBlock();
- ASSERT(box);
- if (!box)
- break;
- }
- }
+ // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
+ // an auto value. Add a method to determine this, so that we can avoid the relayout.
+ if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView()) || child->hasViewportPercentageLogicalHeight())
+ child->setChildNeedsLayout(true, MarkOnlyThis);
+
+ // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
+ if (relayoutChildren && child->needsPreferredWidthsRecalculation())
+ child->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
+}
+
+void RenderBlock::dirtyForLayoutFromPercentageHeightDescendants()
+{
+ if (!gPercentHeightDescendantsMap)
+ return;
+
+ TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this);
+ if (!descendants)
+ return;
+
+ TrackedRendererListHashSet::iterator end = descendants->end();
+ for (TrackedRendererListHashSet::iterator it = descendants->begin(); it != end; ++it) {
+ RenderBox* box = *it;
+ while (box != this) {
+ if (box->normalChildNeedsLayout())
+ break;
+ box->setChildNeedsLayout(true, MarkOnlyThis);
+
+ // If the width of an image is affected by the height of a child (e.g., an image with an aspect ratio),
+ // then we have to dirty preferred widths, since even enclosing blocks can become dirty as a result.
+ // (A horizontal flexbox that contains an inline image wrapped in an anonymous block for example.)
+ if (box->hasAspectRatio())
+ box->setPreferredLogicalWidthsDirty(true);
+
+ box = box->containingBlock();
+ ASSERT(box);
+ if (!box)
+ break;
}
}
+}
+
+void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
+{
+ dirtyForLayoutFromPercentageHeightDescendants();
- LayoutUnit beforeEdge = borderBefore() + paddingBefore();
- LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
+ LayoutUnit beforeEdge = borderAndPaddingBefore();
+ LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
setLogicalHeight(beforeEdge);
@@ -2409,20 +2584,18 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloa
if (childToExclude == child)
continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
- // Make sure we layout children if they need it.
- // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
- // an auto value. Add a method to determine this, so that we can avoid the relayout.
- if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView()))
- child->setChildNeedsLayout(true, MarkOnlyThis);
-
- // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
- if (relayoutChildren && child->needsPreferredWidthsRecalculation())
- child->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
+ updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
- // Handle the four types of special elements first. These include positioned content, floating content, compacts and
- // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
- if (handleSpecialChild(child, marginInfo))
+ if (child->isOutOfFlowPositioned()) {
+ child->containingBlock()->insertPositionedObject(child);
+ adjustPositionedBlock(child, marginInfo);
continue;
+ }
+ if (child->isFloating()) {
+ insertFloatingObject(child);
+ adjustFloatingBlock(marginInfo);
+ continue;
+ }
// Lay out the child.
layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
@@ -2441,13 +2614,6 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay
// The child is a normal flow object. Compute the margins we will use for collapsing now.
child->computeAndSetBlockDirectionMargins(this);
- // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE.
- RenderStyle* childStyle = child->style();
- if (childStyle->marginBeforeCollapse() == MSEPARATE) {
- marginInfo.setAtBeforeSideOfBlock(false);
- marginInfo.clearMargin();
- }
-
// Try to guess our correct logical top position. In most cases this guess will
// be correct. Only if we're wrong (when we compute the real logical top position)
// will we have to potentially relayout.
@@ -2468,6 +2634,14 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay
bool markDescendantsWithFloats = false;
if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
markDescendantsWithFloats = true;
+#if ENABLE(SUBPIXEL_LAYOUT)
+ else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
+ // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
+ // very large elements. If it does the comparison with oldLogicalTop might yield a
+ // false negative as adding and removing margins, borders etc from a saturated number
+ // might yield incorrect results. If this is the case always mark for layout.
+ markDescendantsWithFloats = true;
+#endif
else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
// If an element might be affected by the presence of floats, then always mark it for
// layout.
@@ -2511,7 +2685,7 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay
// Now we have a final top position. See if it really does end up being different from our estimate.
// clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
// when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
- if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout()) {
+ if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout() || (paginated && childRenderBlock && childRenderBlock->shouldBreakAtLineToAvoidWidow())) {
if (child->shrinkToAvoidFloats()) {
// The child's width depends on the line width.
// When the child shifts to clear an item, its width can
@@ -2537,11 +2711,11 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay
marginInfo.setAtBeforeSideOfBlock(false);
// Now place the child in the correct left position
- determineLogicalLeftPositionForChild(child);
+ determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
// Update our height now that the child has been placed in the correct position.
setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
- if (childStyle->marginAfterCollapse() == MSEPARATE) {
+ if (mustSeparateMarginAfterForChild(child)) {
setLogicalHeight(logicalHeight() + marginAfterForChild(child));
marginInfo.clearMargin();
}
@@ -2621,16 +2795,23 @@ bool RenderBlock::simplifiedLayout()
simplifiedNormalFlowLayout();
// Lay out our positioned objects if our positioned child bit is set.
- if (posChildNeedsLayout())
- layoutPositionedObjects(false);
+ // Also, if an absolute position element inside a relative positioned container moves, and the absolute element has a fixed position
+ // child, neither the fixed element nor its container learn of the movement since posChildNeedsLayout() is only marked as far as the
+ // relative positioned container. So if we can have fixed pos objects in our positioned objects list check if any of them
+ // are statically positioned and thus need to move with their absolute ancestors.
+ bool canContainFixedPosObjects = canContainFixedPositionObjects();
+ if (posChildNeedsLayout() || canContainFixedPosObjects)
+ layoutPositionedObjects(false, !posChildNeedsLayout() && canContainFixedPosObjects);
// Recompute our overflow information.
// FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
// updating our overflow if we either used to have overflow or if the new temporary object has overflow.
// For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
// lowestPosition on every relayout so it's not a regression.
- m_overflow.clear();
- computeOverflow(clientLogicalBottom(), true);
+ // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during
+ // simplifiedLayout, we cache the value in m_overflow.
+ LayoutUnit oldClientAfterEdge = hasRenderOverflow() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom();
+ computeOverflow(oldClientAfterEdge, true);
statePusher.pop();
@@ -2642,7 +2823,38 @@ bool RenderBlock::simplifiedLayout()
return true;
}
-void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
+void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderObject* child)
+{
+ if (child->style()->position() != FixedPosition)
+ return;
+
+ bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontalWritingMode());
+ bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontalWritingMode());
+ if (!hasStaticBlockPosition && !hasStaticInlinePosition)
+ return;
+
+ RenderObject* o = child->parent();
+ while (o && !o->isRenderView() && o->style()->position() != AbsolutePosition)
+ o = o->parent();
+ if (o->style()->position() != AbsolutePosition)
+ return;
+
+ RenderBox* box = toRenderBox(child);
+ if (hasStaticInlinePosition) {
+ LogicalExtentComputedValues computedValues;
+ box->computeLogicalWidthInRegion(computedValues);
+ LayoutUnit newLeft = computedValues.m_position;
+ if (newLeft != box->logicalLeft())
+ child->setChildNeedsLayout(true, MarkOnlyThis);
+ } else if (hasStaticBlockPosition) {
+ LayoutUnit oldTop = box->logicalTop();
+ box->updateLogicalHeight();
+ if (box->logicalTop() != oldTop)
+ child->setChildNeedsLayout(true, MarkOnlyThis);
+ }
+}
+
+void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly)
{
TrackedRendererListHashSet* positionedDescendants = positionedObjects();
if (!positionedDescendants)
@@ -2655,6 +2867,16 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
TrackedRendererListHashSet::iterator end = positionedDescendants->end();
for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
r = *it;
+
+ // A fixed position element with an absolute positioned ancestor has no way of knowing if the latter has changed position. So
+ // if this is a fixed position element, mark it for layout if it has an abspos ancestor and needs to move with that ancestor, i.e.
+ // it has static position.
+ markFixedPositionObjectForLayoutIfNeeded(r);
+ if (fixedPositionObjectsOnly) {
+ r->layoutIfNeeded();
+ continue;
+ }
+
// When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
// 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
@@ -2718,7 +2940,7 @@ void RenderBlock::markForPaginationRelayoutIfNeeded()
if (needsLayout())
return;
- if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset()))
+ if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset()) || shouldBreakAtLineToAvoidWidow())
setChildNeedsLayout(true, MarkOnlyThis);
}
@@ -2741,7 +2963,7 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
// condition is replaced with being a descendant of us.
if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->shouldPaint()) && !r->m_renderer->hasSelfPaintingLayer()) {
r->m_renderer->repaint();
- r->m_renderer->repaintOverhangingFloats();
+ r->m_renderer->repaintOverhangingFloats(false);
}
}
}
@@ -2772,7 +2994,7 @@ void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
// 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) && paintInfo.shouldPaintWithinRoot(this))
+ if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this) && !paintInfo.paintRootBackgroundOnly())
layer()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
}
@@ -2786,7 +3008,7 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& pain
EBorderStyle ruleStyle = style()->columnRuleStyle();
LayoutUnit ruleThickness = style()->columnRuleWidth();
LayoutUnit colGap = columnGap();
- bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleThickness <= colGap;
+ bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
if (!renderRule)
return;
@@ -2831,10 +3053,10 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& pain
bool topToBottom = !style()->isFlippedBlocksWritingMode() ^ colInfo->progressionIsReversed();
LayoutUnit ruleLeft = isHorizontalWritingMode()
? borderLeft() + paddingLeft()
- : colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter());
+ : colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderAndPaddingBefore() : borderAndPaddingAfter());
LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness;
LayoutUnit ruleTop = isHorizontalWritingMode()
- ? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter())
+ ? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderAndPaddingBefore() : borderAndPaddingAfter())
: borderStart() + paddingStart();
LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight();
LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
@@ -2864,6 +3086,36 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& pain
}
}
+LayoutUnit RenderBlock::initialBlockOffsetForPainting() const
+{
+ ColumnInfo* colInfo = columnInfo();
+ LayoutUnit result = 0;
+ if (colInfo->progressionAxis() == ColumnInfo::BlockAxis && colInfo->progressionIsReversed()) {
+ LayoutRect colRect = columnRectAt(colInfo, 0);
+ result = isHorizontalWritingMode() ? colRect.y() : colRect.x();
+ result -= borderAndPaddingBefore();
+ if (style()->isFlippedBlocksWritingMode())
+ result = -result;
+ }
+ return result;
+}
+
+LayoutUnit RenderBlock::blockDeltaForPaintingNextColumn() const
+{
+ ColumnInfo* colInfo = columnInfo();
+ LayoutUnit blockDelta = -colInfo->columnHeight();
+ LayoutUnit colGap = columnGap();
+ if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
+ if (!colInfo->progressionIsReversed())
+ blockDelta = colGap;
+ else
+ blockDelta -= (colInfo->columnHeight() + colGap);
+ }
+ if (style()->isFlippedBlocksWritingMode())
+ blockDelta = -blockDelta;
+ return blockDelta;
+}
+
void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
{
// We need to do multiple passes, breaking up our child painting into strips.
@@ -2872,20 +3124,16 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& p
unsigned colCount = columnCount(colInfo);
if (!colCount)
return;
- LayoutUnit currLogicalTopOffset = 0;
LayoutUnit colGap = columnGap();
+ LayoutUnit currLogicalTopOffset = initialBlockOffsetForPainting();
+ LayoutUnit blockDelta = blockDeltaForPaintingNextColumn();
for (unsigned i = 0; i < colCount; i++) {
// For each rect, we clip to the rect, and then we adjust our coords.
LayoutRect colRect = columnRectAt(colInfo, i);
flipForWritingMode(colRect);
+
LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
- if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
- if (isHorizontalWritingMode())
- offset.expand(0, colRect.y() - borderTop() - paddingTop());
- else
- offset.expand(colRect.x() - borderLeft() - paddingLeft(), 0);
- }
colRect.moveBy(paintOffset);
PaintInfo info(paintInfo);
info.rect.intersect(pixelSnappedIntRect(colRect));
@@ -2913,12 +3161,7 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& p
else
paintContents(info, adjustedPaintOffset);
}
-
- LayoutUnit blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
- if (style()->isFlippedBlocksWritingMode())
- currLogicalTopOffset += blockDelta;
- else
- currLogicalTopOffset -= blockDelta;
+ currLogicalTopOffset += blockDelta;
}
}
@@ -2939,7 +3182,7 @@ void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOf
// We don't paint our own background, but we do let the kids paint their backgrounds.
PaintInfo paintInfoForChild(paintInfo);
paintInfoForChild.phase = newPhase;
- paintInfoForChild.updatePaintingRootForChildren(this);
+ paintInfoForChild.updateSubtreePaintRootForChildren(this);
// FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
// NSViews. Do not add any more code for this.
@@ -3026,7 +3269,7 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs
if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
if (hasBoxDecorations())
paintBoxDecorations(paintInfo, paintOffset);
- if (hasColumns())
+ if (hasColumns() && !paintInfo.paintRootBackgroundOnly())
paintColumnRules(paintInfo, paintOffset);
}
@@ -3036,7 +3279,7 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs
}
// We're done. We don't bother painting any children.
- if (paintPhase == PaintPhaseBlockBackground)
+ if (paintPhase == PaintPhaseBlockBackground || paintInfo.paintRootBackgroundOnly())
return;
// Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
@@ -3068,15 +3311,12 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs
// 5. paint outline.
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
- paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
+ paintOutline(paintInfo, LayoutRect(paintOffset, size()));
// 6. paint continuation outlines.
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
RenderInline* inlineCont = inlineElementContinuation();
- // FIXME: For now, do not add continuations for outline painting by our containing block if we are a relative positioned
- // anonymous block (i.e. have our own layer). This is because a block depends on renderers in its continuation table being
- // in the same layer.
- if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE && !hasLayer()) {
+ if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
RenderBlock* cb = containingBlock();
@@ -3088,10 +3328,13 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffs
}
}
- if (!inlineEnclosedInSelfPaintingLayer)
+ // Do not add continuations for outline painting by our containing block if we are a relative positioned
+ // anonymous block (i.e. have our own layer), paint them straightaway instead. This is because a block depends on renderers in its continuation table being
+ // in the same layer.
+ if (!inlineEnclosedInSelfPaintingLayer && !hasLayer())
cb->addContinuationWithOutline(inlineRenderer);
- else if (!inlineRenderer->firstLineBox())
- inlineRenderer->paintOutline(paintInfo.context, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
+ else if (!inlineRenderer->firstLineBox() || (!inlineEnclosedInSelfPaintingLayer && hasLayer()))
+ inlineRenderer->paintOutline(paintInfo, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
}
paintContinuationOutlines(paintInfo, paintOffset);
}
@@ -3115,7 +3358,7 @@ LayoutPoint RenderBlock::flipFloatForWritingModeForChild(const FloatingObject* c
// case.
if (isHorizontalWritingMode())
return LayoutPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child));
- return LayoutPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
+ return LayoutPoint(point.x() + width() - child->renderer()->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
}
void RenderBlock::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
@@ -3180,7 +3423,7 @@ void RenderBlock::addContinuationWithOutline(RenderInline* flow)
ListHashSet<RenderInline*>* continuations = table->get(this);
if (!continuations) {
continuations = new ListHashSet<RenderInline*>;
- table->set(this, continuations);
+ table->set(this, adoptPtr(continuations));
}
continuations->add(flow);
@@ -3205,7 +3448,7 @@ void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint&
if (table->isEmpty())
return;
- ListHashSet<RenderInline*>* continuations = table->get(this);
+ OwnPtr<ListHashSet<RenderInline*> > continuations = table->take(this);
if (!continuations)
return;
@@ -3219,12 +3462,8 @@ void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint&
for ( ; block && block != this; block = block->containingBlock())
accumulatedPaintOffset.moveBy(block->location());
ASSERT(block);
- flow->paintOutline(info.context, accumulatedPaintOffset);
+ flow->paintOutline(info, accumulatedPaintOffset);
}
-
- // Delete
- delete continuations;
- table->remove(this);
}
bool RenderBlock::shouldPaintSelectionGaps() const
@@ -3234,8 +3473,9 @@ bool RenderBlock::shouldPaintSelectionGaps() const
bool RenderBlock::isSelectionRoot() const
{
- if (!node())
+ if (isPseudoElement())
return false;
+ ASSERT(node() || isAnonymous());
// FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
if (isTable())
@@ -3264,30 +3504,31 @@ GapRects RenderBlock::selectionGapRectsForRepaint(const RenderLayerModelObject*
if (!shouldPaintSelectionGaps())
return GapRects();
- // FIXME: this is broken with transforms
TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
- mapLocalToContainer(repaintContainer, transformState);
+ mapLocalToContainer(repaintContainer, transformState, ApplyContainerFlip | UseTransforms);
LayoutPoint offsetFromRepaintContainer = roundedLayoutPoint(transformState.mappedPoint());
if (hasOverflowClip())
offsetFromRepaintContainer -= scrolledContentOffset();
+ LogicalSelectionOffsetCaches cache(this);
LayoutUnit lastTop = 0;
- LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
- LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
+ LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop, cache);
+ LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop, cache);
- return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
+ return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight, cache);
}
void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
+ LogicalSelectionOffsetCaches cache(this);
LayoutUnit lastTop = 0;
- LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
- LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
+ LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop, cache);
+ LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop, cache);
GraphicsContextStateSaver stateSaver(*paintInfo.context);
- LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
+ LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, cache, &paintInfo);
if (!gapRectsBounds.isEmpty()) {
if (RenderLayer* layer = enclosingLayer()) {
gapRectsBounds.moveBy(-paintOffset);
@@ -3339,7 +3580,7 @@ LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPh
}
GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
+ LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
// IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
// Clip out floating and positioned objects when painting selection gaps.
@@ -3376,25 +3617,27 @@ GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& r
if (hasColumns() || hasTransform() || style()->columnSpan()) {
// FIXME: We should learn how to gap fill multiple columns and transforms eventually.
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
- lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
- lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
+ lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
+ lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
return result;
}
if (childrenInline())
- result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
+ result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, cache, paintInfo);
else
- result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
+ result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, cache, 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 && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
- result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
- logicalHeight(), paintInfo));
+ if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd)) {
+ result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
+ lastLogicalTop, lastLogicalLeft, lastLogicalRight, logicalHeight(), cache, paintInfo));
+ }
+
return result;
}
GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
+ LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
GapRects result;
@@ -3405,8 +3648,8 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPo
// Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
// case.
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
- lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
- lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
+ lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
+ lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
}
return result;
}
@@ -3422,15 +3665,14 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPo
if (!containsStart && !lastSelectedLine &&
selectionState() != SelectionStart && selectionState() != SelectionBoth)
- result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
- selTop, paintInfo));
+ result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
LayoutRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
|| (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
- result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo));
+ result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
lastSelectedLine = curr;
}
@@ -3442,20 +3684,25 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPo
if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
// Go ahead and update our lastY to be the bottom of the last selected line.
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
- lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
- lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
+ lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
+ lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
}
return result;
}
GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
+ LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
GapRects result;
// Go ahead and jump right to the first block child that contains some selected objects.
RenderBox* curr;
for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
+
+ if (!curr)
+ return result;
+
+ LogicalSelectionOffsetCaches childCache(this, cache);
for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
SelectionState childState = curr->selectionState();
@@ -3477,10 +3724,11 @@ GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoi
bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
if (fillBlockGaps) {
// We need to fill the vertical gap above this object.
- if (childState == SelectionEnd || childState == SelectionInside)
+ if (childState == SelectionEnd || childState == SelectionInside) {
// Fill the gap above the object.
- result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
- curr->logicalTop(), paintInfo));
+ result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock,
+ lastLogicalTop, lastLogicalLeft, lastLogicalRight, curr->logicalTop(), cache, paintInfo));
+ }
// Only fill side gaps for objects that paint their own selection if we know for sure the selection is going to extend all the way *past*
// our object. We know this if the selection did not end inside our object.
@@ -3492,26 +3740,27 @@ GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoi
getSelectionGapInfo(childState, leftGap, rightGap);
if (leftGap)
- result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
+ result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), cache, paintInfo));
if (rightGap)
- result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
+ result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), cache, paintInfo));
// Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
// they can without bumping into floating or positioned objects. Ideally they will go right up
// to the border of the root selection block.
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom();
- lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
- lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
- } else if (childState != SelectionNone)
+ lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom(), cache);
+ lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom(), cache);
+ } else if (childState != SelectionNone) {
// We must be a block that has some selected object inside it. Go ahead and recur.
result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
- lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
+ lastLogicalTop, lastLogicalLeft, lastLogicalRight, childCache, paintInfo));
+ }
}
return result;
}
LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo)
+ LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
LayoutUnit logicalTop = lastLogicalTop;
LayoutUnit logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop;
@@ -3519,8 +3768,8 @@ LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPo
return LayoutRect();
// Get the selection offsets for the bottom of the gap
- LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
- LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
+ LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom, cache));
+ LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom, cache));
LayoutUnit logicalWidth = logicalRight - logicalLeft;
if (logicalWidth <= 0)
return LayoutRect();
@@ -3532,11 +3781,12 @@ LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPo
}
LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
+ RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
- LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
- LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalLeft), min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
+ LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop, cache), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight, cache));
+ LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalLeft),
+ min(logicalRightSelectionOffset(rootBlock, logicalTop, cache), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight, cache)));
LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
if (rootBlockLogicalWidth <= 0)
return LayoutRect();
@@ -3548,11 +3798,12 @@ LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const La
}
LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
+ RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
- LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalRight), max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
- LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
+ LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalRight),
+ max(logicalLeftSelectionOffset(rootBlock, logicalTop, cache), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight, cache)));
+ LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop, cache), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight, cache));
LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
if (rootBlockLogicalWidth <= 0)
return LayoutRect();
@@ -3574,37 +3825,45 @@ void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool&
(state == RenderObject::SelectionEnd && !ltr);
}
-LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
+LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches& cache)
{
LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false);
if (logicalLeft == logicalLeftOffsetForContent()) {
- if (rootBlock != this)
- // The border can potentially be further extended by our containingBlock().
- return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
+ if (rootBlock != this) // The border can potentially be further extended by our containingBlock().
+ return cache.containingBlockInfo(this).logicalLeftSelectionOffset(rootBlock, position + logicalTop());
return logicalLeft;
} else {
RenderBlock* cb = this;
+ const LogicalSelectionOffsetCaches* currentCache = &cache;
while (cb != rootBlock) {
logicalLeft += cb->logicalLeft();
- cb = cb->containingBlock();
+
+ ASSERT(currentCache);
+ const LogicalSelectionOffsetCaches::ContainingBlockInfo& info = currentCache->containingBlockInfo(cb);
+ cb = info.block();
+ currentCache = info.cache();
}
}
return logicalLeft;
}
-LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
+LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position, const LogicalSelectionOffsetCaches& cache)
{
LayoutUnit logicalRight = logicalRightOffsetForLine(position, false);
if (logicalRight == logicalRightOffsetForContent()) {
- if (rootBlock != this)
- // The border can potentially be further extended by our containingBlock().
- return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
+ if (rootBlock != this) // The border can potentially be further extended by our containingBlock().
+ return cache.containingBlockInfo(this).logicalRightSelectionOffset(rootBlock, position + logicalTop());
return logicalRight;
} else {
RenderBlock* cb = this;
+ const LogicalSelectionOffsetCaches* currentCache = &cache;
while (cb != rootBlock) {
logicalRight += cb->logicalLeft();
- cb = cb->containingBlock();
+
+ ASSERT(currentCache);
+ const LogicalSelectionOffsetCaches::ContainingBlockInfo& info = currentCache->containingBlockInfo(cb);
+ cb = info.block();
+ currentCache = info.cache();
}
}
return logicalRight;
@@ -3652,7 +3911,7 @@ void RenderBlock::insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDe
TrackedRendererListHashSet* descendantSet = descendantsMap->get(this);
if (!descendantSet) {
descendantSet = new TrackedRendererListHashSet;
- descendantsMap->set(this, descendantSet);
+ descendantsMap->set(this, adoptPtr(descendantSet));
}
bool added = descendantSet->add(descendant).isNewEntry;
if (!added) {
@@ -3664,7 +3923,7 @@ void RenderBlock::insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDe
HashSet<RenderBlock*>* containerSet = containerMap->get(descendant);
if (!containerSet) {
containerSet = new HashSet<RenderBlock*>;
- containerMap->set(descendant, containerSet);
+ containerMap->set(descendant, adoptPtr(containerSet));
}
ASSERT(!containerSet->contains(this));
containerSet->add(this);
@@ -3675,7 +3934,7 @@ void RenderBlock::removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDe
if (!descendantsMap)
return;
- HashSet<RenderBlock*>* containerSet = containerMap->take(descendant);
+ OwnPtr<HashSet<RenderBlock*> > containerSet = containerMap->take(descendant);
if (!containerSet)
return;
@@ -3688,19 +3947,16 @@ void RenderBlock::removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDe
// their ancestor chain before being moved. See webkit bug 93766.
// ASSERT(descendant->isDescendantOf(container));
- TrackedRendererListHashSet* descendantSet = descendantsMap->get(container);
- ASSERT(descendantSet);
- if (!descendantSet)
+ TrackedDescendantsMap::iterator descendantsMapIterator = descendantsMap->find(container);
+ ASSERT(descendantsMapIterator != descendantsMap->end());
+ if (descendantsMapIterator == descendantsMap->end())
continue;
+ TrackedRendererListHashSet* descendantSet = descendantsMapIterator->value.get();
ASSERT(descendantSet->contains(descendant));
descendantSet->remove(descendant);
- if (descendantSet->isEmpty()) {
- descendantsMap->remove(container);
- delete descendantSet;
- }
+ if (descendantSet->isEmpty())
+ descendantsMap->remove(descendantsMapIterator);
}
-
- delete containerSet;
}
TrackedRendererListHashSet* RenderBlock::positionedObjects() const
@@ -3774,7 +4030,7 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
// Create the list of special objects if we don't aleady have one
if (!m_floatingObjects)
- m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
+ createFloatingObjects();
else {
// Don't insert the object again if it's already in the list
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
@@ -3800,8 +4056,14 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
o->updateLogicalWidth();
o->computeAndSetBlockDirectionMargins(this);
}
+
setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o));
+#if ENABLE(CSS_SHAPES)
+ if (ShapeOutsideInfo* shapeOutside = o->shapeOutsideInfo())
+ shapeOutside->setShapeSize(logicalWidthForChild(o), logicalHeightForChild(o));
+#endif
+
newObj->setShouldPaint(!o->hasSelfPaintingLayer()); // If a layer exists, the float will paint itself. Otherwise someone else will.
newObj->setIsDescendant(true);
newObj->m_renderer = o;
@@ -3851,7 +4113,7 @@ void RenderBlock::removeFloatingObject(RenderBox* o)
void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
{
- if (!m_floatingObjects)
+ if (!containsFloats())
return;
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
@@ -3869,21 +4131,37 @@ void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logi
LayoutPoint RenderBlock::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset) const
{
RenderBox* childBox = floatingObject->renderer();
- LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
+ LayoutUnit logicalRightOffset; // Constant part of right offset.
+#if ENABLE(CSS_SHAPES)
+ // FIXME Bug 102948: This only works for shape outside directly set on this block.
+ ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo();
+ // FIXME Bug 102846: Take into account the height of the content. The offset should be
+ // equal to the maximum segment length.
+ if (shapeInsideInfo && shapeInsideInfo->hasSegments() && shapeInsideInfo->segments().size() == 1) {
+ // FIXME Bug 102949: Add support for shapes with multipe segments.
+
+ // The segment offsets are relative to the content box.
+ logicalRightOffset = logicalLeftOffset + shapeInsideInfo->segments()[0].logicalRight;
+ logicalLeftOffset += shapeInsideInfo->segments()[0].logicalLeft;
+ } else
+#endif
+ logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset);
+
LayoutUnit floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
LayoutUnit floatLogicalLeft;
+ bool insideFlowThread = flowThreadContainingBlock();
+
if (childBox->style()->floating() == LeftFloat) {
LayoutUnit heightRemainingLeft = 1;
LayoutUnit heightRemainingRight = 1;
- floatLogicalLeft = logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
- // FIXME: LayoutUnit::epsilon is probably only necessary here due to lost precision elsewhere https://bugs.webkit.org/show_bug.cgi?id=94000
- while (logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft + LayoutUnit::epsilon() < floatLogicalWidth) {
+ floatLogicalLeft = logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
+ while (logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
- floatLogicalLeft = logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
- if (inRenderFlowThread()) {
+ floatLogicalLeft = logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
+ if (insideFlowThread) {
// Have to re-evaluate all of our offsets, since they may have changed.
logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
@@ -3894,12 +4172,11 @@ LayoutPoint RenderBlock::computeLogicalLocationForFloat(const FloatingObject* fl
} else {
LayoutUnit heightRemainingLeft = 1;
LayoutUnit heightRemainingRight = 1;
- floatLogicalLeft = logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
- // FIXME: LayoutUnit::epsilon is probably only necessary here due to lost precision elsewhere https://bugs.webkit.org/show_bug.cgi?id=94000
- while (floatLogicalLeft - logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) + LayoutUnit::epsilon() < floatLogicalWidth) {
+ floatLogicalLeft = logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
+ while (floatLogicalLeft - logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
- floatLogicalLeft = logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
- if (inRenderFlowThread()) {
+ floatLogicalLeft = logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
+ if (insideFlowThread) {
// Have to re-evaluate all of our offsets, since they may have changed.
logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
@@ -3971,6 +4248,7 @@ bool RenderBlock::positionNewFloats()
LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
+
setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
@@ -4000,6 +4278,7 @@ bool RenderBlock::positionNewFloats()
floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
+
setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
@@ -4010,6 +4289,7 @@ bool RenderBlock::positionNewFloats()
}
setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
+
setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
m_floatingObjects->addPlacedObject(floatingObject);
@@ -4129,7 +4409,7 @@ inline void RenderBlock::FloatIntervalSearchAdapter<FloatTypeValue>::collectIfNe
return;
// All the objects returned from the tree should be already placed.
- ASSERT(r->isPlaced() && rangesIntersect(m_renderer->pixelSnappedLogicalTopForFloat(r), m_renderer->pixelSnappedLogicalBottomForFloat(r), m_lowValue, m_highValue));
+ ASSERT(r->isPlaced() && rangesIntersect(m_renderer->logicalTopForFloat(r), m_renderer->logicalBottomForFloat(r), m_lowValue, m_highValue));
if (FloatTypeValue == FloatingObject::FloatLeft
&& m_renderer->logicalRightForFloat(r) > m_offset) {
@@ -4144,6 +4424,10 @@ inline void RenderBlock::FloatIntervalSearchAdapter<FloatTypeValue>::collectIfNe
if (m_heightRemaining)
*m_heightRemaining = m_renderer->logicalBottomForFloat(r) - m_lowValue;
}
+
+#if ENABLE(CSS_SHAPES)
+ m_last = r;
+#endif
}
LayoutUnit RenderBlock::textIndentOffset() const
@@ -4157,27 +4441,30 @@ LayoutUnit RenderBlock::textIndentOffset() const
return minimumValueForLength(style()->textIndent(), cw, renderView);
}
-LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region) const
{
LayoutUnit logicalLeftOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
- if (!inRenderFlowThread())
+ if (!region)
return logicalLeftOffset;
- LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage);
+ LayoutRect boxRect = borderBoxRectInRegion(region);
return logicalLeftOffset + (isHorizontalWritingMode() ? boxRect.x() : boxRect.y());
}
-LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
+LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region) const
{
LayoutUnit logicalRightOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
logicalRightOffset += availableLogicalWidth();
- if (!inRenderFlowThread())
+ if (!region)
return logicalRightOffset;
- LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage);
+ LayoutRect boxRect = borderBoxRectInRegion(region);
return logicalRightOffset - (logicalWidth() - (isHorizontalWritingMode() ? boxRect.maxX() : boxRect.maxY()));
}
-LayoutUnit RenderBlock::logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining, LayoutUnit logicalHeight) const
+LayoutUnit RenderBlock::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const
{
+#if !ENABLE(CSS_SHAPES)
+ UNUSED_PARAM(offsetMode);
+#endif
LayoutUnit left = fixedOffset;
if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) {
if (heightRemaining)
@@ -4185,8 +4472,25 @@ LayoutUnit RenderBlock::logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUn
FloatIntervalSearchAdapter<FloatingObject::FloatLeft> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), left, heightRemaining);
m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
+
+#if ENABLE(CSS_SHAPES)
+ const FloatingObject* lastFloat = adapter.lastFloat();
+ if (offsetMode == ShapeOutsideFloatShapeOffset && lastFloat) {
+ if (ShapeOutsideInfo* shapeOutside = lastFloat->renderer()->shapeOutsideInfo()) {
+ shapeOutside->computeSegmentsForContainingBlockLine(logicalTop, logicalTopForFloat(lastFloat), logicalHeight);
+ left += shapeOutside->rightSegmentMarginBoxDelta();
+ }
+ }
+#endif
}
+ return left;
+}
+
+LayoutUnit RenderBlock::adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const
+{
+ LayoutUnit left = offsetFromFloats;
+
if (applyTextIndent && style()->isLeftToRightDirection())
left += textIndentOffset();
@@ -4223,8 +4527,11 @@ LayoutUnit RenderBlock::logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUn
return left;
}
-LayoutUnit RenderBlock::logicalRightOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining, LayoutUnit logicalHeight) const
+LayoutUnit RenderBlock::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const
{
+#if !ENABLE(CSS_SHAPES)
+ UNUSED_PARAM(offsetMode);
+#endif
LayoutUnit right = fixedOffset;
if (m_floatingObjects && m_floatingObjects->hasRightObjects()) {
if (heightRemaining)
@@ -4233,8 +4540,26 @@ LayoutUnit RenderBlock::logicalRightOffsetForLine(LayoutUnit logicalTop, LayoutU
LayoutUnit rightFloatOffset = fixedOffset;
FloatIntervalSearchAdapter<FloatingObject::FloatRight> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), rightFloatOffset, heightRemaining);
m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
+
+#if ENABLE(CSS_SHAPES)
+ const FloatingObject* lastFloat = adapter.lastFloat();
+ if (offsetMode == ShapeOutsideFloatShapeOffset && lastFloat) {
+ if (ShapeOutsideInfo* shapeOutside = lastFloat->renderer()->shapeOutsideInfo()) {
+ shapeOutside->computeSegmentsForContainingBlockLine(logicalTop, logicalTopForFloat(lastFloat), logicalHeight);
+ rightFloatOffset += shapeOutside->leftSegmentMarginBoxDelta();
+ }
+ }
+#endif
+
right = min(right, rightFloatOffset);
}
+
+ return right;
+}
+
+LayoutUnit RenderBlock::adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const
+{
+ LayoutUnit right = offsetFromFloats;
if (applyTextIndent && !style()->isLeftToRightDirection())
right -= textIndentOffset();
@@ -4509,8 +4834,7 @@ LayoutUnit RenderBlock::addOverhangingFloats(RenderBlock* child, bool makeChildP
// We create the floating object list lazily.
if (!m_floatingObjects)
- m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
-
+ createFloatingObjects();
m_floatingObjects->add(floatingObj);
}
} else {
@@ -4582,7 +4906,7 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, LayoutUnit logicalLeftOf
// We create the floating object list lazily.
if (!m_floatingObjects)
- m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
+ createFloatingObjects();
m_floatingObjects->add(floatingObj);
}
}
@@ -4602,7 +4926,7 @@ bool RenderBlock::containsFloat(RenderBox* renderer) const
void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
{
- if (!everHadLayout())
+ if (!everHadLayout() && !containsFloats())
return;
MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
@@ -4679,7 +5003,7 @@ LayoutUnit RenderBlock::getClearDelta(RenderBox* child, LayoutUnit logicalTop)
return newLogicalTop - logicalTop;
RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
- LayoutRect borderBox = child->borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage() + logicalTopForChild(child), DoNotCacheRenderBoxRegionInfo);
+ LayoutRect borderBox = child->borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
// FIXME: None of this is right for perpendicular writing-mode children.
@@ -4691,7 +5015,7 @@ LayoutUnit RenderBlock::getClearDelta(RenderBox* child, LayoutUnit logicalTop)
child->setLogicalTop(newLogicalTop);
child->updateLogicalWidth();
region = regionAtBlockOffset(logicalTopForChild(child));
- borderBox = child->borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage() + logicalTopForChild(child), DoNotCacheRenderBoxRegionInfo);
+ borderBox = child->borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
child->setLogicalTop(childOldLogicalTop);
@@ -4768,7 +5092,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
// Hit test contents if we don't have columns.
if (!hasColumns()) {
if (hitTestContents(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
- updateHitTestResult(result, locationInContainer.point() - localOffset);
+ updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
return true;
}
if (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, toLayoutPoint(scrolledOffset)))
@@ -4779,6 +5103,15 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
}
}
+ // Check if the point is outside radii.
+ if (!isRenderView() && style()->hasBorderRadius()) {
+ LayoutRect borderRect = borderBoxRect();
+ borderRect.moveBy(adjustedLocation);
+ RoundedRect border = style()->getRoundedBorderFor(borderRect, view());
+ if (!locationInContainer.intersects(border))
+ return false;
+ }
+
// Now hit test our background
if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
LayoutRect boundsRect(adjustedLocation, size());
@@ -4833,7 +5166,10 @@ public:
{
int colCount = m_colInfo->columnCount();
m_colIndex = colCount - 1;
- m_currLogicalTopOffset = colCount * m_colInfo->columnHeight() * m_direction;
+
+ m_currLogicalTopOffset = m_block.initialBlockOffsetForPainting();
+ m_currLogicalTopOffset = colCount * m_block.blockDeltaForPaintingNextColumn();
+
update();
}
@@ -4851,12 +5187,6 @@ public:
{
LayoutUnit currLogicalLeftOffset = (m_isHorizontal ? m_colRect.x() : m_colRect.y()) - m_logicalLeft;
offset += m_isHorizontal ? LayoutSize(currLogicalLeftOffset, m_currLogicalTopOffset) : LayoutSize(m_currLogicalTopOffset, currLogicalLeftOffset);
- if (m_colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
- if (m_isHorizontal)
- offset.expand(0, m_colRect.y() - m_block.borderTop() - m_block.paddingTop());
- else
- offset.expand(m_colRect.x() - m_block.borderLeft() - m_block.paddingLeft(), 0);
- }
}
private:
@@ -4864,10 +5194,9 @@ private:
{
if (m_colIndex < 0)
return;
-
m_colRect = m_block.columnRectAt(const_cast<ColumnInfo*>(m_colInfo), m_colIndex);
m_block.flipForWritingMode(m_colRect);
- m_currLogicalTopOffset -= (m_isHorizontal ? m_colRect.height() : m_colRect.width()) * m_direction;
+ m_currLogicalTopOffset -= m_block.blockDeltaForPaintingNextColumn();
}
const RenderBlock& m_block;
@@ -4943,22 +5272,22 @@ Position RenderBlock::positionForBox(InlineBox *box, bool start) const
if (!box)
return Position();
- if (!box->renderer()->node())
- return createLegacyEditingPosition(node(), start ? caretMinOffset() : caretMaxOffset());
+ if (!box->renderer()->nonPseudoNode())
+ return createLegacyEditingPosition(nonPseudoNode(), start ? caretMinOffset() : caretMaxOffset());
if (!box->isInlineTextBox())
- return createLegacyEditingPosition(box->renderer()->node(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
+ return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
InlineTextBox* textBox = toInlineTextBox(box);
- return createLegacyEditingPosition(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len());
+ return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? textBox->start() : textBox->start() + textBox->len());
}
static inline bool isEditingBoundary(RenderObject* ancestor, RenderObject* child)
{
- ASSERT(!ancestor || ancestor->node());
- ASSERT(child && child->node());
+ ASSERT(!ancestor || ancestor->nonPseudoNode());
+ ASSERT(child && child->nonPseudoNode());
return !ancestor || !ancestor->parent() || (ancestor->hasLayer() && ancestor->parent()->isRenderView())
- || ancestor->node()->rendererIsEditable() == child->node()->rendererIsEditable();
+ || ancestor->nonPseudoNode()->rendererIsEditable() == child->nonPseudoNode()->rendererIsEditable();
}
// FIXME: This function should go on RenderObject as an instance method. Then
@@ -4974,14 +5303,14 @@ static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBlock*
LayoutPoint pointInChildCoordinates(toLayoutPoint(pointInParentCoordinates - childLocation));
// If this is an anonymous renderer, we just recur normally
- Node* childNode = child->node();
+ Node* childNode = child->nonPseudoNode();
if (!childNode)
return child->positionForPoint(pointInChildCoordinates);
// 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())
+ while (ancestor && !ancestor->nonPseudoNode())
ancestor = ancestor->parent();
// If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
@@ -5039,7 +5368,7 @@ VisiblePosition RenderBlock::positionForPointWithInlineChildren(const LayoutPoin
}
}
- bool moveCaretToBoundary = document()->frame()->editor()->behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
+ bool moveCaretToBoundary = document()->frame()->editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
// y coordinate is below last root line box, pretend we hit it
@@ -5218,7 +5547,7 @@ void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width)
bool destroyColumns = !requiresColumns(count);
if (destroyColumns) {
if (hasColumns()) {
- delete gColumnInfoMap->take(this);
+ gColumnInfoMap->take(this);
setHasColumns(false);
}
} else {
@@ -5229,7 +5558,7 @@ void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width)
if (!gColumnInfoMap)
gColumnInfoMap = new ColumnInfoMap;
info = new ColumnInfo;
- gColumnInfoMap->add(this, info);
+ gColumnInfoMap->add(this, adoptPtr(info));
setHasColumns(true);
}
info->setDesiredColumnCount(count);
@@ -5300,9 +5629,9 @@ LayoutRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
// Compute the appropriate rect based off our information.
LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
LayoutUnit colLogicalHeight = colInfo->columnHeight();
- LayoutUnit colLogicalTop = borderBefore() + paddingBefore();
+ LayoutUnit colLogicalTop = borderAndPaddingBefore();
LayoutUnit colLogicalLeft = logicalLeftOffsetForContent();
- int colGap = columnGap();
+ LayoutUnit colGap = columnGap();
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
if (style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed())
colLogicalLeft += index * (colLogicalWidth + colGap);
@@ -5330,7 +5659,7 @@ bool RenderBlock::relayoutForPagination(bool hasSpecifiedPageLogicalHeight, Layo
addOverflowFromInlineChildren();
else
addOverflowFromBlockChildren();
- LayoutUnit layoutOverflowLogicalBottom = (isHorizontalWritingMode() ? layoutOverflowRect().maxY() : layoutOverflowRect().maxX()) - borderBefore() - paddingBefore();
+ LayoutUnit layoutOverflowLogicalBottom = (isHorizontalWritingMode() ? layoutOverflowRect().maxY() : layoutOverflowRect().maxX()) - borderAndPaddingBefore();
// FIXME: We don't balance properly at all in the presence of forced page breaks. We need to understand what
// the distance between forced page breaks is so that we can avoid making the minimum column height too tall.
@@ -5344,7 +5673,7 @@ bool RenderBlock::relayoutForPagination(bool hasSpecifiedPageLogicalHeight, Layo
// maximum page break distance.
if (!pageLogicalHeight) {
LayoutUnit distanceBetweenBreaks = max<LayoutUnit>(colInfo->maximumDistanceBetweenForcedBreaks(),
- view()->layoutState()->pageLogicalOffset(this, borderBefore() + paddingBefore() + layoutOverflowLogicalBottom) - colInfo->forcedBreakOffset());
+ view()->layoutState()->pageLogicalOffset(this, borderAndPaddingBefore() + layoutOverflowLogicalBottom) - colInfo->forcedBreakOffset());
columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks);
}
} else if (layoutOverflowLogicalBottom > boundedMultiply(pageLogicalHeight, desiredColumnCount)) {
@@ -5364,7 +5693,7 @@ bool RenderBlock::relayoutForPagination(bool hasSpecifiedPageLogicalHeight, Layo
colInfo->setColumnCountAndHeight(ceilf((float)layoutOverflowLogicalBottom / pageLogicalHeight), pageLogicalHeight);
if (columnCount(colInfo)) {
- setLogicalHeight(borderBefore() + paddingBefore() + colInfo->columnHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
+ setLogicalHeight(borderAndPaddingBefore() + colInfo->columnHeight() + borderAndPaddingAfter() + scrollbarLogicalHeight());
m_overflow.clear();
} else
m_overflow = savedOverflow.release();
@@ -5476,13 +5805,13 @@ void RenderBlock::adjustRectForColumns(LayoutRect& r) const
LayoutRect result;
bool isHorizontal = isHorizontalWritingMode();
- LayoutUnit beforeBorderPadding = borderBefore() + paddingBefore();
+ LayoutUnit beforeBorderPadding = borderAndPaddingBefore();
LayoutUnit colHeight = colInfo->columnHeight();
if (!colHeight)
return;
LayoutUnit startOffset = max(isHorizontal ? r.y() : r.x(), beforeBorderPadding);
- LayoutUnit endOffset = min<LayoutUnit>(isHorizontal ? r.maxY() : r.maxX(), beforeBorderPadding + colCount * colHeight);
+ LayoutUnit endOffset = max(min<LayoutUnit>(isHorizontal ? r.maxY() : r.maxX(), beforeBorderPadding + colCount * colHeight), beforeBorderPadding);
// FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
unsigned startColumn = (startOffset - beforeBorderPadding) / colHeight;
@@ -5525,7 +5854,7 @@ LayoutPoint RenderBlock::flipForWritingModeIncludingColumns(const LayoutPoint& p
return point;
ColumnInfo* colInfo = columnInfo();
LayoutUnit columnLogicalHeight = colInfo->columnHeight();
- LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
+ LayoutUnit expandedLogicalHeight = borderAndPaddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAndPaddingAfter() + scrollbarLogicalHeight();
if (isHorizontalWritingMode())
return LayoutPoint(point.x(), expandedLogicalHeight - point.y());
return LayoutPoint(expandedLogicalHeight - point.x(), point.y());
@@ -5539,7 +5868,7 @@ void RenderBlock::adjustStartEdgeForWritingModeIncludingColumns(LayoutRect& rect
ColumnInfo* colInfo = columnInfo();
LayoutUnit columnLogicalHeight = colInfo->columnHeight();
- LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
+ LayoutUnit expandedLogicalHeight = borderAndPaddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAndPaddingAfter() + scrollbarLogicalHeight();
if (isHorizontalWritingMode())
rect.setY(expandedLogicalHeight - rect.maxY());
@@ -5561,7 +5890,7 @@ void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point)
for (unsigned i = 0; i < colCount; ++i) {
// Compute the edges for a given column in the block progression direction.
- LayoutRect sliceRect = LayoutRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
+ LayoutRect sliceRect = LayoutRect(logicalLeft, borderAndPaddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
if (!isHorizontalWritingMode())
sliceRect = sliceRect.transposedRect();
@@ -5573,7 +5902,7 @@ void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point)
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset);
else
- offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderBefore() - paddingBefore());
+ offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderAndPaddingBefore());
return;
}
} else {
@@ -5581,61 +5910,55 @@ void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point)
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft);
else
- offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderBefore() - paddingBefore(), 0);
+ offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderAndPaddingBefore(), 0);
return;
}
}
}
}
+void RenderBlock::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
+{
+ if (childrenInline()) {
+ // FIXME: Remove this const_cast.
+ const_cast<RenderBlock*>(this)->computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
+ } else
+ computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
+
+ maxLogicalWidth = max(minLogicalWidth, maxLogicalWidth);
+
+ if (!style()->autoWrap() && childrenInline()) {
+ // A horizontal marquee with inline children has no minimum width.
+ if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
+ minLogicalWidth = 0;
+ }
+
+ if (isTableCell()) {
+ Length tableCellWidth = toRenderTableCell(this)->styleOrColLogicalWidth();
+ if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
+ maxLogicalWidth = max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
+ }
+
+ int scrollbarWidth = instrinsicScrollbarLogicalWidth();
+ maxLogicalWidth += scrollbarWidth;
+ minLogicalWidth += scrollbarWidth;
+}
+
void RenderBlock::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
updateFirstLetter();
+ m_minPreferredLogicalWidth = 0;
+ m_maxPreferredLogicalWidth = 0;
+
RenderStyle* styleToUse = style();
if (!isTableCell() && styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() >= 0
- && style()->marqueeBehavior() != MALTERNATE && !(isDeprecatedFlexItem() && !styleToUse->logicalWidth().intValue()))
+ && !(isDeprecatedFlexItem() && !styleToUse->logicalWidth().intValue()))
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value());
- else {
- m_minPreferredLogicalWidth = 0;
- m_maxPreferredLogicalWidth = 0;
-
- if (childrenInline())
- computeInlinePreferredLogicalWidths();
- else
- computeBlockPreferredLogicalWidths();
-
- m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
-
- if (!styleToUse->autoWrap() && childrenInline()) {
- m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
-
- // A horizontal marquee with inline children has no minimum width.
- if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
- m_minPreferredLogicalWidth = 0;
- }
-
- int scrollbarWidth = 0;
- // FIXME: This should only be done for horizontal writing mode.
- // For vertical writing mode, this should check overflowX and use the horizontalScrollbarHeight.
- if (hasOverflowClip() && styleToUse->overflowY() == OSCROLL) {
- layer()->setHasVerticalScrollbar(true);
- scrollbarWidth = verticalScrollbarWidth();
- m_maxPreferredLogicalWidth += scrollbarWidth;
- }
-
- if (isTableCell()) {
- Length w = toRenderTableCell(this)->styleOrColLogicalWidth();
- if (w.isFixed() && w.value() > 0) {
- m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(w.value()));
- scrollbarWidth = 0;
- }
- }
-
- m_minPreferredLogicalWidth += scrollbarWidth;
- }
+ else
+ computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
@@ -5783,7 +6106,7 @@ static inline LayoutUnit adjustFloatForSubPixelLayout(float value)
}
-void RenderBlock::computeInlinePreferredLogicalWidths()
+void RenderBlock::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth)
{
float inlineMax = 0;
float inlineMin = 0;
@@ -5806,7 +6129,12 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
autoWrap = oldAutoWrap = styleToUse->autoWrap();
InlineMinMaxIterator childIterator(this);
- bool addedTextIndent = false; // Only gets added in once.
+
+ // Only gets added to the max preffered width once.
+ bool addedTextIndent = false;
+ // Signals the text indent was more negative than the min preferred width
+ bool hasRemainingNegativeTextIndent = false;
+
LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw, view());
RenderObject* prevFloat = 0;
bool isPrevChildInlineFlow = false;
@@ -5900,22 +6228,21 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = 0;
}
// If we're supposed to clear the previous float, then terminate maxwidth as well.
if (clearPreviousFloat) {
- updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
+ updatePreferredWidth(maxLogicalWidth, inlineMax);
inlineMax = 0;
}
// Add in text-indent. This is added in only once.
- LayoutUnit ti = 0;
- if (!addedTextIndent) {
- ti = textIndent;
- childMin += ti.ceilToFloat();
- childMax += ti.ceilToFloat();
+ if (!addedTextIndent && !child->isFloating()) {
+ LayoutUnit ceiledIndent = textIndent.ceilToFloat();
+ childMin += ceiledIndent;
+ childMax += ceiledIndent;
if (childMin < 0)
textIndent = adjustFloatForSubPixelLayout(childMin);
@@ -5928,19 +6255,19 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) {
if (child->isFloating())
- updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
+ updatePreferredWidth(minLogicalWidth, childMin);
else
inlineMin += childMin;
} else {
// Now check our line.
- updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
+ updatePreferredWidth(minLogicalWidth, childMin);
// Now start a new line.
inlineMin = 0;
}
if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = 0;
}
@@ -5955,7 +6282,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
RenderText* t = toRenderText(child);
if (t->isWordBreak()) {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = 0;
continue;
}
@@ -5979,7 +6306,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
// This text object will not be rendered, but it may still provide a breaking opportunity.
if (!hasBreak && childMax == 0) {
if (autoWrap && (beginWS || endWS)) {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = 0;
}
continue;
@@ -5992,18 +6319,24 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
// Add in text-indent. This is added in only once.
float ti = 0;
- if (!addedTextIndent) {
+ if (!addedTextIndent || hasRemainingNegativeTextIndent) {
ti = textIndent.ceilToFloat();
-
childMin += ti;
- childMax += ti;
beginMin += ti;
- beginMax += ti;
- if (childMin < 0)
- textIndent = childMin;
- else
+ // It the text indent negative and larger than the child minimum, we re-use the remainder
+ // in future minimum calculations, but using the negative value again on the maximum
+ // will lead to under-counting the max pref width.
+ if (!addedTextIndent) {
+ childMax += ti;
+ beginMax += ti;
addedTextIndent = true;
+ }
+
+ if (childMin < 0) {
+ textIndent = childMin;
+ hasRemainingNegativeTextIndent = true;
+ }
}
// If we have no breakable characters at all,
@@ -6016,10 +6349,10 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
// we start and end with whitespace.
if (beginWS)
// Go ahead and end the current line.
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
else {
inlineMin += beginMin;
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
childMin -= ti;
}
@@ -6028,11 +6361,11 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
if (endWS) {
// We end in whitespace, which means we can go ahead
// and end our current line.
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = 0;
shouldBreakLineAfterText = false;
} else {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
inlineMin = endMin;
shouldBreakLineAfterText = true;
}
@@ -6040,8 +6373,8 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
if (hasBreak) {
inlineMax += beginMax;
- updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
- updatePreferredWidth(m_maxPreferredLogicalWidth, childMax);
+ updatePreferredWidth(maxLogicalWidth, inlineMax);
+ updatePreferredWidth(maxLogicalWidth, childMax);
inlineMax = endMax;
addedTextIndent = true;
} else
@@ -6052,8 +6385,8 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
if (child->isListMarker())
stripFrontSpaces = true;
} else {
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
- updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
+ updatePreferredWidth(maxLogicalWidth, inlineMax);
inlineMin = inlineMax = 0;
stripFrontSpaces = true;
trailingSpaceChild = 0;
@@ -6071,11 +6404,11 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
if (styleToUse->collapseWhiteSpace())
stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
- updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
- updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
+ updatePreferredWidth(minLogicalWidth, inlineMin);
+ updatePreferredWidth(maxLogicalWidth, inlineMax);
}
-void RenderBlock::computeBlockPreferredLogicalWidths()
+void RenderBlock::computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
{
RenderStyle* styleToUse = style();
bool nowrap = styleToUse->whiteSpace() == NOWRAP;
@@ -6094,11 +6427,11 @@ void RenderBlock::computeBlockPreferredLogicalWidths()
if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) {
LayoutUnit floatTotalWidth = floatLeftWidth + floatRightWidth;
if (childStyle->clear() & CLEFT) {
- m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth);
floatLeftWidth = 0;
}
if (childStyle->clear() & CRIGHT) {
- m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth);
floatRightWidth = 0;
}
}
@@ -6129,11 +6462,11 @@ void RenderBlock::computeBlockPreferredLogicalWidths()
}
LayoutUnit w = childMinPreferredLogicalWidth + margin;
- m_minPreferredLogicalWidth = max(w, m_minPreferredLogicalWidth);
+ minLogicalWidth = max(w, minLogicalWidth);
// IE ignores tables for calculation of nowrap. Makes some sense.
if (nowrap && !child->isTable())
- m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(w, maxLogicalWidth);
w = childMaxPreferredLogicalWidth + margin;
@@ -6151,26 +6484,26 @@ void RenderBlock::computeBlockPreferredLogicalWidths()
w = max(w, floatLeftWidth + floatRightWidth);
}
else
- m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
floatLeftWidth = floatRightWidth = 0;
}
if (child->isFloating()) {
- if (styleToUse->floating() == LeftFloat)
+ if (childStyle->floating() == LeftFloat)
floatLeftWidth += w;
else
floatRightWidth += w;
} else
- m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(w, maxLogicalWidth);
child = child->nextSibling();
}
// Always make sure these values are non-negative.
- m_minPreferredLogicalWidth = max<LayoutUnit>(0, m_minPreferredLogicalWidth);
- m_maxPreferredLogicalWidth = max<LayoutUnit>(0, m_maxPreferredLogicalWidth);
+ minLogicalWidth = max<LayoutUnit>(0, minLogicalWidth);
+ maxLogicalWidth = max<LayoutUnit>(0, maxLogicalWidth);
- m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
+ maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
}
bool RenderBlock::hasLineIfEmpty() const
@@ -6181,7 +6514,7 @@ bool RenderBlock::hasLineIfEmpty() const
if (node()->isRootEditableElement())
return true;
- if (node()->isShadowRoot() && toShadowRoot(node())->host()->hasTagName(inputTag))
+ if (node()->isShadowRoot() && isHTMLInputElement(toShadowRoot(node())->host()))
return true;
return false;
@@ -6329,10 +6662,17 @@ RenderBlock* RenderBlock::firstLineBlock() const
if (hasPseudo)
break;
RenderObject* parentBlock = firstLineBlock->parent();
- if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() ||
- !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow())
+ // We include isRenderButton in this check because buttons are
+ // implemented using flex box but should still support first-line. The
+ // flex box spec requires that flex box does not support first-line,
+ // though.
+ // FIXME: Remove when buttons are implemented with align-items instead
+ // of flexbox.
+ if (firstLineBlock->isReplaced() || firstLineBlock->isFloating()
+ || !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow()
+ || (parentBlock->isFlexibleBox() && !parentBlock->isRenderButton()))
break;
- ASSERT(parentBlock->isRenderBlock());
+ ASSERT_WITH_SECURITY_IMPLICATION(parentBlock->isRenderBlock());
firstLineBlock = toRenderBlock(parentBlock);
}
@@ -6374,14 +6714,21 @@ static inline RenderObject* findFirstLetterBlock(RenderBlock* start)
{
RenderObject* firstLetterBlock = start;
while (true) {
+ // We include isRenderButton in these two checks because buttons are
+ // implemented using flex box but should still support first-letter.
+ // The flex box spec requires that flex box does not support
+ // first-letter, though.
+ // FIXME: Remove when buttons are implemented with align-items instead
+ // of flexbox.
bool canHaveFirstLetterRenderer = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER)
- && firstLetterBlock->canHaveGeneratedChildren();
+ && firstLetterBlock->canHaveGeneratedChildren()
+ && (!firstLetterBlock->isFlexibleBox() || firstLetterBlock->isRenderButton());
if (canHaveFirstLetterRenderer)
return firstLetterBlock;
RenderObject* parentBlock = firstLetterBlock->parent();
if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock ||
- !parentBlock->isBlockFlow())
+ !parentBlock->isBlockFlow() || (parentBlock->isFlexibleBox() && !parentBlock->isRenderButton()))
return 0;
firstLetterBlock = parentBlock;
}
@@ -6400,9 +6747,9 @@ void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderO
// The first-letter renderer needs to be replaced. Create a new renderer of the right type.
RenderObject* newFirstLetter;
if (pseudoStyle->display() == INLINE)
- newFirstLetter = new (renderArena()) RenderInline(document());
+ newFirstLetter = RenderInline::createAnonymous(document());
else
- newFirstLetter = new (renderArena()) RenderBlock(document());
+ newFirstLetter = RenderBlock::createAnonymous(document());
newFirstLetter->setStyle(pseudoStyle);
// Move the first letter into the new renderer.
@@ -6446,9 +6793,9 @@ void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, Rend
RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
RenderObject* firstLetter = 0;
if (pseudoStyle->display() == INLINE)
- firstLetter = new (renderArena()) RenderInline(document());
+ firstLetter = RenderInline::createAnonymous(document());
else
- firstLetter = new (renderArena()) RenderBlock(document());
+ firstLetter = RenderBlock::createAnonymous(document());
firstLetter->setStyle(pseudoStyle);
firstLetterContainer->addChild(firstLetter, currentChild);
@@ -6571,28 +6918,6 @@ static bool shouldCheckLines(RenderObject* obj)
&& (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
}
-static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count)
-{
- if (block->style()->visibility() == VISIBLE) {
- if (block->childrenInline()) {
- for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
- if (count++ == i)
- return box;
- }
- }
- else {
- for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) {
- if (shouldCheckLines(obj)) {
- RootInlineBox *box = getLineAtIndex(toRenderBlock(obj), i, count);
- if (box)
- return box;
- }
- }
- }
- }
- return 0;
-}
-
static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count)
{
if (block->style()->visibility() == VISIBLE) {
@@ -6620,23 +6945,54 @@ static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom,
return -1;
}
-RootInlineBox* RenderBlock::lineAtIndex(int i)
+RootInlineBox* RenderBlock::lineAtIndex(int i) const
{
- int count = 0;
- return getLineAtIndex(this, i, count);
+ ASSERT(i >= 0);
+
+ if (style()->visibility() != VISIBLE)
+ return 0;
+
+ if (childrenInline()) {
+ for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
+ if (!i--)
+ return box;
+ } else {
+ for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ if (!shouldCheckLines(child))
+ continue;
+ if (RootInlineBox* box = toRenderBlock(child)->lineAtIndex(i))
+ return box;
+ }
+ }
+
+ return 0;
}
-int RenderBlock::lineCount()
+int RenderBlock::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
{
int count = 0;
+
if (style()->visibility() == VISIBLE) {
if (childrenInline())
- for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
+ for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
count++;
+ if (box == stopRootInlineBox) {
+ if (found)
+ *found = true;
+ break;
+ }
+ }
else
for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
- if (shouldCheckLines(obj))
- count += toRenderBlock(obj)->lineCount();
+ if (shouldCheckLines(obj)) {
+ bool recursiveFound = false;
+ count += toRenderBlock(obj)->lineCount(stopRootInlineBox, &recursiveFound);
+ if (recursiveFound) {
+ if (found)
+ *found = true;
+ break;
+ }
+ }
}
return count;
}
@@ -6691,32 +7047,30 @@ void RenderBlock::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit&
}
}
-void RenderBlock::borderFitAdjust(LayoutRect& rect) const
+void RenderBlock::fitBorderToLinesIfNeeded()
{
- if (style()->borderFit() == BorderFitBorder)
+ if (style()->borderFit() == BorderFitBorder || hasOverrideWidth())
return;
// Walk any normal flow lines to snugly fit.
LayoutUnit left = LayoutUnit::max();
LayoutUnit right = LayoutUnit::min();
- LayoutUnit oldWidth = rect.width();
+ LayoutUnit oldWidth = contentWidth();
adjustForBorderFit(0, left, right);
- if (left != LayoutUnit::max()) {
- left = min(left, oldWidth - (borderRight() + paddingRight()));
-
- left -= (borderLeft() + paddingLeft());
- if (left > 0) {
- rect.move(left, 0);
- rect.expand(-left, 0);
- }
- }
- if (right != LayoutUnit::min()) {
- right = max(right, borderLeft() + paddingLeft());
-
- right += (borderRight() + paddingRight());
- if (right < oldWidth)
- rect.expand(-(oldWidth - right), 0);
- }
+
+ // Clamp to our existing edges. We can never grow. We only shrink.
+ LayoutUnit leftEdge = borderLeft() + paddingLeft();
+ LayoutUnit rightEdge = leftEdge + oldWidth;
+ left = min(rightEdge, max(leftEdge, left));
+ right = max(leftEdge, min(rightEdge, right));
+
+ LayoutUnit newContentWidth = right - left;
+ if (newContentWidth == oldWidth)
+ return;
+
+ setOverrideLogicalContentWidth(newContentWidth);
+ layoutBlock(false);
+ clearOverrideLogicalContentWidth();
}
void RenderBlock::clearTruncation()
@@ -6757,6 +7111,99 @@ void RenderBlock::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
m_rareData->m_margins.setNegativeMarginAfter(neg);
}
+void RenderBlock::setMustDiscardMarginBefore(bool value)
+{
+ if (style()->marginBeforeCollapse() == MDISCARD) {
+ ASSERT(value);
+ return;
+ }
+
+ if (!m_rareData && !value)
+ return;
+
+ if (!m_rareData)
+ m_rareData = adoptPtr(new RenderBlockRareData(this));
+
+ m_rareData->m_discardMarginBefore = value;
+}
+
+void RenderBlock::setMustDiscardMarginAfter(bool value)
+{
+ if (style()->marginAfterCollapse() == MDISCARD) {
+ ASSERT(value);
+ return;
+ }
+
+ if (!m_rareData && !value)
+ return;
+
+ if (!m_rareData)
+ m_rareData = adoptPtr(new RenderBlockRareData(this));
+
+ m_rareData->m_discardMarginAfter = value;
+}
+
+bool RenderBlock::mustDiscardMarginBefore() const
+{
+ return style()->marginBeforeCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginBefore);
+}
+
+bool RenderBlock::mustDiscardMarginAfter() const
+{
+ return style()->marginAfterCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginAfter);
+}
+
+bool RenderBlock::mustDiscardMarginBeforeForChild(const RenderBox* child) const
+{
+ ASSERT(!child->selfNeedsLayout());
+ if (!child->isWritingModeRoot())
+ return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
+
+ // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
+ // In case the boxes are perpendicular we assume the property is not specified.
+ return false;
+}
+
+bool RenderBlock::mustDiscardMarginAfterForChild(const RenderBox* child) const
+{
+ ASSERT(!child->selfNeedsLayout());
+ if (!child->isWritingModeRoot())
+ return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
+
+ // FIXME: See |mustDiscardMarginBeforeForChild| above.
+ return false;
+}
+
+bool RenderBlock::mustSeparateMarginBeforeForChild(const RenderBox* child) const
+{
+ ASSERT(!child->selfNeedsLayout());
+ const RenderStyle* childStyle = child->style();
+ if (!child->isWritingModeRoot())
+ return childStyle->marginBeforeCollapse() == MSEPARATE;
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return childStyle->marginAfterCollapse() == MSEPARATE;
+
+ // FIXME: See |mustDiscardMarginBeforeForChild| above.
+ return false;
+}
+
+bool RenderBlock::mustSeparateMarginAfterForChild(const RenderBox* child) const
+{
+ ASSERT(!child->selfNeedsLayout());
+ const RenderStyle* childStyle = child->style();
+ if (!child->isWritingModeRoot())
+ return childStyle->marginAfterCollapse() == MSEPARATE;
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return childStyle->marginBeforeCollapse() == MSEPARATE;
+
+ // FIXME: See |mustDiscardMarginBeforeForChild| above.
+ return false;
+}
+
void RenderBlock::setPaginationStrut(LayoutUnit strut)
{
if (!m_rareData) {
@@ -6777,6 +7224,23 @@ void RenderBlock::setPageLogicalOffset(LayoutUnit logicalOffset)
m_rareData->m_pageLogicalOffset = logicalOffset;
}
+void RenderBlock::setBreakAtLineToAvoidWidow(RootInlineBox* lineToBreak)
+{
+ ASSERT(lineToBreak);
+ if (!m_rareData)
+ m_rareData = adoptPtr(new RenderBlockRareData(this));
+ m_rareData->m_shouldBreakAtLineToAvoidWidow = true;
+ m_rareData->m_lineBreakToAvoidWidow = lineToBreak;
+}
+
+void RenderBlock::clearShouldBreakAtLineToAvoidWidow() const
+{
+ if (!m_rareData)
+ return;
+ m_rareData->m_shouldBreakAtLineToAvoidWidow = false;
+ m_rareData->m_lineBreakToAvoidWidow = 0;
+}
+
void RenderBlock::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
{
// For blocks inside inlines, we go ahead and include margins so that we run right up to the
@@ -6863,29 +7327,14 @@ LayoutRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, La
LayoutRect caretRect = localCaretRectForEmptyElement(width(), textIndentOffset());
- if (extraWidthToEndOfLine) {
- if (isRenderBlock()) {
- *extraWidthToEndOfLine = width() - caretRect.maxX();
- } else {
- // FIXME: This code looks wrong.
- // myRight and containerRight are set up, but then clobbered.
- // So *extraWidthToEndOfLine will always be 0 here.
-
- LayoutUnit myRight = caretRect.maxX();
- // FIXME: why call localToAbsoluteForContent() twice here, too?
- FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0));
-
- LayoutUnit containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent();
- FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0));
-
- *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();
- }
- }
+ // FIXME: Does this need to adjust for vertical orientation?
+ if (extraWidthToEndOfLine)
+ *extraWidthToEndOfLine = width() - caretRect.maxX();
return caretRect;
}
-void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
+void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
{
// 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
@@ -6920,16 +7369,16 @@ void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& a
FloatPoint pos;
// FIXME: This doesn't work correctly with transforms.
if (box->layer())
- pos = curr->localToAbsolute();
+ pos = curr->localToContainerPoint(FloatPoint(), paintContainer);
else
pos = FloatPoint(additionalOffset.x() + box->x(), additionalOffset.y() + box->y());
- box->addFocusRingRects(rects, flooredLayoutPoint(pos));
+ box->addFocusRingRects(rects, flooredLayoutPoint(pos), paintContainer);
}
}
}
if (inlineElementContinuation())
- inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location()));
+ inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location()), paintContainer);
}
RenderBox* RenderBlock::createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const
@@ -6945,16 +7394,17 @@ bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBou
{
ASSERT(view()->layoutState() && view()->layoutState()->isPaginated());
- if (!inRenderFlowThread())
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (!flowThread)
return true; // Printing and multi-column both make new pages to accommodate content.
// See if we're in the last region.
LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
- RenderRegion* region = enclosingRenderFlowThread()->regionAtBlockOffset(pageOffset, this);
+ RenderRegion* region = flowThread->regionAtBlockOffset(pageOffset, this);
if (!region)
return false;
if (region->isLastRegion())
- return region->isRenderRegionSet() || region->style()->regionOverflow() == BreakRegionOverflow
+ return region->isRenderRegionSet() || region->style()->regionFragment() == BreakRegionFragment
|| (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
return true;
}
@@ -6996,7 +7446,8 @@ LayoutUnit RenderBlock::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOff
// FIXME: Add page break checking here when we support printing.
bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
- bool checkRegionBreaks = inRenderFlowThread();
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS)
|| (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS);
if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
@@ -7004,7 +7455,7 @@ LayoutUnit RenderBlock::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOff
view()->layoutState()->addForcedColumnBreak(child, logicalOffset);
if (checkRegionBreaks) {
LayoutUnit offsetBreakAdjustment = 0;
- if (enclosingRenderFlowThread()->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment))
+ if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment))
return logicalOffset + offsetBreakAdjustment;
}
return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
@@ -7017,18 +7468,22 @@ LayoutUnit RenderBlock::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffs
// FIXME: Add page break checking here when we support printing.
bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
- bool checkRegionBreaks = inRenderFlowThread();
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS)
|| (checkRegionBreaks && child->style()->regionBreakAfter() == PBALWAYS);
if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
- marginInfo.setMarginAfterQuirk(true); // Cause margins to be discarded for any following content.
+ LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
+
+ // So our margin doesn't participate in the next collapsing steps.
+ marginInfo.clearMargin();
+
if (checkColumnBreaks)
view()->layoutState()->addForcedColumnBreak(child, logicalOffset);
if (checkRegionBreaks) {
- LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
LayoutUnit offsetBreakAdjustment = 0;
- if (enclosingRenderFlowThread()->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment))
- return logicalOffset + offsetBreakAdjustment;
+ if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment))
+ return logicalOffset + marginOffset + offsetBreakAdjustment;
}
return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
}
@@ -7042,21 +7497,23 @@ LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const
LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_layoutOffset.height() : renderView->layoutState()->m_layoutOffset.width();
LayoutUnit cumulativeOffset = offset + blockLogicalTop;
- if (!inRenderFlowThread()) {
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (!flowThread) {
LayoutUnit pageLogicalHeight = renderView->layoutState()->pageLogicalHeight();
if (!pageLogicalHeight)
return 0;
return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
}
- return enclosingRenderFlowThread()->pageLogicalTopForOffset(cumulativeOffset);
+ return flowThread->pageLogicalTopForOffset(cumulativeOffset);
}
LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const
{
RenderView* renderView = view();
- if (!inRenderFlowThread())
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (!flowThread)
return renderView->layoutState()->m_pageLogicalHeight;
- return enclosingRenderFlowThread()->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
+ return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
}
LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
@@ -7064,7 +7521,8 @@ LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, P
RenderView* renderView = view();
offset += offsetFromLogicalTopOfFirstPage();
- if (!inRenderFlowThread()) {
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (!flowThread) {
LayoutUnit pageLogicalHeight = renderView->layoutState()->m_pageLogicalHeight;
LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
if (pageBoundaryRule == IncludePageBoundary) {
@@ -7075,25 +7533,24 @@ LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, P
return remainingHeight;
}
- return enclosingRenderFlowThread()->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
+ return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
}
LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins)
{
bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight;
- bool checkRegionBreaks = inRenderFlowThread();
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
bool isUnsplittable = child->isUnsplittableForPagination() || (checkColumnBreaks && child->style()->columnBreakInside() == PBAVOID)
|| (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID)
|| (checkRegionBreaks && child->style()->regionBreakInside() == PBAVOID);
if (!isUnsplittable)
return logicalOffset;
LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
- LayoutState* layoutState = view()->layoutState();
- if (layoutState->m_columnInfo)
- layoutState->m_columnInfo->updateMinimumColumnHeight(childLogicalHeight);
LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
- bool hasUniformPageLogicalHeight = !inRenderFlowThread() || enclosingRenderFlowThread()->regionsHaveUniformLogicalHeight();
+ bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
+ updateMinimumPageHeight(logicalOffset, childLogicalHeight);
if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
|| !hasNextPage(logicalOffset))
return logicalOffset;
@@ -7121,7 +7578,39 @@ bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment,
return !checkRegion;
}
-void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta)
+void RenderBlock::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
+{
+ if (RenderFlowThread* flowThread = flowThreadContainingBlock())
+ flowThread->setPageBreak(offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
+}
+
+void RenderBlock::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
+{
+ if (RenderFlowThread* flowThread = flowThreadContainingBlock())
+ flowThread->updateMinimumPageHeight(offsetFromLogicalTopOfFirstPage() + offset, minHeight);
+ else if (ColumnInfo* colInfo = view()->layoutState()->m_columnInfo)
+ colInfo->updateMinimumColumnHeight(minHeight);
+}
+
+static inline LayoutUnit calculateMinimumPageHeight(RenderStyle* renderStyle, RootInlineBox* lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
+{
+ // We may require a certain minimum number of lines per page in order to satisfy
+ // orphans and widows, and that may affect the minimum page height.
+ unsigned lineCount = max<unsigned>(renderStyle->hasAutoOrphans() ? 1 : renderStyle->orphans(), renderStyle->hasAutoWidows() ? 1 : renderStyle->widows());
+ if (lineCount > 1) {
+ RootInlineBox* line = lastLine;
+ for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
+ line = line->prevRootBox();
+
+ // FIXME: Paginating using line overflow isn't all fine. See FIXME in
+ // adjustLinePositionForPagination() for more details.
+ LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
+ lineTop = min(line->lineTopWithLeading(), overflow.y());
+ }
+ return lineBottom - lineTop;
+}
+
+void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, RenderFlowThread* flowThread)
{
// FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
// put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
@@ -7144,23 +7633,24 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, Layout
// line and all following lines.
LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
LayoutUnit logicalOffset = min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
- LayoutUnit lineHeight = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY()) - logicalOffset;
- RenderView* renderView = view();
- LayoutState* layoutState = renderView->layoutState();
- if (layoutState->m_columnInfo)
- layoutState->m_columnInfo->updateMinimumColumnHeight(lineHeight);
+ LayoutUnit logicalBottom = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
+ LayoutUnit lineHeight = logicalBottom - logicalOffset;
+ updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), lineBox, logicalOffset, logicalBottom));
logicalOffset += delta;
lineBox->setPaginationStrut(0);
lineBox->setIsFirstAfterPageBreak(false);
LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
- bool hasUniformPageLogicalHeight = !inRenderFlowThread() || enclosingRenderFlowThread()->regionsHaveUniformLogicalHeight();
+ bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
// If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
// still going to add a strut, so that the visible overflow fits on a single page.
if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight)
|| !hasNextPage(logicalOffset))
return;
LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
- if (remainingLogicalHeight < lineHeight) {
+
+ if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineBox)) {
+ if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineBox)
+ clearShouldBreakAtLineToAvoidWidow();
// If we have a non-uniform page height, then we have to shift further possibly.
if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
return;
@@ -7170,7 +7660,9 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, Layout
}
LayoutUnit totalLogicalHeight = lineHeight + max<LayoutUnit>(0, logicalOffset);
LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
- if (lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset && !isOutOfFlowPositioned() && !isTableCell())
+ setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
+ if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style()->hasAutoOrphans() && style()->orphans() >= lineCount(lineBox)))
+ && !isOutOfFlowPositioned() && !isTableCell())
setPaginationStrut(remainingLogicalHeight + max<LayoutUnit>(0, logicalOffset));
else {
delta += remainingLogicalHeight;
@@ -7215,6 +7707,21 @@ LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfter
// If the object has a page or column break value of "before", then we should shift to the top of the next page.
LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
+ if (pageLogicalHeightForOffset(result)) {
+ LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
+ LayoutUnit spaceShortage = child->logicalHeight() - remainingLogicalHeight;
+ if (spaceShortage > 0) {
+ // If the child crosses a column boundary, report a break, in case nothing inside it has already
+ // done so. The column balancer needs to know how much it has to stretch the columns to make more
+ // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
+ // This should be improved, though, because here we just pretend that the child is
+ // unsplittable. A splittable child, on the other hand, has break opportunities at every position
+ // where there's no child content, border or padding. In other words, we risk stretching more
+ // than necessary.
+ setPageBreak(result, spaceShortage);
+ }
+ }
+
// For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
@@ -7247,19 +7754,16 @@ LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfter
return result;
}
-bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta) const
+bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta, RenderFlowThread* flowThread) const
{
- if (!inRenderFlowThread())
+ if (!flowThread)
return false;
RenderRegion* currentRegion = regionAtBlockOffset(rootBox->lineTopWithLeading() + lineDelta);
- // Just bail if we still don't have a region.
- if (!rootBox->hasContainingRegion() && !currentRegion)
- return false;
// Just bail if the region didn't change.
- if (rootBox->hasContainingRegion() && rootBox->containingRegion() == currentRegion)
+ if (rootBox->containingRegion() == currentRegion)
return false;
- return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(currentRegion, offsetFromLogicalTopOfFirstPage());
+ return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(currentRegion);
}
LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const
@@ -7267,94 +7771,71 @@ LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const
LayoutState* layoutState = view()->layoutState();
if (layoutState && !layoutState->isPaginated())
return 0;
+
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+ if (flowThread)
+ return flowThread->offsetFromLogicalTopOfFirstRegion(this);
+
if (layoutState) {
- // FIXME: Sanity check that the renderer in the layout state is ours, since otherwise the computation will be off.
- // Right now this assert gets hit inside computeLogicalHeight for percentage margins, since they're computed using
- // widths which can vary in each region. Until we patch that, we can't have this assert.
- // ASSERT(layoutState->m_renderer == this);
+ ASSERT(layoutState->m_renderer == this);
LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
return isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
}
- // FIXME: Right now, this assert is hit outside layout, from logicalLeftSelectionOffset in selectionGapRectsForRepaint (called from FrameSelection::selectAll).
- // ASSERT(inRenderFlowThread());
-
- // FIXME: This is a slower path that doesn't use layout state and relies on getting your logical top inside the enclosing flow thread. It doesn't
- // work with columns or pages currently, but it should once they have been switched over to using flow threads.
- if (!inRenderFlowThread())
- return 0;
-
- const RenderBlock* currentBlock = this;
- LayoutRect blockRect(0, 0, width(), height());
-
- while (currentBlock && !currentBlock->isRenderFlowThread()) {
- RenderBlock* containerBlock = currentBlock->containingBlock();
- ASSERT(containerBlock);
- if (!containerBlock)
- return 0;
- LayoutPoint currentBlockLocation = currentBlock->location();
-
- if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) {
- // We have to put the block rect in container coordinates
- // and we have to take into account both the container and current block flipping modes
- if (containerBlock->style()->isFlippedBlocksWritingMode()) {
- if (containerBlock->isHorizontalWritingMode())
- blockRect.setY(currentBlock->height() - blockRect.maxY());
- else
- blockRect.setX(currentBlock->width() - blockRect.maxX());
- }
- currentBlock->flipForWritingMode(blockRect);
- }
- blockRect.moveBy(currentBlockLocation);
- currentBlock = containerBlock;
- };
- return currentBlock->isHorizontalWritingMode() ? blockRect.y() : blockRect.x();
+
+ ASSERT_NOT_REACHED();
+ return 0;
}
RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const
{
- if (!inRenderFlowThread())
- return 0;
-
- RenderFlowThread* flowThread = enclosingRenderFlowThread();
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
if (!flowThread || !flowThread->hasValidRegionInfo())
return 0;
return flowThread->regionAtBlockOffset(offsetFromLogicalTopOfFirstPage() + blockOffset, true);
}
+void RenderBlock::updateStaticInlinePositionForChild(RenderBox* child, LayoutUnit logicalTop)
+{
+ if (child->style()->isOriginalDisplayInlineType())
+ setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, false));
+ else
+ setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
+}
+
void RenderBlock::setStaticInlinePositionForChild(RenderBox* child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
{
- if (inRenderFlowThread()) {
+ if (flowThreadContainingBlock()) {
// Shift the inline position to exclude the region offset.
inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
}
child->layer()->setStaticInlinePosition(inlinePosition);
}
-bool RenderBlock::logicalWidthChangedInRegions() const
+bool RenderBlock::logicalWidthChangedInRegions(RenderFlowThread* flowThread) const
{
- if (!inRenderFlowThread())
- return false;
-
- RenderFlowThread* flowThread = enclosingRenderFlowThread();
if (!flowThread || !flowThread->hasValidRegionInfo())
- return 0;
+ return false;
- return flowThread->logicalWidthChangedInRegions(this, offsetFromLogicalTopOfFirstPage());
+ return flowThread->logicalWidthChangedInRegionsForBlock(this);
}
RenderRegion* RenderBlock::clampToStartAndEndRegions(RenderRegion* region) const
{
- ASSERT(region && inRenderFlowThread());
-
+ RenderFlowThread* flowThread = flowThreadContainingBlock();
+
+ ASSERT(isRenderView() || (region && flowThread));
+ if (isRenderView())
+ return region;
+
// We need to clamp to the block, since we want any lines or blocks that overflow out of the
// logical top or logical bottom of the block to size as though the border box in the first and
// last regions extended infinitely. Otherwise the lines are going to size according to the regions
// they overflow into, which makes no sense when this block doesn't exist in |region| at all.
RenderRegion* startRegion;
RenderRegion* endRegion;
- enclosingRenderFlowThread()->getRegionRangeForBox(this, startRegion, endRegion);
+ flowThread->getRegionRangeForBox(this, startRegion, endRegion);
if (startRegion && region->logicalTopForFlowThreadContent() < startRegion->logicalTopForFlowThreadContent())
return startRegion;
@@ -7398,6 +7879,40 @@ LayoutUnit RenderBlock::collapsedMarginAfterForChild(const RenderBox* child) co
return marginAfterForChild(child);
}
+bool RenderBlock::hasMarginBeforeQuirk(const RenderBox* child) const
+{
+ // If the child has the same directionality as we do, then we can just return its
+ // margin quirk.
+ if (!child->isWritingModeRoot())
+ return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
+
+ // The child has a different directionality. If the child is parallel, then it's just
+ // flipped relative to us. We can use the opposite edge.
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
+
+ // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
+ // whether or not authors specified quirky ems, since they're an implementation detail.
+ return false;
+}
+
+bool RenderBlock::hasMarginAfterQuirk(const RenderBox* child) const
+{
+ // If the child has the same directionality as we do, then we can just return its
+ // margin quirk.
+ if (!child->isWritingModeRoot())
+ return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
+
+ // The child has a different directionality. If the child is parallel, then it's just
+ // flipped relative to us. We can use the opposite edge.
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
+ return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
+
+ // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
+ // whether or not authors specified quirky ems, since they're an implementation detail.
+ return false;
+}
+
RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child) const
{
LayoutUnit childBeforePositive = 0;
@@ -7467,23 +7982,40 @@ const char* RenderBlock::renderName() const
return "RenderBlock (floating)";
if (isOutOfFlowPositioned())
return "RenderBlock (positioned)";
- if (isAnonymousColumnsBlock())
+ if (style() && isAnonymousColumnsBlock())
return "RenderBlock (anonymous multi-column)";
- if (isAnonymousColumnSpanBlock())
+ if (style() && isAnonymousColumnSpanBlock())
return "RenderBlock (anonymous multi-column span)";
- if (isAnonymousBlock())
+ if (style() && isAnonymousBlock())
return "RenderBlock (anonymous)";
- else if (isAnonymous())
+ // FIXME: Temporary hack while the new generated content system is being implemented.
+ if (isPseudoElement())
+ return "RenderBlock (generated)";
+ if (isAnonymous())
return "RenderBlock (generated)";
if (isRelPositioned())
return "RenderBlock (relative positioned)";
if (isStickyPositioned())
return "RenderBlock (sticky positioned)";
- if (isRunIn())
+ if (style() && isRunIn())
return "RenderBlock (run-in)";
return "RenderBlock";
}
+inline RenderBlock::FloatingObjects::FloatingObjects(const RenderBlock* renderer, bool horizontalWritingMode)
+ : m_placedFloatsTree(UninitializedTree)
+ , m_leftObjectsCount(0)
+ , m_rightObjectsCount(0)
+ , m_horizontalWritingMode(horizontalWritingMode)
+ , m_renderer(renderer)
+{
+}
+
+void RenderBlock::createFloatingObjects()
+{
+ m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
+}
+
inline void RenderBlock::FloatingObjects::clear()
{
m_set.clear();
@@ -7511,8 +8043,8 @@ inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::T
inline RenderBlock::FloatingObjectInterval RenderBlock::FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject)
{
if (m_horizontalWritingMode)
- return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxY(), floatingObject);
- return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject);
+ return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().y(), floatingObject->frameRect().maxY(), floatingObject);
+ return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().x(), floatingObject->frameRect().maxX(), floatingObject);
}
void RenderBlock::FloatingObjects::addPlacedObject(FloatingObject* floatingObject)
@@ -7660,15 +8192,18 @@ TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, c
RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const RenderObject* parent, EDisplay display)
{
- // FIXME: Do we need to cover the new flex box here ?
// FIXME: Do we need to convert all our inline displays to block-type in the anonymous logic ?
EDisplay newDisplay;
RenderBlock* newBox = 0;
if (display == BOX || display == INLINE_BOX) {
- newBox = new (parent->renderArena()) RenderDeprecatedFlexibleBox(parent->document() /* anonymous box */);
+ // FIXME: Remove this case once we have eliminated all internal users of old flexbox
+ newBox = RenderDeprecatedFlexibleBox::createAnonymous(parent->document());
newDisplay = BOX;
+ } else if (display == FLEX || display == INLINE_FLEX) {
+ newBox = RenderFlexibleBox::createAnonymous(parent->document());
+ newDisplay = FLEX;
} else {
- newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
+ newBox = RenderBlock::createAnonymous(parent->document());
newDisplay = BLOCK;
}
@@ -7682,7 +8217,7 @@ RenderBlock* RenderBlock::createAnonymousColumnsWithParentRenderer(const RenderO
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
newStyle->inheritColumnPropertiesFrom(parent->style());
- RenderBlock* newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
+ RenderBlock* newBox = RenderBlock::createAnonymous(parent->document());
newBox->setStyle(newStyle.release());
return newBox;
}
@@ -7692,7 +8227,7 @@ RenderBlock* RenderBlock::createAnonymousColumnSpanWithParentRenderer(const Rend
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
newStyle->setColumnSpan(ColumnSpanAll);
- RenderBlock* newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
+ RenderBlock* newBox = RenderBlock::createAnonymous(parent->document());
newBox->setStyle(newStyle.release());
return newBox;
}
@@ -7727,7 +8262,7 @@ String ValueToString<int>::string(const int value)
String ValueToString<RenderBlock::FloatingObject*>::string(const RenderBlock::FloatingObject* floatingObject)
{
- return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject->frameRect().pixelSnappedMaxY());
+ return String::format("%p (%ix%i %ix%i)", floatingObject, floatingObject->frameRect().x().toInt(), floatingObject->frameRect().y().toInt(), floatingObject->frameRect().maxX().toInt(), floatingObject->frameRect().maxY().toInt());
}
#endif