From f55328bb869b1a03a330face408837cf88d71c0b Mon Sep 17 00:00:00 2001 From: Henri Sivonen Date: Tue, 1 Nov 2011 13:33:11 +0200 Subject: [PATCH] Bug 482921 part 3 - Highlight tree builder-level errors in View Source. r=Olli.Pettay. --- .../en-US/chrome/layout/htmlparser.properties | 51 +- parser/html/javasrc/TreeBuilder.java | 596 ++++++++++++------ parser/html/nsHtml5AtomList.h | 2 +- parser/html/nsHtml5Highlighter.cpp | 63 +- parser/html/nsHtml5Highlighter.h | 59 +- parser/html/nsHtml5StreamParser.cpp | 5 +- parser/html/nsHtml5Tokenizer.cpp | 18 +- parser/html/nsHtml5TokenizerCppSupplement.h | 86 +-- parser/html/nsHtml5TreeBuilder.cpp | 394 +++++++----- parser/html/nsHtml5TreeBuilder.h | 1 + parser/html/nsHtml5TreeBuilderCppSupplement.h | 394 ++++++++++++ parser/html/nsHtml5TreeBuilderHSupplement.h | 98 ++- 12 files changed, 1368 insertions(+), 399 deletions(-) diff --git a/dom/locales/en-US/chrome/layout/htmlparser.properties b/dom/locales/en-US/chrome/layout/htmlparser.properties index bc27e77b0ef..bcd26fcd0c6 100644 --- a/dom/locales/en-US/chrome/layout/htmlparser.properties +++ b/dom/locales/en-US/chrome/layout/htmlparser.properties @@ -39,6 +39,7 @@ # http://hg.mozilla.org/projects/htmlparser/file/1f633cef7de7/src/nu/validator/htmlparser/impl/ErrorReportingTokenizer.java # which is available under the MIT license. +# Tokenizer errors errGarbageAfterLtSlash=Garbage after \u201C\u201D. Probable causes: Unescaped \u201C<\u201D (escape as \u201C<\u201D) or mistyped end tag. errCharRefLacksSemicolon=Character reference was not terminated by a semicolon. @@ -100,4 +101,52 @@ errNcrControlChar=Character reference expands to a control character. errNcrZero=Character reference expands to zero. errNoSpaceBetweenDoctypeSystemKeywordAndQuote=No space between the doctype \u201CSYSTEM\u201D keyword and the quote. errNoSpaceBetweenPublicAndSystemIds=No space between the doctype public and system identifiers. -errNoSpaceBetweenDoctypePublicKeywordAndQuote=No space between the doctype \u201CPUBLIC\u201D keyword and the quote. \ No newline at end of file +errNoSpaceBetweenDoctypePublicKeywordAndQuote=No space between the doctype \u201CPUBLIC\u201D keyword and the quote. + +# Tree builder errors +errStrayStartTag=Stray end tag \u201C%1$S\u201D. +errStrayEndTag=Stray end tag \u201C%1$S\u201D. +errUnclosedElements=End tag \u201C%1$S\u201D seen, but there were open elements. +errUnclosedElementsImplied=End tag \u201C%1$S\u201D implied, but there were open elements. +errUnclosedElementsCell=A table cell was implicitly closed, but there were open elements. +errStrayDoctype=Stray doctype. +errAlmostStandardsDoctype=Almost standards mode doctype. Expected \u201C\u201D. +errQuirkyDoctype=Quirky doctype. Expected \u201C\u201D. +errNonSpaceInTrailer=Non-space character in page trailer. +errNonSpaceAfterFrameset=Non-space after \u201Cframeset\u201D. +errNonSpaceInFrameset=Non-space in \u201Cframeset\u201D. +errNonSpaceAfterBody=Non-space character after body. +errNonSpaceInColgroupInFragment=Non-space in \u201Ccolgroup\u201D when parsing fragment. +errNonSpaceInNoscriptInHead=Non-space character inside \u201Cnoscript\u201D inside \u201Chead\u201D. +errFooBetweenHeadAndBody=\u201C%1$S\u201D element between \u201Chead\u201D and \u201Cbody\u201D. +errStartTagWithoutDoctype=Start tag seen without seeing a doctype first. Expected \u201C\u201D. +errNoSelectInTableScope=No \u201Cselect\u201D in table scope. +errStartSelectWhereEndSelectExpected=\u201Cselect\u201D start tag where end tag expected. +errStartTagWithSelectOpen=\u201C%1$S\u201D start tag with \u201Cselect\u201D open. +errBadStartTagInHead=Bad start tag in \u201C%1$S\u201D in \u201Chead\u201D. +errImage=Saw a start tag \u201Cimage\u201D. +errIsindex=\u201Cisindex\u201D seen. +errFooSeenWhenFooOpen=An \u201C%1$S\u201D start tag seen but an element of the same type was already open. +errHeadingWhenHeadingOpen=Heading cannot be a child of another heading. +errFramesetStart=\u201Cframeset\u201D start tag seen. +errNoCellToClose=No cell to close. +errStartTagInTable=Start tag \u201C%1$S\u201D seen in \u201Ctable\u201D. +errFormWhenFormOpen=Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag. +errTableSeenWhileTableOpen=Start tag for \u201Ctable\u201D seen but the previous \u201Ctable\u201D is still open. +errStartTagInTableBody=\u201C%1$S\u201D start tag in table body. +errEndTagSeenWithoutDoctype=End tag seen without seeing a doctype first. Expected \u201C\u201D. +errEndTagAfterBody=Saw an end tag after \u201Cbody\u201D had been closed. +errEndTagSeenWithSelectOpen=\u201C%1$S\u201D end tag with \u201Cselect\u201D open. +errGarbageInColgroup=Garbage in \u201Ccolgroup\u201D fragment. +errEndTagBr=End tag \u201Cbr\u201D. +errNoElementToCloseButEndTagSeen=No \u201C%1$S\u201D element in scope but a \u201C%1$S\u201D end tag seen. +errHtmlStartTagInForeignContext=HTML start tag \u201C%1$S\u201D in a foreign namespace context. +errTableClosedWhileCaptionOpen=\u201Ctable\u201D closed but \u201Ccaption\u201D was still open. +errNoTableRowToClose=No table row to close. +errNonSpaceInTable=Misplaced non-space characters insided a table. +errUnclosedChildrenInRuby=Unclosed children in \u201Cruby\u201D. +errStartTagSeenWithoutRuby=Start tag \u201C%1$S\u201D seen without a \u201Cruby\u201D element being open. +errSelfClosing=Self-closing syntax (\u201C/>\u201D) used on a non-void HTML element. Ignoring the slash and treating as a start tag. +errNoCheckUnclosedElementsOnStack=Unclosed elements on stack. +errEndTagDidNotMatchCurrentOpenElement=End tag \u201C%1$S\u201D did not match the name of the current open element (\u201C%2$S\u201D). +errEndTagViolatesNestingRules=End tag \u201C%1$S\u201D violates nesting rules. \ No newline at end of file diff --git a/parser/html/javasrc/TreeBuilder.java b/parser/html/javasrc/TreeBuilder.java index 90f4e1be8c2..5b3e7920190 100644 --- a/parser/html/javasrc/TreeBuilder.java +++ b/parser/html/javasrc/TreeBuilder.java @@ -476,68 +476,6 @@ public abstract class TreeBuilder implements TokenHandler, errorHandler.error(spe); } - /** - * Reports a stray start tag. - * @param name the name of the stray tag - * - * @throws SAXException - */ - private void errStrayStartTag(String name) throws SAXException { - err("Stray end tag \u201C" + name + "\u201D."); - } - - /** - * Reports a stray end tag. - * @param name the name of the stray tag - * - * @throws SAXException - */ - private void errStrayEndTag(String name) throws SAXException { - err("Stray end tag \u201C" + name + "\u201D."); - } - - /** - * Reports a state when elements expected to be closed were not. - * - * @param eltPos the position of the start tag on the stack of the element - * being closed. - * @param name the name of the end tag - * - * @throws SAXException - */ - private void errUnclosedElements(int eltPos, String name) throws SAXException { - errNoCheck("End tag \u201C" + name + "\u201D seen, but there were open elements."); - errListUnclosedStartTags(eltPos); - } - - /** - * Reports a state when elements expected to be closed ahead of an implied - * end tag but were not. - * - * @param eltPos the position of the start tag on the stack of the element - * being closed. - * @param name the name of the end tag - * - * @throws SAXException - */ - private void errUnclosedElementsImplied(int eltPos, String name) throws SAXException { - errNoCheck("End tag \u201C" + name + "\u201D implied, but there were open elements."); - errListUnclosedStartTags(eltPos); - } - - /** - * Reports a state when elements expected to be closed ahead of an implied - * table cell close. - * - * @param eltPos the position of the start tag on the stack of the element - * being closed. - * @throws SAXException - */ - private void errUnclosedElementsCell(int eltPos) throws SAXException { - errNoCheck("A table cell was implicitly closed, but there were open elements."); - errListUnclosedStartTags(eltPos); - } - private void errListUnclosedStartTags(int eltPos) throws SAXException { if (currentPtr != -1) { for (int i = currentPtr; i > eltPos; i--) { @@ -546,22 +484,6 @@ public abstract class TreeBuilder implements TokenHandler, } } - /** - * Reports arriving at/near end of document with unclosed elements remaining. - * - * @param message - * the message - * @throws SAXException - */ - private void errEndWithUnclosedElements(String message) throws SAXException { - if (errorHandler == null) { - return; - } - errNoCheck(message); - // just report all remaining unclosed elements - errListUnclosedStartTags(0); - } - /** * Reports the name and location of an unclosed element. * @@ -679,13 +601,13 @@ public abstract class TreeBuilder implements TokenHandler, // ]NOCPP] if (isQuirky(name, publicIdentifier, systemIdentifier, forceQuirks)) { - err("Quirky doctype. Expected \u201C\u201D."); + errQuirkyDoctype(); documentModeInternal(DocumentMode.QUIRKS_MODE, publicIdentifier, systemIdentifier, false); } else if (isAlmostStandards(publicIdentifier, systemIdentifier)) { - err("Almost standards mode doctype. Expected \u201C\u201D."); + errAlmostStandardsDoctype(); documentModeInternal( DocumentMode.ALMOST_STANDARDS_MODE, publicIdentifier, systemIdentifier, @@ -864,7 +786,7 @@ public abstract class TreeBuilder implements TokenHandler, /* * A DOCTYPE token Parse error. */ - err("Stray doctype."); + errStrayDoctype(); /* * Ignore the token. */ @@ -1064,6 +986,7 @@ public abstract class TreeBuilder implements TokenHandler, err("Non-space characters found without seeing a doctype first. Expected e.g. \u201C\u201D."); break; case HTML: + // XXX figure out a way to report this in the Gecko View Source case err("Non-space characters found without seeing a doctype first. Expected \u201C\u201D."); break; case HTML401_STRICT: @@ -1160,7 +1083,7 @@ public abstract class TreeBuilder implements TokenHandler, * Parse error. Act as if an end tag with * the tag name "noscript" had been seen */ - err("Non-space character inside \u201Cnoscript\u201D inside \u201Chead\u201D."); + errNonSpaceInNoscriptInHead(); flushCharacters(); pop(); mode = IN_HEAD; @@ -1233,7 +1156,7 @@ public abstract class TreeBuilder implements TokenHandler, * current token. */ if (currentPtr == 0) { - err("Non-space in \u201Ccolgroup\u201D when parsing fragment."); + errNonSpaceInColgroupInFragment(); start = i + 1; continue; } @@ -1246,7 +1169,7 @@ public abstract class TreeBuilder implements TokenHandler, case IN_SELECT_IN_TABLE: break charactersloop; case AFTER_BODY: - err("Non-space character after body."); + errNonSpaceAfterBody(); fatal(); mode = framesetOk ? FRAMESET_OK : IN_BODY; i--; @@ -1260,7 +1183,7 @@ public abstract class TreeBuilder implements TokenHandler, /* * Parse error. */ - err("Non-space in \u201Cframeset\u201D."); + errNonSpaceInFrameset(); /* * Ignore the token. */ @@ -1275,7 +1198,7 @@ public abstract class TreeBuilder implements TokenHandler, /* * Parse error. */ - err("Non-space after \u201Cframeset\u201D."); + errNonSpaceAfterFrameset(); /* * Ignore the token. */ @@ -1285,7 +1208,7 @@ public abstract class TreeBuilder implements TokenHandler, /* * Parse error. */ - err("Non-space character in page trailer."); + errNonSpaceInTrailer(); /* * Switch back to the main mode and * reprocess the token. @@ -1294,10 +1217,7 @@ public abstract class TreeBuilder implements TokenHandler, i--; continue; case AFTER_AFTER_FRAMESET: - /* - * Parse error. - */ - err("Non-space character in page trailer."); + errNonSpaceInTrailer(); /* * Switch back to the main mode and * reprocess the token. @@ -1338,7 +1258,9 @@ public abstract class TreeBuilder implements TokenHandler, flushCharacters(); eofloop: for (;;) { if (isInForeign()) { + // [NOCPP[ err("End of file in a foreign namespace context."); + // ]NOCPP] break eofloop; } switch (mode) { @@ -1396,16 +1318,20 @@ public abstract class TreeBuilder implements TokenHandler, mode = IN_HEAD; continue; case IN_HEAD: + // [NOCPP[ if (errorHandler != null && currentPtr > 1) { - errEndWithUnclosedElements("End of file seen and there were open elements."); + errEofWithUnclosedElements(); } + // ]NOCPP] while (currentPtr > 0) { popOnEof(); } mode = AFTER_HEAD; continue; case IN_HEAD_NOSCRIPT: - errEndWithUnclosedElements("End of file seen and there were open elements."); + // [NOCPP[ + errEofWithUnclosedElements(); + // ]NOCPP] while (currentPtr > 1) { popOnEof(); } @@ -1441,17 +1367,19 @@ public abstract class TreeBuilder implements TokenHandler, case HTML: break; default: - errEndWithUnclosedElements("End of file seen and there were open elements."); + errEofWithUnclosedElements(); break openelementloop; } } // ]NOCPP] break eofloop; case TEXT: + // [NOCPP[ if (errorHandler != null) { errNoCheck("End of file seen when expecting text or an end tag."); errListUnclosedStartTags(0); } + // ]NOCPP] // XXX mark script as already executed if (originalMode == AFTER_HEAD) { popOnEof(); @@ -1465,9 +1393,11 @@ public abstract class TreeBuilder implements TokenHandler, case IN_SELECT: case IN_SELECT_IN_TABLE: case IN_FRAMESET: + // [NOCPP[ if (errorHandler != null && currentPtr > 0) { - errEndWithUnclosedElements("End of file seen and there were open elements."); + errEofWithUnclosedElements(); } + // ]NOCPP] break eofloop; case AFTER_BODY: case AFTER_FRAMESET: @@ -1572,9 +1502,7 @@ public abstract class TreeBuilder implements TokenHandler, case P: case PRE_OR_LISTING: case TABLE: - err("HTML start tag \u201C" - + name - + "\u201D in a foreign namespace context."); + errHtmlStartTagInForeignContext(name); while (!isSpecialParentInForeign(stack[currentPtr])) { pop(); } @@ -1583,9 +1511,7 @@ public abstract class TreeBuilder implements TokenHandler, if (attributes.contains(AttributeName.COLOR) || attributes.contains(AttributeName.FACE) || attributes.contains(AttributeName.SIZE)) { - err("HTML start tag \u201C" - + name - + "\u201D in a foreign namespace context."); + errHtmlStartTagInForeignContext(name); while (!isSpecialParentInForeign(stack[currentPtr])) { pop(); } @@ -1633,8 +1559,7 @@ public abstract class TreeBuilder implements TokenHandler, attributes = null; // CPP break starttagloop; case TD_OR_TH: - err("\u201C" + name - + "\u201D start tag in table body."); + errStartTagInTableBody(name); clearStackBackTo(findLastInTableScopeOrRootTbodyTheadTfoot()); appendToCurrentNodeAndPushElement( ElementName.TR, @@ -1677,7 +1602,7 @@ public abstract class TreeBuilder implements TokenHandler, eltPos = findLastOrRoot(TreeBuilder.TR); if (eltPos == 0) { assert fragment; - err("No table row to close."); + errNoTableRowToClose(); break starttagloop; } clearStackBackTo(eltPos); @@ -1731,7 +1656,7 @@ public abstract class TreeBuilder implements TokenHandler, mode = IN_TABLE_BODY; continue starttagloop; case TABLE: - err("Start tag for \u201Ctable\u201D seen but the previous \u201Ctable\u201D is still open."); + errTableSeenWhileTableOpen(); eltPos = findLastInTableScope(name); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment; @@ -1740,7 +1665,7 @@ public abstract class TreeBuilder implements TokenHandler, generateImpliedEndTags(); // XXX is the next if dead code? if (errorHandler != null && !isCurrent("table")) { - errNoCheck("Unclosed elements on stack."); + errNoCheckUnclosedElementsOnStack(); } while (currentPtr >= eltPos) { pop(); @@ -1785,17 +1710,16 @@ public abstract class TreeBuilder implements TokenHandler, break starttagloop; case FORM: if (formPointer != null) { - err("Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag."); + errFormWhenFormOpen(); break starttagloop; } else { - err("Start tag \u201Cform\u201D seen in \u201Ctable\u201D."); + errStartTagInTable(name); appendVoidFormToCurrent(attributes); attributes = null; // CPP break starttagloop; } default: - err("Start tag \u201C" + name - + "\u201D seen in \u201Ctable\u201D."); + errStartTagInTable(name); // fall through to IN_BODY break intableloop; } @@ -1815,7 +1739,7 @@ public abstract class TreeBuilder implements TokenHandler, } generateImpliedEndTags(); if (errorHandler != null && currentPtr != eltPos) { - errNoCheck("Unclosed elements on stack."); + errNoCheckUnclosedElementsOnStack(); } while (currentPtr >= eltPos) { pop(); @@ -1836,7 +1760,7 @@ public abstract class TreeBuilder implements TokenHandler, case TD_OR_TH: eltPos = findLastInTableScopeTdTh(); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - err("No cell to close."); + errNoCellToClose(); break starttagloop; } else { closeTheCell(eltPos); @@ -1854,7 +1778,7 @@ public abstract class TreeBuilder implements TokenHandler, errStrayStartTag(name); break starttagloop; } else { - err("\u201Cframeset\u201D start tag seen."); + errFramesetStart(); detachFromParent(stack[1].node); while (currentPtr > 0) { pop(); @@ -1925,7 +1849,7 @@ public abstract class TreeBuilder implements TokenHandler, errStrayStartTag(name); break starttagloop; } - err("\u201Cbody\u201D start tag found but the \u201Cbody\u201D element is already open."); + errFooSeenWhenFooOpen(name); framesetOk = false; if (mode == FRAMESET_OK) { mode = IN_BODY; @@ -1947,7 +1871,7 @@ public abstract class TreeBuilder implements TokenHandler, 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) { - err("Heading cannot be a child of another heading."); + errHeadingWhenHeadingOpen(); pop(); } appendToCurrentNodeAndPushElementMayFoster( @@ -1972,7 +1896,7 @@ public abstract class TreeBuilder implements TokenHandler, break starttagloop; case FORM: if (formPointer != null) { - err("Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag."); + errFormWhenFormOpen(); break starttagloop; } else { implicitlyCloseP(); @@ -2023,7 +1947,7 @@ public abstract class TreeBuilder implements TokenHandler, case A: int activeAPos = findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker("a"); if (activeAPos != -1) { - err("An \u201Ca\u201D start tag seen with already an active \u201Ca\u201D element."); + errFooSeenWhenFooOpen(name); StackNode activeA = listOfActiveFormattingElements[activeAPos]; activeA.retain(); adoptionAgencyEndTag("a"); @@ -2052,7 +1976,7 @@ public abstract class TreeBuilder implements TokenHandler, case NOBR: reconstructTheActiveFormattingElements(); if (TreeBuilder.NOT_FOUND_ON_STACK != findLastInScope("nobr")) { - err("\u201Cnobr\u201D start tag seen when there was an open \u201Cnobr\u201D element in scope."); + errFooSeenWhenFooOpen(name); adoptionAgencyEndTag("nobr"); reconstructTheActiveFormattingElements(); } @@ -2064,8 +1988,7 @@ public abstract class TreeBuilder implements TokenHandler, case BUTTON: eltPos = findLastInScope(name); if (eltPos != TreeBuilder.NOT_FOUND_ON_STACK) { - err("\u201Cbutton\u201D start tag seen when there was an open \u201Cbutton\u201D element in scope."); - + errFooSeenWhenFooOpen(name); generateImpliedEndTags(); if (errorHandler != null && !isCurrent(name)) { @@ -2132,7 +2055,7 @@ public abstract class TreeBuilder implements TokenHandler, attributes = null; // CPP break starttagloop; case IMAGE: - err("Saw a start tag \u201Cimage\u201D."); + errImage(); elementName = ElementName.IMG; continue starttagloop; case KEYGEN: @@ -2145,7 +2068,7 @@ public abstract class TreeBuilder implements TokenHandler, attributes = null; // CPP break starttagloop; case ISINDEX: - err("\u201Cisindex\u201D seen."); + errIsindex(); if (formPointer != null) { break starttagloop; } @@ -2310,15 +2233,10 @@ public abstract class TreeBuilder implements TokenHandler, generateImpliedEndTags(); } if (eltPos != currentPtr) { - if (errorHandler != null) { - if (eltPos != NOT_FOUND_ON_STACK) { - - errNoCheck("Start tag \u201C" - + name - + "\u201D seen without a \u201Cruby\u201D element being open."); - } else { - errNoCheck("Unclosed children in \u201Cruby\u201D."); - } + if (eltPos != NOT_FOUND_ON_STACK) { + errStartTagSeenWithoutRuby(name); + } else { + errUnclosedChildrenInRuby(); } while (currentPtr > eltPos) { pop(); @@ -2459,7 +2377,7 @@ public abstract class TreeBuilder implements TokenHandler, break starttagloop; case HEAD: /* Parse error. */ - err("Start tag for \u201Chead\u201D seen when \u201Chead\u201D was already open."); + errFooSeenWhenFooOpen(name); /* Ignore the token. */ break starttagloop; default: @@ -2506,14 +2424,13 @@ public abstract class TreeBuilder implements TokenHandler, attributes = null; // CPP break starttagloop; case HEAD: - err("Start tag for \u201Chead\u201D seen when \u201Chead\u201D was already open."); + errFooSeenWhenFooOpen(name); break starttagloop; case NOSCRIPT: - err("Start tag for \u201Cnoscript\u201D seen when \u201Cnoscript\u201D was already open."); + errFooSeenWhenFooOpen(name); break starttagloop; default: - err("Bad start tag in \u201C" + name - + "\u201D in \u201Chead\u201D."); + errBadStartTagInHead(name); pop(); mode = IN_HEAD; continue; @@ -2537,7 +2454,7 @@ public abstract class TreeBuilder implements TokenHandler, default: if (currentPtr == 0) { assert fragment; - err("Garbage in \u201Ccolgroup\u201D fragment."); + errGarbageInColgroup(); break starttagloop; } pop(); @@ -2551,9 +2468,7 @@ public abstract class TreeBuilder implements TokenHandler, case TR: case TD_OR_TH: case TABLE: - err("\u201C" - + name - + "\u201D start tag with \u201Cselect\u201D open."); + errStartTagWithSelectOpen(name); eltPos = findLastInTableScope("select"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment; @@ -2598,11 +2513,11 @@ public abstract class TreeBuilder implements TokenHandler, attributes = null; // CPP break starttagloop; case SELECT: - err("\u201Cselect\u201D start tag where end tag expected."); + errStartSelectWhereEndSelectExpected(); eltPos = findLastInTableScope(name); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment; - err("No \u201Cselect\u201D in table scope."); + errNoSelectInTableScope(); break starttagloop; } else { while (currentPtr >= eltPos) { @@ -2614,9 +2529,7 @@ public abstract class TreeBuilder implements TokenHandler, case INPUT: case TEXTAREA: case KEYGEN: - err("\u201C" - + name - + "\u201D start tag seen in \u201Cselect\2201D."); + errStartTagWithSelectOpen(name); eltPos = findLastInTableScope("select"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment; @@ -2710,7 +2623,9 @@ public abstract class TreeBuilder implements TokenHandler, err("Start tag seen without seeing a doctype first. Expected e.g. \u201C\u201D."); break; case HTML: - err("Start tag seen without seeing a doctype first. Expected \u201C\u201D."); + // ]NOCPP] + errStartTagWithoutDoctype(); + // [NOCPP[ break; case HTML401_STRICT: err("Start tag seen without seeing a doctype first. Expected \u201C\u201D."); @@ -2846,7 +2761,7 @@ public abstract class TreeBuilder implements TokenHandler, attributes = null; // CPP break starttagloop; case BASE: - err("\u201Cbase\u201D element outside \u201Chead\u201D."); + errFooBetweenHeadAndBody(name); pushHeadPointerOntoStack(); appendVoidElementToCurrentMayFoster( elementName, @@ -2856,7 +2771,7 @@ public abstract class TreeBuilder implements TokenHandler, attributes = null; // CPP break starttagloop; case LINK_OR_BASEFONT_OR_BGSOUND: - err("\u201Clink\u201D element outside \u201Chead\u201D."); + errFooBetweenHeadAndBody(name); pushHeadPointerOntoStack(); appendVoidElementToCurrentMayFoster( elementName, @@ -2866,7 +2781,7 @@ public abstract class TreeBuilder implements TokenHandler, attributes = null; // CPP break starttagloop; case META: - err("\u201Cmeta\u201D element outside \u201Chead\u201D."); + errFooBetweenHeadAndBody(name); checkMetaCharset(attributes); pushHeadPointerOntoStack(); appendVoidElementToCurrentMayFoster( @@ -2877,7 +2792,7 @@ public abstract class TreeBuilder implements TokenHandler, attributes = null; // CPP break starttagloop; case SCRIPT: - err("\u201Cscript\u201D element between \u201Chead\u201D and \u201Cbody\u201D."); + errFooBetweenHeadAndBody(name); pushHeadPointerOntoStack(); appendToCurrentNodeAndPushElement( elementName, @@ -2890,9 +2805,7 @@ public abstract class TreeBuilder implements TokenHandler, break starttagloop; case STYLE: case NOFRAMES: - err("\u201C" - + name - + "\u201D element between \u201Chead\u201D and \u201Cbody\u201D."); + errFooBetweenHeadAndBody(name); pushHeadPointerOntoStack(); appendToCurrentNodeAndPushElement( elementName, @@ -2904,7 +2817,7 @@ public abstract class TreeBuilder implements TokenHandler, attributes = null; // CPP break starttagloop; case TITLE: - err("\u201Ctitle\u201D element outside \u201Chead\u201D."); + errFooBetweenHeadAndBody(name); pushHeadPointerOntoStack(); appendToCurrentNodeAndPushElement( elementName, @@ -2967,8 +2880,8 @@ public abstract class TreeBuilder implements TokenHandler, // fails } } - if (errorHandler != null && selfClosing) { - errNoCheck("Self-closing syntax (\u201C/>\u201D) used on a non-void HTML element. Ignoring the slash and treating as a start tag."); + if (selfClosing) { + errSelfClosing(); } if (attributes != HtmlAttributes.EMPTY_ATTRIBUTES) { Portability.delete(attributes); @@ -3184,11 +3097,8 @@ public abstract class TreeBuilder implements TokenHandler, @Local String name = elementName.name; endtagloop: for (;;) { if (isInForeign()) { - if (errorHandler != null && stack[currentPtr].name != name) { - errNoCheck("End tag \u201C" - + name - + "\u201D did not match the name of the current open element (\u201C" - + stack[currentPtr].popName + "\u201D)."); + if (stack[currentPtr].name != name) { + errEndTagDidNotMatchCurrentOpenElement(name, stack[currentPtr].popName); } eltPos = currentPtr; for (;;) { @@ -3210,7 +3120,7 @@ public abstract class TreeBuilder implements TokenHandler, eltPos = findLastOrRoot(TreeBuilder.TR); if (eltPos == 0) { assert fragment; - err("No table row to close."); + errNoTableRowToClose(); break endtagloop; } clearStackBackTo(eltPos); @@ -3221,7 +3131,7 @@ public abstract class TreeBuilder implements TokenHandler, eltPos = findLastOrRoot(TreeBuilder.TR); if (eltPos == 0) { assert fragment; - err("No table row to close."); + errNoTableRowToClose(); break endtagloop; } clearStackBackTo(eltPos); @@ -3236,7 +3146,7 @@ public abstract class TreeBuilder implements TokenHandler, eltPos = findLastOrRoot(TreeBuilder.TR); if (eltPos == 0) { assert fragment; - err("No table row to close."); + errNoTableRowToClose(); break endtagloop; } clearStackBackTo(eltPos); @@ -3335,7 +3245,7 @@ public abstract class TreeBuilder implements TokenHandler, mode = IN_TABLE; break endtagloop; case TABLE: - err("\u201Ctable\u201D closed but \u201Ccaption\u201D was still open."); + errTableClosedWhileCaptionOpen(); eltPos = findLastInTableScope("caption"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { break endtagloop; @@ -3422,7 +3332,7 @@ public abstract class TreeBuilder implements TokenHandler, case TBODY_OR_THEAD_OR_TFOOT: break; default: - errEndWithUnclosedElements("End tag for \u201Cbody\u201D seen but there were unclosed elements."); + errEndWithUnclosedElements(name); break uncloseloop1; } } @@ -3447,7 +3357,7 @@ public abstract class TreeBuilder implements TokenHandler, case HTML: break; default: - errEndWithUnclosedElements("End tag for \u201Chtml\u201D seen but there were unclosed elements."); + errEndWithUnclosedElements(name); break uncloseloop2; } } @@ -3493,12 +3403,10 @@ public abstract class TreeBuilder implements TokenHandler, case P: eltPos = findLastInButtonScope("p"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - err("No \u201Cp\u201D element in scope but a \u201Cp\u201D end tag seen."); + errNoElementToCloseButEndTagSeen("p"); // XXX Can the 'in foreign' case happen anymore? if (isInForeign()) { - err("HTML start tag \u201C" - + name - + "\u201D in a foreign namespace context."); + errHtmlStartTagInForeignContext(name); while (stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") { pop(); } @@ -3520,7 +3428,7 @@ public abstract class TreeBuilder implements TokenHandler, case LI: eltPos = findLastInListScope(name); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - err("No \u201Cli\u201D element in list scope but a \u201Cli\u201D end tag seen."); + errNoElementToCloseButEndTagSeen(name); } else { generateImpliedEndTagsExceptFor(name); if (errorHandler != null @@ -3535,10 +3443,7 @@ public abstract class TreeBuilder implements TokenHandler, case DD_OR_DT: eltPos = findLastInScope(name); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { - err("No \u201C" - + name - + "\u201D element in scope but a \u201C" - + name + "\u201D end tag seen."); + errNoElementToCloseButEndTagSeen(name); } else { generateImpliedEndTagsExceptFor(name); if (errorHandler != null @@ -3581,11 +3486,9 @@ public abstract class TreeBuilder implements TokenHandler, } break endtagloop; case BR: - err("End tag \u201Cbr\u201D."); + errEndTagBr(); if (isInForeign()) { - err("HTML start tag \u201C" - + name - + "\u201D in a foreign namespace context."); + errHtmlStartTagInForeignContext(name); while (stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") { pop(); } @@ -3657,7 +3560,7 @@ public abstract class TreeBuilder implements TokenHandler, case COLGROUP: if (currentPtr == 0) { assert fragment; - err("Garbage in \u201Ccolgroup\u201D fragment."); + errGarbageInColgroup(); break endtagloop; } pop(); @@ -3669,7 +3572,7 @@ public abstract class TreeBuilder implements TokenHandler, default: if (currentPtr == 0) { assert fragment; - err("Garbage in \u201Ccolgroup\u201D fragment."); + errGarbageInColgroup(); break endtagloop; } pop(); @@ -3683,9 +3586,7 @@ public abstract class TreeBuilder implements TokenHandler, case TBODY_OR_THEAD_OR_TFOOT: case TR: case TD_OR_TH: - err("\u201C" - + name - + "\u201D end tag with \u201Cselect\u201D open."); + errEndTagSeenWithSelectOpen(name); if (findLastInTableScope(name) != TreeBuilder.NOT_FOUND_ON_STACK) { eltPos = findLastInTableScope("select"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { @@ -3751,7 +3652,7 @@ public abstract class TreeBuilder implements TokenHandler, break endtagloop; } default: - err("Saw an end tag after \u201Cbody\u201D had been closed."); + errEndTagAfterBody(); mode = framesetOk ? FRAMESET_OK : IN_BODY; continue; } @@ -3791,7 +3692,9 @@ public abstract class TreeBuilder implements TokenHandler, err("End tag seen without seeing a doctype first. Expected e.g. \u201C\u201D."); break; case HTML: - err("End tag seen without seeing a doctype first. Expected \u201C\u201D."); + // ]NOCPP] + errEndTagSeenWithoutDoctype(); + // [NOCPP[ break; case HTML401_STRICT: err("End tag seen without seeing a doctype first. Expected \u201C\u201D."); @@ -4377,17 +4280,17 @@ public abstract class TreeBuilder implements TokenHandler, formattingEltStackPos--; } if (formattingEltStackPos == -1) { - err("No element \u201C" + name + "\u201D to close."); + errNoElementToCloseButEndTagSeen(name); removeFromListOfActiveFormattingElements(formattingEltListPos); return true; } if (!inScope) { - err("No element \u201C" + name + "\u201D to close."); + errNoElementToCloseButEndTagSeen(name); return true; } // stackPos now points to the formatting element and it is in scope - if (errorHandler != null && formattingEltStackPos != currentPtr) { - errNoCheck("End tag \u201C" + name + "\u201D violates nesting rules."); + if (formattingEltStackPos != currentPtr) { + errEndTagViolatesNestingRules(name); } int furthestBlockPos = formattingEltStackPos + 1; while (furthestBlockPos <= currentPtr) { @@ -5410,7 +5313,7 @@ public abstract class TreeBuilder implements TokenHandler, if (charBufferLen > 0) { if ((mode == IN_TABLE || mode == IN_TABLE_BODY || mode == IN_ROW) && charBufferContainsNonWhitespace()) { - err("Misplaced non-space characters insided a table."); + errNonSpaceInTable(); reconstructTheActiveFormattingElements(); if (!stack[currentPtr].isFosterParenting()) { // reconstructing gave us a new current node @@ -5717,4 +5620,313 @@ public abstract class TreeBuilder implements TokenHandler, return currentPtr + 1; } + /** + * Reports a stray start tag. + * @param name the name of the stray tag + * + * @throws SAXException + */ + private void errStrayStartTag(@Local String name) throws SAXException { + err("Stray end tag \u201C" + name + "\u201D."); + } + + /** + * Reports a stray end tag. + * @param name the name of the stray tag + * + * @throws SAXException + */ + private void errStrayEndTag(@Local String name) throws SAXException { + err("Stray end tag \u201C" + name + "\u201D."); + } + + /** + * Reports a state when elements expected to be closed were not. + * + * @param eltPos the position of the start tag on the stack of the element + * being closed. + * @param name the name of the end tag + * + * @throws SAXException + */ + private void errUnclosedElements(int eltPos, @Local String name) throws SAXException { + errNoCheck("End tag \u201C" + name + "\u201D seen, but there were open elements."); + errListUnclosedStartTags(eltPos); + } + + /** + * Reports a state when elements expected to be closed ahead of an implied + * end tag but were not. + * + * @param eltPos the position of the start tag on the stack of the element + * being closed. + * @param name the name of the end tag + * + * @throws SAXException + */ + private void errUnclosedElementsImplied(int eltPos, String name) throws SAXException { + errNoCheck("End tag \u201C" + name + "\u201D implied, but there were open elements."); + errListUnclosedStartTags(eltPos); + } + + /** + * Reports a state when elements expected to be closed ahead of an implied + * table cell close. + * + * @param eltPos the position of the start tag on the stack of the element + * being closed. + * @throws SAXException + */ + private void errUnclosedElementsCell(int eltPos) throws SAXException { + errNoCheck("A table cell was implicitly closed, but there were open elements."); + errListUnclosedStartTags(eltPos); + } + + private void errStrayDoctype() throws SAXException { + err("Stray doctype."); + } + + private void errAlmostStandardsDoctype() throws SAXException { + err("Almost standards mode doctype. Expected \u201C\u201D."); + } + + private void errQuirkyDoctype() throws SAXException { + err("Quirky doctype. Expected \u201C\u201D."); + } + + private void errNonSpaceInTrailer() throws SAXException { + err("Non-space character in page trailer."); + } + + private void errNonSpaceAfterFrameset() throws SAXException { + err("Non-space after \u201Cframeset\u201D."); + } + + private void errNonSpaceInFrameset() throws SAXException { + err("Non-space in \u201Cframeset\u201D."); + } + + private void errNonSpaceAfterBody() throws SAXException { + err("Non-space character after body."); + } + + private void errNonSpaceInColgroupInFragment() throws SAXException { + err("Non-space in \u201Ccolgroup\u201D when parsing fragment."); + } + + private void errNonSpaceInNoscriptInHead() throws SAXException { + err("Non-space character inside \u201Cnoscript\u201D inside \u201Chead\u201D."); + } + + private void errFooBetweenHeadAndBody(@Local String name) throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("\u201C" + name + "\u201D element between \u201Chead\u201D and \u201Cbody\u201D."); + } + + private void errStartTagWithoutDoctype() throws SAXException { + err("Start tag seen without seeing a doctype first. Expected \u201C\u201D."); + } + + private void errNoSelectInTableScope() throws SAXException { + err("No \u201Cselect\u201D in table scope."); + } + + private void errStartSelectWhereEndSelectExpected() throws SAXException { + err("\u201Cselect\u201D start tag where end tag expected."); + } + + private void errStartTagWithSelectOpen(@Local String name) + throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("\u201C" + name + + "\u201D start tag with \u201Cselect\u201D open."); + } + + private void errBadStartTagInHead(@Local String name) throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("Bad start tag in \u201C" + name + + "\u201D in \u201Chead\u201D."); + } + + private void errImage() throws SAXException { + err("Saw a start tag \u201Cimage\u201D."); + } + + private void errIsindex() throws SAXException { + err("\u201Cisindex\u201D seen."); + } + + private void errFooSeenWhenFooOpen(@Local String name) throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("An \u201C" + name + "\u201D start tag seen but an element of the same type was already open."); + } + + private void errHeadingWhenHeadingOpen() throws SAXException { + err("Heading cannot be a child of another heading."); + } + + private void errFramesetStart() throws SAXException { + err("\u201Cframeset\u201D start tag seen."); + } + + private void errNoCellToClose() throws SAXException { + err("No cell to close."); + } + + private void errStartTagInTable(@Local String name) throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("Start tag \u201C" + name + + "\u201D seen in \u201Ctable\u201D."); + } + + private void errFormWhenFormOpen() throws SAXException { + err("Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag."); + } + + private void errTableSeenWhileTableOpen() throws SAXException { + err("Start tag for \u201Ctable\u201D seen but the previous \u201Ctable\u201D is still open."); + } + + private void errStartTagInTableBody(@Local String name) throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("\u201C" + name + "\u201D start tag in table body."); + } + + private void errEndTagSeenWithoutDoctype() throws SAXException { + err("End tag seen without seeing a doctype first. Expected \u201C\u201D."); + } + + private void errEndTagAfterBody() throws SAXException { + err("Saw an end tag after \u201Cbody\u201D had been closed."); + } + + private void errEndTagSeenWithSelectOpen(@Local String name) throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("\u201C" + name + + "\u201D end tag with \u201Cselect\u201D open."); + } + + private void errGarbageInColgroup() throws SAXException { + err("Garbage in \u201Ccolgroup\u201D fragment."); + } + + private void errEndTagBr() throws SAXException { + err("End tag \u201Cbr\u201D."); + } + + private void errNoElementToCloseButEndTagSeen(@Local String name) + throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("No \u201C" + name + "\u201D element in scope but a \u201C" + + name + "\u201D end tag seen."); + } + + private void errHtmlStartTagInForeignContext(@Local String name) + throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("HTML start tag \u201C" + name + + "\u201D in a foreign namespace context."); + } + + private void errTableClosedWhileCaptionOpen() throws SAXException { + err("\u201Ctable\u201D closed but \u201Ccaption\u201D was still open."); + } + + private void errNoTableRowToClose() throws SAXException { + err("No table row to close."); + } + + private void errNonSpaceInTable() throws SAXException { + err("Misplaced non-space characters insided a table."); + } + + private void errUnclosedChildrenInRuby() throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("Unclosed children in \u201Cruby\u201D."); + } + + private void errStartTagSeenWithoutRuby(@Local String name) throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("Start tag \u201C" + + name + + "\u201D seen without a \u201Cruby\u201D element being open."); + } + + private void errSelfClosing() throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("Self-closing syntax (\u201C/>\u201D) used on a non-void HTML element. Ignoring the slash and treating as a start tag."); + } + + private void errNoCheckUnclosedElementsOnStack() throws SAXException { + errNoCheck("Unclosed elements on stack."); + } + + private void errEndTagDidNotMatchCurrentOpenElement(@Local String name, + @Local String currOpenName) throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("End tag \u201C" + + name + + "\u201D did not match the name of the current open element (\u201C" + + currOpenName + "\u201D)."); + } + + private void errEndTagViolatesNestingRules(@Local String name) throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("End tag \u201C" + name + "\u201D violates nesting rules."); + } + + private void errEofWithUnclosedElements() throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("End of file seen and there were open elements."); + // just report all remaining unclosed elements + errListUnclosedStartTags(0); + } + + /** + * Reports arriving at/near end of document with unclosed elements remaining. + * + * @param message + * the message + * @throws SAXException + */ + private void errEndWithUnclosedElements(@Local String name) throws SAXException { + if (errorHandler == null) { + return; + } + errNoCheck("End tag for \u201C" + + name + + "\u201D seen, but there were unclosed elements."); + // just report all remaining unclosed elements + errListUnclosedStartTags(0); + } } diff --git a/parser/html/nsHtml5AtomList.h b/parser/html/nsHtml5AtomList.h index f3baca0f278..873bbaa7419 100644 --- a/parser/html/nsHtml5AtomList.h +++ b/parser/html/nsHtml5AtomList.h @@ -31,6 +31,7 @@ HTML5_ATOM(noframes, "noframes") HTML5_ATOM(noscript, "noscript") HTML5_ATOM(plaintext, "plaintext") HTML5_ATOM(script, "script") +HTML5_ATOM(table, "table") HTML5_ATOM(caption, "caption") HTML5_ATOM(p, "p") HTML5_ATOM(address, "address") @@ -42,7 +43,6 @@ HTML5_ATOM(option, "option") HTML5_ATOM(ruby, "ruby") HTML5_ATOM(select, "select") HTML5_ATOM(optgroup, "optgroup") -HTML5_ATOM(table, "table") HTML5_ATOM(frameset, "frameset") HTML5_ATOM(button, "button") HTML5_ATOM(ul, "ul") diff --git a/parser/html/nsHtml5Highlighter.cpp b/parser/html/nsHtml5Highlighter.cpp index d62b950dbe8..18df802e403 100644 --- a/parser/html/nsHtml5Highlighter.cpp +++ b/parser/html/nsHtml5Highlighter.cpp @@ -75,12 +75,16 @@ nsHtml5Highlighter::nsHtml5Highlighter(nsAHtml5TreeOpSink* aOpSink) , mCStart(PR_INT32_MAX) , mPos(0) , mInlinesOpen(0) + , mInCharacters(false) , mBuffer(nsnull) , mSyntaxHighlight(Preferences::GetBool("view_source.syntax_highlight", true)) , mWrapLongLines(Preferences::GetBool("view_source.wrap_long_lines", true)) , mTabSize(Preferences::GetInt("view_source.tab_size", 4)) , mOpSink(aOpSink) + , mCurrentRun(nsnull) + , mAmpersand(nsnull) + , mSlash(nsnull) , mHandles(new nsIContent*[NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH]) , mHandlesUsed(0) { @@ -149,6 +153,8 @@ nsHtml5Highlighter::Start() preAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, preId); Push(nsGkAtoms::pre, preAttrs); + StartCharacters(); + mOpQueue.AppendElement()->Init(eTreeOpStartLayout); } @@ -163,13 +169,15 @@ nsHtml5Highlighter::Transition(PRInt32 aState, bool aReconsume, PRInt32 aPos) case NS_HTML5TOKENIZER_DATA: // We can transition on < and on &. Either way, we don't yet know the // role of the token, so open a span without class. - StartSpan(); if (aState == NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE) { + StartSpan(); // Start another span for highlighting the ampersand StartSpan(); mAmpersand = CurrentNode(); } else { - mMarkupDecl = CurrentNode(); + EndCharacters(); + StartSpan(); + mCurrentRun = CurrentNode(); } break; case NS_HTML5TOKENIZER_TAG_OPEN: @@ -178,7 +186,7 @@ nsHtml5Highlighter::Transition(PRInt32 aState, bool aReconsume, PRInt32 aPos) StartSpan(sStartTag); break; case NS_HTML5TOKENIZER_DATA: - EndInline(); // DATA + FinishTag(); // DATA break; } break; @@ -387,6 +395,7 @@ nsHtml5Highlighter::Transition(PRInt32 aState, bool aReconsume, PRInt32 aPos) break; } EndInline(); + StartCharacters(); break; case NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME: switch (aState) { @@ -420,6 +429,7 @@ nsHtml5Highlighter::Transition(PRInt32 aState, bool aReconsume, PRInt32 aPos) case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED: case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_DASH: if (aState == NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN) { + EndCharacters(); StartSpan(); } break; @@ -537,6 +547,25 @@ nsHtml5Highlighter::EndInline() --mInlinesOpen; } +void +nsHtml5Highlighter::StartCharacters() +{ + NS_PRECONDITION(!mInCharacters, "Already in characters!"); + FlushChars(); + Push(nsGkAtoms::span, nsnull); + mCurrentRun = CurrentNode(); + mInCharacters = true; +} + +void +nsHtml5Highlighter::EndCharacters() +{ + NS_PRECONDITION(mInCharacters, "Not in characters!"); + FlushChars(); + Pop(); + mInCharacters = false; +} + void nsHtml5Highlighter::StartA() { @@ -555,6 +584,7 @@ nsHtml5Highlighter::FinishTag() FlushCurrent(); // > EndInline(); // DATA NS_ASSERTION(!mInlinesOpen, "mInlinesOpen got out of sync!"); + StartCharacters(); } void @@ -703,12 +733,33 @@ nsHtml5Highlighter::AddErrorToCurrentNode(const char* aMsgId) } void -nsHtml5Highlighter::AddErrorToCurrentMarkupDecl(const char* aMsgId) +nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId) { - NS_PRECONDITION(mMarkupDecl, "Adding error to markup decl without one!"); + NS_PRECONDITION(mCurrentRun, "Adding error to run without one!"); nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); NS_ASSERTION(treeOp, "Tree op allocation failed."); - treeOp->Init(mMarkupDecl, aMsgId); + treeOp->Init(mCurrentRun, aMsgId); +} + +void +nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId, + nsIAtom* aName) +{ + NS_PRECONDITION(mCurrentRun, "Adding error to run without one!"); + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(mCurrentRun, aMsgId); +} + +void +nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId, + nsIAtom* aName, + nsIAtom* aOther) +{ + NS_PRECONDITION(mCurrentRun, "Adding error to run without one!"); + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(mCurrentRun, aMsgId); } void diff --git a/parser/html/nsHtml5Highlighter.h b/parser/html/nsHtml5Highlighter.h index 811a50402a2..e5d1095d1b0 100644 --- a/parser/html/nsHtml5Highlighter.h +++ b/parser/html/nsHtml5Highlighter.h @@ -123,24 +123,56 @@ class nsHtml5Highlighter /** * Adds an error annotation to the node that's currently on top of * mStack. + * + * @param aMsgId the id of the message in the property file */ void AddErrorToCurrentNode(const char* aMsgId); /** * Adds an error annotation to the node that corresponds to the most - * recently opened markup declaration/tag span. + * recently opened markup declaration/tag span, character reference or + * run of text. + * + * @param aMsgId the id of the message in the property file */ - void AddErrorToCurrentMarkupDecl(const char* aMsgId); + void AddErrorToCurrentRun(const char* aMsgId); + + /** + * Adds an error annotation to the node that corresponds to the most + * recently opened markup declaration/tag span, character reference or + * run of text with one atom to use when formatting the message. + * + * @param aMsgId the id of the message in the property file + * @param aName the atom + */ + void AddErrorToCurrentRun(const char* aMsgId, nsIAtom* aName); + + /** + * Adds an error annotation to the node that corresponds to the most + * recently opened markup declaration/tag span, character reference or + * run of text with two atoms to use when formatting the message. + * + * @param aMsgId the id of the message in the property file + * @param aName the first atom + * @param aOther the second atom + */ + void AddErrorToCurrentRun(const char* aMsgId, + nsIAtom* aName, + nsIAtom* aOther); /** * Adds an error annotation to the node that corresponds to the most * recent potentially character reference-starting ampersand. + * + * @param aMsgId the id of the message in the property file */ void AddErrorToCurrentAmpersand(const char* aMsgId); /** * Adds an error annotation to the node that corresponds to the most * recent potentially self-closing slash. + * + * @param aMsgId the id of the message in the property file */ void AddErrorToCurrentSlash(const char* aMsgId); @@ -164,6 +196,16 @@ class nsHtml5Highlighter */ void EndInline(); + /** + * Starts a wrapper around a run of characters. + */ + void StartCharacters(); + + /** + * Ends a wrapper around a run of characters. + */ + void EndCharacters(); + /** * Starts an . */ @@ -270,10 +312,17 @@ class nsHtml5Highlighter PRInt32 mPos; /** - * The number of inline elements open inside the
.
+     * The number of inline elements open inside the 
 excluding the
