[HTMLTemplateElement] <template> inside of <head> may not create <body> if EOF is hit
authorrafaelw@chromium.org <rafaelw@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Feb 2013 23:34:55 +0000 (23:34 +0000)
committerrafaelw@chromium.org <rafaelw@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Feb 2013 23:34:55 +0000 (23:34 +0000)
https://bugs.webkit.org/show_bug.cgi?id=109338

Reviewed by Adam Barth.

Source/WebCore:

This patch adds the logic to clear the stack of open elements back to the first <template> when EOF
is hit. This allows a <body> to be generated if the initial <template> was opened inside of <head>.

Tests added to html5lib.

* html/parser/HTMLTreeBuilder.cpp:
(WebCore):
(WebCore::HTMLTreeBuilder::popAllTemplates):
(WebCore::HTMLTreeBuilder::processEndTag):
(WebCore::HTMLTreeBuilder::processEndOfFile):
* html/parser/HTMLTreeBuilder.h:
(HTMLTreeBuilder):

LayoutTests:

* html5lib/resources/template.dat:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@142531 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 7cecc5e..0eda039 100644 (file)
@@ -1,3 +1,12 @@
+2013-02-11  Rafael Weinstein  <rafaelw@chromium.org>
+
+        [HTMLTemplateElement] <template> inside of <head> may not create <body> if EOF is hit
+        https://bugs.webkit.org/show_bug.cgi?id=109338
+
+        Reviewed by Adam Barth.
+
+        * html5lib/resources/template.dat:
+
 2013-02-11  Bem Jones-Bey  <bjonesbe@adobe.com>
 
         [CSS Exclusions] Handle shape-outside changing a float's overhang behavior
index 31eb96b..f48f27d 100644 (file)
 |           <tr>
 |             <td>
 |               "Foo"
+
+#data
+<template></figcaption><sub><table></table>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <sub>
+|           <table>
+|   <body>
+
+#data
+<template><template>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|   <body>
+
+#data
+<template><div>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <div>
+|   <body>
+
+#data
+<template><template><div>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <div>
+|   <body>
+
+#data
+<template><template><table>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <table>
+|   <body>
+
+#data
+<template><template><tbody>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <tbody>
+|   <body>
+
+#data
+<template><template><tr>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <tr>
+|   <body>
+
+#data
+<template><template><td>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <td>
+|   <body>
+
+#data
+<template><template><caption>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <caption>
+|   <body>
+
+#data
+<template><template><colgroup>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <colgroup>
+|   <body>
+
+#data
+<template><template><col>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <col>
+|   <body>
+
+#data
+<template><template><tbody><select>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <tbody>
+|             <select>
+|   <body>
+
+#data
+<template><template><table>Foo
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <table>
+|             "Foo"
+|   <body>
+
+#data
+<template><template><frame>
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <frame>
+|   <body>
+
+#data
+<template><template><script>var i
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <script>
+|               "var i"
+|   <body>
+
+#data
+<template><template><style>var i
+#errors
+#document
+| <html>
+|   <head>
+|     <template>
+|       #document-fragment
+|         <template>
+|           #document-fragment
+|             <style>
+|               "var i"
+|   <body>
index 8ebca5e..8f88e3a 100644 (file)
@@ -1,3 +1,23 @@
+2013-02-11  Rafael Weinstein  <rafaelw@chromium.org>
+
+        [HTMLTemplateElement] <template> inside of <head> may not create <body> if EOF is hit
+        https://bugs.webkit.org/show_bug.cgi?id=109338
+
+        Reviewed by Adam Barth.
+
+        This patch adds the logic to clear the stack of open elements back to the first <template> when EOF
+        is hit. This allows a <body> to be generated if the initial <template> was opened inside of <head>.
+
+        Tests added to html5lib.
+
+        * html/parser/HTMLTreeBuilder.cpp:
+        (WebCore):
+        (WebCore::HTMLTreeBuilder::popAllTemplates):
+        (WebCore::HTMLTreeBuilder::processEndTag):
+        (WebCore::HTMLTreeBuilder::processEndOfFile):
+        * html/parser/HTMLTreeBuilder.h:
+        (HTMLTreeBuilder):
+
 2013-02-11  Andreas Kling  <akling@apple.com>
 
         RenderText::isAllCollapsibleWhitespace() shouldn't upconvert string to 16-bit.
index 6cddddc..89dd612 100644 (file)
@@ -969,11 +969,33 @@ void HTMLTreeBuilder::processTemplateEndTag(AtomicHTMLToken* token)
     m_templateInsertionModes.removeLast();
     resetInsertionModeAppropriately();
 }
