Bug 818976 - Part 3: Generated code for HTML5 parser. r=hsivonen
authorWilliam Chen <wchen@mozilla.com>
Tue, 26 Mar 2013 00:15:23 -0700
changeset 126207 833a9f1cce27
parent 126206 f704985a8246
child 126208 7ca7e8926e07
push id25348
push userwchen@mozilla.com
push dateTue, 26 Mar 2013 07:18:51 +0000
treeherdermozilla-inbound@833a9f1cce27 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsivonen
bugs818976
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 818976 - Part 3: Generated code for HTML5 parser. r=hsivonen
parser/html/javasrc/ElementName.java
parser/html/javasrc/MetaScanner.java
parser/html/javasrc/Tokenizer.java
parser/html/javasrc/TreeBuilder.java
parser/html/nsHtml5AtomList.h
parser/html/nsHtml5AttributeName.cpp
parser/html/nsHtml5ElementName.cpp
parser/html/nsHtml5ElementName.h
parser/html/nsHtml5MetaScanner.cpp
parser/html/nsHtml5Tokenizer.cpp
parser/html/nsHtml5TreeBuilder.cpp
parser/html/nsHtml5TreeBuilder.h
--- a/parser/html/javasrc/ElementName.java
+++ b/parser/html/javasrc/ElementName.java
@@ -27,17 +27,17 @@ import java.util.Arrays;
 import nu.validator.htmlparser.annotation.Inline;
 import nu.validator.htmlparser.annotation.Local;
 import nu.validator.htmlparser.annotation.NoLength;
 import nu.validator.htmlparser.annotation.Virtual;
 import nu.validator.htmlparser.common.Interner;
 
 public final class ElementName
 // uncomment when regenerating self
-//        implements Comparable<ElementName> 
+//        implements Comparable<ElementName>
 {
 
     /**
      * The mask for extracting the dispatch group.
      */
     public static final int GROUP_MASK = 127;
 
     /**
@@ -185,29 +185,29 @@ public final class ElementName
 //        if ((flags & SPECIAL) != 0) {
 //            buf.append(" | SPECIAL");
 //        }
 //        if ((flags & FOSTER_PARENTING) != 0) {
 //            buf.append(" | FOSTER_PARENTING");
 //        }
 //        if ((flags & SCOPING) != 0) {
 //            buf.append(" | SCOPING");
-//        }        
+//        }
 //        if ((flags & SCOPING_AS_MATHML) != 0) {
 //            buf.append(" | SCOPING_AS_MATHML");
 //        }
 //        if ((flags & SCOPING_AS_SVG) != 0) {
 //            buf.append(" | SCOPING_AS_SVG");
 //        }
 //        if ((flags & OPTIONAL_END_TAG) != 0) {
 //            buf.append(" | OPTIONAL_END_TAG");
 //        }
 //        return buf.toString();
 //    }
-//    
+//
 //    private String constName() {
 //        char[] buf = new char[name.length()];
 //        for (int i = 0; i < name.length(); i++) {
 //            char c = name.charAt(i);
 //            if (c == '-') {
 //                buf[i] = '_';
 //            } else if (c >= '0' && c <= '9') {
 //                buf[i] = c;
@@ -307,16 +307,18 @@ public final class ElementName
 //            case TreeBuilder.STYLE:
 //                return "STYLE";
 //            case TreeBuilder.TABLE:
 //                return "TABLE";
 //            case TreeBuilder.TEXTAREA:
 //                return "TEXTAREA";
 //            case TreeBuilder.TITLE:
 //                return "TITLE";
+//            case TreeBuilder.TEMPLATE:
+//                return "TEMPLATE";
 //            case TreeBuilder.TR:
 //                return "TR";
 //            case TreeBuilder.XMP:
 //                return "XMP";
 //            case TreeBuilder.TBODY_OR_THEAD_OR_TFOOT:
 //                return "TBODY_OR_THEAD_OR_TFOOT";
 //            case TreeBuilder.TD_OR_TH:
 //                return "TD_OR_TH";
@@ -344,17 +346,17 @@ public final class ElementName
 //                return "EMBED_OR_IMG";
 //            case TreeBuilder.AREA_OR_WBR:
 //                return "AREA_OR_WBR";
 //            case TreeBuilder.DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
 //                return "DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU";
 //            case TreeBuilder.FIELDSET:
 //                return "FIELDSET";
 //            case TreeBuilder.ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY:
-//                return "ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_NAV_OR_SECTION_OR_SUMMARY";
+//                return "ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY";
 //            case TreeBuilder.RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR:
 //                return "RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR";
 //            case TreeBuilder.RT_OR_RP:
 //                return "RT_OR_RP";
 //            case TreeBuilder.COMMAND:
 //                return "COMMAND";
 //            case TreeBuilder.PARAM_OR_SOURCE_OR_TRACK:
 //                return "PARAM_OR_SOURCE_OR_TRACK";
@@ -369,17 +371,17 @@ public final class ElementName
 //            case TreeBuilder.MENUITEM:
 //                return "MENUITEM";
 //        }
 //        return null;
 //    }
 //
 //    /**
 //     * Regenerate self
-//     * 
+//     *
 //     * @param args
 //     */
 //    public static void main(String[] args) {
 //        Arrays.sort(ELEMENT_NAMES);
 //        for (int i = 1; i < ELEMENT_NAMES.length; i++) {
 //            if (ELEMENT_NAMES[i].hash() == ELEMENT_NAMES[i - 1].hash()) {
 //                System.err.println("Hash collision: " + ELEMENT_NAMES[i].name
 //                        + ", " + ELEMENT_NAMES[i - 1].name);
@@ -719,16 +721,17 @@ public final class ElementName
     public static final ElementName OPTGROUP = new ElementName("optgroup", "optgroup", TreeBuilder.OPTGROUP | OPTIONAL_END_TAG);
     public static final ElementName POLYLINE = new ElementName("polyline", "polyline", TreeBuilder.OTHER);
     public static final ElementName PREFETCH = new ElementName("prefetch", "prefetch", TreeBuilder.OTHER);
     public static final ElementName PROGRESS = new ElementName("progress", "progress", TreeBuilder.OTHER);
     public static final ElementName PRSUBSET = new ElementName("prsubset", "prsubset", TreeBuilder.OTHER);
     public static final ElementName QUOTIENT = new ElementName("quotient", "quotient", TreeBuilder.OTHER);
     public static final ElementName SELECTOR = new ElementName("selector", "selector", TreeBuilder.OTHER);
     public static final ElementName TEXTAREA = new ElementName("textarea", "textarea", TreeBuilder.TEXTAREA | SPECIAL);
+    public static final ElementName TEMPLATE = new ElementName("template", "template", TreeBuilder.TEMPLATE | SPECIAL);
     public static final ElementName TEXTPATH = new ElementName("textpath", "textPath", TreeBuilder.OTHER);
     public static final ElementName VARIANCE = new ElementName("variance", "variance", TreeBuilder.OTHER);
     public static final ElementName ANIMATION = new ElementName("animation", "animation", TreeBuilder.OTHER);
     public static final ElementName CONJUGATE = new ElementName("conjugate", "conjugate", TreeBuilder.OTHER);
     public static final ElementName CONDITION = new ElementName("condition", "condition", TreeBuilder.OTHER);
     public static final ElementName COMPLEXES = new ElementName("complexes", "complexes", TreeBuilder.OTHER);
     public static final ElementName FONT_FACE = new ElementName("font-face", "font-face", TreeBuilder.OTHER);
     public static final ElementName FACTORIAL = new ElementName("factorial", "factorial", TreeBuilder.OTHER);
@@ -1113,16 +1116,17 @@ public final class ElementName
     OPTGROUP,
     POLYLINE,
     PREFETCH,
     PROGRESS,
     PRSUBSET,
     QUOTIENT,
     SELECTOR,
     TEXTAREA,
+    TEMPLATE,
     TEXTPATH,
     VARIANCE,
     ANIMATION,
     CONJUGATE,
     CONDITION,
     COMPLEXES,
     FONT_FACE,
     FACTORIAL,
@@ -1508,16 +1512,17 @@ public final class ElementName
     284710386,
     285391148,
     285478533,
     285854898,
     285873762,
     286931113,
     288964227,
     289445441,
+    289591340,
     289689648,
     291671489,
     303512884,
     305319975,
     305610036,
     305764101,
     308448294,
     308675890,
--- a/parser/html/javasrc/MetaScanner.java
+++ b/parser/html/javasrc/MetaScanner.java
@@ -31,32 +31,34 @@ import nu.validator.htmlparser.common.By
 
 import org.xml.sax.SAXException;
 
 public abstract class MetaScanner {
 
     /**
      * Constant for "charset".
      */
-    private static final char[] CHARSET = "harset".toCharArray();
+    private static final char[] CHARSET = { 'h', 'a', 'r', 's', 'e', 't' };
     
     /**
      * Constant for "content".
      */
-    private static final char[] CONTENT = "ontent".toCharArray();
+    private static final char[] CONTENT = { 'o', 'n', 't', 'e', 'n', 't' };
 
     /**
      * Constant for "http-equiv".
      */
-    private static final char[] HTTP_EQUIV = "ttp-equiv".toCharArray();
+    private static final char[] HTTP_EQUIV = { 't', 't', 'p', '-', 'e', 'q',
+            'u', 'i', 'v' };
 
     /**
      * Constant for "content-type".
      */
-    private static final char[] CONTENT_TYPE = "content-type".toCharArray();
+    private static final char[] CONTENT_TYPE = { 'c', 'o', 'n', 't', 'e', 'n',
+            't', '-', 't', 'y', 'p', 'e' };
 
     private static final int NO = 0;
 
     private static final int M = 1;
     
     private static final int E = 2;
     
     private static final int T = 3;
--- a/parser/html/javasrc/Tokenizer.java
+++ b/parser/html/javasrc/Tokenizer.java
@@ -265,32 +265,34 @@ public class Tokenizer implements Locato
     /**
      * Buffer growth parameter.
      */
     private static final int BUFFER_GROW_BY = 1024;
 
     /**
      * "CDATA[" as <code>char[]</code>
      */
-    private static final @NoLength char[] CDATA_LSQB = "CDATA[".toCharArray();
+    private static final @NoLength char[] CDATA_LSQB = { 'C', 'D', 'A', 'T',
+            'A', '[' };
 
     /**
      * "octype" as <code>char[]</code>
      */
-    private static final @NoLength char[] OCTYPE = "octype".toCharArray();
+    private static final @NoLength char[] OCTYPE = { 'o', 'c', 't', 'y', 'p',
+            'e' };
 
     /**
      * "ublic" as <code>char[]</code>
      */
-    private static final @NoLength char[] UBLIC = "ublic".toCharArray();
+    private static final @NoLength char[] UBLIC = { 'u', 'b', 'l', 'i', 'c' };
 
     /**
      * "ystem" as <code>char[]</code>
      */
-    private static final @NoLength char[] YSTEM = "ystem".toCharArray();
+    private static final @NoLength char[] YSTEM = { 'y', 's', 't', 'e', 'm' };
 
     private static final char[] TITLE_ARR = { 't', 'i', 't', 'l', 'e' };
 
     private static final char[] SCRIPT_ARR = { 's', 'c', 'r', 'i', 'p', 't' };
 
     private static final char[] STYLE_ARR = { 's', 't', 'y', 'l', 'e' };
 
     private static final char[] PLAINTEXT_ARR = { 'p', 'l', 'a', 'i', 'n', 't',
--- a/parser/html/javasrc/TreeBuilder.java
+++ b/parser/html/javasrc/TreeBuilder.java
@@ -1,40 +1,40 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
  * Copyright (c) 2007-2011 Mozilla Foundation
- * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla 
+ * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
  * Foundation, and Opera Software ASA.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a 
- * copy of this software and associated documentation files (the "Software"), 
- * to deal in the Software without restriction, including without limitation 
- * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
- * and/or sell copies of the Software, and to permit persons to whom the 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
  * Software is furnished to do so, subject to the following conditions:
  *
- * The above copyright notice and this permission notice shall be included in 
+ * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
- * The comments following this one that use the same comment syntax as this 
- * comment are quotes from the WHATWG HTML 5 spec as of 27 June 2007 
+ * The comments following this one that use the same comment syntax as this
+ * comment are quotes from the WHATWG HTML 5 spec as of 27 June 2007
  * amended as of June 28 2007.
  * That document came with this statement:
- * "© Copyright 2004-2007 Apple Computer, Inc., Mozilla Foundation, and 
- * Opera Software ASA. You are granted a license to use, reproduce and 
+ * "© Copyright 2004-2007 Apple Computer, Inc., Mozilla Foundation, and
+ * Opera Software ASA. You are granted a license to use, reproduce and
  * create derivative works of this document."
  */
 
 package nu.validator.htmlparser.impl;
 
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
@@ -56,22 +56,22 @@ import nu.validator.htmlparser.common.Xm
 
 import org.xml.sax.ErrorHandler;
 import org.xml.sax.Locator;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXParseException;
 
 public abstract class TreeBuilder<T> implements TokenHandler,
         TreeBuilderState<T> {
-    
+
     /**
      * Array version of U+FFFD.
      */
     private static final @NoLength char[] REPLACEMENT_CHARACTER = { '\uFFFD' };
-    
+
     // Start dispatch groups
 
     final static int OTHER = 0;
 
     final static int A = 1;
 
     final static int BASE = 2;
 
@@ -196,16 +196,18 @@ public abstract class TreeBuilder<T> imp
     final static int OBJECT = 63;
 
     final static int FONT = 64;
 
     final static int KEYGEN = 65;
 
     final static int MENUITEM = 66;
 
+    final static int TEMPLATE = 67;
+
     // start insertion modes
 
     private static final int IN_ROW = 0;
 
     private static final int IN_TABLE_BODY = 1;
 
     private static final int IN_TABLE = 2;
 
@@ -217,63 +219,65 @@ public abstract class TreeBuilder<T> imp
 
     private static final int IN_BODY = 6;
 
     private static final int IN_HEAD = 7;
 
     private static final int IN_HEAD_NOSCRIPT = 8;
 
     // no fall-through
-    
+
     private static final int IN_COLUMN_GROUP = 9;
 
     // no fall-through
-    
+
     private static final int IN_SELECT_IN_TABLE = 10;
 
     private static final int IN_SELECT = 11;
 
     // no fall-through
-    
+
     private static final int AFTER_BODY = 12;
 
     // no fall-through
-    
+
     private static final int IN_FRAMESET = 13;
 
     private static final int AFTER_FRAMESET = 14;
 
-    // no fall-through    
-    
+    // no fall-through
+
     private static final int INITIAL = 15;
-    
+
     // could add fall-through
 
     private static final int BEFORE_HTML = 16;
 
     // could add fall-through
 
     private static final int BEFORE_HEAD = 17;
 
-    // no fall-through    
-    
+    // no fall-through
+
     private static final int AFTER_HEAD = 18;
 
-    // no fall-through    
-    
+    // no fall-through
+
     private static final int AFTER_AFTER_BODY = 19;
 
-    // no fall-through    
-    
+    // no fall-through
+
     private static final int AFTER_AFTER_FRAMESET = 20;
 
-    // no fall-through    
-    
+    // no fall-through
+
     private static final int TEXT = 21;
 
+    private static final int TEMPLATE_CONTENTS = 22;
+
     // start charset states
 
     private static final int CHARSET_INITIAL = 0;
 
     private static final int CHARSET_C = 1;
 
     private static final int CHARSET_H = 2;
 
@@ -360,40 +364,40 @@ public abstract class TreeBuilder<T> imp
             "-//w3o//dtd w3 html 3.0//", "-//webtechs//dtd mozilla html 2.0//",
             "-//webtechs//dtd mozilla html//" };
 
     private static final int NOT_FOUND_ON_STACK = Integer.MAX_VALUE;
 
     // [NOCPP[
 
     private static final @Local String HTML_LOCAL = "html";
-    
+
     // ]NOCPP]
 
     private int mode = INITIAL;
 
     private int originalMode = INITIAL;
-    
+
     /**
      * Used only when moving back to IN_BODY.
      */
     private boolean framesetOk = true;
 
     protected Tokenizer tokenizer;
 
     // [NOCPP[
 
     protected ErrorHandler errorHandler;
 
     private DocumentModeHandler documentModeHandler;
 
     private DoctypeExpectation doctypeExpectation = DoctypeExpectation.HTML;
 
     private LocatorImpl firstCommentLocation;
-    
+
     // ]NOCPP]
 
     private boolean scriptingEnabled = false;
 
     private boolean needToDropLF;
 
     // [NOCPP[
 
@@ -404,16 +408,26 @@ public abstract class TreeBuilder<T> imp
     private boolean fragment;
 
     private @Local String contextName;
 
     private @NsUri String contextNamespace;
 
     private T contextNode;
 
+    /**
+     * Stack of template insertion modes
+     */
+    private @Auto int[] templateModeStack;
+
+    /**
+     * Current template mode stack pointer.
+     */
+    private int templateModePtr = -1;
+
     private @Auto StackNode<T>[] stack;
 
     private int currentPtr = -1;
 
     private @Auto StackNode<T>[] listOfActiveFormattingElements;
 
     private int listPtr = -1;
 
@@ -446,17 +460,17 @@ public abstract class TreeBuilder<T> imp
 
     protected TreeBuilder() {
         fragment = false;
     }
 
     /**
      * Reports an condition that would make the infoset incompatible with XML
      * 1.0 as fatal.
-     * 
+     *
      * @throws SAXException
      * @throws SAXParseException
      */
     protected void fatal() throws SAXException {
     }
 
     // [NOCPP[
 
@@ -474,31 +488,31 @@ public abstract class TreeBuilder<T> imp
         if (errorHandler != null) {
             errorHandler.fatalError(spe);
         }
         throw spe;
     }
 
     /**
      * Reports a Parse Error.
-     * 
+     *
      * @param message
      *            the message
      * @throws SAXException
      */
     final void err(String message) throws SAXException {
         if (errorHandler == null) {
             return;
         }
         errNoCheck(message);
     }
-    
+
     /**
      * Reports a Parse Error without checking if an error handler is present.
-     * 
+     *
      * @param message
      *            the message
      * @throws SAXException
      */
     final void errNoCheck(String message) throws SAXException {
         SAXParseException spe = new SAXParseException(message, tokenizer);
         errorHandler.error(spe);
     }
@@ -508,17 +522,17 @@ public abstract class TreeBuilder<T> imp
             for (int i = currentPtr; i > eltPos; i--) {
                 reportUnclosedElementNameAndLocation(i);
             }
         }
     }
 
     /**
      * Reports the name and location of an unclosed element.
-     * 
+     *
      * @throws SAXException
      */
     private final void reportUnclosedElementNameAndLocation(int pos) throws SAXException {
         StackNode<T> node = stack[pos];
         if (node.isOptionalEndTag()) {
             return;
         }
         TaintableLocatorImpl locator = node.getLocator();
@@ -528,52 +542,54 @@ public abstract class TreeBuilder<T> imp
         locator.markTainted();
         SAXParseException spe = new SAXParseException(
                 "Unclosed element \u201C" + node.popName + "\u201D.", locator);
         errorHandler.error(spe);
     }
 
     /**
      * Reports a warning
-     * 
+     *
      * @param message
      *            the message
      * @throws SAXException
      */
     final void warn(String message) throws SAXException {
         if (errorHandler == null) {
             return;
         }
         SAXParseException spe = new SAXParseException(message, tokenizer);
         errorHandler.warning(spe);
     }
 
     /**
      * Reports a warning with an explicit locator
-     * 
+     *
      * @param message
      *            the message
      * @throws SAXException
      */
     final void warn(String message, Locator locator) throws SAXException {
         if (errorHandler == null) {
             return;
         }
         SAXParseException spe = new SAXParseException(message, locator);
         errorHandler.warning(spe);
     }
 
     // ]NOCPP]
-    
+
     @SuppressWarnings("unchecked") public final void startTokenization(Tokenizer self) throws SAXException {
         tokenizer = self;
         stack = new StackNode[64];
+        templateModeStack = new int[64];
         listOfActiveFormattingElements = new StackNode[64];
         needToDropLF = false;
         originalMode = INITIAL;
+        templateModePtr = -1;
         currentPtr = -1;
         listPtr = -1;
         formPointer = null;
         headPointer = null;
         deepTreeSurrogateParent = null;
         // [NOCPP[
         html4 = false;
         idLocations.clear();
@@ -593,16 +609,19 @@ public abstract class TreeBuilder<T> imp
             }
             StackNode<T> node = new StackNode<T>(ElementName.HTML, elt
             // [NOCPP[
                     , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
             // ]NOCPP]
             );
             currentPtr++;
             stack[currentPtr] = node;
+            if ("template" == contextName) {
+                pushTemplateMode(TEMPLATE_CONTENTS);
+            }
             resetTheInsertionMode();
             if ("title" == contextName || "textarea" == contextName) {
                 tokenizer.setStateAndEndTagExpectation(Tokenizer.RCDATA, contextName);
             } else if ("style" == contextName || "xmp" == contextName
                     || "iframe" == contextName || "noembed" == contextName
                     || "noframes" == contextName
                     || (scriptingEnabled && "noscript" == contextName)) {
                 tokenizer.setStateAndEndTagExpectation(Tokenizer.RAWTEXT, contextName);
@@ -833,17 +852,17 @@ public abstract class TreeBuilder<T> imp
                         documentModeInternal(DocumentMode.STANDARDS_MODE,
                                 publicIdentifier, systemIdentifier, false);
                     }
                     break;
             }
             // ]NOCPP]
 
             /*
-             * 
+             *
              * Then, switch to the root element mode of the tree construction
              * stage.
              */
             mode = BEFORE_HTML;
             return;
         }
         /*
          * A DOCTYPE token Parse error.
@@ -983,16 +1002,17 @@ public abstract class TreeBuilder<T> imp
                                 case IN_COLUMN_GROUP:
                                 case IN_FRAMESET:
                                 case AFTER_FRAMESET:
                                     /*
                                      * Append the character to the current node.
                                      */
                                     continue;
                                 case FRAMESET_OK:
+                                case TEMPLATE_CONTENTS:
                                 case IN_BODY:
                                 case IN_CELL:
                                 case IN_CAPTION:
                                     if (start < i) {
                                         accumulateCharacters(buf, start, i
                                                 - start);
                                         start = i;
                                     }
@@ -1064,17 +1084,17 @@ public abstract class TreeBuilder<T> imp
                                             break;
                                         case HTML401_TRANSITIONAL:
                                             err("Non-space characters found without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D.");
                                             break;
                                         case NO_DOCTYPE_ERRORS:
                                     }
                                     // ]NOCPP]
                                     /*
-                                     * 
+                                     *
                                      * Set the document to quirks mode.
                                      */
                                     documentModeInternal(
                                             DocumentMode.QUIRKS_MODE, null,
                                             null, false);
                                     /*
                                      * Then, switch to the root element mode of
                                      * the tree construction stage
@@ -1112,17 +1132,17 @@ public abstract class TreeBuilder<T> imp
                                      * name "head" and no attributes had been
                                      * seen,
                                      */
                                     flushCharacters();
                                     appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
                                     mode = IN_HEAD;
                                     /*
                                      * then reprocess the current token.
-                                     * 
+                                     *
                                      * This will result in an empty head element
                                      * being generated, with the current token
                                      * being reprocessed in the "after head"
                                      * insertion mode.
                                      */
                                     i--;
                                     continue;
                                 case IN_HEAD:
@@ -1181,16 +1201,17 @@ public abstract class TreeBuilder<T> imp
                                      */
                                     i--;
                                     continue;
                                 case FRAMESET_OK:
                                     framesetOk = false;
                                     mode = IN_BODY;
                                     i--;
                                     continue;
+                                case TEMPLATE_CONTENTS:
                                 case IN_BODY:
                                 case IN_CELL:
                                 case IN_CAPTION:
                                     if (start < i) {
                                         accumulateCharacters(buf, start, i
                                                 - start);
                                         start = i;
                                     }