+     * span potentially wrapping a run of characters.
      */
     PRInt32 mInlinesOpen;
 
+    /**
+     * Whether there's a span wrapping a run of characters (excluding CDATA
+     * section) open.
+     */
+    bool mInCharacters;
+
     /**
      * The current buffer being tokenized.
      */
@@ -310,9 +359,9 @@ class nsHtml5Highlighter
     nsAHtml5TreeOpSink* mOpSink;
 
     /**
-     * The most recently opened markup declaration/tag.
+     * The most recently opened markup declaration/tag or run of characters.
      */
-    nsIContent** mMarkupDecl;
+    nsIContent** mCurrentRun;
 
     /**
      * The most recent ampersand in a place where character references were
diff --git a/parser/html/nsHtml5StreamParser.cpp b/parser/html/nsHtml5StreamParser.cpp
index 5fbcb0311b5..f013aa84aab 100644
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -206,7 +206,10 @@ nsHtml5StreamParser::nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
   mTokenizer->setEncodingDeclarationHandler(this);
 
   if (aMode == VIEW_SOURCE_HTML || aMode == VIEW_SOURCE_XML) {
-    mTokenizer->EnableViewSource(new nsHtml5Highlighter(mExecutor->GetStage()));
+    nsHtml5Highlighter* highlighter =
+      new nsHtml5Highlighter(mExecutor->GetStage());
+    mTokenizer->EnableViewSource(highlighter); // takes ownership
+    mTreeBuilder->EnableViewSource(highlighter); // doesn't own
   }
 
   // Chardet instantiation adapted from nsDOMFile.
diff --git a/parser/html/nsHtml5Tokenizer.cpp b/parser/html/nsHtml5Tokenizer.cpp
index 52672d4d13e..d11ecea8689 100644
--- a/parser/html/nsHtml5Tokenizer.cpp
+++ b/parser/html/nsHtml5Tokenizer.cpp
@@ -1537,7 +1537,11 @@ nsHtml5Tokenizer::stateLoop(PRInt32 state, PRUnichar c, PRInt32 pos, PRUnichar*
                 NS_HTML5_CONTINUE(stateloop);
               }
             }
+            if ((returnState & NS_HTML5TOKENIZER_DATA_AND_RCDATA_MASK)) {
 
+            } else {
+
+            }
           }
 
           const PRUnichar* val = nsHtml5NamedCharacters::VALUES[candidate];
@@ -4419,7 +4423,11 @@ nsHtml5Tokenizer::stateLoopReportTransitions(PRInt32 state, PRUnichar c, PRInt32
                 NS_HTML5_CONTINUE(stateloop);
               }
             }
-
+            if ((returnState & NS_HTML5TOKENIZER_DATA_AND_RCDATA_MASK)) {
+              errUnescapedAmpersandInterpretedAsCharacterReference();
+            } else {
+              errNotSemicolonTerminated();
+            }
           }
           mViewSource->CompletedNamedCharacterReference();
           const PRUnichar* val = nsHtml5NamedCharacters::VALUES[candidate];
@@ -6509,7 +6517,11 @@ nsHtml5Tokenizer::eof()
                 NS_HTML5_CONTINUE(eofloop);
               }
             }
-
+            if ((returnState & NS_HTML5TOKENIZER_DATA_AND_RCDATA_MASK)) {
+              errUnescapedAmpersandInterpretedAsCharacterReference();
+            } else {
+              errNotSemicolonTerminated();
+            }
           }
           const PRUnichar* val = nsHtml5NamedCharacters::VALUES[candidate];
           if (!val[1]) {
@@ -6538,6 +6550,8 @@ nsHtml5Tokenizer::eof()
           emitOrAppendStrBuf(returnState);
           state = returnState;
           continue;
+        } else {
+          errCharRefLacksSemicolon();
         }
         handleNcrValue(returnState);
         state = returnState;
diff --git a/parser/html/nsHtml5TokenizerCppSupplement.h b/parser/html/nsHtml5TokenizerCppSupplement.h
index 8956527b083..e62481b3856 100644
--- a/parser/html/nsHtml5TokenizerCppSupplement.h
+++ b/parser/html/nsHtml5TokenizerCppSupplement.h
@@ -136,7 +136,7 @@ nsHtml5Tokenizer::maybeErrAttributesOnEndTag(nsHtml5HtmlAttributes* attrs)
      * When an end tag token is emitted with attributes, that is a parse
      * error.
      */
