doesn't need to be reopened. It can just close.
HTMLStackElem* currElem = maxElem->next;
HTMLStackElem* prevElem = maxElem;
while (currElem != elem) {
HTMLStackElem* nextElem = currElem->next;
if (!isResidualStyleTag(currElem->tagName)) {
prevElem->next = nextElem;
prevElem->derefNode();
prevElem->node = currElem->node;
prevElem->didRefNode = currElem->didRefNode;
delete currElem;
}
else
prevElem = currElem;
currElem = nextElem;
}
// We have to reopen residual tags in between maxElem and elem. An example of this case is:
// MooFoo
.
// In this case, we need to transform the part before the into:
// Moo
// so that the will remain open. This involves the modification of elements
// in the block stack.
// This will also affect how we ultimately reparent the block, since we want it to end up
// under the reopened residual tags (e.g., the in the above example.)
RefPtr prevNode = 0;
currElem = maxElem;
while (currElem->node != residualElem) {
if (isResidualStyleTag(currElem->node->localName())) {
// Create a clone of this element.
// We call releaseRef to get a raw pointer since we plan to hand over ownership to currElem.
Node* currNode = currElem->node->cloneNode(false).releaseRef();
reportError(ResidualStyleError, &currNode->localName());
// Change the stack element's node to point to the clone.
// The stack element adopts the reference we obtained above by calling release().
currElem->derefNode();
currElem->node = currNode;
currElem->didRefNode = true;
// Attach the previous node as a child of this new node.
if (prevNode)
currNode->appendChild(prevNode, ec);
else // The new parent for the block element is going to be the innermost clone.
parentElem = currNode; // FIXME: We shifted parentElem to be a residual inline. We never checked to see if blockElem could be legally placed inside the inline though.
prevNode = currNode;
}
currElem = currElem->next;
}
// Now append the chain of new residual style elements if one exists.
if (prevNode)
elem->node->appendChild(prevNode, ec); // FIXME: This append can result in weird stuff happening, like an inline chain being put into a table section.
}
// Check if the block is still in the tree. If it isn't, then we don't
// want to remove it from its parent (that would crash) or insert it into
// a new parent later. See http://bugs.webkit.org/show_bug.cgi?id=6778
bool isBlockStillInTree = blockElem->parentNode();
// We need to make a clone of |residualElem| and place it just inside |blockElem|.
// All content of |blockElem| is reparented to be under this clone. We then
// reparent |blockElem| using real DOM calls so that attachment/detachment will
// be performed to fix up the rendering tree.
// So for this example: ...FooGoo
// The end result will be: ...FooGoo
//
// Step 1: Remove |blockElem| from its parent, doing a batch detach of all the kids.
if (isBlockStillInTree)
blockElem->parentNode()->removeChild(blockElem, ec);
Node* newNodePtr = 0;
if (blockElem->firstChild()) {
// Step 2: Clone |residualElem|.
RefPtr newNode = residualElem->cloneNode(false); // Shallow clone. We don't pick up the same kids.
newNodePtr = newNode.get();
reportError(ResidualStyleError, &newNode->localName());
// Step 3: Place |blockElem|'s children under |newNode|. Remove all of the children of |blockElem|
// before we've put |newElem| into the document. That way we'll only do one attachment of all
// the new content (instead of a bunch of individual attachments).
Node* currNode = blockElem->firstChild();
while (currNode) {
Node* nextNode = currNode->nextSibling();
newNode->appendChild(currNode, ec);
currNode = nextNode;
}
// Step 4: Place |newNode| under |blockElem|. |blockElem| is still out of the document, so no
// attachment can occur yet.
blockElem->appendChild(newNode.release(), ec);
} else
finished = true;
// Step 5: Reparent |blockElem|. Now the full attachment of the fixed up tree takes place.
if (isBlockStillInTree)
parentElem->appendChild(blockElem, ec);
// Step 6: Pull |elem| out of the stack, since it is no longer enclosing us. Also update
// the node associated with the previous stack element so that when it gets popped,
// it doesn't make the residual element the next current node.
HTMLStackElem* currElem = maxElem;
HTMLStackElem* prevElem = 0;
while (currElem != elem) {
prevElem = currElem;
currElem = currElem->next;
}
prevElem->next = elem->next;
prevElem->derefNode();
prevElem->node = elem->node;
prevElem->didRefNode = elem->didRefNode;
if (!finished) {
// Repurpose |elem| to represent |newNode| and insert it at the appropriate position
// in the stack. We do not do this for the innermost block, because in that case the new
// node is effectively no longer open.
elem->next = maxElem;
elem->node = prevMaxElem->node;
elem->didRefNode = prevMaxElem->didRefNode;
elem->strayTableContent = false;
prevMaxElem->next = elem;
ASSERT(newNodePtr);
prevMaxElem->node = newNodePtr;
prevMaxElem->didRefNode = false;
} else
delete elem;
}
// FIXME: If we ever make a case like this work:
//
// Then this check will be too simplistic. Right now the