+
+bool HTMLTreeBuilder::popAllTemplatesForEndOfFile()
+{
+    if (m_templateInsertionModes.isEmpty())
+        return false;
+
+    while (!m_templateInsertionModes.isEmpty()) {
+        if (m_tree.currentIsRootNode())
+            return false;
+        if (m_tree.currentNode()->hasTagName(templateTag))
+            m_templateInsertionModes.removeLast();
+        m_tree.openElements()->pop();
+    }
+
+    resetInsertionModeAppropriately();
+    return true;
+}
 #endif
 
 bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup()
 {
-    if (m_tree.currentIsRootNode() || m_tree.currentNode()->hasTagName(templateTag)) {
+    bool ignoreFakeEndTag = m_tree.currentIsRootNode();
+#if ENABLE(TEMPLATE_ELEMENT)
+    ignoreFakeEndTag = ignoreFakeEndTag || m_tree.currentNode()->hasTagName(templateTag);
+#endif
+
+    if (ignoreFakeEndTag) {
         ASSERT(isParsingFragmentOrTemplateContents());
         // FIXME: parse error
         return false;
@@ -2501,9 +2523,6 @@ 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);
@@ -2536,6 +2555,12 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token)
         ASSERT(insertionMode() == InBodyMode || insertionMode() == InCellMode || insertionMode() == InCaptionMode || insertionMode() == InRowMode);
 #endif
         notImplemented(); // Emit parse error based on what elements are still open.
+#if ENABLE(TEMPLATE_ELEMENT)
+        if (popAllTemplatesForEndOfFile()) {
+            processEndOfFile(token);
+            return;
+        }
+#endif
         break;
     case AfterBodyMode:
     case AfterAfterBodyMode:
@@ -2550,26 +2575,34 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token)
     case AfterAfterFramesetMode:
         ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode);
         break;
+    case InColumnGroupMode:
+        if (m_tree.currentIsRootNode()) {
+            ASSERT(isParsingFragment());
+            return; // FIXME: Should we break here instead of returning?
+        }
+#if ENABLE(TEMPLATE_ELEMENT)
+        ASSERT(m_tree.currentNode()->hasTagName(colgroupTag));
+#else
+        ASSERT(m_tree.currentNode()->hasTagName(colgroupTag) || m_tree.currentNode()->hasTagName(templateTag));
+#endif
+        processColgroupEndTagForInColumnGroup();
+        // Fall through
     case InFramesetMode:
     case InTableMode:
     case InTableBodyMode:
     case InSelectInTableMode:
     case InSelectMode:
-        ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode || insertionMode() == InTableMode || insertionMode() == InFramesetMode || insertionMode() == InTableBodyMode);
+        ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode || insertionMode() == InTableMode || insertionMode() == InFramesetMode || insertionMode() == InTableBodyMode || insertionMode() == InColumnGroupMode);
         if (m_tree.currentNode() != m_tree.openElements()->rootNode())
             parseError(token);
-        break;
-    case InColumnGroupMode:
-        if (m_tree.currentIsRootNode()) {
-            ASSERT(isParsingFragment());
-            return; // FIXME: Should we break here instead of returning?
-        }
-        if (!processColgroupEndTagForInColumnGroup()) {
-            ASSERT(isParsingFragmentOrTemplateContents());
-            return; // FIXME: Should we break here instead of returning?
+
+#if ENABLE(TEMPLATE_ELEMENT)
+        if (popAllTemplatesForEndOfFile()) {
+            processEndOfFile(token);
+            return;
         }
-        processEndOfFile(token);
-        return;
+#endif
+        break;
     case InTableTextMode:
         defaultForInTableText();
         processEndOfFile(token);
@@ -2584,15 +2617,16 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token)
         processEndOfFile(token);
         return;
     case TemplateContentsMode:
-        if (m_tree.currentIsRootNode()) {
-            ASSERT(isParsingFragment());
-            break;
-        }
+#if ENABLE(TEMPLATE_ELEMENT)
         parseError(token);
-        m_tree.openElements()->pop();
-        resetInsertionModeAppropriately();
-        processEndOfFile(token);
-        return;
+        if (popAllTemplatesForEndOfFile()) {
+            processEndOfFile(token);
+            return;
+        }
+        break;
+#else
+        ASSERT_NOT_REACHED();
+#endif
     }
     ASSERT(m_tree.currentNode());
     m_tree.openElements()->popAll();
index 47e1d82..7dbc89c 100644 (file)
@@ -195,6 +195,7 @@ private:
 #if ENABLE(TEMPLATE_ELEMENT)
     void processTemplateStartTag(AtomicHTMLToken*);
     void processTemplateEndTag(AtomicHTMLToken*);
+    bool popAllTemplatesForEndOfFile();
 #endif
 
     class FragmentParsingContext {