-    mViewSource->AddErrorToCurrentMarkupDecl("maybeErrAttributesOnEndTag");
+    mViewSource->AddErrorToCurrentRun("maybeErrAttributesOnEndTag");
   }
 }
 
@@ -151,7 +151,7 @@ nsHtml5Tokenizer::maybeErrSlashInEndTag(bool selfClosing)
 PRUnichar
 nsHtml5Tokenizer::errNcrNonCharacter(PRUnichar ch)
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errNcrNonCharacter");
   }
   return ch;
@@ -160,7 +160,7 @@ nsHtml5Tokenizer::errNcrNonCharacter(PRUnichar ch)
 void
 nsHtml5Tokenizer::errAstralNonCharacter(int ch)
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errAstralNonCharacter");
   }
 }
@@ -168,7 +168,7 @@ nsHtml5Tokenizer::errAstralNonCharacter(int ch)
 PRUnichar
 nsHtml5Tokenizer::errNcrControlChar(PRUnichar ch)
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errNcrControlChar");
   }
   return ch;
@@ -189,13 +189,15 @@ nsHtml5Tokenizer::errLtSlashGt()
 void
 nsHtml5Tokenizer::errCharRefLacksSemicolon()
 {
-  mViewSource->AddErrorToCurrentNode("errCharRefLacksSemicolon");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentNode("errCharRefLacksSemicolon");
+  }
 }
 
 void
 nsHtml5Tokenizer::errNoDigitsInNCR()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errNoDigitsInNCR");
   }
 }