@@ -1220,17 +1241,18 @@ public abstract class TreeBuilder<T> imp
                                         start = i;
                                     }
                                     /*
                                      * Act as if an end tag with the tag name
                                      * "colgroup" had been seen, and then, if
                                      * that token wasn't ignored, reprocess the
                                      * current token.
                                      */
-                                    if (currentPtr == 0) {
+                                    if (currentPtr == 0 || stack[currentPtr].getGroup() ==
+                                            TreeBuilder.TEMPLATE) {
                                         errNonSpaceInColgroupInFragment();
                                         start = i + 1;
                                         continue;
                                     }
                                     flushCharacters();
                                     pop();
                                     mode = IN_TABLE;
                                     i--;
@@ -1348,17 +1370,17 @@ public abstract class TreeBuilder<T> imp
                             break;
                         case HTML401_TRANSITIONAL:
                             err("End of file seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D.");
                             break;
                         case NO_DOCTYPE_ERRORS:
                     }
                     // ]NOCPP]
                     /*
-                     * 
+                     *
                      * Set the document to quirks mode.
                      */
                     documentModeInternal(DocumentMode.QUIRKS_MODE, null, null,
                             false);
                     /*
                      * Then, switch to the root element mode of the tree
                      * construction stage
                      */
@@ -1461,16 +1483,27 @@ public abstract class TreeBuilder<T> imp
                 case IN_SELECT_IN_TABLE:
                 case IN_FRAMESET:
                     // [NOCPP[
                     if (errorHandler != null && currentPtr > 0) {
                         errEofWithUnclosedElements();
                     }
                     // ]NOCPP]
                     break eofloop;
