| Index: WebCore/rendering/RenderRubyBase.cpp
|
| ===================================================================
|
| --- WebCore/rendering/RenderRubyBase.cpp (revision 37095)
|
| +++ WebCore/rendering/RenderRubyBase.cpp (working copy)
|
| @@ -48,39 +48,139 @@
|
| return child->isInline();
|
| }
|
|
|
| -void RenderRubyBase::splitToLeft(RenderBlock* leftBase, RenderObject* beforeChild)
|
| +bool RenderRubyBase::hasOnlyWrappedInlineChildren(RenderObject* beforeChild) const
|
| {
|
| + // Tests whether all children in the base before beforeChild are either floated/positioned,
|
| + // or inline objects wrapped in anonymous blocks.
|
| + // Note that beforeChild may be 0, in which case all children are looked at.
|
| + for (RenderObject* child = firstChild(); child != beforeChild; child = child->nextSibling()) {
|
| + if (!child->isFloatingOrPositioned() && !(child->isAnonymousBlock() && child->childrenInline()))
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void RenderRubyBase::moveChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
|
| +{
|
| // This function removes all children that are before (!) beforeChild
|
| - // and appends them to leftBase.
|
| - ASSERT(leftBase);
|
| -
|
| + // and appends them to toBase.
|
| + ASSERT(toBase);
|
| +
|
| // First make sure that beforeChild (if set) is indeed a direct child of this.
|
| - // Fallback: climb up the tree to make sure. This may result in somewhat incorrect rendering.
|
| - // FIXME: Can this happen? Is there a better/more correct way to solve this?
|
| - ASSERT(!beforeChild || beforeChild->parent() == this);
|
| - while (beforeChild && beforeChild->parent() != this)
|
| - beforeChild = beforeChild->parent();
|
| + // Inline children might be wrapped in an anonymous block if there's a continuation.
|
| + // Theoretically, in ruby bases, this can happen with only the first such a child,
|
| + // so it should be OK to just climb the tree.
|
| + while (fromBeforeChild && fromBeforeChild->parent() != this)
|
| + fromBeforeChild = fromBeforeChild->parent();
|
|
|
| - RenderObject* child = firstChild();
|
| - while (child != beforeChild) {
|
| - RenderObject* nextChild = child->nextSibling();
|
| - moveChildTo(leftBase, leftBase->children(), child);
|
| - child = nextChild;
|
| + if (childrenInline())
|
| + moveInlineChildren(toBase, fromBeforeChild);
|
| + else
|
| + moveBlockChildren(toBase, fromBeforeChild);
|
| +
|
| + setNeedsLayoutAndPrefWidthsRecalc();
|
| + toBase->setNeedsLayoutAndPrefWidthsRecalc();
|
| +}
|
| +
|
| +void RenderRubyBase::moveInlineChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
|
| +{
|
| + RenderBlock* toBlock;
|
| +
|
| + if (toBase->childrenInline()) {
|
| + // The standard and easy case: move the children into the target base
|
| + toBlock = toBase;
|
| + } else {
|
| + // We need to wrap the inline objects into an anonymous block.
|
| + // If toBase has a suitable block, we re-use it, otherwise create a new one.
|
| + RenderObject* lastChild = toBase->lastChild();
|
| + if (lastChild && lastChild->isAnonymousBlock() && lastChild->childrenInline())
|
| + toBlock = toRenderBlock(lastChild);
|
| + else {
|
| + toBlock = toBase->createAnonymousBlock();
|
| + toBase->children()->appendChildNode(toBase, toBlock);
|
| + }
|
| }
|
| + // Move our inline children into the target block we determined above.
|
| + for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild())
|
| + moveChildTo(toBlock, toBlock->children(), child);
|
| }
|
|
|
| -void RenderRubyBase::mergeWithRight(RenderBlock* rightBase)
|
| +void RenderRubyBase::moveBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
|
| {
|
| - // This function removes all children and prepends (!) them to rightBase.
|
| - ASSERT(rightBase);
|
| + if (toBase->childrenInline()) {
|
| + // First check whether we move only wrapped inline objects.
|
| + if (hasOnlyWrappedInlineChildren(fromBeforeChild)) {
|
| + // The reason why the base is in block flow must be after beforeChild.
|
| + // We therefore can extract the inline objects and move them to toBase.
|
| + for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild()) {
|
| + if (child->isAnonymousBlock()) {
|
| + RenderBlock* anonBlock = toRenderBlock(child);
|
| + ASSERT(anonBlock->childrenInline());
|
| + ASSERT(!anonBlock->inlineContinuation());
|
| + anonBlock->moveAllChildrenTo(toBase, toBase->children());
|
| + anonBlock->deleteLineBoxTree();
|
| + anonBlock->destroy();
|
| + } else {
|
| + ASSERT(child->isFloatingOrPositioned());
|
| + moveChildTo(toBase, toBase->children(), child);
|
| + }
|
| + }
|
| + } else {
|
| + // Moving block children -> have to set toBase as block flow
|
| + toBase->makeChildrenNonInline();
|
| + // Move children, potentially collapsing anonymous block wrappers.
|
| + mergeBlockChildren(toBase, fromBeforeChild);
|
|
|
| - RenderObject* firstPos = rightBase->firstChild();
|
| - RenderObject* child = lastChild();
|
| - while (child) {
|
| - moveChildTo(rightBase, rightBase->children(), firstPos, child);
|
| - firstPos = child;
|
| - child = lastChild();
|
| + // Now we need to check if the leftover children are all inline.
|
| + // If so, make this base inline again.
|
| + if (hasOnlyWrappedInlineChildren()) {
|
| + RenderObject* next = 0;
|
| + for (RenderObject* child = firstChild(); child; child = next) {
|
| + next = child->nextSibling();
|
| + if (child->isFloatingOrPositioned())
|
| + continue;
|
| + ASSERT(child->isAnonymousBlock());
|
| +
|
| + RenderBlock* anonBlock = toRenderBlock(child);
|
| + ASSERT(anonBlock->childrenInline());
|
| + ASSERT(!anonBlock->inlineContinuation());
|
| + // Move inline children out of anonymous block.
|
| + anonBlock->moveAllChildrenTo(this, children(), anonBlock);
|
| + anonBlock->deleteLineBoxTree();
|
| + anonBlock->destroy();
|
| + }
|
| + setChildrenInline(true);
|
| + }
|
| + }
|
| + } else
|
| + mergeBlockChildren(toBase, fromBeforeChild);
|
| +}
|
| +
|
| +void RenderRubyBase::mergeBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild)
|
| +{
|
| + // This function removes all children that are before fromBeforeChild and appends them to toBase.
|
| + ASSERT(!childrenInline());
|
| + ASSERT(toBase);
|
| + ASSERT(!toBase->childrenInline());
|
| +
|
| + // Quick check whether we have anything to do, to simplify the following code.
|
| + if (fromBeforeChild != firstChild())
|
| + return;
|
| +
|
| + // If an anonymous block would be put next to another such block, then merge those.
|
| + RenderObject* firstChildHere = firstChild();
|
| + RenderObject* lastChildThere = toBase->lastChild();
|
| + if (firstChildHere && firstChildHere->isAnonymousBlock() && firstChildHere->childrenInline()
|
| + && lastChildThere && lastChildThere->isAnonymousBlock() && lastChildThere->childrenInline()) {
|
| + RenderBlock* anonBlockHere = toRenderBlock(firstChildHere);
|
| + RenderBlock* anonBlockThere = toRenderBlock(lastChildThere);
|
| + anonBlockHere->moveAllChildrenTo(anonBlockThere, anonBlockThere->children());
|
| + anonBlockHere->deleteLineBoxTree();
|
| + anonBlockHere->destroy();
|
| }
|
| + // Move all remaining children normally.
|
| + for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild())
|
| + moveChildTo(toBase, toBase->children(), child);
|
| }
|
|
|
| } // namespace WebCore
|
|
|