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.
RefPtr currNode = currElem->node->cloneNode(false);
// Change the stack element's node to point to the clone.
currElem->node = currNode;
// 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.get();
prevNode = currNode.get();
}
currElem = currElem->next;
}
// Now append the chain of new residual style elements if one exists.
if (prevNode)
elem->node->appendChild(prevNode, ec);
}
// 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://bugzilla.opendarwin.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 (form)
form->setPreserveAcrossRemove(true);
if (isBlockStillInTree)
blockElem->parentNode()->removeChild(blockElem, ec);
// Step 2: Clone |residualElem|.
RefPtr newNode = residualElem->cloneNode(false); // Shallow clone. We don't pick up the same kids.
// 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);
// Step 5: Reparent |blockElem|. Now the full attachment of the fixed up tree takes place.
if (isBlockStillInTree)
parentElem->appendChild(blockElem, ec);
// Step 6: Elide |elem|, since it is effectively no longer open. 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->node = elem->node;
delete elem;
// Step 7: Reopen intermediate inlines, e.g.,

FooGoo

.
// In the above example, Goo should stay italic.
curr = blockStack;
HTMLStackElem* residualStyleStack = 0;
while (curr && curr != maxElem) {
// We will actually schedule this tag for reopening
// after we complete the close of this entire block.
Node* currNode = current;
if (isResidualStyleTag(curr->tagName)) {
// We've overloaded the use of stack elements and are just reusing the
// struct with a slightly different meaning to the variables. Instead of chaining
// from innermost to outermost, we build up a list of all the tags we need to reopen
// from the outermost to the innermost, i.e., residualStyleStack will end up pointing
// to the outermost tag we need to reopen.
// We also set curr->node to be the actual element that corresponds to the ID stored in
// curr->id rather than the node that you should pop to when the element gets pulled off
// the stack.
popOneBlock(false);
curr->node = currNode;
curr->next = residualStyleStack;
residualStyleStack = curr;
}
else
popOneBlock();
curr = blockStack;
}
reopenResidualStyleTags(residualStyleStack, 0); // FIXME: Deal with stray table content some day
// if it becomes necessary to do so.
if (form)
form->setPreserveAcrossRemove(false);
}
void HTMLParser::reopenResidualStyleTags(HTMLStackElem* elem, Node* malformedTableParent)
{
// Loop for each tag that needs to be reopened.
while (elem) {
// Create a shallow clone of the DOM node for this element.
RefPtr newNode = elem->node->cloneNode(false);
// Append the new node. In the malformed table case, we need to insert before the table,
// which will be the last child.
ExceptionCode ec = 0;
if (malformedTableParent)
malformedTableParent->insertBefore(newNode, malformedTableParent->lastChild(), ec);
else
current->appendChild(newNode, ec);
// FIXME: Is it really OK to ignore the exceptions here?
// Now push a new stack element for this node we just created.
pushBlock(elem->tagName, elem->level);
// Set our strayTableContent boolean if needed, so that the reopened tag also knows
// that it is inside a malformed table.
blockStack->strayTableContent = malformedTableParent != 0;
if (blockStack->strayTableContent)
inStrayTableContent++;
// Clear our malformed table parent variable.
malformedTableParent = 0;
// Update |current| manually to point to the new node.
setCurrent(newNode.get());
// Advance to the next tag that needs to be reopened.
HTMLStackElem* next = elem->next;
delete elem;
elem = next;
}
}
void HTMLParser::pushBlock(const AtomicString& tagName, int _level)
{
HTMLStackElem *Elem = new HTMLStackElem(tagName, _level, current, blockStack);
blockStack = Elem;
}
void HTMLParser::popBlock(const AtomicString& _tagName)
{
HTMLStackElem *Elem = blockStack;
int maxLevel = 0;
while (Elem && (Elem->tagName != _tagName)) {
if (maxLevel < Elem->level)
maxLevel = Elem->level;
Elem = Elem->next;
}
if (!Elem)
return;
if (maxLevel > Elem->level) {
// We didn't match because the tag is in a different scope, e.g.,
//

.
// If we end up needing to reopen residual style tags, the root of the reopened chain
// must also know that it is the root of malformed content inside a

/

.
if (strayTable && (inStrayTableContent < strayTable) && residualStyleStack) {
Node* curr = current;
while (curr && !curr->hasTagName(tableTag))
curr = curr->parentNode();
malformedTableParent = curr ? curr->parentNode() : 0;
}
}
else {
if (form && Elem->tagName == formTag)
// A is being closed prematurely (and this is
// malformed HTML). Set an attribute on the form to clear out its
// bottom margin.
form->setMalformed(true);
// Schedule this tag for reopening
// after we complete the close of this entire block.
Node* currNode = current;
if (isAffectedByStyle && isResidualStyleTag(Elem->tagName)) {
// We've overloaded the use of stack elements and are just reusing the
// struct with a slightly different meaning to the variables. Instead of chaining
// from innermost to outermost, we build up a list of all the tags we need to reopen
// from the outermost to the innermost, i.e., residualStyleStack will end up pointing
// to the outermost tag we need to reopen.
// We also set Elem->node to be the actual element that corresponds to the ID stored in
// Elem->id rather than the node that you should pop to when the element gets pulled off
// the stack.
popOneBlock(false);
Elem->next = residualStyleStack;
Elem->node = currNode;
residualStyleStack = Elem;
}
else
popOneBlock();
Elem = blockStack;
}
}
reopenResidualStyleTags(residualStyleStack, malformedTableParent);
}
void HTMLParser::popOneBlock(bool delBlock)
{
HTMLStackElem* elem = blockStack;
// Form elements restore their state during the parsing process.
// Also, a few elements (