[HTMLTemplateElement] Prevent first-level recursive <template> from resetting the...
authoradamk@chromium.org <adamk@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Dec 2012 21:06:33 +0000 (21:06 +0000)
committeradamk@chromium.org <adamk@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Dec 2012 21:06:33 +0000 (21:06 +0000)
https://bugs.webkit.org/show_bug.cgi?id=104142

Reviewed by Eric Seidel.

Source/WebCore:

This patch adds a stack of InsertionModes retains the chosen
"implied context" for each template element.

Based on a patch by Rafael Weinstein.

Tests added to html5lib/run-template.html

* html/parser/HTMLTreeBuilder.cpp:
(WebCore::HTMLTreeBuilder::HTMLTreeBuilder): Initialize the stack appropriately for HTMLTemplateElement.innerHTML.
(WebCore::HTMLTreeBuilder::processTemplateStartTag):
(WebCore::HTMLTreeBuilder::processTemplateEndTag):
(WebCore::HTMLTreeBuilder::processStartTag): Once we've figured out the insertion mode for a given <template> store it in the stack.
(WebCore::HTMLTreeBuilder::resetInsertionModeAppropriately):
(WebCore::HTMLTreeBuilder::processEndTag):
(WebCore::HTMLTreeBuilder::processEndOfFile): Clear the stack if we hit end of file to allow the assertion in finish().
(WebCore::HTMLTreeBuilder::finished):
* html/parser/HTMLTreeBuilder.h:
(HTMLTreeBuilder):

LayoutTests:

Added test that the original template context is retained after inner template.

* html5lib/resources/template.dat:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@138059 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/html5lib/resources/template.dat
Source/WebCore/ChangeLog
Source/WebCore/html/parser/HTMLTreeBuilder.cpp
Source/WebCore/html/parser/HTMLTreeBuilder.h

index c3ef12b..18b597e 100644 (file)
@@ -1,3 +1,14 @@
+2012-12-18  Adam Klein  <adamk@chromium.org>
+
+        [HTMLTemplateElement] Prevent first-level recursive <template> from resetting the implied context
+        https://bugs.webkit.org/show_bug.cgi?id=104142
+
+        Reviewed by Eric Seidel.
+
+        Added test that the original template context is retained after inner template.
+
+        * html5lib/resources/template.dat:
+
 2012-12-18  Hans Muller  <hmuller@adobe.com>
 
         [CSS Exclusions] shape-inside layout fails to adjust first line correctly for writing-mode: vertical-rl
index 1bae81e..fdc249b 100644 (file)
 |         <tr>
 |         <template>
 |           #document-fragment
-|         <td>
+|         <tr>
+|           <td>
+
+#data
+<body><template><thead></thead><template><tr></tr></template><tr></tr><tfoot></tfoot></template>
+#errors
+#document
+| <html>
+|   <head>
+|   <body>
+|     <template>
+|       #document-fragment
+|         <thead>
+|         <template>
+|           #document-fragment
+|             <tr>
+|         <tbody>
+|           <tr>
+|         <tfoot>
index f12c7bf..47d4886 100644 (file)
@@ -1,3 +1,29 @@
+2012-12-18  Adam Klein  <adamk@chromium.org>
+
+        [HTMLTemplateElement] Prevent first-level recursive <template> from resetting the implied context
+        https://bugs.webkit.org/show_bug.cgi?id=104142
+
+        Reviewed by Eric Seidel.
+
+        This patch adds a stack of InsertionModes retains the chosen
+        "implied context" for each template element.
+
+        Based on a patch by Rafael Weinstein.
+
+        Tests added to html5lib/run-template.html
+
+        * html/parser/HTMLTreeBuilder.cpp:
+        (WebCore::HTMLTreeBuilder::HTMLTreeBuilder): Initialize the stack appropriately for HTMLTemplateElement.innerHTML.
+        (WebCore::HTMLTreeBuilder::processTemplateStartTag):
+        (WebCore::HTMLTreeBuilder::processTemplateEndTag):
+        (WebCore::HTMLTreeBuilder::processStartTag): Once we've figured out the insertion mode for a given <template> store it in the stack.
+        (WebCore::HTMLTreeBuilder::resetInsertionModeAppropriately):
+        (WebCore::HTMLTreeBuilder::processEndTag):
+        (WebCore::HTMLTreeBuilder::processEndOfFile): Clear the stack if we hit end of file to allow the assertion in finish().
+        (WebCore::HTMLTreeBuilder::finished):
+        * html/parser/HTMLTreeBuilder.h:
+        (HTMLTreeBuilder):
+
 2012-12-18  Andrew Lo  <anlo@rim.com>
 
         [BlackBerry] Use midpoint for fixed position heuristic
index 6974c64..2e524e4 100644 (file)
@@ -303,6 +303,12 @@ HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser* parser, DocumentFragment* f
         // For efficiency, we skip step 4.2 ("Let root be a new html element with no attributes")
         // and instead use the DocumentFragment as a root node.
         m_tree.openElements()->pushRootNode(HTMLStackItem::create(fragment, HTMLStackItem::ItemForDocumentFragmentNode));
