Changeset 21472 in webkit


Ignore:
Timestamp:
May 14, 2007 6:41:53 PM (17 years ago)
Author:
bdash
Message:

2007-05-14 Mitz Pettel <mitz@webkit.org>

Reviewed by Dave Hyatt.

Test: fast/parser/residual-style-close-across-n-blocks.html

  • html/HTMLParser.cpp: (WebCore::HTMLParser::handleResidualStyleCloseTagAcrossBlocks): Changed to deal with multiple block crossings instead of bailing out, by doing multiple reparenting passes, starting from the outermost block.

2007-05-14 Mitz Pettel <mitz@webkit.org>

Reviewed by Dave Hyatt.

  • fast/parser/residual-style-close-across-n-blocks-expected.txt: Added.
  • fast/parser/residual-style-close-across-n-blocks.html: Added.
Location:
trunk
Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r21470 r21472  
     12007-05-14  Mitz Pettel  <mitz@webkit.org>
     2
     3        Reviewed by Dave Hyatt.
     4
     5        - test for http://bugs.webkit.org/show_bug.cgi?id=13603
     6          style leaks in washingtonpost.com
     7
     8        * fast/parser/residual-style-close-across-n-blocks-expected.txt: Added.
     9        * fast/parser/residual-style-close-across-n-blocks.html: Added.
     10
    1112007-05-14  Sam Weinig  <sam@webkit.org>
    212
  • trunk/WebCore/ChangeLog

    r21471 r21472  
     12007-05-14  Mitz Pettel  <mitz@webkit.org>
     2
     3        Reviewed by Dave Hyatt.
     4
     5        - fix http://bugs.webkit.org/show_bug.cgi?id=13603
     6          style leaks in washingtonpost.com
     7          also known as http://bugs.webkit.org/show_bug.cgi?id=8750
     8          w3c.org: incorrect recovery from unclosed <a> elements
     9          also known as http://bugs.webkit.org/show_bug.cgi?id=12808
     10          Handling of misnested tags results in entire page appearing as link
     11          also known as http://bugs.webkit.org/show_bug.cgi?id=12861
     12          Post text renders as link
     13
     14        Test: fast/parser/residual-style-close-across-n-blocks.html
     15
     16        * html/HTMLParser.cpp:
     17        (WebCore::HTMLParser::handleResidualStyleCloseTagAcrossBlocks): Changed to
     18        deal with multiple block crossings instead of bailing out, by doing multiple
     19        reparenting passes, starting from the outermost block.
     20
    1212007-05-14  Mitz Pettel  <mitz@webkit.org>
    222
  • trunk/WebCore/html/HTMLParser.cpp

    r21439 r21472  
    978978void HTMLParser::handleResidualStyleCloseTagAcrossBlocks(HTMLStackElem* elem)
    979979{
    980     // Find the element that crosses over to a higher level.   For now, if there is more than
    981     // one, we will just give up and not attempt any sort of correction.  It's highly unlikely that
    982     // there will be more than one, since <p> tags aren't allowed to be nested.
    983     ExceptionCode ec = 0;
    984     HTMLStackElem* curr = blockStack;
    985     HTMLStackElem* maxElem = 0;
    986     HTMLStackElem* prev = 0;
    987     HTMLStackElem* prevMaxElem = 0;
    988     while (curr && curr != elem) {
    989         if (curr->level > elem->level) {
    990             if (maxElem)
    991                 return;
    992             maxElem = curr;
    993             prevMaxElem = prev;
     980    HTMLStackElem* maxElem;
     981    bool finished = false;
     982    while (!finished) {
     983        // Find the outermost element that crosses over to a higher level. If there exists another higher-level
     984        // element, we will do another pass, until we have corrected the innermost one.
     985        ExceptionCode ec = 0;
     986        HTMLStackElem* curr = blockStack;
     987        HTMLStackElem* prev = 0;
     988        HTMLStackElem* prevMaxElem = 0;
     989        maxElem = 0;
     990        finished = true;
     991        while (curr && curr != elem) {
     992            if (curr->level > elem->level) {
     993                if (!isAffectedByResidualStyle(curr->tagName))
     994                    return;
     995                if (maxElem)
     996                    // We will need another pass.
     997                    finished = false;
     998                maxElem = curr;
     999                prevMaxElem = prev;
     1000            }
     1001
     1002            prev = curr;
     1003            curr = curr->next;
    9941004        }
    9951005
    996         prev = curr;
    997         curr = curr->next;
    998     }
    999 
    1000     if (!curr || !maxElem || !isAffectedByResidualStyle(maxElem->tagName)) return;
    1001 
    1002     Node* residualElem = prev->node;
    1003     Node* blockElem = prevMaxElem ? prevMaxElem->node : current;
    1004     Node* parentElem = elem->node;
    1005 
    1006     // Check to see if the reparenting that is going to occur is allowed according to the DOM.
    1007     // FIXME: We should either always allow it or perform an additional fixup instead of
    1008     // just bailing here.
    1009     // Example: <p><font><center>blah</font></center></p> isn't doing a fixup right now.
    1010     if (!parentElem->childAllowed(blockElem))
    1011         return;
    1012    
    1013     if (maxElem->node->parentNode() != elem->node) {
    1014         // Walk the stack and remove any elements that aren't residual style tags.  These
    1015         // are basically just being closed up.  Example:
    1016         // <font><span>Moo<p>Goo</font></p>.
    1017         // In the above example, the <span> doesn't need to be reopened.  It can just close.
    1018         HTMLStackElem* currElem = maxElem->next;
    1019         HTMLStackElem* prevElem = maxElem;
     1006        if (!curr || !maxElem)
     1007            return;
     1008
     1009        Node* residualElem = prev->node;
     1010        Node* blockElem = prevMaxElem ? prevMaxElem->node : current;
     1011        Node* parentElem = elem->node;
     1012
     1013        // Check to see if the reparenting that is going to occur is allowed according to the DOM.
     1014        // FIXME: We should either always allow it or perform an additional fixup instead of
     1015        // just bailing here.
     1016        // Example: <p><font><center>blah</font></center></p> isn't doing a fixup right now.
     1017        if (!parentElem->childAllowed(blockElem))
     1018            return;
     1019
     1020        if (maxElem->node->parentNode() != elem->node) {
     1021            // Walk the stack and remove any elements that aren't residual style tags.  These
     1022            // are basically just being closed up.  Example:
     1023            // <font><span>Moo<p>Goo</font></p>.
     1024            // In the above example, the <span> doesn't need to be reopened.  It can just close.
     1025            HTMLStackElem* currElem = maxElem->next;
     1026            HTMLStackElem* prevElem = maxElem;
     1027            while (currElem != elem) {
     1028                HTMLStackElem* nextElem = currElem->next;
     1029                if (!isResidualStyleTag(currElem->tagName)) {
     1030                    prevElem->next = nextElem;
     1031                    prevElem->derefNode();
     1032                    prevElem->node = currElem->node;
     1033                    prevElem->didRefNode = currElem->didRefNode;
     1034                    delete currElem;
     1035                }
     1036                else
     1037                    prevElem = currElem;
     1038                currElem = nextElem;
     1039            }
     1040
     1041            // We have to reopen residual tags in between maxElem and elem.  An example of this case is:
     1042            // <font><i>Moo<p>Foo</font>.
     1043            // In this case, we need to transform the part before the <p> into:
     1044            // <font><i>Moo</i></font><i>
     1045            // so that the <i> will remain open.  This involves the modification of elements
     1046            // in the block stack.
     1047            // This will also affect how we ultimately reparent the block, since we want it to end up
     1048            // under the reopened residual tags (e.g., the <i> in the above example.)
     1049            RefPtr<Node> prevNode = 0;
     1050            currElem = maxElem;
     1051            while (currElem->node != residualElem) {
     1052                if (isResidualStyleTag(currElem->node->localName())) {
     1053                    // Create a clone of this element.
     1054                    // We call releaseRef to get a raw pointer since we plan to hand over ownership to currElem.
     1055                    Node* currNode = currElem->node->cloneNode(false).releaseRef();
     1056
     1057                    // Change the stack element's node to point to the clone.
     1058                    // The stack element adopts the reference we obtained above by calling release().
     1059                    currElem->derefNode();
     1060                    currElem->node = currNode;
     1061                    currElem->didRefNode = true;
     1062
     1063                    // Attach the previous node as a child of this new node.
     1064                    if (prevNode)
     1065                        currNode->appendChild(prevNode, ec);
     1066                    else // The new parent for the block element is going to be the innermost clone.
     1067                        parentElem = currNode;
     1068
     1069                    prevNode = currNode;
     1070                }
     1071
     1072                currElem = currElem->next;
     1073            }
     1074
     1075            // Now append the chain of new residual style elements if one exists.
     1076            if (prevNode)
     1077                elem->node->appendChild(prevNode, ec);
     1078        }
     1079
     1080        // Check if the block is still in the tree. If it isn't, then we don't
     1081        // want to remove it from its parent (that would crash) or insert it into
     1082        // a new parent later. See http://bugs.webkit.org/show_bug.cgi?id=6778
     1083        bool isBlockStillInTree = blockElem->parentNode();
     1084
     1085        // We need to make a clone of |residualElem| and place it just inside |blockElem|.
     1086        // All content of |blockElem| is reparented to be under this clone.  We then
     1087        // reparent |blockElem| using real DOM calls so that attachment/detachment will
     1088        // be performed to fix up the rendering tree.
     1089        // So for this example: <b>...<p>Foo</b>Goo</p>
     1090        // The end result will be: <b>...</b><p><b>Foo</b>Goo</p>
     1091        //
     1092        // Step 1: Remove |blockElem| from its parent, doing a batch detach of all the kids.
     1093        if (m_currentFormElement)
     1094            m_currentFormElement->setPreserveAcrossRemove(true);
     1095        if (isBlockStillInTree)
     1096            blockElem->parentNode()->removeChild(blockElem, ec);
     1097
     1098        // Step 2: Clone |residualElem|.
     1099        RefPtr<Node> newNode = residualElem->cloneNode(false); // Shallow clone. We don't pick up the same kids.
     1100        Node* newNodePtr = newNode.get();
     1101
     1102        // Step 3: Place |blockElem|'s children under |newNode|.  Remove all of the children of |blockElem|
     1103        // before we've put |newElem| into the document.  That way we'll only do one attachment of all
     1104        // the new content (instead of a bunch of individual attachments).
     1105        Node* currNode = blockElem->firstChild();
     1106        while (currNode) {
     1107            Node* nextNode = currNode->nextSibling();
     1108            newNode->appendChild(currNode, ec);
     1109            currNode = nextNode;
     1110        }
     1111
     1112        // Step 4: Place |newNode| under |blockElem|.  |blockElem| is still out of the document, so no
     1113        // attachment can occur yet.
     1114        blockElem->appendChild(newNode.release(), ec);
     1115
     1116        // Step 5: Reparent |blockElem|.  Now the full attachment of the fixed up tree takes place.
     1117        if (isBlockStillInTree)
     1118            parentElem->appendChild(blockElem, ec);
     1119
     1120        // Step 6: Pull |elem| out of the stack, since it is no longer enclosing us.  Also update
     1121        // the node associated with the previous stack element so that when it gets popped,
     1122        // it doesn't make the residual element the next current node.
     1123        HTMLStackElem* currElem = maxElem;
     1124        HTMLStackElem* prevElem = 0;
    10201125        while (currElem != elem) {
    1021             HTMLStackElem* nextElem = currElem->next;
    1022             if (!isResidualStyleTag(currElem->tagName)) {
    1023                 prevElem->next = nextElem;
    1024                 prevElem->derefNode();
    1025                 prevElem->node = currElem->node;
    1026                 prevElem->didRefNode = currElem->didRefNode;
    1027                 delete currElem;
    1028             }
    1029             else
    1030                 prevElem = currElem;
    1031             currElem = nextElem;
    1032         }
    1033        
    1034         // We have to reopen residual tags in between maxElem and elem.  An example of this case is:
    1035         // <font><i>Moo<p>Foo</font>.
    1036         // In this case, we need to transform the part before the <p> into:
    1037         // <font><i>Moo</i></font><i>
    1038         // so that the <i> will remain open.  This involves the modification of elements
    1039         // in the block stack.
    1040         // This will also affect how we ultimately reparent the block, since we want it to end up
    1041         // under the reopened residual tags (e.g., the <i> in the above example.)
    1042         RefPtr<Node> prevNode = 0;
    1043         currElem = maxElem;
    1044         while (currElem->node != residualElem) {
    1045             if (isResidualStyleTag(currElem->node->localName())) {
    1046                 // Create a clone of this element.
    1047                 // We call releaseRef to get a raw pointer since we plan to hand over ownership to currElem.
    1048                 Node* currNode = currElem->node->cloneNode(false).releaseRef();
    1049 
    1050                 // Change the stack element's node to point to the clone.
    1051                 // The stack element adopts the reference we obtained above by calling release().
    1052                 currElem->derefNode();
    1053                 currElem->node = currNode;
    1054                 currElem->didRefNode = true;
    1055                
    1056                 // Attach the previous node as a child of this new node.
    1057                 if (prevNode)
    1058                     currNode->appendChild(prevNode, ec);
    1059                 else // The new parent for the block element is going to be the innermost clone.
    1060                     parentElem = currNode;
    1061                                
    1062                 prevNode = currNode;
    1063             }
    1064            
     1126            prevElem = currElem;
    10651127            currElem = currElem->next;
    10661128        }
    1067 
    1068         // Now append the chain of new residual style elements if one exists.
    1069         if (prevNode)
    1070             elem->node->appendChild(prevNode, ec);
    1071     }
    1072          
    1073     // Check if the block is still in the tree. If it isn't, then we don't
    1074     // want to remove it from its parent (that would crash) or insert it into
    1075     // a new parent later. See http://bugs.webkit.org/show_bug.cgi?id=6778
    1076     bool isBlockStillInTree = blockElem->parentNode();
    1077 
    1078     // We need to make a clone of |residualElem| and place it just inside |blockElem|.
    1079     // All content of |blockElem| is reparented to be under this clone.  We then
    1080     // reparent |blockElem| using real DOM calls so that attachment/detachment will
    1081     // be performed to fix up the rendering tree.
    1082     // So for this example: <b>...<p>Foo</b>Goo</p>
    1083     // The end result will be: <b>...</b><p><b>Foo</b>Goo</p>
    1084     //
    1085     // Step 1: Remove |blockElem| from its parent, doing a batch detach of all the kids.
    1086     if (m_currentFormElement)
    1087         m_currentFormElement->setPreserveAcrossRemove(true);
    1088     if (isBlockStillInTree)
    1089         blockElem->parentNode()->removeChild(blockElem, ec);
    1090 
    1091     // Step 2: Clone |residualElem|.
    1092     RefPtr<Node> newNode = residualElem->cloneNode(false); // Shallow clone. We don't pick up the same kids.
    1093 
    1094     // Step 3: Place |blockElem|'s children under |newNode|.  Remove all of the children of |blockElem|
    1095     // before we've put |newElem| into the document.  That way we'll only do one attachment of all
    1096     // the new content (instead of a bunch of individual attachments).
    1097     Node* currNode = blockElem->firstChild();
    1098     while (currNode) {
    1099         Node* nextNode = currNode->nextSibling();
    1100         newNode->appendChild(currNode, ec);
    1101         currNode = nextNode;
    1102     }
    1103 
    1104     // Step 4: Place |newNode| under |blockElem|.  |blockElem| is still out of the document, so no
    1105     // attachment can occur yet.
    1106     blockElem->appendChild(newNode.release(), ec);
    1107    
    1108     // Step 5: Reparent |blockElem|.  Now the full attachment of the fixed up tree takes place.
    1109     if (isBlockStillInTree)
    1110         parentElem->appendChild(blockElem, ec);
    1111        
    1112     // Step 6: Elide |elem|, since it is effectively no longer open.  Also update
    1113     // the node associated with the previous stack element so that when it gets popped,
    1114     // it doesn't make the residual element the next current node.
    1115     HTMLStackElem* currElem = maxElem;
    1116     HTMLStackElem* prevElem = 0;
    1117     while (currElem != elem) {
    1118         prevElem = currElem;
    1119         currElem = currElem->next;
    1120     }
    1121     prevElem->next = elem->next;
    1122     prevElem->derefNode();
    1123     prevElem->node = elem->node;
    1124     prevElem->didRefNode = elem->didRefNode;
    1125     delete elem;
    1126    
     1129        prevElem->next = elem->next;
     1130        prevElem->derefNode();
     1131        prevElem->node = elem->node;
     1132        prevElem->didRefNode = elem->didRefNode;
     1133        if (!finished) {
     1134            // Repurpose |elem| to represent |newNode| and insert it at the appropriate position
     1135            // in the stack. We do not do this for the innermost block, because in that case the new
     1136            // node is effectively no longer open.
     1137            elem->next = maxElem;
     1138            elem->node = prevMaxElem->node;
     1139            elem->didRefNode = prevMaxElem->didRefNode;
     1140            prevMaxElem->next = elem;
     1141            prevMaxElem->node = newNodePtr;
     1142            prevMaxElem->didRefNode = false;
     1143        } else
     1144            delete elem;
     1145    }
     1146
    11271147    // Step 7: Reopen intermediate inlines, e.g., <b><p><i>Foo</b>Goo</p>.
    11281148    // In the above example, Goo should stay italic.
    11291149    // We cap the number of tags we're willing to reopen based off cResidualStyleMaxDepth.
    1130     curr = blockStack;
     1150    HTMLStackElem* curr = blockStack;
    11311151    HTMLStackElem* residualStyleStack = 0;
    11321152    unsigned stackDepth = 1;
     
    11521172    reopenResidualStyleTags(residualStyleStack, 0); // FIXME: Deal with stray table content some day
    11531173                                                    // if it becomes necessary to do so.
    1154                                                    
     1174
    11551175    if (m_currentFormElement)
    11561176        m_currentFormElement->setPreserveAcrossRemove(false);
Note: See TracChangeset for help on using the changeset viewer.