@@ -221,7 +223,7 @@ nsHtml5Tokenizer::errNamelessDoctype()
 void
 nsHtml5Tokenizer::errConsecutiveHyphens()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errConsecutiveHyphens");
   }
 }
@@ -235,7 +237,7 @@ nsHtml5Tokenizer::errPrematureEndOfComment()
 void
 nsHtml5Tokenizer::errBogusComment()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errBogusComment");
   }
 }
@@ -279,19 +281,23 @@ nsHtml5Tokenizer::errProcessingInstruction()
 void
 nsHtml5Tokenizer::errUnescapedAmpersandInterpretedAsCharacterReference()
 {
-  mViewSource->AddErrorToCurrentAmpersand("errUnescapedAmpersandInterpretedAsCharacterReference");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentAmpersand("errUnescapedAmpersandInterpretedAsCharacterReference");
+  }
 }
 
 void
 nsHtml5Tokenizer::errNotSemicolonTerminated()
 {
-  mViewSource->AddErrorToCurrentNode("errNotSemicolonTerminated");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentNode("errNotSemicolonTerminated");
+  }
 }
 
 void
 nsHtml5Tokenizer::errNoNamedCharacterMatch()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentAmpersand("errNoNamedCharacterMatch");
   }
 }
@@ -311,7 +317,7 @@ nsHtml5Tokenizer::errExpectedPublicId()
 void
 nsHtml5Tokenizer::errBogusDoctype()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errBogusDoctype");
   }
 }
