public final void endTag()

in parser/html/javasrc/TreeBuilder.java [3201:3981]


    public final void endTag(ElementName elementName) throws SAXException {
        flushCharacters();
        needToDropLF = false;
        int eltPos;
        int group = elementName.getGroup();
        @Local String name = elementName.getName();
        endtagloop: for (;;) {
            if (isInForeign()) {
                if (stack[currentPtr].name != name) {
                    if (currentPtr == 0) {
                        errStrayEndTag(name);
                    } else {
                        errEndTagDidNotMatchCurrentOpenElement(name, stack[currentPtr].popName);
                    }
                }
                eltPos = currentPtr;
                int origPos = currentPtr;
                for (;;) {
                    if (eltPos == 0) {
                        assert fragment: "We can get this close to the root of the stack in foreign content only in the fragment case.";
                        break endtagloop;
                    }
                    if (stack[eltPos].name == name) {
                        while (currentPtr >= eltPos) {
                            popForeign(origPos, eltPos);
                        }
                        break endtagloop;
                    }
                    if (stack[--eltPos].ns == "http://www.w3.org/1999/xhtml") {
                        break;
                    }
                }
            }
            switch (mode) {
                case IN_TEMPLATE:
                    switch (group) {
                        case TEMPLATE:
                            // fall through to IN_HEAD
                            break;
                        default:
                            errStrayEndTag(name);
                            break endtagloop;
                    }
                    // CPPONLY: MOZ_FALLTHROUGH;
                case IN_ROW:
                    switch (group) {
                        case TR:
                            eltPos = findLastOrRoot(TreeBuilder.TR);
                            if (eltPos == 0) {
                                assert fragment || isTemplateContents();
                                errNoTableRowToClose();
                                break endtagloop;
                            }
                            clearStackBackTo(eltPos);
                            pop();
                            mode = IN_TABLE_BODY;
                            break endtagloop;
                        case TABLE:
                            eltPos = findLastOrRoot(TreeBuilder.TR);
                            if (eltPos == 0) {
                                assert fragment || isTemplateContents();
                                errNoTableRowToClose();
                                break endtagloop;
                            }
                            clearStackBackTo(eltPos);
                            pop();
                            mode = IN_TABLE_BODY;
                            continue;
                        case TBODY_OR_THEAD_OR_TFOOT:
                            if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) {
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            eltPos = findLastOrRoot(TreeBuilder.TR);
                            if (eltPos == 0) {
                                assert fragment || isTemplateContents();
                                errNoTableRowToClose();
                                break endtagloop;
                            }
                            clearStackBackTo(eltPos);
                            pop();
                            mode = IN_TABLE_BODY;
                            continue;
                        case BODY:
                        case CAPTION:
                        case COL:
                        case COLGROUP:
                        case HTML:
                        case TD_OR_TH:
                            errStrayEndTag(name);
                            break endtagloop;
                        default:
                            // fall through to IN_TABLE
                    }
                    // CPPONLY: MOZ_FALLTHROUGH;
                case IN_TABLE_BODY:
                    switch (group) {
                        case TBODY_OR_THEAD_OR_TFOOT:
                            eltPos = findLastOrRoot(name);
                            if (eltPos == 0) {
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            clearStackBackTo(eltPos);
                            pop();
                            mode = IN_TABLE;
                            break endtagloop;
                        case TABLE:
                            eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
                            if (eltPos == 0 || stack[eltPos].getGroup() == TEMPLATE) {
                                assert fragment || isTemplateContents();
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            clearStackBackTo(eltPos);
                            pop();
                            mode = IN_TABLE;
                            continue;
                        case BODY:
                        case CAPTION:
                        case COL:
                        case COLGROUP:
                        case HTML:
                        case TD_OR_TH:
                        case TR:
                            errStrayEndTag(name);
                            break endtagloop;
                        default:
                            // fall through to IN_TABLE
                    }
                    // CPPONLY: MOZ_FALLTHROUGH;
                case IN_TABLE:
                    switch (group) {
                        case TABLE:
                            eltPos = findLast("table");
                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                assert fragment || isTemplateContents();
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            while (currentPtr >= eltPos) {
                                pop();
                            }
                            resetTheInsertionMode();
                            break endtagloop;
                        case BODY:
                        case CAPTION:
                        case COL:
                        case COLGROUP:
                        case HTML:
                        case TBODY_OR_THEAD_OR_TFOOT:
                        case TD_OR_TH:
                        case TR:
                            errStrayEndTag(name);
                            break endtagloop;
                        case TEMPLATE:
                            // fall through to IN_HEAD
                            break;
                        default:
                            errStrayEndTag(name);
                            // fall through to IN_BODY
                    }
                    // CPPONLY: MOZ_FALLTHROUGH;
                case IN_CAPTION:
                    switch (group) {
                        case CAPTION:
                            eltPos = findLastInTableScope("caption");
                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                break endtagloop;
                            }
                            generateImpliedEndTags();
                            if (errorHandler != null && currentPtr != eltPos) {
                                errUnclosedElements(eltPos, name);
                            }
                            while (currentPtr >= eltPos) {
                                pop();
                            }
                            clearTheListOfActiveFormattingElementsUpToTheLastMarker();
                            mode = IN_TABLE;
                            break endtagloop;
                        case TABLE:
                            eltPos = findLastInTableScope("caption");

                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                assert fragment || isTemplateContents();
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            generateImpliedEndTags();
                            if (errorHandler != null && currentPtr != eltPos) {
                                errUnclosedElements(eltPos, name);
                            }
                            while (currentPtr >= eltPos) {
                                pop();
                            }
                            clearTheListOfActiveFormattingElementsUpToTheLastMarker();
                            mode = IN_TABLE;
                            continue;
                        case BODY:
                        case COL:
                        case COLGROUP:
                        case HTML:
                        case TBODY_OR_THEAD_OR_TFOOT:
                        case TD_OR_TH:
                        case TR:
                            errStrayEndTag(name);
                            break endtagloop;
                        default:
                            // fall through to IN_BODY
                    }
                    // CPPONLY: MOZ_FALLTHROUGH;
                case IN_CELL:
                    switch (group) {
                        case TD_OR_TH:
                            eltPos = findLastInTableScope(name);
                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            generateImpliedEndTags();
                            if (errorHandler != null && !isCurrent(name)) {
                                errUnclosedElements(eltPos, name);
                            }
                            while (currentPtr >= eltPos) {
                                pop();
                            }
                            clearTheListOfActiveFormattingElementsUpToTheLastMarker();
                            mode = IN_ROW;
                            break endtagloop;
                        case TABLE:
                        case TBODY_OR_THEAD_OR_TFOOT:
                        case TR:
                            if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) {
                                assert name == "tbody" || name == "tfoot" || name == "thead" || fragment || isTemplateContents();
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            closeTheCell(findLastInTableScopeTdTh());
                            continue;
                        case BODY:
                        case CAPTION:
                        case COL:
                        case COLGROUP:
                        case HTML:
                            errStrayEndTag(name);
                            break endtagloop;
                        default:
                            // fall through to IN_BODY
                    }
                    // CPPONLY: MOZ_FALLTHROUGH;
                case FRAMESET_OK:
                case IN_BODY:
                    switch (group) {
                        case BODY:
                            if (!isSecondOnStackBody()) {
                                assert fragment || isTemplateContents();
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            assert currentPtr >= 1;
                            if (errorHandler != null) {
                                uncloseloop1: for (int i = 2; i <= currentPtr; i++) {
                                    switch (stack[i].getGroup()) {
                                        case DD_OR_DT:
                                        case LI:
                                        case OPTGROUP:
                                        case OPTION: // is this possible?
                                        case P:
                                        case RB_OR_RTC:
                                        case RT_OR_RP:
                                        case TD_OR_TH:
                                        case TBODY_OR_THEAD_OR_TFOOT:
                                            break;
                                        default:
                                            errEndWithUnclosedElements(name);
                                            break uncloseloop1;
                                    }
                                }
                            }
                            mode = AFTER_BODY;
                            break endtagloop;
                        case HTML:
                            if (!isSecondOnStackBody()) {
                                assert fragment || isTemplateContents();
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            if (errorHandler != null) {
                                uncloseloop2: for (int i = 0; i <= currentPtr; i++) {
                                    switch (stack[i].getGroup()) {
                                        case DD_OR_DT:
                                        case LI:
                                        case P:
                                        case RB_OR_RTC:
                                        case RT_OR_RP:
                                        case TBODY_OR_THEAD_OR_TFOOT:
                                        case TD_OR_TH:
                                        case BODY:
                                        case HTML:
                                            break;
                                        default:
                                            errEndWithUnclosedElements(name);
                                            break uncloseloop2;
                                    }
                                }
                            }
                            mode = AFTER_BODY;
                            continue;
                        case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
                        case UL_OR_OL_OR_DL:
                        case PRE_OR_LISTING:
                        case FIELDSET:
                        case BUTTON:
                        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:
                            eltPos = findLastInScope(name);
                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                errStrayEndTag(name);
                            } else {
                                generateImpliedEndTags();
                                if (errorHandler != null && !isCurrent(name)) {
                                    errUnclosedElements(eltPos, name);
                                }
                                while (currentPtr >= eltPos) {
                                    pop();
                                }
                            }
                            break endtagloop;
                        case FORM:
                            if (!isTemplateContents()) {
                                if (formPointer == null) {
                                    errStrayEndTag(name);
                                    break endtagloop;
                                }
                                formPointer = null;
                                eltPos = findLastInScope(name);
                                if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                    errStrayEndTag(name);
                                    break endtagloop;
                                }
                                generateImpliedEndTags();
                                if (errorHandler != null && !isCurrent(name)) {
                                    errUnclosedElements(eltPos, name);
                                }
                                removeFromStack(eltPos);
                                break endtagloop;
                            } else {
                                eltPos = findLastInScope(name);
                                if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                    errStrayEndTag(name);
                                    break endtagloop;
                                }
                                generateImpliedEndTags();
                                if (errorHandler != null && !isCurrent(name)) {
                                    errUnclosedElements(eltPos, name);
                                }
                                while (currentPtr >= eltPos) {
                                    pop();
                                }
                                break endtagloop;
                            }
                        case P:
                            eltPos = findLastInButtonScope("p");
                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                errNoElementToCloseButEndTagSeen("p");
                                // XXX Can the 'in foreign' case happen anymore?
                                if (isInForeign()) {
                                    errHtmlStartTagInForeignContext(name);
                                    // Check for currentPtr for the fragment
                                    // case.
                                    while (currentPtr >= 0 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") {
                                        pop();
                                    }
                                }
                                appendVoidElementToCurrentMayFoster(
                                        elementName,
                                        HtmlAttributes.EMPTY_ATTRIBUTES);
                                break endtagloop;
                            }
                            generateImpliedEndTagsExceptFor("p");
                            assert eltPos != TreeBuilder.NOT_FOUND_ON_STACK;
                            if (errorHandler != null && eltPos != currentPtr) {
                                errUnclosedElements(eltPos, name);
                            }
                            while (currentPtr >= eltPos) {
                                pop();
                            }
                            break endtagloop;
                        case LI:
                            eltPos = findLastInListScope(name);
                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                errNoElementToCloseButEndTagSeen(name);
                            } else {
                                generateImpliedEndTagsExceptFor(name);
                                if (errorHandler != null
                                        && eltPos != currentPtr) {
                                    errUnclosedElements(eltPos, name);
                                }
                                while (currentPtr >= eltPos) {
                                    pop();
                                }
                            }
                            break endtagloop;
                        case DD_OR_DT:
                            eltPos = findLastInScope(name);
                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                errNoElementToCloseButEndTagSeen(name);
                            } else {
                                generateImpliedEndTagsExceptFor(name);
                                if (errorHandler != null
                                        && eltPos != currentPtr) {
                                    errUnclosedElements(eltPos, name);
                                }
                                while (currentPtr >= eltPos) {
                                    pop();
                                }
                            }
                            break endtagloop;
                        case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
                            eltPos = findLastInScopeHn();
                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                errStrayEndTag(name);
                            } else {
                                generateImpliedEndTags();
                                if (errorHandler != null && !isCurrent(name)) {
                                    errUnclosedElements(eltPos, name);
                                }
                                while (currentPtr >= eltPos) {
                                    pop();
                                }
                            }
                            break endtagloop;
                        case OBJECT:
                        case MARQUEE_OR_APPLET:
                            eltPos = findLastInScope(name);
                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                errStrayEndTag(name);
                            } else {
                                generateImpliedEndTags();
                                if (errorHandler != null && !isCurrent(name)) {
                                    errUnclosedElements(eltPos, name);
                                }
                                while (currentPtr >= eltPos) {
                                    pop();
                                }
                                clearTheListOfActiveFormattingElementsUpToTheLastMarker();
                            }
                            break endtagloop;
                        case BR:
                            errEndTagBr();
                            if (isInForeign()) {
                                // XXX can this happen anymore?
                                errHtmlStartTagInForeignContext(name);
                                // Check for currentPtr for the fragment
                                // case.
                                while (currentPtr >= 0 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") {
                                    pop();
                                }
                            }
                            reconstructTheActiveFormattingElements();
                            appendVoidElementToCurrentMayFoster(
                                    elementName,
                                    HtmlAttributes.EMPTY_ATTRIBUTES);
                            break endtagloop;
                        case TEMPLATE:
                            // fall through to IN_HEAD;
                            break;
                        case AREA_OR_WBR:
                        case KEYGEN: // XXX??
                        case PARAM_OR_SOURCE_OR_TRACK:
                        case EMBED:
                        case IMG:
                        case IMAGE:
                        case INPUT:
                        case HR:
                        case IFRAME:
                        case NOEMBED: // XXX???
                        case NOFRAMES: // XXX??
                        case SELECT:
                        case TABLE:
                        case TEXTAREA: // XXX??
                            errStrayEndTag(name);
                            break endtagloop;
                        case NOSCRIPT:
                            if (scriptingEnabled) {
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            // CPPONLY: MOZ_FALLTHROUGH;
                        case A:
                        case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
                        case FONT:
                        case NOBR:
                            if (adoptionAgencyEndTag(name)) {
                                break endtagloop;
                            }
                            // else handle like any other tag
                            // CPPONLY: MOZ_FALLTHROUGH;
                        default:
                            if (isCurrent(name)) {
                                pop();
                                break endtagloop;
                            }

                            eltPos = currentPtr;
                            for (;;) {
                                StackNode<T> node = stack[eltPos];
                                if (node.ns == "http://www.w3.org/1999/xhtml" && node.name == name) {
                                    generateImpliedEndTags();
                                    if (errorHandler != null
                                            && !isCurrent(name)) {
                                        errUnclosedElements(eltPos, name);
                                    }
                                    while (currentPtr >= eltPos) {
                                        pop();
                                    }
                                    break endtagloop;
                                } else if (eltPos == 0 || node.isSpecial()) {
                                    errStrayEndTag(name);
                                    break endtagloop;
                                }
                                eltPos--;
                            }
                    }
                    // CPPONLY: MOZ_FALLTHROUGH;
                case IN_HEAD:
                    switch (group) {
                        case HEAD:
                            pop();
                            mode = AFTER_HEAD;
                            break endtagloop;
                        case BR:
                        case HTML:
                        case BODY:
                            pop();
                            mode = AFTER_HEAD;
                            continue;
                        case TEMPLATE:
                            endTagTemplateInHead();
                            break endtagloop;
                        default:
                            errStrayEndTag(name);
                            break endtagloop;
                    }
                case IN_HEAD_NOSCRIPT:
                    switch (group) {
                        case NOSCRIPT:
                            pop();
                            mode = IN_HEAD;
                            break endtagloop;
                        case BR:
                            errStrayEndTag(name);
                            pop();
                            mode = IN_HEAD;
                            continue;
                        default:
                            errStrayEndTag(name);
                            break endtagloop;
                    }
                case IN_COLUMN_GROUP:
                    switch (group) {
                        case COLGROUP:
                            if (currentPtr == 0 || stack[currentPtr].getGroup() ==
                                    TreeBuilder.TEMPLATE) {
                                assert fragment || isTemplateContents();
                                errGarbageInColgroup();
                                break endtagloop;
                            }
                            pop();
                            mode = IN_TABLE;
                            break endtagloop;
                        case COL:
                            errStrayEndTag(name);
                            break endtagloop;
                        case TEMPLATE:
                            endTagTemplateInHead();
                            break endtagloop;
                        default:
                            if (currentPtr == 0 || stack[currentPtr].getGroup() ==
                                    TreeBuilder.TEMPLATE) {
                                assert fragment || isTemplateContents();
                                errGarbageInColgroup();
                                break endtagloop;
                            }
                            pop();
                            mode = IN_TABLE;
                            continue;
                    }
                case IN_SELECT_IN_TABLE:
                    switch (group) {
                        case CAPTION:
                        case TABLE:
                        case TBODY_OR_THEAD_OR_TFOOT:
                        case TR:
                        case TD_OR_TH:
                            errEndTagSeenWithSelectOpen(name);
                            if (findLastInTableScope(name) != TreeBuilder.NOT_FOUND_ON_STACK) {
                                eltPos = findLastInTableScope("select");
                                if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                    assert fragment;
                                    break endtagloop; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375
                                }
                                while (currentPtr >= eltPos) {
                                    pop();
                                }
                                resetTheInsertionMode();
                                continue;
                            } else {
                                break endtagloop;
                            }
                        default:
                            // fall through to IN_SELECT
                    }
                    // CPPONLY: MOZ_FALLTHROUGH;
                case IN_SELECT:
                    switch (group) {
                        case OPTION:
                            if (isCurrent("option")) {
                                pop();
                                break endtagloop;
                            } else {
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                        case OPTGROUP:
                            if (isCurrent("option")
                                    && "optgroup" == stack[currentPtr - 1].name) {
                                pop();
                            }
                            if (isCurrent("optgroup")) {
                                pop();
                            } else {
                                errStrayEndTag(name);
                            }
                            break endtagloop;
                        case SELECT:
                            eltPos = findLastInTableScope("select");
                            if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
                                assert fragment;
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            while (currentPtr >= eltPos) {
                                pop();
                            }
                            resetTheInsertionMode();
                            break endtagloop;
                        case TEMPLATE:
                            endTagTemplateInHead();
                            break endtagloop;
                        default:
                            errStrayEndTag(name);
                            break endtagloop;
                    }
                case AFTER_BODY:
                    switch (group) {
                        case HTML:
                            if (fragment) {
                                errStrayEndTag(name);
                                break endtagloop;
                            } else {
                                mode = AFTER_AFTER_BODY;
                                break endtagloop;
                            }
                        default:
                            errEndTagAfterBody();
                            mode = framesetOk ? FRAMESET_OK : IN_BODY;
                            continue;
                    }
                case IN_FRAMESET:
                    switch (group) {
                        case FRAMESET:
                            if (currentPtr == 0) {
                                assert fragment;
                                errStrayEndTag(name);
                                break endtagloop;
                            }
                            pop();
                            if ((!fragment) && !isCurrent("frameset")) {
                                mode = AFTER_FRAMESET;
                            }
                            break endtagloop;
                        default:
                            errStrayEndTag(name);
                            break endtagloop;
                    }
                case AFTER_FRAMESET:
                    switch (group) {
                        case HTML:
                            mode = AFTER_AFTER_FRAMESET;
                            break endtagloop;
                        default:
                            errStrayEndTag(name);
                            break endtagloop;
                    }
                case INITIAL:
                    /*
                     * Parse error.
                     */
                    errEndTagSeenWithoutDoctype();
                    /*
                     *
                     * Set the document to quirks mode.
                     */
                    documentModeInternal(DocumentMode.QUIRKS_MODE, null, null);
                    /*
                     * Then, switch to the root element mode of the tree
                     * construction stage
                     */
                    mode = BEFORE_HTML;
                    /*
                     * and reprocess the current token.
                     */
                    continue;
                case BEFORE_HTML:
                    switch (group) {
                        case HEAD:
                        case BR:
                        case HTML:
                        case BODY:
                            /*
                             * Create an HTMLElement node with the tag name
                             * html, in the HTML namespace. Append it to the
                             * Document object.
                             */
                            appendHtmlElementToDocumentAndPush();
                            /* Switch to the main mode */
                            mode = BEFORE_HEAD;
                            /*
                             * reprocess the current token.
                             */
                            continue;
                        default:
                            errStrayEndTag(name);
                            break endtagloop;
                    }
                case BEFORE_HEAD:
                    switch (group) {
                        case HEAD:
                        case BR:
                        case HTML:
                        case BODY:
                            appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
                            mode = IN_HEAD;
                            continue;
                        default:
                            errStrayEndTag(name);
                            break endtagloop;
                    }
                case AFTER_HEAD:
                    switch (group) {
                        case TEMPLATE:
                            endTagTemplateInHead();
                            break endtagloop;
                        case HTML:
                        case BODY:
                        case BR:
                            appendToCurrentNodeAndPushBodyElement();
                            mode = FRAMESET_OK;
                            continue;
                        default:
                            errStrayEndTag(name);
                            break endtagloop;
                    }
                case AFTER_AFTER_BODY:
                    errStrayEndTag(name);
                    mode = framesetOk ? FRAMESET_OK : IN_BODY;
                    continue;
                case AFTER_AFTER_FRAMESET:
                    errStrayEndTag(name);
                    break endtagloop;
                case TEXT:
                    // XXX need to manage insertion point here
                    pop();
                    if (originalMode == AFTER_HEAD) {
                        silentPop();
                    }
                    mode = originalMode;
                    break endtagloop;
            }
        } // endtagloop
    }