void nsHtml5TreeBuilder::endTag()

in parser/html/nsHtml5TreeBuilder.cpp [2362:3199]


void nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) {
  flushCharacters();
  needToDropLF = false;
  int32_t eltPos;
  int32_t group = elementName->getGroup();
  nsAtom* name = elementName->getName();
  for (;;) {
    if (isInForeign()) {
      if (stack[currentPtr]->name != name) {
        if (!currentPtr) {
          errStrayEndTag(name);
        } else {
          errEndTagDidNotMatchCurrentOpenElement(name,
                                                 stack[currentPtr]->popName);
        }
      }
      eltPos = currentPtr;
      int32_t origPos = currentPtr;
      for (;;) {
        if (!eltPos) {
          MOZ_ASSERT(fragment,
                     "We can get this close to the root of the stack in "
                     "foreign content only in the fragment case.");
          NS_HTML5_BREAK(endtagloop);
        }
        if (stack[eltPos]->name == name) {
          while (currentPtr >= eltPos) {
            popForeign(origPos, eltPos);
          }
          NS_HTML5_BREAK(endtagloop);
        }
        if (stack[--eltPos]->ns == kNameSpaceID_XHTML) {
          break;
        }
      }
    }
    switch (mode) {
      case IN_TEMPLATE: {
        switch (group) {
          case TEMPLATE: {
            break;
          }
          default: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
        }
        [[fallthrough]];
      }
      case IN_ROW: {
        switch (group) {
          case TR: {
            eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
            if (!eltPos) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errNoTableRowToClose();
              NS_HTML5_BREAK(endtagloop);
            }
            clearStackBackTo(eltPos);
            pop();
            mode = IN_TABLE_BODY;
            NS_HTML5_BREAK(endtagloop);
          }
          case TABLE: {
            eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
            if (!eltPos) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errNoTableRowToClose();
              NS_HTML5_BREAK(endtagloop);
            }
            clearStackBackTo(eltPos);
            pop();
            mode = IN_TABLE_BODY;
            continue;
          }
          case TBODY_OR_THEAD_OR_TFOOT: {
            if (findLastInTableScope(name) ==
                nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
            eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
            if (!eltPos) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errNoTableRowToClose();
              NS_HTML5_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);
            NS_HTML5_BREAK(endtagloop);
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case IN_TABLE_BODY: {
        switch (group) {
          case TBODY_OR_THEAD_OR_TFOOT: {
            eltPos = findLastOrRoot(name);
            if (!eltPos) {
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
            clearStackBackTo(eltPos);
            pop();
            mode = IN_TABLE;
            NS_HTML5_BREAK(endtagloop);
          }
          case TABLE: {
            eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
            if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errStrayEndTag(name);
              NS_HTML5_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);
            NS_HTML5_BREAK(endtagloop);
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case IN_TABLE: {
        switch (group) {
          case TABLE: {
            eltPos = findLast(nsGkAtoms::table);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
            while (currentPtr >= eltPos) {
              pop();
            }
            resetTheInsertionMode();
            NS_HTML5_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);
            NS_HTML5_BREAK(endtagloop);
          }
          case TEMPLATE: {
            break;
          }
          default: {
            errStrayEndTag(name);
          }
        }
        [[fallthrough]];
      }
      case IN_CAPTION: {
        switch (group) {
          case CAPTION: {
            eltPos = findLastInTableScope(nsGkAtoms::caption);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              NS_HTML5_BREAK(endtagloop);
            }
            generateImpliedEndTags();
            if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
              errUnclosedElements(eltPos, name);
            }
            while (currentPtr >= eltPos) {
              pop();
            }
            clearTheListOfActiveFormattingElementsUpToTheLastMarker();
            mode = IN_TABLE;
            NS_HTML5_BREAK(endtagloop);
          }
          case TABLE: {
            eltPos = findLastInTableScope(nsGkAtoms::caption);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
            generateImpliedEndTags();
            if (!!MOZ_UNLIKELY(mViewSource) && 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);
            NS_HTML5_BREAK(endtagloop);
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case IN_CELL: {
        switch (group) {
          case TD_OR_TH: {
            eltPos = findLastInTableScope(name);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
            generateImpliedEndTags();
            if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
              errUnclosedElements(eltPos, name);
            }
            while (currentPtr >= eltPos) {
              pop();
            }
            clearTheListOfActiveFormattingElementsUpToTheLastMarker();
            mode = IN_ROW;
            NS_HTML5_BREAK(endtagloop);
          }
          case TABLE:
          case TBODY_OR_THEAD_OR_TFOOT:
          case TR: {
            if (findLastInTableScope(name) ==
                nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              MOZ_ASSERT(name == nsGkAtoms::tbody || name == nsGkAtoms::tfoot ||
                         name == nsGkAtoms::thead || fragment ||
                         isTemplateContents());
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
            closeTheCell(findLastInTableScopeTdTh());
            continue;
          }
          case BODY:
          case CAPTION:
          case COL:
          case COLGROUP:
          case HTML: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case FRAMESET_OK:
      case IN_BODY: {
        switch (group) {
          case BODY: {
            if (!isSecondOnStackBody()) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
            MOZ_ASSERT(currentPtr >= 1);
            if (MOZ_UNLIKELY(mViewSource)) {
              for (int32_t i = 2; i <= currentPtr; i++) {
                switch (stack[i]->getGroup()) {
                  case DD_OR_DT:
                  case LI:
                  case OPTGROUP:
                  case OPTION:
                  case P:
                  case RB_OR_RTC:
                  case RT_OR_RP:
                  case TD_OR_TH:
                  case TBODY_OR_THEAD_OR_TFOOT: {
                    break;
                  }
                  default: {
                    errEndWithUnclosedElements(name);
                    NS_HTML5_BREAK(uncloseloop1);
                  }
                }
              }
            uncloseloop1_end:;
            }
            mode = AFTER_BODY;
            NS_HTML5_BREAK(endtagloop);
          }
          case HTML: {
            if (!isSecondOnStackBody()) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
            if (MOZ_UNLIKELY(mViewSource)) {
              for (int32_t i = 0; i <= currentPtr; i++) {
                switch (stack[i]->getGroup()) {
                  case 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);
                    NS_HTML5_BREAK(uncloseloop2);
                  }
                }
              }
            uncloseloop2_end:;
            }
            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 == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              errStrayEndTag(name);
            } else {
              generateImpliedEndTags();
              if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
                errUnclosedElements(eltPos, name);
              }
              while (currentPtr >= eltPos) {
                pop();
              }
            }
            NS_HTML5_BREAK(endtagloop);
          }
          case FORM: {
            if (!isTemplateContents()) {
              if (!formPointer) {
                errStrayEndTag(name);
                NS_HTML5_BREAK(endtagloop);
              }
              formPointer = nullptr;
              eltPos = findLastInScope(name);
              if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
                errStrayEndTag(name);
                NS_HTML5_BREAK(endtagloop);
              }
              generateImpliedEndTags();
              if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
                errUnclosedElements(eltPos, name);
              }
              removeFromStack(eltPos);
              NS_HTML5_BREAK(endtagloop);
            } else {
              eltPos = findLastInScope(name);
              if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
                errStrayEndTag(name);
                NS_HTML5_BREAK(endtagloop);
              }
              generateImpliedEndTags();
              if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
                errUnclosedElements(eltPos, name);
              }
              while (currentPtr >= eltPos) {
                pop();
              }
              NS_HTML5_BREAK(endtagloop);
            }
          }
          case P: {
            eltPos = findLastInButtonScope(nsGkAtoms::p);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              errNoElementToCloseButEndTagSeen(nsGkAtoms::p);
              if (isInForeign()) {
                errHtmlStartTagInForeignContext(name);
                while (currentPtr >= 0 &&
                       stack[currentPtr]->ns != kNameSpaceID_XHTML) {
                  pop();
                }
              }
              appendVoidElementToCurrentMayFoster(
                  elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
              NS_HTML5_BREAK(endtagloop);
            }
            generateImpliedEndTagsExceptFor(nsGkAtoms::p);
            MOZ_ASSERT(eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK);
            if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
              errUnclosedElements(eltPos, name);
            }
            while (currentPtr >= eltPos) {
              pop();
            }
            NS_HTML5_BREAK(endtagloop);
          }
          case LI: {
            eltPos = findLastInListScope(name);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              errNoElementToCloseButEndTagSeen(name);
            } else {
              generateImpliedEndTagsExceptFor(name);
              if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
                errUnclosedElements(eltPos, name);
              }
              while (currentPtr >= eltPos) {
                pop();
              }
            }
            NS_HTML5_BREAK(endtagloop);
          }
          case DD_OR_DT: {
            eltPos = findLastInScope(name);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              errNoElementToCloseButEndTagSeen(name);
            } else {
              generateImpliedEndTagsExceptFor(name);
              if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
                errUnclosedElements(eltPos, name);
              }
              while (currentPtr >= eltPos) {
                pop();
              }
            }
            NS_HTML5_BREAK(endtagloop);
          }
          case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
            eltPos = findLastInScopeHn();
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              errStrayEndTag(name);
            } else {
              generateImpliedEndTags();
              if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
                errUnclosedElements(eltPos, name);
              }
              while (currentPtr >= eltPos) {
                pop();
              }
            }
            NS_HTML5_BREAK(endtagloop);
          }
          case OBJECT:
          case MARQUEE_OR_APPLET: {
            eltPos = findLastInScope(name);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              errStrayEndTag(name);
            } else {
              generateImpliedEndTags();
              if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
                errUnclosedElements(eltPos, name);
              }
              while (currentPtr >= eltPos) {
                pop();
              }
              clearTheListOfActiveFormattingElementsUpToTheLastMarker();
            }
            NS_HTML5_BREAK(endtagloop);
          }
          case BR: {
            errEndTagBr();
            if (isInForeign()) {
              errHtmlStartTagInForeignContext(name);
              while (currentPtr >= 0 &&
                     stack[currentPtr]->ns != kNameSpaceID_XHTML) {
                pop();
              }
            }
            reconstructTheActiveFormattingElements();
            appendVoidElementToCurrentMayFoster(
                elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
            NS_HTML5_BREAK(endtagloop);
          }
          case TEMPLATE: {
            break;
          }
          case AREA_OR_WBR:
          case KEYGEN:
          case PARAM_OR_SOURCE_OR_TRACK:
          case EMBED:
          case IMG:
          case IMAGE:
          case INPUT:
          case HR:
          case IFRAME:
          case NOEMBED:
          case NOFRAMES:
          case SELECT:
          case TABLE:
          case TEXTAREA: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
          case NOSCRIPT: {
            if (scriptingEnabled) {
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
            [[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)) {
              NS_HTML5_BREAK(endtagloop);
            }
            [[fallthrough]];
          }
          default: {
            if (isCurrent(name)) {
              pop();
              NS_HTML5_BREAK(endtagloop);
            }
            eltPos = currentPtr;
            for (;;) {
              nsHtml5StackNode* node = stack[eltPos];
              if (node->ns == kNameSpaceID_XHTML && node->name == name) {
                generateImpliedEndTags();
                if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
                  errUnclosedElements(eltPos, name);
                }
                while (currentPtr >= eltPos) {
                  pop();
                }
                NS_HTML5_BREAK(endtagloop);
              } else if (!eltPos || node->isSpecial()) {
                errStrayEndTag(name);
                NS_HTML5_BREAK(endtagloop);
              }
              eltPos--;
            }
          }
        }
        [[fallthrough]];
      }
      case IN_HEAD: {
        switch (group) {
          case HEAD: {
            pop();
            mode = AFTER_HEAD;
            NS_HTML5_BREAK(endtagloop);
          }
          case BR:
          case HTML:
          case BODY: {
            pop();
            mode = AFTER_HEAD;
            continue;
          }
          case TEMPLATE: {
            endTagTemplateInHead();
            NS_HTML5_BREAK(endtagloop);
          }
          default: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
        }
      }
      case IN_HEAD_NOSCRIPT: {
        switch (group) {
          case NOSCRIPT: {
            pop();
            mode = IN_HEAD;
            NS_HTML5_BREAK(endtagloop);
          }
          case BR: {
            errStrayEndTag(name);
            pop();
            mode = IN_HEAD;
            continue;
          }
          default: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
        }
      }
      case IN_COLUMN_GROUP: {
        switch (group) {
          case COLGROUP: {
            if (!currentPtr ||
                stack[currentPtr]->getGroup() == nsHtml5TreeBuilder::TEMPLATE) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errGarbageInColgroup();
              NS_HTML5_BREAK(endtagloop);
            }
            pop();
            mode = IN_TABLE;
            NS_HTML5_BREAK(endtagloop);
          }
          case COL: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
          case TEMPLATE: {
            endTagTemplateInHead();
            NS_HTML5_BREAK(endtagloop);
          }
          default: {
            if (!currentPtr ||
                stack[currentPtr]->getGroup() == nsHtml5TreeBuilder::TEMPLATE) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errGarbageInColgroup();
              NS_HTML5_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) !=
                nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              eltPos = findLastInTableScope(nsGkAtoms::select);
              if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
                MOZ_ASSERT(fragment);
                NS_HTML5_BREAK(endtagloop);
              }
              while (currentPtr >= eltPos) {
                pop();
              }
              resetTheInsertionMode();
              continue;
            } else {
              NS_HTML5_BREAK(endtagloop);
            }
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case IN_SELECT: {
        switch (group) {
          case OPTION: {
            if (isCurrent(nsGkAtoms::option)) {
              pop();
              NS_HTML5_BREAK(endtagloop);
            } else {
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
          }
          case OPTGROUP: {
            if (isCurrent(nsGkAtoms::option) &&
                nsGkAtoms::optgroup == stack[currentPtr - 1]->name) {
              pop();
            }
            if (isCurrent(nsGkAtoms::optgroup)) {
              pop();
            } else {
              errStrayEndTag(name);
            }
            NS_HTML5_BREAK(endtagloop);
          }
          case SELECT: {
            eltPos = findLastInTableScope(nsGkAtoms::select);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              MOZ_ASSERT(fragment);
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
            while (currentPtr >= eltPos) {
              pop();
            }
            resetTheInsertionMode();
            NS_HTML5_BREAK(endtagloop);
          }
          case TEMPLATE: {
            endTagTemplateInHead();
            NS_HTML5_BREAK(endtagloop);
          }
          default: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
        }
      }
      case AFTER_BODY: {
        switch (group) {
          case HTML: {
            if (fragment) {
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            } else {
              mode = AFTER_AFTER_BODY;
              NS_HTML5_BREAK(endtagloop);
            }
          }
          default: {
            errEndTagAfterBody();
            mode = framesetOk ? FRAMESET_OK : IN_BODY;
            continue;
          }
        }
      }
      case IN_FRAMESET: {
        switch (group) {
          case FRAMESET: {
            if (!currentPtr) {
              MOZ_ASSERT(fragment);
              errStrayEndTag(name);
              NS_HTML5_BREAK(endtagloop);
            }
            pop();
            if ((!fragment) && !isCurrent(nsGkAtoms::frameset)) {
              mode = AFTER_FRAMESET;
            }
            NS_HTML5_BREAK(endtagloop);
          }
          default: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
        }
      }
      case AFTER_FRAMESET: {
        switch (group) {
          case HTML: {
            mode = AFTER_AFTER_FRAMESET;
            NS_HTML5_BREAK(endtagloop);
          }
          default: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
        }
      }
      case INITIAL: {
        errEndTagSeenWithoutDoctype();
        documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
        mode = BEFORE_HTML;
        continue;
      }
      case BEFORE_HTML: {
        switch (group) {
          case HEAD:
          case BR:
          case HTML:
          case BODY: {
            appendHtmlElementToDocumentAndPush();
            mode = BEFORE_HEAD;
            continue;
          }
          default: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
        }
      }
      case BEFORE_HEAD: {
        switch (group) {
          case HEAD:
          case BR:
          case HTML:
          case BODY: {
            appendToCurrentNodeAndPushHeadElement(
                nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
            mode = IN_HEAD;
            continue;
          }
          default: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
        }
      }
      case AFTER_HEAD: {
        switch (group) {
          case TEMPLATE: {
            endTagTemplateInHead();
            NS_HTML5_BREAK(endtagloop);
          }
          case HTML:
          case BODY:
          case BR: {
            appendToCurrentNodeAndPushBodyElement();
            mode = FRAMESET_OK;
            continue;
          }
          default: {
            errStrayEndTag(name);
            NS_HTML5_BREAK(endtagloop);
          }
        }
      }
      case AFTER_AFTER_BODY: {
        errStrayEndTag(name);
        mode = framesetOk ? FRAMESET_OK : IN_BODY;
        continue;
      }
      case AFTER_AFTER_FRAMESET: {
        errStrayEndTag(name);
        NS_HTML5_BREAK(endtagloop);
      }
      case TEXT: {
        pop();
        if (originalMode == AFTER_HEAD) {
          silentPop();
        }
        mode = originalMode;
        NS_HTML5_BREAK(endtagloop);
      }
    }
  }
endtagloop_end:;
}