Index: Source/WebCore/rendering/RenderBlock.cpp |
=================================================================== |
--- Source/WebCore/rendering/RenderBlock.cpp (revision 118862) |
+++ Source/WebCore/rendering/RenderBlock.cpp (working copy) |
@@ -932,6 +932,14 @@ |
} |
RenderBox::addChild(newChild, beforeChild); |
+ |
+ // Handle positioning of run-ins. |
+ if (newChild->isRunIn()) |
+ moveRunInUnderSiblingBlockIfNeeded(newChild); |
+ else if (RenderObject* prevSibling = newChild->previousSibling()) { |
+ if (prevSibling->isRunIn()) |
+ moveRunInUnderSiblingBlockIfNeeded(prevSibling); |
+ } |
if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock()) |
toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); |
@@ -1038,6 +1046,13 @@ |
if (!child) |
return; |
+ // Since we are going to have block children, we have to move |
+ // back the run-in to its original place. |
+ if (child->isRunIn()) { |
+ moveRunInToOriginalPosition(child); |
+ child = firstChild(); |
+ } |
+ |
deleteLineBoxTree(); |
while (child) { |
@@ -1724,8 +1739,7 @@ |
{ |
// Handle in the given order |
return handlePositionedChild(child, marginInfo) |
- || handleFloatingChild(child, marginInfo) |
- || handleRunInChild(child); |
+ || handleFloatingChild(child, marginInfo); |
} |
@@ -1749,77 +1763,115 @@ |
return false; |
} |
-bool RenderBlock::handleRunInChild(RenderBox* child) |
+static void destroyRunIn(RenderBoxModelObject* runIn) |
{ |
- // See if we have a run-in element with inline children. If the |
- // children aren't inline, then just treat the run-in as a normal |
- // block. |
- if (!child->isRunIn() || !child->childrenInline()) |
- return false; |
+ ASSERT(runIn->isRunIn()); |
+ ASSERT(!runIn->firstChild()); |
+ // If it is a block run-in, delete its line box tree as well. This is needed as our |
+ // children got moved and our line box tree is no longer valid. |
+ if (runIn->isRenderBlock()) |
+ toRenderBlock(runIn)->deleteLineBoxTree(); |
+ runIn->destroy(); |
+} |
+ |
+RenderBoxModelObject* RenderBlock::createReplacementRunIn(RenderBoxModelObject* runIn) |
+{ |
+ ASSERT(runIn->isRunIn()); |
+ |
+ // 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()); |
+ else |
+ newRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document()); |
+ 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); |
+ |
+ return newRunIn; |
+} |
+ |
+void RenderBlock::moveRunInUnderSiblingBlockIfNeeded(RenderObject* runIn) |
+{ |
+ ASSERT(runIn->isRunIn()); |
+ |
+ // See if we have inline children. If the children aren't inline, |
+ // then just treat the run-in as a normal block. |
+ if (!runIn->childrenInline()) |
+ return; |
+ |
// FIXME: We don't handle non-block elements with run-in for now. |
- if (!child->isRenderBlock()) |
- return false; |
+ if (!runIn->isRenderBlock()) |
+ return; |
- // Run-in child shouldn't intrude into the sibling block if it is part of a |
+ // We shouldn't run in into the sibling block if we are part of a |
// continuation chain. In that case, treat it as a normal block. |
- if (child->isElementContinuation() || child->virtualContinuation()) |
- return false; |
+ if (runIn->isElementContinuation() || runIn->virtualContinuation()) |
+ return; |
// Check if this node is allowed to run-in. E.g. <select> expects its renderer to |
// be a RenderListBox or RenderMenuList, and hence cannot be a RenderInline run-in. |
- Node* runInNode = child->node(); |
+ Node* runInNode = runIn->node(); |
if (runInNode && runInNode->hasTagName(selectTag)) |
- return false; |
+ return; |
- RenderBlock* blockRunIn = toRenderBlock(child); |
- RenderObject* curr = blockRunIn->nextSibling(); |
- if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous() || curr->isFloatingOrPositioned()) |
- return false; |
+ RenderObject* curr = runIn->nextSibling(); |
+ if (!curr || !curr->isRenderBlock() || !curr->childrenInline()) |
+ return; |
- RenderBlock* currBlock = toRenderBlock(curr); |
+ // 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())) |
+ return; |
- // First we destroy any :before/:after content. It will be regenerated by the new inline. |
- // Exception is if the run-in itself is generated. |
- if (child->style()->styleType() != BEFORE && child->style()->styleType() != AFTER) { |
- RenderObject* generatedContent; |
- if (child->getCachedPseudoStyle(BEFORE) && (generatedContent = child->beforePseudoElementRenderer())) |
- generatedContent->destroy(); |
- if (child->getCachedPseudoStyle(AFTER) && (generatedContent = child->afterPseudoElementRenderer())) |
- generatedContent->destroy(); |
- } |
+ if (curr->isAnonymous() || curr->isFloatingOrPositioned()) |
+ return; |
- // Remove the old child. |
- children()->removeChildNode(this, blockRunIn); |
+ RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn); |
+ RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn); |
+ destroyRunIn(oldRunIn); |
- // Create an inline. |
- RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document()); |
- inlineRunIn->setStyle(blockRunIn->style()); |
+ // Now insert the new child under |curr| block. Use addChild instead of insertChildNode |
+ // since it handles correct placement of the children, especially where we cannot insert |
+ // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228. |
+ curr->addChild(newRunIn, curr->firstChild()); |
+} |
- // Move the nodes from the old child to the new child |
- for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild;) { |
- RenderObject* nextSibling = runInChild->nextSibling(); |
- blockRunIn->children()->removeChildNode(blockRunIn, runInChild); |
- inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content. |
- runInChild = nextSibling; |
- } |
+void RenderBlock::moveRunInToOriginalPosition(RenderObject* runIn) |
+{ |
+ ASSERT(runIn->isRunIn()); |
- // Now insert the new child under |currBlock|. Use addChild instead of insertChildNode since it handles correct placement of the children, esp where we cannot insert |
- // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228. |
- currBlock->addChild(inlineRunIn, currBlock->firstChild()); |
- |
- // If the run-in had an element, we need to set the new renderer. |
- if (runInNode) |
- runInNode->setRenderer(inlineRunIn); |
+ // If we don't have a parent, there is nothing to move. This might |
+ // happen if |this| got detached from parent after |runIn| run into |this|. |
+ if (!parent()) |
+ return; |
- // Destroy the block run-in, which includes deleting its line box tree. |
- blockRunIn->deleteLineBoxTree(); |
- blockRunIn->destroy(); |
+ // An intruded run-in needs to be an inline. |
+ if (!runIn->isRenderInline()) |
+ return; |
- // The block acts like an inline, so just null out its |
- // position. |
- |
- return true; |
+ RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn); |
+ RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn); |
+ destroyRunIn(oldRunIn); |
+ |
+ // Add the run-in block as our previous sibling. |
+ parent()->addChild(newRunIn, this); |
} |
LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) |