@@ -319,7 +325,7 @@ nsHtml5Tokenizer::errBogusDoctype()
 void
 nsHtml5Tokenizer::errNcrSurrogate()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errNcrSurrogate");
   }
 }
@@ -327,7 +333,7 @@ nsHtml5Tokenizer::errNcrSurrogate()
 void
 nsHtml5Tokenizer::errNcrCr()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errNcrCr");
   }
 }
@@ -335,7 +341,7 @@ nsHtml5Tokenizer::errNcrCr()
 void
 nsHtml5Tokenizer::errNcrInC1Range()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errNcrInC1Range");
   }
 }
@@ -343,79 +349,79 @@ nsHtml5Tokenizer::errNcrInC1Range()
 void
 nsHtml5Tokenizer::errEofInPublicId()
 {
-  if (mViewSource) {
-    mViewSource->AddErrorToCurrentMarkupDecl("errEofInPublicId");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEofInPublicId");
   }
 }
 
 void
 nsHtml5Tokenizer::errEofInComment()
 {
-  if (mViewSource) {
-    mViewSource->AddErrorToCurrentMarkupDecl("errEofInComment");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEofInComment");
   }
 }
 
 void
 nsHtml5Tokenizer::errEofInDoctype()
 {
-  if (mViewSource) {
-    mViewSource->AddErrorToCurrentMarkupDecl("errEofInDoctype");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEofInDoctype");
   }
 }
 
 void
 nsHtml5Tokenizer::errEofInAttributeValue()
 {
-  if (mViewSource) {
-    mViewSource->AddErrorToCurrentMarkupDecl("errEofInAttributeValue");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEofInAttributeValue");
   }
 }
 
 void
 nsHtml5Tokenizer::errEofInAttributeName()
 {
-  if (mViewSource) {
-    mViewSource->AddErrorToCurrentMarkupDecl("errEofInAttributeName");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEofInAttributeName");
   }
 }
 
 void
 nsHtml5Tokenizer::errEofWithoutGt()
 {
-  if (mViewSource) {
-    mViewSource->AddErrorToCurrentMarkupDecl("errEofWithoutGt");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEofWithoutGt");
   }
 }
 
 void
 nsHtml5Tokenizer::errEofInTagName()
 {
-  if (mViewSource) {
-    mViewSource->AddErrorToCurrentMarkupDecl("errEofInTagName");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEofInTagName");
   }
 }
 
 void
 nsHtml5Tokenizer::errEofInEndTag()
 {
-  if (mViewSource) {
-    mViewSource->AddErrorToCurrentMarkupDecl("errEofInEndTag");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEofInEndTag");
   }
 }
 
 void
 nsHtml5Tokenizer::errEofAfterLt()
 {
-  if (mViewSource) {
-    mViewSource->AddErrorToCurrentMarkupDecl("errEofAfterLt");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEofAfterLt");
   }
 }
 
 void
 nsHtml5Tokenizer::errNcrOutOfRange()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errNcrOutOfRange");
   }
 }
@@ -423,7 +429,7 @@ nsHtml5Tokenizer::errNcrOutOfRange()
 void
 nsHtml5Tokenizer::errNcrUnassigned()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errNcrUnassigned");
   }
 }
@@ -431,7 +437,7 @@ nsHtml5Tokenizer::errNcrUnassigned()
 void
 nsHtml5Tokenizer::errDuplicateAttribute()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errDuplicateAttribute");
   }
 }
@@ -439,8 +445,8 @@ nsHtml5Tokenizer::errDuplicateAttribute()
 void
 nsHtml5Tokenizer::errEofInSystemId()
 {
-  if (mViewSource) {
-    mViewSource->AddErrorToCurrentMarkupDecl("errEofInSystemId");
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEofInSystemId");
   }
 }
 
@@ -465,7 +471,7 @@ nsHtml5Tokenizer::errHyphenHyphenBang()
 void
 nsHtml5Tokenizer::errNcrControlChar()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errNcrControlChar");
   }
 }
@@ -473,7 +479,7 @@ nsHtml5Tokenizer::errNcrControlChar()
 void
 nsHtml5Tokenizer::errNcrZero()
 {
-  if (mViewSource) {
+  if (NS_UNLIKELY(mViewSource)) {
     mViewSource->AddErrorToCurrentNode("errNcrZero");
   }
 }
diff --git a/parser/html/nsHtml5TreeBuilder.cpp b/parser/html/nsHtml5TreeBuilder.cpp
index 19b8bf4900d..08cf9269665 100644
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -51,6 +51,7 @@
 #include "nsHtml5TreeOpExecutor.h"
 #include "nsHtml5StreamParser.h"
 #include "nsAHtml5TreeBuilderState.h"
+#include "nsHtml5Highlighter.h"
 
 #include "nsHtml5Tokenizer.h"
 #include "nsHtml5MetaScanner.h"
@@ -124,10 +125,10 @@ nsHtml5TreeBuilder::doctype(nsIAtom* name, nsString* publicIdentifier, nsString*
         appendDoctypeToDocument(!name ? nsHtml5Atoms::emptystring : name, !publicIdentifier ? emptyString : publicIdentifier, !systemIdentifier ? emptyString : systemIdentifier);
         nsHtml5Portability::releaseString(emptyString);
         if (isQuirky(name, publicIdentifier, systemIdentifier, forceQuirks)) {
-
+          errQuirkyDoctype();
           documentModeInternal(QUIRKS_MODE, publicIdentifier, systemIdentifier, false);
         } else if (isAlmostStandards(publicIdentifier, systemIdentifier)) {
-
+          errAlmostStandardsDoctype();
           documentModeInternal(ALMOST_STANDARDS_MODE, publicIdentifier, systemIdentifier, false);
         } else {
           documentModeInternal(STANDARDS_MODE, publicIdentifier, systemIdentifier, false);
@@ -140,7 +141,7 @@ nsHtml5TreeBuilder::doctype(nsIAtom* name, nsString* publicIdentifier, nsString*
       }
     }
   }
-
+  errStrayDoctype();
   return;
 }
 
@@ -306,7 +307,7 @@ nsHtml5TreeBuilder::characters(const PRUnichar* buf, PRInt32 start, PRInt32 leng
                   accumulateCharacters(buf, start, i - start);
                   start = i;
                 }
-
+                errNonSpaceInNoscriptInHead();
                 flushCharacters();
                 pop();
                 mode = NS_HTML5TREE_BUILDER_IN_HEAD;
@@ -356,7 +357,7 @@ nsHtml5TreeBuilder::characters(const PRUnichar* buf, PRInt32 start, PRInt32 leng
                   start = i;
                 }
                 if (!currentPtr) {
-
+                  errNonSpaceInColgroupInFragment();
                   start = i + 1;
                   continue;
                 }
@@ -371,7 +372,7 @@ nsHtml5TreeBuilder::characters(const PRUnichar* buf, PRInt32 start, PRInt32 leng
                 NS_HTML5_BREAK(charactersloop);
               }
               case NS_HTML5TREE_BUILDER_AFTER_BODY: {
-
+                errNonSpaceAfterBody();
 
                 mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
                 i--;
@@ -382,7 +383,7 @@ nsHtml5TreeBuilder::characters(const PRUnichar* buf, PRInt32 start, PRInt32 leng
                   accumulateCharacters(buf, start, i - start);
                   start = i;
                 }
-
+                errNonSpaceInFrameset();
                 start = i + 1;
                 continue;
               }
@@ -391,18 +392,18 @@ nsHtml5TreeBuilder::characters(const PRUnichar* buf, PRInt32 start, PRInt32 leng
                   accumulateCharacters(buf, start, i - start);
                   start = i;
                 }