+                case TEMPLATE_CONTENTS:
+                    if (currentPtr == 0) {
+                        assert fragment;
+                        break eofloop;
+                    }
+
+                    // TODO: Parse error. Add error reporting.
+                    popOnEof();
+                    resetTheInsertionMode();
+                    // Reprocess token.
+                    continue;
                 case AFTER_BODY:
                 case AFTER_FRAMESET:
                 case AFTER_AFTER_BODY:
                 case AFTER_AFTER_FRAMESET:
                 default:
                     // [NOCPP[
                     if (currentPtr == 0) { // This silliness is here to poison
                         // buggy compiler optimizations in
@@ -1492,16 +1525,17 @@ public abstract class TreeBuilder<T> imp
 
     /**
      * @see nu.validator.htmlparser.common.TokenHandler#endTokenization()
      */
     public final void endTokenization() throws SAXException {
         formPointer = null;
         headPointer = null;
         deepTreeSurrogateParent = null;
+        templateModeStack = null;
         if (stack != null) {
             while (currentPtr > -1) {
                 stack[currentPtr].release();
                 currentPtr--;
             }
             stack = null;
         }
         if (listOfActiveFormattingElements != null) {
@@ -1610,16 +1644,84 @@ public abstract class TreeBuilder<T> imp
                                 }
                                 attributes = null; // CPP
                                 break starttagloop;
                             }
                     } // switch
                 } // foreignObject / annotation-xml
             }
             switch (mode) {
+                case TEMPLATE_CONTENTS:
+                    switch (group) {
+                        case FRAME:
+                            popTemplateMode();
+                            pushTemplateMode(IN_FRAMESET);
+                            mode = IN_FRAMESET;
+                            // Reprocess token.
+                            continue;
+                        case COL:
+                            popTemplateMode();
+                            pushTemplateMode(IN_COLUMN_GROUP);
+                            mode = IN_COLUMN_GROUP;
+                            // Reprocess token.
+                            continue;
+                        case CAPTION:
+                        case COLGROUP:
+                        case TBODY_OR_THEAD_OR_TFOOT:
+                            popTemplateMode();
+                            pushTemplateMode(IN_TABLE);
+                            mode = IN_TABLE;
+                            // Reprocess token.
+                            continue;
+                        case TR:
+                            popTemplateMode();
+                            pushTemplateMode(IN_TABLE_BODY);
+                            mode = IN_TABLE_BODY;
+                            // Reprocess token.
+                            continue;
+                        case TD_OR_TH:
+                            popTemplateMode();
+                            pushTemplateMode(IN_ROW);
+                            mode = IN_ROW;
+                            // Reprocess token.
+                            continue;
+                        case META:
+                            checkMetaCharset(attributes);
+                            appendVoidElementToCurrentMayFoster(
+                                    elementName,
+                                    attributes);
+                            selfClosing = false;
+                            attributes = null; // CPP
+                            break starttagloop;
+                        case LINK_OR_BASEFONT_OR_BGSOUND:
+                            appendVoidElementToCurrentMayFoster(
+                                    elementName,
+                                    attributes);
+                            selfClosing = false;
+                            attributes = null; // CPP
+                            break starttagloop;
+                        case SCRIPT:
+                            startTagScriptInHead(elementName, attributes);
+                            attributes = null; // CPP
+                            break starttagloop;
+                        case STYLE:
+                            startTagGenericRawText(elementName, attributes);
+                            attributes = null; // CPP
+                            break starttagloop;
+                        case TEMPLATE:
+                            startTagTemplateInHead(elementName, attributes);
+                            attributes = null; // CPP
+                            break starttagloop;
+                        default:
+                            popTemplateMode();
+                            pushTemplateMode(IN_BODY);
+                            mode = IN_BODY;
+                            // Reprocess token.
+                            continue;
+                    }
                 case IN_ROW:
                     switch (group) {
                         case TD_OR_TH:
                             clearStackBackTo(findLastOrRoot(TreeBuilder.TR));
                             appendToCurrentNodeAndPushElement(
                                     elementName,
                                     attributes);
                             mode = IN_CELL;
@@ -1628,51 +1730,52 @@ public abstract class TreeBuilder<T> imp
                             break starttagloop;
                         case CAPTION:
                         case COL:
                         case COLGROUP:
                         case TBODY_OR_THEAD_OR_TFOOT:
                         case TR:
                             eltPos = findLastOrRoot(TreeBuilder.TR);
                             if (eltPos == 0) {
-                                assert fragment;
+                                assert fragment || isTemplateContents();
                                 errNoTableRowToClose();
                                 break starttagloop;
                             }
                             clearStackBackTo(eltPos);
                             pop();
                             mode = IN_TABLE_BODY;
                             continue;
                         default:
                             // fall through to IN_TABLE
                     }
                 case IN_TABLE_BODY:
                     switch (group) {
                         case TR:
-                            clearStackBackTo(findLastInTableScopeOrRootTbodyTheadTfoot());
+                            clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
                             appendToCurrentNodeAndPushElement(
                                     elementName,
                                     attributes);
                             mode = IN_ROW;
                             attributes = null; // CPP
                             break starttagloop;
                         case TD_OR_TH:
                             errStartTagInTableBody(name);
-                            clearStackBackTo(findLastInTableScopeOrRootTbodyTheadTfoot());
+                            clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
                             appendToCurrentNodeAndPushElement(
                                     ElementName.TR,
                                     HtmlAttributes.EMPTY_ATTRIBUTES);
                             mode = IN_ROW;
                             continue;
                         case CAPTION:
                         case COL:
                         case COLGROUP:
                         case TBODY_OR_THEAD_OR_TFOOT:
-                            eltPos = findLastInTableScopeOrRootTbodyTheadTfoot();
-                            if (eltPos == 0) {
+                            eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
+                            if (eltPos == 0 || stack[eltPos].getGroup() == TEMPLATE) {
+                                assert fragment || isTemplateContents();
                                 errStrayStartTag(name);
                                 break starttagloop;
                             } else {
                                 clearStackBackTo(eltPos);
                                 pop();
                                 mode = IN_TABLE;
                                 continue;
                             }
@@ -1717,21 +1820,24 @@ public abstract class TreeBuilder<T> imp
                             case TR:
                             case TD_OR_TH:
                                 clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
                                 appendToCurrentNodeAndPushElement(
                                         ElementName.TBODY,
                                         HtmlAttributes.EMPTY_ATTRIBUTES);
                                 mode = IN_TABLE_BODY;
                                 continue starttagloop;
+                            case TEMPLATE:
+                                // fall through to IN_HEAD
+                                break intableloop;
                             case TABLE:
                                 errTableSeenWhileTableOpen();
                                 eltPos = findLastInTableScope(name);
                                 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
-                                    assert fragment;
+                                    assert fragment || isTemplateContents();
                                     break starttagloop;
                                 }
                                 generateImpliedEndTags();
                                 // XXX is the next if dead code?
                                 if (errorHandler != null && !isCurrent("table")) {
                                     errNoCheckUnclosedElementsOnStack();
                                 }
                                 while (currentPtr >= eltPos) {
@@ -1836,17 +1942,17 @@ public abstract class TreeBuilder<T> imp
                         default:
                             // fall through to IN_BODY
                     }
                 case FRAMESET_OK:
                     switch (group) {
                         case FRAMESET:
                             if (mode == FRAMESET_OK) {
                                 if (currentPtr == 0 || stack[1].getGroup() != BODY) {
-                                    assert fragment;
+                                    assert fragment || isTemplateContents();
                                     errStrayStartTag(name);
                                     break starttagloop;
                                 } else {
                                     errFramesetStart();
                                     detachFromParent(stack[1].node);
                                     while (currentPtr > 0) {
                                         pop();
                                     }
@@ -1890,34 +1996,34 @@ public abstract class TreeBuilder<T> imp
                         default:
                             // fall through to IN_BODY
                     }
                 case IN_BODY:
                     inbodyloop: for (;;) {
                         switch (group) {
                             case HTML:
                                 errStrayStartTag(name);
-                                if (!fragment) {
+                                if (!fragment && !isTemplateContents()) {
                                     addAttributesToHtml(attributes);
                                     attributes = null; // CPP
                                 }
                                 break starttagloop;
                             case BASE:
                             case LINK_OR_BASEFONT_OR_BGSOUND:
                             case META:
                             case STYLE:
                             case SCRIPT:
                             case TITLE:
                             case COMMAND:
+                            case TEMPLATE:
                                 // Fall through to IN_HEAD
                                 break inbodyloop;
                             case BODY:
-                                if (currentPtr == 0
-                                        || stack[1].getGroup() != BODY) {
-                                    assert fragment;
+                                if (currentPtr == 0 || stack[1].getGroup() != BODY || isTemplateContents()) {
+                                    assert fragment || isTemplateContents();
                                     errStrayStartTag(name);
                                     break starttagloop;
                                 }
                                 errFooSeenWhenFooOpen(name);
                                 framesetOk = false;
                                 if (mode == FRAMESET_OK) {
                                     mode = IN_BODY;
                                 }
@@ -2239,23 +2345,17 @@ public abstract class TreeBuilder<T> imp
                                     attributes = null; // CPP
                                     break starttagloop;
                                 } else {
                                     // fall through
                                 }
                             case NOFRAMES:
                             case IFRAME:
                             case NOEMBED:
-                                appendToCurrentNodeAndPushElementMayFoster(
-                                        elementName,
-                                        attributes);
-                                originalMode = mode;
-                                mode = TEXT;
-                                tokenizer.setStateAndEndTagExpectation(
-                                        Tokenizer.RAWTEXT, elementName);
+                                startTagGenericRawText(elementName, attributes);
                                 attributes = null; // CPP
                                 break starttagloop;
                             case SELECT:
                                 reconstructTheActiveFormattingElements();
                                 appendToCurrentNodeAndPushElementMayFoster(
                                         elementName,
                                         attributes, formPointer);
                                 switch (mode) {
@@ -2355,17 +2455,17 @@ public abstract class TreeBuilder<T> imp
                                 break starttagloop;
                         }
                     }
                 case IN_HEAD:
                     inheadloop: for (;;) {
                         switch (group) {
                             case HTML:
                                 errStrayStartTag(name);
-                                if (!fragment) {
+                                if (!fragment && !isTemplateContents()) {
                                     addAttributesToHtml(attributes);
                                     attributes = null; // CPP
                                 }
                                 break starttagloop;
                             case BASE:
                             case COMMAND:
                                 appendVoidElementToCurrentMayFoster(
                                         elementName,
@@ -2400,58 +2500,46 @@ public abstract class TreeBuilder<T> imp
                                     appendToCurrentNodeAndPushElementMayFoster(
                                             elementName,
                                             attributes);
                                     mode = IN_HEAD_NOSCRIPT;
                                 }
                                 attributes = null; // CPP
                                 break starttagloop;
                             case SCRIPT:
-                                // XXX need to manage much more stuff
-                                // here if
-                                // supporting
-                                // document.write()
-                                appendToCurrentNodeAndPushElementMayFoster(
-                                        elementName,
-                                        attributes);
-                                originalMode = mode;
-                                mode = TEXT;
-                                tokenizer.setStateAndEndTagExpectation(
-                                        Tokenizer.SCRIPT_DATA, elementName);
+                                startTagScriptInHead(elementName, attributes);
                                 attributes = null; // CPP
                                 break starttagloop;
                             case STYLE:
                             case NOFRAMES:
-                                appendToCurrentNodeAndPushElementMayFoster(
-                                        elementName,
-                                        attributes);
-                                originalMode = mode;
-                                mode = TEXT;
-                                tokenizer.setStateAndEndTagExpectation(
-                                        Tokenizer.RAWTEXT, elementName);
+                                startTagGenericRawText(elementName, attributes);
                                 attributes = null; // CPP
                                 break starttagloop;
                             case HEAD:
                                 /* Parse error. */
                                 errFooSeenWhenFooOpen(name);
                                 /* Ignore the token. */
                                 break starttagloop;
+                            case TEMPLATE:
+                                startTagTemplateInHead(elementName, attributes);
+                                attributes = null; // CPP
+                                break starttagloop;
                             default:
                                 pop();
                                 mode = AFTER_HEAD;
                                 continue starttagloop;
                         }
                     }
                 case IN_HEAD_NOSCRIPT:
                     switch (group) {
                         case HTML:
                             // XXX did Hixie really mean to omit "base"
                             // here?
                             errStrayStartTag(name);
-                            if (!fragment) {
+                            if (!fragment && !isTemplateContents()) {
                                 addAttributesToHtml(attributes);
                                 attributes = null; // CPP
                             }
                             break starttagloop;
                         case LINK_OR_BASEFONT_OR_BGSOUND:
                             appendVoidElementToCurrentMayFoster(
                                     elementName,
                                     attributes);
@@ -2488,31 +2576,35 @@ public abstract class TreeBuilder<T> imp
                             pop();
                             mode = IN_HEAD;
                             continue;
                     }
                 case IN_COLUMN_GROUP:
                     switch (group) {
                         case HTML:
                             errStrayStartTag(name);
-                            if (!fragment) {
+                            if (!fragment && !isTemplateContents()) {
                                 addAttributesToHtml(attributes);
                                 attributes = null; // CPP
                             }
                             break starttagloop;
                         case COL:
                             appendVoidElementToCurrentMayFoster(
                                     elementName,
                                     attributes);
                             selfClosing = false;
                             attributes = null; // CPP
                             break starttagloop;
+                        case TEMPLATE:
+                            startTagTemplateInHead(elementName, attributes);
+                            attributes = null; // CPP
+                            break starttagloop;
                         default:
-                            if (currentPtr == 0) {
-                                assert fragment;
+                            if (currentPtr == 0 || stack[currentPtr].getGroup() == TEMPLATE) {
+                                assert fragment || isTemplateContents();
                                 errGarbageInColgroup();
                                 break starttagloop;
                             }
                             pop();
                             mode = IN_TABLE;
                             continue;
                     }
                 case IN_SELECT_IN_TABLE:
@@ -2590,38 +2682,32 @@ public abstract class TreeBuilder<T> imp
                                 break starttagloop;
                             }
                             while (currentPtr >= eltPos) {
                                 pop();
                             }
                             resetTheInsertionMode();
                             continue;
                         case SCRIPT:
-                            // XXX need to manage much more stuff
-                            // here if
-                            // supporting
-                            // document.write()
-                            appendToCurrentNodeAndPushElementMayFoster(
-                                    elementName,
-                                    attributes);
-                            originalMode = mode;
-                            mode = TEXT;
-                            tokenizer.setStateAndEndTagExpectation(
-                                    Tokenizer.SCRIPT_DATA, elementName);
+                            startTagScriptInHead(elementName, attributes);
+                            attributes = null; // CPP
+                            break starttagloop;
+                        case TEMPLATE:
+                            startTagTemplateInHead(elementName, attributes);
                             attributes = null; // CPP
                             break starttagloop;
                         default:
                             errStrayStartTag(name);
                             break starttagloop;
                     }
                 case AFTER_BODY:
                     switch (group) {
                         case HTML:
                             errStrayStartTag(name);
-                            if (!fragment) {
+                            if (!fragment && !isTemplateContents()) {
                                 addAttributesToHtml(attributes);
                                 attributes = null; // CPP
                             }
                             break starttagloop;
                         default:
                             errStrayStartTag(name);
                             mode = framesetOk ? FRAMESET_OK : IN_BODY;
                             continue;
@@ -2636,24 +2722,28 @@ public abstract class TreeBuilder<T> imp
                             break starttagloop;
                         case FRAME:
                             appendVoidElementToCurrentMayFoster(
                                     elementName,
                                     attributes);
                             selfClosing = false;
                             attributes = null; // CPP
                             break starttagloop;
+                        case TEMPLATE:
+                            startTagTemplateInHead(elementName, attributes);
+                            attributes = null; // CPP
+                            break starttagloop;
                         default:
                             // fall through to AFTER_FRAMESET
                     }
                 case AFTER_FRAMESET:
                     switch (group) {
                         case HTML:
                             errStrayStartTag(name);
-                            if (!fragment) {
+                            if (!fragment && !isTemplateContents()) {
                                 addAttributesToHtml(attributes);
                                 attributes = null; // CPP
                             }
                             break starttagloop;
                         case NOFRAMES:
                             appendToCurrentNodeAndPushElement(
                                     elementName,
                                     attributes);
@@ -2686,17 +2776,17 @@ public abstract class TreeBuilder<T> imp
                             break;
                         case HTML401_TRANSITIONAL:
                             err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D.");
                             break;
                         case NO_DOCTYPE_ERRORS:
                     }
                     // ]NOCPP]
                     /*
-                     * 
+                     *
                      * Set the document to quirks mode.
                      */
                     documentModeInternal(DocumentMode.QUIRKS_MODE, null, null,
                             false);
                     /*
                      * Then, switch to the root element mode of the tree
                      * construction stage
                      */
@@ -2737,63 +2827,63 @@ public abstract class TreeBuilder<T> imp
                              * reprocess the current token.
                              */
                             continue;
                     }
                 case BEFORE_HEAD:
                     switch (group) {
                         case HTML:
                             errStrayStartTag(name);
-                            if (!fragment) {
+                            if (!fragment && !isTemplateContents()) {
                                 addAttributesToHtml(attributes);
                                 attributes = null; // CPP
                             }
                             break starttagloop;
                         case HEAD:
                             /*
                              * A start tag whose tag name is "head"
-                             * 
+                             *
                              * Create an element for the token.
-                             * 
+                             *
                              * Set the head element pointer to this new element
                              * node.
-                             * 
+                             *
                              * Append the new element to the current node and
                              * push it onto the stack of open elements.
                              */
                             appendToCurrentNodeAndPushHeadElement(attributes);
                             /*
                              * Change the insertion mode to "in head".
                              */
                             mode = IN_HEAD;
                             attributes = null; // CPP
                             break starttagloop;
                         default:
                             /*
                              * Any other start tag token
-                             * 
+                             *
                              * Act as if a start tag token with the tag name
                              * "head" and no attributes had been seen,
                              */
                             appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
                             mode = IN_HEAD;
                             /*
                              * then reprocess the current token.
-                             * 
+                             *
                              * This will result in an empty head element being
                              * generated, with the current token being
                              * reprocessed in the "after head" insertion mode.
                              */
                             continue;
                     }
                 case AFTER_HEAD:
                     switch (group) {
                         case HTML:
                             errStrayStartTag(name);
-                            if (!fragment) {
+                            if (!fragment && !isTemplateContents()) {
                                 addAttributesToHtml(attributes);
                                 attributes = null; // CPP
                             }
                             break starttagloop;
                         case BODY:
                             if (attributes.getLength() == 0) {
                                 // This has the right magic side effect
                                 // that
@@ -2889,44 +2979,38 @@ public abstract class TreeBuilder<T> imp
                             appendToCurrentNodeAndPushBodyElement();
                             mode = FRAMESET_OK;
                             continue;
                     }
                 case AFTER_AFTER_BODY:
                     switch (group) {
                         case HTML:
                             errStrayStartTag(name);
-                            if (!fragment) {
+                            if (!fragment && !isTemplateContents()) {
                                 addAttributesToHtml(attributes);
                                 attributes = null; // CPP
                             }
                             break starttagloop;
                         default:
                             errStrayStartTag(name);
                             fatal();
                             mode = framesetOk ? FRAMESET_OK : IN_BODY;
                             continue;
                     }
                 case AFTER_AFTER_FRAMESET:
                     switch (group) {
                         case HTML:
                             errStrayStartTag(name);
-                            if (!fragment) {
+                            if (!fragment && !isTemplateContents()) {
                                 addAttributesToHtml(attributes);
                                 attributes = null; // CPP
                             }
                             break starttagloop;
                         case NOFRAMES:
-                            appendToCurrentNodeAndPushElementMayFoster(
-                                    elementName,
-                                    attributes);
-                            originalMode = mode;
-                            mode = TEXT;
-                            tokenizer.setStateAndEndTagExpectation(
-                                    Tokenizer.SCRIPT_DATA, elementName);
+                            startTagScriptInHead(elementName, attributes);
                             attributes = null; // CPP
                             break starttagloop;
                         default:
                             errStrayStartTag(name);
                             break starttagloop;
                     }
                 case TEXT:
                     assert false;
@@ -2937,28 +3021,55 @@ public abstract class TreeBuilder<T> imp
         if (selfClosing) {
             errSelfClosing();
         }
         if (attributes != HtmlAttributes.EMPTY_ATTRIBUTES) {
             Portability.delete(attributes);
         }
     }
 
+    private void startTagGenericRawText(ElementName elementName, HtmlAttributes attributes) throws SAXException {
+        appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
+        originalMode = mode;
+        mode = TEXT;
+        tokenizer.setStateAndEndTagExpectation(Tokenizer.RAWTEXT, elementName);
+    }
+
+    private void startTagScriptInHead(ElementName elementName, HtmlAttributes attributes) throws SAXException {
+        // XXX need to manage much more stuff here if supporting document.write()
+        appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
+        originalMode = mode;
+        mode = TEXT;
+        tokenizer.setStateAndEndTagExpectation(Tokenizer.SCRIPT_DATA, elementName);
+    }
+
+    private void startTagTemplateInHead(ElementName elementName, HtmlAttributes attributes) throws SAXException {
+        insertMarker();
+        appendToCurrentNodeAndPushElement(elementName, attributes);
+        originalMode = mode;
+        mode = TEMPLATE_CONTENTS;
+        pushTemplateMode(TEMPLATE_CONTENTS);
+    }
+
+    private boolean isTemplateContents() {
+        return TreeBuilder.NOT_FOUND_ON_STACK != findLast("template");
+    }
+
     private boolean isSpecialParentInForeign(StackNode<T> stackNode) {
         @NsUri String ns = stackNode.ns;
         return ("http://www.w3.org/1999/xhtml" == ns)
                 || (stackNode.isHtmlIntegrationPoint())
                 || (("http://www.w3.org/1998/Math/MathML" == ns) && (stackNode.getGroup() == MI_MO_MN_MS_MTEXT));
     }
 
     /**
-     * 
+     *
      * <p>
      * C++ memory note: The return value must be released.
-     * 
+     *
      * @return
      * @throws SAXException
      * @throws StopSniffingException
      */
     public static String extractCharsetFromContent(String attributeValue) {
         // This is a bit ugly. Converting the string to char array in order to
         // make the portability layer smaller.
         int charsetState = CHARSET_INITIAL;
@@ -3117,32 +3228,32 @@ public abstract class TreeBuilder<T> imp
 
     private void checkMetaCharset(HtmlAttributes attributes)
             throws SAXException {
         String charset = attributes.getValue(AttributeName.CHARSET);
         if (charset != null) {
             if (tokenizer.internalEncodingDeclaration(charset)) {
                 requestSuspension();
                 return;
-            }            
+            }
             return;
         }
         if (!Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
                 "content-type",
                 attributes.getValue(AttributeName.HTTP_EQUIV))) {
             return;
         }
         String content = attributes.getValue(AttributeName.CONTENT);
         if (content != null) {
             String extract = TreeBuilder.extractCharsetFromContent(content);
             // remember not to return early without releasing the string
             if (extract != null) {
                 if (tokenizer.internalEncodingDeclaration(extract)) {
                     requestSuspension();
-                }                
+                }
             }
             Portability.releaseString(extract);
         }
     }
 
     public final void endTag(ElementName elementName) throws SAXException {
         flushCharacters();
         needToDropLF = false;
@@ -3163,48 +3274,57 @@ public abstract class TreeBuilder<T> imp
                         break endtagloop;
                     }
                     if (stack[--eltPos].ns == "http://www.w3.org/1999/xhtml") {
                         break;
                     }
                 }
             }
             switch (mode) {
+                case TEMPLATE_CONTENTS:
+                    switch (group) {
+                        case TEMPLATE:
+                            // fall through to IN_HEAD
+                            break;
+                        default:
+                            errStrayEndTag(name);
+                            break endtagloop;
+                    }
                 case IN_ROW:
                     switch (group) {
                         case TR:
                             eltPos = findLastOrRoot(TreeBuilder.TR);
                             if (eltPos == 0) {
-                                assert fragment;
+                                assert fragment || isTemplateContents();
                                 errNoTableRowToClose();
                                 break endtagloop;
                             }
                             clearStackBackTo(eltPos);
                             pop();
                             mode = IN_TABLE_BODY;
                             break endtagloop;
                         case TABLE:
                             eltPos = findLastOrRoot(TreeBuilder.TR);
                             if (eltPos == 0) {
-                                assert fragment;
+                                assert fragment || isTemplateContents();
                                 errNoTableRowToClose();
                                 break endtagloop;
                             }
                             clearStackBackTo(eltPos);
                             pop();
                             mode = IN_TABLE_BODY;
                             continue;
                         case TBODY_OR_THEAD_OR_TFOOT:
                             if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) {
                                 errStrayEndTag(name);
                                 break endtagloop;
                             }
                             eltPos = findLastOrRoot(TreeBuilder.TR);
                             if (eltPos == 0) {
-                                assert fragment;
+                                assert fragment || isTemplateContents();
                                 errNoTableRowToClose();
                                 break endtagloop;
                             }
                             clearStackBackTo(eltPos);
                             pop();
                             mode = IN_TABLE_BODY;
                             continue;
                         case BODY:
@@ -3226,19 +3346,19 @@ public abstract class TreeBuilder<T> imp
                                 errStrayEndTag(name);
                                 break endtagloop;
                             }
                             clearStackBackTo(eltPos);
                             pop();
                             mode = IN_TABLE;
                             break endtagloop;
                         case TABLE:
-                            eltPos = findLastInTableScopeOrRootTbodyTheadTfoot();
-                            if (eltPos == 0) {
-                                assert fragment;
+                            eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
+                            if (eltPos == 0 || stack[eltPos].getGroup() == TEMPLATE) {
+                                assert fragment || isTemplateContents();
                                 errStrayEndTag(name);
                                 break endtagloop;
                             }
                             clearStackBackTo(eltPos);
                             pop();
                             mode = IN_TABLE;
                             continue;
                         case BODY:
@@ -3253,17 +3373,17 @@ public abstract class TreeBuilder<T> imp
                         default:
                             // fall through to IN_TABLE
                     }
                 case IN_TABLE:
                     switch (group) {
                         case TABLE:
                             eltPos = findLast("table");
                             if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
-                                assert fragment;
+                                assert fragment || isTemplateContents();
                                 errStrayEndTag(name);
                                 break endtagloop;
                             }
                             while (currentPtr >= eltPos) {
                                 pop();
                             }
                             resetTheInsertionMode();
                             break endtagloop;
@@ -3272,16 +3392,19 @@ public abstract class TreeBuilder<T> imp
                         case COL:
                         case COLGROUP:
                         case HTML:
                         case TBODY_OR_THEAD_OR_TFOOT:
                         case TD_OR_TH:
                         case TR:
                             errStrayEndTag(name);
                             break endtagloop;
+                        case TEMPLATE:
+                            // fall through to IN_HEAD
+                            break;
                         default:
                             errStrayEndTag(name);
                             // fall through to IN_BODY
                     }
                 case IN_CAPTION:
                     switch (group) {
                         case CAPTION:
                             eltPos = findLastInTableScope("caption");
@@ -3343,16 +3466,17 @@ public abstract class TreeBuilder<T> imp
                             }
                             clearTheListOfActiveFormattingElementsUpToTheLastMarker();
                             mode = IN_ROW;
                             break endtagloop;
                         case TABLE:
                         case TBODY_OR_THEAD_OR_TFOOT:
                         case TR:
                             if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) {
+                                assert name == "tbody" || name == "tfoot" || name == "thead" || fragment || isTemplateContents();
                                 errStrayEndTag(name);
                                 break endtagloop;
                             }
                             closeTheCell(findLastInTableScopeTdTh());
                             continue;
                         case BODY:
                         case CAPTION:
                         case COL:
@@ -3363,17 +3487,17 @@ public abstract class TreeBuilder<T> imp
                         default:
                             // fall through to IN_BODY
                     }
                 case FRAMESET_OK:
                 case IN_BODY:
                     switch (group) {
                         case BODY:
                             if (!isSecondOnStackBody()) {
-                                assert fragment;
+                                assert fragment || isTemplateContents();
                                 errStrayEndTag(name);
                                 break endtagloop;
                             }
                             assert currentPtr >= 1;
                             if (errorHandler != null) {
                                 uncloseloop1: for (int i = 2; i <= currentPtr; i++) {
                                     switch (stack[i].getGroup()) {
                                         case DD_OR_DT:
@@ -3390,17 +3514,17 @@ public abstract class TreeBuilder<T> imp
                                             break uncloseloop1;
                                     }
                                 }
                             }
                             mode = AFTER_BODY;
                             break endtagloop;
                         case HTML:
                             if (!isSecondOnStackBody()) {
-                                assert fragment;
+                                assert fragment || isTemplateContents();
                                 errStrayEndTag(name);
                                 break endtagloop;
                             }
                             if (errorHandler != null) {
                                 uncloseloop2: for (int i = 0; i <= currentPtr; i++) {
                                     switch (stack[i].getGroup()) {
                                         case DD_OR_DT:
                                         case LI:
@@ -3547,16 +3671,19 @@ public abstract class TreeBuilder<T> imp
                                     pop();
                                 }
                             }
                             reconstructTheActiveFormattingElements();
                             appendVoidElementToCurrentMayFoster(
                                     elementName,
                                     HtmlAttributes.EMPTY_ATTRIBUTES);
                             break endtagloop;
+                        case TEMPLATE:
+                            // fall through to IN_HEAD;
+                            break;
                         case AREA_OR_WBR:
                         // CPPONLY: case MENUITEM:
                         case PARAM_OR_SOURCE_OR_TRACK:
                         case EMBED_OR_IMG:
                         case IMAGE:
                         case INPUT:
                         case KEYGEN: // XXX??
                         case HR:
@@ -3617,16 +3744,19 @@ public abstract class TreeBuilder<T> imp
                             mode = AFTER_HEAD;
                             break endtagloop;
                         case BR:
                         case HTML:
                         case BODY:
                             pop();
                             mode = AFTER_HEAD;
                             continue;
+                        case TEMPLATE:
+                            endTagTemplateInHead(name);
+                            break endtagloop;
                         default:
                             errStrayEndTag(name);
                             break endtagloop;
                     }
                 case IN_HEAD_NOSCRIPT:
                     switch (group) {
                         case NOSCRIPT:
                             pop();
@@ -3639,30 +3769,35 @@ public abstract class TreeBuilder<T> imp
                             continue;
                         default:
                             errStrayEndTag(name);
                             break endtagloop;
                     }
                 case IN_COLUMN_GROUP:
                     switch (group) {
                         case COLGROUP:
-                            if (currentPtr == 0) {
-                                assert fragment;
+                            if (currentPtr == 0 || stack[currentPtr].getGroup() ==
+                                    TreeBuilder.TEMPLATE) {
+                                assert fragment || isTemplateContents();
                                 errGarbageInColgroup();
                                 break endtagloop;
                             }
                             pop();
                             mode = IN_TABLE;
                             break endtagloop;
                         case COL:
                             errStrayEndTag(name);
                             break endtagloop;
+                        case TEMPLATE:
+                            endTagTemplateInHead(name);
+                            break endtagloop;
                         default:
-                            if (currentPtr == 0) {
-                                assert fragment;
+                            if (currentPtr == 0 || stack[currentPtr].getGroup() ==
+                                    TreeBuilder.TEMPLATE) {
+                                assert fragment || isTemplateContents();
                                 errGarbageInColgroup();
                                 break endtagloop;
                             }
                             pop();
                             mode = IN_TABLE;
                             continue;
                     }
                 case IN_SELECT_IN_TABLE:
@@ -3718,16 +3853,19 @@ public abstract class TreeBuilder<T> imp
                                 errStrayEndTag(name);
                                 break endtagloop;
                             }
                             while (currentPtr >= eltPos) {
                                 pop();
                             }
                             resetTheInsertionMode();
                             break endtagloop;
+                        case TEMPLATE:
+                            endTagTemplateInHead(name);
+                            break endtagloop;
                         default:
                             errStrayEndTag(name);
                             break endtagloop;
                     }
                 case AFTER_BODY:
                     switch (group) {
                         case HTML:
                             if (fragment) {
@@ -3740,26 +3878,29 @@ public abstract class TreeBuilder<T> imp
                         default:
                             errEndTagAfterBody();
                             mode = framesetOk ? FRAMESET_OK : IN_BODY;
                             continue;
                     }
                 case IN_FRAMESET:
                     switch (group) {
                         case FRAMESET:
-                            if (currentPtr == 0) {
-                                assert fragment;
+                            if (currentPtr == 0 || isTemplateContents()) {
+                                assert fragment || isTemplateContents();
                                 errStrayEndTag(name);
                                 break endtagloop;
                             }
                             pop();
                             if ((!fragment) && !isCurrent("frameset")) {
                                 mode = AFTER_FRAMESET;
                             }
                             break endtagloop;
+                        case TEMPLATE:
+                            endTagTemplateInHead(name);
+                            break endtagloop;
                         default:
                             errStrayEndTag(name);
                             break endtagloop;
                     }
                 case AFTER_FRAMESET:
                     switch (group) {
                         case HTML:
                             mode = AFTER_AFTER_FRAMESET;
@@ -3787,17 +3928,17 @@ public abstract class TreeBuilder<T> imp
                             break;
                         case HTML401_TRANSITIONAL:
                             err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\u201D.");
                             break;
                         case NO_DOCTYPE_ERRORS:
                     }
                     // ]NOCPP]
                     /*
-                     * 
+                     *
                      * Set the document to quirks mode.
                      */
                     documentModeInternal(DocumentMode.QUIRKS_MODE, null, null,
                             false);
                     /*
                      * Then, switch to the root element mode of the tree
                      * construction stage
                      */
@@ -3868,19 +4009,38 @@ public abstract class TreeBuilder<T> imp
                         silentPop();
                     }
                     mode = originalMode;
                     break endtagloop;
             }
         } // endtagloop
     }
 
-    private int findLastInTableScopeOrRootTbodyTheadTfoot() {
+    private void endTagTemplateInHead(@Local String name) throws SAXException {
+        int eltPos = findLast(name);
+        if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
+            errStrayEndTag(name);
+            return;
+        }
+        generateImpliedEndTags();
+        if (errorHandler != null && !isCurrent(name)) {
+            errUnclosedElements(eltPos, name);
+        }
+        while (currentPtr >= eltPos) {
+            pop();
+        }
+        clearTheListOfActiveFormattingElementsUpToTheLastMarker();
+        popTemplateMode();
+        resetTheInsertionMode();
+    }
+
+    private int findLastInTableScopeOrRootTemplateTbodyTheadTfoot() {
         for (int i = currentPtr; i > 0; i--) {
-            if (stack[i].getGroup() == TreeBuilder.TBODY_OR_THEAD_OR_TFOOT) {
+            if (stack[i].getGroup() == TreeBuilder.TBODY_OR_THEAD_OR_TFOOT ||
+                    stack[i].getGroup() == TreeBuilder.TEMPLATE) {
                 return i;
             }
         }
         return 0;
     }
 
     private int findLast(@Local String name) {
         for (int i = currentPtr; i > 0; i--) {
@@ -3890,17 +4050,17 @@ public abstract class TreeBuilder<T> imp
         }
         return TreeBuilder.NOT_FOUND_ON_STACK;
     }
 
     private int findLastInTableScope(@Local String name) {
         for (int i = currentPtr; i > 0; i--) {
             if (stack[i].name == name) {
                 return i;
-            } else if (stack[i].name == "table") {
+            } else if (stack[i].name == "table" || stack[i].name == "template") {
                 return TreeBuilder.NOT_FOUND_ON_STACK;
             }
         }
         return TreeBuilder.NOT_FOUND_ON_STACK;
     }
 
     private int findLastInButtonScope(@Local String name) {
         for (int i = currentPtr; i > 0; i--) {
@@ -3929,17 +4089,17 @@ public abstract class TreeBuilder<T> imp
             if (stack[i].name == name) {
                 return i;
             } else if (stack[i].isScoping() || stack[i].name == "ul" || stack[i].name == "ol") {
                 return TreeBuilder.NOT_FOUND_ON_STACK;
             }
         }
         return TreeBuilder.NOT_FOUND_ON_STACK;
     }
-    
+
     private int findLastInScopeHn() {
         for (int i = currentPtr; i > 0; i--) {
             if (stack[i].getGroup() == TreeBuilder.H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
                 return i;
             } else if (stack[i].isScoping()) {
                 return TreeBuilder.NOT_FOUND_ON_STACK;
             }
         }
@@ -4085,25 +4245,30 @@ public abstract class TreeBuilder<T> imp
         return;
     }
 
     private int findLastInTableScopeTdTh() {
         for (int i = currentPtr; i > 0; i--) {
             @Local String name = stack[i].name;
             if ("td" == name || "th" == name) {
                 return i;
-            } else if (name == "table") {
+            } else if (name == "table" || name == "template") {
                 return TreeBuilder.NOT_FOUND_ON_STACK;
             }
         }
         return TreeBuilder.NOT_FOUND_ON_STACK;
     }
 
     private void clearStackBackTo(int eltPos) throws SAXException {
+        int eltGroup = stack[eltPos].getGroup();
         while (currentPtr > eltPos) { // > not >= intentional
+            if (stack[currentPtr].getGroup() == TEMPLATE
+                    && (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT|| eltGroup == TR || eltGroup == HTML)) {
+                return;
+            }
             pop();
         }
     }
 
     private void resetTheInsertionMode() {
         StackNode<T> node;
         @Local String name;
         @NsUri String ns;
@@ -4115,66 +4280,78 @@ public abstract class TreeBuilder<T> imp
                 if (!(contextNamespace == "http://www.w3.org/1999/xhtml" && (contextName == "td" || contextName == "th"))) {
                     name = contextName;
                     ns = contextNamespace;
                 } else {
                     mode = framesetOk ? FRAMESET_OK : IN_BODY; // XXX from Hixie's email
                     return;
                 }
             }
-            if ("select" == name) {
+            if ("template" == name) {
+                mode = templateModeStack[templateModePtr];
+                return;
+            } else if ("select" == name) {
+                // TODO: Fragment case. Add error reporting.
                 mode = IN_SELECT;
                 return;
             } else if ("td" == name || "th" == name) {
                 mode = IN_CELL;
                 return;
             } else if ("tr" == name) {
                 mode = IN_ROW;
                 return;
             } else if ("tbody" == name || "thead" == name || "tfoot" == name) {
                 mode = IN_TABLE_BODY;
                 return;
             } else if ("caption" == name) {
                 mode = IN_CAPTION;
                 return;
             } else if ("colgroup" == name) {
+                // TODO: Fragment case. Add error reporting.
                 mode = IN_COLUMN_GROUP;
                 return;
             } else if ("table" == name) {
                 mode = IN_TABLE;
                 return;
             } else if ("http://www.w3.org/1999/xhtml" != ns) {
                 mode = framesetOk ? FRAMESET_OK : IN_BODY;
                 return;
             } else if ("head" == name) {
-                mode = framesetOk ? FRAMESET_OK : IN_BODY; // really
+                if (name == contextName) {
+                    // TODO: Fragment case. Add error reporting.
+                    mode = framesetOk ? FRAMESET_OK : IN_BODY; // really
+                } else {
+                    mode = IN_HEAD;
+                }
                 return;
             } else if ("body" == name) {
                 mode = framesetOk ? FRAMESET_OK : IN_BODY;
                 return;
             } else if ("frameset" == name) {
+                // TODO: Fragment case. Add error reporting.
                 mode = IN_FRAMESET;
                 return;
             } else if ("html" == name) {
                 if (headPointer == null) {
+                    // TODO: Fragment case. Add error reporting.
                     mode = BEFORE_HEAD;
                 } else {
                     mode = AFTER_HEAD;
                 }
                 return;
             } else if (i == 0) {
                 mode = framesetOk ? FRAMESET_OK : IN_BODY;
                 return;
             }
         }
     }
 
     /**
      * @throws SAXException
-     * 
+     *
      */
     private void implicitlyCloseP() throws SAXException {
         int eltPos = findLastInButtonScope("p");
         if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
             return;
         }
         generateImpliedEndTagsExceptFor("p");
         if (errorHandler != null && eltPos != currentPtr) {
@@ -4190,16 +4367,26 @@ public abstract class TreeBuilder<T> imp
         return true;
     }
 
     private boolean debugOnlyClearLastListSlot() {
         listOfActiveFormattingElements[listPtr] = null;
         return true;
     }
 
+    private void pushTemplateMode(int mode) {
+        templateModePtr++;
+        if (templateModePtr == templateModeStack.length) {
+            int[] newStack = new int[templateModeStack.length + 64];
+            System.arraycopy(templateModeStack, 0, newStack, 0, templateModeStack.length);
+            templateModeStack = newStack;
+        }
+        templateModeStack[templateModePtr] = mode;
+    }
+
     @SuppressWarnings("unchecked") private void push(StackNode<T> node) throws SAXException {
         currentPtr++;
         if (currentPtr == stack.length) {
             StackNode<T>[] newStack = new StackNode[stack.length + 64];
             System.arraycopy(stack, 0, newStack, 0, stack.length);
             stack = newStack;
         }
         stack[currentPtr] = node;
@@ -4394,17 +4581,17 @@ public abstract class TreeBuilder<T> imp
                 assert node == listOfActiveFormattingElements[nodeListPos];
                 assert node == stack[nodePos];
                 T clone = createElement("http://www.w3.org/1999/xhtml",
                         node.name, node.attributes.cloneAttributes(null));
                 StackNode<T> newNode = new StackNode<T>(node.getFlags(), node.ns,
                         node.name, clone, node.popName, node.attributes
                         // [NOCPP[
                         , node.getLocator()
-                // ]NOCPP]       
+                // ]NOCPP]
                 ); // creation
                 // ownership
                 // goes
                 // to
                 // stack
                 node.dropAttributes(); // adopt ownership to newNode
                 stack[nodePos] = newNode;
                 newNode.retain(); // retain for list
@@ -4518,17 +4705,17 @@ public abstract class TreeBuilder<T> imp
                 candidate = i;
                 ++count;
             }
         }
         if (count >= 3) {
             removeFromListOfActiveFormattingElements(candidate);
         }
     }
-    
+
     private int findLastOrRoot(@Local String name) {
         for (int i = currentPtr; i > 0; i--) {
             if (stack[i].name == name) {
                 return i;
             }
         }
         return 0;
     }
@@ -4580,17 +4767,17 @@ public abstract class TreeBuilder<T> imp
         // [NOCPP[
                 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
         // ]NOCPP]
         ));
     }
 
     /**
      * @throws SAXException
-     * 
+     *
      */
     private void reconstructTheActiveFormattingElements() throws SAXException {
         if (listPtr == -1) {
             return;
         }
         StackNode<T> mostRecent = listOfActiveFormattingElements[listPtr];
         if (mostRecent == null || isInStack(mostRecent)) {
             return;
@@ -4632,35 +4819,41 @@ public abstract class TreeBuilder<T> imp
             listOfActiveFormattingElements[entryPos] = entryClone;
             // overwriting the old entry on the list, so release & retain
             entry.release();
             entryClone.retain();
         }
     }
 
     private void insertIntoFosterParent(T child) throws SAXException {
-        int eltPos = findLastOrRoot(TreeBuilder.TABLE);
-        StackNode<T> node = stack[eltPos];
-        T elt = node.node;
-        if (eltPos == 0) {
-            appendElement(child, elt);
+        int tablePos = findLastOrRoot(TreeBuilder.TABLE);
+        int templatePos = findLastOrRoot(TreeBuilder.TEMPLATE);
+
+        if (templatePos >= tablePos) {
+            appendElement(child, stack[templatePos].node);
             return;
         }
-        insertFosterParentedChild(child, elt, stack[eltPos - 1].node);
+
+        StackNode<T> node = stack[tablePos];
+        insertFosterParentedChild(child, node.node, stack[tablePos - 1].node);
     }
 
     private boolean isInStack(StackNode<T> node) {
         for (int i = currentPtr; i >= 0; i--) {
             if (stack[i] == node) {
                 return true;
             }
         }
         return false;
     }
 
+    private void popTemplateMode() {
+        templateModePtr--;
+    }
+
     private void pop() throws SAXException {
         StackNode<T> node = stack[currentPtr];
         assert debugOnlyClearLastStackSlot();
         currentPtr--;
         elementPopped(node.ns, node.popName, node.node);
         node.release();
     }
 
@@ -4873,16 +5066,19 @@ public abstract class TreeBuilder<T> imp
             HtmlAttributes attributes)
             throws SAXException {
         // [NOCPP[
         checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
         // ]NOCPP]
         // This method can't be called for custom elements
         T elt = createElement("http://www.w3.org/1999/xhtml", elementName.name, attributes);
         appendElement(elt, stack[currentPtr].node);
+        if (ElementName.TEMPLATE == elementName) {
+            elt = getDocumentFragmentForTemplate(elt);
+        }
         StackNode<T> node = new StackNode<T>(elementName, elt
                 // [NOCPP[
                 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
         // ]NOCPP]
         );
         push(node);
     }
 
@@ -4940,16 +5136,22 @@ public abstract class TreeBuilder<T> imp
                 markAsHtmlIntegrationPoint
                 // [NOCPP[
                 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
         // ]NOCPP]
         );
         push(node);
     }
 
+    // [NOCPP[
+    T getDocumentFragmentForTemplate(T template) {
+        return template;
+    }
+    // ]NOCPP]
+
     private boolean annotationXmlEncodingPermitsHtml(HtmlAttributes attributes) {
         String encoding = attributes.getValue(AttributeName.ENCODING);
         if (encoding == null) {
             return false;
         }
         return Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
                 "application/xhtml+xml", encoding)
                 || Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
@@ -5113,31 +5315,31 @@ public abstract class TreeBuilder<T> imp
         // ownership transferred to form pointer
         StackNode<T> current = stack[currentPtr];
         appendElement(elt, current.node);
         elementPushed("http://www.w3.org/1999/xhtml", "form", elt);
         elementPopped("http://www.w3.org/1999/xhtml", "form", elt);
     }
 
     // [NOCPP[
