tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TreeBuilder.java (279560B)


      1 /*
      2 * Copyright (c) 2007 Henri Sivonen
      3 * Copyright (c) 2007-2017 Mozilla Foundation
      4 * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
      5 * Foundation, and Opera Software ASA.
      6 *
      7 * Permission is hereby granted, free of charge, to any person obtaining a
      8 * copy of this software and associated documentation files (the "Software"),
      9 * to deal in the Software without restriction, including without limitation
     10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11 * and/or sell copies of the Software, and to permit persons to whom the
     12 * Software is furnished to do so, subject to the following conditions:
     13 *
     14 * The above copyright notice and this permission notice shall be included in
     15 * all copies or substantial portions of the Software.
     16 *
     17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     23 * DEALINGS IN THE SOFTWARE.
     24 */
     25 
     26 /*
     27 * The comments following this one that use the same comment syntax as this
     28 * comment are quotes from the WHATWG HTML 5 spec as of 27 June 2007
     29 * amended as of June 28 2007.
     30 * That document came with this statement:
     31 * "© Copyright 2004-2007 Apple Computer, Inc., Mozilla Foundation, and
     32 * Opera Software ASA. You are granted a license to use, reproduce and
     33 * create derivative works of this document."
     34 */
     35 
     36 package nu.validator.htmlparser.impl;
     37 
     38 import java.util.Arrays;
     39 import java.util.HashMap;
     40 import java.util.Map;
     41 
     42 import org.xml.sax.ErrorHandler;
     43 import org.xml.sax.Locator;
     44 import org.xml.sax.SAXException;
     45 import org.xml.sax.SAXParseException;
     46 
     47 import nu.validator.htmlparser.annotation.Auto;
     48 import nu.validator.htmlparser.annotation.Const;
     49 import nu.validator.htmlparser.annotation.IdType;
     50 import nu.validator.htmlparser.annotation.Inline;
     51 import nu.validator.htmlparser.annotation.Literal;
     52 import nu.validator.htmlparser.annotation.Local;
     53 import nu.validator.htmlparser.annotation.NoLength;
     54 import nu.validator.htmlparser.annotation.NsUri;
     55 import nu.validator.htmlparser.common.DocumentMode;
     56 import nu.validator.htmlparser.common.DocumentModeHandler;
     57 import nu.validator.htmlparser.common.Interner;
     58 import nu.validator.htmlparser.common.TokenHandler;
     59 import nu.validator.htmlparser.common.XmlViolationPolicy;
     60 
     61 public abstract class TreeBuilder<T> implements TokenHandler,
     62        TreeBuilderState<T> {
     63 
     64    /**
     65     * Array version of U+FFFD.
     66     */
     67    private static final @NoLength char[] REPLACEMENT_CHARACTER = { '\uFFFD' };
     68 
     69    // Start dispatch groups
     70 
     71    final static int OTHER = 0;
     72 
     73    final static int A = 1;
     74 
     75    final static int BASE = 2;
     76 
     77    final static int BODY = 3;
     78 
     79    final static int BR = 4;
     80 
     81    final static int BUTTON = 5;
     82 
     83    final static int CAPTION = 6;
     84 
     85    final static int COL = 7;
     86 
     87    final static int COLGROUP = 8;
     88 
     89    final static int FORM = 9;
     90 
     91    final static int FRAME = 10;
     92 
     93    final static int FRAMESET = 11;
     94 
     95    final static int IMAGE = 12;
     96 
     97    final static int INPUT = 13;
     98 
     99    final static int RT_OR_RP = 14;
    100 
    101    final static int LI = 15;
    102 
    103    final static int LINK_OR_BASEFONT_OR_BGSOUND = 16;
    104 
    105    final static int MATH = 17;
    106 
    107    final static int META = 18;
    108 
    109    final static int SVG = 19;
    110 
    111    final static int HEAD = 20;
    112 
    113    final static int HR = 22;
    114 
    115    final static int HTML = 23;
    116 
    117    final static int NOBR = 24;
    118 
    119    final static int NOFRAMES = 25;
    120 
    121    final static int NOSCRIPT = 26;
    122 
    123    final static int OPTGROUP = 27;
    124 
    125    final static int OPTION = 28;
    126 
    127    final static int P = 29;
    128 
    129    final static int PLAINTEXT = 30;
    130 
    131    final static int SCRIPT = 31;
    132 
    133    final static int SELECT = 32;
    134 
    135    final static int STYLE = 33;
    136 
    137    final static int TABLE = 34;
    138 
    139    final static int TEXTAREA = 35;
    140 
    141    final static int TITLE = 36;
    142 
    143    final static int TR = 37;
    144 
    145    final static int XMP = 38;
    146 
    147    final static int TBODY_OR_THEAD_OR_TFOOT = 39;
    148 
    149    final static int TD_OR_TH = 40;
    150 
    151    final static int DD_OR_DT = 41;
    152 
    153    final static int H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6 = 42;
    154 
    155    final static int MARQUEE_OR_APPLET = 43;
    156 
    157    final static int PRE_OR_LISTING = 44;
    158 
    159    final static int B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U = 45;
    160 
    161    final static int UL_OR_OL_OR_DL = 46;
    162 
    163    final static int IFRAME = 47;
    164 
    165    final static int EMBED = 48;
    166 
    167    final static int AREA_OR_WBR = 49;
    168 
    169    final static int DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU = 50;
    170 
    171    final static int ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SEARCH_OR_SECTION_OR_SUMMARY = 51;
    172 
    173    final static int RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR = 52;
    174 
    175    final static int RB_OR_RTC = 53;
    176 
    177    final static int PARAM_OR_SOURCE_OR_TRACK = 55;
    178 
    179    final static int MGLYPH_OR_MALIGNMARK = 56;
    180 
    181    final static int MI_MO_MN_MS_MTEXT = 57;
    182 
    183    final static int ANNOTATION_XML = 58;
    184 
    185    final static int FOREIGNOBJECT_OR_DESC = 59;
    186 
    187    final static int NOEMBED = 60;
    188 
    189    final static int FIELDSET = 61;
    190 
    191    final static int OUTPUT = 62;
    192 
    193    final static int OBJECT = 63;
    194 
    195    final static int FONT = 64;
    196 
    197    final static int KEYGEN = 65;
    198 
    199    final static int TEMPLATE = 66;
    200 
    201    final static int IMG = 67;
    202 
    203    // start insertion modes
    204 
    205    private static final int IN_ROW = 0;
    206 
    207    private static final int IN_TABLE_BODY = 1;
    208 
    209    private static final int IN_TABLE = 2;
    210 
    211    private static final int IN_CAPTION = 3;
    212 
    213    private static final int IN_CELL = 4;
    214 
    215    private static final int FRAMESET_OK = 5;
    216 
    217    private static final int IN_BODY = 6;
    218 
    219    private static final int IN_HEAD = 7;
    220 
    221    private static final int IN_HEAD_NOSCRIPT = 8;
    222 
    223    // no fall-through
    224 
    225    private static final int IN_COLUMN_GROUP = 9;
    226 
    227    // no fall-through
    228 
    229    private static final int IN_SELECT_IN_TABLE = 10;
    230 
    231    private static final int IN_SELECT = 11;
    232 
    233    // no fall-through
    234 
    235    private static final int AFTER_BODY = 12;
    236 
    237    // no fall-through
    238 
    239    private static final int IN_FRAMESET = 13;
    240 
    241    private static final int AFTER_FRAMESET = 14;
    242 
    243    // no fall-through
    244 
    245    private static final int INITIAL = 15;
    246 
    247    // could add fall-through
    248 
    249    private static final int BEFORE_HTML = 16;
    250 
    251    // could add fall-through
    252 
    253    private static final int BEFORE_HEAD = 17;
    254 
    255    // no fall-through
    256 
    257    private static final int AFTER_HEAD = 18;
    258 
    259    // no fall-through
    260 
    261    private static final int AFTER_AFTER_BODY = 19;
    262 
    263    // no fall-through
    264 
    265    private static final int AFTER_AFTER_FRAMESET = 20;
    266 
    267    // no fall-through
    268 
    269    private static final int TEXT = 21;
    270 
    271    private static final int IN_TEMPLATE = 22;
    272 
    273    // start charset states
    274 
    275    private static final int CHARSET_INITIAL = 0;
    276 
    277    private static final int CHARSET_C = 1;
    278 
    279    private static final int CHARSET_H = 2;
    280 
    281    private static final int CHARSET_A = 3;
    282 
    283    private static final int CHARSET_R = 4;
    284 
    285    private static final int CHARSET_S = 5;
    286 
    287    private static final int CHARSET_E = 6;
    288 
    289    private static final int CHARSET_T = 7;
    290 
    291    private static final int CHARSET_EQUALS = 8;
    292 
    293    private static final int CHARSET_SINGLE_QUOTED = 9;
    294 
    295    private static final int CHARSET_DOUBLE_QUOTED = 10;
    296 
    297    private static final int CHARSET_UNQUOTED = 11;
    298 
    299    // end pseudo enums
    300 
    301    @Literal private final static String[] QUIRKY_PUBLIC_IDS = {
    302            "+//silmaril//dtd html pro v0r11 19970101//",
    303            "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
    304            "-//as//dtd html 3.0 aswedit + extensions//",
    305            "-//ietf//dtd html 2.0 level 1//",
    306            "-//ietf//dtd html 2.0 level 2//",
    307            "-//ietf//dtd html 2.0 strict level 1//",
    308            "-//ietf//dtd html 2.0 strict level 2//",
    309            "-//ietf//dtd html 2.0 strict//",
    310            "-//ietf//dtd html 2.0//",
    311            "-//ietf//dtd html 2.1e//",
    312            "-//ietf//dtd html 3.0//",
    313            "-//ietf//dtd html 3.2 final//",
    314            "-//ietf//dtd html 3.2//",
    315            "-//ietf//dtd html 3//",
    316            "-//ietf//dtd html level 0//",
    317            "-//ietf//dtd html level 1//",
    318            "-//ietf//dtd html level 2//",
    319            "-//ietf//dtd html level 3//",
    320            "-//ietf//dtd html strict level 0//",
    321            "-//ietf//dtd html strict level 1//",
    322            "-//ietf//dtd html strict level 2//",
    323            "-//ietf//dtd html strict level 3//",
    324            "-//ietf//dtd html strict//",
    325            "-//ietf//dtd html//",
    326            "-//metrius//dtd metrius presentational//",
    327            "-//microsoft//dtd internet explorer 2.0 html strict//",
    328            "-//microsoft//dtd internet explorer 2.0 html//",
    329            "-//microsoft//dtd internet explorer 2.0 tables//",
    330            "-//microsoft//dtd internet explorer 3.0 html strict//",
    331            "-//microsoft//dtd internet explorer 3.0 html//",
    332            "-//microsoft//dtd internet explorer 3.0 tables//",
    333            "-//netscape comm. corp.//dtd html//",
    334            "-//netscape comm. corp.//dtd strict html//",
    335            "-//o'reilly and associates//dtd html 2.0//",
    336            "-//o'reilly and associates//dtd html extended 1.0//",
    337            "-//o'reilly and associates//dtd html extended relaxed 1.0//",
    338            "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
    339            "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
    340            "-//spyglass//dtd html 2.0 extended//",
    341            "-//sq//dtd html 2.0 hotmetal + extensions//",
    342            "-//sun microsystems corp.//dtd hotjava html//",
    343            "-//sun microsystems corp.//dtd hotjava strict html//",
    344            "-//w3c//dtd html 3 1995-03-24//", "-//w3c//dtd html 3.2 draft//",
    345            "-//w3c//dtd html 3.2 final//", "-//w3c//dtd html 3.2//",
    346            "-//w3c//dtd html 3.2s draft//", "-//w3c//dtd html 4.0 frameset//",
    347            "-//w3c//dtd html 4.0 transitional//",
    348            "-//w3c//dtd html experimental 19960712//",
    349            "-//w3c//dtd html experimental 970421//", "-//w3c//dtd w3 html//",
    350            "-//w3o//dtd w3 html 3.0//", "-//webtechs//dtd mozilla html 2.0//",
    351            "-//webtechs//dtd mozilla html//" };
    352 
    353    private static final int NOT_FOUND_ON_STACK = Integer.MAX_VALUE;
    354 
    355    // [NOCPP[
    356 
    357    private static final @Local String HTML_LOCAL = "html";
    358 
    359    // ]NOCPP]
    360 
    361    private int mode = INITIAL;
    362 
    363    private int originalMode = INITIAL;
    364 
    365    /**
    366     * Used only when moving back to IN_BODY.
    367     */
    368    private boolean framesetOk = true;
    369 
    370    protected Tokenizer tokenizer;
    371 
    372    // [NOCPP[
    373 
    374    protected ErrorHandler errorHandler;
    375 
    376    private DocumentModeHandler documentModeHandler;
    377 
    378    // ]NOCPP]
    379 
    380    private boolean scriptingEnabled = false;
    381 
    382    private boolean needToDropLF;
    383 
    384    // [NOCPP[
    385 
    386    private boolean wantingComments;
    387 
    388    // ]NOCPP]
    389 
    390    private boolean fragment;
    391 
    392    private @Local String contextName;
    393 
    394    private @NsUri String contextNamespace;
    395 
    396    private T contextNode;
    397 
    398    /**
    399     * Stack of template insertion modes
    400     */
    401    private @Auto int[] templateModeStack;
    402 
    403    /**
    404     * Current template mode stack pointer.
    405     */
    406    private int templateModePtr = -1;
    407 
    408    private @Auto StackNode<T>[] stackNodes;
    409 
    410    /**
    411     * Index of the earliest possible unused or empty element in stackNodes.
    412     */
    413    private int stackNodesIdx = -1;
    414 
    415    private int numStackNodes = 0;
    416 
    417    private @Auto StackNode<T>[] stack;
    418 
    419    private int currentPtr = -1;
    420 
    421    private @Auto StackNode<T>[] listOfActiveFormattingElements;
    422 
    423    private int listPtr = -1;
    424 
    425    private T formPointer;
    426 
    427    private T headPointer;
    428 
    429    protected @Auto char[] charBuffer;
    430 
    431    protected int charBufferLen = 0;
    432 
    433    private boolean quirks = false;
    434 
    435    private boolean forceNoQuirks = false;
    436 
    437    private boolean allowDeclarativeShadowRoots = false;
    438 
    439    private boolean keepBuffer = false;
    440 
    441    // [NOCPP[
    442 
    443    private boolean reportingDoctype = true;
    444 
    445    private XmlViolationPolicy namePolicy = XmlViolationPolicy.ALTER_INFOSET;
    446 
    447    private final Map<String, LocatorImpl> idLocations = new HashMap<String, LocatorImpl>();
    448 
    449    // ]NOCPP]
    450 
    451    protected TreeBuilder() {
    452        fragment = false;
    453    }
    454 
    455    /**
    456     * Reports an condition that would make the infoset incompatible with XML
    457     * 1.0 as fatal.
    458     *
    459     * @throws SAXException
    460     * @throws SAXParseException
    461     */
    462    protected void fatal() throws SAXException {
    463    }
    464 
    465    // CPPONLY: @Inline private @Creator Object htmlCreator(@HtmlCreator Object htmlCreator) {
    466    // CPPONLY:     @Creator Object creator;
    467    // CPPONLY:     creator.html = htmlCreator;
    468    // CPPONLY:     return creator;
    469    // CPPONLY: }
    470    // CPPONLY:
    471    // CPPONLY: @Inline private @Creator Object svgCreator(@SvgCreator Object svgCreator) {
    472    // CPPONLY:     @Creator Object creator;
    473    // CPPONLY:     creator.svg = svgCreator;
    474    // CPPONLY:     return creator;
    475    // CPPONLY: }
    476 
    477    // [NOCPP[
    478 
    479    protected final void fatal(Exception e) throws SAXException {
    480        SAXParseException spe = new SAXParseException(e.getMessage(),
    481                tokenizer, e);
    482        if (errorHandler != null) {
    483            errorHandler.fatalError(spe);
    484        }
    485        throw spe;
    486    }
    487 
    488    final void fatal(String s) throws SAXException {
    489        SAXParseException spe = new SAXParseException(s, tokenizer);
    490        if (errorHandler != null) {
    491            errorHandler.fatalError(spe);
    492        }
    493        throw spe;
    494    }
    495 
    496    /**
    497     * Reports a Parse Error.
    498     *
    499     * @param message
    500     *            the message
    501     * @throws SAXException
    502     */
    503    final void err(String message) throws SAXException {
    504        if (errorHandler == null) {
    505            return;
    506        }
    507        errNoCheck(message);
    508    }
    509 
    510    /**
    511     * Reports a Parse Error without checking if an error handler is present.
    512     *
    513     * @param message
    514     *            the message
    515     * @throws SAXException
    516     */
    517    final void errNoCheck(String message) throws SAXException {
    518        SAXParseException spe = new SAXParseException(message, tokenizer);
    519        errorHandler.error(spe);
    520    }
    521 
    522    private void errListUnclosedStartTags(int eltPos) throws SAXException {
    523        if (currentPtr != -1) {
    524            for (int i = currentPtr; i > eltPos; i--) {
    525                reportUnclosedElementNameAndLocation(i);
    526            }
    527        }
    528    }
    529 
    530    /**
    531     * Reports the name and location of an unclosed element.
    532     *
    533     * @throws SAXException
    534     */
    535    private final void reportUnclosedElementNameAndLocation(int pos) throws SAXException {
    536        StackNode<T> node = stack[pos];
    537        if (node.isOptionalEndTag()) {
    538            return;
    539        }
    540        TaintableLocatorImpl locator = node.getLocator();
    541        if (locator.isTainted()) {
    542            return;
    543        }
    544        locator.markTainted();
    545        SAXParseException spe = new SAXParseException(
    546                "Unclosed element \u201C" + node.popName + "\u201D.", locator);
    547        errorHandler.error(spe);
    548    }
    549 
    550    /**
    551     * Reports a warning
    552     *
    553     * @param message
    554     *            the message
    555     * @throws SAXException
    556     */
    557    final void warn(String message) throws SAXException {
    558        if (errorHandler == null) {
    559            return;
    560        }
    561        SAXParseException spe = new SAXParseException(message, tokenizer);
    562        errorHandler.warning(spe);
    563    }
    564 
    565    /**
    566     * Reports a warning with an explicit locator
    567     *
    568     * @param message
    569     *            the message
    570     * @throws SAXException
    571     */
    572    final void warn(String message, Locator locator) throws SAXException {
    573        if (errorHandler == null) {
    574            return;
    575        }
    576        SAXParseException spe = new SAXParseException(message, locator);
    577        errorHandler.warning(spe);
    578    }
    579 
    580    // ]NOCPP]
    581 
    582    public void setKeepBuffer(boolean keepBuffer) {
    583        this.keepBuffer = keepBuffer;
    584    }
    585 
    586    public boolean dropBufferIfLongerThan(int length) {
    587        if (charBuffer.length > length) {
    588            charBuffer = null;
    589            return true;
    590        }
    591        return false;
    592    }
    593 
    594    @SuppressWarnings("unchecked") public final void startTokenization(Tokenizer self) throws SAXException {
    595        tokenizer = self;
    596        stackNodes = new StackNode[64];
    597        stack = new StackNode[64];
    598        templateModeStack = new int[64];
    599        listOfActiveFormattingElements = new StackNode[64];
    600        needToDropLF = false;
    601        originalMode = INITIAL;
    602        templateModePtr = -1;
    603        stackNodesIdx = 0;
    604        numStackNodes = 0;
    605        currentPtr = -1;
    606        listPtr = -1;
    607        formPointer = null;
    608        headPointer = null;
    609        // [NOCPP[
    610        idLocations.clear();
    611        wantingComments = wantsComments();
    612        // ]NOCPP]
    613        start(fragment);
    614        charBufferLen = 0;
    615        if (!keepBuffer) {
    616            charBuffer = null;
    617        }
    618        framesetOk = true;
    619        if (fragment) {
    620            T elt;
    621            if (contextNode != null) {
    622                elt = contextNode;
    623            } else {
    624                elt = createHtmlElementSetAsRoot(tokenizer.emptyAttributes());
    625            }
    626            // When the context node is not in the HTML namespace, contrary
    627            // to the spec, the first node on the stack is not set to "html"
    628            // in the HTML namespace. Instead, it is set to a node that has
    629            // the characteristics of the appropriate "adjusted current node".
    630            // This way, there is no need to perform "adjusted current node"
    631            // checks during tree construction. Instead, it's sufficient to
    632            // just look at the current node. However, this also means that it
    633            // is not safe to treat "html" in the HTML namespace as a sentinel
    634            // that ends stack popping. Instead, stack popping loops that are
    635            // meant not to pop the first element on the stack need to check
    636            // for currentPos becoming zero.
    637            if (contextNamespace == "http://www.w3.org/2000/svg") {
    638                ElementName elementName = ElementName.SVG;
    639                if ("title" == contextName || "desc" == contextName
    640                        || "foreignObject" == contextName) {
    641                    // These elements are all alike and we don't care about
    642                    // the exact name.
    643                    elementName = ElementName.FOREIGNOBJECT;
    644                }
    645                // This is the SVG variant of the StackNode constructor.
    646                StackNode<T> node = createStackNode(elementName,
    647                        elementName.getCamelCaseName(), elt
    648                        // [NOCPP[
    649                        , errorHandler == null ? null
    650                                : new TaintableLocatorImpl(tokenizer)
    651                // ]NOCPP]
    652                );
    653                currentPtr++;
    654                stack[currentPtr] = node;
    655                tokenizer.setState(Tokenizer.DATA);
    656                // The frameset-ok flag is set even though <frameset> never
    657                // ends up being allowed as HTML frameset in the fragment case.
    658                mode = FRAMESET_OK;
    659            } else if (contextNamespace == "http://www.w3.org/1998/Math/MathML") {
    660                ElementName elementName = ElementName.MATH;
    661                if ("mi" == contextName || "mo" == contextName
    662                        || "mn" == contextName || "ms" == contextName
    663                        || "mtext" == contextName) {
    664                    // These elements are all alike and we don't care about
    665                    // the exact name.
    666                    elementName = ElementName.MTEXT;
    667                } else if ("annotation-xml" == contextName) {
    668                    elementName = ElementName.ANNOTATION_XML;
    669                    // Blink does not check the encoding attribute of the
    670                    // annotation-xml element innerHTML is being set on.
    671                    // Let's do the same at least until
    672                    // https://www.w3.org/Bugs/Public/show_bug.cgi?id=26783
    673                    // is resolved.
    674                }
    675                // This is the MathML variant of the StackNode constructor.
    676                StackNode<T> node = createStackNode(elementName, elt,
    677                        elementName.getName(), false
    678                        // [NOCPP[
    679                        , errorHandler == null ? null
    680                                : new TaintableLocatorImpl(tokenizer)
    681                // ]NOCPP]
    682                );
    683                currentPtr++;
    684                stack[currentPtr] = node;
    685                tokenizer.setState(Tokenizer.DATA);
    686                // The frameset-ok flag is set even though <frameset> never
    687                // ends up being allowed as HTML frameset in the fragment case.
    688                mode = FRAMESET_OK;
    689            } else { // html
    690                StackNode<T> node = createStackNode(ElementName.HTML, elt
    691                // [NOCPP[
    692                        , errorHandler == null ? null
    693                                : new TaintableLocatorImpl(tokenizer)
    694                // ]NOCPP]
    695                );
    696                currentPtr++;
    697                stack[currentPtr] = node;
    698                if ("template" == contextName) {
    699                    pushTemplateMode(IN_TEMPLATE);
    700                }
    701                resetTheInsertionMode();
    702                formPointer = getFormPointerForContext(contextNode);
    703                if ("title" == contextName || "textarea" == contextName) {
    704                    tokenizer.setState(Tokenizer.RCDATA);
    705                } else if ("style" == contextName || "xmp" == contextName
    706                        || "iframe" == contextName || "noembed" == contextName
    707                        || "noframes" == contextName
    708                        || (scriptingEnabled && "noscript" == contextName)) {
    709                    tokenizer.setState(Tokenizer.RAWTEXT);
    710                } else if ("plaintext" == contextName) {
    711                    tokenizer.setState(Tokenizer.PLAINTEXT);
    712                } else if ("script" == contextName) {
    713                    tokenizer.setState(Tokenizer.SCRIPT_DATA);
    714                } else {
    715                    tokenizer.setState(Tokenizer.DATA);
    716                }
    717            }
    718        } else {
    719            mode = INITIAL;
    720            // If we are viewing XML source, put a foreign element permanently
    721            // on the stack so that cdataSectionAllowed() returns true.
    722            // CPPONLY: if (tokenizer.isViewingXmlSource()) {
    723            // CPPONLY: T elt = createElement("http://www.w3.org/2000/svg",
    724            // CPPONLY: "svg",
    725            // CPPONLY: tokenizer.emptyAttributes(), null,
    726            // CPPONLY: svgCreator(NS_NewSVGSVGElement));
    727            // CPPONLY: StackNode<T> node = createStackNode(ElementName.SVG,
    728            // CPPONLY: "svg",
    729            // CPPONLY: elt);
    730            // CPPONLY: currentPtr++;
    731            // CPPONLY: stack[currentPtr] = node;
    732            // CPPONLY: }
    733        }
    734    }
    735 
    736    public final void doctype(@Local String name, String publicIdentifier,
    737            String systemIdentifier, boolean forceQuirks) throws SAXException {
    738        needToDropLF = false;
    739        if (!isInForeign() && mode == INITIAL) {
    740            // [NOCPP[
    741            if (reportingDoctype) {
    742                // ]NOCPP]
    743                String emptyString = Portability.newEmptyString();
    744                appendDoctypeToDocument(name == null ? "" : name,
    745                        publicIdentifier == null ? emptyString
    746                                : publicIdentifier,
    747                        systemIdentifier == null ? emptyString
    748                                : systemIdentifier);
    749                Portability.releaseString(emptyString);
    750                // [NOCPP[
    751            }
    752            // ]NOCPP]
    753            if (isQuirky(name, publicIdentifier, systemIdentifier,
    754                    forceQuirks)) {
    755                errQuirkyDoctype();
    756                documentModeInternal(DocumentMode.QUIRKS_MODE,
    757                        publicIdentifier, systemIdentifier);
    758            } else if (isAlmostStandards(publicIdentifier,
    759                    systemIdentifier)) {
    760                errAlmostStandardsDoctype();
    761                documentModeInternal(
    762                        DocumentMode.ALMOST_STANDARDS_MODE,
    763                        publicIdentifier, systemIdentifier);
    764            } else {
    765                // [NOCPP[
    766                if ((Portability.literalEqualsString(
    767                        "-//W3C//DTD HTML 4.0//EN", publicIdentifier) && (systemIdentifier == null || Portability.literalEqualsString(
    768                        "http://www.w3.org/TR/REC-html40/strict.dtd",
    769                        systemIdentifier)))
    770                        || (Portability.literalEqualsString(
    771                                "-//W3C//DTD HTML 4.01//EN",
    772                                publicIdentifier) && (systemIdentifier == null || Portability.literalEqualsString(
    773                                "http://www.w3.org/TR/html4/strict.dtd",
    774                                systemIdentifier)))
    775                        || (Portability.literalEqualsString(
    776                                "-//W3C//DTD XHTML 1.0 Strict//EN",
    777                                publicIdentifier) && Portability.literalEqualsString(
    778                                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd",
    779                                systemIdentifier))
    780                        || (Portability.literalEqualsString(
    781                                "-//W3C//DTD XHTML 1.1//EN",
    782                                publicIdentifier) && Portability.literalEqualsString(
    783                                "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd",
    784                                systemIdentifier))
    785 
    786                ) {
    787                    err("Obsolete doctype. Expected \u201C<!DOCTYPE html>\u201D.");
    788                } else if (!((systemIdentifier == null || Portability.literalEqualsString(
    789                        "about:legacy-compat", systemIdentifier)) && publicIdentifier == null)) {
    790                    err("Legacy doctype. Expected \u201C<!DOCTYPE html>\u201D.");
    791                }
    792                // ]NOCPP]
    793                documentModeInternal(DocumentMode.STANDARDS_MODE,
    794                        publicIdentifier, systemIdentifier);
    795            }
    796 
    797            /*
    798             *
    799             * Then, switch to the root element mode of the tree construction
    800             * stage.
    801             */
    802            mode = BEFORE_HTML;
    803            return;
    804        }
    805        /*
    806         * A DOCTYPE token Parse error.
    807         */
    808        errStrayDoctype();
    809        /*
    810         * Ignore the token.
    811         */
    812        return;
    813    }
    814 
    815    public final void comment(@NoLength char[] buf, int start, int length)
    816            throws SAXException {
    817        needToDropLF = false;
    818        // [NOCPP[
    819        if (!wantingComments) {
    820            return;
    821        }
    822        // ]NOCPP]
    823        if (!isInForeign()) {
    824            switch (mode) {
    825                case INITIAL:
    826                case BEFORE_HTML:
    827                case AFTER_AFTER_BODY:
    828                case AFTER_AFTER_FRAMESET:
    829                    /*
    830                     * A comment token Append a Comment node to the Document
    831                     * object with the data attribute set to the data given in
    832                     * the comment token.
    833                     */
    834                    appendCommentToDocument(buf, start, length);
    835                    return;
    836                case AFTER_BODY:
    837                    /*
    838                     * A comment token Append a Comment node to the first
    839                     * element in the stack of open elements (the html element),
    840                     * with the data attribute set to the data given in the
    841                     * comment token.
    842                     */
    843                    flushCharacters();
    844                    appendComment(stack[0].node, buf, start, length);
    845                    return;
    846                default:
    847                    break;
    848            }
    849        }
    850        /*
    851         * A comment token Append a Comment node to the current node with the
    852         * data attribute set to the data given in the comment token.
    853         */
    854        flushCharacters();
    855        appendComment(stack[currentPtr].node, buf, start, length);
    856        return;
    857    }
    858 
    859    /**
    860     * @see nu.validator.htmlparser.common.TokenHandler#characters(char[], int,
    861     *      int)
    862     */
    863    public final void characters(@Const @NoLength char[] buf, int start, int length)
    864            throws SAXException {
    865        // Note: Can't attach error messages to EOF in C++ yet
    866 
    867        // CPPONLY: if (tokenizer.isViewingXmlSource()) {
    868        // CPPONLY: return;
    869        // CPPONLY: }
    870        if (needToDropLF) {
    871            needToDropLF = false;
    872            if (buf[start] == '\n') {
    873                start++;
    874                length--;
    875                if (length == 0) {
    876                    return;
    877                }
    878            }
    879        }
    880 
    881        // optimize the most common case
    882        switch (mode) {
    883            case IN_BODY:
    884            case IN_CELL:
    885            case IN_CAPTION:
    886                if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
    887                    reconstructTheActiveFormattingElements();
    888                }
    889                // CPPONLY: MOZ_FALLTHROUGH;
    890            case TEXT:
    891                accumulateCharacters(buf, start, length);
    892                return;
    893            case IN_TABLE:
    894            case IN_TABLE_BODY:
    895            case IN_ROW:
    896                accumulateCharactersForced(buf, start, length);
    897                return;
    898            default:
    899                int end = start + length;
    900                charactersloop: for (int i = start; i < end; i++) {
    901                    switch (buf[i]) {
    902                        case ' ':
    903                        case '\t':
    904                        case '\n':
    905                        case '\r':
    906                        case '\u000C':
    907                            /*
    908                             * A character token that is one of one of U+0009
    909                             * CHARACTER TABULATION, U+000A LINE FEED (LF),
    910                             * U+000C FORM FEED (FF), or U+0020 SPACE
    911                             */
    912                            switch (mode) {
    913                                case INITIAL:
    914                                case BEFORE_HTML:
    915                                case BEFORE_HEAD:
    916                                    /*
    917                                     * Ignore the token.
    918                                     */
    919                                    start = i + 1;
    920                                    continue;
    921                                case IN_HEAD:
    922                                case IN_HEAD_NOSCRIPT:
    923                                case AFTER_HEAD:
    924                                case IN_COLUMN_GROUP:
    925                                case IN_FRAMESET:
    926                                case AFTER_FRAMESET:
    927                                    /*
    928                                     * Append the character to the current node.
    929                                     */
    930                                    continue;
    931                                case FRAMESET_OK:
    932                                case IN_TEMPLATE:
    933                                case IN_BODY:
    934                                case IN_CELL:
    935                                case IN_CAPTION:
    936                                    if (start < i) {
    937                                        accumulateCharacters(buf, start, i
    938                                                - start);
    939                                        start = i;
    940                                    }
    941 
    942                                    /*
    943                                     * Reconstruct the active formatting
    944                                     * elements, if any.
    945                                     */
    946                                    if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
    947                                        flushCharacters();
    948                                        reconstructTheActiveFormattingElements();
    949                                    }
    950                                    /*
    951                                     * Append the token's character to the
    952                                     * current node.
    953                                     */
    954                                    break charactersloop;
    955                                case IN_SELECT:
    956                                case IN_SELECT_IN_TABLE:
    957                                    break charactersloop;
    958                                case IN_TABLE:
    959                                case IN_TABLE_BODY:
    960                                case IN_ROW:
    961                                    accumulateCharactersForced(buf, i, 1);
    962                                    start = i + 1;
    963                                    continue;
    964                                case AFTER_BODY:
    965                                case AFTER_AFTER_BODY:
    966                                case AFTER_AFTER_FRAMESET:
    967                                    if (start < i) {
    968                                        accumulateCharacters(buf, start, i
    969                                                - start);
    970                                        start = i;
    971                                    }
    972                                    /*
    973                                     * Reconstruct the active formatting
    974                                     * elements, if any.
    975                                     */
    976                                    flushCharacters();
    977                                    reconstructTheActiveFormattingElements();
    978                                    /*
    979                                     * Append the token's character to the
    980                                     * current node.
    981                                     */
    982                                    continue;
    983                            }
    984                            // CPPONLY: MOZ_FALLTHROUGH_ASSERT();
    985                        default:
    986                            /*
    987                             * A character token that is not one of one of
    988                             * U+0009 CHARACTER TABULATION, U+000A LINE FEED
    989                             * (LF), U+000C FORM FEED (FF), or U+0020 SPACE
    990                             */
    991                            switch (mode) {
    992                                case INITIAL:
    993                                    /*
    994                                     * Parse error.
    995                                     */
    996                                    // [NOCPP[
    997                                    // XXX figure out a way to report this in the Gecko View Source case
    998                                    err("Non-space characters found without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
    999                                    // ]NOCPP]
   1000                                    /*
   1001                                     *
   1002                                     * Set the document to quirks mode.
   1003                                     */
   1004                                    documentModeInternal(
   1005                                            DocumentMode.QUIRKS_MODE, null,
   1006                                            null);
   1007                                    /*
   1008                                     * Then, switch to the root element mode of
   1009                                     * the tree construction stage
   1010                                     */
   1011                                    mode = BEFORE_HTML;
   1012                                    /*
   1013                                     * and reprocess the current token.
   1014                                     */
   1015                                    i--;
   1016                                    continue;
   1017                                case BEFORE_HTML:
   1018                                    /*
   1019                                     * Create an HTMLElement node with the tag
   1020                                     * name html, in the HTML namespace. Append
   1021                                     * it to the Document object.
   1022                                     */
   1023                                    // No need to flush characters here,
   1024                                    // because there's nothing to flush.
   1025                                    appendHtmlElementToDocumentAndPush();
   1026                                    /* Switch to the main mode */
   1027                                    mode = BEFORE_HEAD;
   1028                                    /*
   1029                                     * reprocess the current token.
   1030                                     */
   1031                                    i--;
   1032                                    continue;
   1033                                case BEFORE_HEAD:
   1034                                    if (start < i) {
   1035                                        accumulateCharacters(buf, start, i
   1036                                                - start);
   1037                                        start = i;
   1038                                    }
   1039                                    /*
   1040                                     * /Act as if a start tag token with the tag
   1041                                     * name "head" and no attributes had been
   1042                                     * seen,
   1043                                     */
   1044                                    flushCharacters();
   1045                                    appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
   1046                                    mode = IN_HEAD;
   1047                                    /*
   1048                                     * then reprocess the current token.
   1049                                     *
   1050                                     * This will result in an empty head element
   1051                                     * being generated, with the current token
   1052                                     * being reprocessed in the "after head"
   1053                                     * insertion mode.
   1054                                     */
   1055                                    i--;
   1056                                    continue;
   1057                                case IN_HEAD:
   1058                                    if (start < i) {
   1059                                        accumulateCharacters(buf, start, i
   1060                                                - start);
   1061                                        start = i;
   1062                                    }
   1063                                    /*
   1064                                     * Act as if an end tag token with the tag
   1065                                     * name "head" had been seen,
   1066                                     */
   1067                                    flushCharacters();
   1068                                    pop();
   1069                                    mode = AFTER_HEAD;
   1070                                    /*
   1071                                     * and reprocess the current token.
   1072                                     */
   1073                                    i--;
   1074                                    continue;
   1075                                case IN_HEAD_NOSCRIPT:
   1076                                    if (start < i) {
   1077                                        accumulateCharacters(buf, start, i
   1078                                                - start);
   1079                                        start = i;
   1080                                    }
   1081                                    /*
   1082                                     * Parse error. Act as if an end tag with
   1083                                     * the tag name "noscript" had been seen
   1084                                     */
   1085                                    errNonSpaceInNoscriptInHead();
   1086                                    flushCharacters();
   1087                                    pop();
   1088                                    mode = IN_HEAD;
   1089                                    /*
   1090                                     * and reprocess the current token.
   1091                                     */
   1092                                    i--;
   1093                                    continue;
   1094                                case AFTER_HEAD:
   1095                                    if (start < i) {
   1096                                        accumulateCharacters(buf, start, i
   1097                                                - start);
   1098                                        start = i;
   1099                                    }
   1100                                    /*
   1101                                     * Act as if a start tag token with the tag
   1102                                     * name "body" and no attributes had been
   1103                                     * seen,
   1104                                     */
   1105                                    flushCharacters();
   1106                                    appendToCurrentNodeAndPushBodyElement();
   1107                                    mode = FRAMESET_OK;
   1108                                    /*
   1109                                     * and then reprocess the current token.
   1110                                     */
   1111                                    i--;
   1112                                    continue;
   1113                                case FRAMESET_OK:
   1114                                    framesetOk = false;
   1115                                    mode = IN_BODY;
   1116                                    i--;
   1117                                    continue;
   1118                                case IN_TEMPLATE:
   1119                                case IN_BODY:
   1120                                case IN_CELL:
   1121                                case IN_CAPTION:
   1122                                    if (start < i) {
   1123                                        accumulateCharacters(buf, start, i
   1124                                                - start);
   1125                                        start = i;
   1126                                    }
   1127                                    /*
   1128                                     * Reconstruct the active formatting
   1129                                     * elements, if any.
   1130                                     */
   1131                                    if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
   1132                                        flushCharacters();
   1133                                        reconstructTheActiveFormattingElements();
   1134                                    }
   1135                                    /*
   1136                                     * Append the token's character to the
   1137                                     * current node.
   1138                                     */
   1139                                    break charactersloop;
   1140                                case IN_TABLE:
   1141                                case IN_TABLE_BODY:
   1142                                case IN_ROW:
   1143                                    accumulateCharactersForced(buf, i, 1);
   1144                                    start = i + 1;
   1145                                    continue;
   1146                                case IN_COLUMN_GROUP:
   1147                                    if (start < i) {
   1148                                        accumulateCharacters(buf, start, i
   1149                                                - start);
   1150                                        start = i;
   1151                                    }
   1152                                    /*
   1153                                     * Act as if an end tag with the tag name
   1154                                     * "colgroup" had been seen, and then, if
   1155                                     * that token wasn't ignored, reprocess the
   1156                                     * current token.
   1157                                     */
   1158                                    if (currentPtr == 0 || stack[currentPtr].getGroup() ==
   1159                                            TreeBuilder.TEMPLATE) {
   1160                                        errNonSpaceInColgroupInFragment();
   1161                                        start = i + 1;
   1162                                        continue;
   1163                                    }
   1164                                    flushCharacters();
   1165                                    pop();
   1166                                    mode = IN_TABLE;
   1167                                    i--;
   1168                                    continue;
   1169                                case IN_SELECT:
   1170                                case IN_SELECT_IN_TABLE:
   1171                                    break charactersloop;
   1172                                case AFTER_BODY:
   1173                                    errNonSpaceAfterBody();
   1174                                    fatal();
   1175                                    mode = framesetOk ? FRAMESET_OK : IN_BODY;
   1176                                    i--;
   1177                                    continue;
   1178                                case IN_FRAMESET:
   1179                                    if (start < i) {
   1180                                        accumulateCharacters(buf, start, i
   1181                                                - start);
   1182                                        // start index is adjusted below.
   1183                                    }
   1184                                    /*
   1185                                     * Parse error.
   1186                                     */
   1187                                    errNonSpaceInFrameset();
   1188                                    /*
   1189                                     * Ignore the token.
   1190                                     */
   1191                                    start = i + 1;
   1192                                    continue;
   1193                                case AFTER_FRAMESET:
   1194                                    if (start < i) {
   1195                                        accumulateCharacters(buf, start, i
   1196                                                - start);
   1197                                        // start index is adjusted below.
   1198                                    }
   1199                                    /*
   1200                                     * Parse error.
   1201                                     */
   1202                                    errNonSpaceAfterFrameset();
   1203                                    /*
   1204                                     * Ignore the token.
   1205                                     */
   1206                                    start = i + 1;
   1207                                    continue;
   1208                                case AFTER_AFTER_BODY:
   1209                                    /*
   1210                                     * Parse error.
   1211                                     */
   1212                                    errNonSpaceInTrailer();
   1213                                    /*
   1214                                     * Switch back to the main mode and
   1215                                     * reprocess the token.
   1216                                     */
   1217                                    mode = framesetOk ? FRAMESET_OK : IN_BODY;
   1218                                    i--;
   1219                                    continue;
   1220                                case AFTER_AFTER_FRAMESET:
   1221                                    if (start < i) {
   1222                                        accumulateCharacters(buf, start, i
   1223                                                - start);
   1224                                        // start index is adjusted below.
   1225                                    }
   1226                                    /*
   1227                                     * Parse error.
   1228                                     */
   1229                                    errNonSpaceInTrailer();
   1230                                    /*
   1231                                     * Ignore the token.
   1232                                     */
   1233                                    start = i + 1;
   1234                                    continue;
   1235                            }
   1236                    }
   1237                }
   1238                if (start < end) {
   1239                    accumulateCharacters(buf, start, end - start);
   1240                }
   1241        }
   1242    }
   1243 
   1244    /**
   1245     * @see nu.validator.htmlparser.common.TokenHandler#zeroOriginatingReplacementCharacter()
   1246     */
   1247    public void zeroOriginatingReplacementCharacter() throws SAXException {
   1248        if (mode == TEXT) {
   1249            accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
   1250            return;
   1251        }
   1252        if (currentPtr >= 0) {
   1253            if (isSpecialParentInForeign(stack[currentPtr])) {
   1254                return;
   1255            }
   1256            accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
   1257        }
   1258    }
   1259 
   1260    /**
   1261     * @see nu.validator.htmlparser.common.TokenHandler#zeroOrReplacementCharacter()
   1262     */
   1263    public void zeroOrReplacementCharacter() throws SAXException {
   1264        zeroOriginatingReplacementCharacter();
   1265    }
   1266 
   1267    public final void eof() throws SAXException {
   1268        flushCharacters();
   1269        // Note: Can't attach error messages to EOF in C++ yet
   1270        eofloop: for (;;) {
   1271            switch (mode) {
   1272                case INITIAL:
   1273                    /*
   1274                     * Parse error.
   1275                     */
   1276                    // [NOCPP[
   1277                    err("End of file seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
   1278                    // ]NOCPP]
   1279                    /*
   1280                     *
   1281                     * Set the document to quirks mode.
   1282                     */
   1283                    documentModeInternal(DocumentMode.QUIRKS_MODE, null, null);
   1284                    /*
   1285                     * Then, switch to the root element mode of the tree
   1286                     * construction stage
   1287                     */
   1288                    mode = BEFORE_HTML;
   1289                    /*
   1290                     * and reprocess the current token.
   1291                     */
   1292                    continue;
   1293                case BEFORE_HTML:
   1294                    /*
   1295                     * Create an HTMLElement node with the tag name html, in the
   1296                     * HTML namespace. Append it to the Document object.
   1297                     */
   1298                    appendHtmlElementToDocumentAndPush();
   1299                    // XXX application cache manifest
   1300                    /* Switch to the main mode */
   1301                    mode = BEFORE_HEAD;
   1302                    /*
   1303                     * reprocess the current token.
   1304                     */
   1305                    continue;
   1306                case BEFORE_HEAD:
   1307                    appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
   1308                    mode = IN_HEAD;
   1309                    continue;
   1310                case IN_HEAD:
   1311                    // [NOCPP[
   1312                    if (errorHandler != null && currentPtr > 1) {
   1313                        errEofWithUnclosedElements();
   1314                    }
   1315                    // ]NOCPP]
   1316                    while (currentPtr > 0) {
   1317                        popOnEof();
   1318                    }
   1319                    mode = AFTER_HEAD;
   1320                    continue;
   1321                case IN_HEAD_NOSCRIPT:
   1322                    // [NOCPP[
   1323                    errEofWithUnclosedElements();
   1324                    // ]NOCPP]
   1325                    while (currentPtr > 1) {
   1326                        popOnEof();
   1327                    }
   1328                    mode = IN_HEAD;
   1329                    continue;
   1330                case AFTER_HEAD:
   1331                    appendToCurrentNodeAndPushBodyElement();
   1332                    mode = IN_BODY;
   1333                    continue;
   1334                case IN_TABLE_BODY:
   1335                case IN_ROW:
   1336                case IN_TABLE:
   1337                case IN_SELECT_IN_TABLE:
   1338                case IN_SELECT:
   1339                case IN_COLUMN_GROUP:
   1340                case FRAMESET_OK:
   1341                case IN_CAPTION:
   1342                case IN_CELL:
   1343                case IN_BODY:
   1344                    // [NOCPP[
   1345                    // i > 0 to stop in time in the foreign fragment case.
   1346                    openelementloop: for (int i = currentPtr; i > 0; i--) {
   1347                        int group = stack[i].getGroup();
   1348                        switch (group) {
   1349                            case DD_OR_DT:
   1350                            case LI:
   1351                            case P:
   1352                            case TBODY_OR_THEAD_OR_TFOOT:
   1353                            case TD_OR_TH:
   1354                            case BODY:
   1355                            case HTML:
   1356                                break;
   1357                            default:
   1358                                errEofWithUnclosedElements();
   1359                                break openelementloop;
   1360                        }
   1361                    }
   1362                    // ]NOCPP]
   1363 
   1364                    if (isTemplateModeStackEmpty()) {
   1365                        break eofloop;
   1366                    }
   1367 
   1368                    // fall through to IN_TEMPLATE
   1369                    // CPPONLY: MOZ_FALLTHROUGH;
   1370                case IN_TEMPLATE:
   1371                    int eltPos = findLast("template");
   1372                    if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   1373                        assert fragment;
   1374                        break eofloop;
   1375                    }
   1376                    if (errorHandler != null) {
   1377                        errListUnclosedStartTags(0);
   1378                    }
   1379                    while (currentPtr >= eltPos) {
   1380                        pop();
   1381                    }
   1382                    clearTheListOfActiveFormattingElementsUpToTheLastMarker();
   1383                    popTemplateMode();
   1384                    resetTheInsertionMode();
   1385 
   1386                    // Reprocess token.
   1387                    continue;
   1388                case TEXT:
   1389                    // [NOCPP[
   1390                    if (errorHandler != null) {
   1391                        errNoCheck("End of file seen when expecting text or an end tag.");
   1392                        errListUnclosedStartTags(0);
   1393                    }
   1394                    // ]NOCPP]
   1395                    // XXX mark script as already executed
   1396                    if (originalMode == AFTER_HEAD) {
   1397                        popOnEof();
   1398                    }
   1399                    popOnEof();
   1400                    mode = originalMode;
   1401                    continue;
   1402                case IN_FRAMESET:
   1403                    // [NOCPP[
   1404                    if (errorHandler != null && currentPtr > 0) {
   1405                        errEofWithUnclosedElements();
   1406                    }
   1407                    // ]NOCPP]
   1408                    break eofloop;
   1409                case AFTER_BODY:
   1410                case AFTER_FRAMESET:
   1411                case AFTER_AFTER_BODY:
   1412                case AFTER_AFTER_FRAMESET:
   1413                default:
   1414                    // [NOCPP[
   1415                    if (currentPtr == 0) { // This silliness is here to poison
   1416                        // buggy compiler optimizations in
   1417                        // GWT
   1418                        System.currentTimeMillis();
   1419                    }
   1420                    // ]NOCPP]
   1421                    break eofloop;
   1422            }
   1423        }
   1424        while (currentPtr > 0) {
   1425            popOnEof();
   1426        }
   1427        if (!fragment) {
   1428            popOnEof();
   1429        }
   1430        /* Stop parsing. */
   1431    }
   1432 
   1433    /**
   1434     * @see nu.validator.htmlparser.common.TokenHandler#endTokenization()
   1435     */
   1436    public final void endTokenization() throws SAXException {
   1437        formPointer = null;
   1438        headPointer = null;
   1439        contextName = null;
   1440        contextNode = null;
   1441        templateModeStack = null;
   1442        if (stack != null) {
   1443            while (currentPtr > -1) {
   1444                stack[currentPtr].release(this);
   1445                currentPtr--;
   1446            }
   1447            stack = null;
   1448        }
   1449        if (listOfActiveFormattingElements != null) {
   1450            while (listPtr > -1) {
   1451                if (listOfActiveFormattingElements[listPtr] != null) {
   1452                    listOfActiveFormattingElements[listPtr].release(this);
   1453                }
   1454                listPtr--;
   1455            }
   1456            listOfActiveFormattingElements = null;
   1457        }
   1458        if (stackNodes != null) {
   1459            for (int i = 0; i < numStackNodes; i++) {
   1460                assert stackNodes[i].isUnused();
   1461                Portability.delete(stackNodes[i]);
   1462            }
   1463            numStackNodes = 0;
   1464            stackNodesIdx = 0;
   1465            stackNodes = null;
   1466        }
   1467        // [NOCPP[
   1468        idLocations.clear();
   1469        // ]NOCPP]
   1470 
   1471        if (!keepBuffer) {
   1472            charBuffer = null;
   1473        }
   1474        end();
   1475    }
   1476 
   1477    public final void startTag(ElementName elementName,
   1478            HtmlAttributes attributes, boolean selfClosing) throws SAXException {
   1479        flushCharacters();
   1480 
   1481        // [NOCPP[
   1482        boolean wasSelfClosing = selfClosing;
   1483        boolean voidElement = false;
   1484        if (errorHandler != null) {
   1485            // ID uniqueness
   1486            @IdType String id = attributes.getId();
   1487            if (id != null && !isTemplateContents()) {
   1488                LocatorImpl oldLoc = idLocations.get(id);
   1489                if (oldLoc != null) {
   1490                    err("Duplicate ID \u201C" + id + "\u201D.");
   1491                    errorHandler.warning(new SAXParseException(
   1492                            "The first occurrence of ID \u201C" + id
   1493                            + "\u201D was here.", oldLoc));
   1494                } else {
   1495                    idLocations.put(id, new LocatorImpl(tokenizer));
   1496                }
   1497            }
   1498        }
   1499        // ]NOCPP]
   1500 
   1501        int eltPos;
   1502        needToDropLF = false;
   1503        starttagloop: for (;;) {
   1504            int group = elementName.getGroup();
   1505            @Local String name = elementName.getName();
   1506            if (isInForeign()) {
   1507                StackNode<T> currentNode = stack[currentPtr];
   1508                @NsUri String currNs = currentNode.ns;
   1509                if (!(currentNode.isHtmlIntegrationPoint() || (currNs == "http://www.w3.org/1998/Math/MathML" && ((currentNode.getGroup() == MI_MO_MN_MS_MTEXT && group != MGLYPH_OR_MALIGNMARK) || (currentNode.getGroup() == ANNOTATION_XML && group == SVG))))) {
   1510                    switch (group) {
   1511                        case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
   1512                        case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
   1513                        case BODY:
   1514                        case BR:
   1515                        case RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR:
   1516                        case DD_OR_DT:
   1517                        case UL_OR_OL_OR_DL:
   1518                        case EMBED:
   1519                        case IMG:
   1520                        case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
   1521                        case HEAD:
   1522                        case HR:
   1523                        case LI:
   1524                        case META:
   1525                        case NOBR:
   1526                        case P:
   1527                        case PRE_OR_LISTING:
   1528                        case TABLE:
   1529                        case FONT:
   1530                            // re-check FONT to deal with the special case
   1531                            if (!(group == FONT && !(attributes.contains(AttributeName.COLOR)
   1532                                    || attributes.contains(AttributeName.FACE) || attributes.contains(AttributeName.SIZE)))) {
   1533                                errHtmlStartTagInForeignContext(name);
   1534                                if (!fragment) {
   1535                                    while (!isSpecialParentInForeign(stack[currentPtr])) {
   1536                                        popForeign(-1, -1);
   1537                                    }
   1538                                    continue starttagloop;
   1539                                } // else fall thru
   1540                            }
   1541                            // CPPONLY: MOZ_FALLTHROUGH;
   1542                        default:
   1543                            if ("http://www.w3.org/2000/svg" == currNs) {
   1544                                attributes.adjustForSvg();
   1545                                if (selfClosing) {
   1546                                    appendVoidElementToCurrentMayFosterSVG(
   1547                                            elementName, attributes);
   1548                                    selfClosing = false;
   1549                                } else {
   1550                                    appendToCurrentNodeAndPushElementMayFosterSVG(
   1551                                            elementName, attributes);
   1552                                }
   1553                                attributes = null; // CPP
   1554                                break starttagloop;
   1555                            } else {
   1556                                attributes.adjustForMath();
   1557                                if (selfClosing) {
   1558                                    appendVoidElementToCurrentMayFosterMathML(
   1559                                            elementName, attributes);
   1560                                    selfClosing = false;
   1561                                } else {
   1562                                    appendToCurrentNodeAndPushElementMayFosterMathML(
   1563                                            elementName, attributes);
   1564                                }
   1565                                attributes = null; // CPP
   1566                                break starttagloop;
   1567                            }
   1568                    } // switch
   1569                } // foreignObject / annotation-xml
   1570            }
   1571            switch (mode) {
   1572                case IN_TEMPLATE:
   1573                    switch (group) {
   1574                        case COL:
   1575                            popTemplateMode();
   1576                            pushTemplateMode(IN_COLUMN_GROUP);
   1577                            mode = IN_COLUMN_GROUP;
   1578                            // Reprocess token.
   1579                            continue;
   1580                        case CAPTION:
   1581                        case COLGROUP:
   1582                        case TBODY_OR_THEAD_OR_TFOOT:
   1583                            popTemplateMode();
   1584                            pushTemplateMode(IN_TABLE);
   1585                            mode = IN_TABLE;
   1586                            // Reprocess token.
   1587                            continue;
   1588                        case TR:
   1589                            popTemplateMode();
   1590                            pushTemplateMode(IN_TABLE_BODY);
   1591                            mode = IN_TABLE_BODY;
   1592                            // Reprocess token.
   1593                            continue;
   1594                        case TD_OR_TH:
   1595                            popTemplateMode();
   1596                            pushTemplateMode(IN_ROW);
   1597                            mode = IN_ROW;
   1598                            // Reprocess token.
   1599                            continue;
   1600                        case META:
   1601                            checkMetaCharset(attributes);
   1602                            appendVoidElementToCurrentMayFoster(
   1603                                    elementName,
   1604                                    attributes);
   1605                            selfClosing = false;
   1606                            // [NOCPP[
   1607                            voidElement = true;
   1608                            // ]NOCPP]
   1609                            attributes = null; // CPP
   1610                            break starttagloop;
   1611                        case TITLE:
   1612                            startTagTitleInHead(elementName, attributes);
   1613                            attributes = null; // CPP
   1614                            break starttagloop;
   1615                        case BASE:
   1616                        case LINK_OR_BASEFONT_OR_BGSOUND:
   1617                            appendVoidElementToCurrentMayFoster(
   1618                                    elementName,
   1619                                    attributes);
   1620                            selfClosing = false;
   1621                            // [NOCPP[
   1622                            voidElement = true;
   1623                            // ]NOCPP]
   1624                            attributes = null; // CPP
   1625                            break starttagloop;
   1626                        case SCRIPT:
   1627                            startTagScriptInHead(elementName, attributes);
   1628                            attributes = null; // CPP
   1629                            break starttagloop;
   1630                        case NOFRAMES:
   1631                        case STYLE:
   1632                            startTagGenericRawText(elementName, attributes);
   1633                            attributes = null; // CPP
   1634                            break starttagloop;
   1635                        case TEMPLATE:
   1636                            startTagTemplateInHead(elementName, attributes);
   1637                            attributes = null; // CPP
   1638                            break starttagloop;
   1639                        default:
   1640                            popTemplateMode();
   1641                            pushTemplateMode(IN_BODY);
   1642                            mode = IN_BODY;
   1643                            // Reprocess token.
   1644                            continue;
   1645                    }
   1646                case IN_ROW:
   1647                    switch (group) {
   1648                        case TD_OR_TH:
   1649                            clearStackBackTo(findLastOrRoot(TreeBuilder.TR));
   1650                            appendToCurrentNodeAndPushElement(
   1651                                    elementName,
   1652                                    attributes);
   1653                            mode = IN_CELL;
   1654                            insertMarker();
   1655                            attributes = null; // CPP
   1656                            break starttagloop;
   1657                        case CAPTION:
   1658                        case COL:
   1659                        case COLGROUP:
   1660                        case TBODY_OR_THEAD_OR_TFOOT:
   1661                        case TR:
   1662                            eltPos = findLastOrRoot(TreeBuilder.TR);
   1663                            if (eltPos == 0) {
   1664                                assert fragment || isTemplateContents();
   1665                                errNoTableRowToClose();
   1666                                break starttagloop;
   1667                            }
   1668                            clearStackBackTo(eltPos);
   1669                            pop();
   1670                            mode = IN_TABLE_BODY;
   1671                            continue;
   1672                        default:
   1673                            // fall through to IN_TABLE
   1674                    }
   1675                    // CPPONLY: MOZ_FALLTHROUGH;
   1676                case IN_TABLE_BODY:
   1677                    switch (group) {
   1678                        case TR:
   1679                            clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
   1680                            appendToCurrentNodeAndPushElement(
   1681                                    elementName,
   1682                                    attributes);
   1683                            mode = IN_ROW;
   1684                            attributes = null; // CPP
   1685                            break starttagloop;
   1686                        case TD_OR_TH:
   1687                            errStartTagInTableBody(name);
   1688                            clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
   1689                            appendToCurrentNodeAndPushElement(
   1690                                    ElementName.TR,
   1691                                    HtmlAttributes.EMPTY_ATTRIBUTES);
   1692                            mode = IN_ROW;
   1693                            continue;
   1694                        case CAPTION:
   1695                        case COL:
   1696                        case COLGROUP:
   1697                        case TBODY_OR_THEAD_OR_TFOOT:
   1698                            eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
   1699                            if (eltPos == 0 || stack[eltPos].getGroup() == TEMPLATE) {
   1700                                assert fragment || isTemplateContents();
   1701                                errStrayStartTag(name);
   1702                                break starttagloop;
   1703                            } else {
   1704                                clearStackBackTo(eltPos);
   1705                                pop();
   1706                                mode = IN_TABLE;
   1707                                continue;
   1708                            }
   1709                        default:
   1710                            // fall through to IN_TABLE
   1711                    }
   1712                    // CPPONLY: MOZ_FALLTHROUGH;
   1713                case IN_TABLE:
   1714                    intableloop: for (;;) {
   1715                        switch (group) {
   1716                            case CAPTION:
   1717                                clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
   1718                                insertMarker();
   1719                                appendToCurrentNodeAndPushElement(
   1720                                        elementName,
   1721                                        attributes);
   1722                                mode = IN_CAPTION;
   1723                                attributes = null; // CPP
   1724                                break starttagloop;
   1725                            case COLGROUP:
   1726                                clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
   1727                                appendToCurrentNodeAndPushElement(
   1728                                        elementName,
   1729                                        attributes);
   1730                                mode = IN_COLUMN_GROUP;
   1731                                attributes = null; // CPP
   1732                                break starttagloop;
   1733                            case COL:
   1734                                clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
   1735                                appendToCurrentNodeAndPushElement(
   1736                                        ElementName.COLGROUP,
   1737                                        HtmlAttributes.EMPTY_ATTRIBUTES);
   1738                                mode = IN_COLUMN_GROUP;
   1739                                continue starttagloop;
   1740                            case TBODY_OR_THEAD_OR_TFOOT:
   1741                                clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
   1742                                appendToCurrentNodeAndPushElement(
   1743                                        elementName,
   1744                                        attributes);
   1745                                mode = IN_TABLE_BODY;
   1746                                attributes = null; // CPP
   1747                                break starttagloop;
   1748                            case TR:
   1749                            case TD_OR_TH:
   1750                                clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
   1751                                appendToCurrentNodeAndPushElement(
   1752                                        ElementName.TBODY,
   1753                                        HtmlAttributes.EMPTY_ATTRIBUTES);
   1754                                mode = IN_TABLE_BODY;
   1755                                continue starttagloop;
   1756                            case TEMPLATE:
   1757                                // fall through to IN_HEAD
   1758                                break intableloop;
   1759                            case TABLE:
   1760                                errTableSeenWhileTableOpen();
   1761                                eltPos = findLastInTableScope(name);
   1762                                if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   1763                                    assert fragment || isTemplateContents();
   1764                                    break starttagloop;
   1765                                }
   1766                                generateImpliedEndTags();
   1767                                if (errorHandler != null && !isCurrent("table")) {
   1768                                    errNoCheckUnclosedElementsOnStack();
   1769                                }
   1770                                while (currentPtr >= eltPos) {
   1771                                    pop();
   1772                                }
   1773                                resetTheInsertionMode();
   1774                                continue starttagloop;
   1775                            case SCRIPT:
   1776                                // XXX need to manage much more stuff
   1777                                // here if
   1778                                // supporting
   1779                                // document.write()
   1780                                appendToCurrentNodeAndPushElement(
   1781                                        elementName,
   1782                                        attributes);
   1783                                originalMode = mode;
   1784                                mode = TEXT;
   1785                                tokenizer.setStateAndEndTagExpectation(
   1786                                        Tokenizer.SCRIPT_DATA, elementName);
   1787                                attributes = null; // CPP
   1788                                break starttagloop;
   1789                            case STYLE:
   1790                                appendToCurrentNodeAndPushElement(
   1791                                        elementName,
   1792                                        attributes);
   1793                                originalMode = mode;
   1794                                mode = TEXT;
   1795                                tokenizer.setStateAndEndTagExpectation(
   1796                                        Tokenizer.RAWTEXT, elementName);
   1797                                attributes = null; // CPP
   1798                                break starttagloop;
   1799                            case INPUT:
   1800                                errStartTagInTable(name);
   1801                                if (!Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
   1802                                        "hidden",
   1803                                        attributes.getValue(AttributeName.TYPE))) {
   1804                                    break intableloop;
   1805                                }
   1806                                appendVoidInputToCurrent(
   1807                                        attributes,
   1808                                        formPointer);
   1809                                selfClosing = false;
   1810                                // [NOCPP[
   1811                                voidElement = true;
   1812                                // ]NOCPP]
   1813                                attributes = null; // CPP
   1814                                break starttagloop;
   1815                            case FORM:
   1816                                if (formPointer != null || isTemplateContents()) {
   1817                                    errFormWhenFormOpen();
   1818                                    break starttagloop;
   1819                                } else {
   1820                                    errStartTagInTable(name);
   1821                                    appendVoidFormToCurrent(attributes);
   1822                                    attributes = null; // CPP
   1823                                    break starttagloop;
   1824                                }
   1825                            default:
   1826                                errStartTagInTable(name);
   1827                                // fall through to IN_BODY
   1828                                break intableloop;
   1829                        }
   1830                    }
   1831                    // CPPONLY: MOZ_FALLTHROUGH;
   1832                case IN_CAPTION:
   1833                    switch (group) {
   1834                        case CAPTION:
   1835                        case COL:
   1836                        case COLGROUP:
   1837                        case TBODY_OR_THEAD_OR_TFOOT:
   1838                        case TR:
   1839                        case TD_OR_TH:
   1840                            eltPos = findLastInTableScope("caption");
   1841                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   1842                                assert fragment || isTemplateContents();
   1843                                errStrayStartTag(name);
   1844                                break starttagloop;
   1845                            }
   1846                            generateImpliedEndTags();
   1847                            if (errorHandler != null && currentPtr != eltPos) {
   1848                                errNoCheckUnclosedElementsOnStack();
   1849                            }
   1850                            while (currentPtr >= eltPos) {
   1851                                pop();
   1852                            }
   1853                            clearTheListOfActiveFormattingElementsUpToTheLastMarker();
   1854                            mode = IN_TABLE;
   1855                            continue;
   1856                        default:
   1857                            // fall through to IN_BODY
   1858                    }
   1859                    // CPPONLY: MOZ_FALLTHROUGH;
   1860                case IN_CELL:
   1861                    switch (group) {
   1862                        case CAPTION:
   1863                        case COL:
   1864                        case COLGROUP:
   1865                        case TBODY_OR_THEAD_OR_TFOOT:
   1866                        case TR:
   1867                        case TD_OR_TH:
   1868                            eltPos = findLastInTableScopeTdTh();
   1869                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   1870                                errNoCellToClose();
   1871                                break starttagloop;
   1872                            } else {
   1873                                closeTheCell(eltPos);
   1874                                continue;
   1875                            }
   1876                        default:
   1877                            // fall through to IN_BODY
   1878                    }
   1879                    // CPPONLY: MOZ_FALLTHROUGH;
   1880                case FRAMESET_OK:
   1881                    switch (group) {
   1882                        case FRAMESET:
   1883                            if (mode == FRAMESET_OK) {
   1884                                if (currentPtr == 0 || stack[1].getGroup() != BODY) {
   1885                                    assert fragment || isTemplateContents();
   1886                                    errStrayStartTag(name);
   1887                                    break starttagloop;
   1888                                } else {
   1889                                    errFramesetStart();
   1890                                    detachFromParent(stack[1].node);
   1891                                    while (currentPtr > 0) {
   1892                                        pop();
   1893                                    }
   1894                                    appendToCurrentNodeAndPushElement(
   1895                                            elementName,
   1896                                            attributes);
   1897                                    mode = IN_FRAMESET;
   1898                                    attributes = null; // CPP
   1899                                    break starttagloop;
   1900                                }
   1901                            } else {
   1902                                errStrayStartTag(name);
   1903                                break starttagloop;
   1904                            }
   1905                            // NOT falling through!
   1906                        case PRE_OR_LISTING:
   1907                        case LI:
   1908                        case DD_OR_DT:
   1909                        case BUTTON:
   1910                        case MARQUEE_OR_APPLET:
   1911                        case OBJECT:
   1912                        case TABLE:
   1913                        case AREA_OR_WBR:
   1914                        case KEYGEN:
   1915                        case BR:
   1916                        case EMBED:
   1917                        case IMG:
   1918                        case INPUT:
   1919                        case HR:
   1920                        case TEXTAREA:
   1921                        case XMP:
   1922                        case IFRAME:
   1923                        case SELECT:
   1924                            if (mode == FRAMESET_OK
   1925                                    && !(group == INPUT && Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
   1926                                            "hidden",
   1927                                            attributes.getValue(AttributeName.TYPE)))) {
   1928                                framesetOk = false;
   1929                                mode = IN_BODY;
   1930                            }
   1931                            // CPPONLY: MOZ_FALLTHROUGH;
   1932                        default:
   1933                            // fall through to IN_BODY
   1934                    }
   1935                    // CPPONLY: MOZ_FALLTHROUGH;
   1936                case IN_BODY:
   1937                    inbodyloop: for (;;) {
   1938                        switch (group) {
   1939                            case HTML:
   1940                                errStrayStartTag(name);
   1941                                if (!fragment && !isTemplateContents()) {
   1942                                    addAttributesToHtml(attributes);
   1943                                    attributes = null; // CPP
   1944                                }
   1945                                break starttagloop;
   1946                            case BASE:
   1947                            case LINK_OR_BASEFONT_OR_BGSOUND:
   1948                            case META:
   1949                            case STYLE:
   1950                            case SCRIPT:
   1951                            case TITLE:
   1952                            case TEMPLATE:
   1953                                // Fall through to IN_HEAD
   1954                                break inbodyloop;
   1955                            case BODY:
   1956                                if (currentPtr == 0 || stack[1].getGroup() != BODY || isTemplateContents()) {
   1957                                    assert fragment || isTemplateContents();
   1958                                    errStrayStartTag(name);
   1959                                    break starttagloop;
   1960                                }
   1961                                errFooSeenWhenFooOpen(name);
   1962                                framesetOk = false;
   1963                                if (mode == FRAMESET_OK) {
   1964                                    mode = IN_BODY;
   1965                                }
   1966                                if (addAttributesToBody(attributes)) {
   1967                                    attributes = null; // CPP
   1968                                }
   1969                                break starttagloop;
   1970                            case P:
   1971                            case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
   1972                            case UL_OR_OL_OR_DL:
   1973                            case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SEARCH_OR_SECTION_OR_SUMMARY:
   1974                                implicitlyCloseP();
   1975                                appendToCurrentNodeAndPushElementMayFoster(
   1976                                        elementName,
   1977                                        attributes);
   1978                                attributes = null; // CPP
   1979                                break starttagloop;
   1980                            case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
   1981                                implicitlyCloseP();
   1982                                if (stack[currentPtr].getGroup() == H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
   1983                                    errHeadingWhenHeadingOpen();
   1984                                    pop();
   1985                                }
   1986                                appendToCurrentNodeAndPushElementMayFoster(
   1987                                        elementName,
   1988                                        attributes);
   1989                                attributes = null; // CPP
   1990                                break starttagloop;
   1991                            case FIELDSET:
   1992                                implicitlyCloseP();
   1993                                appendToCurrentNodeAndPushElementMayFoster(
   1994                                        elementName,
   1995                                        attributes, formPointer);
   1996                                attributes = null; // CPP
   1997                                break starttagloop;
   1998                            case PRE_OR_LISTING:
   1999                                implicitlyCloseP();
   2000                                appendToCurrentNodeAndPushElementMayFoster(
   2001                                        elementName,
   2002                                        attributes);
   2003                                needToDropLF = true;
   2004                                attributes = null; // CPP
   2005                                break starttagloop;
   2006                            case FORM:
   2007                                if (formPointer != null && !isTemplateContents()) {
   2008                                    errFormWhenFormOpen();
   2009                                    break starttagloop;
   2010                                } else {
   2011                                    implicitlyCloseP();
   2012                                    appendToCurrentNodeAndPushFormElementMayFoster(attributes);
   2013                                    attributes = null; // CPP
   2014                                    break starttagloop;
   2015                                }
   2016                            case LI:
   2017                            case DD_OR_DT:
   2018                                eltPos = currentPtr;
   2019                                for (;;) {
   2020                                    StackNode<T> node = stack[eltPos]; // weak
   2021                                    // ref
   2022                                    if (node.getGroup() == group) { // LI or
   2023                                        // DD_OR_DT
   2024                                        generateImpliedEndTagsExceptFor(node.name);
   2025                                        if (errorHandler != null
   2026                                                && eltPos != currentPtr) {
   2027                                            errUnclosedElementsImplied(eltPos, name);
   2028                                        }
   2029                                        while (currentPtr >= eltPos) {
   2030                                            pop();
   2031                                        }
   2032                                        break;
   2033                                    } else if (eltPos == 0 || (node.isSpecial()
   2034                                            && (node.ns != "http://www.w3.org/1999/xhtml"
   2035                                                    || (node.name != "p"
   2036                                                            && node.name != "address"
   2037                                                            && node.name != "div")))) {
   2038                                        break;
   2039                                    }
   2040                                    eltPos--;
   2041                                }
   2042                                implicitlyCloseP();
   2043                                appendToCurrentNodeAndPushElementMayFoster(
   2044                                        elementName,
   2045                                        attributes);
   2046                                attributes = null; // CPP
   2047                                break starttagloop;
   2048                            case PLAINTEXT:
   2049                                implicitlyCloseP();
   2050                                appendToCurrentNodeAndPushElementMayFoster(
   2051                                        elementName,
   2052                                        attributes);
   2053                                tokenizer.setStateAndEndTagExpectation(
   2054                                        Tokenizer.PLAINTEXT, elementName);
   2055                                attributes = null; // CPP
   2056                                break starttagloop;
   2057                            case A:
   2058                                int activeAPos = findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker("a");
   2059                                if (activeAPos != -1) {
   2060                                    errFooSeenWhenFooOpen(name);
   2061                                    StackNode<T> activeA = listOfActiveFormattingElements[activeAPos];
   2062                                    activeA.retain();
   2063                                    adoptionAgencyEndTag("a");
   2064                                    removeFromStack(activeA);
   2065                                    activeAPos = findInListOfActiveFormattingElements(activeA);
   2066                                    if (activeAPos != -1) {
   2067                                        removeFromListOfActiveFormattingElements(activeAPos);
   2068                                    }
   2069                                    activeA.release(this);
   2070                                }
   2071                                reconstructTheActiveFormattingElements();
   2072                                appendToCurrentNodeAndPushFormattingElementMayFoster(
   2073                                        elementName,
   2074                                        attributes);
   2075                                attributes = null; // CPP
   2076                                break starttagloop;
   2077                            case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
   2078                            case FONT:
   2079                                reconstructTheActiveFormattingElements();
   2080                                maybeForgetEarlierDuplicateFormattingElement(elementName.getName(), attributes);
   2081                                appendToCurrentNodeAndPushFormattingElementMayFoster(
   2082                                        elementName,
   2083                                        attributes);
   2084                                attributes = null; // CPP
   2085                                break starttagloop;
   2086                            case NOBR:
   2087                                reconstructTheActiveFormattingElements();
   2088                                if (TreeBuilder.NOT_FOUND_ON_STACK != findLastInScope("nobr")) {
   2089                                    errFooSeenWhenFooOpen(name);
   2090                                    adoptionAgencyEndTag("nobr");
   2091                                    reconstructTheActiveFormattingElements();
   2092                                }
   2093                                appendToCurrentNodeAndPushFormattingElementMayFoster(
   2094                                        elementName,
   2095                                        attributes);
   2096                                attributes = null; // CPP
   2097                                break starttagloop;
   2098                            case BUTTON:
   2099                                eltPos = findLastInScope(name);
   2100                                if (eltPos != TreeBuilder.NOT_FOUND_ON_STACK) {
   2101                                    errFooSeenWhenFooOpen(name);
   2102                                    generateImpliedEndTags();
   2103                                    if (errorHandler != null
   2104                                            && !isCurrent(name)) {
   2105                                        errUnclosedElementsImplied(eltPos, name);
   2106                                    }
   2107                                    while (currentPtr >= eltPos) {
   2108                                        pop();
   2109                                    }
   2110                                    continue starttagloop;
   2111                                } else {
   2112                                    reconstructTheActiveFormattingElements();
   2113                                    appendToCurrentNodeAndPushElementMayFoster(
   2114                                            elementName,
   2115                                            attributes, formPointer);
   2116                                    attributes = null; // CPP
   2117                                    break starttagloop;
   2118                                }
   2119                            case OBJECT:
   2120                                reconstructTheActiveFormattingElements();
   2121                                appendToCurrentNodeAndPushElementMayFoster(
   2122                                        elementName,
   2123                                        attributes, formPointer);
   2124                                insertMarker();
   2125                                attributes = null; // CPP
   2126                                break starttagloop;
   2127                            case MARQUEE_OR_APPLET:
   2128                                reconstructTheActiveFormattingElements();
   2129                                appendToCurrentNodeAndPushElementMayFoster(
   2130                                        elementName,
   2131                                        attributes);
   2132                                insertMarker();
   2133                                attributes = null; // CPP
   2134                                break starttagloop;
   2135                            case TABLE:
   2136                                // The only quirk. Blame Hixie and
   2137                                // Acid2.
   2138                                if (!quirks) {
   2139                                    implicitlyCloseP();
   2140                                }
   2141                                appendToCurrentNodeAndPushElementMayFoster(
   2142                                        elementName,
   2143                                        attributes);
   2144                                mode = IN_TABLE;
   2145                                attributes = null; // CPP
   2146                                break starttagloop;
   2147                            case BR:
   2148                            case EMBED:
   2149                            case AREA_OR_WBR:
   2150                            case KEYGEN:
   2151                                reconstructTheActiveFormattingElements();
   2152                                // FALL THROUGH to PARAM_OR_SOURCE_OR_TRACK
   2153                                // CPPONLY: MOZ_FALLTHROUGH;
   2154                            case PARAM_OR_SOURCE_OR_TRACK:
   2155                                appendVoidElementToCurrentMayFoster(
   2156                                        elementName,
   2157                                        attributes);
   2158                                selfClosing = false;
   2159                                // [NOCPP[
   2160                                voidElement = true;
   2161                                // ]NOCPP]
   2162                                attributes = null; // CPP
   2163                                break starttagloop;
   2164                            case HR:
   2165                                implicitlyCloseP();
   2166                                appendVoidElementToCurrentMayFoster(
   2167                                        elementName,
   2168                                        attributes);
   2169                                selfClosing = false;
   2170                                // [NOCPP[
   2171                                voidElement = true;
   2172                                // ]NOCPP]
   2173                                attributes = null; // CPP
   2174                                break starttagloop;
   2175                            case IMAGE:
   2176                                errImage();
   2177                                elementName = ElementName.IMG;
   2178                                continue starttagloop;
   2179                            case IMG:
   2180                            case INPUT:
   2181                                reconstructTheActiveFormattingElements();
   2182                                appendVoidElementToCurrentMayFoster(
   2183                                        elementName, attributes,
   2184                                        formPointer);
   2185                                selfClosing = false;
   2186                                // [NOCPP[
   2187                                voidElement = true;
   2188                                // ]NOCPP]
   2189                                attributes = null; // CPP
   2190                                break starttagloop;
   2191                            case TEXTAREA:
   2192                                appendToCurrentNodeAndPushElementMayFoster(
   2193                                        elementName,
   2194                                        attributes, formPointer);
   2195                                tokenizer.setStateAndEndTagExpectation(
   2196                                        Tokenizer.RCDATA, elementName);
   2197                                originalMode = mode;
   2198                                mode = TEXT;
   2199                                needToDropLF = true;
   2200                                attributes = null; // CPP
   2201                                break starttagloop;
   2202                            case XMP:
   2203                                implicitlyCloseP();
   2204                                reconstructTheActiveFormattingElements();
   2205                                appendToCurrentNodeAndPushElementMayFoster(
   2206                                        elementName,
   2207                                        attributes);
   2208                                originalMode = mode;
   2209                                mode = TEXT;
   2210                                tokenizer.setStateAndEndTagExpectation(
   2211                                        Tokenizer.RAWTEXT, elementName);
   2212                                attributes = null; // CPP
   2213                                break starttagloop;
   2214                            case NOSCRIPT:
   2215                                if (!scriptingEnabled) {
   2216                                    reconstructTheActiveFormattingElements();
   2217                                    appendToCurrentNodeAndPushElementMayFoster(
   2218                                            elementName,
   2219                                            attributes);
   2220                                    attributes = null; // CPP
   2221                                    break starttagloop;
   2222                                }
   2223                                // CPPONLY: MOZ_FALLTHROUGH;
   2224                            case NOFRAMES:
   2225                            case IFRAME:
   2226                            case NOEMBED:
   2227                                startTagGenericRawText(elementName, attributes);
   2228                                attributes = null; // CPP
   2229                                break starttagloop;
   2230                            case SELECT:
   2231                                reconstructTheActiveFormattingElements();
   2232                                appendToCurrentNodeAndPushElementMayFoster(
   2233                                        elementName,
   2234                                        attributes, formPointer);
   2235                                switch (mode) {
   2236                                    case IN_TABLE:
   2237                                    case IN_CAPTION:
   2238                                    case IN_COLUMN_GROUP:
   2239                                    case IN_TABLE_BODY:
   2240                                    case IN_ROW:
   2241                                    case IN_CELL:
   2242                                        mode = IN_SELECT_IN_TABLE;
   2243                                        break;
   2244                                    default:
   2245                                        mode = IN_SELECT;
   2246                                        break;
   2247                                }
   2248                                attributes = null; // CPP
   2249                                break starttagloop;
   2250                            case OPTGROUP:
   2251                            case OPTION:
   2252                                if (isCurrent("option")) {
   2253                                    pop();
   2254                                }
   2255                                reconstructTheActiveFormattingElements();
   2256                                appendToCurrentNodeAndPushElementMayFoster(
   2257                                        elementName,
   2258                                        attributes);
   2259                                attributes = null; // CPP
   2260                                break starttagloop;
   2261                            case RB_OR_RTC:
   2262                                eltPos = findLastInScope("ruby");
   2263                                if (eltPos != NOT_FOUND_ON_STACK) {
   2264                                    generateImpliedEndTags();
   2265                                }
   2266                                if (eltPos != currentPtr) {
   2267                                    if (eltPos == NOT_FOUND_ON_STACK) {
   2268                                        errStartTagSeenWithoutRuby(name);
   2269                                    } else {
   2270                                        errUnclosedChildrenInRuby();
   2271                                    }
   2272                                }
   2273                                appendToCurrentNodeAndPushElementMayFoster(
   2274                                        elementName,
   2275                                        attributes);
   2276                                attributes = null; // CPP
   2277                                break starttagloop;
   2278                            case RT_OR_RP:
   2279                                eltPos = findLastInScope("ruby");
   2280                                if (eltPos != NOT_FOUND_ON_STACK) {
   2281                                    generateImpliedEndTagsExceptFor("rtc");
   2282                                }
   2283                                if (eltPos != currentPtr) {
   2284                                    if (!isCurrent("rtc")) {
   2285                                        if (eltPos == NOT_FOUND_ON_STACK) {
   2286                                            errStartTagSeenWithoutRuby(name);
   2287                                        } else {
   2288                                            errUnclosedChildrenInRuby();
   2289                                        }
   2290                                    }
   2291                                }
   2292                                appendToCurrentNodeAndPushElementMayFoster(
   2293                                        elementName,
   2294                                        attributes);
   2295                                attributes = null; // CPP
   2296                                break starttagloop;
   2297                            case MATH:
   2298                                reconstructTheActiveFormattingElements();
   2299                                attributes.adjustForMath();
   2300                                if (selfClosing) {
   2301                                    appendVoidElementToCurrentMayFosterMathML(
   2302                                            elementName, attributes);
   2303                                    selfClosing = false;
   2304                                } else {
   2305                                    appendToCurrentNodeAndPushElementMayFosterMathML(
   2306                                            elementName, attributes);
   2307                                }
   2308                                attributes = null; // CPP
   2309                                break starttagloop;
   2310                            case SVG:
   2311                                reconstructTheActiveFormattingElements();
   2312                                attributes.adjustForSvg();
   2313                                if (selfClosing) {
   2314                                    appendVoidElementToCurrentMayFosterSVG(
   2315                                            elementName,
   2316                                            attributes);
   2317                                    selfClosing = false;
   2318                                } else {
   2319                                    appendToCurrentNodeAndPushElementMayFosterSVG(
   2320                                            elementName, attributes);
   2321                                }
   2322                                attributes = null; // CPP
   2323                                break starttagloop;
   2324                            case CAPTION:
   2325                            case COL:
   2326                            case COLGROUP:
   2327                            case TBODY_OR_THEAD_OR_TFOOT:
   2328                            case TR:
   2329                            case TD_OR_TH:
   2330                            case FRAME:
   2331                            case FRAMESET:
   2332                            case HEAD:
   2333                                errStrayStartTag(name);
   2334                                break starttagloop;
   2335                            case OUTPUT:
   2336                                reconstructTheActiveFormattingElements();
   2337                                appendToCurrentNodeAndPushElementMayFoster(
   2338                                        elementName,
   2339                                        attributes, formPointer);
   2340                                attributes = null; // CPP
   2341                                break starttagloop;
   2342                            default:
   2343                                reconstructTheActiveFormattingElements();
   2344                                appendToCurrentNodeAndPushElementMayFoster(
   2345                                        elementName,
   2346                                        attributes);
   2347                                attributes = null; // CPP
   2348                                break starttagloop;
   2349                        }
   2350                    }
   2351                    // CPPONLY: MOZ_FALLTHROUGH;
   2352                case IN_HEAD:
   2353                    inheadloop: for (;;) {
   2354                        switch (group) {
   2355                            case HTML:
   2356                                errStrayStartTag(name);
   2357                                if (!fragment && !isTemplateContents()) {
   2358                                    addAttributesToHtml(attributes);
   2359                                    attributes = null; // CPP
   2360                                }
   2361                                break starttagloop;
   2362                            case BASE:
   2363                            case LINK_OR_BASEFONT_OR_BGSOUND:
   2364                                appendVoidElementToCurrentMayFoster(
   2365                                        elementName,
   2366                                        attributes);
   2367                                selfClosing = false;
   2368                                // [NOCPP[
   2369                                voidElement = true;
   2370                                // ]NOCPP]
   2371                                attributes = null; // CPP
   2372                                break starttagloop;
   2373                            case META:
   2374                                // Fall through to IN_HEAD_NOSCRIPT
   2375                                break inheadloop;
   2376                            case TITLE:
   2377                                startTagTitleInHead(elementName, attributes);
   2378                                attributes = null; // CPP
   2379                                break starttagloop;
   2380                            case NOSCRIPT:
   2381                                if (scriptingEnabled) {
   2382                                    appendToCurrentNodeAndPushElement(
   2383                                            elementName,
   2384                                            attributes);
   2385                                    originalMode = mode;
   2386                                    mode = TEXT;
   2387                                    tokenizer.setStateAndEndTagExpectation(
   2388                                            Tokenizer.RAWTEXT, elementName);
   2389                                } else {
   2390                                    appendToCurrentNodeAndPushElementMayFoster(
   2391                                            elementName,
   2392                                            attributes);
   2393                                    mode = IN_HEAD_NOSCRIPT;
   2394                                }
   2395                                attributes = null; // CPP
   2396                                break starttagloop;
   2397                            case SCRIPT:
   2398                                startTagScriptInHead(elementName, attributes);
   2399                                attributes = null; // CPP
   2400                                break starttagloop;
   2401                            case STYLE:
   2402                            case NOFRAMES:
   2403                                startTagGenericRawText(elementName, attributes);
   2404                                attributes = null; // CPP
   2405                                break starttagloop;
   2406                            case HEAD:
   2407                                /* Parse error. */
   2408                                errFooSeenWhenFooOpen(name);
   2409                                /* Ignore the token. */
   2410                                break starttagloop;
   2411                            case TEMPLATE:
   2412                                startTagTemplateInHead(elementName, attributes);
   2413                                attributes = null; // CPP
   2414                                break starttagloop;
   2415                            default:
   2416                                pop();
   2417                                mode = AFTER_HEAD;
   2418                                continue starttagloop;
   2419                        }
   2420                    }
   2421                    // CPPONLY: MOZ_FALLTHROUGH;
   2422                case IN_HEAD_NOSCRIPT:
   2423                    switch (group) {
   2424                        case HTML:
   2425                            // XXX did Hixie really mean to omit "base"
   2426                            // here?
   2427                            errStrayStartTag(name);
   2428                            if (!fragment && !isTemplateContents()) {
   2429                                addAttributesToHtml(attributes);
   2430                                attributes = null; // CPP
   2431                            }
   2432                            break starttagloop;
   2433                        case LINK_OR_BASEFONT_OR_BGSOUND:
   2434                            appendVoidElementToCurrentMayFoster(
   2435                                    elementName,
   2436                                    attributes);
   2437                            selfClosing = false;
   2438                            // [NOCPP[
   2439                            voidElement = true;
   2440                            // ]NOCPP]
   2441                            attributes = null; // CPP
   2442                            break starttagloop;
   2443                        case META:
   2444                            checkMetaCharset(attributes);
   2445                            appendVoidElementToCurrentMayFoster(
   2446                                    elementName,
   2447                                    attributes);
   2448                            selfClosing = false;
   2449                            // [NOCPP[
   2450                            voidElement = true;
   2451                            // ]NOCPP]
   2452                            attributes = null; // CPP
   2453                            break starttagloop;
   2454                        case STYLE:
   2455                        case NOFRAMES:
   2456                            appendToCurrentNodeAndPushElement(
   2457                                    elementName,
   2458                                    attributes);
   2459                            originalMode = mode;
   2460                            mode = TEXT;
   2461                            tokenizer.setStateAndEndTagExpectation(
   2462                                    Tokenizer.RAWTEXT, elementName);
   2463                            attributes = null; // CPP
   2464                            break starttagloop;
   2465                        case HEAD:
   2466                            errFooSeenWhenFooOpen(name);
   2467                            break starttagloop;
   2468                        case NOSCRIPT:
   2469                            errFooSeenWhenFooOpen(name);
   2470                            break starttagloop;
   2471                        default:
   2472                            errBadStartTagInNoscriptInHead(name);
   2473                            pop();
   2474                            mode = IN_HEAD;
   2475                            continue;
   2476                    }
   2477                case IN_COLUMN_GROUP:
   2478                    switch (group) {
   2479                        case HTML:
   2480                            errStrayStartTag(name);
   2481                            if (!fragment && !isTemplateContents()) {
   2482                                addAttributesToHtml(attributes);
   2483                                attributes = null; // CPP
   2484                            }
   2485                            break starttagloop;
   2486                        case COL:
   2487                            appendVoidElementToCurrentMayFoster(
   2488                                    elementName,
   2489                                    attributes);
   2490                            selfClosing = false;
   2491                            // [NOCPP[
   2492                            voidElement = true;
   2493                            // ]NOCPP]
   2494                            attributes = null; // CPP
   2495                            break starttagloop;
   2496                        case TEMPLATE:
   2497                            startTagTemplateInHead(elementName, attributes);
   2498                            attributes = null; // CPP
   2499                            break starttagloop;
   2500                        default:
   2501                            if (currentPtr == 0 || stack[currentPtr].getGroup() == TEMPLATE) {
   2502                                assert fragment || isTemplateContents();
   2503                                errGarbageInColgroup();
   2504                                break starttagloop;
   2505                            }
   2506                            pop();
   2507                            mode = IN_TABLE;
   2508                            continue;
   2509                    }
   2510                case IN_SELECT_IN_TABLE:
   2511                    switch (group) {
   2512                        case CAPTION:
   2513                        case TBODY_OR_THEAD_OR_TFOOT:
   2514                        case TR:
   2515                        case TD_OR_TH:
   2516                        case TABLE:
   2517                            errStartTagWithSelectOpen(name);
   2518                            eltPos = findLastInTableScope("select");
   2519                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   2520                                assert fragment;
   2521                                break starttagloop; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375
   2522                            }
   2523                            while (currentPtr >= eltPos) {
   2524                                pop();
   2525                            }
   2526                            resetTheInsertionMode();
   2527                            continue;
   2528                        default:
   2529                            // fall through to IN_SELECT
   2530                    }
   2531                    // CPPONLY: MOZ_FALLTHROUGH;
   2532                case IN_SELECT:
   2533                    switch (group) {
   2534                        case HTML:
   2535                            errStrayStartTag(name);
   2536                            if (!fragment) {
   2537                                addAttributesToHtml(attributes);
   2538                                attributes = null; // CPP
   2539                            }
   2540                            break starttagloop;
   2541                        case OPTION:
   2542                            if (isCurrent("option")) {
   2543                                pop();
   2544                            }
   2545                            appendToCurrentNodeAndPushElement(
   2546                                    elementName,
   2547                                    attributes);
   2548                            attributes = null; // CPP
   2549                            break starttagloop;
   2550                        case OPTGROUP:
   2551                            if (isCurrent("option")) {
   2552                                pop();
   2553                            }
   2554                            if (isCurrent("optgroup")) {
   2555                                pop();
   2556                            }
   2557                            appendToCurrentNodeAndPushElement(
   2558                                    elementName,
   2559                                    attributes);
   2560                            attributes = null; // CPP
   2561                            break starttagloop;
   2562                        case SELECT:
   2563                            errStartSelectWhereEndSelectExpected();
   2564                            eltPos = findLastInTableScope(name);
   2565                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   2566                                assert fragment;
   2567                                errNoSelectInTableScope();
   2568                                break starttagloop;
   2569                            } else {
   2570                                while (currentPtr >= eltPos) {
   2571                                    pop();
   2572                                }
   2573                                resetTheInsertionMode();
   2574                                break starttagloop;
   2575                            }
   2576                        case INPUT:
   2577                        case TEXTAREA:
   2578                            errStartTagWithSelectOpen(name);
   2579                            eltPos = findLastInTableScope("select");
   2580                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   2581                                assert fragment;
   2582                                break starttagloop;
   2583                            }
   2584                            while (currentPtr >= eltPos) {
   2585                                pop();
   2586                            }
   2587                            resetTheInsertionMode();
   2588                            continue;
   2589                        case SCRIPT:
   2590                            startTagScriptInHead(elementName, attributes);
   2591                            attributes = null; // CPP
   2592                            break starttagloop;
   2593                        case TEMPLATE:
   2594                            startTagTemplateInHead(elementName, attributes);
   2595                            attributes = null; // CPP
   2596                            break starttagloop;
   2597                        case HR:
   2598                            if (isCurrent("option")) {
   2599                                pop();
   2600                            }
   2601                            if (isCurrent("optgroup")) {
   2602                                pop();
   2603                            }
   2604                            appendVoidElementToCurrent(elementName, attributes);
   2605                            selfClosing = false;
   2606                            // [NOCPP[
   2607                            voidElement = true;
   2608                            // ]NOCPP]
   2609                            attributes = null; // CPP
   2610                            break starttagloop;
   2611                        default:
   2612                            errStrayStartTag(name);
   2613                            break starttagloop;
   2614                    }
   2615                case AFTER_BODY:
   2616                    switch (group) {
   2617                        case HTML:
   2618                            errStrayStartTag(name);
   2619                            if (!fragment && !isTemplateContents()) {
   2620                                addAttributesToHtml(attributes);
   2621                                attributes = null; // CPP
   2622                            }
   2623                            break starttagloop;
   2624                        default:
   2625                            errStrayStartTag(name);
   2626                            mode = framesetOk ? FRAMESET_OK : IN_BODY;
   2627                            continue;
   2628                    }
   2629                case IN_FRAMESET:
   2630                    switch (group) {
   2631                        case FRAMESET:
   2632                            appendToCurrentNodeAndPushElement(
   2633                                    elementName,
   2634                                    attributes);
   2635                            attributes = null; // CPP
   2636                            break starttagloop;
   2637                        case FRAME:
   2638                            appendVoidElementToCurrentMayFoster(
   2639                                    elementName,
   2640                                    attributes);
   2641                            selfClosing = false;
   2642                            // [NOCPP[
   2643                            voidElement = true;
   2644                            // ]NOCPP]
   2645                            attributes = null; // CPP
   2646                            break starttagloop;
   2647                        default:
   2648                            // fall through to AFTER_FRAMESET
   2649                    }
   2650                    // CPPONLY: MOZ_FALLTHROUGH;
   2651                case AFTER_FRAMESET:
   2652                    switch (group) {
   2653                        case HTML:
   2654                            errStrayStartTag(name);
   2655                            if (!fragment && !isTemplateContents()) {
   2656                                addAttributesToHtml(attributes);
   2657                                attributes = null; // CPP
   2658                            }
   2659                            break starttagloop;
   2660                        case NOFRAMES:
   2661                            appendToCurrentNodeAndPushElement(
   2662                                    elementName,
   2663                                    attributes);
   2664                            originalMode = mode;
   2665                            mode = TEXT;
   2666                            tokenizer.setStateAndEndTagExpectation(
   2667                                    Tokenizer.RAWTEXT, elementName);
   2668                            attributes = null; // CPP
   2669                            break starttagloop;
   2670                        default:
   2671                            errStrayStartTag(name);
   2672                            break starttagloop;
   2673                    }
   2674                case INITIAL:
   2675                    /*
   2676                     * Parse error.
   2677                     */
   2678                    errStartTagWithoutDoctype();
   2679                    /*
   2680                     *
   2681                     * Set the document to quirks mode.
   2682                     */
   2683                    documentModeInternal(DocumentMode.QUIRKS_MODE, null, null);
   2684                    /*
   2685                     * Then, switch to the root element mode of the tree
   2686                     * construction stage
   2687                     */
   2688                    mode = BEFORE_HTML;
   2689                    /*
   2690                     * and reprocess the current token.
   2691                     */
   2692                    continue;
   2693                case BEFORE_HTML:
   2694                    switch (group) {
   2695                        case HTML:
   2696                            // optimize error check and streaming SAX by
   2697                            // hoisting
   2698                            // "html" handling here.
   2699                            if (attributes == HtmlAttributes.EMPTY_ATTRIBUTES) {
   2700                                // This has the right magic side effect
   2701                                // that
   2702                                // it
   2703                                // makes attributes in SAX Tree mutable.
   2704                                appendHtmlElementToDocumentAndPush();
   2705                            } else {
   2706                                appendHtmlElementToDocumentAndPush(attributes);
   2707                            }
   2708                            // XXX application cache should fire here
   2709                            mode = BEFORE_HEAD;
   2710                            attributes = null; // CPP
   2711                            break starttagloop;
   2712                        default:
   2713                            /*
   2714                             * Create an HTMLElement node with the tag name
   2715                             * html, in the HTML namespace. Append it to the
   2716                             * Document object.
   2717                             */
   2718                            appendHtmlElementToDocumentAndPush();
   2719                            /* Switch to the main mode */
   2720                            mode = BEFORE_HEAD;
   2721                            /*
   2722                             * reprocess the current token.
   2723                             */
   2724                            continue;
   2725                    }
   2726                case BEFORE_HEAD:
   2727                    switch (group) {
   2728                        case HTML:
   2729                            errStrayStartTag(name);
   2730                            if (!fragment && !isTemplateContents()) {
   2731                                addAttributesToHtml(attributes);
   2732                                attributes = null; // CPP
   2733                            }
   2734                            break starttagloop;
   2735                        case HEAD:
   2736                            /*
   2737                             * A start tag whose tag name is "head"
   2738                             *
   2739                             * Create an element for the token.
   2740                             *
   2741                             * Set the head element pointer to this new element
   2742                             * node.
   2743                             *
   2744                             * Append the new element to the current node and
   2745                             * push it onto the stack of open elements.
   2746                             */
   2747                            appendToCurrentNodeAndPushHeadElement(attributes);
   2748                            /*
   2749                             * Change the insertion mode to "in head".
   2750                             */
   2751                            mode = IN_HEAD;
   2752                            attributes = null; // CPP
   2753                            break starttagloop;
   2754                        default:
   2755                            /*
   2756                             * Any other start tag token
   2757                             *
   2758                             * Act as if a start tag token with the tag name
   2759                             * "head" and no attributes had been seen,
   2760                             */
   2761                            appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
   2762                            mode = IN_HEAD;
   2763                            /*
   2764                             * then reprocess the current token.
   2765                             *
   2766                             * This will result in an empty head element being
   2767                             * generated, with the current token being
   2768                             * reprocessed in the "after head" insertion mode.
   2769                             */
   2770                            continue;
   2771                    }
   2772                case AFTER_HEAD:
   2773                    switch (group) {
   2774                        case HTML:
   2775                            errStrayStartTag(name);
   2776                            if (!fragment && !isTemplateContents()) {
   2777                                addAttributesToHtml(attributes);
   2778                                attributes = null; // CPP
   2779                            }
   2780                            break starttagloop;
   2781                        case BODY:
   2782                            if (attributes.getLength() == 0) {
   2783                                // This has the right magic side effect
   2784                                // that
   2785                                // it
   2786                                // makes attributes in SAX Tree mutable.
   2787                                appendToCurrentNodeAndPushBodyElement();
   2788                            } else {
   2789                                appendToCurrentNodeAndPushBodyElement(attributes);
   2790                            }
   2791                            framesetOk = false;
   2792                            mode = IN_BODY;
   2793                            attributes = null; // CPP
   2794                            break starttagloop;
   2795                        case FRAMESET:
   2796                            appendToCurrentNodeAndPushElement(
   2797                                    elementName,
   2798                                    attributes);
   2799                            mode = IN_FRAMESET;
   2800                            attributes = null; // CPP
   2801                            break starttagloop;
   2802                        case TEMPLATE:
   2803                            errFooBetweenHeadAndBody(name);
   2804                            pushHeadPointerOntoStack();
   2805                            StackNode<T> headOnStack = stack[currentPtr];
   2806                            startTagTemplateInHead(elementName, attributes);
   2807                            removeFromStack(headOnStack);
   2808                            attributes = null; // CPP
   2809                            break starttagloop;
   2810                        case BASE:
   2811                        case LINK_OR_BASEFONT_OR_BGSOUND:
   2812                            errFooBetweenHeadAndBody(name);
   2813                            pushHeadPointerOntoStack();
   2814                            appendVoidElementToCurrentMayFoster(
   2815                                    elementName,
   2816                                    attributes);
   2817                            selfClosing = false;
   2818                            // [NOCPP[
   2819                            voidElement = true;
   2820                            // ]NOCPP]
   2821                            pop(); // head
   2822                            attributes = null; // CPP
   2823                            break starttagloop;
   2824                        case META:
   2825                            errFooBetweenHeadAndBody(name);
   2826                            checkMetaCharset(attributes);
   2827                            pushHeadPointerOntoStack();
   2828                            appendVoidElementToCurrentMayFoster(
   2829                                    elementName,
   2830                                    attributes);
   2831                            selfClosing = false;
   2832                            // [NOCPP[
   2833                            voidElement = true;
   2834                            // ]NOCPP]
   2835                            pop(); // head
   2836                            attributes = null; // CPP
   2837                            break starttagloop;
   2838                        case SCRIPT:
   2839                            errFooBetweenHeadAndBody(name);
   2840                            pushHeadPointerOntoStack();
   2841                            appendToCurrentNodeAndPushElement(
   2842                                    elementName,
   2843                                    attributes);
   2844                            originalMode = mode;
   2845                            mode = TEXT;
   2846                            tokenizer.setStateAndEndTagExpectation(
   2847                                    Tokenizer.SCRIPT_DATA, elementName);
   2848                            attributes = null; // CPP
   2849                            break starttagloop;
   2850                        case STYLE:
   2851                        case NOFRAMES:
   2852                            errFooBetweenHeadAndBody(name);
   2853                            pushHeadPointerOntoStack();
   2854                            appendToCurrentNodeAndPushElement(
   2855                                    elementName,
   2856                                    attributes);
   2857                            originalMode = mode;
   2858                            mode = TEXT;
   2859                            tokenizer.setStateAndEndTagExpectation(
   2860                                    Tokenizer.RAWTEXT, elementName);
   2861                            attributes = null; // CPP
   2862                            break starttagloop;
   2863                        case TITLE:
   2864                            errFooBetweenHeadAndBody(name);
   2865                            pushHeadPointerOntoStack();
   2866                            appendToCurrentNodeAndPushElement(
   2867                                    elementName,
   2868                                    attributes);
   2869                            originalMode = mode;
   2870                            mode = TEXT;
   2871                            tokenizer.setStateAndEndTagExpectation(
   2872                                    Tokenizer.RCDATA, elementName);
   2873                            attributes = null; // CPP
   2874                            break starttagloop;
   2875                        case HEAD:
   2876                            errStrayStartTag(name);
   2877                            break starttagloop;
   2878                        default:
   2879                            appendToCurrentNodeAndPushBodyElement();
   2880                            mode = FRAMESET_OK;
   2881                            continue;
   2882                    }
   2883                case AFTER_AFTER_BODY:
   2884                    switch (group) {
   2885                        case HTML:
   2886                            errStrayStartTag(name);
   2887                            if (!fragment && !isTemplateContents()) {
   2888                                addAttributesToHtml(attributes);
   2889                                attributes = null; // CPP
   2890                            }
   2891                            break starttagloop;
   2892                        default:
   2893                            errStrayStartTag(name);
   2894                            fatal();
   2895                            mode = framesetOk ? FRAMESET_OK : IN_BODY;
   2896                            continue;
   2897                    }
   2898                case AFTER_AFTER_FRAMESET:
   2899                    switch (group) {
   2900                        case HTML:
   2901                            errStrayStartTag(name);
   2902                            if (!fragment && !isTemplateContents()) {
   2903                                addAttributesToHtml(attributes);
   2904                                attributes = null; // CPP
   2905                            }
   2906                            break starttagloop;
   2907                        case NOFRAMES:
   2908                            startTagGenericRawText(elementName, attributes);
   2909                            attributes = null; // CPP
   2910                            break starttagloop;
   2911                        default:
   2912                            errStrayStartTag(name);
   2913                            break starttagloop;
   2914                    }
   2915                case TEXT:
   2916                    assert false;
   2917                    break starttagloop; // Avoid infinite loop if the assertion
   2918                                        // fails
   2919            }
   2920        }
   2921        if (selfClosing) {
   2922            errSelfClosing();
   2923        // [NOCPP[
   2924        } else if (wasSelfClosing && voidElement
   2925                && tokenizer.getErrorProfile() != null
   2926                && tokenizer.getErrorProfile().get("html-strict") != null) {
   2927            warn("Trailing slash on void elements has no effect and interacts"
   2928                    + " badly with unquoted attribute values.");
   2929        // ]NOCPP]
   2930        }
   2931        // CPPONLY: if (mBuilder == null && attributes != HtmlAttributes.EMPTY_ATTRIBUTES) {
   2932        // CPPONLY:    Portability.delete(attributes);
   2933        // CPPONLY: }
   2934    }
   2935 
   2936    private void startTagTitleInHead(ElementName elementName, HtmlAttributes attributes) throws SAXException {
   2937        appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
   2938        originalMode = mode;
   2939        mode = TEXT;
   2940        tokenizer.setStateAndEndTagExpectation(Tokenizer.RCDATA, elementName);
   2941    }
   2942 
   2943    private void startTagGenericRawText(ElementName elementName, HtmlAttributes attributes) throws SAXException {
   2944        appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
   2945        originalMode = mode;
   2946        mode = TEXT;
   2947        tokenizer.setStateAndEndTagExpectation(Tokenizer.RAWTEXT, elementName);
   2948    }
   2949 
   2950    private void startTagScriptInHead(ElementName elementName, HtmlAttributes attributes) throws SAXException {
   2951        // XXX need to manage much more stuff here if supporting document.write()
   2952        appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
   2953        originalMode = mode;
   2954        mode = TEXT;
   2955        tokenizer.setStateAndEndTagExpectation(Tokenizer.SCRIPT_DATA, elementName);
   2956    }
   2957 
   2958    private void startTagTemplateInHead(ElementName elementName, HtmlAttributes attributes) throws SAXException {
   2959        appendToCurrentNodeAndPushElement(elementName, attributes);
   2960        insertMarker();
   2961        framesetOk = false;
   2962        originalMode = mode;
   2963        mode = IN_TEMPLATE;
   2964        pushTemplateMode(IN_TEMPLATE);
   2965    }
   2966 
   2967    private boolean isTemplateContents() {
   2968        return TreeBuilder.NOT_FOUND_ON_STACK != findLast("template");
   2969    }
   2970 
   2971    private boolean isTemplateModeStackEmpty() {
   2972        return templateModePtr == -1;
   2973    }
   2974 
   2975    private boolean isSpecialParentInForeign(StackNode<T> stackNode) {
   2976        @NsUri String ns = stackNode.ns;
   2977        return ("http://www.w3.org/1999/xhtml" == ns)
   2978                || (stackNode.isHtmlIntegrationPoint())
   2979                || (("http://www.w3.org/1998/Math/MathML" == ns) && (stackNode.getGroup() == MI_MO_MN_MS_MTEXT));
   2980    }
   2981 
   2982    private T getDeclarativeShadowRoot(T currentNode, T templateNode, HtmlAttributes attributes) {
   2983        if (!isAllowDeclarativeShadowRoots()) {
   2984            return null;
   2985        }
   2986 
   2987        String shadowRootMode = attributes.getValue(AttributeName.SHADOWROOTMODE);
   2988        if (shadowRootMode == null) {
   2989            return null;
   2990        }
   2991 
   2992        boolean shadowRootIsClonable = attributes.contains(AttributeName.SHADOWROOTCLONABLE);
   2993        boolean shadowRootIsSerializable = attributes.contains(AttributeName.SHADOWROOTSERIALIZABLE);
   2994        boolean shadowRootDelegatesFocus = attributes.contains(AttributeName.SHADOWROOTDELEGATESFOCUS);
   2995        String shadowRootReferenceTarget = attributes.getValue(AttributeName.SHADOWROOTREFERENCETARGET);
   2996 
   2997        return getShadowRootFromHost(currentNode, templateNode, shadowRootMode, shadowRootIsClonable, shadowRootIsSerializable, shadowRootDelegatesFocus, shadowRootReferenceTarget);
   2998    }
   2999 
   3000    /**
   3001     *
   3002     * <p>
   3003     * C++ memory note: The return value must be released.
   3004     *
   3005     * @return
   3006     * @throws SAXException
   3007     * @throws StopSniffingException
   3008     */
   3009    public static String extractCharsetFromContent(String attributeValue
   3010        // CPPONLY: , TreeBuilder tb
   3011    ) {
   3012        // This is a bit ugly. Converting the string to char array in order to
   3013        // make the portability layer smaller.
   3014        int charsetState = CHARSET_INITIAL;
   3015        int start = -1;
   3016        int end = -1;
   3017        @Auto char[] buffer = Portability.newCharArrayFromString(attributeValue);
   3018 
   3019        charsetloop: for (int i = 0; i < buffer.length; i++) {
   3020            char c = buffer[i];
   3021            switch (charsetState) {
   3022                case CHARSET_INITIAL:
   3023                    switch (c) {
   3024                        case 'c':
   3025                        case 'C':
   3026                            charsetState = CHARSET_C;
   3027                            continue;
   3028                        default:
   3029                            continue;
   3030                    }
   3031                case CHARSET_C:
   3032                    switch (c) {
   3033                        case 'h':
   3034                        case 'H':
   3035                            charsetState = CHARSET_H;
   3036                            continue;
   3037                        default:
   3038                            charsetState = CHARSET_INITIAL;
   3039                            continue;
   3040                    }
   3041                case CHARSET_H:
   3042                    switch (c) {
   3043                        case 'a':
   3044                        case 'A':
   3045                            charsetState = CHARSET_A;
   3046                            continue;
   3047                        default:
   3048                            charsetState = CHARSET_INITIAL;
   3049                            continue;
   3050                    }
   3051                case CHARSET_A:
   3052                    switch (c) {
   3053                        case 'r':
   3054                        case 'R':
   3055                            charsetState = CHARSET_R;
   3056                            continue;
   3057                        default:
   3058                            charsetState = CHARSET_INITIAL;
   3059                            continue;
   3060                    }
   3061                case CHARSET_R:
   3062                    switch (c) {
   3063                        case 's':
   3064                        case 'S':
   3065                            charsetState = CHARSET_S;
   3066                            continue;
   3067                        default:
   3068                            charsetState = CHARSET_INITIAL;
   3069                            continue;
   3070                    }
   3071                case CHARSET_S:
   3072                    switch (c) {
   3073                        case 'e':
   3074                        case 'E':
   3075                            charsetState = CHARSET_E;
   3076                            continue;
   3077                        default:
   3078                            charsetState = CHARSET_INITIAL;
   3079                            continue;
   3080                    }
   3081                case CHARSET_E:
   3082                    switch (c) {
   3083                        case 't':
   3084                        case 'T':
   3085                            charsetState = CHARSET_T;
   3086                            continue;
   3087                        default:
   3088                            charsetState = CHARSET_INITIAL;
   3089                            continue;
   3090                    }
   3091                case CHARSET_T:
   3092                    switch (c) {
   3093                        case '\t':
   3094                        case '\n':
   3095                        case '\u000C':
   3096                        case '\r':
   3097                        case ' ':
   3098                            continue;
   3099                        case '=':
   3100                            charsetState = CHARSET_EQUALS;
   3101                            continue;
   3102                        default:
   3103                            return null;
   3104                    }
   3105                case CHARSET_EQUALS:
   3106                    switch (c) {
   3107                        case '\t':
   3108                        case '\n':
   3109                        case '\u000C':
   3110                        case '\r':
   3111                        case ' ':
   3112                            continue;
   3113                        case '\'':
   3114                            start = i + 1;
   3115                            charsetState = CHARSET_SINGLE_QUOTED;
   3116                            continue;
   3117                        case '\"':
   3118                            start = i + 1;
   3119                            charsetState = CHARSET_DOUBLE_QUOTED;
   3120                            continue;
   3121                        default:
   3122                            start = i;
   3123                            charsetState = CHARSET_UNQUOTED;
   3124                            continue;
   3125                    }
   3126                case CHARSET_SINGLE_QUOTED:
   3127                    switch (c) {
   3128                        case '\'':
   3129                            end = i;
   3130                            break charsetloop;
   3131                        default:
   3132                            continue;
   3133                    }
   3134                case CHARSET_DOUBLE_QUOTED:
   3135                    switch (c) {
   3136                        case '\"':
   3137                            end = i;
   3138                            break charsetloop;
   3139                        default:
   3140                            continue;
   3141                    }
   3142                case CHARSET_UNQUOTED:
   3143                    switch (c) {
   3144                        case '\t':
   3145                        case '\n':
   3146                        case '\u000C':
   3147                        case '\r':
   3148                        case ' ':
   3149                        case ';':
   3150                            end = i;
   3151                            break charsetloop;
   3152                        default:
   3153                            continue;
   3154                    }
   3155            }
   3156        }
   3157        if (start != -1) {
   3158            if (end == -1) {
   3159                if (charsetState == CHARSET_UNQUOTED) {
   3160                    end = buffer.length;
   3161                } else {
   3162                    return null;
   3163                }
   3164            }
   3165            return Portability.newStringFromBuffer(buffer, start, end
   3166                    - start
   3167                // CPPONLY: , tb, false
   3168            );
   3169        }
   3170        return null;
   3171    }
   3172 
   3173    private void checkMetaCharset(HtmlAttributes attributes)
   3174            throws SAXException {
   3175        String charset = attributes.getValue(AttributeName.CHARSET);
   3176        if (charset != null) {
   3177            if (tokenizer.internalEncodingDeclaration(charset)) {
   3178                requestSuspension();
   3179                return;
   3180            }
   3181            return;
   3182        }
   3183        if (!Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
   3184                "content-type",
   3185                attributes.getValue(AttributeName.HTTP_EQUIV))) {
   3186            return;
   3187        }
   3188        String content = attributes.getValue(AttributeName.CONTENT);
   3189        if (content != null) {
   3190            String extract = TreeBuilder.extractCharsetFromContent(content
   3191                // CPPONLY: , this
   3192            );
   3193            // remember not to return early without releasing the string
   3194            if (extract != null) {
   3195                if (tokenizer.internalEncodingDeclaration(extract)) {
   3196                    requestSuspension();
   3197                }
   3198            }
   3199            Portability.releaseString(extract);
   3200        }
   3201    }
   3202 
   3203    public final void endTag(ElementName elementName) throws SAXException {
   3204        flushCharacters();
   3205        needToDropLF = false;
   3206        int eltPos;
   3207        int group = elementName.getGroup();
   3208        @Local String name = elementName.getName();
   3209        endtagloop: for (;;) {
   3210            if (isInForeign()) {
   3211                if (stack[currentPtr].name != name) {
   3212                    if (currentPtr == 0) {
   3213                        errStrayEndTag(name);
   3214                    } else {
   3215                        errEndTagDidNotMatchCurrentOpenElement(name, stack[currentPtr].popName);
   3216                    }
   3217                }
   3218                eltPos = currentPtr;
   3219                int origPos = currentPtr;
   3220                for (;;) {
   3221                    if (eltPos == 0) {
   3222                        assert fragment: "We can get this close to the root of the stack in foreign content only in the fragment case.";
   3223                        break endtagloop;
   3224                    }
   3225                    if (stack[eltPos].name == name) {
   3226                        while (currentPtr >= eltPos) {
   3227                            popForeign(origPos, eltPos);
   3228                        }
   3229                        break endtagloop;
   3230                    }
   3231                    if (stack[--eltPos].ns == "http://www.w3.org/1999/xhtml") {
   3232                        break;
   3233                    }
   3234                }
   3235            }
   3236            switch (mode) {
   3237                case IN_TEMPLATE:
   3238                    switch (group) {
   3239                        case TEMPLATE:
   3240                            // fall through to IN_HEAD
   3241                            break;
   3242                        default:
   3243                            errStrayEndTag(name);
   3244                            break endtagloop;
   3245                    }
   3246                    // CPPONLY: MOZ_FALLTHROUGH;
   3247                case IN_ROW:
   3248                    switch (group) {
   3249                        case TR:
   3250                            eltPos = findLastOrRoot(TreeBuilder.TR);
   3251                            if (eltPos == 0) {
   3252                                assert fragment || isTemplateContents();
   3253                                errNoTableRowToClose();
   3254                                break endtagloop;
   3255                            }
   3256                            clearStackBackTo(eltPos);
   3257                            pop();
   3258                            mode = IN_TABLE_BODY;
   3259                            break endtagloop;
   3260                        case TABLE:
   3261                            eltPos = findLastOrRoot(TreeBuilder.TR);
   3262                            if (eltPos == 0) {
   3263                                assert fragment || isTemplateContents();
   3264                                errNoTableRowToClose();
   3265                                break endtagloop;
   3266                            }
   3267                            clearStackBackTo(eltPos);
   3268                            pop();
   3269                            mode = IN_TABLE_BODY;
   3270                            continue;
   3271                        case TBODY_OR_THEAD_OR_TFOOT:
   3272                            if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) {
   3273                                errStrayEndTag(name);
   3274                                break endtagloop;
   3275                            }
   3276                            eltPos = findLastOrRoot(TreeBuilder.TR);
   3277                            if (eltPos == 0) {
   3278                                assert fragment || isTemplateContents();
   3279                                errNoTableRowToClose();
   3280                                break endtagloop;
   3281                            }
   3282                            clearStackBackTo(eltPos);
   3283                            pop();
   3284                            mode = IN_TABLE_BODY;
   3285                            continue;
   3286                        case BODY:
   3287                        case CAPTION:
   3288                        case COL:
   3289                        case COLGROUP:
   3290                        case HTML:
   3291                        case TD_OR_TH:
   3292                            errStrayEndTag(name);
   3293                            break endtagloop;
   3294                        default:
   3295                            // fall through to IN_TABLE
   3296                    }
   3297                    // CPPONLY: MOZ_FALLTHROUGH;
   3298                case IN_TABLE_BODY:
   3299                    switch (group) {
   3300                        case TBODY_OR_THEAD_OR_TFOOT:
   3301                            eltPos = findLastOrRoot(name);
   3302                            if (eltPos == 0) {
   3303                                errStrayEndTag(name);
   3304                                break endtagloop;
   3305                            }
   3306                            clearStackBackTo(eltPos);
   3307                            pop();
   3308                            mode = IN_TABLE;
   3309                            break endtagloop;
   3310                        case TABLE:
   3311                            eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
   3312                            if (eltPos == 0 || stack[eltPos].getGroup() == TEMPLATE) {
   3313                                assert fragment || isTemplateContents();
   3314                                errStrayEndTag(name);
   3315                                break endtagloop;
   3316                            }
   3317                            clearStackBackTo(eltPos);
   3318                            pop();
   3319                            mode = IN_TABLE;
   3320                            continue;
   3321                        case BODY:
   3322                        case CAPTION:
   3323                        case COL:
   3324                        case COLGROUP:
   3325                        case HTML:
   3326                        case TD_OR_TH:
   3327                        case TR:
   3328                            errStrayEndTag(name);
   3329                            break endtagloop;
   3330                        default:
   3331                            // fall through to IN_TABLE
   3332                    }
   3333                    // CPPONLY: MOZ_FALLTHROUGH;
   3334                case IN_TABLE:
   3335                    switch (group) {
   3336                        case TABLE:
   3337                            eltPos = findLast("table");
   3338                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3339                                assert fragment || isTemplateContents();
   3340                                errStrayEndTag(name);
   3341                                break endtagloop;
   3342                            }
   3343                            while (currentPtr >= eltPos) {
   3344                                pop();
   3345                            }
   3346                            resetTheInsertionMode();
   3347                            break endtagloop;
   3348                        case BODY:
   3349                        case CAPTION:
   3350                        case COL:
   3351                        case COLGROUP:
   3352                        case HTML:
   3353                        case TBODY_OR_THEAD_OR_TFOOT:
   3354                        case TD_OR_TH:
   3355                        case TR:
   3356                            errStrayEndTag(name);
   3357                            break endtagloop;
   3358                        case TEMPLATE:
   3359                            // fall through to IN_HEAD
   3360                            break;
   3361                        default:
   3362                            errStrayEndTag(name);
   3363                            // fall through to IN_BODY
   3364                    }
   3365                    // CPPONLY: MOZ_FALLTHROUGH;
   3366                case IN_CAPTION:
   3367                    switch (group) {
   3368                        case CAPTION:
   3369                            eltPos = findLastInTableScope("caption");
   3370                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3371                                break endtagloop;
   3372                            }
   3373                            generateImpliedEndTags();
   3374                            if (errorHandler != null && currentPtr != eltPos) {
   3375                                errUnclosedElements(eltPos, name);
   3376                            }
   3377                            while (currentPtr >= eltPos) {
   3378                                pop();
   3379                            }
   3380                            clearTheListOfActiveFormattingElementsUpToTheLastMarker();
   3381                            mode = IN_TABLE;
   3382                            break endtagloop;
   3383                        case TABLE:
   3384                            eltPos = findLastInTableScope("caption");
   3385 
   3386                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3387                                assert fragment || isTemplateContents();
   3388                                errStrayEndTag(name);
   3389                                break endtagloop;
   3390                            }
   3391                            generateImpliedEndTags();
   3392                            if (errorHandler != null && currentPtr != eltPos) {
   3393                                errUnclosedElements(eltPos, name);
   3394                            }
   3395                            while (currentPtr >= eltPos) {
   3396                                pop();
   3397                            }
   3398                            clearTheListOfActiveFormattingElementsUpToTheLastMarker();
   3399                            mode = IN_TABLE;
   3400                            continue;
   3401                        case BODY:
   3402                        case COL:
   3403                        case COLGROUP:
   3404                        case HTML:
   3405                        case TBODY_OR_THEAD_OR_TFOOT:
   3406                        case TD_OR_TH:
   3407                        case TR:
   3408                            errStrayEndTag(name);
   3409                            break endtagloop;
   3410                        default:
   3411                            // fall through to IN_BODY
   3412                    }
   3413                    // CPPONLY: MOZ_FALLTHROUGH;
   3414                case IN_CELL:
   3415                    switch (group) {
   3416                        case TD_OR_TH:
   3417                            eltPos = findLastInTableScope(name);
   3418                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3419                                errStrayEndTag(name);
   3420                                break endtagloop;
   3421                            }
   3422                            generateImpliedEndTags();
   3423                            if (errorHandler != null && !isCurrent(name)) {
   3424                                errUnclosedElements(eltPos, name);
   3425                            }
   3426                            while (currentPtr >= eltPos) {
   3427                                pop();
   3428                            }
   3429                            clearTheListOfActiveFormattingElementsUpToTheLastMarker();
   3430                            mode = IN_ROW;
   3431                            break endtagloop;
   3432                        case TABLE:
   3433                        case TBODY_OR_THEAD_OR_TFOOT:
   3434                        case TR:
   3435                            if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) {
   3436                                assert name == "tbody" || name == "tfoot" || name == "thead" || fragment || isTemplateContents();
   3437                                errStrayEndTag(name);
   3438                                break endtagloop;
   3439                            }
   3440                            closeTheCell(findLastInTableScopeTdTh());
   3441                            continue;
   3442                        case BODY:
   3443                        case CAPTION:
   3444                        case COL:
   3445                        case COLGROUP:
   3446                        case HTML:
   3447                            errStrayEndTag(name);
   3448                            break endtagloop;
   3449                        default:
   3450                            // fall through to IN_BODY
   3451                    }
   3452                    // CPPONLY: MOZ_FALLTHROUGH;
   3453                case FRAMESET_OK:
   3454                case IN_BODY:
   3455                    switch (group) {
   3456                        case BODY:
   3457                            if (!isSecondOnStackBody()) {
   3458                                assert fragment || isTemplateContents();
   3459                                errStrayEndTag(name);
   3460                                break endtagloop;
   3461                            }
   3462                            assert currentPtr >= 1;
   3463                            if (errorHandler != null) {
   3464                                uncloseloop1: for (int i = 2; i <= currentPtr; i++) {
   3465                                    switch (stack[i].getGroup()) {
   3466                                        case DD_OR_DT:
   3467                                        case LI:
   3468                                        case OPTGROUP:
   3469                                        case OPTION: // is this possible?
   3470                                        case P:
   3471                                        case RB_OR_RTC:
   3472                                        case RT_OR_RP:
   3473                                        case TD_OR_TH:
   3474                                        case TBODY_OR_THEAD_OR_TFOOT:
   3475                                            break;
   3476                                        default:
   3477                                            errEndWithUnclosedElements(name);
   3478                                            break uncloseloop1;
   3479                                    }
   3480                                }
   3481                            }
   3482                            mode = AFTER_BODY;
   3483                            break endtagloop;
   3484                        case HTML:
   3485                            if (!isSecondOnStackBody()) {
   3486                                assert fragment || isTemplateContents();
   3487                                errStrayEndTag(name);
   3488                                break endtagloop;
   3489                            }
   3490                            if (errorHandler != null) {
   3491                                uncloseloop2: for (int i = 0; i <= currentPtr; i++) {
   3492                                    switch (stack[i].getGroup()) {
   3493                                        case DD_OR_DT:
   3494                                        case LI:
   3495                                        case P:
   3496                                        case RB_OR_RTC:
   3497                                        case RT_OR_RP:
   3498                                        case TBODY_OR_THEAD_OR_TFOOT:
   3499                                        case TD_OR_TH:
   3500                                        case BODY:
   3501                                        case HTML:
   3502                                            break;
   3503                                        default:
   3504                                            errEndWithUnclosedElements(name);
   3505                                            break uncloseloop2;
   3506                                    }
   3507                                }
   3508                            }
   3509                            mode = AFTER_BODY;
   3510                            continue;
   3511                        case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
   3512                        case UL_OR_OL_OR_DL:
   3513                        case PRE_OR_LISTING:
   3514                        case FIELDSET:
   3515                        case BUTTON:
   3516                        case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SEARCH_OR_SECTION_OR_SUMMARY:
   3517                            eltPos = findLastInScope(name);
   3518                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3519                                errStrayEndTag(name);
   3520                            } else {
   3521                                generateImpliedEndTags();
   3522                                if (errorHandler != null && !isCurrent(name)) {
   3523                                    errUnclosedElements(eltPos, name);
   3524                                }
   3525                                while (currentPtr >= eltPos) {
   3526                                    pop();
   3527                                }
   3528                            }
   3529                            break endtagloop;
   3530                        case FORM:
   3531                            if (!isTemplateContents()) {
   3532                                if (formPointer == null) {
   3533                                    errStrayEndTag(name);
   3534                                    break endtagloop;
   3535                                }
   3536                                formPointer = null;
   3537                                eltPos = findLastInScope(name);
   3538                                if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3539                                    errStrayEndTag(name);
   3540                                    break endtagloop;
   3541                                }
   3542                                generateImpliedEndTags();
   3543                                if (errorHandler != null && !isCurrent(name)) {
   3544                                    errUnclosedElements(eltPos, name);
   3545                                }
   3546                                removeFromStack(eltPos);
   3547                                break endtagloop;
   3548                            } else {
   3549                                eltPos = findLastInScope(name);
   3550                                if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3551                                    errStrayEndTag(name);
   3552                                    break endtagloop;
   3553                                }
   3554                                generateImpliedEndTags();
   3555                                if (errorHandler != null && !isCurrent(name)) {
   3556                                    errUnclosedElements(eltPos, name);
   3557                                }
   3558                                while (currentPtr >= eltPos) {
   3559                                    pop();
   3560                                }
   3561                                break endtagloop;
   3562                            }
   3563                        case P:
   3564                            eltPos = findLastInButtonScope("p");
   3565                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3566                                errNoElementToCloseButEndTagSeen("p");
   3567                                // XXX Can the 'in foreign' case happen anymore?
   3568                                if (isInForeign()) {
   3569                                    errHtmlStartTagInForeignContext(name);
   3570                                    // Check for currentPtr for the fragment
   3571                                    // case.
   3572                                    while (currentPtr >= 0 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") {
   3573                                        pop();
   3574                                    }
   3575                                }
   3576                                appendVoidElementToCurrentMayFoster(
   3577                                        elementName,
   3578                                        HtmlAttributes.EMPTY_ATTRIBUTES);
   3579                                break endtagloop;
   3580                            }
   3581                            generateImpliedEndTagsExceptFor("p");
   3582                            assert eltPos != TreeBuilder.NOT_FOUND_ON_STACK;
   3583                            if (errorHandler != null && eltPos != currentPtr) {
   3584                                errUnclosedElements(eltPos, name);
   3585                            }
   3586                            while (currentPtr >= eltPos) {
   3587                                pop();
   3588                            }
   3589                            break endtagloop;
   3590                        case LI:
   3591                            eltPos = findLastInListScope(name);
   3592                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3593                                errNoElementToCloseButEndTagSeen(name);
   3594                            } else {
   3595                                generateImpliedEndTagsExceptFor(name);
   3596                                if (errorHandler != null
   3597                                        && eltPos != currentPtr) {
   3598                                    errUnclosedElements(eltPos, name);
   3599                                }
   3600                                while (currentPtr >= eltPos) {
   3601                                    pop();
   3602                                }
   3603                            }
   3604                            break endtagloop;
   3605                        case DD_OR_DT:
   3606                            eltPos = findLastInScope(name);
   3607                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3608                                errNoElementToCloseButEndTagSeen(name);
   3609                            } else {
   3610                                generateImpliedEndTagsExceptFor(name);
   3611                                if (errorHandler != null
   3612                                        && eltPos != currentPtr) {
   3613                                    errUnclosedElements(eltPos, name);
   3614                                }
   3615                                while (currentPtr >= eltPos) {
   3616                                    pop();
   3617                                }
   3618                            }
   3619                            break endtagloop;
   3620                        case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
   3621                            eltPos = findLastInScopeHn();
   3622                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3623                                errStrayEndTag(name);
   3624                            } else {
   3625                                generateImpliedEndTags();
   3626                                if (errorHandler != null && !isCurrent(name)) {
   3627                                    errUnclosedElements(eltPos, name);
   3628                                }
   3629                                while (currentPtr >= eltPos) {
   3630                                    pop();
   3631                                }
   3632                            }
   3633                            break endtagloop;
   3634                        case OBJECT:
   3635                        case MARQUEE_OR_APPLET:
   3636                            eltPos = findLastInScope(name);
   3637                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3638                                errStrayEndTag(name);
   3639                            } else {
   3640                                generateImpliedEndTags();
   3641                                if (errorHandler != null && !isCurrent(name)) {
   3642                                    errUnclosedElements(eltPos, name);
   3643                                }
   3644                                while (currentPtr >= eltPos) {
   3645                                    pop();
   3646                                }
   3647                                clearTheListOfActiveFormattingElementsUpToTheLastMarker();
   3648                            }
   3649                            break endtagloop;
   3650                        case BR:
   3651                            errEndTagBr();
   3652                            if (isInForeign()) {
   3653                                // XXX can this happen anymore?
   3654                                errHtmlStartTagInForeignContext(name);
   3655                                // Check for currentPtr for the fragment
   3656                                // case.
   3657                                while (currentPtr >= 0 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") {
   3658                                    pop();
   3659                                }
   3660                            }
   3661                            reconstructTheActiveFormattingElements();
   3662                            appendVoidElementToCurrentMayFoster(
   3663                                    elementName,
   3664                                    HtmlAttributes.EMPTY_ATTRIBUTES);
   3665                            break endtagloop;
   3666                        case TEMPLATE:
   3667                            // fall through to IN_HEAD;
   3668                            break;
   3669                        case AREA_OR_WBR:
   3670                        case KEYGEN: // XXX??
   3671                        case PARAM_OR_SOURCE_OR_TRACK:
   3672                        case EMBED:
   3673                        case IMG:
   3674                        case IMAGE:
   3675                        case INPUT:
   3676                        case HR:
   3677                        case IFRAME:
   3678                        case NOEMBED: // XXX???
   3679                        case NOFRAMES: // XXX??
   3680                        case SELECT:
   3681                        case TABLE:
   3682                        case TEXTAREA: // XXX??
   3683                            errStrayEndTag(name);
   3684                            break endtagloop;
   3685                        case NOSCRIPT:
   3686                            if (scriptingEnabled) {
   3687                                errStrayEndTag(name);
   3688                                break endtagloop;
   3689                            }
   3690                            // CPPONLY: MOZ_FALLTHROUGH;
   3691                        case A:
   3692                        case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
   3693                        case FONT:
   3694                        case NOBR:
   3695                            if (adoptionAgencyEndTag(name)) {
   3696                                break endtagloop;
   3697                            }
   3698                            // else handle like any other tag
   3699                            // CPPONLY: MOZ_FALLTHROUGH;
   3700                        default:
   3701                            if (isCurrent(name)) {
   3702                                pop();
   3703                                break endtagloop;
   3704                            }
   3705 
   3706                            eltPos = currentPtr;
   3707                            for (;;) {
   3708                                StackNode<T> node = stack[eltPos];
   3709                                if (node.ns == "http://www.w3.org/1999/xhtml" && node.name == name) {
   3710                                    generateImpliedEndTags();
   3711                                    if (errorHandler != null
   3712                                            && !isCurrent(name)) {
   3713                                        errUnclosedElements(eltPos, name);
   3714                                    }
   3715                                    while (currentPtr >= eltPos) {
   3716                                        pop();
   3717                                    }
   3718                                    break endtagloop;
   3719                                } else if (eltPos == 0 || node.isSpecial()) {
   3720                                    errStrayEndTag(name);
   3721                                    break endtagloop;
   3722                                }
   3723                                eltPos--;
   3724                            }
   3725                    }
   3726                    // CPPONLY: MOZ_FALLTHROUGH;
   3727                case IN_HEAD:
   3728                    switch (group) {
   3729                        case HEAD:
   3730                            pop();
   3731                            mode = AFTER_HEAD;
   3732                            break endtagloop;
   3733                        case BR:
   3734                        case HTML:
   3735                        case BODY:
   3736                            pop();
   3737                            mode = AFTER_HEAD;
   3738                            continue;
   3739                        case TEMPLATE:
   3740                            endTagTemplateInHead();
   3741                            break endtagloop;
   3742                        default:
   3743                            errStrayEndTag(name);
   3744                            break endtagloop;
   3745                    }
   3746                case IN_HEAD_NOSCRIPT:
   3747                    switch (group) {
   3748                        case NOSCRIPT:
   3749                            pop();
   3750                            mode = IN_HEAD;
   3751                            break endtagloop;
   3752                        case BR:
   3753                            errStrayEndTag(name);
   3754                            pop();
   3755                            mode = IN_HEAD;
   3756                            continue;
   3757                        default:
   3758                            errStrayEndTag(name);
   3759                            break endtagloop;
   3760                    }
   3761                case IN_COLUMN_GROUP:
   3762                    switch (group) {
   3763                        case COLGROUP:
   3764                            if (currentPtr == 0 || stack[currentPtr].getGroup() ==
   3765                                    TreeBuilder.TEMPLATE) {
   3766                                assert fragment || isTemplateContents();
   3767                                errGarbageInColgroup();
   3768                                break endtagloop;
   3769                            }
   3770                            pop();
   3771                            mode = IN_TABLE;
   3772                            break endtagloop;
   3773                        case COL:
   3774                            errStrayEndTag(name);
   3775                            break endtagloop;
   3776                        case TEMPLATE:
   3777                            endTagTemplateInHead();
   3778                            break endtagloop;
   3779                        default:
   3780                            if (currentPtr == 0 || stack[currentPtr].getGroup() ==
   3781                                    TreeBuilder.TEMPLATE) {
   3782                                assert fragment || isTemplateContents();
   3783                                errGarbageInColgroup();
   3784                                break endtagloop;
   3785                            }
   3786                            pop();
   3787                            mode = IN_TABLE;
   3788                            continue;
   3789                    }
   3790                case IN_SELECT_IN_TABLE:
   3791                    switch (group) {
   3792                        case CAPTION:
   3793                        case TABLE:
   3794                        case TBODY_OR_THEAD_OR_TFOOT:
   3795                        case TR:
   3796                        case TD_OR_TH:
   3797                            errEndTagSeenWithSelectOpen(name);
   3798                            if (findLastInTableScope(name) != TreeBuilder.NOT_FOUND_ON_STACK) {
   3799                                eltPos = findLastInTableScope("select");
   3800                                if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3801                                    assert fragment;
   3802                                    break endtagloop; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375
   3803                                }
   3804                                while (currentPtr >= eltPos) {
   3805                                    pop();
   3806                                }
   3807                                resetTheInsertionMode();
   3808                                continue;
   3809                            } else {
   3810                                break endtagloop;
   3811                            }
   3812                        default:
   3813                            // fall through to IN_SELECT
   3814                    }
   3815                    // CPPONLY: MOZ_FALLTHROUGH;
   3816                case IN_SELECT:
   3817                    switch (group) {
   3818                        case OPTION:
   3819                            if (isCurrent("option")) {
   3820                                pop();
   3821                                break endtagloop;
   3822                            } else {
   3823                                errStrayEndTag(name);
   3824                                break endtagloop;
   3825                            }
   3826                        case OPTGROUP:
   3827                            if (isCurrent("option")
   3828                                    && "optgroup" == stack[currentPtr - 1].name) {
   3829                                pop();
   3830                            }
   3831                            if (isCurrent("optgroup")) {
   3832                                pop();
   3833                            } else {
   3834                                errStrayEndTag(name);
   3835                            }
   3836                            break endtagloop;
   3837                        case SELECT:
   3838                            eltPos = findLastInTableScope("select");
   3839                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3840                                assert fragment;
   3841                                errStrayEndTag(name);
   3842                                break endtagloop;
   3843                            }
   3844                            while (currentPtr >= eltPos) {
   3845                                pop();
   3846                            }
   3847                            resetTheInsertionMode();
   3848                            break endtagloop;
   3849                        case TEMPLATE:
   3850                            endTagTemplateInHead();
   3851                            break endtagloop;
   3852                        default:
   3853                            errStrayEndTag(name);
   3854                            break endtagloop;
   3855                    }
   3856                case AFTER_BODY:
   3857                    switch (group) {
   3858                        case HTML:
   3859                            if (fragment) {
   3860                                errStrayEndTag(name);
   3861                                break endtagloop;
   3862                            } else {
   3863                                mode = AFTER_AFTER_BODY;
   3864                                break endtagloop;
   3865                            }
   3866                        default:
   3867                            errEndTagAfterBody();
   3868                            mode = framesetOk ? FRAMESET_OK : IN_BODY;
   3869                            continue;
   3870                    }
   3871                case IN_FRAMESET:
   3872                    switch (group) {
   3873                        case FRAMESET:
   3874                            if (currentPtr == 0) {
   3875                                assert fragment;
   3876                                errStrayEndTag(name);
   3877                                break endtagloop;
   3878                            }
   3879                            pop();
   3880                            if ((!fragment) && !isCurrent("frameset")) {
   3881                                mode = AFTER_FRAMESET;
   3882                            }
   3883                            break endtagloop;
   3884                        default:
   3885                            errStrayEndTag(name);
   3886                            break endtagloop;
   3887                    }
   3888                case AFTER_FRAMESET:
   3889                    switch (group) {
   3890                        case HTML:
   3891                            mode = AFTER_AFTER_FRAMESET;
   3892                            break endtagloop;
   3893                        default:
   3894                            errStrayEndTag(name);
   3895                            break endtagloop;
   3896                    }
   3897                case INITIAL:
   3898                    /*
   3899                     * Parse error.
   3900                     */
   3901                    errEndTagSeenWithoutDoctype();
   3902                    /*
   3903                     *
   3904                     * Set the document to quirks mode.
   3905                     */
   3906                    documentModeInternal(DocumentMode.QUIRKS_MODE, null, null);
   3907                    /*
   3908                     * Then, switch to the root element mode of the tree
   3909                     * construction stage
   3910                     */
   3911                    mode = BEFORE_HTML;
   3912                    /*
   3913                     * and reprocess the current token.
   3914                     */
   3915                    continue;
   3916                case BEFORE_HTML:
   3917                    switch (group) {
   3918                        case HEAD:
   3919                        case BR:
   3920                        case HTML:
   3921                        case BODY:
   3922                            /*
   3923                             * Create an HTMLElement node with the tag name
   3924                             * html, in the HTML namespace. Append it to the
   3925                             * Document object.
   3926                             */
   3927                            appendHtmlElementToDocumentAndPush();
   3928                            /* Switch to the main mode */
   3929                            mode = BEFORE_HEAD;
   3930                            /*
   3931                             * reprocess the current token.
   3932                             */
   3933                            continue;
   3934                        default:
   3935                            errStrayEndTag(name);
   3936                            break endtagloop;
   3937                    }
   3938                case BEFORE_HEAD:
   3939                    switch (group) {
   3940                        case HEAD:
   3941                        case BR:
   3942                        case HTML:
   3943                        case BODY:
   3944                            appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
   3945                            mode = IN_HEAD;
   3946                            continue;
   3947                        default:
   3948                            errStrayEndTag(name);
   3949                            break endtagloop;
   3950                    }
   3951                case AFTER_HEAD:
   3952                    switch (group) {
   3953                        case TEMPLATE:
   3954                            endTagTemplateInHead();
   3955                            break endtagloop;
   3956                        case HTML:
   3957                        case BODY:
   3958                        case BR:
   3959                            appendToCurrentNodeAndPushBodyElement();
   3960                            mode = FRAMESET_OK;
   3961                            continue;
   3962                        default:
   3963                            errStrayEndTag(name);
   3964                            break endtagloop;
   3965                    }
   3966                case AFTER_AFTER_BODY:
   3967                    errStrayEndTag(name);
   3968                    mode = framesetOk ? FRAMESET_OK : IN_BODY;
   3969                    continue;
   3970                case AFTER_AFTER_FRAMESET:
   3971                    errStrayEndTag(name);
   3972                    break endtagloop;
   3973                case TEXT:
   3974                    // XXX need to manage insertion point here
   3975                    pop();
   3976                    if (originalMode == AFTER_HEAD) {
   3977                        silentPop();
   3978                    }
   3979                    mode = originalMode;
   3980                    break endtagloop;
   3981            }
   3982        } // endtagloop
   3983    }
   3984 
   3985    private void endTagTemplateInHead() throws SAXException {
   3986        int eltPos = findLast("template");
   3987        if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   3988            errStrayEndTag("template");
   3989            return;
   3990        }
   3991        generateImpliedEndTagsThoroughly();
   3992        if (errorHandler != null && !isCurrent("template")) {
   3993            errUnclosedElements(eltPos, "template");
   3994        }
   3995        while (currentPtr >= eltPos) {
   3996            pop();
   3997        }
   3998        clearTheListOfActiveFormattingElementsUpToTheLastMarker();
   3999        popTemplateMode();
   4000        resetTheInsertionMode();
   4001    }
   4002 
   4003    private int findLastInTableScopeOrRootTemplateTbodyTheadTfoot() {
   4004        for (int i = currentPtr; i > 0; i--) {
   4005            if (stack[i].ns == "http://www.w3.org/1999/xhtml"
   4006                    && (stack[i].getGroup() == TreeBuilder.TBODY_OR_THEAD_OR_TFOOT
   4007                            || stack[i].getGroup() == TreeBuilder.TEMPLATE)) {
   4008                return i;
   4009            }
   4010        }
   4011        return 0;
   4012    }
   4013 
   4014    private int findLast(@Local String name) {
   4015        for (int i = currentPtr; i > 0; i--) {
   4016            if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].name == name) {
   4017                return i;
   4018            }
   4019        }
   4020        return TreeBuilder.NOT_FOUND_ON_STACK;
   4021    }
   4022 
   4023    private int findLastInTableScope(@Local String name) {
   4024        for (int i = currentPtr; i > 0; i--) {
   4025            if (stack[i].ns == "http://www.w3.org/1999/xhtml") {
   4026                if (stack[i].name == name) {
   4027                    return i;
   4028                } else if (stack[i].name == "table" || stack[i].name == "template") {
   4029                    return TreeBuilder.NOT_FOUND_ON_STACK;
   4030                }
   4031            }
   4032        }
   4033        return TreeBuilder.NOT_FOUND_ON_STACK;
   4034    }
   4035 
   4036    private int findLastInButtonScope(@Local String name) {
   4037        for (int i = currentPtr; i > 0; i--) {
   4038            if (stack[i].ns == "http://www.w3.org/1999/xhtml") {
   4039                if (stack[i].name == name) {
   4040                    return i;
   4041                } else if (stack[i].name == "button") {
   4042                    return TreeBuilder.NOT_FOUND_ON_STACK;
   4043                }
   4044            }
   4045 
   4046            if (stack[i].isScoping()) {
   4047                return TreeBuilder.NOT_FOUND_ON_STACK;
   4048            }
   4049        }
   4050        return TreeBuilder.NOT_FOUND_ON_STACK;
   4051    }
   4052 
   4053    private int findLastInScope(@Local String name) {
   4054        for (int i = currentPtr; i > 0; i--) {
   4055            if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].name == name) {
   4056                return i;
   4057            } else if (stack[i].isScoping()) {
   4058                return TreeBuilder.NOT_FOUND_ON_STACK;
   4059            }
   4060        }
   4061        return TreeBuilder.NOT_FOUND_ON_STACK;
   4062    }
   4063 
   4064    private int findLastInListScope(@Local String name) {
   4065        for (int i = currentPtr; i > 0; i--) {
   4066            if (stack[i].ns == "http://www.w3.org/1999/xhtml") {
   4067                if (stack[i].name == name) {
   4068                    return i;
   4069                } else if (stack[i].name == "ul" || stack[i].name == "ol") {
   4070                    return TreeBuilder.NOT_FOUND_ON_STACK;
   4071                }
   4072            }
   4073 
   4074            if (stack[i].isScoping()) {
   4075                return TreeBuilder.NOT_FOUND_ON_STACK;
   4076            }
   4077        }
   4078        return TreeBuilder.NOT_FOUND_ON_STACK;
   4079    }
   4080 
   4081    private int findLastInScopeHn() {
   4082        for (int i = currentPtr; i > 0; i--) {
   4083            if (stack[i].getGroup() == TreeBuilder.H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
   4084                return i;
   4085            } else if (stack[i].isScoping()) {
   4086                return TreeBuilder.NOT_FOUND_ON_STACK;
   4087            }
   4088        }
   4089        return TreeBuilder.NOT_FOUND_ON_STACK;
   4090    }
   4091 
   4092    private void generateImpliedEndTagsExceptFor(@Local String name)
   4093            throws SAXException {
   4094        for (;;) {
   4095            StackNode<T> node = stack[currentPtr];
   4096            switch (node.getGroup()) {
   4097                case P:
   4098                case LI:
   4099                case DD_OR_DT:
   4100                case OPTION:
   4101                case OPTGROUP:
   4102                case RB_OR_RTC:
   4103                case RT_OR_RP:
   4104                    if (node.ns == "http://www.w3.org/1999/xhtml" && node.name == name) {
   4105                        return;
   4106                    }
   4107                    pop();
   4108                    continue;
   4109                default:
   4110                    return;
   4111            }
   4112        }
   4113    }
   4114 
   4115    private void generateImpliedEndTags() throws SAXException {
   4116        for (;;) {
   4117            switch (stack[currentPtr].getGroup()) {
   4118                case P:
   4119                case LI:
   4120                case DD_OR_DT:
   4121                case OPTION:
   4122                case OPTGROUP:
   4123                case RB_OR_RTC:
   4124                case RT_OR_RP:
   4125                    pop();
   4126                    continue;
   4127                default:
   4128                    return;
   4129            }
   4130        }
   4131    }
   4132 
   4133    private void generateImpliedEndTagsThoroughly() throws SAXException {
   4134        for (;;) {
   4135            switch (stack[currentPtr].getGroup()) {
   4136                case CAPTION:
   4137                case COLGROUP:
   4138                case DD_OR_DT:
   4139                case LI:
   4140                case OPTGROUP:
   4141                case OPTION:
   4142                case P:
   4143                case RB_OR_RTC:
   4144                case RT_OR_RP:
   4145                case TBODY_OR_THEAD_OR_TFOOT:
   4146                case TD_OR_TH:
   4147                case TR:
   4148                    pop();
   4149                    continue;
   4150                default:
   4151                    return;
   4152            }
   4153        }
   4154    }
   4155 
   4156    private boolean isSecondOnStackBody() {
   4157        return currentPtr >= 1 && stack[1].getGroup() == TreeBuilder.BODY;
   4158    }
   4159 
   4160    private void documentModeInternal(DocumentMode m, String publicIdentifier,
   4161            String systemIdentifier)
   4162            throws SAXException {
   4163 
   4164        if (forceNoQuirks) {
   4165            // Srcdoc documents are always rendered in standards mode.
   4166            quirks = false;
   4167            if (documentModeHandler != null) {
   4168                documentModeHandler.documentMode(
   4169                        DocumentMode.STANDARDS_MODE
   4170                        // [NOCPP[
   4171                        , null, null
   4172                // ]NOCPP]
   4173                );
   4174            }
   4175            return;
   4176        }
   4177 
   4178        quirks = (m == DocumentMode.QUIRKS_MODE);
   4179        if (documentModeHandler != null) {
   4180            documentModeHandler.documentMode(
   4181                    m
   4182                    // [NOCPP[
   4183                    , publicIdentifier, systemIdentifier
   4184            // ]NOCPP]
   4185            );
   4186        }
   4187        // [NOCPP[
   4188        documentMode(m, publicIdentifier, systemIdentifier);
   4189        // ]NOCPP]
   4190    }
   4191 
   4192    private boolean isAlmostStandards(String publicIdentifier,
   4193            String systemIdentifier) {
   4194        if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
   4195                "-//w3c//dtd xhtml 1.0 transitional//", publicIdentifier)) {
   4196            return true;
   4197        }
   4198        if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
   4199                "-//w3c//dtd xhtml 1.0 frameset//", publicIdentifier)) {
   4200            return true;
   4201        }
   4202        if (systemIdentifier != null) {
   4203            if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
   4204                    "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) {
   4205                return true;
   4206            }
   4207            if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
   4208                    "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) {
   4209                return true;
   4210            }
   4211        }
   4212        return false;
   4213    }
   4214 
   4215    private boolean isQuirky(@Local String name, String publicIdentifier,
   4216            String systemIdentifier, boolean forceQuirks) {
   4217        if (forceQuirks) {
   4218            return true;
   4219        }
   4220        if (name != HTML_LOCAL) {
   4221            return true;
   4222        }
   4223        if (publicIdentifier != null) {
   4224            for (int i = 0; i < TreeBuilder.QUIRKY_PUBLIC_IDS.length; i++) {
   4225                if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
   4226                        TreeBuilder.QUIRKY_PUBLIC_IDS[i], publicIdentifier)) {
   4227                    return true;
   4228                }
   4229            }
   4230            if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
   4231                    "-//w3o//dtd w3 html strict 3.0//en//", publicIdentifier)
   4232                    || Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
   4233                            "-/w3c/dtd html 4.0 transitional/en",
   4234                            publicIdentifier)
   4235                    || Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
   4236                            "html", publicIdentifier)) {
   4237                return true;
   4238            }
   4239        }
   4240        if (systemIdentifier == null) {
   4241            if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
   4242                    "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) {
   4243                return true;
   4244            } else if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
   4245                    "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) {
   4246                return true;
   4247            }
   4248        } else if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
   4249                "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd",
   4250                systemIdentifier)) {
   4251            return true;
   4252        }
   4253        return false;
   4254    }
   4255 
   4256    private void closeTheCell(int eltPos) throws SAXException {
   4257        generateImpliedEndTags();
   4258        if (errorHandler != null && eltPos != currentPtr) {
   4259            errUnclosedElementsCell(eltPos);
   4260        }
   4261        while (currentPtr >= eltPos) {
   4262            pop();
   4263        }
   4264        clearTheListOfActiveFormattingElementsUpToTheLastMarker();
   4265        mode = IN_ROW;
   4266        return;
   4267    }
   4268 
   4269    private int findLastInTableScopeTdTh() {
   4270        for (int i = currentPtr; i > 0; i--) {
   4271            @Local String name = stack[i].name;
   4272            if (stack[i].ns == "http://www.w3.org/1999/xhtml") {
   4273                if ("td" == name || "th" == name) {
   4274                    return i;
   4275                } else if (name == "table" || name == "template") {
   4276                    return TreeBuilder.NOT_FOUND_ON_STACK;
   4277                }
   4278            }
   4279        }
   4280        return TreeBuilder.NOT_FOUND_ON_STACK;
   4281    }
   4282 
   4283    private void clearStackBackTo(int eltPos) throws SAXException {
   4284        int eltGroup = stack[eltPos].getGroup();
   4285        while (currentPtr > eltPos) { // > not >= intentional
   4286            if (stack[currentPtr].ns == "http://www.w3.org/1999/xhtml"
   4287                    && stack[currentPtr].getGroup() == TEMPLATE
   4288                    && (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT|| eltGroup == TR || eltPos == 0)) {
   4289                return;
   4290            }
   4291            pop();
   4292        }
   4293    }
   4294 
   4295    private void resetTheInsertionMode() {
   4296        StackNode<T> node;
   4297        @Local String name;
   4298        @NsUri String ns;
   4299        for (int i = currentPtr; i >= 0; i--) {
   4300            node = stack[i];
   4301            name = node.name;
   4302            ns = node.ns;
   4303            if (i == 0) {
   4304                if (!(contextNamespace == "http://www.w3.org/1999/xhtml" && (contextName == "td" || contextName == "th"))) {
   4305                    if (fragment) {
   4306                        // Make sure we are parsing a fragment otherwise the context element doesn't make sense.
   4307                        name = contextName;
   4308                        ns = contextNamespace;
   4309                    }
   4310                } else {
   4311                    mode = framesetOk ? FRAMESET_OK : IN_BODY; // XXX from Hixie's email
   4312                    return;
   4313                }
   4314            }
   4315            if ("select" == name) {
   4316                int ancestorIndex = i;
   4317                while (ancestorIndex > 0) {
   4318                    StackNode<T> ancestor = stack[ancestorIndex--];
   4319                    if ("http://www.w3.org/1999/xhtml" == ancestor.ns) {
   4320                        if ("template" == ancestor.name) {
   4321                            break;
   4322                        }
   4323                        if ("table" == ancestor.name) {
   4324                            mode = IN_SELECT_IN_TABLE;
   4325                            return;
   4326                        }
   4327                    }
   4328                }
   4329                mode = IN_SELECT;
   4330                return;
   4331            } else if ("td" == name || "th" == name) {
   4332                mode = IN_CELL;
   4333                return;
   4334            } else if ("tr" == name) {
   4335                mode = IN_ROW;
   4336                return;
   4337            } else if ("tbody" == name || "thead" == name || "tfoot" == name) {
   4338                mode = IN_TABLE_BODY;
   4339                return;
   4340            } else if ("caption" == name) {
   4341                mode = IN_CAPTION;
   4342                return;
   4343            } else if ("colgroup" == name) {
   4344                mode = IN_COLUMN_GROUP;
   4345                return;
   4346            } else if ("table" == name) {
   4347                mode = IN_TABLE;
   4348                return;
   4349            } else if ("http://www.w3.org/1999/xhtml" != ns) {
   4350                mode = framesetOk ? FRAMESET_OK : IN_BODY;
   4351                return;
   4352            } else if ("template" == name) {
   4353                assert templateModePtr >= 0;
   4354                mode = templateModeStack[templateModePtr];
   4355                return;
   4356            }  else if ("head" == name) {
   4357                if (name == contextName) {
   4358                    mode = framesetOk ? FRAMESET_OK : IN_BODY; // really
   4359                } else {
   4360                    mode = IN_HEAD;
   4361                }
   4362                return;
   4363            } else if ("body" == name) {
   4364                mode = framesetOk ? FRAMESET_OK : IN_BODY;
   4365                return;
   4366            } else if ("frameset" == name) {
   4367                // TODO: Fragment case. Add error reporting.
   4368                mode = IN_FRAMESET;
   4369                return;
   4370            } else if ("html" == name) {
   4371                if (headPointer == null) {
   4372                    // TODO: Fragment case. Add error reporting.
   4373                    mode = BEFORE_HEAD;
   4374                } else {
   4375                    mode = AFTER_HEAD;
   4376                }
   4377                return;
   4378            } else if (i == 0) {
   4379                mode = framesetOk ? FRAMESET_OK : IN_BODY;
   4380                return;
   4381            }
   4382        }
   4383    }
   4384 
   4385    /**
   4386     * @throws SAXException
   4387     *
   4388     */
   4389    private void implicitlyCloseP() throws SAXException {
   4390        int eltPos = findLastInButtonScope("p");
   4391        if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
   4392            return;
   4393        }
   4394        generateImpliedEndTagsExceptFor("p");
   4395        if (errorHandler != null && eltPos != currentPtr) {
   4396            errUnclosedElementsImplied(eltPos, "p");
   4397        }
   4398        while (currentPtr >= eltPos) {
   4399            pop();
   4400        }
   4401    }
   4402 
   4403    private boolean debugOnlyClearLastStackSlot() {
   4404        stack[currentPtr] = null;
   4405        return true;
   4406    }
   4407 
   4408    private boolean debugOnlyClearLastListSlot() {
   4409        listOfActiveFormattingElements[listPtr] = null;
   4410        return true;
   4411    }
   4412 
   4413    private void pushTemplateMode(int mode) {
   4414        templateModePtr++;
   4415        if (templateModePtr == templateModeStack.length) {
   4416            int[] newStack = new int[templateModeStack.length + 64];
   4417            System.arraycopy(templateModeStack, 0, newStack, 0, templateModeStack.length);
   4418            templateModeStack = newStack;
   4419        }
   4420        templateModeStack[templateModePtr] = mode;
   4421    }
   4422 
   4423    @SuppressWarnings("unchecked") private void push(StackNode<T> node) throws SAXException {
   4424        currentPtr++;
   4425        if (currentPtr == stack.length) {
   4426            StackNode<T>[] newStack = new StackNode[stack.length + 64];
   4427            System.arraycopy(stack, 0, newStack, 0, stack.length);
   4428            stack = newStack;
   4429        }
   4430        stack[currentPtr] = node;
   4431        elementPushed(node.ns, node.popName, node.node);
   4432    }
   4433 
   4434    @SuppressWarnings("unchecked") private void silentPush(StackNode<T> node) throws SAXException {
   4435        currentPtr++;
   4436        if (currentPtr == stack.length) {
   4437            StackNode<T>[] newStack = new StackNode[stack.length + 64];
   4438            System.arraycopy(stack, 0, newStack, 0, stack.length);
   4439            stack = newStack;
   4440        }
   4441        stack[currentPtr] = node;
   4442    }
   4443 
   4444    @SuppressWarnings("unchecked") private void append(StackNode<T> node) {
   4445        listPtr++;
   4446        if (listPtr == listOfActiveFormattingElements.length) {
   4447            StackNode<T>[] newList = new StackNode[listOfActiveFormattingElements.length + 64];
   4448            System.arraycopy(listOfActiveFormattingElements, 0, newList, 0,
   4449                    listOfActiveFormattingElements.length);
   4450            listOfActiveFormattingElements = newList;
   4451        }
   4452        listOfActiveFormattingElements[listPtr] = node;
   4453    }
   4454 
   4455    @Inline private void insertMarker() {
   4456        append(null);
   4457    }
   4458 
   4459    private void clearTheListOfActiveFormattingElementsUpToTheLastMarker() {
   4460        while (listPtr > -1) {
   4461            if (listOfActiveFormattingElements[listPtr] == null) {
   4462                --listPtr;
   4463                return;
   4464            }
   4465            listOfActiveFormattingElements[listPtr].release(this);
   4466            --listPtr;
   4467        }
   4468    }
   4469 
   4470    @Inline private boolean isCurrent(@Local String name) {
   4471        return stack[currentPtr].ns == "http://www.w3.org/1999/xhtml" &&
   4472                name == stack[currentPtr].name;
   4473    }
   4474 
   4475    private void removeFromStack(int pos) throws SAXException {
   4476        if (currentPtr == pos) {
   4477            pop();
   4478        } else {
   4479            fatal();
   4480            stack[pos].release(this);
   4481            System.arraycopy(stack, pos + 1, stack, pos, currentPtr - pos);
   4482            assert debugOnlyClearLastStackSlot();
   4483            currentPtr--;
   4484        }
   4485    }
   4486 
   4487    private void removeFromStack(StackNode<T> node) throws SAXException {
   4488        if (stack[currentPtr] == node) {
   4489            pop();
   4490        } else {
   4491            int pos = currentPtr - 1;
   4492            while (pos >= 0 && stack[pos] != node) {
   4493                pos--;
   4494            }
   4495            if (pos == -1) {
   4496                // dead code?
   4497                return;
   4498            }
   4499            fatal();
   4500            node.release(this);
   4501            System.arraycopy(stack, pos + 1, stack, pos, currentPtr - pos);
   4502            currentPtr--;
   4503        }
   4504    }
   4505 
   4506    private void removeFromListOfActiveFormattingElements(int pos) {
   4507        assert listOfActiveFormattingElements[pos] != null;
   4508        listOfActiveFormattingElements[pos].release(this);
   4509        if (pos == listPtr) {
   4510            assert debugOnlyClearLastListSlot();
   4511            listPtr--;
   4512            return;
   4513        }
   4514        assert pos < listPtr;
   4515        System.arraycopy(listOfActiveFormattingElements, pos + 1,
   4516                listOfActiveFormattingElements, pos, listPtr - pos);
   4517        assert debugOnlyClearLastListSlot();
   4518        listPtr--;
   4519    }
   4520 
   4521    /**
   4522     * Adoption agency algorithm.
   4523     *
   4524     * @param name subject as described in the specified algorithm.
   4525     * @return Returns true if the algorithm has completed and there is nothing remaining to
   4526     * be done. Returns false if the algorithm needs to "act as described in the 'any other
   4527     * end tag' entry" as described in the specified algorithm.
   4528     * @throws SAXException
   4529     */
   4530    private boolean adoptionAgencyEndTag(@Local String name) throws SAXException {
   4531        // This check intends to ensure that for properly nested tags, closing tags will match
   4532        // against the stack instead of the listOfActiveFormattingElements.
   4533        if (stack[currentPtr].ns == "http://www.w3.org/1999/xhtml" &&
   4534                stack[currentPtr].name == name &&
   4535                findInListOfActiveFormattingElements(stack[currentPtr]) == -1) {
   4536            // If the current element matches the name but isn't on the list of active
   4537            // formatting elements, then it is possible that the list was mangled by the Noah's Ark
   4538            // clause. In this case, we want to match the end tag against the stack instead of
   4539            // proceeding with the AAA algorithm that may match against the list of
   4540            // active formatting elements (and possibly mangle the tree in unexpected ways).
   4541            pop();
   4542            return true;
   4543        }
   4544 
   4545        // If you crash around here, perhaps some stack node variable claimed to
   4546        // be a weak ref isn't.
   4547        for (int i = 0; i < 8; ++i) {
   4548            int formattingEltListPos = listPtr;
   4549            while (formattingEltListPos > -1) {
   4550                StackNode<T> listNode = listOfActiveFormattingElements[formattingEltListPos]; // weak ref
   4551                if (listNode == null) {
   4552                    formattingEltListPos = -1;
   4553                    break;
   4554                } else if (listNode.name == name) {
   4555                    break;
   4556                }
   4557                formattingEltListPos--;
   4558            }
   4559            if (formattingEltListPos == -1) {
   4560                return false;
   4561            }
   4562            // this *looks* like a weak ref to the list of formatting elements
   4563            StackNode<T> formattingElt = listOfActiveFormattingElements[formattingEltListPos];
   4564            int formattingEltStackPos = currentPtr;
   4565            boolean inScope = true;
   4566            while (formattingEltStackPos > -1) {
   4567                StackNode<T> node = stack[formattingEltStackPos]; // weak ref
   4568                if (node == formattingElt) {
   4569                    break;
   4570                } else if (node.isScoping()) {
   4571                    inScope = false;
   4572                }
   4573                formattingEltStackPos--;
   4574            }
   4575            if (formattingEltStackPos == -1) {
   4576                errNoElementToCloseButEndTagSeen(name);
   4577                removeFromListOfActiveFormattingElements(formattingEltListPos);
   4578                return true;
   4579            }
   4580            if (!inScope) {
   4581                errNoElementToCloseButEndTagSeen(name);
   4582                return true;
   4583            }
   4584            // stackPos now points to the formatting element and it is in scope
   4585            if (formattingEltStackPos != currentPtr) {
   4586                errEndTagViolatesNestingRules(name);
   4587            }
   4588            int furthestBlockPos = formattingEltStackPos + 1;
   4589            while (furthestBlockPos <= currentPtr) {
   4590                StackNode<T> node = stack[furthestBlockPos]; // weak ref
   4591                assert furthestBlockPos > 0: "How is formattingEltStackPos + 1 not > 0?";
   4592                if (node.isSpecial()) {
   4593                    break;
   4594                }
   4595                furthestBlockPos++;
   4596            }
   4597            if (furthestBlockPos > currentPtr) {
   4598                // no furthest block
   4599                while (currentPtr >= formattingEltStackPos) {
   4600                    pop();
   4601                }
   4602                removeFromListOfActiveFormattingElements(formattingEltListPos);
   4603                return true;
   4604            }
   4605            // commonAncestor is used for running the algorithm and
   4606            // insertionCommonAncestor is used for the actual insertions to
   4607            // keep them depth-limited.
   4608            StackNode<T> commonAncestor = stack[formattingEltStackPos - 1]; // weak ref
   4609            T insertionCommonAncestor = nodeFromStackWithBlinkCompat(formattingEltStackPos - 1); // weak ref
   4610            StackNode<T> furthestBlock = stack[furthestBlockPos]; // weak ref
   4611            // detachFromParent(furthestBlock.node); XXX AAA CHANGE
   4612            int bookmark = formattingEltListPos;
   4613            int nodePos = furthestBlockPos;
   4614            StackNode<T> lastNode = furthestBlock; // weak ref
   4615            int j = 0;
   4616            for (;;) {
   4617                ++j;
   4618                nodePos--;
   4619                if (nodePos == formattingEltStackPos) {
   4620                    break;
   4621                }
   4622                StackNode<T> node = stack[nodePos]; // weak ref
   4623                int nodeListPos = findInListOfActiveFormattingElements(node);
   4624 
   4625                if (j > 3 && nodeListPos != -1) {
   4626                    removeFromListOfActiveFormattingElements(nodeListPos);
   4627 
   4628                    // Adjust the indices into the list to account
   4629                    // for the removal of nodeListPos.
   4630                    if (nodeListPos <= formattingEltListPos) {
   4631                        formattingEltListPos--;
   4632                    }
   4633                    if (nodeListPos <= bookmark) {
   4634                        bookmark--;
   4635                    }
   4636 
   4637                    // Update position to reflect removal from list.
   4638                    nodeListPos = -1;
   4639                }
   4640 
   4641                if (nodeListPos == -1) {
   4642                    assert formattingEltStackPos < nodePos;
   4643                    assert bookmark < nodePos;
   4644                    assert furthestBlockPos > nodePos;
   4645                    removeFromStack(nodePos); // node is now a bad pointer in C++
   4646                    furthestBlockPos--;
   4647                    continue;
   4648                }
   4649                // now node is both on stack and in the list
   4650                if (nodePos == furthestBlockPos) {
   4651                    bookmark = nodeListPos + 1;
   4652                }
   4653                // if (hasChildren(node.node)) { XXX AAA CHANGE
   4654                assert node == listOfActiveFormattingElements[nodeListPos];
   4655                assert node == stack[nodePos];
   4656                T clone = createElement("http://www.w3.org/1999/xhtml",
   4657                        node.name, node.attributes.cloneAttributes(), insertionCommonAncestor
   4658                        // CPPONLY: , htmlCreator(node.getHtmlCreator())
   4659                        );
   4660                StackNode<T> newNode = createStackNode(node.getFlags(), node.ns,
   4661                        node.name, clone, node.popName, node.attributes
   4662                        // CPPONLY: , node.getHtmlCreator()
   4663                        // [NOCPP[
   4664                        , node.getLocator()
   4665                        // ]NOCPP]
   4666                ); // creation ownership goes to stack
   4667                node.dropAttributes(); // adopt ownership to newNode
   4668                stack[nodePos] = newNode;
   4669                newNode.retain(); // retain for list
   4670                listOfActiveFormattingElements[nodeListPos] = newNode;
   4671                node.release(this); // release from stack
   4672                node.release(this); // release from list
   4673                node = newNode;
   4674                // } XXX AAA CHANGE
   4675                detachFromParent(lastNode.node);
   4676                appendElement(lastNode.node, nodeFromStackWithBlinkCompat(nodePos));
   4677                lastNode = node;
   4678            }
   4679            // If we insert into a foster parent, for simplicity, we insert
   4680            // accoding to the spec without Blink's depth limit.
   4681            if (commonAncestor.isFosterParenting()) {
   4682                fatal();
   4683                detachFromParent(lastNode.node);
   4684                insertIntoFosterParent(lastNode.node);
   4685            } else {
   4686                detachFromParent(lastNode.node);
   4687                appendElement(lastNode.node, insertionCommonAncestor);
   4688            }
   4689            T clone = createElement("http://www.w3.org/1999/xhtml",
   4690                    formattingElt.name,
   4691                    formattingElt.attributes.cloneAttributes(), furthestBlock.node
   4692                    // CPPONLY: , htmlCreator(formattingElt.getHtmlCreator())
   4693                    );
   4694            StackNode<T> formattingClone = createStackNode(
   4695                    formattingElt.getFlags(), formattingElt.ns,
   4696                    formattingElt.name, clone, formattingElt.popName,
   4697                    formattingElt.attributes
   4698                    // CPPONLY: , formattingElt.getHtmlCreator()
   4699                    // [NOCPP[
   4700                    , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
   4701                    // ]NOCPP]
   4702            ); // Ownership transfers to stack below
   4703            formattingElt.dropAttributes(); // transfer ownership to
   4704                                            // formattingClone
   4705            appendChildrenToNewParent(furthestBlock.node, clone);
   4706            appendElement(clone, furthestBlock.node);
   4707            removeFromListOfActiveFormattingElements(formattingEltListPos);
   4708            insertIntoListOfActiveFormattingElements(formattingClone, bookmark);
   4709            assert formattingEltStackPos < furthestBlockPos;
   4710            removeFromStack(formattingEltStackPos);
   4711            // furthestBlockPos is now off by one and points to the slot after
   4712            // it
   4713            insertIntoStack(formattingClone, furthestBlockPos);
   4714        }
   4715        return true;
   4716    }
   4717 
   4718    private void insertIntoStack(StackNode<T> node, int position)
   4719            throws SAXException {
   4720        assert currentPtr + 1 < stack.length;
   4721        assert position <= currentPtr + 1;
   4722        if (position == currentPtr + 1) {
   4723            push(node);
   4724        } else {
   4725            System.arraycopy(stack, position, stack, position + 1,
   4726                    (currentPtr - position) + 1);
   4727            currentPtr++;
   4728            stack[position] = node;
   4729        }
   4730    }
   4731 
   4732    private void insertIntoListOfActiveFormattingElements(
   4733            StackNode<T> formattingClone, int bookmark) {
   4734        formattingClone.retain();
   4735        assert listPtr + 1 < listOfActiveFormattingElements.length;
   4736        if (bookmark <= listPtr) {
   4737            System.arraycopy(listOfActiveFormattingElements, bookmark,
   4738                    listOfActiveFormattingElements, bookmark + 1,
   4739                    (listPtr - bookmark) + 1);
   4740        }
   4741        listPtr++;
   4742        listOfActiveFormattingElements[bookmark] = formattingClone;
   4743    }
   4744 
   4745    private int findInListOfActiveFormattingElements(StackNode<T> node) {
   4746        for (int i = listPtr; i >= 0; i--) {
   4747            if (node == listOfActiveFormattingElements[i]) {
   4748                return i;
   4749            }
   4750        }
   4751        return -1;
   4752    }
   4753 
   4754    private int findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
   4755            @Local String name) {
   4756        for (int i = listPtr; i >= 0; i--) {
   4757            StackNode<T> node = listOfActiveFormattingElements[i];
   4758            if (node == null) {
   4759                return -1;
   4760            } else if (node.name == name) {
   4761                return i;
   4762            }
   4763        }
   4764        return -1;
   4765    }
   4766 
   4767 
   4768    private void maybeForgetEarlierDuplicateFormattingElement(
   4769            @Local String name, HtmlAttributes attributes) throws SAXException {
   4770        int candidate = -1;
   4771        int count = 0;
   4772        for (int i = listPtr; i >= 0; i--) {
   4773            StackNode<T> node = listOfActiveFormattingElements[i];
   4774            if (node == null) {
   4775                break;
   4776            }
   4777            if (node.name == name && node.attributes.equalsAnother(attributes)) {
   4778                candidate = i;
   4779                ++count;
   4780            }
   4781        }
   4782        if (count >= 3) {
   4783            removeFromListOfActiveFormattingElements(candidate);
   4784        }
   4785    }
   4786 
   4787    private int findLastOrRoot(@Local String name) {
   4788        for (int i = currentPtr; i > 0; i--) {
   4789            if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].name == name) {
   4790                return i;
   4791            }
   4792        }
   4793        return 0;
   4794    }
   4795 
   4796    private int findLastOrRoot(int group) {
   4797        for (int i = currentPtr; i > 0; i--) {
   4798            if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].getGroup() == group) {
   4799                return i;
   4800            }
   4801        }
   4802        return 0;
   4803    }
   4804 
   4805    /**
   4806     * Attempt to add attribute to the body element.
   4807     * @param attributes the attributes
   4808     * @return <code>true</code> iff the attributes were added
   4809     * @throws SAXException
   4810     */
   4811    private boolean addAttributesToBody(HtmlAttributes attributes)
   4812            throws SAXException {
   4813        // [NOCPP[
   4814        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   4815        // ]NOCPP]
   4816        if (currentPtr >= 1) {
   4817            StackNode<T> body = stack[1];
   4818            if (body.getGroup() == TreeBuilder.BODY) {
   4819                addAttributesToElement(body.node, attributes);
   4820                return true;
   4821            }
   4822        }
   4823        return false;
   4824    }
   4825 
   4826    private void addAttributesToHtml(HtmlAttributes attributes)
   4827            throws SAXException {
   4828        // [NOCPP[
   4829        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   4830        // ]NOCPP]
   4831        addAttributesToElement(stack[0].node, attributes);
   4832    }
   4833 
   4834    private void pushHeadPointerOntoStack() throws SAXException {
   4835        assert headPointer != null;
   4836        assert mode == AFTER_HEAD;
   4837        fatal();
   4838        silentPush(createStackNode(ElementName.HEAD, headPointer
   4839        // [NOCPP[
   4840                , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
   4841        // ]NOCPP]
   4842        ));
   4843    }
   4844 
   4845    /**
   4846     * @throws SAXException
   4847     *
   4848     */
   4849    private void reconstructTheActiveFormattingElements() throws SAXException {
   4850        if (listPtr == -1) {
   4851            return;
   4852        }
   4853        StackNode<T> mostRecent = listOfActiveFormattingElements[listPtr];
   4854        if (mostRecent == null || isInStack(mostRecent)) {
   4855            return;
   4856        }
   4857        int entryPos = listPtr;
   4858        for (;;) {
   4859            entryPos--;
   4860            if (entryPos == -1) {
   4861                break;
   4862            }
   4863            if (listOfActiveFormattingElements[entryPos] == null) {
   4864                break;
   4865            }
   4866            if (isInStack(listOfActiveFormattingElements[entryPos])) {
   4867                break;
   4868            }
   4869        }
   4870        while (entryPos < listPtr) {
   4871            entryPos++;
   4872            StackNode<T> entry = listOfActiveFormattingElements[entryPos];
   4873            StackNode<T> current = stack[currentPtr];
   4874 
   4875            T clone;
   4876            if (current.isFosterParenting()) {
   4877                clone = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", entry.name,
   4878                        entry.attributes.cloneAttributes()
   4879                        // CPPONLY: , htmlCreator(entry.getHtmlCreator())
   4880                        );
   4881            } else {
   4882                T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   4883                clone = createElement("http://www.w3.org/1999/xhtml", entry.name,
   4884                        entry.attributes.cloneAttributes(), currentNode
   4885                        // CPPONLY: , htmlCreator(entry.getHtmlCreator())
   4886                        );
   4887                appendElement(clone, currentNode);
   4888            }
   4889 
   4890            StackNode<T> entryClone = createStackNode(entry.getFlags(),
   4891                    entry.ns, entry.name, clone, entry.popName,
   4892                    entry.attributes
   4893                    // CPPONLY: , entry.getHtmlCreator()
   4894                    // [NOCPP[
   4895                    , entry.getLocator()
   4896                    // ]NOCPP]
   4897            );
   4898 
   4899            entry.dropAttributes(); // transfer ownership to entryClone
   4900 
   4901            push(entryClone);
   4902            // stack takes ownership of the local variable
   4903            listOfActiveFormattingElements[entryPos] = entryClone;
   4904            // overwriting the old entry on the list, so release & retain
   4905            entry.release(this);
   4906            entryClone.retain();
   4907        }
   4908    }
   4909 
   4910    void notifyUnusedStackNode(int idxInStackNodes) {
   4911        // stackNodesIdx is the earliest possible index of a stack node that might be unused,
   4912        // so update the index if necessary.
   4913        if (idxInStackNodes < stackNodesIdx) {
   4914            stackNodesIdx = idxInStackNodes;
   4915        }
   4916    }
   4917 
   4918    @SuppressWarnings("unchecked") private StackNode<T> getUnusedStackNode() {
   4919        // Search for an unused stack node.
   4920        while (stackNodesIdx < numStackNodes) {
   4921            if (stackNodes[stackNodesIdx].isUnused()) {
   4922                return stackNodes[stackNodesIdx++];
   4923            }
   4924            stackNodesIdx++;
   4925        }
   4926 
   4927        if (stackNodesIdx < stackNodes.length) {
   4928            // No unused stack nodes, but there is still space in the storage array.
   4929            stackNodes[stackNodesIdx] = new StackNode<T>(stackNodesIdx);
   4930            numStackNodes++;
   4931            return stackNodes[stackNodesIdx++];
   4932        }
   4933 
   4934        // Could not find an unused stack node and storage array is full.
   4935        StackNode<T>[] newStack = new StackNode[stackNodes.length + 64];
   4936        System.arraycopy(stackNodes, 0, newStack, 0, stackNodes.length);
   4937        stackNodes = newStack;
   4938 
   4939        // Create a new stack node and return it.
   4940        stackNodes[stackNodesIdx] = new StackNode<T>(stackNodesIdx);
   4941        numStackNodes++;
   4942        return stackNodes[stackNodesIdx++];
   4943    }
   4944 
   4945    private StackNode<T> createStackNode(int flags, @NsUri String ns, @Local String name, T node,
   4946            @Local String popName, HtmlAttributes attributes
   4947            // CPPONLY: , @HtmlCreator Object htmlCreator
   4948            // [NOCPP[
   4949            , TaintableLocatorImpl locator
   4950            // ]NOCPP]
   4951    ) {
   4952        StackNode<T> instance = getUnusedStackNode();
   4953        instance.setValues(flags, ns, name, node, popName, attributes
   4954                // CPPONLY: , htmlCreator
   4955                // [NOCPP[
   4956                , locator
   4957                // ]NOCPP]
   4958        );
   4959        return instance;
   4960    }
   4961 
   4962    private StackNode<T> createStackNode(ElementName elementName, T node
   4963            // [NOCPP[
   4964            , TaintableLocatorImpl locator
   4965            // ]NOCPP]
   4966    ) {
   4967        StackNode<T> instance = getUnusedStackNode();
   4968        instance.setValues(elementName, node
   4969                // [NOCPP[
   4970                , locator
   4971                // ]NOCPP]
   4972        );
   4973        return instance;
   4974    }
   4975 
   4976    private StackNode<T> createStackNode(ElementName elementName, T node, HtmlAttributes attributes
   4977            // [NOCPP[
   4978            , TaintableLocatorImpl locator
   4979            // ]NOCPP]
   4980    ) {
   4981        StackNode<T> instance = getUnusedStackNode();
   4982        instance.setValues(elementName, node, attributes
   4983                // [NOCPP[
   4984                , locator
   4985                // ]NOCPP]
   4986        );
   4987        return instance;
   4988    }
   4989 
   4990    private StackNode<T> createStackNode(ElementName elementName, T node, @Local String popName
   4991            // [NOCPP[
   4992            , TaintableLocatorImpl locator
   4993            // ]NOCPP]
   4994    ) {
   4995        StackNode<T> instance = getUnusedStackNode();
   4996        instance.setValues(elementName, node, popName
   4997                // [NOCPP[
   4998                , locator
   4999                // ]NOCPP]
   5000        );
   5001        return instance;
   5002    }
   5003 
   5004    private StackNode<T> createStackNode(ElementName elementName, @Local String popName, T node
   5005            // [NOCPP[
   5006            , TaintableLocatorImpl locator
   5007            // ]NOCPP]
   5008    ) {
   5009        StackNode<T> instance = getUnusedStackNode();
   5010        instance.setValues(elementName, popName, node
   5011                // [NOCPP[
   5012                , locator
   5013                // ]NOCPP]
   5014        );
   5015        return instance;
   5016    }
   5017 
   5018    private StackNode<T> createStackNode(ElementName elementName, T node, @Local String popName,
   5019            boolean markAsIntegrationPoint
   5020            // [NOCPP[
   5021            , TaintableLocatorImpl locator
   5022            // ]NOCPP]
   5023    ) {
   5024        StackNode<T> instance = getUnusedStackNode();
   5025        instance.setValues(elementName, node, popName, markAsIntegrationPoint
   5026                // [NOCPP[
   5027                , locator
   5028                // ]NOCPP]
   5029        );
   5030        return instance;
   5031    }
   5032 
   5033    private void insertIntoFosterParent(T child) throws SAXException {
   5034        int tablePos = findLastOrRoot(TreeBuilder.TABLE);
   5035        int templatePos = findLastOrRoot(TreeBuilder.TEMPLATE);
   5036 
   5037        if (templatePos >= tablePos) {
   5038            appendElement(child, stack[templatePos].node);
   5039            return;
   5040        }
   5041 
   5042        StackNode<T> node = stack[tablePos];
   5043        insertFosterParentedChild(child, node.node, stack[tablePos - 1].node);
   5044    }
   5045 
   5046    private T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name,
   5047            HtmlAttributes attributes
   5048            // CPPONLY: , @Creator Object creator
   5049            ) throws SAXException {
   5050        return createAndInsertFosterParentedElement(ns, name, attributes, null
   5051                // CPPONLY: , creator
   5052                );
   5053    }
   5054 
   5055    private T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name,
   5056            HtmlAttributes attributes, T form
   5057            // CPPONLY: , @Creator Object creator
   5058            ) throws SAXException {
   5059        int tablePos = findLastOrRoot(TreeBuilder.TABLE);
   5060        int templatePos = findLastOrRoot(TreeBuilder.TEMPLATE);
   5061 
   5062        if (templatePos >= tablePos) {
   5063            T child = createElement(ns, name, attributes, form, stack[templatePos].node
   5064                    // CPPONLY: , creator
   5065                    );
   5066            appendElement(child, stack[templatePos].node);
   5067            return child;
   5068        }
   5069 
   5070        StackNode<T> node = stack[tablePos];
   5071        return createAndInsertFosterParentedElement(ns, name, attributes, form, node.node, stack[tablePos - 1].node
   5072                // CPPONLY: , creator
   5073                );
   5074    }
   5075 
   5076    private boolean isInStack(StackNode<T> node) {
   5077        for (int i = currentPtr; i >= 0; i--) {
   5078            if (stack[i] == node) {
   5079                return true;
   5080            }
   5081        }
   5082        return false;
   5083    }
   5084 
   5085    private void popTemplateMode() {
   5086        templateModePtr--;
   5087    }
   5088 
   5089    private void pop() throws SAXException {
   5090        StackNode<T> node = stack[currentPtr];
   5091        assert debugOnlyClearLastStackSlot();
   5092        currentPtr--;
   5093        elementPopped(node.ns, node.popName, node.node);
   5094        node.release(this);
   5095    }
   5096 
   5097    private void popForeign(int origPos, int eltPos) throws SAXException {
   5098        StackNode<T> node = stack[currentPtr];
   5099        if (origPos != currentPtr || eltPos != currentPtr) {
   5100            markMalformedIfScript(node.node);
   5101        }
   5102        assert debugOnlyClearLastStackSlot();
   5103        currentPtr--;
   5104        elementPopped(node.ns, node.popName, node.node);
   5105        node.release(this);
   5106    }
   5107 
   5108    private void silentPop() throws SAXException {
   5109        StackNode<T> node = stack[currentPtr];
   5110        assert debugOnlyClearLastStackSlot();
   5111        currentPtr--;
   5112        node.release(this);
   5113    }
   5114 
   5115    private void popOnEof() throws SAXException {
   5116        StackNode<T> node = stack[currentPtr];
   5117        assert debugOnlyClearLastStackSlot();
   5118        currentPtr--;
   5119        markMalformedIfScript(node.node);
   5120        elementPopped(node.ns, node.popName, node.node);
   5121        node.release(this);
   5122    }
   5123 
   5124    // [NOCPP[
   5125    private void checkAttributes(HtmlAttributes attributes, @NsUri String ns)
   5126            throws SAXException {
   5127        if (errorHandler != null) {
   5128            int len = attributes.getXmlnsLength();
   5129            for (int i = 0; i < len; i++) {
   5130                AttributeName name = attributes.getXmlnsAttributeName(i);
   5131                if (name == AttributeName.XMLNS) {
   5132                    String xmlns = attributes.getXmlnsValue(i);
   5133                    if (!ns.equals(xmlns)) {
   5134                        err("Bad value \u201C"
   5135                                + xmlns
   5136                                + "\u201D for the attribute \u201Cxmlns\u201D (only \u201C"
   5137                                + ns + "\u201D permitted here).");
   5138                        switch (namePolicy) {
   5139                            case ALTER_INFOSET:
   5140                                // fall through
   5141                            case ALLOW:
   5142                                warn("Attribute \u201Cxmlns\u201D is not serializable as XML 1.0.");
   5143                                break;
   5144                            case FATAL:
   5145                                fatal("Attribute \u201Cxmlns\u201D is not serializable as XML 1.0.");
   5146                                break;
   5147                        }
   5148                    }
   5149                } else if (ns != "http://www.w3.org/1999/xhtml"
   5150                        && name == AttributeName.XMLNS_XLINK) {
   5151                    String xmlns = attributes.getXmlnsValue(i);
   5152                    if (!"http://www.w3.org/1999/xlink".equals(xmlns)) {
   5153                        err("Bad value \u201C"
   5154                                + xmlns
   5155                                + "\u201D for the attribute \u201Cxmlns:link\u201D (only \u201Chttp://www.w3.org/1999/xlink\u201D permitted here).");
   5156                        switch (namePolicy) {
   5157                            case ALTER_INFOSET:
   5158                                // fall through
   5159                            case ALLOW:
   5160                                warn("Attribute \u201Cxmlns:xlink\u201D with a value other than \u201Chttp://www.w3.org/1999/xlink\u201D is not serializable as XML 1.0 without changing document semantics.");
   5161                                break;
   5162                            case FATAL:
   5163                                fatal("Attribute \u201Cxmlns:xlink\u201D with a value other than \u201Chttp://www.w3.org/1999/xlink\u201D is not serializable as XML 1.0 without changing document semantics.");
   5164                                break;
   5165                        }
   5166                    }
   5167                } else {
   5168                    err("Attribute \u201C" + attributes.getXmlnsLocalName(i)
   5169                            + "\u201D not allowed here.");
   5170                    switch (namePolicy) {
   5171                        case ALTER_INFOSET:
   5172                            // fall through
   5173                        case ALLOW:
   5174                            warn("Attribute with the local name \u201C"
   5175                                    + attributes.getXmlnsLocalName(i)
   5176                                    + "\u201D is not serializable as XML 1.0.");
   5177                            break;
   5178                        case FATAL:
   5179                            fatal("Attribute with the local name \u201C"
   5180                                    + attributes.getXmlnsLocalName(i)
   5181                                    + "\u201D is not serializable as XML 1.0.");
   5182                            break;
   5183                    }
   5184                }
   5185            }
   5186        }
   5187        attributes.processNonNcNames(this, namePolicy);
   5188    }
   5189 
   5190    private String checkPopName(@Local String name) throws SAXException {
   5191        if (NCName.isNCName(name)) {
   5192            return name;
   5193        } else {
   5194            switch (namePolicy) {
   5195                case ALLOW:
   5196                    warn("Element name \u201C" + name
   5197                            + "\u201D cannot be represented as XML 1.0.");
   5198                    return name;
   5199                case ALTER_INFOSET:
   5200                    warn("Element name \u201C" + name
   5201                            + "\u201D cannot be represented as XML 1.0.");
   5202                    return NCName.escapeName(name);
   5203                case FATAL:
   5204                    fatal("Element name \u201C" + name
   5205                            + "\u201D cannot be represented as XML 1.0.");
   5206            }
   5207        }
   5208        return null; // keep compiler happy
   5209    }
   5210 
   5211    // ]NOCPP]
   5212 
   5213    private void appendHtmlElementToDocumentAndPush(HtmlAttributes attributes)
   5214            throws SAXException {
   5215        // [NOCPP[
   5216        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5217        // ]NOCPP]
   5218        T elt = createHtmlElementSetAsRoot(attributes);
   5219        StackNode<T> node = createStackNode(ElementName.HTML,
   5220                elt
   5221                // [NOCPP[
   5222                , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
   5223        // ]NOCPP]
   5224        );
   5225        push(node);
   5226    }
   5227 
   5228    private void appendHtmlElementToDocumentAndPush() throws SAXException {
   5229        appendHtmlElementToDocumentAndPush(tokenizer.emptyAttributes());
   5230    }
   5231 
   5232    private void appendToCurrentNodeAndPushHeadElement(HtmlAttributes attributes)
   5233            throws SAXException {
   5234        // [NOCPP[
   5235        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5236        // ]NOCPP]
   5237        T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5238        T elt = createElement("http://www.w3.org/1999/xhtml", "head", attributes, currentNode
   5239                /*
   5240                 * head uses NS_NewHTMLSharedElement creator
   5241                 */
   5242                // CPPONLY: , htmlCreator(NS_NewHTMLSharedElement)
   5243                );
   5244        appendElement(elt, currentNode);
   5245        headPointer = elt;
   5246        StackNode<T> node = createStackNode(ElementName.HEAD,
   5247                elt
   5248                // [NOCPP[
   5249                , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
   5250        // ]NOCPP]
   5251        );
   5252        push(node);
   5253    }
   5254 
   5255    private void appendToCurrentNodeAndPushBodyElement(HtmlAttributes attributes)
   5256            throws SAXException {
   5257        appendToCurrentNodeAndPushElement(ElementName.BODY,
   5258                attributes);
   5259    }
   5260 
   5261    private void appendToCurrentNodeAndPushBodyElement() throws SAXException {
   5262        appendToCurrentNodeAndPushBodyElement(tokenizer.emptyAttributes());
   5263    }
   5264 
   5265    private void appendToCurrentNodeAndPushFormElementMayFoster(
   5266            HtmlAttributes attributes) throws SAXException {
   5267        // [NOCPP[
   5268        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5269        // ]NOCPP]
   5270 
   5271        T elt;
   5272        StackNode<T> current = stack[currentPtr];
   5273        if (current.isFosterParenting()) {
   5274            fatal();
   5275            elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", "form", attributes
   5276                    // CPPONLY: , htmlCreator(NS_NewHTMLFormElement)
   5277                    );
   5278        } else {
   5279            T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5280            elt = createElement("http://www.w3.org/1999/xhtml", "form", attributes, currentNode
   5281                    // CPPONLY: , htmlCreator(NS_NewHTMLFormElement)
   5282                    );
   5283            appendElement(elt, currentNode);
   5284        }
   5285 
   5286        if (!isTemplateContents()) {
   5287            formPointer = elt;
   5288        }
   5289 
   5290        StackNode<T> node = createStackNode(ElementName.FORM,
   5291                elt
   5292                // [NOCPP[
   5293                , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
   5294                // ]NOCPP]
   5295        );
   5296        push(node);
   5297    }
   5298 
   5299    private void appendToCurrentNodeAndPushFormattingElementMayFoster(
   5300            ElementName elementName, HtmlAttributes attributes)
   5301            throws SAXException {
   5302        // [NOCPP[
   5303        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5304        // ]NOCPP]
   5305        // This method can't be called for custom elements
   5306        HtmlAttributes clone = attributes.cloneAttributes();
   5307        // Attributes must not be read after calling createElement, because
   5308        // createElement may delete attributes in C++.
   5309        T elt;
   5310        StackNode<T> current = stack[currentPtr];
   5311        if (current.isFosterParenting()) {
   5312            fatal();
   5313            elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName.getName(), attributes
   5314                    // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5315                    );
   5316        } else {
   5317            T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5318            elt = createElement("http://www.w3.org/1999/xhtml", elementName.getName(), attributes, currentNode
   5319                    // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5320                    );
   5321            appendElement(elt, currentNode);
   5322        }
   5323        StackNode<T> node = createStackNode(elementName, elt, clone
   5324                // [NOCPP[
   5325                , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
   5326        // ]NOCPP]
   5327        );
   5328        push(node);
   5329        append(node);
   5330        node.retain(); // append doesn't retain itself
   5331    }
   5332 
   5333    private void appendToCurrentNodeAndPushElement(ElementName elementName,
   5334            HtmlAttributes attributes)
   5335            throws SAXException {
   5336        // [NOCPP[
   5337        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5338        // ]NOCPP]
   5339        // This method can't be called for custom elements
   5340        T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5341        T elt = createElement("http://www.w3.org/1999/xhtml", elementName.getName(), attributes, currentNode
   5342                // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5343                );
   5344        if (ElementName.TEMPLATE == elementName) {
   5345            T root = getDeclarativeShadowRoot(currentNode, elt, attributes);
   5346            if (root != null) {
   5347                setDocumentFragmentForTemplate(elt, root);
   5348                elt = root;
   5349            } else {
   5350                appendElement(elt, currentNode);
   5351                elt = getDocumentFragmentForTemplate(elt);
   5352            }
   5353        } else {
   5354            appendElement(elt, currentNode);
   5355        }
   5356        StackNode<T> node = createStackNode(elementName, elt
   5357                // [NOCPP[
   5358                , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
   5359        // ]NOCPP]
   5360        );
   5361        push(node);
   5362    }
   5363 
   5364    private void appendToCurrentNodeAndPushElementMayFoster(ElementName elementName,
   5365            HtmlAttributes attributes)
   5366            throws SAXException {
   5367        @Local String popName = elementName.getName();
   5368        // [NOCPP[
   5369        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5370        if (!elementName.isInterned()) {
   5371            popName = checkPopName(popName);
   5372        }
   5373        // ]NOCPP]
   5374        T elt;
   5375        StackNode<T> current = stack[currentPtr];
   5376        if (current.isFosterParenting()) {
   5377            fatal();
   5378            elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", popName, attributes
   5379                    // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5380                    );
   5381        } else {
   5382            T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5383            elt = createElement("http://www.w3.org/1999/xhtml", popName, attributes, currentNode
   5384                    // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5385                    );
   5386            appendElement(elt, currentNode);
   5387        }
   5388        StackNode<T> node = createStackNode(elementName, elt, popName
   5389                // [NOCPP[
   5390                , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
   5391        // ]NOCPP]
   5392        );
   5393        push(node);
   5394    }
   5395 
   5396    private void appendToCurrentNodeAndPushElementMayFosterMathML(
   5397            ElementName elementName, HtmlAttributes attributes)
   5398            throws SAXException {
   5399        @Local String popName = elementName.getName();
   5400        // [NOCPP[
   5401        checkAttributes(attributes, "http://www.w3.org/1998/Math/MathML");
   5402        if (!elementName.isInterned()) {
   5403            popName = checkPopName(popName);
   5404        }
   5405        // ]NOCPP]
   5406        boolean markAsHtmlIntegrationPoint = false;
   5407        if (ElementName.ANNOTATION_XML == elementName
   5408                && annotationXmlEncodingPermitsHtml(attributes)) {
   5409            markAsHtmlIntegrationPoint = true;
   5410        }
   5411        // Attributes must not be read after calling createElement(), since
   5412        // createElement may delete the object in C++.
   5413        T elt;
   5414        StackNode<T> current = stack[currentPtr];
   5415        if (current.isFosterParenting()) {
   5416            fatal();
   5417            elt = createAndInsertFosterParentedElement("http://www.w3.org/1998/Math/MathML", popName, attributes
   5418                    // CPPONLY: , htmlCreator(null)
   5419                    );
   5420        } else {
   5421            T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5422            elt  = createElement("http://www.w3.org/1998/Math/MathML", popName, attributes, currentNode
   5423                    // CPPONLY: , htmlCreator(null)
   5424                    );
   5425            appendElement(elt, currentNode);
   5426        }
   5427        StackNode<T> node = createStackNode(elementName, elt, popName,
   5428                markAsHtmlIntegrationPoint
   5429                // [NOCPP[
   5430                , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
   5431        // ]NOCPP]
   5432        );
   5433        push(node);
   5434    }
   5435 
   5436    // [NOCPP[
   5437    T getDocumentFragmentForTemplate(T template) {
   5438        return template;
   5439    }
   5440 
   5441    void setDocumentFragmentForTemplate(T template, T fragment) {
   5442    }
   5443 
   5444    T getShadowRootFromHost(T host, T template, String shadowRootMode,
   5445            boolean shadowRootIsClonable, boolean shadowRootIsSerializable, boolean shadowRootDelegatesFocus,
   5446            String shadowRootReferenceTarget) {
   5447        return null;
   5448    }
   5449 
   5450    T getFormPointerForContext(T context) {
   5451        return null;
   5452    }
   5453    // ]NOCPP]
   5454 
   5455    private boolean annotationXmlEncodingPermitsHtml(HtmlAttributes attributes) {
   5456        String encoding = attributes.getValue(AttributeName.ENCODING);
   5457        if (encoding == null) {
   5458            return false;
   5459        }
   5460        return Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
   5461                "application/xhtml+xml", encoding)
   5462                || Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
   5463                        "text/html", encoding);
   5464    }
   5465 
   5466    private void appendToCurrentNodeAndPushElementMayFosterSVG(
   5467            ElementName elementName, HtmlAttributes attributes)
   5468            throws SAXException {
   5469        @Local String popName = elementName.getCamelCaseName();
   5470        // [NOCPP[
   5471        checkAttributes(attributes, "http://www.w3.org/2000/svg");
   5472        if (!elementName.isInterned()) {
   5473            popName = checkPopName(popName);
   5474        }
   5475        // ]NOCPP]
   5476        T elt;
   5477        StackNode<T> current = stack[currentPtr];
   5478        if (current.isFosterParenting()) {
   5479            fatal();
   5480            elt = createAndInsertFosterParentedElement("http://www.w3.org/2000/svg", popName, attributes
   5481                    // CPPONLY: , svgCreator(elementName.getSvgCreator())
   5482                    );
   5483        } else {
   5484            T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5485            elt = createElement("http://www.w3.org/2000/svg", popName, attributes, currentNode
   5486                    // CPPONLY: , svgCreator(elementName.getSvgCreator())
   5487                    );
   5488            appendElement(elt, currentNode);
   5489        }
   5490        StackNode<T> node = createStackNode(elementName, popName, elt
   5491                // [NOCPP[
   5492                , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
   5493        // ]NOCPP]
   5494        );
   5495        push(node);
   5496    }
   5497 
   5498    private void appendToCurrentNodeAndPushElementMayFoster(ElementName elementName,
   5499            HtmlAttributes attributes, T form)
   5500            throws SAXException {
   5501        // [NOCPP[
   5502        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5503        // ]NOCPP]
   5504        // Can't be called for custom elements
   5505        T elt;
   5506        T formOwner = form == null || fragment || isTemplateContents() ? null : form;
   5507        StackNode<T> current = stack[currentPtr];
   5508        if (current.isFosterParenting()) {
   5509            fatal();
   5510            elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName.getName(),
   5511                    attributes, formOwner
   5512                    // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5513                    );
   5514        } else {
   5515            T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5516            elt = createElement("http://www.w3.org/1999/xhtml", elementName.getName(),
   5517                    attributes, formOwner, currentNode
   5518                    // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5519                    );
   5520            appendElement(elt, currentNode);
   5521        }
   5522        StackNode<T> node = createStackNode(elementName, elt
   5523                // [NOCPP[
   5524                , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
   5525        // ]NOCPP]
   5526        );
   5527        push(node);
   5528    }
   5529 
   5530    private void appendVoidElementToCurrent(
   5531            ElementName elementName, HtmlAttributes attributes)
   5532            throws SAXException {
   5533        @Local String popName = elementName.getName();
   5534        // [NOCPP[
   5535        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5536        if (!elementName.isInterned()) {
   5537            popName = checkPopName(popName);
   5538        }
   5539        // ]NOCPP]
   5540        T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5541        T elt = createElement("http://www.w3.org/1999/xhtml", popName, attributes, currentNode
   5542                // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5543                );
   5544        appendElement(elt, currentNode);
   5545        elementPushed("http://www.w3.org/1999/xhtml", popName, elt);
   5546        elementPopped("http://www.w3.org/1999/xhtml", popName, elt);
   5547    }
   5548 
   5549    private void appendVoidElementToCurrentMayFoster(
   5550            ElementName elementName, HtmlAttributes attributes, T form) throws SAXException {
   5551        @Local String name = elementName.getName();
   5552        // [NOCPP[
   5553        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5554        // ]NOCPP]
   5555        // Can't be called for custom elements
   5556        T elt;
   5557        T formOwner = form == null || fragment || isTemplateContents() ? null : form;
   5558        StackNode<T> current = stack[currentPtr];
   5559        if (current.isFosterParenting()) {
   5560            fatal();
   5561            elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", name,
   5562                    attributes, formOwner
   5563                    // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5564                    );
   5565        } else {
   5566            T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5567            elt = createElement("http://www.w3.org/1999/xhtml", name,
   5568 
   5569                    attributes, formOwner, currentNode
   5570                    // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5571                    );
   5572            appendElement(elt, currentNode);
   5573        }
   5574        elementPushed("http://www.w3.org/1999/xhtml", name, elt);
   5575        elementPopped("http://www.w3.org/1999/xhtml", name, elt);
   5576    }
   5577 
   5578    private void appendVoidElementToCurrentMayFoster(
   5579            ElementName elementName, HtmlAttributes attributes)
   5580            throws SAXException {
   5581        @Local String popName = elementName.getName();
   5582        // [NOCPP[
   5583        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5584        if (!elementName.isInterned()) {
   5585            popName = checkPopName(popName);
   5586        }
   5587        // ]NOCPP]
   5588        T elt;
   5589        StackNode<T> current = stack[currentPtr];
   5590        if (current.isFosterParenting()) {
   5591            fatal();
   5592            elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", popName, attributes
   5593                    // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5594                    );
   5595        } else {
   5596            T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5597            elt = createElement("http://www.w3.org/1999/xhtml", popName, attributes, currentNode
   5598                    // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
   5599                    );
   5600            appendElement(elt, currentNode);
   5601        }
   5602        elementPushed("http://www.w3.org/1999/xhtml", popName, elt);
   5603        elementPopped("http://www.w3.org/1999/xhtml", popName, elt);
   5604    }
   5605 
   5606    private void appendVoidElementToCurrentMayFosterSVG(
   5607            ElementName elementName, HtmlAttributes attributes)
   5608            throws SAXException {
   5609        @Local String popName = elementName.getCamelCaseName();
   5610        // [NOCPP[
   5611        checkAttributes(attributes, "http://www.w3.org/2000/svg");
   5612        if (!elementName.isInterned()) {
   5613            popName = checkPopName(popName);
   5614        }
   5615        // ]NOCPP]
   5616        T elt;
   5617        StackNode<T> current = stack[currentPtr];
   5618        if (current.isFosterParenting()) {
   5619            fatal();
   5620            elt = createAndInsertFosterParentedElement("http://www.w3.org/2000/svg", popName, attributes
   5621                    // CPPONLY: , svgCreator(elementName.getSvgCreator())
   5622                    );
   5623        } else {
   5624            T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5625            elt = createElement("http://www.w3.org/2000/svg", popName, attributes, currentNode
   5626                    // CPPONLY: , svgCreator(elementName.getSvgCreator())
   5627                    );
   5628            appendElement(elt, currentNode);
   5629        }
   5630        elementPushed("http://www.w3.org/2000/svg", popName, elt);
   5631        elementPopped("http://www.w3.org/2000/svg", popName, elt);
   5632    }
   5633 
   5634    private void appendVoidElementToCurrentMayFosterMathML(
   5635            ElementName elementName, HtmlAttributes attributes)
   5636            throws SAXException {
   5637        @Local String popName = elementName.getName();
   5638        // [NOCPP[
   5639        checkAttributes(attributes, "http://www.w3.org/1998/Math/MathML");
   5640        if (!elementName.isInterned()) {
   5641            popName = checkPopName(popName);
   5642        }
   5643        // ]NOCPP]
   5644        T elt;
   5645        StackNode<T> current = stack[currentPtr];
   5646        if (current.isFosterParenting()) {
   5647            fatal();
   5648            elt = createAndInsertFosterParentedElement("http://www.w3.org/1998/Math/MathML", popName, attributes
   5649                    // CPPONLY: , htmlCreator(null)
   5650                    );
   5651        } else {
   5652            T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5653            elt = createElement("http://www.w3.org/1998/Math/MathML", popName, attributes, currentNode
   5654                    // CPPONLY: , htmlCreator(null)
   5655                    );
   5656            appendElement(elt, currentNode);
   5657        }
   5658        elementPushed("http://www.w3.org/1998/Math/MathML", popName, elt);
   5659        elementPopped("http://www.w3.org/1998/Math/MathML", popName, elt);
   5660    }
   5661 
   5662    private void appendVoidInputToCurrent(HtmlAttributes attributes, T form) throws SAXException {
   5663        // [NOCPP[
   5664        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5665        // ]NOCPP]
   5666        // Can't be called for custom elements
   5667        T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5668        T elt = createElement("http://www.w3.org/1999/xhtml", "input", attributes,
   5669                form == null || fragment || isTemplateContents() ? null : form, currentNode
   5670                        // CPPONLY: , htmlCreator(NS_NewHTMLInputElement)
   5671                        );
   5672        appendElement(elt, currentNode);
   5673        elementPushed("http://www.w3.org/1999/xhtml", "input", elt);
   5674        elementPopped("http://www.w3.org/1999/xhtml", "input", elt);
   5675    }
   5676 
   5677    private void appendVoidFormToCurrent(HtmlAttributes attributes) throws SAXException {
   5678        // [NOCPP[
   5679        checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
   5680        // ]NOCPP]
   5681        T currentNode = nodeFromStackWithBlinkCompat(currentPtr);
   5682        T elt = createElement("http://www.w3.org/1999/xhtml", "form",
   5683                attributes, currentNode
   5684                // CPPONLY: , htmlCreator(NS_NewHTMLFormElement)
   5685                );
   5686        formPointer = elt;
   5687        // ownership transferred to form pointer
   5688        appendElement(elt, currentNode);
   5689        elementPushed("http://www.w3.org/1999/xhtml", "form", elt);
   5690        elementPopped("http://www.w3.org/1999/xhtml", "form", elt);
   5691    }
   5692 
   5693    // [NOCPP[
   5694 
   5695    private final void accumulateCharactersForced(@Const @NoLength char[] buf,
   5696            int start, int length) throws SAXException {
   5697        System.arraycopy(buf, start, charBuffer, charBufferLen, length);
   5698        charBufferLen += length;
   5699    }
   5700 
   5701    @Override public void ensureBufferSpace(int inputLength)
   5702            throws SAXException {
   5703        // TODO: Unify Tokenizer.strBuf and TreeBuilder.charBuffer so that
   5704        // this method becomes unnecessary.
   5705        int worstCase = charBufferLen + inputLength;
   5706        if (charBuffer == null) {
   5707            // Add an arbitrary small value to avoid immediate reallocation
   5708            // once there are a few characters in the buffer.
   5709            charBuffer = new char[worstCase + 128];
   5710        } else if (worstCase > charBuffer.length) {
   5711            // HotSpot reportedly allocates memory with 8-byte accuracy, so
   5712            // there's no point in trying to do math here to avoid slop.
   5713            // Maybe we should add some small constant to worstCase here
   5714            // but not doing that without profiling. In C++ with jemalloc,
   5715            // the corresponding method should do math to round up here
   5716            // to avoid slop.
   5717            char[] newBuf = new char[worstCase];
   5718            System.arraycopy(charBuffer, 0, newBuf, 0, charBufferLen);
   5719            charBuffer = newBuf;
   5720        }
   5721    }
   5722 
   5723    // ]NOCPP]
   5724 
   5725    protected void accumulateCharacters(@Const @NoLength char[] buf, int start,
   5726            int length) throws SAXException {
   5727        appendCharacters(stack[currentPtr].node, buf, start, length);
   5728    }
   5729 
   5730    // ------------------------------- //
   5731 
   5732    protected final void requestSuspension() {
   5733        tokenizer.requestSuspension();
   5734    }
   5735 
   5736    protected abstract T createElement(@NsUri String ns, @Local String name,
   5737            HtmlAttributes attributes, T intendedParent
   5738            // CPPONLY: , @Creator Object creator
   5739            ) throws SAXException;
   5740 
   5741    protected T createElement(@NsUri String ns, @Local String name,
   5742            HtmlAttributes attributes, T form, T intendedParent
   5743            // CPPONLY: , @Creator Object creator
   5744            ) throws SAXException {
   5745        return createElement("http://www.w3.org/1999/xhtml", name, attributes, intendedParent
   5746                // CPPONLY: , creator
   5747                );
   5748    }
   5749 
   5750    protected abstract T createHtmlElementSetAsRoot(HtmlAttributes attributes)
   5751            throws SAXException;
   5752 
   5753    protected abstract void detachFromParent(T element) throws SAXException;
   5754 
   5755    protected abstract boolean hasChildren(T element) throws SAXException;
   5756 
   5757    protected abstract void appendElement(T child, T newParent)
   5758            throws SAXException;
   5759 
   5760    protected abstract void appendChildrenToNewParent(T oldParent, T newParent)
   5761            throws SAXException;
   5762 
   5763    protected abstract void insertFosterParentedChild(T child, T table,
   5764            T stackParent) throws SAXException;
   5765 
   5766    // We don't generate CPP code for this method because it is not used in generated CPP
   5767    // code. Instead, the form owner version of this method is called with a null form owner.
   5768    // [NOCPP[
   5769 
   5770    protected abstract T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name,
   5771            HtmlAttributes attributes, T table, T stackParent) throws SAXException;
   5772 
   5773    // ]NOCPP]
   5774 
   5775    protected T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name,
   5776            HtmlAttributes attributes, T form, T table, T stackParent
   5777            // CPPONLY: , @Creator Object creator
   5778            ) throws SAXException {
   5779        return createAndInsertFosterParentedElement(ns, name, attributes, table, stackParent);
   5780    };
   5781 
   5782    protected abstract void insertFosterParentedCharacters(
   5783            @NoLength char[] buf, int start, int length, T table, T stackParent)
   5784            throws SAXException;
   5785 
   5786    protected abstract void appendCharacters(T parent, @NoLength char[] buf,
   5787            int start, int length) throws SAXException;
   5788 
   5789    protected abstract void appendComment(T parent, @NoLength char[] buf,
   5790            int start, int length) throws SAXException;
   5791 
   5792    protected abstract void appendCommentToDocument(@NoLength char[] buf,
   5793            int start, int length) throws SAXException;
   5794 
   5795    protected abstract void addAttributesToElement(T element,
   5796            HtmlAttributes attributes) throws SAXException;
   5797 
   5798    protected void markMalformedIfScript(T elt) throws SAXException {
   5799 
   5800    }
   5801 
   5802    protected void start(boolean fragmentMode) throws SAXException {
   5803 
   5804    }
   5805 
   5806    protected void end() throws SAXException {
   5807 
   5808    }
   5809 
   5810    protected void appendDoctypeToDocument(@Local String name,
   5811            String publicIdentifier, String systemIdentifier)
   5812            throws SAXException {
   5813 
   5814    }
   5815 
   5816    protected void elementPushed(@NsUri String ns, @Local String name, T node)
   5817            throws SAXException {
   5818 
   5819    }
   5820 
   5821    protected void elementPopped(@NsUri String ns, @Local String name, T node)
   5822            throws SAXException {
   5823 
   5824    }
   5825 
   5826    // [NOCPP[
   5827 
   5828    protected void documentMode(DocumentMode m, String publicIdentifier,
   5829            String systemIdentifier)
   5830            throws SAXException {
   5831 
   5832    }
   5833 
   5834    /**
   5835     * @see nu.validator.htmlparser.common.TokenHandler#wantsComments()
   5836     */
   5837    public boolean wantsComments() {
   5838        return wantingComments;
   5839    }
   5840 
   5841    public void setIgnoringComments(boolean ignoreComments) {
   5842        wantingComments = !ignoreComments;
   5843    }
   5844 
   5845    /**
   5846     * Sets the errorHandler.
   5847     *
   5848     * @param errorHandler
   5849     *            the errorHandler to set
   5850     */
   5851    public final void setErrorHandler(ErrorHandler errorHandler) {
   5852        this.errorHandler = errorHandler;
   5853    }
   5854 
   5855    /**
   5856     * Returns the errorHandler.
   5857     *
   5858     * @return the errorHandler
   5859     */
   5860    public ErrorHandler getErrorHandler() {
   5861        return errorHandler;
   5862    }
   5863 
   5864    /**
   5865     * The argument MUST be an interned string or <code>null</code>.
   5866     *
   5867     * @param context
   5868     */
   5869    public final void setFragmentContext(@Local String context) {
   5870        this.contextName = context;
   5871        this.contextNamespace = "http://www.w3.org/1999/xhtml";
   5872        this.contextNode = null;
   5873        this.fragment = (contextName != null);
   5874        this.quirks = false;
   5875    }
   5876 
   5877    // ]NOCPP]
   5878 
   5879    /**
   5880     * @see nu.validator.htmlparser.common.TokenHandler#cdataSectionAllowed()
   5881     */
   5882    @Inline public boolean cdataSectionAllowed() throws SAXException {
   5883        return isInForeign();
   5884    }
   5885 
   5886    private boolean isInForeign() {
   5887        return currentPtr >= 0
   5888                && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml";
   5889    }
   5890 
   5891    private boolean isInForeignButNotHtmlOrMathTextIntegrationPoint() {
   5892        if (currentPtr < 0) {
   5893            return false;
   5894        }
   5895        return !isSpecialParentInForeign(stack[currentPtr]);
   5896    }
   5897 
   5898    /**
   5899     * The argument MUST be an interned string or <code>null</code>.
   5900     *
   5901     * @param context
   5902     */
   5903    public final void setFragmentContext(@Local String context,
   5904            @NsUri String ns, T node, boolean quirks) {
   5905        // [NOCPP[
   5906        if (!((context == null && ns == null)
   5907                || "http://www.w3.org/1999/xhtml" == ns
   5908                || "http://www.w3.org/2000/svg" == ns || "http://www.w3.org/1998/Math/MathML" == ns)) {
   5909            throw new IllegalArgumentException(
   5910                    "The namespace must be the HTML, SVG or MathML namespace (or null when the local name is null). Got: "
   5911                            + ns);
   5912        }
   5913        // ]NOCPP]
   5914        this.contextName = context;
   5915        this.contextNamespace = ns;
   5916        this.contextNode = node;
   5917        this.fragment = (contextName != null);
   5918        this.quirks = quirks;
   5919    }
   5920 
   5921    protected final T currentNode() {
   5922        return stack[currentPtr].node;
   5923    }
   5924 
   5925    /**
   5926     * Returns the scriptingEnabled.
   5927     *
   5928     * @return the scriptingEnabled
   5929     */
   5930    public boolean isScriptingEnabled() {
   5931        return scriptingEnabled;
   5932    }
   5933 
   5934    /**
   5935     * Sets the scriptingEnabled.
   5936     *
   5937     * @param scriptingEnabled
   5938     *            the scriptingEnabled to set
   5939     */
   5940    public void setScriptingEnabled(boolean scriptingEnabled) {
   5941        this.scriptingEnabled = scriptingEnabled;
   5942    }
   5943 
   5944    public void setForceNoQuirks(boolean forceNoQuirks) {
   5945        this.forceNoQuirks = forceNoQuirks;
   5946    }
   5947 
   5948    // Redundant method retained because previously public.
   5949    public void setIsSrcdocDocument(boolean isSrcdocDocument) {
   5950        this.setForceNoQuirks(isSrcdocDocument);
   5951    }
   5952 
   5953    public boolean isAllowDeclarativeShadowRoots() {
   5954        return allowDeclarativeShadowRoots;
   5955    }
   5956 
   5957    public void setAllowDeclarativeShadowRoots(boolean allow) {
   5958        allowDeclarativeShadowRoots = allow;
   5959    }
   5960 
   5961    // [NOCPP[
   5962 
   5963    public void setNamePolicy(XmlViolationPolicy namePolicy) {
   5964        this.namePolicy = namePolicy;
   5965    }
   5966 
   5967    /**
   5968     * Sets the documentModeHandler.
   5969     *
   5970     * @param documentModeHandler
   5971     *            the documentModeHandler to set
   5972     */
   5973    public void setDocumentModeHandler(DocumentModeHandler documentModeHandler) {
   5974        this.documentModeHandler = documentModeHandler;
   5975    }
   5976 
   5977    /**
   5978     * Sets the reportingDoctype.
   5979     *
   5980     * @param reportingDoctype
   5981     *            the reportingDoctype to set
   5982     */
   5983    public void setReportingDoctype(boolean reportingDoctype) {
   5984        this.reportingDoctype = reportingDoctype;
   5985    }
   5986 
   5987    // ]NOCPP]
   5988 
   5989    /**
   5990     * Flushes the pending characters. Public for document.write use cases only.
   5991     * @throws SAXException
   5992     */
   5993    public final void flushCharacters() throws SAXException {
   5994        if (charBufferLen > 0) {
   5995            if ((mode == IN_TABLE || mode == IN_TABLE_BODY || mode == IN_ROW)
   5996                    && charBufferContainsNonWhitespace()) {
   5997                errNonSpaceInTable();
   5998                reconstructTheActiveFormattingElements();
   5999                if (!stack[currentPtr].isFosterParenting()) {
   6000                    // reconstructing gave us a new current node
   6001                    appendCharacters(currentNode(), charBuffer, 0,
   6002                            charBufferLen);
   6003                    charBufferLen = 0;
   6004                    return;
   6005                }
   6006 
   6007                int tablePos = findLastOrRoot(TreeBuilder.TABLE);
   6008                int templatePos = findLastOrRoot(TreeBuilder.TEMPLATE);
   6009 
   6010                if (templatePos >= tablePos) {
   6011                    appendCharacters(stack[templatePos].node, charBuffer, 0, charBufferLen);
   6012                    charBufferLen = 0;
   6013                    return;
   6014                }
   6015 
   6016                StackNode<T> tableElt = stack[tablePos];
   6017                insertFosterParentedCharacters(charBuffer, 0, charBufferLen,
   6018                        tableElt.node, stack[tablePos - 1].node);
   6019                charBufferLen = 0;
   6020                return;
   6021            }
   6022            appendCharacters(currentNode(), charBuffer, 0, charBufferLen);
   6023            charBufferLen = 0;
   6024        }
   6025    }
   6026 
   6027    private boolean charBufferContainsNonWhitespace() {
   6028        for (int i = 0; i < charBufferLen; i++) {
   6029            switch (charBuffer[i]) {
   6030                case ' ':
   6031                case '\t':
   6032                case '\n':
   6033                case '\r':
   6034                case '\u000C':
   6035                    continue;
   6036                default:
   6037                    return true;
   6038            }
   6039        }
   6040        return false;
   6041    }
   6042 
   6043    /**
   6044     * Creates a comparable snapshot of the tree builder state. Snapshot
   6045     * creation is only supported immediately after a script end tag has been
   6046     * processed. In C++ the caller is responsible for calling
   6047     * <code>delete</code> on the returned object.
   6048     *
   6049     * @return a snapshot.
   6050     * @throws SAXException
   6051     */
   6052    @SuppressWarnings("unchecked") public TreeBuilderState<T> newSnapshot()
   6053            throws SAXException {
   6054        StackNode<T>[] listCopy = new StackNode[listPtr + 1];
   6055        for (int i = 0; i < listCopy.length; i++) {
   6056            StackNode<T> node = listOfActiveFormattingElements[i];
   6057            if (node != null) {
   6058                StackNode<T> newNode = new StackNode<T>(-1);
   6059                newNode.setValues(node.getFlags(), node.ns,
   6060                        node.name, node.node, node.popName,
   6061                        node.attributes.cloneAttributes()
   6062                        // CPPONLY: , node.getHtmlCreator()
   6063                        // [NOCPP[
   6064                        , node.getLocator()
   6065                        // ]NOCPP]
   6066                );
   6067                listCopy[i] = newNode;
   6068            } else {
   6069                listCopy[i] = null;
   6070            }
   6071        }
   6072        StackNode<T>[] stackCopy = new StackNode[currentPtr + 1];
   6073        for (int i = 0; i < stackCopy.length; i++) {
   6074            StackNode<T> node = stack[i];
   6075            int listIndex = findInListOfActiveFormattingElements(node);
   6076            if (listIndex == -1) {
   6077                StackNode<T> newNode = new StackNode<T>(-1);
   6078                newNode.setValues(node.getFlags(), node.ns,
   6079                        node.name, node.node, node.popName,
   6080                        null
   6081                        // CPPONLY: , node.getHtmlCreator()
   6082                        // [NOCPP[
   6083                        , node.getLocator()
   6084                        // ]NOCPP]
   6085                );
   6086                stackCopy[i] = newNode;
   6087            } else {
   6088                stackCopy[i] = listCopy[listIndex];
   6089                stackCopy[i].retain();
   6090            }
   6091        }
   6092        int[] templateModeStackCopy = new int[templateModePtr + 1];
   6093        System.arraycopy(templateModeStack, 0, templateModeStackCopy, 0,
   6094                templateModeStackCopy.length);
   6095        return new StateSnapshot<T>(stackCopy, listCopy, templateModeStackCopy, formPointer,
   6096                headPointer, mode, originalMode, framesetOk,
   6097                needToDropLF, quirks);
   6098    }
   6099 
   6100    public boolean snapshotMatches(TreeBuilderState<T> snapshot) {
   6101        StackNode<T>[] stackCopy = snapshot.getStack();
   6102        int stackLen = snapshot.getStackLength();
   6103        StackNode<T>[] listCopy = snapshot.getListOfActiveFormattingElements();
   6104        int listLen = snapshot.getListOfActiveFormattingElementsLength();
   6105        int[] templateModeStackCopy = snapshot.getTemplateModeStack();
   6106        int templateModeStackLen = snapshot.getTemplateModeStackLength();
   6107 
   6108        if (stackLen != currentPtr + 1
   6109                || listLen != listPtr + 1
   6110                || templateModeStackLen != templateModePtr + 1
   6111                || formPointer != snapshot.getFormPointer()
   6112                || headPointer != snapshot.getHeadPointer()
   6113                || mode != snapshot.getMode()
   6114                || originalMode != snapshot.getOriginalMode()
   6115                || framesetOk != snapshot.isFramesetOk()
   6116                || needToDropLF != snapshot.isNeedToDropLF()
   6117                || quirks != snapshot.isQuirks()) { // maybe just assert quirks
   6118            return false;
   6119        }
   6120        for (int i = listLen - 1; i >= 0; i--) {
   6121            if (listCopy[i] == null
   6122                    && listOfActiveFormattingElements[i] == null) {
   6123                continue;
   6124            } else if (listCopy[i] == null
   6125                    || listOfActiveFormattingElements[i] == null) {
   6126                return false;
   6127            }
   6128            if (listCopy[i].node != listOfActiveFormattingElements[i].node) {
   6129                return false; // it's possible that this condition is overly
   6130                              // strict
   6131            }
   6132        }
   6133        for (int i = stackLen - 1; i >= 0; i--) {
   6134            if (stackCopy[i].node != stack[i].node) {
   6135                return false;
   6136            }
   6137        }
   6138        for (int i = templateModeStackLen - 1; i >=0; i--) {
   6139            if (templateModeStackCopy[i] != templateModeStack[i]) {
   6140                return false;
   6141            }
   6142        }
   6143        return true;
   6144    }
   6145 
   6146    @SuppressWarnings("unchecked") public void loadState(
   6147            TreeBuilderState<T> snapshot)
   6148            throws SAXException {
   6149        // CPPONLY: mCurrentHtmlScriptCannotDocumentWriteOrBlock = false;
   6150        StackNode<T>[] stackCopy = snapshot.getStack();
   6151        int stackLen = snapshot.getStackLength();
   6152        StackNode<T>[] listCopy = snapshot.getListOfActiveFormattingElements();
   6153        int listLen = snapshot.getListOfActiveFormattingElementsLength();
   6154        int[] templateModeStackCopy = snapshot.getTemplateModeStack();
   6155        int templateModeStackLen = snapshot.getTemplateModeStackLength();
   6156 
   6157        for (int i = 0; i <= listPtr; i++) {
   6158            if (listOfActiveFormattingElements[i] != null) {
   6159                listOfActiveFormattingElements[i].release(this);
   6160            }
   6161        }
   6162        if (listOfActiveFormattingElements.length < listLen) {
   6163            listOfActiveFormattingElements = new StackNode[listLen];
   6164        }
   6165        listPtr = listLen - 1;
   6166 
   6167        for (int i = 0; i <= currentPtr; i++) {
   6168            stack[i].release(this);
   6169        }
   6170        if (stack.length < stackLen) {
   6171            stack = new StackNode[stackLen];
   6172        }
   6173        currentPtr = stackLen - 1;
   6174 
   6175        if (templateModeStack.length < templateModeStackLen) {
   6176            templateModeStack = new int[templateModeStackLen];
   6177        }
   6178        templateModePtr = templateModeStackLen - 1;
   6179 
   6180        for (int i = 0; i < listLen; i++) {
   6181            StackNode<T> node = listCopy[i];
   6182            if (node != null) {
   6183                StackNode<T> newNode = createStackNode(node.getFlags(), node.ns,
   6184                        node.name, node.node,
   6185                        node.popName,
   6186                        node.attributes.cloneAttributes()
   6187                        // CPPONLY: , node.getHtmlCreator()
   6188                        // [NOCPP[
   6189                        , node.getLocator()
   6190                // ]NOCPP]
   6191                );
   6192                listOfActiveFormattingElements[i] = newNode;
   6193            } else {
   6194                listOfActiveFormattingElements[i] = null;
   6195            }
   6196        }
   6197        for (int i = 0; i < stackLen; i++) {
   6198            StackNode<T> node = stackCopy[i];
   6199            int listIndex = findInArray(node, listCopy);
   6200            if (listIndex == -1) {
   6201                StackNode<T> newNode = createStackNode(node.getFlags(), node.ns,
   6202                        node.name, node.node,
   6203                        node.popName,
   6204                        null
   6205                        // CPPONLY: , node.getHtmlCreator()
   6206                        // [NOCPP[
   6207                        , node.getLocator()
   6208                // ]NOCPP]
   6209                );
   6210                stack[i] = newNode;
   6211            } else {
   6212                stack[i] = listOfActiveFormattingElements[listIndex];
   6213                stack[i].retain();
   6214            }
   6215        }
   6216        System.arraycopy(templateModeStackCopy, 0, templateModeStack, 0, templateModeStackLen);
   6217        formPointer = snapshot.getFormPointer();
   6218        headPointer = snapshot.getHeadPointer();
   6219        mode = snapshot.getMode();
   6220        originalMode = snapshot.getOriginalMode();
   6221        framesetOk = snapshot.isFramesetOk();
   6222        needToDropLF = snapshot.isNeedToDropLF();
   6223        quirks = snapshot.isQuirks();
   6224    }
   6225 
   6226    private int findInArray(StackNode<T> node, StackNode<T>[] arr) {
   6227        for (int i = listPtr; i >= 0; i--) {
   6228            if (node == arr[i]) {
   6229                return i;
   6230            }
   6231        }
   6232        return -1;
   6233    }
   6234 
   6235    /**
   6236     * Returns <code>stack[stackPos].node</code> if <code>stackPos</code> is
   6237     * smaller than Blink's magic limit or the node at Blink's magic limit
   6238     * otherwise.
   6239     *
   6240     * In order to get Blink-compatible handling of excessive deeply-nested
   6241     * markup, this method must be used to obtain the node that is used as the
   6242     * parent node of an insertion.
   6243     *
   6244     * Blink's magic number is 512, but our counting is off by one compared to
   6245     * Blink's way of counting, so in order to get the same
   6246     * externally-observable outcome, we use 511 as our magic number.
   6247     *
   6248     * @param stackPos the stack position to attempt to read
   6249     * @return node at the position capped to Blink's magic number
   6250     * @throws SAXException
   6251     */
   6252    private T nodeFromStackWithBlinkCompat(int stackPos) throws SAXException {
   6253        // Magic number if off by one relative to Blink's magic number, but the
   6254        // outcome is the same, because the counting is different by one.
   6255        if (stackPos > 511) {
   6256            errDeepTree();
   6257            return stack[511].node;
   6258        }
   6259        return stack[stackPos].node;
   6260    }
   6261    /**
   6262     * @see nu.validator.htmlparser.impl.TreeBuilderState#getFormPointer()
   6263     */
   6264    @Override
   6265    public T getFormPointer() {
   6266        return formPointer;
   6267    }
   6268 
   6269    /**
   6270     * Returns the headPointer.
   6271     *
   6272     * @return the headPointer
   6273     */
   6274    @Override
   6275    public T getHeadPointer() {
   6276        return headPointer;
   6277    }
   6278 
   6279    /**
   6280     * @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElements()
   6281     */
   6282    @Override
   6283    public StackNode<T>[] getListOfActiveFormattingElements() {
   6284        return listOfActiveFormattingElements;
   6285    }
   6286 
   6287    /**
   6288     * @see nu.validator.htmlparser.impl.TreeBuilderState#getStack()
   6289     */
   6290    @Override
   6291    public StackNode<T>[] getStack() {
   6292        return stack;
   6293    }
   6294 
   6295    /**
   6296     * @see nu.validator.htmlparser.impl.TreeBuilderState#getTemplateModeStack()
   6297     */
   6298    @Override
   6299    public int[] getTemplateModeStack() {
   6300        return templateModeStack;
   6301    }
   6302 
   6303    /**
   6304     * Returns the mode.
   6305     *
   6306     * @return the mode
   6307     */
   6308    @Override
   6309    public int getMode() {
   6310        return mode;
   6311    }
   6312 
   6313    /**
   6314     * Returns the originalMode.
   6315     *
   6316     * @return the originalMode
   6317     */
   6318    @Override
   6319    public int getOriginalMode() {
   6320        return originalMode;
   6321    }
   6322 
   6323    /**
   6324     * Returns the framesetOk.
   6325     *
   6326     * @return the framesetOk
   6327     */
   6328    @Override
   6329    public boolean isFramesetOk() {
   6330        return framesetOk;
   6331    }
   6332 
   6333    /**
   6334     * Returns the needToDropLF.
   6335     *
   6336     * @return the needToDropLF
   6337     */
   6338    @Override
   6339    public boolean isNeedToDropLF() {
   6340        return needToDropLF;
   6341    }
   6342 
   6343    /**
   6344     * Returns the quirks.
   6345     *
   6346     * @return the quirks
   6347     */
   6348    @Override
   6349    public boolean isQuirks() {
   6350        return quirks;
   6351    }
   6352 
   6353    /**
   6354     * @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElementsLength()
   6355     */
   6356    @Override
   6357    public int getListOfActiveFormattingElementsLength() {
   6358        return listPtr + 1;
   6359    }
   6360 
   6361    /**
   6362     * @see nu.validator.htmlparser.impl.TreeBuilderState#getStackLength()
   6363     */
   6364    @Override
   6365    public int getStackLength() {
   6366        return currentPtr + 1;
   6367    }
   6368 
   6369    /**
   6370     * @see nu.validator.htmlparser.impl.TreeBuilderState#getTemplateModeStackLength()
   6371     */
   6372    @Override
   6373    public int getTemplateModeStackLength() {
   6374        return templateModePtr + 1;
   6375    }
   6376 
   6377    /**
   6378     * Complains about an over-deep tree. Theoretically this should just be
   6379     * a warning, but in practice authors should take this as an error.
   6380     *
   6381     * @throws SAXException
   6382     */
   6383    private void errDeepTree() throws SAXException {
   6384        err("The document tree is more than 513 elements deep, which causes Firefox and Chrome to flatten the tree.");
   6385    }
   6386 
   6387    /**
   6388     * Reports a stray start tag.
   6389     * @param name the name of the stray tag
   6390     *
   6391     * @throws SAXException
   6392     */
   6393    private void errStrayStartTag(@Local String name) throws SAXException {
   6394        err("Stray start tag \u201C" + name + "\u201D.");
   6395    }
   6396 
   6397    /**
   6398     * Reports a stray end tag.
   6399     * @param name the name of the stray tag
   6400     *
   6401     * @throws SAXException
   6402     */
   6403    private void errStrayEndTag(@Local String name) throws SAXException {
   6404        err("Stray end tag \u201C" + name + "\u201D.");
   6405    }
   6406 
   6407    /**
   6408     * Reports a state when elements expected to be closed were not.
   6409     *
   6410     * @param eltPos the position of the start tag on the stack of the element
   6411     * being closed.
   6412     * @param name the name of the end tag
   6413     *
   6414     * @throws SAXException
   6415     */
   6416    private void errUnclosedElements(int eltPos, @Local String name) throws SAXException {
   6417        errNoCheck("End tag \u201C" + name + "\u201D seen, but there were open elements.");
   6418        errListUnclosedStartTags(eltPos);
   6419    }
   6420 
   6421    /**
   6422     * Reports a state when elements expected to be closed ahead of an implied
   6423     * end tag but were not.
   6424     *
   6425     * @param eltPos the position of the start tag on the stack of the element
   6426     * being closed.
   6427     * @param name the name of the end tag
   6428     *
   6429     * @throws SAXException
   6430     */
   6431    private void errUnclosedElementsImplied(int eltPos, String name) throws SAXException {
   6432        errNoCheck("End tag \u201C" + name + "\u201D implied, but there were open elements.");
   6433        errListUnclosedStartTags(eltPos);
   6434    }
   6435 
   6436    /**
   6437     * Reports a state when elements expected to be closed ahead of an implied
   6438     * table cell close.
   6439     *
   6440     * @param eltPos the position of the start tag on the stack of the element
   6441     * being closed.
   6442     * @throws SAXException
   6443     */
   6444    private void errUnclosedElementsCell(int eltPos) throws SAXException {
   6445        errNoCheck("A table cell was implicitly closed, but there were open elements.");
   6446        errListUnclosedStartTags(eltPos);
   6447    }
   6448 
   6449    private void errStrayDoctype() throws SAXException {
   6450        err("Stray doctype.");
   6451    }
   6452 
   6453    private void errAlmostStandardsDoctype() throws SAXException {
   6454        if (!forceNoQuirks) {
   6455            err("Almost standards mode doctype. Expected \u201C<!DOCTYPE html>\u201D.");
   6456        }
   6457    }
   6458 
   6459    private void errQuirkyDoctype() throws SAXException {
   6460        if (!forceNoQuirks) {
   6461            err("Quirky doctype. Expected \u201C<!DOCTYPE html>\u201D.");
   6462        }
   6463    }
   6464 
   6465    private void errNonSpaceInTrailer() throws SAXException {
   6466        err("Non-space character in page trailer.");
   6467    }
   6468 
   6469    private void errNonSpaceAfterFrameset() throws SAXException {
   6470        err("Non-space after \u201Cframeset\u201D.");
   6471    }
   6472 
   6473    private void errNonSpaceInFrameset() throws SAXException {
   6474        err("Non-space in \u201Cframeset\u201D.");
   6475    }
   6476 
   6477    private void errNonSpaceAfterBody() throws SAXException {
   6478        err("Non-space character after body.");
   6479    }
   6480 
   6481    private void errNonSpaceInColgroupInFragment() throws SAXException {
   6482        err("Non-space in \u201Ccolgroup\u201D when parsing fragment.");
   6483    }
   6484 
   6485    private void errNonSpaceInNoscriptInHead() throws SAXException {
   6486        err("Non-space character inside \u201Cnoscript\u201D inside \u201Chead\u201D.");
   6487    }
   6488 
   6489    private void errFooBetweenHeadAndBody(@Local String name) throws SAXException {
   6490        if (errorHandler == null) {
   6491            return;
   6492        }
   6493        errNoCheck("\u201C" + name + "\u201D element between \u201Chead\u201D and \u201Cbody\u201D.");
   6494    }
   6495 
   6496    private void errStartTagWithoutDoctype() throws SAXException {
   6497        if (!forceNoQuirks) {
   6498            err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
   6499        }
   6500    }
   6501 
   6502    private void errNoSelectInTableScope() throws SAXException {
   6503        err("No \u201Cselect\u201D in table scope.");
   6504    }
   6505 
   6506    private void errStartSelectWhereEndSelectExpected() throws SAXException {
   6507        err("\u201Cselect\u201D start tag where end tag expected.");
   6508    }
   6509 
   6510    private void errStartTagWithSelectOpen(@Local String name)
   6511            throws SAXException {
   6512        if (errorHandler == null) {
   6513            return;
   6514        }
   6515        errNoCheck("\u201C" + name
   6516                + "\u201D start tag with \u201Cselect\u201D open.");
   6517    }
   6518 
   6519    private void errBadStartTagInNoscriptInHead(@Local String name) throws SAXException {
   6520        if (errorHandler == null) {
   6521            return;
   6522        }
   6523        errNoCheck("Bad start tag in \u201C" + name
   6524                + "\u201D in \u201Cnoscript\u201D in \u201Chead\u201D.");
   6525    }
   6526 
   6527    private void errImage() throws SAXException {
   6528        err("Saw a start tag \u201Cimage\u201D.");
   6529    }
   6530 
   6531    private void errFooSeenWhenFooOpen(@Local String name) throws SAXException {
   6532        if (errorHandler == null) {
   6533            return;
   6534        }
   6535        errNoCheck("Start tag \u201C" + name + "\u201D seen but an element of the same type was already open.");
   6536    }
   6537 
   6538    private void errHeadingWhenHeadingOpen() throws SAXException {
   6539        err("Heading cannot be a child of another heading.");
   6540    }
   6541 
   6542    private void errFramesetStart() throws SAXException {
   6543        err("\u201Cframeset\u201D start tag seen.");
   6544    }
   6545 
   6546    private void errNoCellToClose() throws SAXException {
   6547        err("No cell to close.");
   6548    }
   6549 
   6550    private void errStartTagInTable(@Local String name) throws SAXException {
   6551        if (errorHandler == null) {
   6552            return;
   6553        }
   6554        errNoCheck("Start tag \u201C" + name
   6555                + "\u201D seen in \u201Ctable\u201D.");
   6556    }
   6557 
   6558    private void errFormWhenFormOpen() throws SAXException {
   6559        err("Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag.");
   6560    }
   6561 
   6562    private void errTableSeenWhileTableOpen() throws SAXException {
   6563        err("Start tag for \u201Ctable\u201D seen but the previous \u201Ctable\u201D is still open.");
   6564    }
   6565 
   6566    private void errStartTagInTableBody(@Local String name) throws SAXException {
   6567        if (errorHandler == null) {
   6568            return;
   6569        }
   6570        errNoCheck("\u201C" + name + "\u201D start tag in table body.");
   6571    }
   6572 
   6573    private void errEndTagSeenWithoutDoctype() throws SAXException {
   6574        if (!forceNoQuirks) {
   6575            err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
   6576        }
   6577    }
   6578 
   6579    private void errEndTagAfterBody() throws SAXException {
   6580        err("Saw an end tag after \u201Cbody\u201D had been closed.");
   6581    }
   6582 
   6583    private void errEndTagSeenWithSelectOpen(@Local String name) throws SAXException {
   6584        if (errorHandler == null) {
   6585            return;
   6586        }
   6587        errNoCheck("\u201C" + name
   6588                + "\u201D end tag with \u201Cselect\u201D open.");
   6589    }
   6590 
   6591    private void errGarbageInColgroup() throws SAXException {
   6592        err("Garbage in \u201Ccolgroup\u201D fragment.");
   6593    }
   6594 
   6595    private void errEndTagBr() throws SAXException {
   6596        err("End tag \u201Cbr\u201D.");
   6597    }
   6598 
   6599    private void errNoElementToCloseButEndTagSeen(@Local String name)
   6600            throws SAXException {
   6601        if (errorHandler == null) {
   6602            return;
   6603        }
   6604        errNoCheck("No \u201C" + name + "\u201D element in scope but a \u201C"
   6605                + name + "\u201D end tag seen.");
   6606    }
   6607 
   6608    private void errHtmlStartTagInForeignContext(@Local String name)
   6609            throws SAXException {
   6610        if (errorHandler == null) {
   6611            return;
   6612        }
   6613        errNoCheck("HTML start tag \u201C" + name
   6614                + "\u201D in a foreign namespace context.");
   6615    }
   6616 
   6617    private void errNoTableRowToClose() throws SAXException {
   6618        err("No table row to close.");
   6619    }
   6620 
   6621    private void errNonSpaceInTable() throws SAXException {
   6622        err("Misplaced non-space characters inside a table.");
   6623    }
   6624 
   6625    private void errUnclosedChildrenInRuby() throws SAXException {
   6626        if (errorHandler == null) {
   6627            return;
   6628        }
   6629        errNoCheck("Unclosed children in \u201Cruby\u201D.");
   6630    }
   6631 
   6632    private void errStartTagSeenWithoutRuby(@Local String name) throws SAXException {
   6633        if (errorHandler == null) {
   6634            return;
   6635        }
   6636        errNoCheck("Start tag \u201C"
   6637                + name
   6638                + "\u201D seen without a \u201Cruby\u201D element being open.");
   6639    }
   6640 
   6641    private void errSelfClosing() throws SAXException {
   6642        if (errorHandler == null) {
   6643            return;
   6644        }
   6645        errNoCheck("Self-closing syntax (\u201C/>\u201D) used on a non-void HTML element. Ignoring the slash and treating as a start tag.");
   6646    }
   6647 
   6648    private void errNoCheckUnclosedElementsOnStack() throws SAXException {
   6649        errNoCheck("Unclosed elements on stack.");
   6650    }
   6651 
   6652    private void errEndTagDidNotMatchCurrentOpenElement(@Local String name,
   6653            @Local String currOpenName) throws SAXException {
   6654        if (errorHandler == null) {
   6655            return;
   6656        }
   6657        errNoCheck("End tag \u201C"
   6658                + name
   6659                + "\u201D did not match the name of the current open element (\u201C"
   6660                + currOpenName + "\u201D).");
   6661    }
   6662 
   6663    private void errEndTagViolatesNestingRules(@Local String name) throws SAXException {
   6664        if (errorHandler == null) {
   6665            return;
   6666        }
   6667        errNoCheck("End tag \u201C" + name + "\u201D violates nesting rules.");
   6668    }
   6669 
   6670    private void errEofWithUnclosedElements() throws SAXException {
   6671        if (errorHandler == null) {
   6672            return;
   6673        }
   6674        errNoCheck("End of file seen and there were open elements.");
   6675        // just report all remaining unclosed elements
   6676        errListUnclosedStartTags(0);
   6677    }
   6678 
   6679    /**
   6680     * Reports arriving at/near end of document with unclosed elements remaining.
   6681     *
   6682     * @param message
   6683     *            the message
   6684     * @throws SAXException
   6685     */
   6686    private void errEndWithUnclosedElements(@Local String name) throws SAXException {
   6687        if (errorHandler == null) {
   6688            return;
   6689        }
   6690        errNoCheck("End tag for  \u201C"
   6691                + name
   6692                + "\u201D seen, but there were unclosed elements.");
   6693        // just report all remaining unclosed elements
   6694        errListUnclosedStartTags(0);
   6695    }
   6696 }