-
+                errNonSpaceAfterFrameset();
                 start = i + 1;
                 continue;
               }
               case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY: {
-
+                errNonSpaceInTrailer();
                 mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
                 i--;
                 continue;
               }
               case NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET: {
-
+                errNonSpaceInTrailer();
                 mode = NS_HTML5TREE_BUILDER_IN_FRAMESET;
                 i--;
                 continue;
@@ -444,7 +445,6 @@ nsHtml5TreeBuilder::eof()
   flushCharacters();
   for (; ; ) {
     if (isInForeign()) {
-
       NS_HTML5_BREAK(eofloop);
     }
     switch(mode) {
@@ -464,7 +464,6 @@ nsHtml5TreeBuilder::eof()
         continue;
       }
       case NS_HTML5TREE_BUILDER_IN_HEAD: {
-
         while (currentPtr > 0) {
           popOnEof();
         }
@@ -472,7 +471,6 @@ nsHtml5TreeBuilder::eof()
         continue;
       }
       case NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT: {
-
         while (currentPtr > 1) {
           popOnEof();
         }
@@ -501,7 +499,6 @@ nsHtml5TreeBuilder::eof()
         NS_HTML5_BREAK(eofloop);
       }
       case NS_HTML5TREE_BUILDER_TEXT: {
-
         if (originalMode == NS_HTML5TREE_BUILDER_AFTER_HEAD) {
           popOnEof();
         }
@@ -515,7 +512,6 @@ nsHtml5TreeBuilder::eof()
       case NS_HTML5TREE_BUILDER_IN_SELECT:
       case NS_HTML5TREE_BUILDER_IN_SELECT_IN_TABLE:
       case NS_HTML5TREE_BUILDER_IN_FRAMESET: {
-
         NS_HTML5_BREAK(eofloop);
       }
       case NS_HTML5TREE_BUILDER_AFTER_BODY:
@@ -593,7 +589,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
           case NS_HTML5TREE_BUILDER_P:
           case NS_HTML5TREE_BUILDER_PRE_OR_LISTING:
           case NS_HTML5TREE_BUILDER_TABLE: {
-
+            errHtmlStartTagInForeignContext(name);
             while (!isSpecialParentInForeign(stack[currentPtr])) {
               pop();
             }
@@ -601,7 +597,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
           }
           case NS_HTML5TREE_BUILDER_FONT: {
             if (attributes->contains(nsHtml5AttributeName::ATTR_COLOR) || attributes->contains(nsHtml5AttributeName::ATTR_FACE) || attributes->contains(nsHtml5AttributeName::ATTR_SIZE)) {
-
+              errHtmlStartTagInForeignContext(name);
               while (!isSpecialParentInForeign(stack[currentPtr])) {
                 pop();
               }
@@ -645,7 +641,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_TD_OR_TH: {
-
+            errStartTagInTableBody(name);
             clearStackBackTo(findLastInTableScopeOrRootTbodyTheadTfoot());
             appendToCurrentNodeAndPushElement(nsHtml5ElementName::ELT_TR, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
             mode = NS_HTML5TREE_BUILDER_IN_ROW;
@@ -657,7 +653,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: {
             eltPos = findLastInTableScopeOrRootTbodyTheadTfoot();
             if (!eltPos) {
-
+              errStrayStartTag(name);
               NS_HTML5_BREAK(starttagloop);
             } else {
               clearStackBackTo(eltPos);
@@ -688,7 +684,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR);
             if (!eltPos) {
 
-
+              errNoTableRowToClose();
               NS_HTML5_BREAK(starttagloop);
             }
             clearStackBackTo(eltPos);
@@ -739,14 +735,16 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
               NS_HTML5_CONTINUE(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_TABLE: {
-
+              errTableSeenWhileTableOpen();
               eltPos = findLastInTableScope(name);
               if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
 
                 NS_HTML5_BREAK(starttagloop);
               }
               generateImpliedEndTags();
-
+              if (!!NS_UNLIKELY(mViewSource) && !isCurrent(nsHtml5Atoms::table)) {
+                errNoCheckUnclosedElementsOnStack();
+              }
               while (currentPtr >= eltPos) {
                 pop();
               }
@@ -780,17 +778,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             }
             case NS_HTML5TREE_BUILDER_FORM: {
               if (formPointer) {
-
+                errFormWhenFormOpen();
                 NS_HTML5_BREAK(starttagloop);
               } else {
-
+                errStartTagInTable(name);
                 appendVoidFormToCurrent(attributes);
                 attributes = nsnull;
                 NS_HTML5_BREAK(starttagloop);
               }
             }
             default: {
-
+              errStartTagInTable(name);
               NS_HTML5_BREAK(intableloop);
             }
           }
@@ -805,13 +803,15 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT:
           case NS_HTML5TREE_BUILDER_TR:
           case NS_HTML5TREE_BUILDER_TD_OR_TH: {
-
+            errStrayStartTag(name);
             eltPos = findLastInTableScope(nsHtml5Atoms::caption);
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
               NS_HTML5_BREAK(starttagloop);
             }
             generateImpliedEndTags();
-
+            if (!!NS_UNLIKELY(mViewSource) && currentPtr != eltPos) {
+              errNoCheckUnclosedElementsOnStack();
+            }
             while (currentPtr >= eltPos) {
               pop();
             }
@@ -833,7 +833,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
           case NS_HTML5TREE_BUILDER_TD_OR_TH: {
             eltPos = findLastInTableScopeTdTh();
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
-
+              errNoCellToClose();
               NS_HTML5_BREAK(starttagloop);
             } else {
               closeTheCell(eltPos);
@@ -850,10 +850,10 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             if (mode == NS_HTML5TREE_BUILDER_FRAMESET_OK) {
               if (!currentPtr || stack[1]->getGroup() != NS_HTML5TREE_BUILDER_BODY) {
 
-
+                errStrayStartTag(name);
                 NS_HTML5_BREAK(starttagloop);
               } else {
-
+                errFramesetStart();
                 detachFromParent(stack[1]->node);
                 while (currentPtr > 0) {
                   pop();
@@ -864,7 +864,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
                 NS_HTML5_BREAK(starttagloop);
               }
             } else {
-
+              errStrayStartTag(name);
               NS_HTML5_BREAK(starttagloop);
             }
           }
@@ -898,7 +898,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
         for (; ; ) {
           switch(group) {
             case NS_HTML5TREE_BUILDER_HTML: {
-
+              errStrayStartTag(name);
               if (!fragment) {
                 addAttributesToHtml(attributes);
                 attributes = nsnull;
@@ -917,10 +917,10 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             case NS_HTML5TREE_BUILDER_BODY: {
               if (!currentPtr || stack[1]->getGroup() != NS_HTML5TREE_BUILDER_BODY) {
 
-
+                errStrayStartTag(name);
                 NS_HTML5_BREAK(starttagloop);
               }
-
+              errFooSeenWhenFooOpen(name);
               framesetOk = false;
               if (mode == NS_HTML5TREE_BUILDER_FRAMESET_OK) {
                 mode = NS_HTML5TREE_BUILDER_IN_BODY;
@@ -942,7 +942,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             case NS_HTML5TREE_BUILDER_H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
               implicitlyCloseP();
               if (stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
-
+                errHeadingWhenHeadingOpen();
                 pop();
               }
               appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
@@ -964,7 +964,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             }
             case NS_HTML5TREE_BUILDER_FORM: {
               if (formPointer) {
-
+                errFormWhenFormOpen();
                 NS_HTML5_BREAK(starttagloop);
               } else {
                 implicitlyCloseP();
@@ -980,7 +980,9 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
                 nsHtml5StackNode* node = stack[eltPos];
                 if (node->getGroup() == group) {
                   generateImpliedEndTagsExceptFor(node->name);
-
+                  if (!!NS_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+                    errUnclosedElementsImplied(eltPos, name);
+                  }
                   while (currentPtr >= eltPos) {
                     pop();
                   }
@@ -1005,7 +1007,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             case NS_HTML5TREE_BUILDER_A: {
               PRInt32 activeAPos = findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(nsHtml5Atoms::a);
               if (activeAPos != -1) {
-
+                errFooSeenWhenFooOpen(name);
                 nsHtml5StackNode* activeA = listOfActiveFormattingElements[activeAPos];
                 activeA->retain();
                 adoptionAgencyEndTag(nsHtml5Atoms::a);
@@ -1032,7 +1034,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             case NS_HTML5TREE_BUILDER_NOBR: {
               reconstructTheActiveFormattingElements();
               if (NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK != findLastInScope(nsHtml5Atoms::nobr)) {
-
+                errFooSeenWhenFooOpen(name);
                 adoptionAgencyEndTag(nsHtml5Atoms::nobr);
                 reconstructTheActiveFormattingElements();
               }
@@ -1043,9 +1045,11 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             case NS_HTML5TREE_BUILDER_BUTTON: {
               eltPos = findLastInScope(name);
               if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
-
+                errFooSeenWhenFooOpen(name);
                 generateImpliedEndTags();
-
+                if (!!NS_UNLIKELY(mViewSource) && !isCurrent(name)) {
+                  errUnclosedElementsImplied(eltPos, name);
+                }
                 while (currentPtr >= eltPos) {
                   pop();
                 }
@@ -1102,7 +1106,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_IMAGE: {
-
+              errImage();
               elementName = nsHtml5ElementName::ELT_IMG;
               NS_HTML5_CONTINUE(starttagloop);
             }
@@ -1115,7 +1119,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_ISINDEX: {
-
+              errIsindex();
               if (formPointer) {
                 NS_HTML5_BREAK(starttagloop);
               }
@@ -1228,7 +1232,11 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
                 generateImpliedEndTags();
               }
               if (eltPos != currentPtr) {
-
+                if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+                  errStartTagSeenWithoutRuby(name);
+                } else {
+                  errUnclosedChildrenInRuby();
+                }
                 while (currentPtr > eltPos) {
                   pop();
                 }
@@ -1270,7 +1278,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             case NS_HTML5TREE_BUILDER_FRAME:
             case NS_HTML5TREE_BUILDER_FRAMESET:
             case NS_HTML5TREE_BUILDER_HEAD: {
-
+              errStrayStartTag(name);
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_OUTPUT_OR_LABEL: {
@@ -1293,7 +1301,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
         for (; ; ) {
           switch(group) {
             case NS_HTML5TREE_BUILDER_HTML: {
-
+              errStrayStartTag(name);
               if (!fragment) {
                 addAttributesToHtml(attributes);
                 attributes = nsnull;
@@ -1350,7 +1358,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_HEAD: {
-
+              errFooSeenWhenFooOpen(name);
               NS_HTML5_BREAK(starttagloop);
             }
             default: {
@@ -1365,7 +1373,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
       case NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
-
+            errStrayStartTag(name);
             if (!fragment) {
               addAttributesToHtml(attributes);
               attributes = nsnull;
@@ -1395,15 +1403,15 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_HEAD: {
-
+            errFooSeenWhenFooOpen(name);
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_NOSCRIPT: {
-
+            errFooSeenWhenFooOpen(name);
             NS_HTML5_BREAK(starttagloop);
           }
           default: {
-
+            errBadStartTagInHead(name);
             pop();
             mode = NS_HTML5TREE_BUILDER_IN_HEAD;
             continue;
@@ -1413,7 +1421,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
       case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
-
+            errStrayStartTag(name);
             if (!fragment) {
               addAttributesToHtml(attributes);
               attributes = nsnull;
@@ -1429,7 +1437,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
           default: {
             if (!currentPtr) {
 
-
+              errGarbageInColgroup();
               NS_HTML5_BREAK(starttagloop);
             }
             pop();
@@ -1445,7 +1453,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
           case NS_HTML5TREE_BUILDER_TR:
           case NS_HTML5TREE_BUILDER_TD_OR_TH:
           case NS_HTML5TREE_BUILDER_TABLE: {
-
+            errStartTagWithSelectOpen(name);
             eltPos = findLastInTableScope(nsHtml5Atoms::select);
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
 
@@ -1464,7 +1472,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
       case NS_HTML5TREE_BUILDER_IN_SELECT: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
-
+            errStrayStartTag(name);
             if (!fragment) {
               addAttributesToHtml(attributes);
               attributes = nsnull;
@@ -1491,11 +1499,11 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_SELECT: {
-
+            errStartSelectWhereEndSelectExpected();
             eltPos = findLastInTableScope(name);
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
 
-
+              errNoSelectInTableScope();
               NS_HTML5_BREAK(starttagloop);
             } else {
               while (currentPtr >= eltPos) {
@@ -1508,7 +1516,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
           case NS_HTML5TREE_BUILDER_INPUT:
           case NS_HTML5TREE_BUILDER_TEXTAREA:
           case NS_HTML5TREE_BUILDER_KEYGEN: {
-
+            errStartTagWithSelectOpen(name);
             eltPos = findLastInTableScope(nsHtml5Atoms::select);
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
 
@@ -1529,7 +1537,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           default: {
-
+            errStrayStartTag(name);
             NS_HTML5_BREAK(starttagloop);
           }
         }
@@ -1537,7 +1545,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
       case NS_HTML5TREE_BUILDER_AFTER_BODY: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
-
+            errStrayStartTag(name);
             if (!fragment) {
               addAttributesToHtml(attributes);
               attributes = nsnull;
@@ -1545,7 +1553,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           default: {
-
+            errStrayStartTag(name);
             mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
             continue;
           }
@@ -1571,7 +1579,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
       case NS_HTML5TREE_BUILDER_AFTER_FRAMESET: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
-
+            errStrayStartTag(name);
             if (!fragment) {
               addAttributesToHtml(attributes);
               attributes = nsnull;
@@ -1587,12 +1595,13 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           default: {
-
+            errStrayStartTag(name);
             NS_HTML5_BREAK(starttagloop);
           }
         }
       }
       case NS_HTML5TREE_BUILDER_INITIAL: {
+        errStartTagWithoutDoctype();
         documentModeInternal(QUIRKS_MODE, nsnull, nsnull, false);
         mode = NS_HTML5TREE_BUILDER_BEFORE_HTML;
         continue;
@@ -1619,7 +1628,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
       case NS_HTML5TREE_BUILDER_BEFORE_HEAD: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
-
+            errStrayStartTag(name);
             if (!fragment) {
               addAttributesToHtml(attributes);
               attributes = nsnull;
@@ -1642,7 +1651,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
       case NS_HTML5TREE_BUILDER_AFTER_HEAD: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
-
+            errStrayStartTag(name);
             if (!fragment) {
               addAttributesToHtml(attributes);
               attributes = nsnull;
@@ -1667,7 +1676,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_BASE: {
-
+            errFooBetweenHeadAndBody(name);
             pushHeadPointerOntoStack();
             appendVoidElementToCurrentMayFoster(elementName, attributes);
             selfClosing = false;
@@ -1676,7 +1685,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND: {
-
+            errFooBetweenHeadAndBody(name);
             pushHeadPointerOntoStack();
             appendVoidElementToCurrentMayFoster(elementName, attributes);
             selfClosing = false;
@@ -1685,7 +1694,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_META: {
-
+            errFooBetweenHeadAndBody(name);
             checkMetaCharset(attributes);
             pushHeadPointerOntoStack();
             appendVoidElementToCurrentMayFoster(elementName, attributes);
@@ -1695,7 +1704,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_SCRIPT: {
-
+            errFooBetweenHeadAndBody(name);
             pushHeadPointerOntoStack();
             appendToCurrentNodeAndPushElement(elementName, attributes);
             originalMode = mode;
@@ -1706,7 +1715,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
           }
           case NS_HTML5TREE_BUILDER_STYLE:
           case NS_HTML5TREE_BUILDER_NOFRAMES: {
-
+            errFooBetweenHeadAndBody(name);
             pushHeadPointerOntoStack();
             appendToCurrentNodeAndPushElement(elementName, attributes);
             originalMode = mode;
@@ -1716,7 +1725,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_TITLE: {
-
+            errFooBetweenHeadAndBody(name);
             pushHeadPointerOntoStack();
             appendToCurrentNodeAndPushElement(elementName, attributes);
             originalMode = mode;
@@ -1726,7 +1735,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           case NS_HTML5TREE_BUILDER_HEAD: {
-
+            errStrayStartTag(name);
             NS_HTML5_BREAK(starttagloop);
           }
           default: {
@@ -1739,7 +1748,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
       case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
-
+            errStrayStartTag(name);
             if (!fragment) {
               addAttributesToHtml(attributes);
               attributes = nsnull;
@@ -1747,7 +1756,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           default: {
-
+            errStrayStartTag(name);
 
             mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
             continue;
@@ -1757,7 +1766,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
       case NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET: {
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
-
+            errStrayStartTag(name);
             if (!fragment) {
               addAttributesToHtml(attributes);
               attributes = nsnull;
@@ -1773,7 +1782,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
             NS_HTML5_BREAK(starttagloop);
           }
           default: {
-
+            errStrayStartTag(name);
             NS_HTML5_BREAK(starttagloop);
           }
         }
@@ -1785,7 +1794,9 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
     }
   }
   starttagloop_end: ;
-
+  if (selfClosing) {
+    errSelfClosing();
+  }
   if (attributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
     delete attributes;
   }
@@ -2029,7 +2040,9 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
   nsIAtom* name = elementName->name;
   for (; ; ) {
     if (isInForeign()) {
-
+      if (stack[currentPtr]->name != name) {
+        errEndTagDidNotMatchCurrentOpenElement(name, stack[currentPtr]->popName);
+      }
       eltPos = currentPtr;
       for (; ; ) {
         if (stack[eltPos]->name == name) {
@@ -2050,7 +2063,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR);
             if (!eltPos) {
 
-
+              errNoTableRowToClose();
               NS_HTML5_BREAK(endtagloop);
             }
             clearStackBackTo(eltPos);
@@ -2062,7 +2075,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR);
             if (!eltPos) {
 
-
+              errNoTableRowToClose();
               NS_HTML5_BREAK(endtagloop);
             }
             clearStackBackTo(eltPos);
@@ -2072,13 +2085,13 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           }
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: {
             if (findLastInTableScope(name) == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR);
             if (!eltPos) {
 
-
+              errNoTableRowToClose();
               NS_HTML5_BREAK(endtagloop);
             }
             clearStackBackTo(eltPos);
@@ -2092,7 +2105,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_COLGROUP:
           case NS_HTML5TREE_BUILDER_HTML:
           case NS_HTML5TREE_BUILDER_TD_OR_TH: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
           default:
@@ -2104,7 +2117,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: {
             eltPos = findLastOrRoot(name);
             if (!eltPos) {
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             clearStackBackTo(eltPos);
@@ -2116,7 +2129,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             eltPos = findLastInTableScopeOrRootTbodyTheadTfoot();
             if (!eltPos) {
 
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             clearStackBackTo(eltPos);
@@ -2131,7 +2144,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_HTML:
           case NS_HTML5TREE_BUILDER_TD_OR_TH:
           case NS_HTML5TREE_BUILDER_TR: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
           default:
@@ -2144,7 +2157,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             eltPos = findLast(nsHtml5Atoms::table);
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
 
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             while (currentPtr >= eltPos) {
@@ -2161,11 +2174,12 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT:
           case NS_HTML5TREE_BUILDER_TD_OR_TH:
           case NS_HTML5TREE_BUILDER_TR: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
-          default:
-            ; // fall through
+          default: {
+            errStrayEndTag(name);
+          }
         }
       }
       case NS_HTML5TREE_BUILDER_IN_CAPTION: {
@@ -2176,7 +2190,9 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
               NS_HTML5_BREAK(endtagloop);
             }
             generateImpliedEndTags();
-
+            if (!!NS_UNLIKELY(mViewSource) && currentPtr != eltPos) {
+              errUnclosedElements(eltPos, name);
+            }
             while (currentPtr >= eltPos) {
               pop();
             }
@@ -2185,13 +2201,15 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_TABLE: {
-
+            errTableClosedWhileCaptionOpen();
             eltPos = findLastInTableScope(nsHtml5Atoms::caption);
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
               NS_HTML5_BREAK(endtagloop);
             }
             generateImpliedEndTags();
-
+            if (!!NS_UNLIKELY(mViewSource) && currentPtr != eltPos) {
+              errUnclosedElements(eltPos, name);
+            }
             while (currentPtr >= eltPos) {
               pop();
             }
@@ -2206,7 +2224,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT:
           case NS_HTML5TREE_BUILDER_TD_OR_TH:
           case NS_HTML5TREE_BUILDER_TR: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
           default:
@@ -2218,11 +2236,13 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_TD_OR_TH: {
             eltPos = findLastInTableScope(name);
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             generateImpliedEndTags();
-
+            if (!!NS_UNLIKELY(mViewSource) && !isCurrent(name)) {
+              errUnclosedElements(eltPos, name);
+            }
             while (currentPtr >= eltPos) {
               pop();
             }
@@ -2234,7 +2254,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT:
           case NS_HTML5TREE_BUILDER_TR: {
             if (findLastInTableScope(name) == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             closeTheCell(findLastInTableScopeTdTh());
@@ -2245,7 +2265,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_COL:
           case NS_HTML5TREE_BUILDER_COLGROUP:
           case NS_HTML5TREE_BUILDER_HTML: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
           default:
@@ -2258,21 +2278,60 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_BODY: {
             if (!isSecondOnStackBody()) {
 
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
 
-
+            if (NS_UNLIKELY(mViewSource)) {
+              for (PRInt32 i = 2; i <= currentPtr; i++) {
+                switch(stack[i]->getGroup()) {
+                  case NS_HTML5TREE_BUILDER_DD_OR_DT:
+                  case NS_HTML5TREE_BUILDER_LI:
+                  case NS_HTML5TREE_BUILDER_OPTGROUP:
+                  case NS_HTML5TREE_BUILDER_OPTION:
+                  case NS_HTML5TREE_BUILDER_P:
+                  case NS_HTML5TREE_BUILDER_RT_OR_RP:
+                  case NS_HTML5TREE_BUILDER_TD_OR_TH:
+                  case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: {
+                    break;
+                  }
+                  default: {
+                    errEndWithUnclosedElements(name);
+                    NS_HTML5_BREAK(uncloseloop1);
+                  }
+                }
+              }
+              uncloseloop1_end: ;
+            }
             mode = NS_HTML5TREE_BUILDER_AFTER_BODY;
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_HTML: {
             if (!isSecondOnStackBody()) {
 
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
-
+            if (NS_UNLIKELY(mViewSource)) {
+              for (PRInt32 i = 0; i <= currentPtr; i++) {
+                switch(stack[i]->getGroup()) {
+                  case NS_HTML5TREE_BUILDER_DD_OR_DT:
+                  case NS_HTML5TREE_BUILDER_LI:
+                  case NS_HTML5TREE_BUILDER_P:
+                  case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT:
+                  case NS_HTML5TREE_BUILDER_TD_OR_TH:
+                  case NS_HTML5TREE_BUILDER_BODY:
+                  case NS_HTML5TREE_BUILDER_HTML: {
+                    break;
+                  }
+                  default: {
+                    errEndWithUnclosedElements(name);
+                    NS_HTML5_BREAK(uncloseloop2);
+                  }
+                }
+              }
+              uncloseloop2_end: ;
+            }
             mode = NS_HTML5TREE_BUILDER_AFTER_BODY;
             continue;
           }
@@ -2283,9 +2342,13 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_BUTTON:
           case NS_HTML5TREE_BUILDER_ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_NAV_OR_SECTION_OR_SUMMARY: {
             eltPos = findLastInScope(name);
-            if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+            if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+              errStrayEndTag(name);
+            } else {
               generateImpliedEndTags();
-
+              if (!!NS_UNLIKELY(mViewSource) && !isCurrent(name)) {
+                errUnclosedElements(eltPos, name);
+              }
               while (currentPtr >= eltPos) {
                 pop();
               }
@@ -2294,26 +2357,28 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           }
           case NS_HTML5TREE_BUILDER_FORM: {
             if (!formPointer) {
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             formPointer = nsnull;
             eltPos = findLastInScope(name);
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             generateImpliedEndTags();
-
+            if (!!NS_UNLIKELY(mViewSource) && !isCurrent(name)) {
+              errUnclosedElements(eltPos, name);
+            }
             removeFromStack(eltPos);
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_P: {
             eltPos = findLastInButtonScope(nsHtml5Atoms::p);
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
-
+              errNoElementToCloseButEndTagSeen(nsHtml5Atoms::p);
               if (isInForeign()) {
-
+                errHtmlStartTagInForeignContext(name);
                 while (stack[currentPtr]->ns != kNameSpaceID_XHTML) {
                   pop();
                 }
@@ -2323,7 +2388,9 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             }
             generateImpliedEndTagsExceptFor(nsHtml5Atoms::p);
 
-
+            if (!!NS_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+              errUnclosedElements(eltPos, name);
+            }
             while (currentPtr >= eltPos) {
               pop();
             }
@@ -2331,9 +2398,13 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           }
           case NS_HTML5TREE_BUILDER_LI: {
             eltPos = findLastInListScope(name);
-            if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+            if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+              errNoElementToCloseButEndTagSeen(name);
+            } else {
               generateImpliedEndTagsExceptFor(name);
-
+              if (!!NS_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+                errUnclosedElements(eltPos, name);
+              }
               while (currentPtr >= eltPos) {
                 pop();
               }
@@ -2342,9 +2413,13 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           }
           case NS_HTML5TREE_BUILDER_DD_OR_DT: {
             eltPos = findLastInScope(name);
-            if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+            if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+              errNoElementToCloseButEndTagSeen(name);
+            } else {
               generateImpliedEndTagsExceptFor(name);
-
+              if (!!NS_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+                errUnclosedElements(eltPos, name);
+              }
               while (currentPtr >= eltPos) {
                 pop();
               }
@@ -2353,9 +2428,13 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           }
           case NS_HTML5TREE_BUILDER_H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
             eltPos = findLastInScopeHn();
-            if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+            if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+              errStrayEndTag(name);
+            } else {
               generateImpliedEndTags();
-
+              if (!!NS_UNLIKELY(mViewSource) && !isCurrent(name)) {
+                errUnclosedElements(eltPos, name);
+              }
               while (currentPtr >= eltPos) {
                 pop();
               }
@@ -2365,9 +2444,13 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_OBJECT:
           case NS_HTML5TREE_BUILDER_MARQUEE_OR_APPLET: {
             eltPos = findLastInScope(name);
-            if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+            if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
+              errStrayEndTag(name);
+            } else {
               generateImpliedEndTags();
-
+              if (!!NS_UNLIKELY(mViewSource) && !isCurrent(name)) {
+                errUnclosedElements(eltPos, name);
+              }
               while (currentPtr >= eltPos) {
                 pop();
               }
@@ -2376,9 +2459,9 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_BR: {
-
+            errEndTagBr();
             if (isInForeign()) {
-
+              errHtmlStartTagInForeignContext(name);
               while (stack[currentPtr]->ns != kNameSpaceID_XHTML) {
                 pop();
               }
@@ -2404,12 +2487,12 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_SELECT:
           case NS_HTML5TREE_BUILDER_TABLE:
           case NS_HTML5TREE_BUILDER_TEXTAREA: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_NOSCRIPT: {
             if (scriptingEnabled) {
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             } else {
             }
@@ -2432,13 +2515,15 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
               nsHtml5StackNode* node = stack[eltPos];
               if (node->name == name) {
                 generateImpliedEndTags();
-
+                if (!!NS_UNLIKELY(mViewSource) && !isCurrent(name)) {
+                  errUnclosedElements(eltPos, name);
+                }
                 while (currentPtr >= eltPos) {
                   pop();
                 }
                 NS_HTML5_BREAK(endtagloop);
               } else if (node->isSpecial()) {
-
+                errStrayEndTag(name);
                 NS_HTML5_BREAK(endtagloop);
               }
               eltPos--;
@@ -2451,7 +2536,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_COLGROUP: {
             if (!currentPtr) {
 
-
+              errGarbageInColgroup();
               NS_HTML5_BREAK(endtagloop);
             }
             pop();
@@ -2459,13 +2544,13 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_COL: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
           default: {
             if (!currentPtr) {
 
-
+              errGarbageInColgroup();
               NS_HTML5_BREAK(endtagloop);
             }
             pop();
@@ -2481,7 +2566,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT:
           case NS_HTML5TREE_BUILDER_TR:
           case NS_HTML5TREE_BUILDER_TD_OR_TH: {
-
+            errEndTagSeenWithSelectOpen(name);
             if (findLastInTableScope(name) != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
               eltPos = findLastInTableScope(nsHtml5Atoms::select);
               if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
@@ -2508,7 +2593,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
               pop();
               NS_HTML5_BREAK(endtagloop);
             } else {
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
           }
@@ -2518,6 +2603,8 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             }
             if (isCurrent(nsHtml5Atoms::optgroup)) {
               pop();
+            } else {
+              errStrayEndTag(name);
             }
             NS_HTML5_BREAK(endtagloop);
           }
@@ -2525,7 +2612,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             eltPos = findLastInTableScope(nsHtml5Atoms::select);
             if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
 
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             while (currentPtr >= eltPos) {
@@ -2535,7 +2622,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             NS_HTML5_BREAK(endtagloop);
           }
           default: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
@@ -2544,7 +2631,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
         switch(group) {
           case NS_HTML5TREE_BUILDER_HTML: {
             if (fragment) {
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             } else {
               mode = NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY;
@@ -2552,7 +2639,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             }
           }
           default: {
-
+            errEndTagAfterBody();
             mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
             continue;
           }
@@ -2563,7 +2650,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
           case NS_HTML5TREE_BUILDER_FRAMESET: {
             if (!currentPtr) {
 
-
+              errStrayEndTag(name);
               NS_HTML5_BREAK(endtagloop);
             }
             pop();
@@ -2573,7 +2660,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             NS_HTML5_BREAK(endtagloop);
           }
           default: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
@@ -2585,12 +2672,13 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             NS_HTML5_BREAK(endtagloop);
           }
           default: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
       }
       case NS_HTML5TREE_BUILDER_INITIAL: {
+        errEndTagSeenWithoutDoctype();
         documentModeInternal(QUIRKS_MODE, nsnull, nsnull, false);
         mode = NS_HTML5TREE_BUILDER_BEFORE_HTML;
         continue;
@@ -2606,7 +2694,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             continue;
           }
           default: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
@@ -2622,7 +2710,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             continue;
           }
           default: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
@@ -2642,7 +2730,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             continue;
           }
           default: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
@@ -2655,13 +2743,13 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             NS_HTML5_BREAK(endtagloop);
           }
           case NS_HTML5TREE_BUILDER_BR: {
-
+            errStrayEndTag(name);
             pop();
             mode = NS_HTML5TREE_BUILDER_IN_HEAD;
             continue;
           }
           default: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
@@ -2676,18 +2764,18 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
             continue;
           }
           default: {
-
+            errStrayEndTag(name);
             NS_HTML5_BREAK(endtagloop);
           }
         }
       }
       case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY: {
-
+        errStrayEndTag(name);
         mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY;
         continue;
       }
       case NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET: {
-
+        errStrayEndTag(name);
         mode = NS_HTML5TREE_BUILDER_IN_FRAMESET;
         continue;
       }
@@ -2907,7 +2995,9 @@ void
 nsHtml5TreeBuilder::closeTheCell(PRInt32 eltPos)
 {
   generateImpliedEndTags();
-
+  if (!!NS_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+    errUnclosedElementsCell(eltPos);
+  }
   while (currentPtr >= eltPos) {
     pop();
   }
@@ -3012,7 +3102,9 @@ nsHtml5TreeBuilder::implicitlyCloseP()
     return;
   }
   generateImpliedEndTagsExceptFor(nsHtml5Atoms::p);
-
+  if (!!NS_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+    errUnclosedElementsImplied(eltPos, nsHtml5Atoms::p);
+  }
   while (currentPtr >= eltPos) {
     pop();
   }
@@ -3163,15 +3255,17 @@ nsHtml5TreeBuilder::adoptionAgencyEndTag(nsIAtom* name)
       formattingEltStackPos--;
     }
     if (formattingEltStackPos == -1) {
-
+      errNoElementToCloseButEndTagSeen(name);
       removeFromListOfActiveFormattingElements(formattingEltListPos);
       return true;
     }
     if (!inScope) {
-
+      errNoElementToCloseButEndTagSeen(name);
       return true;
     }
-
+    if (formattingEltStackPos != currentPtr) {
+      errEndTagViolatesNestingRules(name);
+    }
     PRInt32 furthestBlockPos = formattingEltStackPos + 1;
     while (furthestBlockPos <= currentPtr) {
       nsHtml5StackNode* node = stack[furthestBlockPos];
@@ -3755,7 +3849,7 @@ nsHtml5TreeBuilder::flushCharacters()
 {
   if (charBufferLen > 0) {
     if ((mode == NS_HTML5TREE_BUILDER_IN_TABLE || mode == NS_HTML5TREE_BUILDER_IN_TABLE_BODY || mode == NS_HTML5TREE_BUILDER_IN_ROW) && charBufferContainsNonWhitespace()) {
-
+      errNonSpaceInTable();
       reconstructTheActiveFormattingElements();
       if (!stack[currentPtr]->isFosterParenting()) {
         appendCharacters(currentNode(), charBuffer, 0, charBufferLen);
diff --git a/parser/html/nsHtml5TreeBuilder.h b/parser/html/nsHtml5TreeBuilder.h
index f337af83896..4333e040c42 100644
--- a/parser/html/nsHtml5TreeBuilder.h
+++ b/parser/html/nsHtml5TreeBuilder.h
@@ -52,6 +52,7 @@
 #include "nsHtml5TreeOpExecutor.h"
 #include "nsHtml5StreamParser.h"
 #include "nsAHtml5TreeBuilderState.h"
+#include "nsHtml5Highlighter.h"
 
 class nsHtml5StreamParser;
 
diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h
index b307727d865..3fb16234322 100644
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -57,6 +57,7 @@ nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
   , contextNode(nsnull)
   , formPointer(nsnull)
   , headPointer(nsnull)
+  , mViewSource(nsnull)
   , mOpSink(aOpSink)
   , mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH])
   , mHandlesUsed(0)
@@ -707,3 +708,396 @@ nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m)
   NS_ASSERTION(treeOp, "Tree op allocation failed.");
   treeOp->Init(m);
 }
+
+// Error reporting
+
+void
+nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter)
+{
+  mViewSource = aHighlighter;
+}
+
+void
+nsHtml5TreeBuilder::errStrayStartTag(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errStrayStartTag", aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errStrayEndTag(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errStrayEndTag", aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errUnclosedElements(PRInt32 aIndex, nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errUnclosedElements", aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errUnclosedElementsImplied(PRInt32 aIndex, nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errUnclosedElementsImplied",
+        aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errUnclosedElementsCell(PRInt32 aIndex)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errUnclosedElementsCell");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errStrayDoctype()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errStrayDoctype");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errAlmostStandardsDoctype()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errAlmostStandardsDoctype");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errQuirkyDoctype()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errQuirkyDoctype");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNonSpaceInTrailer()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errNonSpaceInTrailer");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNonSpaceAfterFrameset()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errNonSpaceAfterFrameset");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNonSpaceInFrameset()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errNonSpaceInFrameset");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNonSpaceAfterBody()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errNonSpaceAfterBody");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errStartTagWithoutDoctype()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errStartTagWithoutDoctype");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNoSelectInTableScope()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errNoSelectInTableScope");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun(
+        "errStartSelectWhereEndSelectExpected");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errBadStartTagInHead(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errBadStartTagInHead", aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errImage()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errImage");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errIsindex()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errIsindex");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errFooSeenWhenFooOpen", aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errHeadingWhenHeadingOpen()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errHeadingWhenHeadingOpen");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errFramesetStart()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errFramesetStart");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNoCellToClose()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errNoCellToClose");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errStartTagInTable(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errStartTagInTable", aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errFormWhenFormOpen()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errFormWhenFormOpen");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errTableSeenWhileTableOpen()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errTableSeenWhileTableOpen");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errStartTagInTableBody(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errStartTagInTableBody", aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errEndTagAfterBody()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEndTagAfterBody");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen",
+        aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errGarbageInColgroup()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errGarbageInColgroup");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errEndTagBr()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEndTagBr");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun(
+        "errNoElementToCloseButEndTagSeen", aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errHtmlStartTagInForeignContext",
+        aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errTableClosedWhileCaptionOpen()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errTableClosedWhileCaptionOpen");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNoTableRowToClose()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errNoTableRowToClose");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNonSpaceInTable()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errNonSpaceInTable");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errUnclosedChildrenInRuby()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errUnclosedChildrenInRuby");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errStartTagSeenWithoutRuby",
+        aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errSelfClosing()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentSlash("errSelfClosing");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack()
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun(
+        "errNoCheckUnclosedElementsOnStack");
+  }
+}
+
+void
+nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(nsIAtom* aName,
+                                                           nsIAtom* aOther)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun(
+        "errEndTagDidNotMatchCurrentOpenElement", aName, aOther);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName);
+  }
+}
+
+void
+nsHtml5TreeBuilder::errEndWithUnclosedElements(nsIAtom* aName)
+{
+  if (NS_UNLIKELY(mViewSource)) {
+    mViewSource->AddErrorToCurrentRun("errEndWithUnclosedElements", aName);
+  }
+}
diff --git a/parser/html/nsHtml5TreeBuilderHSupplement.h b/parser/html/nsHtml5TreeBuilderHSupplement.h
index 3623a30d89a..c0b5501aa58 100644
--- a/parser/html/nsHtml5TreeBuilderHSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderHSupplement.h
@@ -38,7 +38,7 @@
 #define NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH 512
 
   private:
-
+    nsHtml5Highlighter*                    mViewSource;
     nsTArray         mOpQueue;
     nsTArray       mSpeculativeLoadQueue;
     nsAHtml5TreeOpSink*                    mOpSink;
@@ -96,4 +96,100 @@
 
     void DropHandles();
 
+    void EnableViewSource(nsHtml5Highlighter* aHighlighter);
+
+    void errStrayStartTag(nsIAtom* aName);
+
+    void errStrayEndTag(nsIAtom* aName);
+
+    void errUnclosedElements(PRInt32 aIndex, nsIAtom* aName);
+
+    void errUnclosedElementsImplied(PRInt32 aIndex, nsIAtom* aName);
+
+    void errUnclosedElementsCell(PRInt32 aIndex);
+
+    void errStrayDoctype();
+
+    void errAlmostStandardsDoctype();
+
+    void errQuirkyDoctype();
+
+    void errNonSpaceInTrailer();
+
+    void errNonSpaceAfterFrameset();
+
+    void errNonSpaceInFrameset();
+
+    void errNonSpaceAfterBody();
+
+    void errNonSpaceInColgroupInFragment();
+
+    void errNonSpaceInNoscriptInHead();
+
+    void errFooBetweenHeadAndBody(nsIAtom* aName);
+
+    void errStartTagWithoutDoctype();
+
+    void errNoSelectInTableScope();
+
+    void errStartSelectWhereEndSelectExpected();
+
+    void errStartTagWithSelectOpen(nsIAtom* aName);
+
+    void errBadStartTagInHead(nsIAtom* aName);
+
+    void errImage();
+
+    void errIsindex();
+
+    void errFooSeenWhenFooOpen(nsIAtom* aName);
+
+    void errHeadingWhenHeadingOpen();
+
+    void errFramesetStart();
+
+    void errNoCellToClose();
+
+    void errStartTagInTable(nsIAtom* aName);
+
+    void errFormWhenFormOpen();
+
+    void errTableSeenWhileTableOpen();
+
+    void errStartTagInTableBody(nsIAtom* aName);
+
+    void errEndTagSeenWithoutDoctype();
+
+    void errEndTagAfterBody();
+
+    void errEndTagSeenWithSelectOpen(nsIAtom* aName);
+
+    void errGarbageInColgroup();
+
+    void errEndTagBr();
+
+    void errNoElementToCloseButEndTagSeen(nsIAtom* aName);
+
+    void errHtmlStartTagInForeignContext(nsIAtom* aName);
+
+    void errTableClosedWhileCaptionOpen();
+
+    void errNoTableRowToClose();
+
+    void errNonSpaceInTable();
+
+    void errUnclosedChildrenInRuby();
+
+    void errStartTagSeenWithoutRuby(nsIAtom* aName);
+
+    void errSelfClosing();
+
+    void errNoCheckUnclosedElementsOnStack();
+
+    void errEndTagDidNotMatchCurrentOpenElement(nsIAtom* aName, nsIAtom* aOther);
+
+    void errEndTagViolatesNestingRules(nsIAtom* aName);
+
+    void errEndWithUnclosedElements(nsIAtom* aName);
+
     void MarkAsBroken();