void nsHtml5TreeBuilder::startTag()

in parser/html/nsHtml5TreeBuilder.cpp [675:2057]


void nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName,
                                  nsHtml5HtmlAttributes* attributes,
                                  bool selfClosing) {
  flushCharacters();
  int32_t eltPos;
  needToDropLF = false;
starttagloop:
  for (;;) {
    int32_t group = elementName->getGroup();
    nsAtom* name = elementName->getName();
    if (isInForeign()) {
      nsHtml5StackNode* currentNode = stack[currentPtr];
      int32_t currNs = currentNode->ns;
      if (!(currentNode->isHtmlIntegrationPoint() ||
            (currNs == kNameSpaceID_MathML &&
             ((currentNode->getGroup() == MI_MO_MN_MS_MTEXT &&
               group != MGLYPH_OR_MALIGNMARK) ||
              (currentNode->getGroup() == ANNOTATION_XML && group == SVG))))) {
        switch (group) {
          case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
          case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
          case BODY:
          case BR:
          case RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR:
          case DD_OR_DT:
          case UL_OR_OL_OR_DL:
          case EMBED:
          case IMG:
          case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
          case HEAD:
          case HR:
          case LI:
          case META:
          case NOBR:
          case P:
          case PRE_OR_LISTING:
          case TABLE:
          case FONT: {
            if (!(group == FONT &&
                  !(attributes->contains(nsHtml5AttributeName::ATTR_COLOR) ||
                    attributes->contains(nsHtml5AttributeName::ATTR_FACE) ||
                    attributes->contains(nsHtml5AttributeName::ATTR_SIZE)))) {
              errHtmlStartTagInForeignContext(name);
              if (!fragment) {
                while (!isSpecialParentInForeign(stack[currentPtr])) {
                  popForeign(-1, -1);
                }
                NS_HTML5_CONTINUE(starttagloop);
              }
            }
            [[fallthrough]];
          }
          default: {
            if (kNameSpaceID_SVG == currNs) {
              attributes->adjustForSvg();
              if (selfClosing) {
                appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
                selfClosing = false;
              } else {
                appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
                                                              attributes);
              }
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            } else {
              attributes->adjustForMath();
              if (selfClosing) {
                appendVoidElementToCurrentMayFosterMathML(elementName,
                                                          attributes);
                selfClosing = false;
              } else {
                appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
                                                                 attributes);
              }
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
          }
        }
      }
    }
    switch (mode) {
      case IN_TEMPLATE: {
        switch (group) {
          case COL: {
            popTemplateMode();
            pushTemplateMode(IN_COLUMN_GROUP);
            mode = IN_COLUMN_GROUP;
            continue;
          }
          case CAPTION:
          case COLGROUP:
          case TBODY_OR_THEAD_OR_TFOOT: {
            popTemplateMode();
            pushTemplateMode(IN_TABLE);
            mode = IN_TABLE;
            continue;
          }
          case TR: {
            popTemplateMode();
            pushTemplateMode(IN_TABLE_BODY);
            mode = IN_TABLE_BODY;
            continue;
          }
          case TD_OR_TH: {
            popTemplateMode();
            pushTemplateMode(IN_ROW);
            mode = IN_ROW;
            continue;
          }
          case META: {
            checkMetaCharset(attributes);
            appendVoidElementToCurrentMayFoster(elementName, attributes);
            selfClosing = false;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case TITLE: {
            startTagTitleInHead(elementName, attributes);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case BASE:
          case LINK_OR_BASEFONT_OR_BGSOUND: {
            appendVoidElementToCurrentMayFoster(elementName, attributes);
            selfClosing = false;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case SCRIPT: {
            startTagScriptInHead(elementName, attributes);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case NOFRAMES:
          case STYLE: {
            startTagGenericRawText(elementName, attributes);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case TEMPLATE: {
            startTagTemplateInHead(elementName, attributes);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          default: {
            popTemplateMode();
            pushTemplateMode(IN_BODY);
            mode = IN_BODY;
            continue;
          }
        }
      }
      case IN_ROW: {
        switch (group) {
          case TD_OR_TH: {
            clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TR));
            appendToCurrentNodeAndPushElement(elementName, attributes);
            mode = IN_CELL;
            insertMarker();
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case CAPTION:
          case COL:
          case COLGROUP:
          case TBODY_OR_THEAD_OR_TFOOT:
          case TR: {
            eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
            if (!eltPos) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errNoTableRowToClose();
              NS_HTML5_BREAK(starttagloop);
            }
            clearStackBackTo(eltPos);
            pop();
            mode = IN_TABLE_BODY;
            continue;
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case IN_TABLE_BODY: {
        switch (group) {
          case TR: {
            clearStackBackTo(
                findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
            appendToCurrentNodeAndPushElement(elementName, attributes);
            mode = IN_ROW;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case TD_OR_TH: {
            errStartTagInTableBody(name);
            clearStackBackTo(
                findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
            appendToCurrentNodeAndPushElement(
                nsHtml5ElementName::ELT_TR,
                nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
            mode = IN_ROW;
            continue;
          }
          case CAPTION:
          case COL:
          case COLGROUP:
          case TBODY_OR_THEAD_OR_TFOOT: {
            eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
            if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errStrayStartTag(name);
              NS_HTML5_BREAK(starttagloop);
            } else {
              clearStackBackTo(eltPos);
              pop();
              mode = IN_TABLE;
              continue;
            }
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case IN_TABLE: {
        for (;;) {
          switch (group) {
            case CAPTION: {
              clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
              insertMarker();
              appendToCurrentNodeAndPushElement(elementName, attributes);
              mode = IN_CAPTION;
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case COLGROUP: {
              clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
              appendToCurrentNodeAndPushElement(elementName, attributes);
              mode = IN_COLUMN_GROUP;
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case COL: {
              clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
              appendToCurrentNodeAndPushElement(
                  nsHtml5ElementName::ELT_COLGROUP,
                  nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
              mode = IN_COLUMN_GROUP;
              NS_HTML5_CONTINUE(starttagloop);
            }
            case TBODY_OR_THEAD_OR_TFOOT: {
              clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
              appendToCurrentNodeAndPushElement(elementName, attributes);
              mode = IN_TABLE_BODY;
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case TR:
            case TD_OR_TH: {
              clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
              appendToCurrentNodeAndPushElement(
                  nsHtml5ElementName::ELT_TBODY,
                  nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
              mode = IN_TABLE_BODY;
              NS_HTML5_CONTINUE(starttagloop);
            }
            case TEMPLATE: {
              NS_HTML5_BREAK(intableloop);
            }
            case TABLE: {
              errTableSeenWhileTableOpen();
              eltPos = findLastInTableScope(name);
              if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
                MOZ_ASSERT(fragment || isTemplateContents());
                NS_HTML5_BREAK(starttagloop);
              }
              generateImpliedEndTags();
              if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsGkAtoms::table)) {
                errNoCheckUnclosedElementsOnStack();
              }
              while (currentPtr >= eltPos) {
                pop();
              }
              resetTheInsertionMode();
              NS_HTML5_CONTINUE(starttagloop);
            }
            case SCRIPT: {
              appendToCurrentNodeAndPushElement(elementName, attributes);
              originalMode = mode;
              mode = TEXT;
              tokenizer->setStateAndEndTagExpectation(
                  nsHtml5Tokenizer::SCRIPT_DATA, elementName);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case STYLE: {
              appendToCurrentNodeAndPushElement(elementName, attributes);
              originalMode = mode;
              mode = TEXT;
              tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
                                                      elementName);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case INPUT: {
              errStartTagInTable(name);
              if (!nsHtml5Portability::
                      lowerCaseLiteralEqualsIgnoreAsciiCaseString(
                          "hidden", attributes->getValue(
                                        nsHtml5AttributeName::ATTR_TYPE))) {
                NS_HTML5_BREAK(intableloop);
              }
              appendVoidInputToCurrent(attributes, formPointer);
              selfClosing = false;
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case FORM: {
              if (!!formPointer || isTemplateContents()) {
                errFormWhenFormOpen();
                NS_HTML5_BREAK(starttagloop);
              } else {
                errStartTagInTable(name);
                appendVoidFormToCurrent(attributes);
                attributes = nullptr;
                NS_HTML5_BREAK(starttagloop);
              }
            }
            default: {
              errStartTagInTable(name);
              NS_HTML5_BREAK(intableloop);
            }
          }
        }
      intableloop_end:;
        [[fallthrough]];
      }
      case IN_CAPTION: {
        switch (group) {
          case CAPTION:
          case COL:
          case COLGROUP:
          case TBODY_OR_THEAD_OR_TFOOT:
          case TR:
          case TD_OR_TH: {
            eltPos = findLastInTableScope(nsGkAtoms::caption);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errStrayStartTag(name);
              NS_HTML5_BREAK(starttagloop);
            }
            generateImpliedEndTags();
            if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
              errNoCheckUnclosedElementsOnStack();
            }
            while (currentPtr >= eltPos) {
              pop();
            }
            clearTheListOfActiveFormattingElementsUpToTheLastMarker();
            mode = IN_TABLE;
            continue;
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case IN_CELL: {
        switch (group) {
          case CAPTION:
          case COL:
          case COLGROUP:
          case TBODY_OR_THEAD_OR_TFOOT:
          case TR:
          case TD_OR_TH: {
            eltPos = findLastInTableScopeTdTh();
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              errNoCellToClose();
              NS_HTML5_BREAK(starttagloop);
            } else {
              closeTheCell(eltPos);
              continue;
            }
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case FRAMESET_OK: {
        switch (group) {
          case FRAMESET: {
            if (mode == FRAMESET_OK) {
              if (!currentPtr || stack[1]->getGroup() != BODY) {
                MOZ_ASSERT(fragment || isTemplateContents());
                errStrayStartTag(name);
                NS_HTML5_BREAK(starttagloop);
              } else {
                errFramesetStart();
                detachFromParent(stack[1]->node);
                while (currentPtr > 0) {
                  pop();
                }
                appendToCurrentNodeAndPushElement(elementName, attributes);
                mode = IN_FRAMESET;
                attributes = nullptr;
                NS_HTML5_BREAK(starttagloop);
              }
            } else {
              errStrayStartTag(name);
              NS_HTML5_BREAK(starttagloop);
            }
          }
          case PRE_OR_LISTING:
          case LI:
          case DD_OR_DT:
          case BUTTON:
          case MARQUEE_OR_APPLET:
          case OBJECT:
          case TABLE:
          case AREA_OR_WBR:
          case KEYGEN:
          case BR:
          case EMBED:
          case IMG:
          case INPUT:
          case HR:
          case TEXTAREA:
          case XMP:
          case IFRAME:
          case SELECT: {
            if (mode == FRAMESET_OK &&
                !(group == INPUT &&
                  nsHtml5Portability::
                      lowerCaseLiteralEqualsIgnoreAsciiCaseString(
                          "hidden", attributes->getValue(
                                        nsHtml5AttributeName::ATTR_TYPE)))) {
              framesetOk = false;
              mode = IN_BODY;
            }
            [[fallthrough]];
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case IN_BODY: {
        for (;;) {
          switch (group) {
            case HTML: {
              errStrayStartTag(name);
              if (!fragment && !isTemplateContents()) {
                addAttributesToHtml(attributes);
                attributes = nullptr;
              }
              NS_HTML5_BREAK(starttagloop);
            }
            case BASE:
            case LINK_OR_BASEFONT_OR_BGSOUND:
            case META:
            case STYLE:
            case SCRIPT:
            case TITLE:
            case TEMPLATE: {
              NS_HTML5_BREAK(inbodyloop);
            }
            case BODY: {
              if (!currentPtr || stack[1]->getGroup() != BODY ||
                  isTemplateContents()) {
                MOZ_ASSERT(fragment || isTemplateContents());
                errStrayStartTag(name);
                NS_HTML5_BREAK(starttagloop);
              }
              errFooSeenWhenFooOpen(name);
              framesetOk = false;
              if (mode == FRAMESET_OK) {
                mode = IN_BODY;
              }
              if (addAttributesToBody(attributes)) {
                attributes = nullptr;
              }
              NS_HTML5_BREAK(starttagloop);
            }
            case P:
            case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
            case UL_OR_OL_OR_DL:
            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: {
              implicitlyCloseP();
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
              implicitlyCloseP();
              if (stack[currentPtr]->getGroup() ==
                  H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
                errHeadingWhenHeadingOpen();
                pop();
              }
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case FIELDSET: {
              implicitlyCloseP();
              appendToCurrentNodeAndPushElementMayFoster(
                  elementName, attributes, formPointer);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case PRE_OR_LISTING: {
              implicitlyCloseP();
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              needToDropLF = true;
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case FORM: {
              if (!!formPointer && !isTemplateContents()) {
                errFormWhenFormOpen();
                NS_HTML5_BREAK(starttagloop);
              } else {
                implicitlyCloseP();
                appendToCurrentNodeAndPushFormElementMayFoster(attributes);
                attributes = nullptr;
                NS_HTML5_BREAK(starttagloop);
              }
            }
            case LI:
            case DD_OR_DT: {
              eltPos = currentPtr;
              for (;;) {
                nsHtml5StackNode* node = stack[eltPos];
                if (node->getGroup() == group) {
                  generateImpliedEndTagsExceptFor(node->name);
                  if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
                    errUnclosedElementsImplied(eltPos, name);
                  }
                  while (currentPtr >= eltPos) {
                    pop();
                  }
                  break;
                } else if (!eltPos || (node->isSpecial() &&
                                       (node->ns != kNameSpaceID_XHTML ||
                                        (node->name != nsGkAtoms::p &&
                                         node->name != nsGkAtoms::address &&
                                         node->name != nsGkAtoms::div)))) {
                  break;
                }
                eltPos--;
              }
              implicitlyCloseP();
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case PLAINTEXT: {
              implicitlyCloseP();
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              tokenizer->setStateAndEndTagExpectation(
                  nsHtml5Tokenizer::PLAINTEXT, elementName);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case A: {
              int32_t activeAPos =
                  findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
                      nsGkAtoms::a);
              if (activeAPos != -1) {
                errFooSeenWhenFooOpen(name);
                nsHtml5StackNode* activeA =
                    listOfActiveFormattingElements[activeAPos];
                activeA->retain();
                adoptionAgencyEndTag(nsGkAtoms::a);
                removeFromStack(activeA);
                activeAPos = findInListOfActiveFormattingElements(activeA);
                if (activeAPos != -1) {
                  removeFromListOfActiveFormattingElements(activeAPos);
                }
                activeA->release(this);
              }
              reconstructTheActiveFormattingElements();
              appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
                                                                   attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
            case FONT: {
              reconstructTheActiveFormattingElements();
              maybeForgetEarlierDuplicateFormattingElement(
                  elementName->getName(), attributes);
              appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
                                                                   attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case NOBR: {
              reconstructTheActiveFormattingElements();
              if (nsHtml5TreeBuilder::NOT_FOUND_ON_STACK !=
                  findLastInScope(nsGkAtoms::nobr)) {
                errFooSeenWhenFooOpen(name);
                adoptionAgencyEndTag(nsGkAtoms::nobr);
                reconstructTheActiveFormattingElements();
              }
              appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
                                                                   attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case BUTTON: {
              eltPos = findLastInScope(name);
              if (eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
                errFooSeenWhenFooOpen(name);
                generateImpliedEndTags();
                if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
                  errUnclosedElementsImplied(eltPos, name);
                }
                while (currentPtr >= eltPos) {
                  pop();
                }
                NS_HTML5_CONTINUE(starttagloop);
              } else {
                reconstructTheActiveFormattingElements();
                appendToCurrentNodeAndPushElementMayFoster(
                    elementName, attributes, formPointer);
                attributes = nullptr;
                NS_HTML5_BREAK(starttagloop);
              }
            }
            case OBJECT: {
              reconstructTheActiveFormattingElements();
              appendToCurrentNodeAndPushElementMayFoster(
                  elementName, attributes, formPointer);
              insertMarker();
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case MARQUEE_OR_APPLET: {
              reconstructTheActiveFormattingElements();
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              insertMarker();
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case TABLE: {
              if (!quirks) {
                implicitlyCloseP();
              }
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              mode = IN_TABLE;
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case BR:
            case EMBED:
            case AREA_OR_WBR:
            case KEYGEN: {
              reconstructTheActiveFormattingElements();
              [[fallthrough]];
            }
            case PARAM_OR_SOURCE_OR_TRACK: {
              appendVoidElementToCurrentMayFoster(elementName, attributes);
              selfClosing = false;
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case HR: {
              implicitlyCloseP();
              appendVoidElementToCurrentMayFoster(elementName, attributes);
              selfClosing = false;
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case IMAGE: {
              errImage();
              elementName = nsHtml5ElementName::ELT_IMG;
              NS_HTML5_CONTINUE(starttagloop);
            }
            case IMG:
            case INPUT: {
              reconstructTheActiveFormattingElements();
              appendVoidElementToCurrentMayFoster(elementName, attributes,
                                                  formPointer);
              selfClosing = false;
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case TEXTAREA: {
              appendToCurrentNodeAndPushElementMayFoster(
                  elementName, attributes, formPointer);
              tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
                                                      elementName);
              originalMode = mode;
              mode = TEXT;
              needToDropLF = true;
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case XMP: {
              implicitlyCloseP();
              reconstructTheActiveFormattingElements();
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              originalMode = mode;
              mode = TEXT;
              tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
                                                      elementName);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case NOSCRIPT: {
              if (!scriptingEnabled) {
                reconstructTheActiveFormattingElements();
                appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                           attributes);
                attributes = nullptr;
                NS_HTML5_BREAK(starttagloop);
              }
              [[fallthrough]];
            }
            case NOFRAMES:
            case IFRAME:
            case NOEMBED: {
              startTagGenericRawText(elementName, attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case SELECT: {
              reconstructTheActiveFormattingElements();
              appendToCurrentNodeAndPushElementMayFoster(
                  elementName, attributes, formPointer);
              switch (mode) {
                case IN_TABLE:
                case IN_CAPTION:
                case IN_COLUMN_GROUP:
                case IN_TABLE_BODY:
                case IN_ROW:
                case IN_CELL: {
                  mode = IN_SELECT_IN_TABLE;
                  break;
                }
                default: {
                  mode = IN_SELECT;
                  break;
                }
              }
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case OPTGROUP:
            case OPTION: {
              if (isCurrent(nsGkAtoms::option)) {
                pop();
              }
              reconstructTheActiveFormattingElements();
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case RB_OR_RTC: {
              eltPos = findLastInScope(nsGkAtoms::ruby);
              if (eltPos != NOT_FOUND_ON_STACK) {
                generateImpliedEndTags();
              }
              if (eltPos != currentPtr) {
                if (eltPos == NOT_FOUND_ON_STACK) {
                  errStartTagSeenWithoutRuby(name);
                } else {
                  errUnclosedChildrenInRuby();
                }
              }
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case RT_OR_RP: {
              eltPos = findLastInScope(nsGkAtoms::ruby);
              if (eltPos != NOT_FOUND_ON_STACK) {
                generateImpliedEndTagsExceptFor(nsGkAtoms::rtc);
              }
              if (eltPos != currentPtr) {
                if (!isCurrent(nsGkAtoms::rtc)) {
                  if (eltPos == NOT_FOUND_ON_STACK) {
                    errStartTagSeenWithoutRuby(name);
                  } else {
                    errUnclosedChildrenInRuby();
                  }
                }
              }
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case MATH: {
              reconstructTheActiveFormattingElements();
              attributes->adjustForMath();
              if (selfClosing) {
                appendVoidElementToCurrentMayFosterMathML(elementName,
                                                          attributes);
                selfClosing = false;
              } else {
                appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
                                                                 attributes);
              }
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case SVG: {
              reconstructTheActiveFormattingElements();
              attributes->adjustForSvg();
              if (selfClosing) {
                appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
                selfClosing = false;
              } else {
                appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
                                                              attributes);
              }
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case CAPTION:
            case COL:
            case COLGROUP:
            case TBODY_OR_THEAD_OR_TFOOT:
            case TR:
            case TD_OR_TH:
            case FRAME:
            case FRAMESET:
            case HEAD: {
              errStrayStartTag(name);
              NS_HTML5_BREAK(starttagloop);
            }
            case OUTPUT: {
              reconstructTheActiveFormattingElements();
              appendToCurrentNodeAndPushElementMayFoster(
                  elementName, attributes, formPointer);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            default: {
              reconstructTheActiveFormattingElements();
              appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                         attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
          }
        }
      inbodyloop_end:;
        [[fallthrough]];
      }
      case IN_HEAD: {
        for (;;) {
          switch (group) {
            case HTML: {
              errStrayStartTag(name);
              if (!fragment && !isTemplateContents()) {
                addAttributesToHtml(attributes);
                attributes = nullptr;
              }
              NS_HTML5_BREAK(starttagloop);
            }
            case BASE:
            case LINK_OR_BASEFONT_OR_BGSOUND: {
              appendVoidElementToCurrentMayFoster(elementName, attributes);
              selfClosing = false;
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case META: {
              NS_HTML5_BREAK(inheadloop);
            }
            case TITLE: {
              startTagTitleInHead(elementName, attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case NOSCRIPT: {
              if (scriptingEnabled) {
                appendToCurrentNodeAndPushElement(elementName, attributes);
                originalMode = mode;
                mode = TEXT;
                tokenizer->setStateAndEndTagExpectation(
                    nsHtml5Tokenizer::RAWTEXT, elementName);
              } else {
                appendToCurrentNodeAndPushElementMayFoster(elementName,
                                                           attributes);
                mode = IN_HEAD_NOSCRIPT;
              }
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case SCRIPT: {
              startTagScriptInHead(elementName, attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case STYLE:
            case NOFRAMES: {
              startTagGenericRawText(elementName, attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            case HEAD: {
              errFooSeenWhenFooOpen(name);
              NS_HTML5_BREAK(starttagloop);
            }
            case TEMPLATE: {
              startTagTemplateInHead(elementName, attributes);
              attributes = nullptr;
              NS_HTML5_BREAK(starttagloop);
            }
            default: {
              pop();
              mode = AFTER_HEAD;
              NS_HTML5_CONTINUE(starttagloop);
            }
          }
        }
      inheadloop_end:;
        [[fallthrough]];
      }
      case IN_HEAD_NOSCRIPT: {
        switch (group) {
          case HTML: {
            errStrayStartTag(name);
            if (!fragment && !isTemplateContents()) {
              addAttributesToHtml(attributes);
              attributes = nullptr;
            }
            NS_HTML5_BREAK(starttagloop);
          }
          case LINK_OR_BASEFONT_OR_BGSOUND: {
            appendVoidElementToCurrentMayFoster(elementName, attributes);
            selfClosing = false;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case META: {
            checkMetaCharset(attributes);
            appendVoidElementToCurrentMayFoster(elementName, attributes);
            selfClosing = false;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case STYLE:
          case NOFRAMES: {
            appendToCurrentNodeAndPushElement(elementName, attributes);
            originalMode = mode;
            mode = TEXT;
            tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
                                                    elementName);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case HEAD: {
            errFooSeenWhenFooOpen(name);
            NS_HTML5_BREAK(starttagloop);
          }
          case NOSCRIPT: {
            errFooSeenWhenFooOpen(name);
            NS_HTML5_BREAK(starttagloop);
          }
          default: {
            errBadStartTagInNoscriptInHead(name);
            pop();
            mode = IN_HEAD;
            continue;
          }
        }
      }
      case IN_COLUMN_GROUP: {
        switch (group) {
          case HTML: {
            errStrayStartTag(name);
            if (!fragment && !isTemplateContents()) {
              addAttributesToHtml(attributes);
              attributes = nullptr;
            }
            NS_HTML5_BREAK(starttagloop);
          }
          case COL: {
            appendVoidElementToCurrentMayFoster(elementName, attributes);
            selfClosing = false;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case TEMPLATE: {
            startTagTemplateInHead(elementName, attributes);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          default: {
            if (!currentPtr || stack[currentPtr]->getGroup() == TEMPLATE) {
              MOZ_ASSERT(fragment || isTemplateContents());
              errGarbageInColgroup();
              NS_HTML5_BREAK(starttagloop);
            }
            pop();
            mode = IN_TABLE;
            continue;
          }
        }
      }
      case IN_SELECT_IN_TABLE: {
        switch (group) {
          case CAPTION:
          case TBODY_OR_THEAD_OR_TFOOT:
          case TR:
          case TD_OR_TH:
          case TABLE: {
            errStartTagWithSelectOpen(name);
            eltPos = findLastInTableScope(nsGkAtoms::select);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              MOZ_ASSERT(fragment);
              NS_HTML5_BREAK(starttagloop);
            }
            while (currentPtr >= eltPos) {
              pop();
            }
            resetTheInsertionMode();
            continue;
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case IN_SELECT: {
        switch (group) {
          case HTML: {
            errStrayStartTag(name);
            if (!fragment) {
              addAttributesToHtml(attributes);
              attributes = nullptr;
            }
            NS_HTML5_BREAK(starttagloop);
          }
          case OPTION: {
            if (isCurrent(nsGkAtoms::option)) {
              pop();
            }
            appendToCurrentNodeAndPushElement(elementName, attributes);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case OPTGROUP: {
            if (isCurrent(nsGkAtoms::option)) {
              pop();
            }
            if (isCurrent(nsGkAtoms::optgroup)) {
              pop();
            }
            appendToCurrentNodeAndPushElement(elementName, attributes);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case SELECT: {
            errStartSelectWhereEndSelectExpected();
            eltPos = findLastInTableScope(name);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              MOZ_ASSERT(fragment);
              errNoSelectInTableScope();
              NS_HTML5_BREAK(starttagloop);
            } else {
              while (currentPtr >= eltPos) {
                pop();
              }
              resetTheInsertionMode();
              NS_HTML5_BREAK(starttagloop);
            }
          }
          case INPUT:
          case TEXTAREA: {
            errStartTagWithSelectOpen(name);
            eltPos = findLastInTableScope(nsGkAtoms::select);
            if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
              MOZ_ASSERT(fragment);
              NS_HTML5_BREAK(starttagloop);
            }
            while (currentPtr >= eltPos) {
              pop();
            }
            resetTheInsertionMode();
            continue;
          }
          case SCRIPT: {
            startTagScriptInHead(elementName, attributes);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case TEMPLATE: {
            startTagTemplateInHead(elementName, attributes);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case HR: {
            if (isCurrent(nsGkAtoms::option)) {
              pop();
            }
            if (isCurrent(nsGkAtoms::optgroup)) {
              pop();
            }
            appendVoidElementToCurrent(elementName, attributes);
            selfClosing = false;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          default: {
            errStrayStartTag(name);
            NS_HTML5_BREAK(starttagloop);
          }
        }
      }
      case AFTER_BODY: {
        switch (group) {
          case HTML: {
            errStrayStartTag(name);
            if (!fragment && !isTemplateContents()) {
              addAttributesToHtml(attributes);
              attributes = nullptr;
            }
            NS_HTML5_BREAK(starttagloop);
          }
          default: {
            errStrayStartTag(name);
            mode = framesetOk ? FRAMESET_OK : IN_BODY;
            continue;
          }
        }
      }
      case IN_FRAMESET: {
        switch (group) {
          case FRAMESET: {
            appendToCurrentNodeAndPushElement(elementName, attributes);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case FRAME: {
            appendVoidElementToCurrentMayFoster(elementName, attributes);
            selfClosing = false;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          default:;  // fall through
        }
        [[fallthrough]];
      }
      case AFTER_FRAMESET: {
        switch (group) {
          case HTML: {
            errStrayStartTag(name);
            if (!fragment && !isTemplateContents()) {
              addAttributesToHtml(attributes);
              attributes = nullptr;
            }
            NS_HTML5_BREAK(starttagloop);
          }
          case NOFRAMES: {
            appendToCurrentNodeAndPushElement(elementName, attributes);
            originalMode = mode;
            mode = TEXT;
            tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
                                                    elementName);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          default: {
            errStrayStartTag(name);
            NS_HTML5_BREAK(starttagloop);
          }
        }
      }
      case INITIAL: {
        errStartTagWithoutDoctype();
        documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
        mode = BEFORE_HTML;
        continue;
      }
      case BEFORE_HTML: {
        switch (group) {
          case HTML: {
            if (attributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
              appendHtmlElementToDocumentAndPush();
            } else {
              appendHtmlElementToDocumentAndPush(attributes);
            }
            mode = BEFORE_HEAD;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          default: {
            appendHtmlElementToDocumentAndPush();
            mode = BEFORE_HEAD;
            continue;
          }
        }
      }
      case BEFORE_HEAD: {
        switch (group) {
          case HTML: {
            errStrayStartTag(name);
            if (!fragment && !isTemplateContents()) {
              addAttributesToHtml(attributes);
              attributes = nullptr;
            }
            NS_HTML5_BREAK(starttagloop);
          }
          case HEAD: {
            appendToCurrentNodeAndPushHeadElement(attributes);
            mode = IN_HEAD;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          default: {
            appendToCurrentNodeAndPushHeadElement(
                nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
            mode = IN_HEAD;
            continue;
          }
        }
      }
      case AFTER_HEAD: {
        switch (group) {
          case HTML: {
            errStrayStartTag(name);
            if (!fragment && !isTemplateContents()) {
              addAttributesToHtml(attributes);
              attributes = nullptr;
            }
            NS_HTML5_BREAK(starttagloop);
          }
          case BODY: {
            if (!attributes->getLength()) {
              appendToCurrentNodeAndPushBodyElement();
            } else {
              appendToCurrentNodeAndPushBodyElement(attributes);
            }
            framesetOk = false;
            mode = IN_BODY;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case FRAMESET: {
            appendToCurrentNodeAndPushElement(elementName, attributes);
            mode = IN_FRAMESET;
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case TEMPLATE: {
            errFooBetweenHeadAndBody(name);
            pushHeadPointerOntoStack();
            nsHtml5StackNode* headOnStack = stack[currentPtr];
            startTagTemplateInHead(elementName, attributes);
            removeFromStack(headOnStack);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case BASE:
          case LINK_OR_BASEFONT_OR_BGSOUND: {
            errFooBetweenHeadAndBody(name);
            pushHeadPointerOntoStack();
            appendVoidElementToCurrentMayFoster(elementName, attributes);
            selfClosing = false;
            pop();
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case META: {
            errFooBetweenHeadAndBody(name);
            checkMetaCharset(attributes);
            pushHeadPointerOntoStack();
            appendVoidElementToCurrentMayFoster(elementName, attributes);
            selfClosing = false;
            pop();
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case SCRIPT: {
            errFooBetweenHeadAndBody(name);
            pushHeadPointerOntoStack();
            appendToCurrentNodeAndPushElement(elementName, attributes);
            originalMode = mode;
            mode = TEXT;
            tokenizer->setStateAndEndTagExpectation(
                nsHtml5Tokenizer::SCRIPT_DATA, elementName);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case STYLE:
          case NOFRAMES: {
            errFooBetweenHeadAndBody(name);
            pushHeadPointerOntoStack();
            appendToCurrentNodeAndPushElement(elementName, attributes);
            originalMode = mode;
            mode = TEXT;
            tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
                                                    elementName);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case TITLE: {
            errFooBetweenHeadAndBody(name);
            pushHeadPointerOntoStack();
            appendToCurrentNodeAndPushElement(elementName, attributes);
            originalMode = mode;
            mode = TEXT;
            tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
                                                    elementName);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          case HEAD: {
            errStrayStartTag(name);
            NS_HTML5_BREAK(starttagloop);
          }
          default: {
            appendToCurrentNodeAndPushBodyElement();
            mode = FRAMESET_OK;
            continue;
          }
        }
      }
      case AFTER_AFTER_BODY: {
        switch (group) {
          case HTML: {
            errStrayStartTag(name);
            if (!fragment && !isTemplateContents()) {
              addAttributesToHtml(attributes);
              attributes = nullptr;
            }
            NS_HTML5_BREAK(starttagloop);
          }
          default: {
            errStrayStartTag(name);

            mode = framesetOk ? FRAMESET_OK : IN_BODY;
            continue;
          }
        }
      }
      case AFTER_AFTER_FRAMESET: {
        switch (group) {
          case HTML: {
            errStrayStartTag(name);
            if (!fragment && !isTemplateContents()) {
              addAttributesToHtml(attributes);
              attributes = nullptr;
            }
            NS_HTML5_BREAK(starttagloop);
          }
          case NOFRAMES: {
            startTagGenericRawText(elementName, attributes);
            attributes = nullptr;
            NS_HTML5_BREAK(starttagloop);
          }
          default: {
            errStrayStartTag(name);
            NS_HTML5_BREAK(starttagloop);
          }
        }
      }
      case TEXT: {
        MOZ_ASSERT(false);
        NS_HTML5_BREAK(starttagloop);
      }
    }
  }
starttagloop_end:;
  if (selfClosing) {
    errSelfClosing();
  }
  if (!mBuilder && attributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
    delete attributes;
  }
}