-    
+
     private final void accumulateCharactersForced(@Const @NoLength char[] buf,
             int start, int length) throws SAXException {
         int newLen = charBufferLen + length;
         if (newLen > charBuffer.length) {
             char[] newBuf = new char[newLen];
             System.arraycopy(charBuffer, 0, newBuf, 0, charBufferLen);
             charBuffer = newBuf;
         }
         System.arraycopy(buf, start, charBuffer, charBufferLen, length);
         charBufferLen = newLen;
     }
-    
+
     // ]NOCPP]
-    
+
     protected void accumulateCharacters(@Const @NoLength char[] buf, int start,
             int length) throws SAXException {
         appendCharacters(stack[currentPtr].node, buf, start, length);
     }
 
     // ------------------------------- //
 
     protected final void requestSuspension() {
@@ -5171,17 +5373,17 @@ public abstract class TreeBuilder<T> imp
     protected abstract void insertFosterParentedCharacters(
             @NoLength char[] buf, int start, int length, T table, T stackParent)
             throws SAXException;
 
     protected abstract void appendCharacters(T parent, @NoLength char[] buf,
             int start, int length) throws SAXException;
 
     protected abstract void appendIsindexPrompt(T parent) throws SAXException;
-    
+
     protected abstract void appendComment(T parent, @NoLength char[] buf,
             int start, int length) throws SAXException;
 
     protected abstract void appendCommentToDocument(@NoLength char[] buf,
             int start, int length) throws SAXException;
 
     protected abstract void addAttributesToElement(T element,
             HtmlAttributes attributes) throws SAXException;
@@ -5230,36 +5432,36 @@ public abstract class TreeBuilder<T> imp
     }
 
     public void setIgnoringComments(boolean ignoreComments) {
         wantingComments = !ignoreComments;
     }
 
     /**
      * Sets the errorHandler.
-     * 
+     *
      * @param errorHandler
      *            the errorHandler to set
      */
     public final void setErrorHandler(ErrorHandler errorHandler) {
         this.errorHandler = errorHandler;
     }
 
     /**
      * Returns the errorHandler.
-     * 
+     *
      * @return the errorHandler
      */
     public ErrorHandler getErrorHandler() {
         return errorHandler;
     }
 
     /**
      * The argument MUST be an interned string or <code>null</code>.
-     * 
+     *
      * @param context
      */
     public final void setFragmentContext(@Local String context) {
         this.contextName = context;
         this.contextNamespace = "http://www.w3.org/1999/xhtml";
         this.contextNode = null;
         this.fragment = (contextName != null);
         this.quirks = false;
@@ -5268,32 +5470,32 @@ public abstract class TreeBuilder<T> imp
     // ]NOCPP]
 
     /**
      * @see nu.validator.htmlparser.common.TokenHandler#cdataSectionAllowed()
      */
     @Inline public boolean cdataSectionAllowed() throws SAXException {
         return isInForeign();
     }
-    
+
     private boolean isInForeign() {
         return currentPtr >= 0
                 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml";
     }
 
     private boolean isInForeignButNotHtmlOrMathTextIntegrationPoint() {
         if (currentPtr < 0) {
             return false;
         }
         return !isSpecialParentInForeign(stack[currentPtr]);
     }
 
     /**
      * The argument MUST be an interned string or <code>null</code>.
-     * 
+     *
      * @param context
      */
     public final void setFragmentContext(@Local String context,
             @NsUri String ns, T node, boolean quirks) {
         this.contextName = context;
         this.contextNamespace = ns;
         this.contextNode = node;
         this.fragment = (contextName != null);
@@ -5301,62 +5503,62 @@ public abstract class TreeBuilder<T> imp
     }
 
     protected final T currentNode() {
         return stack[currentPtr].node;
     }
 
     /**
      * Returns the scriptingEnabled.
-     * 
+     *
      * @return the scriptingEnabled
      */
     public boolean isScriptingEnabled() {
         return scriptingEnabled;
     }
 
     /**
      * Sets the scriptingEnabled.
-     * 
+     *
      * @param scriptingEnabled
      *            the scriptingEnabled to set
      */
     public void setScriptingEnabled(boolean scriptingEnabled) {
         this.scriptingEnabled = scriptingEnabled;
     }
 
     // [NOCPP[
 
     /**
      * Sets the doctypeExpectation.
-     * 
+     *
      * @param doctypeExpectation
      *            the doctypeExpectation to set
      */
     public void setDoctypeExpectation(DoctypeExpectation doctypeExpectation) {
         this.doctypeExpectation = doctypeExpectation;
     }
 
     public void setNamePolicy(XmlViolationPolicy namePolicy) {
         this.namePolicy = namePolicy;
     }
 
     /**
      * Sets the documentModeHandler.
-     * 
+     *
      * @param documentModeHandler
      *            the documentModeHandler to set
      */
     public void setDocumentModeHandler(DocumentModeHandler documentModeHandler) {
         this.documentModeHandler = documentModeHandler;
     }
 
     /**
      * Sets the reportingDoctype.
-     * 
+     *
      * @param reportingDoctype
      *            the reportingDoctype to set
      */
     public void setReportingDoctype(boolean reportingDoctype) {
         this.reportingDoctype = reportingDoctype;
     }
 
     // ]NOCPP]
@@ -5412,17 +5614,17 @@ public abstract class TreeBuilder<T> imp
         return false;
     }
 
     /**
      * Creates a comparable snapshot of the tree builder state. Snapshot
      * creation is only supported immediately after a script end tag has been
      * processed. In C++ the caller is responsible for calling
      * <code>delete</code> on the returned object.
-     * 
+     *
      * @return a snapshot.
      * @throws SAXException
      */
     @SuppressWarnings("unchecked") public TreeBuilderState<T> newSnapshot()
             throws SAXException {
         StackNode<T>[] listCopy = new StackNode[listPtr + 1];
         for (int i = 0; i < listCopy.length; i++) {
             StackNode<T> node = listOfActiveFormattingElements[i];
@@ -5501,17 +5703,17 @@ public abstract class TreeBuilder<T> imp
 
     @SuppressWarnings("unchecked") public void loadState(
             TreeBuilderState<T> snapshot, Interner interner)
             throws SAXException {
         StackNode<T>[] stackCopy = snapshot.getStack();
         int stackLen = snapshot.getStackLength();
         StackNode<T>[] listCopy = snapshot.getListOfActiveFormattingElements();
         int listLen = snapshot.getListOfActiveFormattingElementsLength();
-        
+
         for (int i = 0; i <= listPtr; i++) {
             if (listOfActiveFormattingElements[i] != null) {
                 listOfActiveFormattingElements[i].release();
             }
         }
         if (listOfActiveFormattingElements.length < listLen) {
             listOfActiveFormattingElements = new StackNode[listLen];
         }
@@ -5546,17 +5748,17 @@ public abstract class TreeBuilder<T> imp
             int listIndex = findInArray(node, listCopy);
             if (listIndex == -1) {
                 StackNode<T> newNode = new StackNode<T>(node.getFlags(), node.ns,
                         Portability.newLocalFromLocal(node.name, interner), node.node,
                         Portability.newLocalFromLocal(node.popName, interner),
                         null
                         // [NOCPP[
                         , node.getLocator()
-                // ]NOCPP]       
+                // ]NOCPP]
                 );
                 stack[i] = newNode;
             } else {
                 stack[i] = listOfActiveFormattingElements[listIndex];
                 stack[i].retain();
             }
         }
         formPointer = snapshot.getFormPointer();
@@ -5582,26 +5784,26 @@ public abstract class TreeBuilder<T> imp
      * @see nu.validator.htmlparser.impl.TreeBuilderState#getFormPointer()
      */
     public T getFormPointer() {
         return formPointer;
     }
 
     /**
      * Returns the headPointer.
-     * 
+     *
      * @return the headPointer
      */
     public T getHeadPointer() {
         return headPointer;
     }
-    
+
     /**
      * Returns the deepTreeSurrogateParent.
-     * 
+     *
      * @return the deepTreeSurrogateParent
      */
     public T getDeepTreeSurrogateParent() {
         return deepTreeSurrogateParent;
     }
 
     /**
      * @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElements()
@@ -5614,53 +5816,53 @@ public abstract class TreeBuilder<T> imp
      * @see nu.validator.htmlparser.impl.TreeBuilderState#getStack()
      */
     public StackNode<T>[] getStack() {
         return stack;
     }
 
     /**
      * Returns the mode.
-     * 
+     *
      * @return the mode
      */
     public int getMode() {
         return mode;
     }
 
     /**
      * Returns the originalMode.
-     * 
+     *
      * @return the originalMode
      */
     public int getOriginalMode() {
         return originalMode;
     }
 
     /**
      * Returns the framesetOk.
-     * 
+     *
      * @return the framesetOk
      */
     public boolean isFramesetOk() {
         return framesetOk;
     }
-    
+
     /**
      * Returns the needToDropLF.
-     * 
+     *
      * @return the needToDropLF
      */
     public boolean isNeedToDropLF() {
         return needToDropLF;
     }
 
     /**
      * Returns the quirks.
-     * 
+     *
      * @return the quirks
      */
     public boolean isQuirks() {
         return quirks;
     }
 
     /**
      * @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElementsLength()
@@ -5674,75 +5876,75 @@ public abstract class TreeBuilder<T> imp
      */
     public int getStackLength() {
         return currentPtr + 1;
     }
 
     /**
      * Reports a stray start tag.
      * @param name the name of the stray tag
-     * 
+     *
      * @throws SAXException
      */
     private void errStrayStartTag(@Local String name) throws SAXException {
-        err("Stray end tag \u201C" + name + "\u201D.");
+        err("Stray start tag \u201C" + name + "\u201D.");
     }
 
     /**
      * Reports a stray end tag.
      * @param name the name of the stray tag
-     * 
+     *
      * @throws SAXException
      */
     private void errStrayEndTag(@Local String name) throws SAXException {
         err("Stray end tag \u201C" + name + "\u201D.");
     }
-    
+
     /**
      * Reports a state when elements expected to be closed were not.
-     * 
+     *
      * @param eltPos the position of the start tag on the stack of the element
      * being closed.
      * @param name the name of the end tag
-     * 
+     *
      * @throws SAXException
      */
     private void errUnclosedElements(int eltPos, @Local String name) throws SAXException {
         errNoCheck("End tag \u201C" + name + "\u201D seen, but there were open elements.");
         errListUnclosedStartTags(eltPos);
     }
 
     /**
-     * Reports a state when elements expected to be closed ahead of an implied 
+     * Reports a state when elements expected to be closed ahead of an implied
      * end tag but were not.
-     * 
+     *
      * @param eltPos the position of the start tag on the stack of the element
      * being closed.
      * @param name the name of the end tag
-     * 
+     *
      * @throws SAXException
      */
     private void errUnclosedElementsImplied(int eltPos, String name) throws SAXException {
         errNoCheck("End tag \u201C" + name + "\u201D implied, but there were open elements.");
         errListUnclosedStartTags(eltPos);
     }
 
     /**
-     * Reports a state when elements expected to be closed ahead of an implied 
+     * Reports a state when elements expected to be closed ahead of an implied
      * table cell close.
-     * 
+     *
      * @param eltPos the position of the start tag on the stack of the element
      * being closed.
      * @throws SAXException
      */
     private void errUnclosedElementsCell(int eltPos) throws SAXException {
         errNoCheck("A table cell was implicitly closed, but there were open elements.");
         errListUnclosedStartTags(eltPos);
     }
-    
+
     private void errStrayDoctype() throws SAXException {
         err("Stray doctype.");
     }
 
     private void errAlmostStandardsDoctype() throws SAXException {
         err("Almost standards mode doctype. Expected \u201C<!DOCTYPE html>\u201D.");
     }
 
@@ -5965,17 +6167,17 @@ public abstract class TreeBuilder<T> imp
         }
         errNoCheck("End of file seen and there were open elements.");
         // just report all remaining unclosed elements
         errListUnclosedStartTags(0);
     }
 
     /**
      * Reports arriving at/near end of document with unclosed elements remaining.
-     * 
+     *
      * @param message
      *            the message
      * @throws SAXException
      */
     private void errEndWithUnclosedElements(@Local String name) throws SAXException {
         if (errorHandler == null) {
             return;
         }
--- a/parser/html/nsHtml5AtomList.h
+++ b/parser/html/nsHtml5AtomList.h
@@ -16,16 +16,17 @@
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
  * DEALINGS IN THE SOFTWARE.
  */
 
 HTML5_ATOM(emptystring, "")
+HTML5_ATOM(template_, "template")
 HTML5_ATOM(title, "title")
 HTML5_ATOM(textarea, "textarea")
 HTML5_ATOM(style, "style")
 HTML5_ATOM(xmp, "xmp")
 HTML5_ATOM(iframe, "iframe")
 HTML5_ATOM(noembed, "noembed")
 HTML5_ATOM(noframes, "noframes")
 HTML5_ATOM(noscript, "noscript")
@@ -39,27 +40,27 @@ HTML5_ATOM(address, "address")
 HTML5_ATOM(div, "div")
 HTML5_ATOM(a, "a")
 HTML5_ATOM(nobr, "nobr")
 HTML5_ATOM(input, "input")
 HTML5_ATOM(option, "option")
 HTML5_ATOM(ruby, "ruby")
 HTML5_ATOM(select, "select")
 HTML5_ATOM(optgroup, "optgroup")
+HTML5_ATOM(tbody, "tbody")
+HTML5_ATOM(tfoot, "tfoot")
+HTML5_ATOM(thead, "thead")
 HTML5_ATOM(frameset, "frameset")
 HTML5_ATOM(button, "button")
 HTML5_ATOM(ul, "ul")
 HTML5_ATOM(ol, "ol")
 HTML5_ATOM(html, "html")
 HTML5_ATOM(td, "td")
 HTML5_ATOM(th, "th")
 HTML5_ATOM(tr, "tr")
-HTML5_ATOM(tbody, "tbody")
-HTML5_ATOM(thead, "thead")
-HTML5_ATOM(tfoot, "tfoot")
 HTML5_ATOM(colgroup, "colgroup")
 HTML5_ATOM(head, "head")
 HTML5_ATOM(body, "body")
 HTML5_ATOM(form, "form")
 HTML5_ATOM(xmlns, "xmlns")
 HTML5_ATOM(xlink, "xlink")
 HTML5_ATOM(xml, "xml")
 HTML5_ATOM(d, "d")
@@ -326,17 +327,16 @@ HTML5_ATOM(onrepeat, "onrepeat")
 HTML5_ATOM(onselect, "onselect")
 HTML5_ATOM(notation, "notation")
 HTML5_ATOM(noresize, "noresize")
 HTML5_ATOM(manifest, "manifest")
 HTML5_ATOM(mathsize, "mathsize")
 HTML5_ATOM(multiple, "multiple")
 HTML5_ATOM(longdesc, "longdesc")
 HTML5_ATOM(language, "language")
-HTML5_ATOM(template_, "template")
 HTML5_ATOM(tabindex, "tabindex")
 HTML5_ATOM(readonly, "readonly")
 HTML5_ATOM(selected, "selected")
 HTML5_ATOM(rowlines, "rowlines")
 HTML5_ATOM(seamless, "seamless")
 HTML5_ATOM(rowalign, "rowalign")
 HTML5_ATOM(stretchy, "stretchy")
 HTML5_ATOM(required, "required")
--- a/parser/html/nsHtml5AttributeName.cpp
+++ b/parser/html/nsHtml5AttributeName.cpp
@@ -771,17 +771,17 @@ nsHtml5AttributeName* nsHtml5AttributeNa
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_STRIKETHROUGH_POSITION = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_STRIKETHROUGH_THICKNESS = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_EXTERNALRESOURCESREQUIRED = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_GLYPH_ORIENTATION_VERTICAL = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_COLOR_INTERPOLATION_FILTERS = nullptr;
 nsHtml5AttributeName* nsHtml5AttributeName::ATTR_GLYPH_ORIENTATION_HORIZONTAL = nullptr;
 nsHtml5AttributeName** nsHtml5AttributeName::ATTRIBUTE_NAMES = 0;
 static int32_t const ATTRIBUTE_HASHES_DATA[] = { 1153, 1383, 1601, 1793, 1827, 1857, 68600, 69146, 69177, 70237, 70270, 71572, 71669, 72415, 72444, 74846, 74904, 74943, 75001, 75276, 75590, 84742, 84839, 85575, 85963, 85992, 87204, 88074, 88171, 89130, 89163, 3207892, 3283895, 3284791, 3338752, 3358197, 3369562, 3539124, 3562402, 3574260, 3670335, 3696933, 3721879, 135280021, 135346322, 136317019, 136475749, 136548517, 136652214, 136884919, 136902418, 136942992, 137292068, 139120259, 139785574, 142250603, 142314056, 142331176, 142519584, 144752417, 145106895, 146147200, 146765926, 148805544, 149655723, 149809441, 150018784, 150445028, 150813181, 150923321, 152528754, 152536216, 152647366, 152962785, 155219321, 155654904, 157317483, 157350248, 157437941, 157447478, 157604838, 157685404, 157894402, 158315188, 166078431, 169409980, 169700259, 169856932, 170007032, 170409695, 170466488, 170513710, 170608367, 173028944, 173896963, 176090625, 176129212, 179390001, 179489057, 179627464, 179840468, 179849042, 180004216, 181779081, 183027151, 183645319, 183698797, 185922012, 185997252, 188312483, 188675799, 190977533, 190992569, 191006194, 191033518, 191038774, 191096249, 191166163, 191194426, 191522106, 191568039, 200104642, 202506661, 202537381, 202602917, 203070590, 203120766, 203389054, 203690071, 203971238, 203986524, 209040857, 209125756, 212055489, 212322418, 212746849, 213002877, 213055164, 213088023, 213259873, 213273386, 213435118, 213437318, 213438231, 213493071, 213532268, 213542834, 213584431, 213659891, 215285828, 215880731, 216112976, 216684637, 217369699, 217565298, 217576549, 218186795, 219743185, 220082234, 221623802, 221986406, 222283890, 223089542, 223138630, 223311265, 224547358, 224587256, 224589550, 224655650, 224785518, 224810917, 224813302, 225429618, 225432950, 225440869, 236107233, 236709921, 236838947, 237117095, 237143271, 237172455, 237209953, 237354143, 237372743, 237668065, 237703073, 237714273, 239743521, 240512803, 240522627, 240560417, 240656513, 241015715, 241062755, 241065383, 243523041, 245865199, 246261793, 246556195, 246774817, 246923491, 246928419, 246981667, 247014847, 247058369, 247112833, 247118177, 247119137, 247128739, 247316903, 249533729, 250235623, 250269543, 251402351, 252339047, 253260911, 253293679, 254844367, 255547879, 256077281, 256345377, 258124199, 258354465, 258605063, 258744193, 258845603, 258856961, 258926689, 269869248, 270174334, 270709417, 270778994, 270781796, 271102503, 271478858, 271490090, 272870654, 273335275, 273369140, 273924313, 274108530, 274116736, 276818662, 277476156, 279156579, 279349675, 280108533, 280128712, 280132869, 280162403, 280280292, 280413430, 280506130, 280677397, 280678580, 280686710, 280689066, 282736758, 283110901, 283275116, 283823226, 283890012, 284479340, 284606461, 286700477, 286798916, 291557706, 291665349, 291804100, 292138018, 292166446, 292418738, 292451039, 300298041, 300374839, 300597935, 303073389, 303083839, 303266673, 303354997, 303430688, 303576261, 303724281, 303819694, 304242723, 304382625, 306247792, 307227811, 307468786, 307724489, 309671175, 310252031, 310358241, 310373094, 311015256, 313357609, 313683893, 313701861, 313706996, 313707317, 313710350, 314027746, 314038181, 314091299, 314205627, 314233813, 316741830, 316797986, 317486755, 317794164, 320076137, 322657125, 322887778, 323506876, 323572412, 323605180, 325060058, 325320188, 325398738, 325541490, 325671619, 333868843, 336806130, 337212108, 337282686, 337285434, 337585223, 338036037, 338298087, 338566051, 340943551, 341190970, 342995704, 343352124, 343912673, 344585053, 346977248, 347218098, 347262163, 347278576, 347438191, 347655959, 347684788, 347726430, 347727772, 347776035, 347776629, 349500753, 350880161, 350887073, 353384123, 355496998, 355906922, 355979793, 356545959, 358637867, 358905016, 359164318, 359247286, 359350571, 359579447, 365560330, 367399355, 367420285, 367510727, 368013212, 370234760, 370353345, 370710317, 371074566, 371122285, 371194213, 371448425, 371448430, 371545055, 371593469, 371596922, 371758751, 371964792, 372151328, 376550136, 376710172, 376795771, 376826271, 376906556, 380514830, 380774774, 380775037, 381030322, 381136500, 381281631, 381282269, 381285504, 381330595, 381331422, 381335911, 381336484, 383907298, 383917408, 384595009, 384595013, 387799894, 387823201, 392581647, 392584937, 392742684, 392906485, 393003349, 400644707, 400973830, 404428547, 404432113, 404432865, 404469244, 404478897, 404694860, 406887479, 408294949, 408789955, 410022510, 410467324, 410586448, 410945965, 411845275, 414327152, 414327932, 414329781, 414346257, 414346439, 414639928, 414835998, 414894517, 414986533, 417465377, 417465381, 417492216, 418259232, 419310946, 420103495, 420242342, 420380455, 420658662, 420717432, 423183880, 424539259, 425929170, 425972964, 426050649, 426126450, 426142833, 426607922, 437289840, 437347469, 437412335, 437423943, 437455540, 437462252, 437597991, 437617485, 437986305, 437986507, 437986828, 437987072, 438015591, 438034813, 438038966, 438179623, 438347971, 438483573, 438547062, 438895551, 441592676, 442032555, 443548979, 447881379, 447881655, 447881895, 447887844, 448416189, 448445746, 448449012, 450942191, 452816744, 453668677, 454434495, 456610076, 456642844, 456738709, 457544600, 459451897, 459680944, 468058810, 468083581, 470964084, 471470955, 471567278, 472267822, 481177859, 481210627, 481435874, 481455115, 481485378, 481490218, 485105638, 486005878, 486383494, 487988916, 488103783, 490661867, 491574090, 491578272, 493041952, 493441205, 493582844, 493716979, 504577572, 504740359, 505091638, 505592418, 505656212, 509516275, 514998531, 515571132, 515594682, 518712698, 521362273, 526592419, 526807354, 527348842, 538294791, 539214049, 544689535, 545535009, 548544752, 548563346, 548595116, 551679010, 558034099, 560329411, 560356209, 560671018, 560671152, 560692590, 560845442, 569212097, 569474241, 572252718, 572768481, 575326764, 576174758, 576190819, 582099184, 582099438, 582372519, 582558889, 586552164, 591325418, 594231990, 594243961, 605711268, 615672071, 616086845, 621792370, 624879850, 627432831, 640040548, 654392808, 658675477, 659420283, 672891587, 694768102, 705890982, 725543146, 759097578, 761686526, 795383908, 843809551, 878105336, 908643300, 945213471 };
-staticJArray<int32_t,int32_t> nsHtml5AttributeName::ATTRIBUTE_HASHES = { ATTRIBUTE_HASHES_DATA, NS_ARRAY_LENGTH(ATTRIBUTE_HASHES_DATA) };
+staticJArray<int32_t,int32_t> nsHtml5AttributeName::ATTRIBUTE_HASHES = { ATTRIBUTE_HASHES_DATA, MOZ_ARRAY_LENGTH(ATTRIBUTE_HASHES_DATA) };
 void
 nsHtml5AttributeName::initializeStatics()
 {
   ALL_NO_NS = new int32_t[3];
   ALL_NO_NS[0] = kNameSpaceID_None;
   ALL_NO_NS[1] = kNameSpaceID_None;
   ALL_NO_NS[2] = kNameSpaceID_None;
   XMLNS_NS = new int32_t[3];
--- a/parser/html/nsHtml5ElementName.cpp
+++ b/parser/html/nsHtml5ElementName.cpp
@@ -446,16 +446,17 @@ nsHtml5ElementName* nsHtml5ElementName::
 nsHtml5ElementName* nsHtml5ElementName::ELT_OPTGROUP = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_POLYLINE = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_PREFETCH = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_PROGRESS = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_PRSUBSET = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_QUOTIENT = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_SELECTOR = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_TEXTAREA = nullptr;
+nsHtml5ElementName* nsHtml5ElementName::ELT_TEMPLATE = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_TEXTPATH = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_VARIANCE = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_ANIMATION = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_CONJUGATE = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_CONDITION = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_COMPLEXES = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_FONT_FACE = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_FACTORIAL = nullptr;
@@ -523,18 +524,18 @@ nsHtml5ElementName* nsHtml5ElementName::
 nsHtml5ElementName* nsHtml5ElementName::ELT_FONT_FACE_FORMAT = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_FECONVOLVEMATRIX = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_FEDIFFUSELIGHTING = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_FEDISPLACEMENTMAP = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_FESPECULARLIGHTING = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_DOMAINOFAPPLICATION = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_FECOMPONENTTRANSFER = nullptr;
 nsHtml5ElementName** nsHtml5ElementName::ELEMENT_NAMES = 0;
-static int32_t const ELEMENT_HASHES_DATA[] = { 1057, 1090, 1255, 1321, 1552, 1585, 1651, 1717, 68162, 68899, 69059, 69764, 70020, 70276, 71077, 71205, 72134, 72232, 72264, 72296, 72328, 72360, 72392, 73351, 74312, 75209, 78124, 78284, 78476, 79149, 79309, 79341, 79469, 81295, 81487, 82224, 84498, 84626, 86164, 86292, 86612, 86676, 87445, 3183041, 3186241, 3198017, 3218722, 3226754, 3247715, 3256803, 3263971, 3264995, 3289252, 3291332, 3295524, 3299620, 3326725, 3379303, 3392679, 3448233, 3460553, 3461577, 3510347, 3546604, 3552364, 3556524, 3576461, 3586349, 3588141, 3590797, 3596333, 3622062, 3625454, 3627054, 3675728, 3749042, 3771059, 3771571, 3776211, 3782323, 3782963, 3784883, 3785395, 3788979, 3815476, 3839605, 3885110, 3917911, 3948984, 3951096, 135304769, 135858241, 136498210, 136906434, 137138658, 137512995, 137531875, 137548067, 137629283, 137645539, 137646563, 137775779, 138529956, 138615076, 139040932, 140954086, 141179366, 141690439, 142738600, 143013512, 146979116, 147175724, 147475756, 147902637, 147936877, 148017645, 148131885, 148228141, 148229165, 148309165, 148317229, 148395629, 148551853, 148618829, 149076462, 149490158, 149572782, 151277616, 151639440, 153268914, 153486514, 153563314, 153750706, 153763314, 153914034, 154406067, 154417459, 154600979, 154678323, 154680979, 154866835, 155366708, 155375188, 155391572, 155465780, 155869364, 158045494, 168988979, 169321621, 169652752, 173151309, 174240818, 174247297, 174669292, 175391532, 176638123, 177380397, 177879204, 177886734, 180753473, 181020073, 181503558, 181686320, 181999237, 181999311, 182048201, 182074866, 182078003, 182083764, 182920847, 184716457, 184976961, 185145071, 187281445, 187872052, 188100653, 188875944, 188919873, 188920457, 189107250, 189203987, 189371817, 189414886, 189567458, 190266670, 191318187, 191337609, 202479203, 202493027, 202835587, 202843747, 203013219, 203036048, 203045987, 203177552, 203898516, 204648562, 205067918, 205078130, 205096654, 205689142, 205690439, 205988909, 207213161, 207794484, 207800999, 208023602, 208213644, 208213647, 210261490, 210310273, 210940978, 213325049, 213946445, 214055079, 215125040, 215134273, 215135028, 215237420, 215418148, 215553166, 215553394, 215563858, 215627949, 215754324, 217529652, 217713834, 217732628, 218731945, 221417045, 221424946, 221493746, 221515401, 221658189, 221908140, 221910626, 221921586, 222659762, 225001091, 236105833, 236113965, 236194995, 236195427, 236206132, 236206387, 236211683, 236212707, 236381647, 236571826, 237124271, 238172205, 238210544, 238270764, 238435405, 238501172, 239224867, 239257644, 239710497, 240307721, 241208789, 241241557, 241318060, 241319404, 241343533, 241344069, 241405397, 241765845, 243864964, 244502085, 244946220, 245109902, 247647266, 247707956, 248648814, 248648836, 248682161, 248986932, 249058914, 249697357, 252132601, 252135604, 252317348, 255007012, 255278388, 255641645, 256365156, 257566121, 269763372, 271202790, 271863856, 272049197, 272127474, 274339449, 274939471, 275388004, 275388005, 275388006, 275977800, 278267602, 278513831, 278712622, 281613765, 281683369, 282120228, 282250732, 282498697, 282508942, 283743649, 283787570, 284710386, 285391148, 285478533, 285854898, 285873762, 286931113, 288964227, 289445441, 289689648, 291671489, 303512884, 305319975, 305610036, 305764101, 308448294, 308675890, 312085683, 312264750, 315032867, 316391000, 317331042, 317902135, 318950711, 319447220, 321499182, 322538804, 323145200, 337067316, 337826293, 339905989, 340833697, 341457068, 342310196, 345302593, 349554733, 349771471, 349786245, 350819405, 356072847, 370349192, 373962798, 375558638, 375574835, 376053993, 383276530, 383373833, 383407586, 384439906, 386079012, 404133513, 404307343, 407031852, 408072233, 409112005, 409608425, 409771500, 419040932, 437730612, 439529766, 442616365, 442813037, 443157674, 443295316, 450118444, 450482697, 456789668, 459935396, 471217869, 474073645, 476230702, 476665218, 476717289, 483014825, 485083298, 489306281, 538364390, 540675748, 543819186, 543958612, 576960820, 577242548, 610515252, 642202932, 644420819 };
-staticJArray<int32_t,int32_t> nsHtml5ElementName::ELEMENT_HASHES = { ELEMENT_HASHES_DATA, NS_ARRAY_LENGTH(ELEMENT_HASHES_DATA) };
+static int32_t const ELEMENT_HASHES_DATA[] = { 1057, 1090, 1255, 1321, 1552, 1585, 1651, 1717, 68162, 68899, 69059, 69764, 70020, 70276, 71077, 71205, 72134, 72232, 72264, 72296, 72328, 72360, 72392, 73351, 74312, 75209, 78124, 78284, 78476, 79149, 79309, 79341, 79469, 81295, 81487, 82224, 84498, 84626, 86164, 86292, 86612, 86676, 87445, 3183041, 3186241, 3198017, 3218722, 3226754, 3247715, 3256803, 3263971, 3264995, 3289252, 3291332, 3295524, 3299620, 3326725, 3379303, 3392679, 3448233, 3460553, 3461577, 3510347, 3546604, 3552364, 3556524, 3576461, 3586349, 3588141, 3590797, 3596333, 3622062, 3625454, 3627054, 3675728, 3749042, 3771059, 3771571, 3776211, 3782323, 3782963, 3784883, 3785395, 3788979, 3815476, 3839605, 3885110, 3917911, 3948984, 3951096, 135304769, 135858241, 136498210, 136906434, 137138658, 137512995, 137531875, 137548067, 137629283, 137645539, 137646563, 137775779, 138529956, 138615076, 139040932, 140954086, 141179366, 141690439, 142738600, 143013512, 146979116, 147175724, 147475756, 147902637, 147936877, 148017645, 148131885, 148228141, 148229165, 148309165, 148317229, 148395629, 148551853, 148618829, 149076462, 149490158, 149572782, 151277616, 151639440, 153268914, 153486514, 153563314, 153750706, 153763314, 153914034, 154406067, 154417459, 154600979, 154678323, 154680979, 154866835, 155366708, 155375188, 155391572, 155465780, 155869364, 158045494, 168988979, 169321621, 169652752, 173151309, 174240818, 174247297, 174669292, 175391532, 176638123, 177380397, 177879204, 177886734, 180753473, 181020073, 181503558, 181686320, 181999237, 181999311, 182048201, 182074866, 182078003, 182083764, 182920847, 184716457, 184976961, 185145071, 187281445, 187872052, 188100653, 188875944, 188919873, 188920457, 189107250, 189203987, 189371817, 189414886, 189567458, 190266670, 191318187, 191337609, 202479203, 202493027, 202835587, 202843747, 203013219, 203036048, 203045987, 203177552, 203898516, 204648562, 205067918, 205078130, 205096654, 205689142, 205690439, 205988909, 207213161, 207794484, 207800999, 208023602, 208213644, 208213647, 210261490, 210310273, 210940978, 213325049, 213946445, 214055079, 215125040, 215134273, 215135028, 215237420, 215418148, 215553166, 215553394, 215563858, 215627949, 215754324, 217529652, 217713834, 217732628, 218731945, 221417045, 221424946, 221493746, 221515401, 221658189, 221908140, 221910626, 221921586, 222659762, 225001091, 236105833, 236113965, 236194995, 236195427, 236206132, 236206387, 236211683, 236212707, 236381647, 236571826, 237124271, 238172205, 238210544, 238270764, 238435405, 238501172, 239224867, 239257644, 239710497, 240307721, 241208789, 241241557, 241318060, 241319404, 241343533, 241344069, 241405397, 241765845, 243864964, 244502085, 244946220, 245109902, 247647266, 247707956, 248648814, 248648836, 248682161, 248986932, 249058914, 249697357, 252132601, 252135604, 252317348, 255007012, 255278388, 255641645, 256365156, 257566121, 269763372, 271202790, 271863856, 272049197, 272127474, 274339449, 274939471, 275388004, 275388005, 275388006, 275977800, 278267602, 278513831, 278712622, 281613765, 281683369, 282120228, 282250732, 282498697, 282508942, 283743649, 283787570, 284710386, 285391148, 285478533, 285854898, 285873762, 286931113, 288964227, 289445441, 289591340, 289689648, 291671489, 303512884, 305319975, 305610036, 305764101, 308448294, 308675890, 312085683, 312264750, 315032867, 316391000, 317331042, 317902135, 318950711, 319447220, 321499182, 322538804, 323145200, 337067316, 337826293, 339905989, 340833697, 341457068, 342310196, 345302593, 349554733, 349771471, 349786245, 350819405, 356072847, 370349192, 373962798, 375558638, 375574835, 376053993, 383276530, 383373833, 383407586, 384439906, 386079012, 404133513, 404307343, 407031852, 408072233, 409112005, 409608425, 409771500, 419040932, 437730612, 439529766, 442616365, 442813037, 443157674, 443295316, 450118444, 450482697, 456789668, 459935396, 471217869, 474073645, 476230702, 476665218, 476717289, 483014825, 485083298, 489306281, 538364390, 540675748, 543819186, 543958612, 576960820, 577242548, 610515252, 642202932, 644420819 };
+staticJArray<int32_t,int32_t> nsHtml5ElementName::ELEMENT_HASHES = { ELEMENT_HASHES_DATA, MOZ_ARRAY_LENGTH(ELEMENT_HASHES_DATA) };
 void
 nsHtml5ElementName::initializeStatics()
 {
   ELT_NULL_ELEMENT_NAME = new nsHtml5ElementName(nullptr);
   ELT_A = new nsHtml5ElementName(nsHtml5Atoms::a, nsHtml5Atoms::a, NS_HTML5TREE_BUILDER_A);
   ELT_B = new nsHtml5ElementName(nsHtml5Atoms::b, nsHtml5Atoms::b, NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U);
   ELT_G = new nsHtml5ElementName(nsHtml5Atoms::g, nsHtml5Atoms::g, NS_HTML5TREE_BUILDER_OTHER);
   ELT_I = new nsHtml5ElementName(nsHtml5Atoms::i, nsHtml5Atoms::i, NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U);
@@ -846,16 +847,17 @@ nsHtml5ElementName::initializeStatics()
   ELT_OPTGROUP = new nsHtml5ElementName(nsHtml5Atoms::optgroup, nsHtml5Atoms::optgroup, NS_HTML5TREE_BUILDER_OPTGROUP | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG);
   ELT_POLYLINE = new nsHtml5ElementName(nsHtml5Atoms::polyline, nsHtml5Atoms::polyline, NS_HTML5TREE_BUILDER_OTHER);
   ELT_PREFETCH = new nsHtml5ElementName(nsHtml5Atoms::prefetch, nsHtml5Atoms::prefetch, NS_HTML5TREE_BUILDER_OTHER);
   ELT_PROGRESS = new nsHtml5ElementName(nsHtml5Atoms::progress, nsHtml5Atoms::progress, NS_HTML5TREE_BUILDER_OTHER);
   ELT_PRSUBSET = new nsHtml5ElementName(nsHtml5Atoms::prsubset, nsHtml5Atoms::prsubset, NS_HTML5TREE_BUILDER_OTHER);
   ELT_QUOTIENT = new nsHtml5ElementName(nsHtml5Atoms::quotient, nsHtml5Atoms::quotient, NS_HTML5TREE_BUILDER_OTHER);
   ELT_SELECTOR = new nsHtml5ElementName(nsHtml5Atoms::selector, nsHtml5Atoms::selector, NS_HTML5TREE_BUILDER_OTHER);
   ELT_TEXTAREA = new nsHtml5ElementName(nsHtml5Atoms::textarea, nsHtml5Atoms::textarea, NS_HTML5TREE_BUILDER_TEXTAREA | NS_HTML5ELEMENT_NAME_SPECIAL);
+  ELT_TEMPLATE = new nsHtml5ElementName(nsHtml5Atoms::template_, nsHtml5Atoms::template_, NS_HTML5TREE_BUILDER_TEMPLATE | NS_HTML5ELEMENT_NAME_SPECIAL);
   ELT_TEXTPATH = new nsHtml5ElementName(nsHtml5Atoms::textpath, nsHtml5Atoms::textPath, NS_HTML5TREE_BUILDER_OTHER);
   ELT_VARIANCE = new nsHtml5ElementName(nsHtml5Atoms::variance, nsHtml5Atoms::variance, NS_HTML5TREE_BUILDER_OTHER);
   ELT_ANIMATION = new nsHtml5ElementName(nsHtml5Atoms::animation, nsHtml5Atoms::animation, NS_HTML5TREE_BUILDER_OTHER);
   ELT_CONJUGATE = new nsHtml5ElementName(nsHtml5Atoms::conjugate, nsHtml5Atoms::conjugate, NS_HTML5TREE_BUILDER_OTHER);
   ELT_CONDITION = new nsHtml5ElementName(nsHtml5Atoms::condition, nsHtml5Atoms::condition, NS_HTML5TREE_BUILDER_OTHER);
   ELT_COMPLEXES = new nsHtml5ElementName(nsHtml5Atoms::complexes, nsHtml5Atoms::complexes, NS_HTML5TREE_BUILDER_OTHER);
   ELT_FONT_FACE = new nsHtml5ElementName(nsHtml5Atoms::font_face, nsHtml5Atoms::font_face, NS_HTML5TREE_BUILDER_OTHER);
   ELT_FACTORIAL = new nsHtml5ElementName(nsHtml5Atoms::factorial, nsHtml5Atoms::factorial, NS_HTML5TREE_BUILDER_OTHER);
@@ -922,17 +924,17 @@ nsHtml5ElementName::initializeStatics()
   ELT_CARTESIANPRODUCT = new nsHtml5ElementName(nsHtml5Atoms::cartesianproduct, nsHtml5Atoms::cartesianproduct, NS_HTML5TREE_BUILDER_OTHER);
   ELT_FONT_FACE_FORMAT = new nsHtml5ElementName(nsHtml5Atoms::font_face_format, nsHtml5Atoms::font_face_format, NS_HTML5TREE_BUILDER_OTHER);
   ELT_FECONVOLVEMATRIX = new nsHtml5ElementName(nsHtml5Atoms::feconvolvematrix, nsHtml5Atoms::feConvolveMatrix, NS_HTML5TREE_BUILDER_OTHER);
   ELT_FEDIFFUSELIGHTING = new nsHtml5ElementName(nsHtml5Atoms::fediffuselighting, nsHtml5Atoms::feDiffuseLighting, NS_HTML5TREE_BUILDER_OTHER);
   ELT_FEDISPLACEMENTMAP = new nsHtml5ElementName(nsHtml5Atoms::fedisplacementmap, nsHtml5Atoms::feDisplacementMap, NS_HTML5TREE_BUILDER_OTHER);
   ELT_FESPECULARLIGHTING = new nsHtml5ElementName(nsHtml5Atoms::fespecularlighting, nsHtml5Atoms::feSpecularLighting, NS_HTML5TREE_BUILDER_OTHER);
   ELT_DOMAINOFAPPLICATION = new nsHtml5ElementName(nsHtml5Atoms::domainofapplication, nsHtml5Atoms::domainofapplication, NS_HTML5TREE_BUILDER_OTHER);
   ELT_FECOMPONENTTRANSFER = new nsHtml5ElementName(nsHtml5Atoms::fecomponenttransfer, nsHtml5Atoms::feComponentTransfer, NS_HTML5TREE_BUILDER_OTHER);
-  ELEMENT_NAMES = new nsHtml5ElementName*[393];
+  ELEMENT_NAMES = new nsHtml5ElementName*[394];
   ELEMENT_NAMES[0] = ELT_A;
   ELEMENT_NAMES[1] = ELT_B;
   ELEMENT_NAMES[2] = ELT_G;
   ELEMENT_NAMES[3] = ELT_I;
   ELEMENT_NAMES[4] = ELT_P;
   ELEMENT_NAMES[5] = ELT_Q;
   ELEMENT_NAMES[6] = ELT_S;
   ELEMENT_NAMES[7] = ELT_U;
@@ -1240,92 +1242,93 @@ nsHtml5ElementName::initializeStatics()
   ELEMENT_NAMES[309] = ELT_OPTGROUP;
   ELEMENT_NAMES[310] = ELT_POLYLINE;
   ELEMENT_NAMES[311] = ELT_PREFETCH;
   ELEMENT_NAMES[312] = ELT_PROGRESS;
   ELEMENT_NAMES[313] = ELT_PRSUBSET;
   ELEMENT_NAMES[314] = ELT_QUOTIENT;
   ELEMENT_NAMES[315] = ELT_SELECTOR;
   ELEMENT_NAMES[316] = ELT_TEXTAREA;
-  ELEMENT_NAMES[317] = ELT_TEXTPATH;
-  ELEMENT_NAMES[318] = ELT_VARIANCE;
-  ELEMENT_NAMES[319] = ELT_ANIMATION;
-  ELEMENT_NAMES[320] = ELT_CONJUGATE;
-  ELEMENT_NAMES[321] = ELT_CONDITION;
-  ELEMENT_NAMES[322] = ELT_COMPLEXES;
-  ELEMENT_NAMES[323] = ELT_FONT_FACE;
-  ELEMENT_NAMES[324] = ELT_FACTORIAL;
-  ELEMENT_NAMES[325] = ELT_INTERSECT;
-  ELEMENT_NAMES[326] = ELT_IMAGINARY;
-  ELEMENT_NAMES[327] = ELT_LAPLACIAN;
-  ELEMENT_NAMES[328] = ELT_MATRIXROW;
-  ELEMENT_NAMES[329] = ELT_NOTSUBSET;
-  ELEMENT_NAMES[330] = ELT_OTHERWISE;
-  ELEMENT_NAMES[331] = ELT_PIECEWISE;
-  ELEMENT_NAMES[332] = ELT_PLAINTEXT;
-  ELEMENT_NAMES[333] = ELT_RATIONALS;
-  ELEMENT_NAMES[334] = ELT_SEMANTICS;
-  ELEMENT_NAMES[335] = ELT_TRANSPOSE;
-  ELEMENT_NAMES[336] = ELT_ANNOTATION;
-  ELEMENT_NAMES[337] = ELT_BLOCKQUOTE;
-  ELEMENT_NAMES[338] = ELT_DIVERGENCE;
-  ELEMENT_NAMES[339] = ELT_EULERGAMMA;
-  ELEMENT_NAMES[340] = ELT_EQUIVALENT;
-  ELEMENT_NAMES[341] = ELT_FIGCAPTION;
-  ELEMENT_NAMES[342] = ELT_IMAGINARYI;
-  ELEMENT_NAMES[343] = ELT_MALIGNMARK;
-  ELEMENT_NAMES[344] = ELT_MUNDEROVER;
-  ELEMENT_NAMES[345] = ELT_MLABELEDTR;
-  ELEMENT_NAMES[346] = ELT_NOTANUMBER;
-  ELEMENT_NAMES[347] = ELT_SOLIDCOLOR;
-  ELEMENT_NAMES[348] = ELT_ALTGLYPHDEF;
-  ELEMENT_NAMES[349] = ELT_DETERMINANT;
-  ELEMENT_NAMES[350] = ELT_FEMERGENODE;
-  ELEMENT_NAMES[351] = ELT_FECOMPOSITE;
-  ELEMENT_NAMES[352] = ELT_FESPOTLIGHT;
-  ELEMENT_NAMES[353] = ELT_MALIGNGROUP;
-  ELEMENT_NAMES[354] = ELT_MPRESCRIPTS;
-  ELEMENT_NAMES[355] = ELT_MOMENTABOUT;
-  ELEMENT_NAMES[356] = ELT_NOTPRSUBSET;
-  ELEMENT_NAMES[357] = ELT_PARTIALDIFF;
-  ELEMENT_NAMES[358] = ELT_ALTGLYPHITEM;
-  ELEMENT_NAMES[359] = ELT_ANIMATECOLOR;
-  ELEMENT_NAMES[360] = ELT_DATATEMPLATE;
-  ELEMENT_NAMES[361] = ELT_EXPONENTIALE;
-  ELEMENT_NAMES[362] = ELT_FETURBULENCE;
-  ELEMENT_NAMES[363] = ELT_FEPOINTLIGHT;
-  ELEMENT_NAMES[364] = ELT_FEMORPHOLOGY;
-  ELEMENT_NAMES[365] = ELT_OUTERPRODUCT;
-  ELEMENT_NAMES[366] = ELT_ANIMATEMOTION;
-  ELEMENT_NAMES[367] = ELT_COLOR_PROFILE;
-  ELEMENT_NAMES[368] = ELT_FONT_FACE_SRC;
-  ELEMENT_NAMES[369] = ELT_FONT_FACE_URI;
-  ELEMENT_NAMES[370] = ELT_FOREIGNOBJECT;
-  ELEMENT_NAMES[371] = ELT_FECOLORMATRIX;
-  ELEMENT_NAMES[372] = ELT_MISSING_GLYPH;
-  ELEMENT_NAMES[373] = ELT_MMULTISCRIPTS;
-  ELEMENT_NAMES[374] = ELT_SCALARPRODUCT;
-  ELEMENT_NAMES[375] = ELT_VECTORPRODUCT;
-  ELEMENT_NAMES[376] = ELT_ANNOTATION_XML;
-  ELEMENT_NAMES[377] = ELT_DEFINITION_SRC;
-  ELEMENT_NAMES[378] = ELT_FONT_FACE_NAME;
-  ELEMENT_NAMES[379] = ELT_FEGAUSSIANBLUR;
-  ELEMENT_NAMES[380] = ELT_FEDISTANTLIGHT;
-  ELEMENT_NAMES[381] = ELT_LINEARGRADIENT;
-  ELEMENT_NAMES[382] = ELT_NATURALNUMBERS;
-  ELEMENT_NAMES[383] = ELT_RADIALGRADIENT;
-  ELEMENT_NAMES[384] = ELT_ANIMATETRANSFORM;
-  ELEMENT_NAMES[385] = ELT_CARTESIANPRODUCT;
-  ELEMENT_NAMES[386] = ELT_FONT_FACE_FORMAT;
-  ELEMENT_NAMES[387] = ELT_FECONVOLVEMATRIX;
-  ELEMENT_NAMES[388] = ELT_FEDIFFUSELIGHTING;
-  ELEMENT_NAMES[389] = ELT_FEDISPLACEMENTMAP;
-  ELEMENT_NAMES[390] = ELT_FESPECULARLIGHTING;
-  ELEMENT_NAMES[391] = ELT_DOMAINOFAPPLICATION;
-  ELEMENT_NAMES[392] = ELT_FECOMPONENTTRANSFER;
+  ELEMENT_NAMES[317] = ELT_TEMPLATE;
+  ELEMENT_NAMES[318] = ELT_TEXTPATH;
+  ELEMENT_NAMES[319] = ELT_VARIANCE;
+  ELEMENT_NAMES[320] = ELT_ANIMATION;
+  ELEMENT_NAMES[321] = ELT_CONJUGATE;
+  ELEMENT_NAMES[322] = ELT_CONDITION;
+  ELEMENT_NAMES[323] = ELT_COMPLEXES;
+  ELEMENT_NAMES[324] = ELT_FONT_FACE;
+  ELEMENT_NAMES[325] = ELT_FACTORIAL;
+  ELEMENT_NAMES[326] = ELT_INTERSECT;
+  ELEMENT_NAMES[327] = ELT_IMAGINARY;
+  ELEMENT_NAMES[328] = ELT_LAPLACIAN;
+  ELEMENT_NAMES[329] = ELT_MATRIXROW;
+  ELEMENT_NAMES[330] = ELT_NOTSUBSET;
+  ELEMENT_NAMES[331] = ELT_OTHERWISE;
+  ELEMENT_NAMES[332] = ELT_PIECEWISE;
+  ELEMENT_NAMES[333] = ELT_PLAINTEXT;
+  ELEMENT_NAMES[334] = ELT_RATIONALS;
+  ELEMENT_NAMES[335] = ELT_SEMANTICS;
+  ELEMENT_NAMES[336] = ELT_TRANSPOSE;
+  ELEMENT_NAMES[337] = ELT_ANNOTATION;
+  ELEMENT_NAMES[338] = ELT_BLOCKQUOTE;
+  ELEMENT_NAMES[339] = ELT_DIVERGENCE;
+  ELEMENT_NAMES[340] = ELT_EULERGAMMA;
+  ELEMENT_NAMES[341] = ELT_EQUIVALENT;
+  ELEMENT_NAMES[342] = ELT_FIGCAPTION;
+  ELEMENT_NAMES[343] = ELT_IMAGINARYI;
+  ELEMENT_NAMES[344] = ELT_MALIGNMARK;
+  ELEMENT_NAMES[345] = ELT_MUNDEROVER;
+  ELEMENT_NAMES[346] = ELT_MLABELEDTR;
+  ELEMENT_NAMES[347] = ELT_NOTANUMBER;
+  ELEMENT_NAMES[348] = ELT_SOLIDCOLOR;
+  ELEMENT_NAMES[349] = ELT_ALTGLYPHDEF;
+  ELEMENT_NAMES[350] = ELT_DETERMINANT;
+  ELEMENT_NAMES[351] = ELT_FEMERGENODE;
+  ELEMENT_NAMES[352] = ELT_FECOMPOSITE;
+  ELEMENT_NAMES[353] = ELT_FESPOTLIGHT;
+  ELEMENT_NAMES[354] = ELT_MALIGNGROUP;
+  ELEMENT_NAMES[355] = ELT_MPRESCRIPTS;
+  ELEMENT_NAMES[356] = ELT_MOMENTABOUT;
+  ELEMENT_NAMES[357] = ELT_NOTPRSUBSET;
+  ELEMENT_NAMES[358] = ELT_PARTIALDIFF;
+  ELEMENT_NAMES[359] = ELT_ALTGLYPHITEM;
+  ELEMENT_NAMES[360] = ELT_ANIMATECOLOR;
+  ELEMENT_NAMES[361] = ELT_DATATEMPLATE;
+  ELEMENT_NAMES[362] = ELT_EXPONENTIALE;
+  ELEMENT_NAMES[363] = ELT_FETURBULENCE;
+  ELEMENT_NAMES[364] = ELT_FEPOINTLIGHT;
+  ELEMENT_NAMES[365] = ELT_FEMORPHOLOGY;
+  ELEMENT_NAMES[366] = ELT_OUTERPRODUCT;
+  ELEMENT_NAMES[367] = ELT_ANIMATEMOTION;
+  ELEMENT_NAMES[368] = ELT_COLOR_PROFILE;
+  ELEMENT_NAMES[369] = ELT_FONT_FACE_SRC;
+  ELEMENT_NAMES[370] = ELT_FONT_FACE_URI;
+  ELEMENT_NAMES[371] = ELT_FOREIGNOBJECT;
+  ELEMENT_NAMES[372] = ELT_FECOLORMATRIX;
+  ELEMENT_NAMES[373] = ELT_MISSING_GLYPH;
+  ELEMENT_NAMES[374] = ELT_MMULTISCRIPTS;
+  ELEMENT_NAMES[375] = ELT_SCALARPRODUCT;
+  ELEMENT_NAMES[376] = ELT_VECTORPRODUCT;
+  ELEMENT_NAMES[377] = ELT_ANNOTATION_XML;
+  ELEMENT_NAMES[378] = ELT_DEFINITION_SRC;
+  ELEMENT_NAMES[379] = ELT_FONT_FACE_NAME;
+  ELEMENT_NAMES[380] = ELT_FEGAUSSIANBLUR;
+  ELEMENT_NAMES[381] = ELT_FEDISTANTLIGHT;
+  ELEMENT_NAMES[382] = ELT_LINEARGRADIENT;
+  ELEMENT_NAMES[383] = ELT_NATURALNUMBERS;
+  ELEMENT_NAMES[384] = ELT_RADIALGRADIENT;
+  ELEMENT_NAMES[385] = ELT_ANIMATETRANSFORM;
+  ELEMENT_NAMES[386] = ELT_CARTESIANPRODUCT;
+  ELEMENT_NAMES[387] = ELT_FONT_FACE_FORMAT;
+  ELEMENT_NAMES[388] = ELT_FECONVOLVEMATRIX;
+  ELEMENT_NAMES[389] = ELT_FEDIFFUSELIGHTING;
+  ELEMENT_NAMES[390] = ELT_FEDISPLACEMENTMAP;
+  ELEMENT_NAMES[391] = ELT_FESPECULARLIGHTING;
+  ELEMENT_NAMES[392] = ELT_DOMAINOFAPPLICATION;
+  ELEMENT_NAMES[393] = ELT_FECOMPONENTTRANSFER;
 }
 
 void
 nsHtml5ElementName::releaseStatics()
 {
   delete ELT_NULL_ELEMENT_NAME;
   delete ELT_A;
   delete ELT_B;
@@ -1639,16 +1642,17 @@ nsHtml5ElementName::releaseStatics()
   delete ELT_OPTGROUP;
   delete ELT_POLYLINE;
   delete ELT_PREFETCH;
   delete ELT_PROGRESS;
   delete ELT_PRSUBSET;
   delete ELT_QUOTIENT;
   delete ELT_SELECTOR;
   delete ELT_TEXTAREA;
+  delete ELT_TEMPLATE;
   delete ELT_TEXTPATH;
   delete ELT_VARIANCE;
   delete ELT_ANIMATION;
   delete ELT_CONJUGATE;
   delete ELT_CONDITION;
   delete ELT_COMPLEXES;
   delete ELT_FONT_FACE;
   delete ELT_FACTORIAL;
--- a/parser/html/nsHtml5ElementName.h
+++ b/parser/html/nsHtml5ElementName.h
@@ -390,16 +390,17 @@ class nsHtml5ElementName
     static nsHtml5ElementName* ELT_OPTGROUP;
     static nsHtml5ElementName* ELT_POLYLINE;
     static nsHtml5ElementName* ELT_PREFETCH;
     static nsHtml5ElementName* ELT_PROGRESS;
     static nsHtml5ElementName* ELT_PRSUBSET;
     static nsHtml5ElementName* ELT_QUOTIENT;
     static nsHtml5ElementName* ELT_SELECTOR;
     static nsHtml5ElementName* ELT_TEXTAREA;
+    static nsHtml5ElementName* ELT_TEMPLATE;
     static nsHtml5ElementName* ELT_TEXTPATH;
     static nsHtml5ElementName* ELT_VARIANCE;
     static nsHtml5ElementName* ELT_ANIMATION;
     static nsHtml5ElementName* ELT_CONJUGATE;
     static nsHtml5ElementName* ELT_CONDITION;
     static nsHtml5ElementName* ELT_COMPLEXES;
     static nsHtml5ElementName* ELT_FONT_FACE;
     static nsHtml5ElementName* ELT_FACTORIAL;
--- a/parser/html/nsHtml5MetaScanner.cpp
+++ b/parser/html/nsHtml5MetaScanner.cpp
@@ -50,23 +50,23 @@
 #include "nsHtml5StackNode.h"
 #include "nsHtml5UTF16Buffer.h"
 #include "nsHtml5StateSnapshot.h"
 #include "nsHtml5Portability.h"
 
 #include "nsHtml5MetaScanner.h"
 
 static PRUnichar const CHARSET_DATA[] = { 'h', 'a', 'r', 's', 'e', 't' };
-staticJArray<PRUnichar,int32_t> nsHtml5MetaScanner::CHARSET = { CHARSET_DATA, NS_ARRAY_LENGTH(CHARSET_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5MetaScanner::CHARSET = { CHARSET_DATA, MOZ_ARRAY_LENGTH(CHARSET_DATA) };
 static PRUnichar const CONTENT_DATA[] = { 'o', 'n', 't', 'e', 'n', 't' };
-staticJArray<PRUnichar,int32_t> nsHtml5MetaScanner::CONTENT = { CONTENT_DATA, NS_ARRAY_LENGTH(CONTENT_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5MetaScanner::CONTENT = { CONTENT_DATA, MOZ_ARRAY_LENGTH(CONTENT_DATA) };
 static PRUnichar const HTTP_EQUIV_DATA[] = { 't', 't', 'p', '-', 'e', 'q', 'u', 'i', 'v' };
-staticJArray<PRUnichar,int32_t> nsHtml5MetaScanner::HTTP_EQUIV = { HTTP_EQUIV_DATA, NS_ARRAY_LENGTH(HTTP_EQUIV_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5MetaScanner::HTTP_EQUIV = { HTTP_EQUIV_DATA, MOZ_ARRAY_LENGTH(HTTP_EQUIV_DATA) };
 static PRUnichar const CONTENT_TYPE_DATA[] = { 'c', 'o', 'n', 't', 'e', 'n', 't', '-', 't', 'y', 'p', 'e' };
-staticJArray<PRUnichar,int32_t> nsHtml5MetaScanner::CONTENT_TYPE = { CONTENT_TYPE_DATA, NS_ARRAY_LENGTH(CONTENT_TYPE_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5MetaScanner::CONTENT_TYPE = { CONTENT_TYPE_DATA, MOZ_ARRAY_LENGTH(CONTENT_TYPE_DATA) };
 
 nsHtml5MetaScanner::nsHtml5MetaScanner()
   : readable(nullptr),
     metaState(NS_HTML5META_SCANNER_NO),
     contentIndex(INT32_MAX),
     charsetIndex(INT32_MAX),
     httpEquivIndex(INT32_MAX),
     contentTypeIndex(INT32_MAX),
--- a/parser/html/nsHtml5Tokenizer.cpp
+++ b/parser/html/nsHtml5Tokenizer.cpp
@@ -63,35 +63,35 @@ PRUnichar nsHtml5Tokenizer::LT_SOLIDUS[]
 PRUnichar nsHtml5Tokenizer::RSQB_RSQB[] = { ']', ']' };
 PRUnichar nsHtml5Tokenizer::REPLACEMENT_CHARACTER[] = { 0xfffd };
 PRUnichar nsHtml5Tokenizer::LF[] = { '\n' };
 PRUnichar nsHtml5Tokenizer::CDATA_LSQB[] = { 'C', 'D', 'A', 'T', 'A', '[' };
 PRUnichar nsHtml5Tokenizer::OCTYPE[] = { 'o', 'c', 't', 'y', 'p', 'e' };
 PRUnichar nsHtml5Tokenizer::UBLIC[] = { 'u', 'b', 'l', 'i', 'c' };
 PRUnichar nsHtml5Tokenizer::YSTEM[] = { 'y', 's', 't', 'e', 'm' };
 static PRUnichar const TITLE_ARR_DATA[] = { 't', 'i', 't', 'l', 'e' };
-staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::TITLE_ARR = { TITLE_ARR_DATA, NS_ARRAY_LENGTH(TITLE_ARR_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::TITLE_ARR = { TITLE_ARR_DATA, MOZ_ARRAY_LENGTH(TITLE_ARR_DATA) };
 static PRUnichar const SCRIPT_ARR_DATA[] = { 's', 'c', 'r', 'i', 'p', 't' };
-staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::SCRIPT_ARR = { SCRIPT_ARR_DATA, NS_ARRAY_LENGTH(SCRIPT_ARR_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::SCRIPT_ARR = { SCRIPT_ARR_DATA, MOZ_ARRAY_LENGTH(SCRIPT_ARR_DATA) };
 static PRUnichar const STYLE_ARR_DATA[] = { 's', 't', 'y', 'l', 'e' };
-staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::STYLE_ARR = { STYLE_ARR_DATA, NS_ARRAY_LENGTH(STYLE_ARR_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::STYLE_ARR = { STYLE_ARR_DATA, MOZ_ARRAY_LENGTH(STYLE_ARR_DATA) };
 static PRUnichar const PLAINTEXT_ARR_DATA[] = { 'p', 'l', 'a', 'i', 'n', 't', 'e', 'x', 't' };
-staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::PLAINTEXT_ARR = { PLAINTEXT_ARR_DATA, NS_ARRAY_LENGTH(PLAINTEXT_ARR_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::PLAINTEXT_ARR = { PLAINTEXT_ARR_DATA, MOZ_ARRAY_LENGTH(PLAINTEXT_ARR_DATA) };
 static PRUnichar const XMP_ARR_DATA[] = { 'x', 'm', 'p' };
-staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::XMP_ARR = { XMP_ARR_DATA, NS_ARRAY_LENGTH(XMP_ARR_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::XMP_ARR = { XMP_ARR_DATA, MOZ_ARRAY_LENGTH(XMP_ARR_DATA) };
 static PRUnichar const TEXTAREA_ARR_DATA[] = { 't', 'e', 'x', 't', 'a', 'r', 'e', 'a' };
-staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::TEXTAREA_ARR = { TEXTAREA_ARR_DATA, NS_ARRAY_LENGTH(TEXTAREA_ARR_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::TEXTAREA_ARR = { TEXTAREA_ARR_DATA, MOZ_ARRAY_LENGTH(TEXTAREA_ARR_DATA) };
 static PRUnichar const IFRAME_ARR_DATA[] = { 'i', 'f', 'r', 'a', 'm', 'e' };
-staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::IFRAME_ARR = { IFRAME_ARR_DATA, NS_ARRAY_LENGTH(IFRAME_ARR_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::IFRAME_ARR = { IFRAME_ARR_DATA, MOZ_ARRAY_LENGTH(IFRAME_ARR_DATA) };
 static PRUnichar const NOEMBED_ARR_DATA[] = { 'n', 'o', 'e', 'm', 'b', 'e', 'd' };
-staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::NOEMBED_ARR = { NOEMBED_ARR_DATA, NS_ARRAY_LENGTH(NOEMBED_ARR_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::NOEMBED_ARR = { NOEMBED_ARR_DATA, MOZ_ARRAY_LENGTH(NOEMBED_ARR_DATA) };
 static PRUnichar const NOSCRIPT_ARR_DATA[] = { 'n', 'o', 's', 'c', 'r', 'i', 'p', 't' };
-staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::NOSCRIPT_ARR = { NOSCRIPT_ARR_DATA, NS_ARRAY_LENGTH(NOSCRIPT_ARR_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::NOSCRIPT_ARR = { NOSCRIPT_ARR_DATA, MOZ_ARRAY_LENGTH(NOSCRIPT_ARR_DATA) };
 static PRUnichar const NOFRAMES_ARR_DATA[] = { 'n', 'o', 'f', 'r', 'a', 'm', 'e', 's' };
-staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::NOFRAMES_ARR = { NOFRAMES_ARR_DATA, NS_ARRAY_LENGTH(NOFRAMES_ARR_DATA) };
+staticJArray<PRUnichar,int32_t> nsHtml5Tokenizer::NOFRAMES_ARR = { NOFRAMES_ARR_DATA, MOZ_ARRAY_LENGTH(NOFRAMES_ARR_DATA) };
 
 nsHtml5Tokenizer::nsHtml5Tokenizer(nsHtml5TreeBuilder* tokenHandler, bool viewingXmlSource)
   : tokenHandler(tokenHandler),
     encodingDeclarationHandler(nullptr),
     bmpChar(jArray<PRUnichar,int32_t>::newJArray(1)),
     astralChar(jArray<PRUnichar,int32_t>::newJArray(2)),
     tagName(nullptr),
     attributeName(nullptr),
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -1,30 +1,30 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
  * Copyright (c) 2007-2011 Mozilla Foundation
- * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla 
+ * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
  * Foundation, and Opera Software ASA.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a 
- * copy of this software and associated documentation files (the "Software"), 
- * to deal in the Software without restriction, including without limitation 
- * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
- * and/or sell copies of the Software, and to permit persons to whom the 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
  * Software is furnished to do so, subject to the following conditions:
  *
- * The above copyright notice and this permission notice shall be included in 
+ * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit TreeBuilder.java instead and regenerate.
  */
 
@@ -45,16 +45,17 @@
 #include "nsHtml5TreeOperation.h"
 #include "nsHtml5PendingNotification.h"
 #include "nsHtml5StateSnapshot.h"
 #include "nsHtml5StackNode.h"
 #include "nsHtml5TreeOpExecutor.h"
 #include "nsHtml5StreamParser.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Highlighter.h"
+#include "nsHtml5PlainTextUtils.h"
 #include "nsHtml5ViewSourceUtils.h"
 #include "mozilla/Likely.h"
 
 #include "nsHtml5Tokenizer.h"
 #include "nsHtml5MetaScanner.h"
 #include "nsHtml5AttributeName.h"
 #include "nsHtml5ElementName.h"
 #include "nsHtml5HtmlAttributes.h"
@@ -62,25 +63,27 @@
 #include "nsHtml5UTF16Buffer.h"
 #include "nsHtml5StateSnapshot.h"
 #include "nsHtml5Portability.h"
 
 #include "nsHtml5TreeBuilder.h"
 
 PRUnichar nsHtml5TreeBuilder::REPLACEMENT_CHARACTER[] = { 0xfffd };
 static const char* const QUIRKY_PUBLIC_IDS_DATA[] = { "+//silmaril//dtd html pro v0r11 19970101//", "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", "-//as//dtd html 3.0 aswedit + extensions//", "-//ietf//dtd html 2.0 level 1//", "-//ietf//dtd html 2.0 level 2//", "-//ietf//dtd html 2.0 strict level 1//", "-//ietf//dtd html 2.0 strict level 2//", "-//ietf//dtd html 2.0 strict//", "-//ietf//dtd html 2.0//", "-//ietf//dtd html 2.1e//", "-//ietf//dtd html 3.0//", "-//ietf//dtd html 3.2 final//", "-//ietf//dtd html 3.2//", "-//ietf//dtd html 3//", "-//ietf//dtd html level 0//", "-//ietf//dtd html level 1//", "-//ietf//dtd html level 2//", "-//ietf//dtd html level 3//", "-//ietf//dtd html strict level 0//", "-//ietf//dtd html strict level 1//", "-//ietf//dtd html strict level 2//", "-//ietf//dtd html strict level 3//", "-//ietf//dtd html strict//", "-//ietf//dtd html//", "-//metrius//dtd metrius presentational//", "-//microsoft//dtd internet explorer 2.0 html strict//", "-//microsoft//dtd internet explorer 2.0 html//", "-//microsoft//dtd internet explorer 2.0 tables//", "-//microsoft//dtd internet explorer 3.0 html strict//", "-//microsoft//dtd internet explorer 3.0 html//", "-//microsoft//dtd internet explorer 3.0 tables//", "-//netscape comm. corp.//dtd html//", "-//netscape comm. corp.//dtd strict html//", "-//o'reilly and associates//dtd html 2.0//", "-//o'reilly and associates//dtd html extended 1.0//", "-//o'reilly and associates//dtd html extended relaxed 1.0//", "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", "-//spyglass//dtd html 2.0 extended//", "-//sq//dtd html 2.0 hotmetal + extensions//", "-//sun microsystems corp.//dtd hotjava html//", "-//sun microsystems corp.//dtd hotjava strict html//", "-//w3c//dtd html 3 1995-03-24//", "-//w3c//dtd html 3.2 draft//", "-//w3c//dtd html 3.2 final//", "-//w3c//dtd html 3.2//", "-//w3c//dtd html 3.2s draft//", "-//w3c//dtd html 4.0 frameset//", "-//w3c//dtd html 4.0 transitional//", "-//w3c//dtd html experimental 19960712//", "-//w3c//dtd html experimental 970421//", "-//w3c//dtd w3 html//", "-//w3o//dtd w3 html 3.0//", "-//webtechs//dtd mozilla html 2.0//", "-//webtechs//dtd mozilla html//" };
-staticJArray<const char*,int32_t> nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = { QUIRKY_PUBLIC_IDS_DATA, NS_ARRAY_LENGTH(QUIRKY_PUBLIC_IDS_DATA) };
+staticJArray<const char*,int32_t> nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = { QUIRKY_PUBLIC_IDS_DATA, MOZ_ARRAY_LENGTH(QUIRKY_PUBLIC_IDS_DATA) };
 void 
 nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self)
 {
   tokenizer = self;
   stack = jArray<nsHtml5StackNode*,int32_t>::newJArray(64);
+  templateModeStack = jArray<int32_t,int32_t>::newJArray(64);
   listOfActiveFormattingElements = jArray<nsHtml5StackNode*,int32_t>::newJArray(64);
   needToDropLF = false;
   originalMode = NS_HTML5TREE_BUILDER_INITIAL;
+  templateModePtr = -1;
   currentPtr = -1;
   listPtr = -1;
   formPointer = nullptr;
   headPointer = nullptr;
   deepTreeSurrogateParent = nullptr;
   start(fragment);
   charBufferLen = 0;
   charBuffer = jArray<PRUnichar,int32_t>::newJArray(1024);
@@ -90,16 +93,19 @@ nsHtml5TreeBuilder::startTokenization(ns
     if (contextNode) {
       elt = contextNode;
     } else {
       elt = createHtmlElementSetAsRoot(tokenizer->emptyAttributes());
     }
     nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_HTML, elt);
     currentPtr++;
     stack[currentPtr] = node;
+    if (nsHtml5Atoms::template_ == contextName) {
+      pushTemplateMode(NS_HTML5TREE_BUILDER_TEMPLATE_CONTENTS);
+    }
     resetTheInsertionMode();
     if (nsHtml5Atoms::title == contextName || nsHtml5Atoms::textarea == contextName) {
       tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RCDATA, contextName);
     } else if (nsHtml5Atoms::style == contextName || nsHtml5Atoms::xmp == contextName || nsHtml5Atoms::iframe == contextName || nsHtml5Atoms::noembed == contextName || nsHtml5Atoms::noframes == contextName || (scriptingEnabled && nsHtml5Atoms::noscript == contextName)) {
       tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, contextName);
     } else if (nsHtml5Atoms::plaintext == contextName) {
       tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_PLAINTEXT, contextName);
     } else if (nsHtml5Atoms::script == contextName) {
@@ -226,16 +232,17 @@ nsHtml5TreeBuilder::characters(const PRU
               case NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT:
               case NS_HTML5TREE_BUILDER_AFTER_HEAD:
               case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP:
               case NS_HTML5TREE_BUILDER_IN_FRAMESET:
               case NS_HTML5TREE_BUILDER_AFTER_FRAMESET: {
                 continue;
               }
               case NS_HTML5TREE_BUILDER_FRAMESET_OK:
+              case NS_HTML5TREE_BUILDER_TEMPLATE_CONTENTS:
               case NS_HTML5TREE_BUILDER_IN_BODY:
               case NS_HTML5TREE_BUILDER_IN_CELL:
               case NS_HTML5TREE_BUILDER_IN_CAPTION: {
                 if (start < i) {
                   accumulateCharacters(buf, start, i - start);
                   start = i;
                 }
                 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
@@ -328,16 +335,17 @@ nsHtml5TreeBuilder::characters(const PRU
                 continue;
               }
               case NS_HTML5TREE_BUILDER_FRAMESET_OK: {
                 framesetOk = false;
                 mode = NS_HTML5TREE_BUILDER_IN_BODY;
                 i--;
                 continue;
               }
+              case NS_HTML5TREE_BUILDER_TEMPLATE_CONTENTS:
               case NS_HTML5TREE_BUILDER_IN_BODY:
               case NS_HTML5TREE_BUILDER_IN_CELL:
               case NS_HTML5TREE_BUILDER_IN_CAPTION: {
                 if (start < i) {
                   accumulateCharacters(buf, start, i - start);
                   start = i;
                 }
                 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
@@ -353,17 +361,17 @@ nsHtml5TreeBuilder::characters(const PRU
                 start = i + 1;
                 continue;
               }
               case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP: {
                 if (start < i) {
                   accumulateCharacters(buf, start, i - start);
                   start = i;
                 }
-                if (!currentPtr) {
+                if (!currentPtr || stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) {
                   errNonSpaceInColgroupInFragment();
                   start = i + 1;
                   continue;
                 }
                 flushCharacters();
                 pop();
                 mode = NS_HTML5TREE_BUILDER_IN_TABLE;
                 i--;
@@ -507,16 +515,25 @@ nsHtml5TreeBuilder::eof()
       case NS_HTML5TREE_BUILDER_IN_TABLE_BODY:
       case NS_HTML5TREE_BUILDER_IN_ROW:
       case NS_HTML5TREE_BUILDER_IN_TABLE:
       case NS_HTML5TREE_BUILDER_IN_SELECT:
       case NS_HTML5TREE_BUILDER_IN_SELECT_IN_TABLE:
       case NS_HTML5TREE_BUILDER_IN_FRAMESET: {
         NS_HTML5_BREAK(eofloop);
       }
+      case NS_HTML5TREE_BUILDER_TEMPLATE_CONTENTS: {
+        if (!currentPtr) {
+          MOZ_ASSERT(fragment);
+          NS_HTML5_BREAK(eofloop);
+        }
+        popOnEof();
+        resetTheInsertionMode();
+        continue;
+      }
       case NS_HTML5TREE_BUILDER_AFTER_BODY:
       case NS_HTML5TREE_BUILDER_AFTER_FRAMESET:
       case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY:
       case NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET:
       default: {
         NS_HTML5_BREAK(eofloop);
       }
     }
@@ -531,16 +548,17 @@ nsHtml5TreeBuilder::eof()
 }
 
 void 
 nsHtml5TreeBuilder::endTokenization()
 {
   formPointer = nullptr;
   headPointer = nullptr;
   deepTreeSurrogateParent = nullptr;
+  templateModeStack = nullptr;
   if (stack) {
     while (currentPtr > -1) {
       stack[currentPtr]->release();
       currentPtr--;
     }
     stack = nullptr;
   }
   if (listOfActiveFormattingElements) {
@@ -624,16 +642,86 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
               attributes = nullptr;
               NS_HTML5_BREAK(starttagloop);
             }
           }
         }
       }
     }
     switch(mode) {
+      case NS_HTML5TREE_BUILDER_TEMPLATE_CONTENTS: {
+        switch(group) {
+          case NS_HTML5TREE_BUILDER_FRAME: {
+            popTemplateMode();
+            pushTemplateMode(NS_HTML5TREE_BUILDER_IN_FRAMESET);
+            mode = NS_HTML5TREE_BUILDER_IN_FRAMESET;
+            continue;
+          }
+          case NS_HTML5TREE_BUILDER_COL: {
+            popTemplateMode();
+            pushTemplateMode(NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP);
+            mode = NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP;
+            continue;
+          }
+          case NS_HTML5TREE_BUILDER_CAPTION:
+          case NS_HTML5TREE_BUILDER_COLGROUP:
+          case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: {
+            popTemplateMode();
+            pushTemplateMode(NS_HTML5TREE_BUILDER_IN_TABLE);
+            mode = NS_HTML5TREE_BUILDER_IN_TABLE;
+            continue;
+          }
+          case NS_HTML5TREE_BUILDER_TR: {
+            popTemplateMode();
+            pushTemplateMode(NS_HTML5TREE_BUILDER_IN_TABLE_BODY);
+            mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY;
+            continue;
+          }
+          case NS_HTML5TREE_BUILDER_TD_OR_TH: {
+            popTemplateMode();
+            pushTemplateMode(NS_HTML5TREE_BUILDER_IN_ROW);
+            mode = NS_HTML5TREE_BUILDER_IN_ROW;
+            continue;
+          }
+          case NS_HTML5TREE_BUILDER_META: {
+            checkMetaCharset(attributes);
+            appendVoidElementToCurrentMayFoster(elementName, attributes);
+            selfClosing = false;
+            attributes = nullptr;
+            NS_HTML5_BREAK(starttagloop);
+          }
+          case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND: {
+            appendVoidElementToCurrentMayFoster(elementName, attributes);
+            selfClosing = false;
+            attributes = nullptr;
+            NS_HTML5_BREAK(starttagloop);
+          }
+          case NS_HTML5TREE_BUILDER_SCRIPT: {
+            startTagScriptInHead(elementName, attributes);
+            attributes = nullptr;
+            NS_HTML5_BREAK(starttagloop);
+          }
+          case NS_HTML5TREE_BUILDER_STYLE: {
+            startTagGenericRawText(elementName, attributes);
+            attributes = nullptr;
+            NS_HTML5_BREAK(starttagloop);
+          }
+          case NS_HTML5TREE_BUILDER_TEMPLATE: {
+            startTagTemplateInHead(elementName, attributes);
+            attributes = nullptr;
+            NS_HTML5_BREAK(starttagloop);
+          }
+          default: {
+            popTemplateMode();
+            pushTemplateMode(NS_HTML5TREE_BUILDER_IN_BODY);
+            mode = NS_HTML5TREE_BUILDER_IN_BODY;
+            continue;
+          }
+        }
+      }
       case NS_HTML5TREE_BUILDER_IN_ROW: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_TD_OR_TH: {
             clearStackBackTo(findLastOrRoot(NS_HTML5TREE_BUILDER_TR));
             appendToCurrentNodeAndPushElement(elementName, attributes);
             mode = NS_HTML5TREE_BUILDER_IN_CELL;
             insertMarker();
             attributes = nullptr;
@@ -641,51 +729,52 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
           }
           case NS_HTML5TREE_BUILDER_CAPTION:
           case NS_HTML5TREE_BUILDER_COL:
           case NS_HTML5TREE_BUILDER_COLGROUP:
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT:
           case NS_HTML5TREE_BUILDER_TR: {
             eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR);
             if (!eltPos) {
-              MOZ_ASSERT(fragment);
+              MOZ_ASSERT(fragment || isTemplateContents());
               errNoTableRowToClose();
               NS_HTML5_BREAK(starttagloop);
             }
             clearStackBackTo(eltPos);
             pop();
             mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY;
             continue;
           }
           default:
             ; // fall through
         }
       }
       case NS_HTML5TREE_BUILDER_IN_TABLE_BODY: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_TR: {
-            clearStackBackTo(findLastInTableScopeOrRootTbodyTheadTfoot());
+            clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
             appendToCurrentNodeAndPushElement(elementName, attributes);
             mode = NS_HTML5TREE_BUILDER_IN_ROW;
             attributes = nullptr;
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_TD_OR_TH: {
             errStartTagInTableBody(name);
-            clearStackBackTo(findLastInTableScopeOrRootTbodyTheadTfoot());
+            clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
             appendToCurrentNodeAndPushElement(nsHtml5ElementName::ELT_TR, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
             mode = NS_HTML5TREE_BUILDER_IN_ROW;
             continue;
           }
           case NS_HTML5TREE_BUILDER_CAPTION:
           case NS_HTML5TREE_BUILDER_COL:
           case NS_HTML5TREE_BUILDER_COLGROUP:
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: {
-            eltPos = findLastInTableScopeOrRootTbodyTheadTfoot();
-            if (!eltPos) {
+            eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
+            if (!eltPos || stack[eltPos]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) {
+              MOZ_ASSERT(fragment || isTemplateContents());
               errStrayStartTag(name);
               NS_HTML5_BREAK(starttagloop);
             } else {
               clearStackBackTo(eltPos);
               pop();
               mode = NS_HTML5TREE_BUILDER_IN_TABLE;
               continue;
             }
@@ -727,21 +816,24 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             }
             case NS_HTML5TREE_BUILDER_TR:
             case NS_HTML5TREE_BUILDER_TD_OR_TH: {
               clearStackBackTo(findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE));
               appendToCurrentNodeAndPushElement(nsHtml5ElementName::ELT_TBODY, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
               mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY;
               NS_HTML5_CONTINUE(starttagloop);
             }
+            case NS_HTML5TREE_BUILDER_TEMPLATE: {
+              NS_HTML5_BREAK(intableloop);
+            }
             case NS_HTML5TREE_BUILDER_TABLE: {
               errTableSeenWhileTableOpen();
               eltPos = findLastInTableScope(name);
               if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
-                MOZ_ASSERT(fragment);
+                MOZ_ASSERT(fragment || isTemplateContents());
                 NS_HTML5_BREAK(starttagloop);
               }
               generateImpliedEndTags();
               if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsHtml5Atoms::table)) {
                 errNoCheckUnclosedElementsOnStack();
               }
               while (currentPtr >= eltPos) {
                 pop();
@@ -842,17 +934,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             ; // fall through
         }
       }
       case NS_HTML5TREE_BUILDER_FRAMESET_OK: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_FRAMESET: {
             if (mode == NS_HTML5TREE_BUILDER_FRAMESET_OK) {
               if (!currentPtr || stack[1]->getGroup() != NS_HTML5TREE_BUILDER_BODY) {
-                MOZ_ASSERT(fragment);
+                MOZ_ASSERT(fragment || isTemplateContents());
                 errStrayStartTag(name);
                 NS_HTML5_BREAK(starttagloop);
               } else {
                 errFramesetStart();
                 detachFromParent(stack[1]->node);
                 while (currentPtr > 0) {
                   pop();
                 }
@@ -892,34 +984,35 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             ; // fall through
         }
       }
       case NS_HTML5TREE_BUILDER_IN_BODY: {
         for (; ; ) {
           switch(group) {
             case NS_HTML5TREE_BUILDER_HTML: {
               errStrayStartTag(name);
-              if (!fragment) {
+              if (!fragment && !isTemplateContents()) {
                 addAttributesToHtml(attributes);
                 attributes = nullptr;
               }
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_BASE:
             case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND:
             case NS_HTML5TREE_BUILDER_META:
             case NS_HTML5TREE_BUILDER_STYLE:
             case NS_HTML5TREE_BUILDER_SCRIPT:
             case NS_HTML5TREE_BUILDER_TITLE:
-            case NS_HTML5TREE_BUILDER_COMMAND: {
+            case NS_HTML5TREE_BUILDER_COMMAND:
+            case NS_HTML5TREE_BUILDER_TEMPLATE: {
               NS_HTML5_BREAK(inbodyloop);
             }
             case NS_HTML5TREE_BUILDER_BODY: {
-              if (!currentPtr || stack[1]->getGroup() != NS_HTML5TREE_BUILDER_BODY) {
-                MOZ_ASSERT(fragment);
+              if (!currentPtr || stack[1]->getGroup() != NS_HTML5TREE_BUILDER_BODY || isTemplateContents()) {
+                MOZ_ASSERT(fragment || isTemplateContents());
                 errStrayStartTag(name);
                 NS_HTML5_BREAK(starttagloop);
               }
               errFooSeenWhenFooOpen(name);
               framesetOk = false;
               if (mode == NS_HTML5TREE_BUILDER_FRAMESET_OK) {
                 mode = NS_HTML5TREE_BUILDER_IN_BODY;
               }
@@ -1181,20 +1274,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
                 attributes = nullptr;
                 NS_HTML5_BREAK(starttagloop);
               } else {
               }
             }
             case NS_HTML5TREE_BUILDER_NOFRAMES:
             case NS_HTML5TREE_BUILDER_IFRAME:
             case NS_HTML5TREE_BUILDER_NOEMBED: {
-              appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
-              originalMode = mode;
-              mode = NS_HTML5TREE_BUILDER_TEXT;
-              tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, elementName);
+              startTagGenericRawText(elementName, attributes);
               attributes = nullptr;
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_SELECT: {
               reconstructTheActiveFormattingElements();
               appendToCurrentNodeAndPushElementMayFoster(elementName, attributes, formPointer);
               switch(mode) {
                 case NS_HTML5TREE_BUILDER_IN_TABLE:
@@ -1292,17 +1382,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
         }
         inbodyloop_end: ;
       }
       case NS_HTML5TREE_BUILDER_IN_HEAD: {
         for (; ; ) {
           switch(group) {
             case NS_HTML5TREE_BUILDER_HTML: {
               errStrayStartTag(name);
-              if (!fragment) {
+              if (!fragment && !isTemplateContents()) {
                 addAttributesToHtml(attributes);
                 attributes = nullptr;
               }
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_BASE:
             case NS_HTML5TREE_BUILDER_COMMAND: {
               appendVoidElementToCurrentMayFoster(elementName, attributes);
@@ -1331,50 +1421,49 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
               } else {
                 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
                 mode = NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT;
               }
               attributes = nullptr;
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_SCRIPT: {
-              appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
-              originalMode = mode;
-              mode = NS_HTML5TREE_BUILDER_TEXT;
-              tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_SCRIPT_DATA, elementName);
+              startTagScriptInHead(elementName, attributes);
               attributes = nullptr;
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_STYLE:
             case NS_HTML5TREE_BUILDER_NOFRAMES: {
-              appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
-              originalMode = mode;
-              mode = NS_HTML5TREE_BUILDER_TEXT;
-              tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, elementName);
+              startTagGenericRawText(elementName, attributes);
               attributes = nullptr;
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_HEAD: {
               errFooSeenWhenFooOpen(name);
               NS_HTML5_BREAK(starttagloop);
             }
+            case NS_HTML5TREE_BUILDER_TEMPLATE: {
+              startTagTemplateInHead(elementName, attributes);
+              attributes = nullptr;
+              NS_HTML5_BREAK(starttagloop);
+            }
             default: {
               pop();
               mode = NS_HTML5TREE_BUILDER_AFTER_HEAD;
               NS_HTML5_CONTINUE(starttagloop);
             }
           }
         }
         inheadloop_end: ;
       }
       case NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
             errStrayStartTag(name);
-            if (!fragment) {
+            if (!fragment && !isTemplateContents()) {
               addAttributesToHtml(attributes);
               attributes = nullptr;
             }
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND: {
             appendVoidElementToCurrentMayFoster(elementName, attributes);
             selfClosing = false;
@@ -1412,31 +1501,36 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             continue;
           }
         }
       }
       case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
             errStrayStartTag(name);
-            if (!fragment) {
+            if (!fragment && !isTemplateContents()) {
               addAttributesToHtml(attributes);
               attributes = nullptr;
             }
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_COL: {
             appendVoidElementToCurrentMayFoster(elementName, attributes);
             selfClosing = false;
             attributes = nullptr;
             NS_HTML5_BREAK(starttagloop);
           }
+          case NS_HTML5TREE_BUILDER_TEMPLATE: {
+            startTagTemplateInHead(elementName, attributes);
+            attributes = nullptr;
+            NS_HTML5_BREAK(starttagloop);
+          }
           default: {
-            if (!currentPtr) {
-              MOZ_ASSERT(fragment);
+            if (!currentPtr || stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) {
+              MOZ_ASSERT(fragment || isTemplateContents());
               errGarbageInColgroup();
               NS_HTML5_BREAK(starttagloop);
             }
             pop();
             mode = NS_HTML5TREE_BUILDER_IN_TABLE;
             continue;
           }
         }
@@ -1519,34 +1613,36 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             }
             while (currentPtr >= eltPos) {
               pop();
             }
             resetTheInsertionMode();
             continue;
           }
           case NS_HTML5TREE_BUILDER_SCRIPT: {
-            appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
-            originalMode = mode;
-            mode = NS_HTML5TREE_BUILDER_TEXT;
-            tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_SCRIPT_DATA, elementName);
+            startTagScriptInHead(elementName, attributes);
+            attributes = nullptr;
+            NS_HTML5_BREAK(starttagloop);
+          }
+          case NS_HTML5TREE_BUILDER_TEMPLATE: {
+            startTagTemplateInHead(elementName, attributes);
             attributes = nullptr;
             NS_HTML5_BREAK(starttagloop);
           }
           default: {
             errStrayStartTag(name);
             NS_HTML5_BREAK(starttagloop);
           }
         }
       }
       case NS_HTML5TREE_BUILDER_AFTER_BODY: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
             errStrayStartTag(name);
-            if (!fragment) {
+            if (!fragment && !isTemplateContents()) {
               addAttributesToHtml(attributes);
               attributes = nullptr;
             }
             NS_HTML5_BREAK(starttagloop);
           }
           default: {
             errStrayStartTag(name);
             mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
@@ -1562,25 +1658,30 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_FRAME: {
             appendVoidElementToCurrentMayFoster(elementName, attributes);
             selfClosing = false;
             attributes = nullptr;
             NS_HTML5_BREAK(starttagloop);
           }
+          case NS_HTML5TREE_BUILDER_TEMPLATE: {
+            startTagTemplateInHead(elementName, attributes);
+            attributes = nullptr;
+            NS_HTML5_BREAK(starttagloop);
+          }
           default:
             ; // fall through
         }
       }
       case NS_HTML5TREE_BUILDER_AFTER_FRAMESET: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
             errStrayStartTag(name);
-            if (!fragment) {
+            if (!fragment && !isTemplateContents()) {
               addAttributesToHtml(attributes);
               attributes = nullptr;
             }
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_NOFRAMES: {
             appendToCurrentNodeAndPushElement(elementName, attributes);
             originalMode = mode;
@@ -1619,17 +1720,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             continue;
           }
         }
       }
       case NS_HTML5TREE_BUILDER_BEFORE_HEAD: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
             errStrayStartTag(name);
-            if (!fragment) {
+            if (!fragment && !isTemplateContents()) {
               addAttributesToHtml(attributes);
               attributes = nullptr;
             }
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_HEAD: {
             appendToCurrentNodeAndPushHeadElement(attributes);
             mode = NS_HTML5TREE_BUILDER_IN_HEAD;
@@ -1642,17 +1743,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             continue;
           }
         }
       }
       case NS_HTML5TREE_BUILDER_AFTER_HEAD: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
             errStrayStartTag(name);
-            if (!fragment) {
+            if (!fragment && !isTemplateContents()) {
               addAttributesToHtml(attributes);
               attributes = nullptr;
             }
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_BODY: {
             if (!attributes->getLength()) {
               appendToCurrentNodeAndPushBodyElement();
@@ -1739,17 +1840,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             continue;
           }
         }
       }
       case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
             errStrayStartTag(name);
-            if (!fragment) {
+            if (!fragment && !isTemplateContents()) {
               addAttributesToHtml(attributes);
               attributes = nullptr;
             }
             NS_HTML5_BREAK(starttagloop);
           }
           default: {
             errStrayStartTag(name);
 
@@ -1757,27 +1858,24 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             continue;
           }
         }
       }
       case NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
             errStrayStartTag(name);
-            if (!fragment) {
+            if (!fragment && !isTemplateContents()) {
               addAttributesToHtml(attributes);
               attributes = nullptr;
             }
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_NOFRAMES: {
-            appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
-            originalMode = mode;
-            mode = NS_HTML5TREE_BUILDER_TEXT;
-            tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_SCRIPT_DATA, elementName);
+            startTagScriptInHead(elementName, attributes);
             attributes = nullptr;
             NS_HTML5_BREAK(starttagloop);
           }
           default: {
             errStrayStartTag(name);
             NS_HTML5_BREAK(starttagloop);
           }
         }
@@ -1792,16 +1890,50 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
   if (selfClosing) {
     errSelfClosing();
   }
   if (attributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
     delete attributes;
   }
 }
 
+void 
+nsHtml5TreeBuilder::startTagGenericRawText(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
+{
+  appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
+  originalMode = mode;
+  mode = NS_HTML5TREE_BUILDER_TEXT;
+  tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, elementName);
+}
+
+void 
+nsHtml5TreeBuilder::startTagScriptInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
+{
+  appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
+  originalMode = mode;
+  mode = NS_HTML5TREE_BUILDER_TEXT;
+  tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_SCRIPT_DATA, elementName);
+}
+
+void 
+nsHtml5TreeBuilder::startTagTemplateInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
+{
+  insertMarker();
+  appendToCurrentNodeAndPushElement(elementName, attributes);
+  originalMode = mode;
+  mode = NS_HTML5TREE_BUILDER_TEMPLATE_CONTENTS;
+  pushTemplateMode(NS_HTML5TREE_BUILDER_TEMPLATE_CONTENTS);
+}
+
+bool 
+nsHtml5TreeBuilder::isTemplateContents()
+{
+  return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK != findLast(nsHtml5Atoms::template_);
+}
+
 bool 
 nsHtml5TreeBuilder::isSpecialParentInForeign(nsHtml5StackNode* stackNode)
 {
   int32_t ns = stackNode->ns;
   return (kNameSpaceID_XHTML == ns) || (stackNode->isHtmlIntegrationPoint()) || ((kNameSpaceID_MathML == ns) && (stackNode->getGroup() == NS_HTML5TREE_BUILDER_MI_MO_MN_MS_MTEXT));
 }
 
 nsString* 
@@ -2047,50 +2179,61 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
           NS_HTML5_BREAK(endtagloop);
         }
         if (stack[--eltPos]->ns == kNameSpaceID_XHTML) {
           break;
         }
       }
     }
     switch(mode) {
+      case NS_HTML5TREE_BUILDER_TEMPLATE_CONTENTS: {
+        switch(group) {
+          case NS_HTML5TREE_BUILDER_TEMPLATE: {
+            break;
+          }
+          default: {
+            errStrayEndTag(name);
+            NS_HTML5_BREAK(endtagloop);
+          }
+        }
+      }
       case NS_HTML5TREE_BUILDER_IN_ROW: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_TR: {
             eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR);
             if (!eltPos) {
-              MOZ_ASSERT(fragment);
+              MOZ_ASSERT(fragment || isTemplateContents());
               errNoTableRowToClose();
               NS_HTML5_BREAK(endtagloop);
             }
             clearStackBackTo(eltPos);
             pop();
             mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY;
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_TABLE: {
             eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR);
             if (!eltPos) {
-              MOZ_ASSERT(fragment);
+              MOZ_ASSERT(fragment || isTemplateContents());
               errNoTableRowToClose();
               NS_HTML5_BREAK(endtagloop);
             }
             clearStackBackTo(eltPos);
             pop();
             mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY;
             continue;
           }
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: {
             if (findLastInTableScope(name) == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
               errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR);
             if (!eltPos) {
-              MOZ_ASSERT(fragment);
+              MOZ_ASSERT(fragment || isTemplateContents());
               errNoTableRowToClose();
               NS_HTML5_BREAK(endtagloop);
             }
             clearStackBackTo(eltPos);
             pop();
             mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY;
             continue;
           }
@@ -2116,19 +2259,19 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
               NS_HTML5_BREAK(endtagloop);
             }
             clearStackBackTo(eltPos);
             pop();
             mode = NS_HTML5TREE_BUILDER_IN_TABLE;
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_TABLE: {
-            eltPos = findLastInTableScopeOrRootTbodyTheadTfoot();
-            if (!eltPos) {
-              MOZ_ASSERT(fragment);
+            eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
+            if (!eltPos || stack[eltPos]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) {
+              MOZ_ASSERT(fragment || isTemplateContents());
               errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             clearStackBackTo(eltPos);
             pop();
             mode = NS_HTML5TREE_BUILDER_IN_TABLE;
             continue;
           }
@@ -2146,17 +2289,17 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
             ; // fall through
         }
       }
       case NS_HTML5TREE_BUILDER_IN_TABLE: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_TABLE: {
             eltPos = findLast(nsHtml5Atoms::table);
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
-              MOZ_ASSERT(fragment);
+              MOZ_ASSERT(fragment || isTemplateContents());
               errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             while (currentPtr >= eltPos) {
               pop();
             }
             resetTheInsertionMode();
             NS_HTML5_BREAK(endtagloop);
@@ -2167,16 +2310,19 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
           case NS_HTML5TREE_BUILDER_COLGROUP:
           case NS_HTML5TREE_BUILDER_HTML:
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT:
           case NS_HTML5TREE_BUILDER_TD_OR_TH:
           case NS_HTML5TREE_BUILDER_TR: {
             errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
+          case NS_HTML5TREE_BUILDER_TEMPLATE: {
+            break;
+          }
           default: {
             errStrayEndTag(name);
           }
         }
       }
       case NS_HTML5TREE_BUILDER_IN_CAPTION: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_CAPTION: {
@@ -2244,16 +2390,17 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
             clearTheListOfActiveFormattingElementsUpToTheLastMarker();
             mode = NS_HTML5TREE_BUILDER_IN_ROW;
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_TABLE:
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT:
           case NS_HTML5TREE_BUILDER_TR: {
             if (findLastInTableScope(name) == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+              MOZ_ASSERT(name == nsHtml5Atoms::tbody || name == nsHtml5Atoms::tfoot || name == nsHtml5Atoms::thead || fragment || isTemplateContents());
               errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             closeTheCell(findLastInTableScopeTdTh());
             continue;
           }
           case NS_HTML5TREE_BUILDER_BODY:
           case NS_HTML5TREE_BUILDER_CAPTION:
@@ -2267,17 +2414,17 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
             ; // fall through
         }
       }
       case NS_HTML5TREE_BUILDER_FRAMESET_OK:
       case NS_HTML5TREE_BUILDER_IN_BODY: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_BODY: {
             if (!isSecondOnStackBody()) {
-              MOZ_ASSERT(fragment);
+              MOZ_ASSERT(fragment || isTemplateContents());
               errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             MOZ_ASSERT(currentPtr >= 1);
             if (MOZ_UNLIKELY(mViewSource)) {
               for (int32_t i = 2; i <= currentPtr; i++) {
                 switch(stack[i]->getGroup()) {
                   case NS_HTML5TREE_BUILDER_DD_OR_DT:
@@ -2298,17 +2445,17 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
               }
               uncloseloop1_end: ;
             }
             mode = NS_HTML5TREE_BUILDER_AFTER_BODY;
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_HTML: {
             if (!isSecondOnStackBody()) {
-              MOZ_ASSERT(fragment);
+              MOZ_ASSERT(fragment || isTemplateContents());
               errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             if (MOZ_UNLIKELY(mViewSource)) {
               for (int32_t i = 0; i <= currentPtr; i++) {
                 switch(stack[i]->getGroup()) {
                   case NS_HTML5TREE_BUILDER_DD_OR_DT:
                   case NS_HTML5TREE_BUILDER_LI:
@@ -2460,16 +2607,19 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
               while (stack[currentPtr]->ns != kNameSpaceID_XHTML) {
                 pop();
               }
             }
             reconstructTheActiveFormattingElements();
             appendVoidElementToCurrentMayFoster(elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
             NS_HTML5_BREAK(endtagloop);
           }
+          case NS_HTML5TREE_BUILDER_TEMPLATE: {
+            break;
+          }
           case NS_HTML5TREE_BUILDER_AREA_OR_WBR:
 #ifdef ENABLE_VOID_MENUITEM
           case NS_HTML5TREE_BUILDER_MENUITEM:
 #endif
           case NS_HTML5TREE_BUILDER_PARAM_OR_SOURCE_OR_TRACK:
           case NS_HTML5TREE_BUILDER_EMBED_OR_IMG:
           case NS_HTML5TREE_BUILDER_IMAGE:
           case NS_HTML5TREE_BUILDER_INPUT:
@@ -2535,16 +2685,20 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
           }
           case NS_HTML5TREE_BUILDER_BR:
           case NS_HTML5TREE_BUILDER_HTML:
           case NS_HTML5TREE_BUILDER_BODY: {
             pop();
             mode = NS_HTML5TREE_BUILDER_AFTER_HEAD;
             continue;
           }
+          case NS_HTML5TREE_BUILDER_TEMPLATE: {
+            endTagTemplateInHead(name);
+            NS_HTML5_BREAK(endtagloop);
+          }
           default: {
             errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
       }
       case NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT: {
         switch(group) {
@@ -2563,32 +2717,36 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
             errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
       }
       case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_COLGROUP: {
-            if (!currentPtr) {
-              MOZ_ASSERT(fragment);
+            if (!currentPtr || stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) {
+              MOZ_ASSERT(fragment || isTemplateContents());
               errGarbageInColgroup();
               NS_HTML5_BREAK(endtagloop);
             }
             pop();
             mode = NS_HTML5TREE_BUILDER_IN_TABLE;
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_COL: {
             errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
+          case NS_HTML5TREE_BUILDER_TEMPLATE: {
+            endTagTemplateInHead(name);
+            NS_HTML5_BREAK(endtagloop);
+          }
           default: {
-            if (!currentPtr) {
-              MOZ_ASSERT(fragment);
+            if (!currentPtr || stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) {
+              MOZ_ASSERT(fragment || isTemplateContents());
               errGarbageInColgroup();
               NS_HTML5_BREAK(endtagloop);
             }
             pop();
             mode = NS_HTML5TREE_BUILDER_IN_TABLE;
             continue;
           }
         }
@@ -2650,16 +2808,20 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
               NS_HTML5_BREAK(endtagloop);
             }
             while (currentPtr >= eltPos) {
               pop();
             }
             resetTheInsertionMode();
             NS_HTML5_BREAK(endtagloop);
           }
+          case NS_HTML5TREE_BUILDER_TEMPLATE: {
+            endTagTemplateInHead(name);
+            NS_HTML5_BREAK(endtagloop);
+          }
           default: {
             errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
       }
       case NS_HTML5TREE_BUILDER_AFTER_BODY: {
         switch(group) {
@@ -2677,27 +2839,31 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
             mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
             continue;
           }
         }
       }
       case NS_HTML5TREE_BUILDER_IN_FRAMESET: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_FRAMESET: {
-            if (!currentPtr) {
-              MOZ_ASSERT(fragment);
+            if (!currentPtr || isTemplateContents()) {
+              MOZ_ASSERT(fragment || isTemplateContents());
               errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             pop();
             if ((!fragment) && !isCurrent(nsHtml5Atoms::frameset)) {
               mode = NS_HTML5TREE_BUILDER_AFTER_FRAMESET;
             }
             NS_HTML5_BREAK(endtagloop);
           }
+          case NS_HTML5TREE_BUILDER_TEMPLATE: {
+            endTagTemplateInHead(name);
+            NS_HTML5_BREAK(endtagloop);
+          }
           default: {
             errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
       }
       case NS_HTML5TREE_BUILDER_AFTER_FRAMESET: {
         switch(group) {
@@ -2782,21 +2948,41 @@ nsHtml5TreeBuilder::endTag(nsHtml5Elemen
         mode = originalMode;
         NS_HTML5_BREAK(endtagloop);
       }
     }
   }
   endtagloop_end: ;
 }
 
+void 
+nsHtml5TreeBuilder::endTagTemplateInHead(nsIAtom* name)
+{
+  int32_t eltPos = findLast(name);
+  if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+    errStrayEndTag(name);
+    return;
+  }
+  generateImpliedEndTags();
+  if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
+    errUnclosedElements(eltPos, name);
+  }
+  while (currentPtr >= eltPos) {
+    pop();
+  }
+  clearTheListOfActiveFormattingElementsUpToTheLastMarker();
+  popTemplateMode();
+  resetTheInsertionMode();
+}
+
 int32_t 
-nsHtml5TreeBuilder::findLastInTableScopeOrRootTbodyTheadTfoot()
+nsHtml5TreeBuilder::findLastInTableScopeOrRootTemplateTbodyTheadTfoot()
 {
   for (int32_t i = currentPtr; i > 0; i--) {
-    if (stack[i]->getGroup() == NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT) {
+    if (stack[i]->getGroup() == NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT || stack[i]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) {
       return i;
     }
   }
   return 0;
 }
 
 int32_t 
 nsHtml5TreeBuilder::findLast(nsIAtom* name)
@@ -2810,17 +2996,17 @@ nsHtml5TreeBuilder::findLast(nsIAtom* na
 }
 
 int32_t 
 nsHtml5TreeBuilder::findLastInTableScope(nsIAtom* name)
 {
   for (int32_t i = currentPtr; i > 0; i--) {
     if (stack[i]->name == name) {
       return i;
-    } else if (stack[i]->name == nsHtml5Atoms::table) {
+    } else if (stack[i]->name == nsHtml5Atoms::table || stack[i]->name == nsHtml5Atoms::template_) {
       return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK;
     }
   }
   return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK;
 }
 
 int32_t 
 nsHtml5TreeBuilder::findLastInButtonScope(nsIAtom* name)
@@ -3003,27 +3189,31 @@ nsHtml5TreeBuilder::closeTheCell(int32_t
 
 int32_t 
 nsHtml5TreeBuilder::findLastInTableScopeTdTh()
 {
   for (int32_t i = currentPtr; i > 0; i--) {
     nsIAtom* name = stack[i]->name;
     if (nsHtml5Atoms::td == name || nsHtml5Atoms::th == name) {
       return i;
-    } else if (name == nsHtml5Atoms::table) {
+    } else if (name == nsHtml5Atoms::table || name == nsHtml5Atoms::template_) {
       return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK;
     }
   }
   return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK;
 }
 
 void 
 nsHtml5TreeBuilder::clearStackBackTo(int32_t eltPos)
 {
+  int32_t eltGroup = stack[eltPos]->getGroup();
   while (currentPtr > eltPos) {
+    if (stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE && (eltGroup == NS_HTML5TREE_BUILDER_TABLE || eltGroup == NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT || eltGroup == NS_HTML5TREE_BUILDER_TR || eltGroup == NS_HTML5TREE_BUILDER_HTML)) {
+      return;
+    }
     pop();
   }
 }
 
 void 
 nsHtml5TreeBuilder::resetTheInsertionMode()
 {
   nsHtml5StackNode* node;
@@ -3037,17 +3227,20 @@ nsHtml5TreeBuilder::resetTheInsertionMod
       if (!(contextNamespace == kNameSpaceID_XHTML && (contextName == nsHtml5Atoms::td || contextName == nsHtml5Atoms::th))) {
         name = contextName;
         ns = contextNamespace;
       } else {
         mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
         return;
       }
     }
-    if (nsHtml5Atoms::select == name) {
+    if (nsHtml5Atoms::template_ == name) {
+      mode = templateModeStack[templateModePtr];
+      return;
+    } else if (nsHtml5Atoms::select == name) {
       mode = NS_HTML5TREE_BUILDER_IN_SELECT;
       return;
     } else if (nsHtml5Atoms::td == name || nsHtml5Atoms::th == name) {
       mode = NS_HTML5TREE_BUILDER_IN_CELL;
       return;
     } else if (nsHtml5Atoms::tr == name) {
       mode = NS_HTML5TREE_BUILDER_IN_ROW;
       return;
@@ -3062,17 +3255,21 @@ nsHtml5TreeBuilder::resetTheInsertionMod
       return;
     } else if (nsHtml5Atoms::table == name) {
       mode = NS_HTML5TREE_BUILDER_IN_TABLE;
       return;
     } else if (kNameSpaceID_XHTML != ns) {
       mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
       return;
     } else if (nsHtml5Atoms::head == name) {
-      mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
+      if (name == contextName) {
+        mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
+      } else {
+        mode = NS_HTML5TREE_BUILDER_IN_HEAD;
+      }
       return;
     } else if (nsHtml5Atoms::body == name) {
       mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
       return;
     } else if (nsHtml5Atoms::frameset == name) {
       mode = NS_HTML5TREE_BUILDER_IN_FRAMESET;
       return;
     } else if (nsHtml5Atoms::html == name) {
@@ -3115,16 +3312,28 @@ nsHtml5TreeBuilder::debugOnlyClearLastSt
 bool 
 nsHtml5TreeBuilder::debugOnlyClearLastListSlot()
 {
   listOfActiveFormattingElements[listPtr] = nullptr;
   return true;
 }
 
 void 
+nsHtml5TreeBuilder::pushTemplateMode(int32_t mode)
+{
+  templateModePtr++;
+  if (templateModePtr == templateModeStack.length) {
+    jArray<int32_t,int32_t> newStack = jArray<int32_t,int32_t>::newJArray(templateModeStack.length + 64);
+    nsHtml5ArrayCopy::arraycopy(templateModeStack, newStack, templateModeStack.length);
+    templateModeStack = newStack;
+  }
+  templateModeStack[templateModePtr] = mode;
+}
+
+void 
 nsHtml5TreeBuilder::push(nsHtml5StackNode* node)
 {
   currentPtr++;
   if (currentPtr == stack.length) {
     jArray<nsHtml5StackNode*,int32_t> newStack = jArray<nsHtml5StackNode*,int32_t>::newJArray(stack.length + 64);
     nsHtml5ArrayCopy::arraycopy(stack, newStack, stack.length);
     stack = newStack;
   }
@@ -3498,38 +3707,44 @@ nsHtml5TreeBuilder::reconstructTheActive
     entry->release();
     entryClone->retain();
   }
 }
 
 void 
 nsHtml5TreeBuilder::insertIntoFosterParent(nsIContent** child)
 {
-  int32_t eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE);
-  nsHtml5StackNode* node = stack[eltPos];
-  nsIContent** elt = node->node;
-  if (!eltPos) {
-    appendElement(child, elt);
+  int32_t tablePos = findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE);
+  int32_t templatePos = findLastOrRoot(NS_HTML5TREE_BUILDER_TEMPLATE);
+  if (templatePos >= tablePos) {
+    appendElement(child, stack[templatePos]->node);
     return;
   }
-  insertFosterParentedChild(child, elt, stack[eltPos - 1]->node);
+  nsHtml5StackNode* node = stack[tablePos];
+  insertFosterParentedChild(child, node->node, stack[tablePos - 1]->node);
 }
 
 bool 
 nsHtml5TreeBuilder::isInStack(nsHtml5StackNode* node)
 {
   for (int32_t i = currentPtr; i >= 0; i--) {
     if (stack[i] == node) {
       return true;
     }
   }
   return false;
 }
 
 void 
+nsHtml5TreeBuilder::popTemplateMode()
+{
+  templateModePtr--;
+}
+
+void 
 nsHtml5TreeBuilder::pop()
 {
   nsHtml5StackNode* node = stack[currentPtr];
   MOZ_ASSERT(debugOnlyClearLastStackSlot());
   currentPtr--;
   elementPopped(node->ns, node->popName, node->node);
   node->release();
 }
@@ -3623,16 +3838,19 @@ nsHtml5TreeBuilder::appendToCurrentNodeA
   node->retain();
 }
 
 void 
 nsHtml5TreeBuilder::appendToCurrentNodeAndPushElement(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
 {
   nsIContent** elt = createElement(kNameSpaceID_XHTML, elementName->name, attributes);
   appendElement(elt, stack[currentPtr]->node);
+  if (nsHtml5ElementName::ELT_TEMPLATE == elementName) {
+    elt = getDocumentFragmentForTemplate(elt);
+  }
   nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt);
   push(node);
 }
 
 void 
 nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
 {
   nsIAtom* popName = elementName->name;
--- a/parser/html/nsHtml5TreeBuilder.h
+++ b/parser/html/nsHtml5TreeBuilder.h
@@ -1,30 +1,30 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
  * Copyright (c) 2007-2011 Mozilla Foundation
- * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla 
+ * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
  * Foundation, and Opera Software ASA.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a 
- * copy of this software and associated documentation files (the "Software"), 
- * to deal in the Software without restriction, including without limitation 
- * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
- * and/or sell copies of the Software, and to permit persons to whom the 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
  * Software is furnished to do so, subject to the following conditions:
  *
- * The above copyright notice and this permission notice shall be included in 
+ * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit TreeBuilder.java instead and regenerate.
  */
 
@@ -79,16 +79,18 @@ class nsHtml5TreeBuilder : public nsAHtm
     nsHtml5Tokenizer* tokenizer;
   private:
     bool scriptingEnabled;
     bool needToDropLF;
     bool fragment;
     nsIAtom* contextName;
     int32_t contextNamespace;
     nsIContent** contextNode;
+    autoJArray<int32_t,int32_t> templateModeStack;
+    int32_t templateModePtr;
     autoJArray<nsHtml5StackNode*,int32_t> stack;
     int32_t currentPtr;
     autoJArray<nsHtml5StackNode*,int32_t> listOfActiveFormattingElements;
     int32_t listPtr;
     nsIContent** formPointer;
     nsIContent** headPointer;
     nsIContent** deepTreeSurrogateParent;
   protected:
@@ -101,25 +103,30 @@ class nsHtml5TreeBuilder : public nsAHtm
     void doctype(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks);
     void comment(PRUnichar* buf, int32_t start, int32_t length);
     void characters(const PRUnichar* buf, int32_t start, int32_t length);
     void zeroOriginatingReplacementCharacter();
     void eof();
     void endTokenization();
     void startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes, bool selfClosing);
   private:
+    void startTagGenericRawText(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes);
+    void startTagScriptInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes);
+    void startTagTemplateInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes);
+    bool isTemplateContents();
     bool isSpecialParentInForeign(nsHtml5StackNode* stackNode);
   public:
     static nsString* extractCharsetFromContent(nsString* attributeValue);
   private:
     void checkMetaCharset(nsHtml5HtmlAttributes* attributes);
   public:
     void endTag(nsHtml5ElementName* elementName);
   private:
-    int32_t findLastInTableScopeOrRootTbodyTheadTfoot();
+    void endTagTemplateInHead(nsIAtom* name);
+    int32_t findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
     int32_t findLast(nsIAtom* name);
     int32_t findLastInTableScope(nsIAtom* name);
     int32_t findLastInButtonScope(nsIAtom* name);
     int32_t findLastInScope(nsIAtom* name);
     int32_t findLastInListScope(nsIAtom* name);
     int32_t findLastInScopeHn();
     void generateImpliedEndTagsExceptFor(nsIAtom* name);
     void generateImpliedEndTags();
@@ -129,16 +136,17 @@ class nsHtml5TreeBuilder : public nsAHtm
     bool isQuirky(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks);
     void closeTheCell(int32_t eltPos);
     int32_t findLastInTableScopeTdTh();
     void clearStackBackTo(int32_t eltPos);
     void resetTheInsertionMode();
     void implicitlyCloseP();
     bool debugOnlyClearLastStackSlot();
     bool debugOnlyClearLastListSlot();
+    void pushTemplateMode(int32_t mode);
     void push(nsHtml5StackNode* node);
     void silentPush(nsHtml5StackNode* node);
     void append(nsHtml5StackNode* node);
     inline void insertMarker()
     {
       append(nullptr);
     }
 
@@ -160,16 +168,17 @@ class nsHtml5TreeBuilder : public nsAHtm
     int32_t findLastOrRoot(nsIAtom* name);
     int32_t findLastOrRoot(int32_t group);
     bool addAttributesToBody(nsHtml5HtmlAttributes* attributes);
     void addAttributesToHtml(nsHtml5HtmlAttributes* attributes);
     void pushHeadPointerOntoStack();
     void reconstructTheActiveFormattingElements();
     void insertIntoFosterParent(nsIContent** child);
     bool isInStack(nsHtml5StackNode* node);
+    void popTemplateMode();
     void pop();
     void silentPop();
     void popOnEof();
     void appendHtmlElementToDocumentAndPush(nsHtml5HtmlAttributes* attributes);
     void appendHtmlElementToDocumentAndPush();
     void appendToCurrentNodeAndPushHeadElement(nsHtml5HtmlAttributes* attributes);
     void appendToCurrentNodeAndPushBodyElement(nsHtml5HtmlAttributes* attributes);
     void appendToCurrentNodeAndPushBodyElement();
@@ -315,16 +324,17 @@ class nsHtml5TreeBuilder : public nsAHtm
 #define NS_HTML5TREE_BUILDER_FOREIGNOBJECT_OR_DESC 59
 #define NS_HTML5TREE_BUILDER_NOEMBED 60
 #define NS_HTML5TREE_BUILDER_FIELDSET 61
 #define NS_HTML5TREE_BUILDER_OUTPUT_OR_LABEL 62
 #define NS_HTML5TREE_BUILDER_OBJECT 63
 #define NS_HTML5TREE_BUILDER_FONT 64
 #define NS_HTML5TREE_BUILDER_KEYGEN 65
 #define NS_HTML5TREE_BUILDER_MENUITEM 66
+#define NS_HTML5TREE_BUILDER_TEMPLATE 67
 #define NS_HTML5TREE_BUILDER_IN_ROW 0
 #define NS_HTML5TREE_BUILDER_IN_TABLE_BODY 1
 #define NS_HTML5TREE_BUILDER_IN_TABLE 2
 #define NS_HTML5TREE_BUILDER_IN_CAPTION 3
 #define NS_HTML5TREE_BUILDER_IN_CELL 4
 #define NS_HTML5TREE_BUILDER_FRAMESET_OK 5
 #define NS_HTML5TREE_BUILDER_IN_BODY 6
 #define NS_HTML5TREE_BUILDER_IN_HEAD 7
@@ -337,16 +347,17 @@ class nsHtml5TreeBuilder : public nsAHtm
 #define NS_HTML5TREE_BUILDER_AFTER_FRAMESET 14
 #define NS_HTML5TREE_BUILDER_INITIAL 15
 #define NS_HTML5TREE_BUILDER_BEFORE_HTML 16
 #define NS_HTML5TREE_BUILDER_BEFORE_HEAD 17
 #define NS_HTML5TREE_BUILDER_AFTER_HEAD 18
 #define NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY 19
 #define NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET 20
 #define NS_HTML5TREE_BUILDER_TEXT 21
+#define NS_HTML5TREE_BUILDER_TEMPLATE_CONTENTS 22
 #define NS_HTML5TREE_BUILDER_CHARSET_INITIAL 0
 #define NS_HTML5TREE_BUILDER_CHARSET_C 1
 #define NS_HTML5TREE_BUILDER_CHARSET_H 2
 #define NS_HTML5TREE_BUILDER_CHARSET_A 3
 #define NS_HTML5TREE_BUILDER_CHARSET_R 4
 #define NS_HTML5TREE_BUILDER_CHARSET_S 5
 #define NS_HTML5TREE_BUILDER_CHARSET_E 6
 #define NS_HTML5TREE_BUILDER_CHARSET_T 7