+
+#if ENABLE(TEMPLATE_ELEMENT)
+        if (contextElement->hasLocalName(templateTag))
+            m_templateInsertionModes.append(TemplateContentsMode);
+#endif
+
         resetInsertionModeAppropriately();
         m_tree.setForm(closestFormAncestor(contextElement));
     }
@@ -960,11 +966,11 @@ void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken* token)
 }
 
 #if ENABLE(TEMPLATE_ELEMENT)
-
 void HTMLTreeBuilder::processTemplateStartTag(AtomicHTMLToken* token)
 {
     m_tree.activeFormattingElements()->appendMarker();
     m_tree.insertHTMLElement(token);
+    m_templateInsertionModes.append(TemplateContentsMode);
     setInsertionMode(TemplateContentsMode);
 }
 
@@ -979,6 +985,7 @@ void HTMLTreeBuilder::processTemplateEndTag(AtomicHTMLToken* token)
         parseError(token);
     m_tree.openElements()->popUntilPopped(token->name());
     m_tree.activeFormattingElements()->clearToLastMarker();
+    m_templateInsertionModes.removeLast();
     resetInsertionModeAppropriately();
 }
 #endif
@@ -1441,18 +1448,24 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token)
             return;
         }
 
+        InsertionMode insertionMode = TemplateContentsMode;
         if (token->name() == frameTag)
-            setInsertionMode(InFramesetMode);
+            insertionMode = InFramesetMode;
         else if (token->name() == colTag)
-            setInsertionMode(InColumnGroupMode);
+            insertionMode = InColumnGroupMode;
         else if (isCaptionColOrColgroupTag(token->name()) || isTableBodyContextTag(token->name()))
-            setInsertionMode(InTableMode);
+            insertionMode = InTableMode;
         else if (token->name() == trTag)
-            setInsertionMode(InTableBodyMode);
+            insertionMode = InTableBodyMode;
         else if (isTableCellContextTag(token->name()))
-            setInsertionMode(InRowMode);
+            insertionMode = InRowMode;
         else
-            setInsertionMode(InBodyMode);
+            insertionMode = InBodyMode;
+
+        ASSERT(insertionMode != TemplateContentsMode);
+        ASSERT(m_templateInsertionModes.last() == TemplateContentsMode);
+        m_templateInsertionModes.last() = insertionMode;
+        setInsertionMode(insertionMode);
 
         processStartTag(token);
 #else
@@ -1641,9 +1654,8 @@ void HTMLTreeBuilder::resetInsertionModeAppropriately()
             item = HTMLStackItem::create(m_fragmentContext.contextElement(), HTMLStackItem::ItemForContextElement);
         }
 #if ENABLE(TEMPLATE_ELEMENT)
-        // FIXME: https://www.w3.org/Bugs/Public/show_bug.cgi?id=20130 (should <template> clear the "implied context element".
         if (item->hasTagName(templateTag))
-            return setInsertionMode(TemplateContentsMode);
+            return setInsertionMode(m_templateInsertionModes.last());
 #endif
         if (item->hasTagName(selectTag)) {
             return setInsertionMode(InSelectMode);
@@ -2275,6 +2287,7 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken* token)
         if (token->name() == templateTag) {
             ASSERT(m_tree.currentStackItem()->hasTagName(templateTag));
             m_tree.openElements()->pop();
+            m_templateInsertionModes.removeLast();
             resetInsertionModeAppropriately();
             return;
         }
@@ -2501,6 +2514,9 @@ void HTMLTreeBuilder::processCharacterBufferForInBody(ExternalCharacterTokenBuff
 void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token)
 {
     ASSERT(token->type() == HTMLTokenTypes::EndOfFile);
+#if ENABLE(TEMPLATE_ELEMENT)
+    m_templateInsertionModes.clear();
+#endif
     switch (insertionMode()) {
     case InitialMode:
         ASSERT(insertionMode() == InitialMode);
@@ -2884,7 +2900,11 @@ void HTMLTreeBuilder::finished()
 {
     if (isParsingFragment())
         return;
-    
+
+#if ENABLE(TEMPLATE_ELEMENT)
+    ASSERT(m_templateInsertionModes.isEmpty());
+#endif
+
     ASSERT(m_document);
     // Warning, this may detach the parser. Do not do anything else after this.
     m_document->finishedParsing();
index 213e7e0..64a09a3 100644 (file)
@@ -37,6 +37,7 @@
 #include <wtf/PassOwnPtr.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
 #include <wtf/text/StringBuilder.h>
 #include <wtf/text/TextPosition.h>
 #include <wtf/unicode/Unicode.h>
@@ -232,6 +233,10 @@ private:
     // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#original-insertion-mode
     InsertionMode m_originalInsertionMode;
 
+#if ENABLE(TEMPLATE_ELEMENT)
+    Vector<InsertionMode> m_templateInsertionModes;
+#endif
+
     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#pending-table-character-tokens
     StringBuilder m_pendingTableCharacters;