summaryrefslogtreecommitdiffstats
path: root/parser/htmlparser
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /parser/htmlparser
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--parser/htmlparser/CNavDTD.cpp69
-rw-r--r--parser/htmlparser/CNavDTD.h32
-rw-r--r--parser/htmlparser/CParserContext.cpp74
-rw-r--r--parser/htmlparser/CParserContext.h66
-rw-r--r--parser/htmlparser/components.conf21
-rw-r--r--parser/htmlparser/moz.build58
-rw-r--r--parser/htmlparser/nsElementTable.cpp206
-rw-r--r--parser/htmlparser/nsElementTable.h21
-rw-r--r--parser/htmlparser/nsExpatDriver.cpp1248
-rw-r--r--parser/htmlparser/nsExpatDriver.h131
-rw-r--r--parser/htmlparser/nsHTMLTagList.h199
-rw-r--r--parser/htmlparser/nsHTMLTags.cpp164
-rw-r--r--parser/htmlparser/nsHTMLTags.h81
-rw-r--r--parser/htmlparser/nsHTMLTokenizer.cpp52
-rw-r--r--parser/htmlparser/nsHTMLTokenizer.h32
-rw-r--r--parser/htmlparser/nsIContentSink.h139
-rw-r--r--parser/htmlparser/nsIDTD.h140
-rw-r--r--parser/htmlparser/nsIExpatSink.idl111
-rw-r--r--parser/htmlparser/nsIFragmentContentSink.h85
-rw-r--r--parser/htmlparser/nsIHTMLContentSink.h90
-rw-r--r--parser/htmlparser/nsIParser.h246
-rw-r--r--parser/htmlparser/nsITokenizer.h44
-rw-r--r--parser/htmlparser/nsParser.cpp1471
-rw-r--r--parser/htmlparser/nsParser.h391
-rw-r--r--parser/htmlparser/nsParserBase.h19
-rw-r--r--parser/htmlparser/nsParserCIID.h17
-rw-r--r--parser/htmlparser/nsParserConstants.h22
-rw-r--r--parser/htmlparser/nsParserModule.cpp18
-rw-r--r--parser/htmlparser/nsParserMsgUtils.cpp62
-rw-r--r--parser/htmlparser/nsParserMsgUtils.h28
-rw-r--r--parser/htmlparser/nsScanner.cpp361
-rw-r--r--parser/htmlparser/nsScanner.h190
-rw-r--r--parser/htmlparser/nsScannerString.cpp578
-rw-r--r--parser/htmlparser/nsScannerString.h508
-rw-r--r--parser/htmlparser/tests/crashtests/121591-1.html22
-rw-r--r--parser/htmlparser/tests/crashtests/1373045-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/147179-1.html7
-rw-r--r--parser/htmlparser/tests/crashtests/151956-1.html18
-rw-r--r--parser/htmlparser/tests/crashtests/152444-1.html15
-rw-r--r--parser/htmlparser/tests/crashtests/1534346-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/1604307-1.html10
-rw-r--r--parser/htmlparser/tests/crashtests/1606499-1.html15
-rw-r--r--parser/htmlparser/tests/crashtests/185073-1.html15
-rw-r--r--parser/htmlparser/tests/crashtests/188474-1.html13
-rw-r--r--parser/htmlparser/tests/crashtests/194329-1.html15
-rw-r--r--parser/htmlparser/tests/crashtests/197052-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/220542-1.html2
-rw-r--r--parser/htmlparser/tests/crashtests/253979-1.html4
-rw-r--r--parser/htmlparser/tests/crashtests/269095-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/286733-1.html4
-rw-r--r--parser/htmlparser/tests/crashtests/286733-2.html4
-rw-r--r--parser/htmlparser/tests/crashtests/299036-1.html2
-rw-r--r--parser/htmlparser/tests/crashtests/30885-1.html17
-rw-r--r--parser/htmlparser/tests/crashtests/30956-1.html10
-rw-r--r--parser/htmlparser/tests/crashtests/31392-1.html15
-rw-r--r--parser/htmlparser/tests/crashtests/31694-1.html8
-rw-r--r--parser/htmlparser/tests/crashtests/31940-1.html15
-rw-r--r--parser/htmlparser/tests/crashtests/32613-1.html18
-rw-r--r--parser/htmlparser/tests/crashtests/328751-1.html9
-rw-r--r--parser/htmlparser/tests/crashtests/34168-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/34168-1.xml6
-rw-r--r--parser/htmlparser/tests/crashtests/408939-1.html139
-rw-r--r--parser/htmlparser/tests/crashtests/41427-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/423373-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/44178-1.html8
-rw-r--r--parser/htmlparser/tests/crashtests/445171-1-inner.svg5
-rw-r--r--parser/htmlparser/tests/crashtests/445171-1.html9
-rw-r--r--parser/htmlparser/tests/crashtests/46495-1.html5
-rw-r--r--parser/htmlparser/tests/crashtests/468538-1.xhtml15
-rw-r--r--parser/htmlparser/tests/crashtests/50134-1.html8
-rw-r--r--parser/htmlparser/tests/crashtests/502103.html1
-rw-r--r--parser/htmlparser/tests/crashtests/502869-iframe.html9
-rw-r--r--parser/htmlparser/tests/crashtests/502869.html18
-rw-r--r--parser/htmlparser/tests/crashtests/50994-1.html12
-rw-r--r--parser/htmlparser/tests/crashtests/515278-1.html3
-rw-r--r--parser/htmlparser/tests/crashtests/515533-1-inner.html12
-rw-r--r--parser/htmlparser/tests/crashtests/515533-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/515816-1.html11
-rw-r--r--parser/htmlparser/tests/crashtests/522326-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/525229-1.html7
-rw-r--r--parser/htmlparser/tests/crashtests/536097-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/555462-iframe.html3
-rw-r--r--parser/htmlparser/tests/crashtests/555462.html21
-rw-r--r--parser/htmlparser/tests/crashtests/563514-1.html10
-rw-r--r--parser/htmlparser/tests/crashtests/574884-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/574884-2.html1
-rw-r--r--parser/htmlparser/tests/crashtests/58455-1.html15
-rw-r--r--parser/htmlparser/tests/crashtests/591330-1.html284
-rw-r--r--parser/htmlparser/tests/crashtests/60110-1.html22
-rw-r--r--parser/htmlparser/tests/crashtests/616027-1.html15
-rw-r--r--parser/htmlparser/tests/crashtests/650501-1.xhtml22
-rw-r--r--parser/htmlparser/tests/crashtests/662185-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/696651-1.html11
-rw-r--r--parser/htmlparser/tests/crashtests/699347-1.xml1
-rw-r--r--parser/htmlparser/tests/crashtests/721313-1.html2
-rw-r--r--parser/htmlparser/tests/crashtests/73331-1.html27
-rw-r--r--parser/htmlparser/tests/crashtests/742414-1.html4
-rw-r--r--parser/htmlparser/tests/crashtests/762726-1.html1
-rw-r--r--parser/htmlparser/tests/crashtests/92647-1.html33
-rw-r--r--parser/htmlparser/tests/crashtests/92788-1.html20
-rw-r--r--parser/htmlparser/tests/crashtests/981279-1.html15
-rw-r--r--parser/htmlparser/tests/crashtests/982285-1.html19
-rw-r--r--parser/htmlparser/tests/crashtests/crashtests.list64
-rw-r--r--parser/htmlparser/tests/crashtests/file_445171-1.html1
-rw-r--r--parser/htmlparser/tests/mochitest/.eslintrc.js5
-rw-r--r--parser/htmlparser/tests/mochitest/blue.pngbin0 -> 2745 bytes
-rw-r--r--parser/htmlparser/tests/mochitest/broken_xml.xhtml7
-rw-r--r--parser/htmlparser/tests/mochitest/browser.ini12
-rw-r--r--parser/htmlparser/tests/mochitest/browser_viewsource.js28
-rw-r--r--parser/htmlparser/tests/mochitest/browser_ysod_telemetry.js47
-rw-r--r--parser/htmlparser/tests/mochitest/bug_502091_iframe.html17
-rw-r--r--parser/htmlparser/tests/mochitest/dir_bug534293/file_bug534293.sjs14
-rw-r--r--parser/htmlparser/tests/mochitest/file_async_bug1104732.sjs14
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug102699.sjs15
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs14
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug534293.sjs14
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug543062.sjs32
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug568470-script.sjs16
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug568470.sjs21
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug594730-1.html3
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug594730-2.html3
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug594730-3.html3
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug594730-4.html3
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug594730-5.html3
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug594730-6.html3
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug594730-7.html3
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug594730-8.html3
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug594730-9.html5
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug642908.sjs16
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug655682.sjs37
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_bomless_utf16.htmlbin0 -> 354 bytes
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html^headers^2
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_late_meta.html1028
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_meta_non_superset.html1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_meta_restart.html1028
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_meta_unsupported.html1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_meta_userdefined.html1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_meta_utf16.html1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_not_declared.html1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug688580.js8
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug716579-16.htmlbin0 -> 82 bytes
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug716579-16.html^headers^1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug716579-16.xhtmlbin0 -> 214 bytes
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug716579-16.xhtml^headers^1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug716579-8.html3
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug716579-8.html^headers^1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug716579-8.xhtml7
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug716579-8.xhtml^headers^1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug717180.html1
-rw-r--r--parser/htmlparser/tests/mochitest/file_defer_bug1104732.js7
-rw-r--r--parser/htmlparser/tests/mochitest/file_img_picture_preload.html167
-rw-r--r--parser/htmlparser/tests/mochitest/file_img_picture_preload.sjs28
-rw-r--r--parser/htmlparser/tests/mochitest/file_viewsource.html18
-rw-r--r--parser/htmlparser/tests/mochitest/html5_tree_construction_exceptions.js11
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/README.md104
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/adoption01.dat337
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/adoption02.dat99
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/comments01.dat206
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/doctype01.dat424
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/domjs-unsafe.datbin0 -> 9884 bytes
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/entities01.dat792
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/entities02.dat283
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/foreign-fragment.dat550
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5lib_license.txt21
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5lib_upstream.txt11
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5test-com.dat291
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/inbody01.dat54
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/isindex.dat49
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/main-element.dat44
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/pending-spec-changes-plain-text-unsafe.datbin0 -> 816 bytes
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/pending-spec-changes.dat46
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/plain-text-unsafe.datbin0 -> 7925 bytes
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/ruby.dat298
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/scriptdata01.dat352
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/adoption01.dat15
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/ark.dat26
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/webkit01.dat28
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tables01.dat286
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/template.dat1406
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests1.dat1959
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests10.dat847
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests11.dat482
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests12.dat62
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests14.dat75
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests15.dat216
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests16.dat2396
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests17.dat180
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests18.dat322
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests19.dat1454
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests2.dat821
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests20.dat516
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests21.dat305
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests22.dat190
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests23.dat168
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests24.dat79
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests25.dat220
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests26.dat411
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests3.dat306
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests4.dat58
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests5.dat197
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests6.dat662
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests7.dat402
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests8.dat149
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests9.dat473
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests_innerHTML_1.dat902
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/tricky01.dat334
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/webkit01.dat705
-rw-r--r--parser/htmlparser/tests/mochitest/html5lib_tree_construction/webkit02.dat116
-rw-r--r--parser/htmlparser/tests/mochitest/invalidchar.xml4
-rw-r--r--parser/htmlparser/tests/mochitest/mochitest.ini152
-rw-r--r--parser/htmlparser/tests/mochitest/parser_datreader.js216
-rw-r--r--parser/htmlparser/tests/mochitest/parser_web_testrunner.js149
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug102699.html75
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug1104732.html59
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug1209658.html35
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug1364399.html43
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug1646140-1.html20
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug1646140-2.html28
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug174351.html31
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug213517.html30
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug339350.xhtml61
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug358797.html31
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug396568.html48
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug418464.html43
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug460437.xhtml40
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug502091.html37
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug534293.html22
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug543062.html26
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug552938-2.html38
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug552938.html33
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug563322.xhtml33
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug566879.html64
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug568470.html51
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug594730.html32
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug613662.html132
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug613662.xhtml137
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug639362.html28
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug642908.html32
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug645115.html32
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug655682.html80
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug667533.html28
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug672453.html91
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug688580.html64
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug688580.xhtml62
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug709083.html30
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug715112.html49
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug715739.html88
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug716579.html44
-rw-r--r--parser/htmlparser/tests/mochitest/test_bug717180.html44
-rw-r--r--parser/htmlparser/tests/mochitest/test_compatmode.html100
-rw-r--r--parser/htmlparser/tests/mochitest/test_html5_tree_construction.html60
-rw-r--r--parser/htmlparser/tests/mochitest/test_html5_tree_construction_part2.html60
-rw-r--r--parser/htmlparser/tests/mochitest/test_img_picture_preload.html86
-rw-r--r--parser/htmlparser/tests/mochitest/test_xml_mislabeled.html62
-rw-r--r--parser/htmlparser/tests/reftest/bug1636607-1-ref.html18
-rw-r--r--parser/htmlparser/tests/reftest/bug1636607-1.html18
-rw-r--r--parser/htmlparser/tests/reftest/bug1636607-2-ref.html17
-rw-r--r--parser/htmlparser/tests/reftest/bug1636607-2.html18
-rw-r--r--parser/htmlparser/tests/reftest/bug482921-1-ref.html27
-rw-r--r--parser/htmlparser/tests/reftest/bug482921-1.html24
-rw-r--r--parser/htmlparser/tests/reftest/bug482921-2-ref.html28
-rw-r--r--parser/htmlparser/tests/reftest/bug482921-2.xhtml25
-rw-r--r--parser/htmlparser/tests/reftest/bug535530-1-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/bug535530-1.html14
-rw-r--r--parser/htmlparser/tests/reftest/bug535530-2-ref.html17
-rw-r--r--parser/htmlparser/tests/reftest/bug535530-2.html14
-rw-r--r--parser/htmlparser/tests/reftest/bug566280-1-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/bug566280-1.htmlbin0 -> 19 bytes
-rw-r--r--parser/htmlparser/tests/reftest/bug569229-1-ref.xml2
-rw-r--r--parser/htmlparser/tests/reftest/bug569229-1.xml6
-rw-r--r--parser/htmlparser/tests/reftest/bug577418-1-ref.html6
-rw-r--r--parser/htmlparser/tests/reftest/bug577418-1.html15
-rw-r--r--parser/htmlparser/tests/reftest/bug582788-1-ref.html11
-rw-r--r--parser/htmlparser/tests/reftest/bug582788-1.html11
-rw-r--r--parser/htmlparser/tests/reftest/bug582940-1-ref.html16
-rw-r--r--parser/htmlparser/tests/reftest/bug582940-1.html16
-rw-r--r--parser/htmlparser/tests/reftest/bug592656-1-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/bug592656-1.html32
-rw-r--r--parser/htmlparser/tests/reftest/bug599320-1-ref.html17
-rw-r--r--parser/htmlparser/tests/reftest/bug599320-1.htmlbin0 -> 616 bytes
-rw-r--r--parser/htmlparser/tests/reftest/bug608373-1-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/bug608373-1.html14
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-1-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-1.html9
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-2-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-2.html9
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-3-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-3.html9
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-4-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-4.html9
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-5-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-5.html9
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-6-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/bug659763-6.html9
-rw-r--r--parser/htmlparser/tests/reftest/bug673094-1-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/bug673094-1.html9
-rw-r--r--parser/htmlparser/tests/reftest/bug696651-1-ref.html1
-rw-r--r--parser/htmlparser/tests/reftest/bug696651-1.html2
-rw-r--r--parser/htmlparser/tests/reftest/bug696651-2-ref.html1
-rw-r--r--parser/htmlparser/tests/reftest/bug696651-2.html6
-rw-r--r--parser/htmlparser/tests/reftest/bug696651-external.js1
-rw-r--r--parser/htmlparser/tests/reftest/bug700260-1-ref.html3
-rw-r--r--parser/htmlparser/tests/reftest/bug700260-1.html3
-rw-r--r--parser/htmlparser/tests/reftest/bug704667-1-ref.html4
-rw-r--r--parser/htmlparser/tests/reftest/bug704667-1.html1
-rw-r--r--parser/htmlparser/tests/reftest/bug731234-1-ref.html30
-rw-r--r--parser/htmlparser/tests/reftest/bug731234-1.html27
-rw-r--r--parser/htmlparser/tests/reftest/bug820508-1-ref.html6
-rw-r--r--parser/htmlparser/tests/reftest/bug820508-1.html6
-rw-r--r--parser/htmlparser/tests/reftest/bug910588-1-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/bug910588-1.html1
-rw-r--r--parser/htmlparser/tests/reftest/frame582940-ref.html51
-rw-r--r--parser/htmlparser/tests/reftest/frame582940.html51
-rw-r--r--parser/htmlparser/tests/reftest/frame599320-1-ref.html15
-rw-r--r--parser/htmlparser/tests/reftest/frame599320-1.html1092
-rw-r--r--parser/htmlparser/tests/reftest/reftest.list28
317 files changed, 35981 insertions, 0 deletions
diff --git a/parser/htmlparser/CNavDTD.cpp b/parser/htmlparser/CNavDTD.cpp
new file mode 100644
index 0000000000..89a682d906
--- /dev/null
+++ b/parser/htmlparser/CNavDTD.cpp
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 et tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.h"
+#include "nsISupportsImpl.h"
+#include "nsIParser.h"
+#include "CNavDTD.h"
+#include "nsIHTMLContentSink.h"
+
+NS_IMPL_ISUPPORTS(CNavDTD, nsIDTD);
+
+CNavDTD::CNavDTD() {}
+
+CNavDTD::~CNavDTD() {}
+
+NS_IMETHODIMP
+CNavDTD::WillBuildModel(const CParserContext& aParserContext,
+ nsITokenizer* aTokenizer, nsIContentSink* aSink) {
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+CNavDTD::BuildModel(nsITokenizer* aTokenizer, nsIContentSink* aSink) {
+ // NB: It is important to throw STOPPARSING if the sink is the wrong type in
+ // order to make sure nsParser cleans up properly after itself.
+ nsCOMPtr<nsIHTMLContentSink> sink = do_QueryInterface(aSink);
+ if (!sink) {
+ return NS_ERROR_HTMLPARSER_STOPPARSING;
+ }
+
+ nsresult rv = sink->OpenContainer(nsIHTMLContentSink::eHTML);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = sink->OpenContainer(nsIHTMLContentSink::eBody);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = sink->CloseContainer(nsIHTMLContentSink::eBody);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+ rv = sink->CloseContainer(nsIHTMLContentSink::eHTML);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+CNavDTD::DidBuildModel(nsresult anErrorCode) { return NS_OK; }
+
+NS_IMETHODIMP_(void)
+CNavDTD::Terminate() {}
+
+NS_IMETHODIMP_(int32_t)
+CNavDTD::GetType() { return NS_IPARSER_FLAG_HTML; }
+
+NS_IMETHODIMP_(nsDTDMode)
+CNavDTD::GetMode() const { return eDTDMode_quirks; }
+
+NS_IMETHODIMP_(bool)
+CNavDTD::CanContain(int32_t aParent, int32_t aChild) const {
+ MOZ_CRASH("nobody calls this");
+ return false;
+}
+
+NS_IMETHODIMP_(bool)
+CNavDTD::IsContainer(int32_t aTag) const {
+ MOZ_CRASH("nobody calls this");
+ return false;
+}
diff --git a/parser/htmlparser/CNavDTD.h b/parser/htmlparser/CNavDTD.h
new file mode 100644
index 0000000000..6b4c2511a9
--- /dev/null
+++ b/parser/htmlparser/CNavDTD.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 et tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef NS_NAVHTMLDTD__
+#define NS_NAVHTMLDTD__
+
+#include "nsIDTD.h"
+#include "nsISupports.h"
+#include "nsCOMPtr.h"
+
+#ifdef _MSC_VER
+# pragma warning(disable : 4275)
+#endif
+
+class CNavDTD : public nsIDTD {
+#ifdef _MSC_VER
+# pragma warning(default : 4275)
+#endif
+
+ virtual ~CNavDTD();
+
+ public:
+ CNavDTD();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIDTD
+};
+
+#endif
diff --git a/parser/htmlparser/CParserContext.cpp b/parser/htmlparser/CParserContext.cpp
new file mode 100644
index 0000000000..bd96134c96
--- /dev/null
+++ b/parser/htmlparser/CParserContext.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsAtom.h"
+#include "CParserContext.h"
+#include "prenv.h"
+#include "nsIHTMLContentSink.h"
+#include "nsHTMLTokenizer.h"
+#include "nsMimeTypes.h"
+#include "nsHTMLTokenizer.h"
+
+CParserContext::CParserContext(CParserContext* aPrevContext,
+ nsScanner* aScanner, void* aKey,
+ eParserCommands aCommand,
+ nsIRequestObserver* aListener,
+ eAutoDetectResult aStatus, bool aCopyUnused)
+ : mListener(aListener),
+ mKey(aKey),
+ mPrevContext(aPrevContext),
+ mScanner(mozilla::WrapUnique(aScanner)),
+ mDTDMode(eDTDMode_unknown),
+ mDocType(static_cast<eParserDocType>(0)),
+ mStreamListenerState(eNone),
+ mContextType(eCTNone),
+ mAutoDetectStatus(aStatus),
+ mParserCommand(aCommand),
+ mMultipart(true),
+ mCopyUnused(aCopyUnused) {
+ MOZ_COUNT_CTOR(CParserContext);
+}
+
+CParserContext::~CParserContext() {
+ // It's ok to simply ingore the PrevContext.
+ MOZ_COUNT_DTOR(CParserContext);
+}
+
+void CParserContext::SetMimeType(const nsACString& aMimeType) {
+ mMimeType.Assign(aMimeType);
+
+ mDocType = ePlainText;
+
+ if (mMimeType.EqualsLiteral(TEXT_HTML))
+ mDocType = eHTML_Strict;
+ else if (mMimeType.EqualsLiteral(TEXT_XML) ||
+ mMimeType.EqualsLiteral(APPLICATION_XML) ||
+ mMimeType.EqualsLiteral(APPLICATION_XHTML_XML) ||
+ mMimeType.EqualsLiteral(IMAGE_SVG_XML) ||
+ mMimeType.EqualsLiteral(APPLICATION_MATHML_XML) ||
+ mMimeType.EqualsLiteral(APPLICATION_RDF_XML) ||
+ mMimeType.EqualsLiteral(APPLICATION_WAPXHTML_XML) ||
+ mMimeType.EqualsLiteral(TEXT_RDF))
+ mDocType = eXML;
+}
+
+nsresult CParserContext::GetTokenizer(nsIDTD* aDTD, nsIContentSink* aSink,
+ nsITokenizer*& aTokenizer) {
+ nsresult result = NS_OK;
+ int32_t type = aDTD ? aDTD->GetType() : NS_IPARSER_FLAG_HTML;
+
+ if (!mTokenizer) {
+ if (type == NS_IPARSER_FLAG_HTML || mParserCommand == eViewSource) {
+ mTokenizer = new nsHTMLTokenizer;
+ } else if (type == NS_IPARSER_FLAG_XML) {
+ mTokenizer = do_QueryInterface(aDTD, &result);
+ }
+ }
+
+ aTokenizer = mTokenizer;
+
+ return result;
+}
diff --git a/parser/htmlparser/CParserContext.h b/parser/htmlparser/CParserContext.h
new file mode 100644
index 0000000000..49e50f3914
--- /dev/null
+++ b/parser/htmlparser/CParserContext.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * MODULE NOTES:
+ * @update gess 4/1/98
+ *
+ */
+
+#ifndef __CParserContext
+#define __CParserContext
+
+#include "mozilla/UniquePtr.h"
+#include "nsIParser.h"
+#include "nsIDTD.h"
+#include "nsIRequest.h"
+#include "nsScanner.h"
+#include "nsString.h"
+#include "nsCOMPtr.h"
+
+/**
+ * Note that the parser is given FULL access to all
+ * data in a parsercontext. Hey, that what it's for!
+ */
+
+class CParserContext {
+ public:
+ enum eContextType { eCTNone, eCTURL, eCTString, eCTStream };
+
+ CParserContext(CParserContext* aPrevContext, nsScanner* aScanner,
+ void* aKey = 0, eParserCommands aCommand = eViewNormal,
+ nsIRequestObserver* aListener = 0,
+ eAutoDetectResult aStatus = eUnknownDetect,
+ bool aCopyUnused = false);
+
+ ~CParserContext();
+
+ nsresult GetTokenizer(nsIDTD* aDTD, nsIContentSink* aSink,
+ nsITokenizer*& aTokenizer);
+ void SetMimeType(const nsACString& aMimeType);
+
+ nsCOMPtr<nsIRequest>
+ mRequest; // provided by necko to differnciate different input streams
+ // why is mRequest strongly referenced? see bug 102376.
+ nsCOMPtr<nsIRequestObserver> mListener;
+ void* const mKey;
+ nsCOMPtr<nsITokenizer> mTokenizer;
+ CParserContext* const mPrevContext;
+ mozilla::UniquePtr<nsScanner> mScanner;
+
+ nsCString mMimeType;
+ nsDTDMode mDTDMode;
+
+ eParserDocType mDocType;
+ eStreamState mStreamListenerState;
+ eContextType mContextType;
+ eAutoDetectResult mAutoDetectStatus;
+ eParserCommands mParserCommand;
+
+ bool mMultipart;
+ bool mCopyUnused;
+};
+
+#endif
diff --git a/parser/htmlparser/components.conf b/parser/htmlparser/components.conf
new file mode 100644
index 0000000000..af928b8f55
--- /dev/null
+++ b/parser/htmlparser/components.conf
@@ -0,0 +1,21 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Headers = [
+ 'nsHTMLTags.h',
+]
+
+InitFunc = 'nsParserInitialize'
+UnloadFunc = 'nsHTMLTags::ReleaseTable'
+
+Classes = [
+ {
+ 'cid': '{2ce606b0-bee6-11d1-aad9-00805f8a3e14}',
+ 'contract_ids': [],
+ 'type': 'nsParser',
+ 'headers': ['/parser/htmlparser/nsParser.h'],
+ },
+]
diff --git a/parser/htmlparser/moz.build b/parser/htmlparser/moz.build
new file mode 100644
index 0000000000..8d79568805
--- /dev/null
+++ b/parser/htmlparser/moz.build
@@ -0,0 +1,58 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+with Files("**"):
+ BUG_COMPONENT = ("Core", "XML")
+
+MOCHITEST_MANIFESTS += ["tests/mochitest/mochitest.ini"]
+BROWSER_CHROME_MANIFESTS += ["tests/mochitest/browser.ini"]
+
+XPIDL_SOURCES += [
+ "nsIExpatSink.idl",
+]
+
+XPIDL_MODULE = "htmlparser"
+
+EXPORTS += [
+ "nsElementTable.h",
+ "nsHTMLTagList.h",
+ "nsHTMLTags.h",
+ "nsIContentSink.h",
+ "nsIDTD.h",
+ "nsIFragmentContentSink.h",
+ "nsIHTMLContentSink.h",
+ "nsIParser.h",
+ "nsITokenizer.h",
+ "nsParserBase.h",
+ "nsParserCIID.h",
+ "nsParserConstants.h",
+ "nsScannerString.h",
+]
+
+UNIFIED_SOURCES += [
+ "CNavDTD.cpp",
+ "CParserContext.cpp",
+ "nsElementTable.cpp",
+ "nsExpatDriver.cpp",
+ "nsHTMLTags.cpp",
+ "nsHTMLTokenizer.cpp",
+ "nsParser.cpp",
+ "nsParserModule.cpp",
+ "nsParserMsgUtils.cpp",
+ "nsScanner.cpp",
+ "nsScannerString.cpp",
+]
+
+XPCOM_MANIFESTS += [
+ "components.conf",
+]
+
+include("/ipc/chromium/chromium-config.mozbuild")
+
+FINAL_LIBRARY = "xul"
+
+if CONFIG["CC_TYPE"] in ("clang", "gcc"):
+ CXXFLAGS += ["-Wno-error=shadow"]
diff --git a/parser/htmlparser/nsElementTable.cpp b/parser/htmlparser/nsElementTable.cpp
new file mode 100644
index 0000000000..7e6c6d488d
--- /dev/null
+++ b/parser/htmlparser/nsElementTable.cpp
@@ -0,0 +1,206 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsElementTable.h"
+
+struct HTMLElement {
+#ifdef DEBUG
+ nsHTMLTag mTagID;
+#endif
+ bool mIsBlock;
+ bool mIsContainer;
+};
+
+#ifdef DEBUG
+# define ELEM(tag, block, container) {eHTMLTag_##tag, block, container},
+#else
+# define ELEM(tag, block, container) {block, container},
+#endif
+
+#define ____ false // This makes the table easier to read.
+
+// Note that the mIsBlock field disagrees with
+// https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements for
+// the following elements: center, details, dialog, dir, dt, figcaption,
+// listing, menu, multicol, noscript, output, summary, tfoot, video.
+//
+// mrbkap thinks that the field values were pulled from the old HTML4 DTD and
+// then got modified in mostly random ways to make the old parser's behavior
+// compatible with the web. So it might make sense to change the mIsBlock
+// values for the abovementioned tags at some point.
+//
+static const HTMLElement gHTMLElements[] = {
+ // clang-format off
+ ELEM(unknown, ____, ____)
+ ELEM(a, ____, true)
+ ELEM(abbr, ____, true)
+ ELEM(acronym, ____, true)
+ ELEM(address, true, true)
+ ELEM(applet, ____, true)
+ ELEM(area, ____, ____)
+ ELEM(article, true, true)
+ ELEM(aside, true, true)
+ ELEM(audio, ____, true)
+ ELEM(b, ____, true)
+ ELEM(base, ____, ____)
+ ELEM(basefont, ____, ____)
+ ELEM(bdi, ____, true)
+ ELEM(bdo, ____, true)
+ ELEM(bgsound, ____, ____)
+ ELEM(big, ____, true)
+ ELEM(blockquote, true, true)
+ ELEM(body, ____, true)
+ ELEM(br, ____, ____)
+ ELEM(button, ____, true)
+ ELEM(canvas, ____, true)
+ ELEM(caption, ____, true)
+ ELEM(center, true, true)
+ ELEM(cite, ____, true)
+ ELEM(code, ____, true)
+ ELEM(col, ____, ____)
+ ELEM(colgroup, ____, true)
+ ELEM(data, ____, true)
+ ELEM(datalist, ____, true)
+ ELEM(dd, ____, true)
+ ELEM(del, ____, true)
+ ELEM(details, true, true)
+ ELEM(dfn, ____, true)
+ ELEM(dialog, true, true)
+ ELEM(dir, true, true)
+ ELEM(div, true, true)
+ ELEM(dl, true, true)
+ ELEM(dt, ____, true)
+ ELEM(em, ____, true)
+ ELEM(embed, ____, ____)
+ ELEM(fieldset, true, true)
+ ELEM(figcaption, ____, true)
+ ELEM(figure, true, true)
+ ELEM(font, ____, true)
+ ELEM(footer, true, true)
+ ELEM(form, true, true)
+ ELEM(frame, ____, ____)
+ ELEM(frameset, ____, true)
+ ELEM(h1, true, true)
+ ELEM(h2, true, true)
+ ELEM(h3, true, true)
+ ELEM(h4, true, true)
+ ELEM(h5, true, true)
+ ELEM(h6, true, true)
+ ELEM(head, ____, true)
+ ELEM(header, true, true)
+ ELEM(hgroup, true, true)
+ ELEM(hr, true, ____)
+ ELEM(html, ____, true)
+ ELEM(i, ____, true)
+ ELEM(iframe, ____, true)
+ ELEM(image, ____, ____)
+ ELEM(img, ____, ____)
+ ELEM(input, ____, ____)
+ ELEM(ins, ____, true)
+ ELEM(kbd, ____, true)
+ ELEM(keygen, ____, ____)
+ ELEM(label, ____, true)
+ ELEM(legend, ____, true)
+ ELEM(li, true, true)
+ ELEM(link, ____, ____)
+ ELEM(listing, true, true)
+ ELEM(main, true, true)
+ ELEM(map, ____, true)
+ ELEM(mark, ____, true)
+ ELEM(marquee, ____, true)
+ ELEM(menu, true, true)
+ ELEM(menuitem, ____, true)
+ ELEM(meta, ____, ____)
+ ELEM(meter, ____, true)
+ ELEM(multicol, true, true)
+ ELEM(nav, true, true)
+ ELEM(nobr, ____, true)
+ ELEM(noembed, ____, true)
+ ELEM(noframes, ____, true)
+ ELEM(noscript, ____, true)
+ ELEM(object, ____, true)
+ ELEM(ol, true, true)
+ ELEM(optgroup, ____, true)
+ ELEM(option, ____, true)
+ ELEM(output, ____, true)
+ ELEM(p, true, true)
+ ELEM(param, ____, ____)
+ ELEM(picture, ____, true)
+ ELEM(plaintext, ____, true)
+ ELEM(pre, true, true)
+ ELEM(progress, ____, true)
+ ELEM(q, ____, true)
+ ELEM(rb, ____, true)
+ ELEM(rp, ____, true)
+ ELEM(rt, ____, true)
+ ELEM(rtc, ____, true)
+ ELEM(ruby, ____, true)
+ ELEM(s, ____, true)
+ ELEM(samp, ____, true)
+ ELEM(script, ____, true)
+ ELEM(section, true, true)
+ ELEM(select, ____, true)
+ ELEM(small, ____, true)
+ ELEM(slot, ____, true)
+ ELEM(source, ____, ____)
+ ELEM(span, ____, true)
+ ELEM(strike, ____, true)
+ ELEM(strong, ____, true)
+ ELEM(style, ____, true)
+ ELEM(sub, ____, true)
+ ELEM(summary, true, true)
+ ELEM(sup, ____, true)
+ ELEM(table, true, true)
+ ELEM(tbody, ____, true)
+ ELEM(td, ____, true)
+ ELEM(textarea, ____, true)
+ ELEM(tfoot, ____, true)
+ ELEM(th, ____, true)
+ ELEM(thead, ____, true)
+ ELEM(template, ____, true)
+ ELEM(time, ____, true)
+ ELEM(title, ____, true)
+ ELEM(tr, ____, true)
+ ELEM(track, ____, ____)
+ ELEM(tt, ____, true)
+ ELEM(u, ____, true)
+ ELEM(ul, true, true)
+ ELEM(var, ____, true)
+ ELEM(video, ____, true)
+ ELEM(wbr, ____, ____)
+ ELEM(xmp, ____, true)
+ ELEM(text, ____, ____)
+ ELEM(whitespace, ____, ____)
+ ELEM(newline, ____, ____)
+ ELEM(comment, ____, true)
+ ELEM(entity, ____, true)
+ ELEM(doctypeDecl, ____, true)
+ ELEM(markupDecl, ____, true)
+ ELEM(instruction, ____, true)
+ ELEM(userdefined, ____, true)
+ // clang-format on
+};
+
+#undef ELEM
+#undef ____
+
+bool nsHTMLElement::IsContainer(nsHTMLTag aId) {
+ return gHTMLElements[aId].mIsContainer;
+}
+
+bool nsHTMLElement::IsBlock(nsHTMLTag aId) {
+ return gHTMLElements[aId].mIsBlock;
+}
+
+#ifdef DEBUG
+void CheckElementTable() {
+ for (nsHTMLTag t = eHTMLTag_unknown; t <= eHTMLTag_userdefined;
+ t = nsHTMLTag(t + 1)) {
+ MOZ_ASSERT(gHTMLElements[t].mTagID == t,
+ "gHTMLElements entries does match tag list.");
+ }
+}
+#endif
diff --git a/parser/htmlparser/nsElementTable.h b/parser/htmlparser/nsElementTable.h
new file mode 100644
index 0000000000..23edea76c7
--- /dev/null
+++ b/parser/htmlparser/nsElementTable.h
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsElementTable_h
+#define nsElementTable_h
+
+#include "nsHTMLTags.h"
+
+#ifdef DEBUG
+void CheckElementTable();
+#endif
+
+struct nsHTMLElement {
+ static bool IsContainer(nsHTMLTag aTag);
+ static bool IsBlock(nsHTMLTag aTag);
+};
+
+#endif // nsElementTable_h
diff --git a/parser/htmlparser/nsExpatDriver.cpp b/parser/htmlparser/nsExpatDriver.cpp
new file mode 100644
index 0000000000..eefbe3bb32
--- /dev/null
+++ b/parser/htmlparser/nsExpatDriver.cpp
@@ -0,0 +1,1248 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsExpatDriver.h"
+#include "nsCOMPtr.h"
+#include "nsParserCIID.h"
+#include "CParserContext.h"
+#include "nsIExpatSink.h"
+#include "nsIContentSink.h"
+#include "nsParserMsgUtils.h"
+#include "nsIURL.h"
+#include "nsIUnicharInputStream.h"
+#include "nsIProtocolHandler.h"
+#include "nsNetUtil.h"
+#include "nsTextFormatter.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsCRT.h"
+#include "nsIConsoleService.h"
+#include "nsIScriptError.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsIContentPolicy.h"
+#include "nsComponentManagerUtils.h"
+#include "nsContentPolicyUtils.h"
+#include "nsError.h"
+#include "nsXPCOMCIDInternal.h"
+#include "nsUnicharInputStream.h"
+#include "nsContentUtils.h"
+#include "mozilla/BasePrincipal.h"
+#include "mozilla/IntegerTypeTraits.h"
+#include "mozilla/NullPrincipal.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/TelemetryComms.h"
+
+#include "mozilla/Logging.h"
+
+using mozilla::fallible;
+using mozilla::LogLevel;
+using mozilla::MakeStringSpan;
+using mozilla::dom::Document;
+
+#define kExpatSeparatorChar 0xFFFF
+
+static const char16_t kUTF16[] = {'U', 'T', 'F', '-', '1', '6', '\0'};
+
+static mozilla::LazyLogModule gExpatDriverLog("expatdriver");
+
+// Use the same maximum tree depth as Chromium (see
+// https://chromium.googlesource.com/chromium/src/+/f464165c1dedff1c955d3c051c5a9a1c6a0e8f6b/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.cpp#85).
+static const uint16_t sMaxXMLTreeDepth = 5000;
+
+/***************************** EXPAT CALL BACKS ******************************/
+// The callback handlers that get called from the expat parser.
+
+static void Driver_HandleXMLDeclaration(void* aUserData,
+ const XML_Char* aVersion,
+ const XML_Char* aEncoding,
+ int aStandalone) {
+ NS_ASSERTION(aUserData, "expat driver should exist");
+ if (aUserData) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
+ driver->HandleXMLDeclaration(aVersion, aEncoding, aStandalone);
+ }
+}
+
+static void Driver_HandleCharacterData(void* aUserData, const XML_Char* aData,
+ int aLength) {
+ NS_ASSERTION(aUserData, "expat driver should exist");
+ if (aUserData) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
+ driver->HandleCharacterData(aData, uint32_t(aLength));
+ }
+}
+
+static void Driver_HandleComment(void* aUserData, const XML_Char* aName) {
+ NS_ASSERTION(aUserData, "expat driver should exist");
+ if (aUserData) {
+ static_cast<nsExpatDriver*>(aUserData)->HandleComment(aName);
+ }
+}
+
+static void Driver_HandleProcessingInstruction(void* aUserData,
+ const XML_Char* aTarget,
+ const XML_Char* aData) {
+ NS_ASSERTION(aUserData, "expat driver should exist");
+ if (aUserData) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
+ driver->HandleProcessingInstruction(aTarget, aData);
+ }
+}
+
+static void Driver_HandleDefault(void* aUserData, const XML_Char* aData,
+ int aLength) {
+ NS_ASSERTION(aUserData, "expat driver should exist");
+ if (aUserData) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aUserData);
+ driver->HandleDefault(aData, uint32_t(aLength));
+ }
+}
+
+static void Driver_HandleStartCdataSection(void* aUserData) {
+ NS_ASSERTION(aUserData, "expat driver should exist");
+ if (aUserData) {
+ static_cast<nsExpatDriver*>(aUserData)->HandleStartCdataSection();
+ }
+}
+
+static void Driver_HandleEndCdataSection(void* aUserData) {
+ NS_ASSERTION(aUserData, "expat driver should exist");
+ if (aUserData) {
+ static_cast<nsExpatDriver*>(aUserData)->HandleEndCdataSection();
+ }
+}
+
+static void Driver_HandleStartDoctypeDecl(void* aUserData,
+ const XML_Char* aDoctypeName,
+ const XML_Char* aSysid,
+ const XML_Char* aPubid,
+ int aHasInternalSubset) {
+ NS_ASSERTION(aUserData, "expat driver should exist");
+ if (aUserData) {
+ static_cast<nsExpatDriver*>(aUserData)->HandleStartDoctypeDecl(
+ aDoctypeName, aSysid, aPubid, !!aHasInternalSubset);
+ }
+}
+
+static void Driver_HandleEndDoctypeDecl(void* aUserData) {
+ NS_ASSERTION(aUserData, "expat driver should exist");
+ if (aUserData) {
+ static_cast<nsExpatDriver*>(aUserData)->HandleEndDoctypeDecl();
+ }
+}
+
+static int Driver_HandleExternalEntityRef(void* aExternalEntityRefHandler,
+ const XML_Char* aOpenEntityNames,
+ const XML_Char* aBase,
+ const XML_Char* aSystemId,
+ const XML_Char* aPublicId) {
+ NS_ASSERTION(aExternalEntityRefHandler, "expat driver should exist");
+ if (!aExternalEntityRefHandler) {
+ return 1;
+ }
+
+ nsExpatDriver* driver =
+ static_cast<nsExpatDriver*>(aExternalEntityRefHandler);
+
+ return driver->HandleExternalEntityRef(aOpenEntityNames, aBase, aSystemId,
+ aPublicId);
+}
+
+/***************************** END CALL BACKS ********************************/
+
+/***************************** CATALOG UTILS *********************************/
+
+// Initially added for bug 113400 to switch from the remote "XHTML 1.0 plus
+// MathML 2.0" DTD to the the lightweight customized version that Mozilla uses.
+// Since Mozilla is not validating, no need to fetch a *huge* file at each
+// click.
+// XXX The cleanest solution here would be to fix Bug 98413: Implement XML
+// Catalogs.
+struct nsCatalogData {
+ const char* mPublicID;
+ const char* mLocalDTD;
+ const char* mAgentSheet;
+};
+
+// The order of this table is guestimated to be in the optimum order
+static const nsCatalogData kCatalogTable[] = {
+ {"-//W3C//DTD XHTML 1.0 Transitional//EN", "htmlmathml-f.ent", nullptr},
+ {"-//W3C//DTD XHTML 1.1//EN", "htmlmathml-f.ent", nullptr},
+ {"-//W3C//DTD XHTML 1.0 Strict//EN", "htmlmathml-f.ent", nullptr},
+ {"-//W3C//DTD XHTML 1.0 Frameset//EN", "htmlmathml-f.ent", nullptr},
+ {"-//W3C//DTD XHTML Basic 1.0//EN", "htmlmathml-f.ent", nullptr},
+ {"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN", "htmlmathml-f.ent", nullptr},
+ {"-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN",
+ "htmlmathml-f.ent", nullptr},
+ {"-//W3C//DTD MathML 2.0//EN", "htmlmathml-f.ent", nullptr},
+ {"-//WAPFORUM//DTD XHTML Mobile 1.0//EN", "htmlmathml-f.ent", nullptr},
+ {nullptr, nullptr, nullptr}};
+
+static const nsCatalogData* LookupCatalogData(const char16_t* aPublicID) {
+ nsDependentString publicID(aPublicID);
+
+ // linear search for now since the number of entries is going to
+ // be negligible, and the fix for bug 98413 would get rid of this
+ // code anyway
+ const nsCatalogData* data = kCatalogTable;
+ while (data->mPublicID) {
+ if (publicID.EqualsASCII(data->mPublicID)) {
+ return data;
+ }
+ ++data;
+ }
+
+ return nullptr;
+}
+
+// This function provides a resource URI to a local DTD
+// in resource://gre/res/dtd/ which may or may not exist.
+// If aCatalogData is provided, it is used to remap the
+// DTD instead of taking the filename from the URI. aDTD
+// may be null in some cases that are relying on
+// aCatalogData working for them.
+static void GetLocalDTDURI(const nsCatalogData* aCatalogData, nsIURI* aDTD,
+ nsIURI** aResult) {
+ nsAutoCString fileName;
+ if (aCatalogData) {
+ // remap the DTD to a known local DTD
+ fileName.Assign(aCatalogData->mLocalDTD);
+ }
+
+ if (fileName.IsEmpty()) {
+ // Try to see if the user has installed the DTD file -- we extract the
+ // filename.ext of the DTD here. Hence, for any DTD for which we have
+ // no predefined mapping, users just have to copy the DTD file to our
+ // special DTD directory and it will be picked.
+ nsCOMPtr<nsIURL> dtdURL = do_QueryInterface(aDTD);
+ if (!dtdURL) {
+ // Not a URL with a filename, or maybe it was null. Either way, nothing
+ // else we can do here.
+ return;
+ }
+
+ dtdURL->GetFileName(fileName);
+ if (fileName.IsEmpty()) {
+ return;
+ }
+ }
+
+ nsAutoCString respath("resource://gre/res/dtd/");
+ respath += fileName;
+ NS_NewURI(aResult, respath);
+}
+
+/***************************** END CATALOG UTILS *****************************/
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsExpatDriver)
+ NS_INTERFACE_MAP_ENTRY(nsITokenizer)
+ NS_INTERFACE_MAP_ENTRY(nsIDTD)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDTD)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsExpatDriver)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsExpatDriver)
+
+NS_IMPL_CYCLE_COLLECTION(nsExpatDriver, mSink)
+
+nsExpatDriver::nsExpatDriver()
+ : mExpatParser(nullptr),
+ mInCData(false),
+ mInInternalSubset(false),
+ mInExternalDTD(false),
+ mMadeFinalCallToExpat(false),
+ mIsFinalChunk(false),
+ mInternalState(NS_OK),
+ mExpatBuffered(0),
+ mTagDepth(0),
+ mCatalogData(nullptr),
+ mInnerWindowID(0) {}
+
+nsExpatDriver::~nsExpatDriver() {
+ if (mExpatParser) {
+ XML_ParserFree(mExpatParser);
+ }
+}
+
+/* static */
+void nsExpatDriver::HandleStartElement(void* aUserData, const char16_t* aName,
+ const char16_t** aAtts) {
+ nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
+
+ NS_ASSERTION(self->mSink, "content sink not found!");
+
+ // Calculate the total number of elements in aAtts.
+ // XML_GetSpecifiedAttributeCount will only give us the number of specified
+ // attrs (twice that number, actually), so we have to check for default attrs
+ // ourselves.
+ uint32_t attrArrayLength;
+ for (attrArrayLength = XML_GetSpecifiedAttributeCount(self->mExpatParser);
+ aAtts[attrArrayLength]; attrArrayLength += 2) {
+ // Just looping till we find out what the length is
+ }
+
+ if (self->mSink) {
+ // We store the tagdepth in a PRUint16, so make sure the limit fits in a
+ // PRUint16.
+ static_assert(
+ sMaxXMLTreeDepth <=
+ std::numeric_limits<decltype(nsExpatDriver::mTagDepth)>::max());
+
+ if (++self->mTagDepth > sMaxXMLTreeDepth) {
+ self->MaybeStopParser(NS_ERROR_HTMLPARSER_HIERARCHYTOODEEP);
+ return;
+ }
+
+ nsresult rv = self->mSink->HandleStartElement(
+ aName, aAtts, attrArrayLength,
+ XML_GetCurrentLineNumber(self->mExpatParser),
+ XML_GetCurrentColumnNumber(self->mExpatParser));
+ self->MaybeStopParser(rv);
+ }
+}
+
+/* static */
+void nsExpatDriver::HandleStartElementForSystemPrincipal(
+ void* aUserData, const char16_t* aName, const char16_t** aAtts) {
+ nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
+
+ if (!MOZ_XML_ProcessingEntityValue(self->mExpatParser)) {
+ HandleStartElement(aUserData, aName, aAtts);
+ } else {
+ nsCOMPtr<Document> doc =
+ do_QueryInterface(self->mOriginalSink->GetTarget());
+
+ // Adjust the column number so that it is one based rather than zero based.
+ uint32_t colNumber = XML_GetCurrentColumnNumber(self->mExpatParser) + 1;
+ uint32_t lineNumber = XML_GetCurrentLineNumber(self->mExpatParser);
+
+ int32_t nameSpaceID;
+ RefPtr<nsAtom> prefix, localName;
+ nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
+ getter_AddRefs(localName), &nameSpaceID);
+
+ nsAutoString error;
+ error.AppendLiteral("Ignoring element <");
+ if (prefix) {
+ error.Append(prefix->GetUTF16String());
+ error.Append(':');
+ }
+ error.Append(localName->GetUTF16String());
+ error.AppendLiteral("> created from entity value.");
+
+ nsContentUtils::ReportToConsoleNonLocalized(
+ error, nsIScriptError::warningFlag, "XML Document"_ns, doc, nullptr,
+ u""_ns, lineNumber, colNumber);
+ }
+}
+
+/* static */
+void nsExpatDriver::HandleEndElement(void* aUserData, const char16_t* aName) {
+ nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
+
+ NS_ASSERTION(self->mSink, "content sink not found!");
+ NS_ASSERTION(self->mInternalState != NS_ERROR_HTMLPARSER_BLOCK,
+ "Shouldn't block from HandleStartElement.");
+
+ if (self->mSink && self->mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
+ nsresult rv = self->mSink->HandleEndElement(aName);
+ --self->mTagDepth;
+ self->MaybeStopParser(rv);
+ }
+}
+
+/* static */
+void nsExpatDriver::HandleEndElementForSystemPrincipal(void* aUserData,
+ const char16_t* aName) {
+ nsExpatDriver* self = static_cast<nsExpatDriver*>(aUserData);
+
+ if (!MOZ_XML_ProcessingEntityValue(self->mExpatParser)) {
+ HandleEndElement(aUserData, aName);
+ }
+}
+
+nsresult nsExpatDriver::HandleCharacterData(const char16_t* aValue,
+ const uint32_t aLength) {
+ NS_ASSERTION(mSink, "content sink not found!");
+
+ if (mInCData) {
+ if (!mCDataText.Append(aValue, aLength, fallible)) {
+ MaybeStopParser(NS_ERROR_OUT_OF_MEMORY);
+ }
+ } else if (mSink) {
+ nsresult rv = mSink->HandleCharacterData(aValue, aLength);
+ MaybeStopParser(rv);
+ }
+
+ return NS_OK;
+}
+
+nsresult nsExpatDriver::HandleComment(const char16_t* aValue) {
+ NS_ASSERTION(mSink, "content sink not found!");
+
+ if (mInExternalDTD) {
+ // Ignore comments from external DTDs
+ return NS_OK;
+ }
+
+ if (mInInternalSubset) {
+ mInternalSubset.AppendLiteral("<!--");
+ mInternalSubset.Append(aValue);
+ mInternalSubset.AppendLiteral("-->");
+ } else if (mSink) {
+ nsresult rv = mSink->HandleComment(aValue);
+ MaybeStopParser(rv);
+ }
+
+ return NS_OK;
+}
+
+nsresult nsExpatDriver::HandleProcessingInstruction(const char16_t* aTarget,
+ const char16_t* aData) {
+ NS_ASSERTION(mSink, "content sink not found!");
+
+ if (mInExternalDTD) {
+ // Ignore PIs in external DTDs for now. Eventually we want to
+ // pass them to the sink in a way that doesn't put them in the DOM
+ return NS_OK;
+ }
+
+ if (mInInternalSubset) {
+ mInternalSubset.AppendLiteral("<?");
+ mInternalSubset.Append(aTarget);
+ mInternalSubset.Append(' ');
+ mInternalSubset.Append(aData);
+ mInternalSubset.AppendLiteral("?>");
+ } else if (mSink) {
+ nsresult rv = mSink->HandleProcessingInstruction(aTarget, aData);
+ MaybeStopParser(rv);
+ }
+
+ return NS_OK;
+}
+
+nsresult nsExpatDriver::HandleXMLDeclaration(const char16_t* aVersion,
+ const char16_t* aEncoding,
+ int32_t aStandalone) {
+ if (mSink) {
+ nsresult rv = mSink->HandleXMLDeclaration(aVersion, aEncoding, aStandalone);
+ MaybeStopParser(rv);
+ }
+
+ return NS_OK;
+}
+
+nsresult nsExpatDriver::HandleDefault(const char16_t* aValue,
+ const uint32_t aLength) {
+ NS_ASSERTION(mSink, "content sink not found!");
+
+ if (mInExternalDTD) {
+ // Ignore newlines in external DTDs
+ return NS_OK;
+ }
+
+ if (mInInternalSubset) {
+ mInternalSubset.Append(aValue, aLength);
+ } else if (mSink) {
+ uint32_t i;
+ nsresult rv = mInternalState;
+ for (i = 0; i < aLength && NS_SUCCEEDED(rv); ++i) {
+ if (aValue[i] == '\n' || aValue[i] == '\r') {
+ rv = mSink->HandleCharacterData(&aValue[i], 1);
+ }
+ }
+ MaybeStopParser(rv);
+ }
+
+ return NS_OK;
+}
+
+nsresult nsExpatDriver::HandleStartCdataSection() {
+ mInCData = true;
+
+ return NS_OK;
+}
+
+nsresult nsExpatDriver::HandleEndCdataSection() {
+ NS_ASSERTION(mSink, "content sink not found!");
+
+ mInCData = false;
+ if (mSink) {
+ nsresult rv =
+ mSink->HandleCDataSection(mCDataText.get(), mCDataText.Length());
+ MaybeStopParser(rv);
+ }
+ mCDataText.Truncate();
+
+ return NS_OK;
+}
+
+nsresult nsExpatDriver::HandleStartDoctypeDecl(const char16_t* aDoctypeName,
+ const char16_t* aSysid,
+ const char16_t* aPubid,
+ bool aHasInternalSubset) {
+ mDoctypeName = aDoctypeName;
+ mSystemID = aSysid;
+ mPublicID = aPubid;
+
+ if (aHasInternalSubset) {
+ // Consuming a huge internal subset translates to numerous
+ // allocations. In an effort to avoid too many allocations
+ // setting mInternalSubset's capacity to be 1K ( just a guesstimate! ).
+ mInInternalSubset = true;
+ mInternalSubset.SetCapacity(1024);
+ } else {
+ // Distinguish missing internal subset from an empty one
+ mInternalSubset.SetIsVoid(true);
+ }
+
+ return NS_OK;
+}
+
+nsresult nsExpatDriver::HandleEndDoctypeDecl() {
+ NS_ASSERTION(mSink, "content sink not found!");
+
+ mInInternalSubset = false;
+
+ if (mSink) {
+ // let the sink know any additional knowledge that we have about the
+ // document (currently, from bug 124570, we only expect to pass additional
+ // agent sheets needed to layout the XML vocabulary of the document)
+ nsCOMPtr<nsIURI> data;
+#if 0
+ if (mCatalogData && mCatalogData->mAgentSheet) {
+ NS_NewURI(getter_AddRefs(data), mCatalogData->mAgentSheet);
+ }
+#endif
+
+ // The unused support for "catalog style sheets" was removed. It doesn't
+ // look like we'll ever fix bug 98413 either.
+ MOZ_ASSERT(!mCatalogData || !mCatalogData->mAgentSheet,
+ "Need to add back support for catalog style sheets");
+
+ // Note: mInternalSubset already doesn't include the [] around it.
+ nsresult rv = mSink->HandleDoctypeDecl(mInternalSubset, mDoctypeName,
+ mSystemID, mPublicID, data);
+ MaybeStopParser(rv);
+ }
+
+ mInternalSubset.Truncate();
+
+ return NS_OK;
+}
+
+static nsresult ExternalDTDStreamReaderFunc(nsIUnicharInputStream* aIn,
+ void* aClosure,
+ const char16_t* aFromSegment,
+ uint32_t aToOffset, uint32_t aCount,
+ uint32_t* aWriteCount) {
+ // Pass the buffer to expat for parsing.
+ if (XML_Parse((XML_Parser)aClosure, (const char*)aFromSegment,
+ aCount * sizeof(char16_t), 0) == XML_STATUS_OK) {
+ *aWriteCount = aCount;
+
+ return NS_OK;
+ }
+
+ *aWriteCount = 0;
+
+ return NS_ERROR_FAILURE;
+}
+
+int nsExpatDriver::HandleExternalEntityRef(const char16_t* openEntityNames,
+ const char16_t* base,
+ const char16_t* systemId,
+ const char16_t* publicId) {
+ if (mInInternalSubset && !mInExternalDTD && openEntityNames) {
+ mInternalSubset.Append(char16_t('%'));
+ mInternalSubset.Append(nsDependentString(openEntityNames));
+ mInternalSubset.Append(char16_t(';'));
+ }
+
+ // Load the external entity into a buffer.
+ nsCOMPtr<nsIInputStream> in;
+ nsAutoString absURL;
+ nsresult rv = OpenInputStreamFromExternalDTD(publicId, systemId, base,
+ getter_AddRefs(in), absURL);
+ if (NS_FAILED(rv)) {
+#ifdef DEBUG
+ nsCString message("Failed to open external DTD: publicId \"");
+ AppendUTF16toUTF8(MakeStringSpan(publicId), message);
+ message += "\" systemId \"";
+ AppendUTF16toUTF8(MakeStringSpan(systemId), message);
+ message += "\" base \"";
+ AppendUTF16toUTF8(MakeStringSpan(base), message);
+ message += "\" URL \"";
+ AppendUTF16toUTF8(absURL, message);
+ message += "\"";
+ NS_WARNING(message.get());
+#endif
+ return 1;
+ }
+
+ nsCOMPtr<nsIUnicharInputStream> uniIn;
+ rv = NS_NewUnicharInputStream(in, getter_AddRefs(uniIn));
+ NS_ENSURE_SUCCESS(rv, 1);
+
+ int result = 1;
+ if (uniIn) {
+ XML_Parser entParser =
+ XML_ExternalEntityParserCreate(mExpatParser, 0, kUTF16);
+ if (entParser) {
+ XML_SetBase(entParser, absURL.get());
+
+ mInExternalDTD = true;
+
+ uint32_t totalRead;
+ do {
+ rv = uniIn->ReadSegments(ExternalDTDStreamReaderFunc, entParser,
+ uint32_t(-1), &totalRead);
+ } while (NS_SUCCEEDED(rv) && totalRead > 0);
+
+ result = XML_Parse(entParser, nullptr, 0, 1);
+
+ mInExternalDTD = false;
+
+ XML_ParserFree(entParser);
+ }
+ }
+
+ return result;
+}
+
+nsresult nsExpatDriver::OpenInputStreamFromExternalDTD(const char16_t* aFPIStr,
+ const char16_t* aURLStr,
+ const char16_t* aBaseURL,
+ nsIInputStream** aStream,
+ nsAString& aAbsURL) {
+ nsCOMPtr<nsIURI> baseURI;
+ nsresult rv =
+ NS_NewURI(getter_AddRefs(baseURI), NS_ConvertUTF16toUTF8(aBaseURL));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIURI> uri;
+ rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(aURLStr), nullptr,
+ baseURI);
+ // Even if the URI is malformed (most likely because we have a
+ // non-hierarchical base URI and a relative DTD URI, with the latter
+ // being the normal XHTML DTD case), we can try to see whether we
+ // have catalog data for aFPIStr.
+ if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_MALFORMED_URI)) {
+ return rv;
+ }
+
+ // make sure the URI, if we have one, is allowed to be loaded in sync
+ bool isUIResource = false;
+ if (uri) {
+ rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_UI_RESOURCE,
+ &isUIResource);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ nsCOMPtr<nsIURI> localURI;
+ if (!isUIResource) {
+ // Check to see if we can map the DTD to a known local DTD, or if a DTD
+ // file of the same name exists in the special DTD directory
+ if (aFPIStr) {
+ // see if the Formal Public Identifier (FPI) maps to a catalog entry
+ mCatalogData = LookupCatalogData(aFPIStr);
+ GetLocalDTDURI(mCatalogData, uri, getter_AddRefs(localURI));
+ }
+ if (!localURI) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ }
+
+ nsCOMPtr<nsIChannel> channel;
+ if (localURI) {
+ localURI.swap(uri);
+ rv = NS_NewChannel(getter_AddRefs(channel), uri,
+ nsContentUtils::GetSystemPrincipal(),
+ nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ nsIContentPolicy::TYPE_DTD);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ NS_ASSERTION(
+ mSink == nsCOMPtr<nsIExpatSink>(do_QueryInterface(mOriginalSink)),
+ "In nsExpatDriver::OpenInputStreamFromExternalDTD: "
+ "mOriginalSink not the same object as mSink?");
+ nsContentPolicyType policyType = nsIContentPolicy::TYPE_INTERNAL_DTD;
+ if (mOriginalSink) {
+ nsCOMPtr<Document> doc;
+ doc = do_QueryInterface(mOriginalSink->GetTarget());
+ if (doc) {
+ if (doc->SkipDTDSecurityChecks()) {
+ policyType = nsIContentPolicy::TYPE_INTERNAL_FORCE_ALLOWED_DTD;
+ }
+ rv = NS_NewChannel(
+ getter_AddRefs(channel), uri, doc,
+ nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT |
+ nsILoadInfo::SEC_ALLOW_CHROME,
+ policyType);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+ if (!channel) {
+ nsCOMPtr<nsIPrincipal> nullPrincipal =
+ mozilla::NullPrincipal::CreateWithoutOriginAttributes();
+ rv = NS_NewChannel(
+ getter_AddRefs(channel), uri, nullPrincipal,
+ nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT |
+ nsILoadInfo::SEC_ALLOW_CHROME,
+ policyType);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ nsAutoCString absURL;
+ rv = uri->GetSpec(absURL);
+ NS_ENSURE_SUCCESS(rv, rv);
+ CopyUTF8toUTF16(absURL, aAbsURL);
+
+ channel->SetContentType("application/xml"_ns);
+ return channel->Open(aStream);
+}
+
+static nsresult CreateErrorText(const char16_t* aDescription,
+ const char16_t* aSourceURL,
+ const uint32_t aLineNumber,
+ const uint32_t aColNumber,
+ nsString& aErrorString, bool spoofEnglish) {
+ aErrorString.Truncate();
+
+ nsAutoString msg;
+ nsresult rv = nsParserMsgUtils::GetLocalizedStringByName(
+ spoofEnglish ? XMLPARSER_PROPERTIES_en_US : XMLPARSER_PROPERTIES,
+ "XMLParsingError", msg);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // XML Parsing Error: %1$S\nLocation: %2$S\nLine Number %3$u, Column %4$u:
+ nsTextFormatter::ssprintf(aErrorString, msg.get(), aDescription, aSourceURL,
+ aLineNumber, aColNumber);
+ return NS_OK;
+}
+
+static nsresult AppendErrorPointer(const int32_t aColNumber,
+ const char16_t* aSourceLine,
+ nsString& aSourceString) {
+ aSourceString.Append(char16_t('\n'));
+
+ // Last character will be '^'.
+ int32_t last = aColNumber - 1;
+ int32_t i;
+ uint32_t minuses = 0;
+ for (i = 0; i < last; ++i) {
+ if (aSourceLine[i] == '\t') {
+ // Since this uses |white-space: pre;| a tab stop equals 8 spaces.
+ uint32_t add = 8 - (minuses % 8);
+ aSourceString.AppendASCII("--------", add);
+ minuses += add;
+ } else {
+ aSourceString.Append(char16_t('-'));
+ ++minuses;
+ }
+ }
+ aSourceString.Append(char16_t('^'));
+
+ return NS_OK;
+}
+
+nsresult nsExpatDriver::HandleError() {
+ int32_t code = XML_GetErrorCode(mExpatParser);
+ NS_ASSERTION(code > XML_ERROR_NONE, "unexpected XML error code");
+
+ // Map Expat error code to an error string
+ // XXX Deal with error returns.
+ nsAutoString description;
+ nsCOMPtr<Document> doc;
+ if (mOriginalSink) {
+ doc = do_QueryInterface(mOriginalSink->GetTarget());
+ }
+
+ bool spoofEnglish =
+ nsContentUtils::SpoofLocaleEnglish() && (!doc || !doc->AllowsL10n());
+ nsParserMsgUtils::GetLocalizedStringByID(
+ spoofEnglish ? XMLPARSER_PROPERTIES_en_US : XMLPARSER_PROPERTIES, code,
+ description);
+
+ if (code == XML_ERROR_TAG_MISMATCH) {
+ /**
+ * Expat can send the following:
+ * localName
+ * namespaceURI<separator>localName
+ * namespaceURI<separator>localName<separator>prefix
+ *
+ * and we use 0xFFFF for the <separator>.
+ *
+ */
+ const char16_t* mismatch = MOZ_XML_GetMismatchedTag(mExpatParser);
+ const char16_t* uriEnd = nullptr;
+ const char16_t* nameEnd = nullptr;
+ const char16_t* pos;
+ for (pos = mismatch; *pos; ++pos) {
+ if (*pos == kExpatSeparatorChar) {
+ if (uriEnd) {
+ nameEnd = pos;
+ } else {
+ uriEnd = pos;
+ }
+ }
+ }
+
+ nsAutoString tagName;
+ if (uriEnd && nameEnd) {
+ // We have a prefix.
+ tagName.Append(nameEnd + 1, pos - nameEnd - 1);
+ tagName.Append(char16_t(':'));
+ }
+ const char16_t* nameStart = uriEnd ? uriEnd + 1 : mismatch;
+ tagName.Append(nameStart, (nameEnd ? nameEnd : pos) - nameStart);
+
+ nsAutoString msg;
+ nsParserMsgUtils::GetLocalizedStringByName(
+ spoofEnglish ? XMLPARSER_PROPERTIES_en_US : XMLPARSER_PROPERTIES,
+ "Expected", msg);
+
+ // . Expected: </%S>.
+ nsAutoString message;
+ nsTextFormatter::ssprintf(message, msg.get(), tagName.get());
+ description.Append(message);
+ }
+
+ // Adjust the column number so that it is one based rather than zero based.
+ uint32_t colNumber = XML_GetCurrentColumnNumber(mExpatParser) + 1;
+ uint32_t lineNumber = XML_GetCurrentLineNumber(mExpatParser);
+
+ nsAutoString errorText;
+ CreateErrorText(description.get(), XML_GetBase(mExpatParser), lineNumber,
+ colNumber, errorText, spoofEnglish);
+
+ nsAutoString sourceText(mLastLine);
+ AppendErrorPointer(colNumber, mLastLine.get(), sourceText);
+
+ if (doc && nsContentUtils::IsChromeDoc(doc)) {
+ nsCString path = doc->GetDocumentURI()->GetSpecOrDefault();
+
+ mozilla::Maybe<nsTArray<mozilla::Telemetry::EventExtraEntry>> extra =
+ mozilla::Some<nsTArray<mozilla::Telemetry::EventExtraEntry>>({
+ mozilla::Telemetry::EventExtraEntry{"error_code"_ns,
+ nsPrintfCString("%u", code)},
+ mozilla::Telemetry::EventExtraEntry{
+ "location"_ns, nsPrintfCString("%u:%u", lineNumber, colNumber)},
+ mozilla::Telemetry::EventExtraEntry{
+ "last_line"_ns, NS_ConvertUTF16toUTF8(mLastLine)},
+ mozilla::Telemetry::EventExtraEntry{
+ "last_line_len"_ns, nsPrintfCString("%u", mLastLine.Length())},
+ });
+
+ mozilla::Telemetry::SetEventRecordingEnabled("ysod"_ns, true);
+ mozilla::Telemetry::RecordEvent(
+ mozilla::Telemetry::EventID::Ysod_Shown_Ysod, mozilla::Some(path),
+ extra);
+ }
+
+ // Try to create and initialize the script error.
+ nsCOMPtr<nsIScriptError> serr(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
+ nsresult rv = NS_ERROR_FAILURE;
+ if (serr) {
+ rv = serr->InitWithWindowID(errorText, mURISpec, mLastLine, lineNumber,
+ colNumber, nsIScriptError::errorFlag,
+ "malformed-xml", mInnerWindowID);
+ }
+
+ // If it didn't initialize, we can't do any logging.
+ bool shouldReportError = NS_SUCCEEDED(rv);
+
+ // mSink might be null here if our parser was terminated.
+ if (mSink && shouldReportError) {
+ rv = mSink->ReportError(errorText.get(), sourceText.get(), serr,
+ &shouldReportError);
+ if (NS_FAILED(rv)) {
+ shouldReportError = true;
+ }
+ }
+
+ // mOriginalSink might be null here if our parser was terminated.
+ if (mOriginalSink) {
+ nsCOMPtr<Document> doc = do_QueryInterface(mOriginalSink->GetTarget());
+ if (doc && doc->SuppressParserErrorConsoleMessages()) {
+ shouldReportError = false;
+ }
+ }
+
+ if (shouldReportError) {
+ nsCOMPtr<nsIConsoleService> cs(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
+ if (cs) {
+ cs->LogMessage(serr);
+ }
+ }
+
+ return NS_ERROR_HTMLPARSER_STOPPARSING;
+}
+
+void nsExpatDriver::ParseBuffer(const char16_t* aBuffer, uint32_t aLength,
+ bool aIsFinal, uint32_t* aConsumed) {
+ NS_ASSERTION((aBuffer && aLength != 0) || (!aBuffer && aLength == 0), "?");
+ NS_ASSERTION(mInternalState != NS_OK || aIsFinal || aBuffer,
+ "Useless call, we won't call Expat");
+ MOZ_ASSERT(!BlockedOrInterrupted() || !aBuffer,
+ "Non-null buffer when resuming");
+ MOZ_ASSERT(XML_GetCurrentByteIndex(mExpatParser) % sizeof(char16_t) == 0,
+ "Consumed part of a char16_t?");
+
+ if (mExpatParser && (mInternalState == NS_OK || BlockedOrInterrupted())) {
+ int32_t parserBytesBefore = XML_GetCurrentByteIndex(mExpatParser);
+ NS_ASSERTION(parserBytesBefore >= 0, "Unexpected value");
+
+ XML_Status status;
+ if (BlockedOrInterrupted()) {
+ mInternalState = NS_OK; // Resume in case we're blocked.
+ status = XML_ResumeParser(mExpatParser);
+ } else {
+ status = XML_Parse(mExpatParser, reinterpret_cast<const char*>(aBuffer),
+ aLength * sizeof(char16_t), aIsFinal);
+ }
+
+ int32_t parserBytesConsumed = XML_GetCurrentByteIndex(mExpatParser);
+
+ NS_ASSERTION(parserBytesConsumed >= 0, "Unexpected value");
+ NS_ASSERTION(parserBytesConsumed >= parserBytesBefore,
+ "How'd this happen?");
+ NS_ASSERTION(parserBytesConsumed % sizeof(char16_t) == 0,
+ "Consumed part of a char16_t?");
+
+ // Consumed something.
+ *aConsumed = (parserBytesConsumed - parserBytesBefore) / sizeof(char16_t);
+ NS_ASSERTION(*aConsumed <= aLength + mExpatBuffered,
+ "Too many bytes consumed?");
+
+ NS_ASSERTION(status != XML_STATUS_SUSPENDED || BlockedOrInterrupted(),
+ "Inconsistent expat suspension state.");
+
+ if (status == XML_STATUS_ERROR) {
+ mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
+ }
+ } else {
+ *aConsumed = 0;
+ }
+}
+
+NS_IMETHODIMP
+nsExpatDriver::ConsumeToken(nsScanner& aScanner, bool& aFlushTokens) {
+ // We keep the scanner pointing to the position where Expat will start
+ // parsing.
+ nsScannerIterator currentExpatPosition;
+ aScanner.CurrentPosition(currentExpatPosition);
+
+ // This is the start of the first buffer that we need to pass to Expat.
+ nsScannerIterator start = currentExpatPosition;
+ start.advance(mExpatBuffered);
+
+ // This is the end of the last buffer (at this point, more data could come in
+ // later).
+ nsScannerIterator end;
+ aScanner.EndReading(end);
+
+ MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
+ ("Remaining in expat's buffer: %i, remaining in scanner: %zu.",
+ mExpatBuffered, Distance(start, end)));
+
+ // We want to call Expat if we have more buffers, or if we know there won't
+ // be more buffers (and so we want to flush the remaining data), or if we're
+ // currently blocked and there's data in Expat's buffer.
+ while (start != end || (mIsFinalChunk && !mMadeFinalCallToExpat) ||
+ (BlockedOrInterrupted() && mExpatBuffered > 0)) {
+ bool noMoreBuffers = start == end && mIsFinalChunk;
+ bool blocked = BlockedOrInterrupted();
+
+ const char16_t* buffer;
+ uint32_t length;
+ if (blocked || noMoreBuffers) {
+ // If we're blocked we just resume Expat so we don't need a buffer, if
+ // there aren't any more buffers we pass a null buffer to Expat.
+ buffer = nullptr;
+ length = 0;
+
+ if (blocked) {
+ MOZ_LOG(
+ gExpatDriverLog, LogLevel::Debug,
+ ("Resuming Expat, will parse data remaining in Expat's "
+ "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n",
+ NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered)
+ .get()));
+ } else {
+ NS_ASSERTION(mExpatBuffered == Distance(currentExpatPosition, end),
+ "Didn't pass all the data to Expat?");
+ MOZ_LOG(
+ gExpatDriverLog, LogLevel::Debug,
+ ("Last call to Expat, will parse data remaining in Expat's "
+ "buffer.\nContent of Expat's buffer:\n-----\n%s\n-----\n",
+ NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered)
+ .get()));
+ }
+ } else {
+ buffer = start.get();
+ length = uint32_t(start.size_forward());
+
+ MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
+ ("Calling Expat, will parse data remaining in Expat's buffer and "
+ "new data.\nContent of Expat's buffer:\n-----\n%s\n-----\nNew "
+ "data:\n-----\n%s\n-----\n",
+ NS_ConvertUTF16toUTF8(currentExpatPosition.get(), mExpatBuffered)
+ .get(),
+ NS_ConvertUTF16toUTF8(start.get(), length).get()));
+ }
+
+ uint32_t consumed;
+ ParseBuffer(buffer, length, noMoreBuffers, &consumed);
+ if (consumed > 0) {
+ nsScannerIterator oldExpatPosition = currentExpatPosition;
+ currentExpatPosition.advance(consumed);
+
+ // We consumed some data, we want to store the last line of data that
+ // was consumed in case we run into an error (to show the line in which
+ // the error occurred).
+
+ // The length of the last line that Expat has parsed.
+ XML_Size lastLineLength = XML_GetCurrentColumnNumber(mExpatParser);
+
+ if (lastLineLength <= consumed) {
+ // The length of the last line was less than what expat consumed, so
+ // there was at least one line break in the consumed data. Store the
+ // last line until the point where we stopped parsing.
+ nsScannerIterator startLastLine = currentExpatPosition;
+ startLastLine.advance(-((ptrdiff_t)lastLineLength));
+ if (!CopyUnicodeTo(startLastLine, currentExpatPosition, mLastLine)) {
+ return (mInternalState = NS_ERROR_OUT_OF_MEMORY);
+ }
+ } else {
+ // There was no line break in the consumed data, append the consumed
+ // data.
+ if (!AppendUnicodeTo(oldExpatPosition, currentExpatPosition,
+ mLastLine)) {
+ return (mInternalState = NS_ERROR_OUT_OF_MEMORY);
+ }
+ }
+ }
+
+ mExpatBuffered += length - consumed;
+
+ if (BlockedOrInterrupted()) {
+ MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
+ ("Blocked or interrupted parser (probably for loading linked "
+ "stylesheets or scripts)."));
+
+ aScanner.SetPosition(currentExpatPosition, true);
+ aScanner.Mark();
+
+ return mInternalState;
+ }
+
+ if (noMoreBuffers && mExpatBuffered == 0) {
+ mMadeFinalCallToExpat = true;
+ }
+
+ if (NS_FAILED(mInternalState)) {
+ if (XML_GetErrorCode(mExpatParser) != XML_ERROR_NONE) {
+ NS_ASSERTION(mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING,
+ "Unexpected error");
+
+ // Look for the next newline after the last one we consumed
+ nsScannerIterator lastLine = currentExpatPosition;
+ while (lastLine != end) {
+ length = uint32_t(lastLine.size_forward());
+ uint32_t endOffset = 0;
+ const char16_t* buffer = lastLine.get();
+ while (endOffset < length && buffer[endOffset] != '\n' &&
+ buffer[endOffset] != '\r') {
+ ++endOffset;
+ }
+ mLastLine.Append(Substring(buffer, buffer + endOffset));
+ if (endOffset < length) {
+ // We found a newline.
+ break;
+ }
+
+ lastLine.advance(length);
+ }
+
+ HandleError();
+ }
+
+ return mInternalState;
+ }
+
+ // Either we have more buffers, or we were blocked (and we'll flush in the
+ // next iteration), or we should have emptied Expat's buffer.
+ NS_ASSERTION(!noMoreBuffers || blocked ||
+ (mExpatBuffered == 0 && currentExpatPosition == end),
+ "Unreachable data left in Expat's buffer");
+
+ start.advance(length);
+
+ // It's possible for start to have passed end if we received more data
+ // (e.g. if we spun the event loop in an inline script). Reload end now
+ // to compensate.
+ aScanner.EndReading(end);
+ }
+
+ aScanner.SetPosition(currentExpatPosition, true);
+ aScanner.Mark();
+
+ MOZ_LOG(gExpatDriverLog, LogLevel::Debug,
+ ("Remaining in expat's buffer: %i, remaining in scanner: %zu.",
+ mExpatBuffered, Distance(currentExpatPosition, end)));
+
+ return NS_SUCCEEDED(mInternalState) ? NS_ERROR_HTMLPARSER_EOF : NS_OK;
+}
+
+NS_IMETHODIMP
+nsExpatDriver::WillBuildModel(const CParserContext& aParserContext,
+ nsITokenizer* aTokenizer, nsIContentSink* aSink) {
+ mSink = do_QueryInterface(aSink);
+ if (!mSink) {
+ NS_ERROR("nsExpatDriver didn't get an nsIExpatSink");
+ // Make sure future calls to us bail out as needed
+ mInternalState = NS_ERROR_UNEXPECTED;
+ return mInternalState;
+ }
+
+ mOriginalSink = aSink;
+
+ static const XML_Memory_Handling_Suite memsuite = {malloc, realloc, free};
+
+ static const char16_t kExpatSeparator[] = {kExpatSeparatorChar, '\0'};
+
+ mExpatParser = XML_ParserCreate_MM(kUTF16, &memsuite, kExpatSeparator);
+ NS_ENSURE_TRUE(mExpatParser, NS_ERROR_FAILURE);
+
+ XML_SetReturnNSTriplet(mExpatParser, XML_TRUE);
+
+#ifdef XML_DTD
+ XML_SetParamEntityParsing(mExpatParser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+#endif
+
+ mURISpec = aParserContext.mScanner->GetFilename();
+
+ XML_SetBase(mExpatParser, mURISpec.get());
+
+ nsCOMPtr<Document> doc = do_QueryInterface(mOriginalSink->GetTarget());
+ if (doc) {
+ nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
+ nsCOMPtr<nsPIDOMWindowInner> inner;
+ if (win) {
+ inner = win->GetCurrentInnerWindow();
+ } else {
+ bool aHasHadScriptHandlingObject;
+ nsIScriptGlobalObject* global =
+ doc->GetScriptHandlingObject(aHasHadScriptHandlingObject);
+ if (global) {
+ inner = do_QueryInterface(global);
+ }
+ }
+ if (inner) {
+ mInnerWindowID = inner->WindowID();
+ }
+ }
+
+ // Set up the callbacks
+ XML_SetXmlDeclHandler(mExpatParser, Driver_HandleXMLDeclaration);
+ if (doc && doc->NodePrincipal()->IsSystemPrincipal()) {
+ XML_SetElementHandler(mExpatParser, HandleStartElementForSystemPrincipal,
+ HandleEndElementForSystemPrincipal);
+ } else {
+ XML_SetElementHandler(mExpatParser, HandleStartElement, HandleEndElement);
+ }
+ XML_SetCharacterDataHandler(mExpatParser, Driver_HandleCharacterData);
+ XML_SetProcessingInstructionHandler(mExpatParser,
+ Driver_HandleProcessingInstruction);
+ XML_SetDefaultHandlerExpand(mExpatParser, Driver_HandleDefault);
+ XML_SetExternalEntityRefHandler(
+ mExpatParser,
+ (XML_ExternalEntityRefHandler)Driver_HandleExternalEntityRef);
+ XML_SetExternalEntityRefHandlerArg(mExpatParser, this);
+ XML_SetCommentHandler(mExpatParser, Driver_HandleComment);
+ XML_SetCdataSectionHandler(mExpatParser, Driver_HandleStartCdataSection,
+ Driver_HandleEndCdataSection);
+
+ XML_SetParamEntityParsing(mExpatParser,
+ XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
+ XML_SetDoctypeDeclHandler(mExpatParser, Driver_HandleStartDoctypeDecl,
+ Driver_HandleEndDoctypeDecl);
+
+ // Set up the user data.
+ XML_SetUserData(mExpatParser, this);
+
+ return mInternalState;
+}
+
+NS_IMETHODIMP
+nsExpatDriver::BuildModel(nsITokenizer* aTokenizer, nsIContentSink* aSink) {
+ return mInternalState;
+}
+
+NS_IMETHODIMP
+nsExpatDriver::DidBuildModel(nsresult anErrorCode) {
+ mOriginalSink = nullptr;
+ mSink = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsExpatDriver::WillTokenize(bool aIsFinalChunk) {
+ mIsFinalChunk = aIsFinalChunk;
+ return NS_OK;
+}
+
+NS_IMETHODIMP_(void)
+nsExpatDriver::Terminate() {
+ // XXX - not sure what happens to the unparsed data.
+ if (mExpatParser) {
+ XML_StopParser(mExpatParser, XML_FALSE);
+ }
+ mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
+}
+
+NS_IMETHODIMP_(int32_t)
+nsExpatDriver::GetType() { return NS_IPARSER_FLAG_XML; }
+
+NS_IMETHODIMP_(nsDTDMode)
+nsExpatDriver::GetMode() const { return eDTDMode_full_standards; }
+
+/*************************** Unused methods **********************************/
+
+NS_IMETHODIMP_(bool)
+nsExpatDriver::IsContainer(int32_t aTag) const { return true; }
+
+NS_IMETHODIMP_(bool)
+nsExpatDriver::CanContain(int32_t aParent, int32_t aChild) const {
+ return true;
+}
+
+void nsExpatDriver::MaybeStopParser(nsresult aState) {
+ if (NS_FAILED(aState)) {
+ // If we had a failure we want to override NS_ERROR_HTMLPARSER_INTERRUPTED
+ // and we want to override NS_ERROR_HTMLPARSER_BLOCK but not with
+ // NS_ERROR_HTMLPARSER_INTERRUPTED.
+ if (NS_SUCCEEDED(mInternalState) ||
+ mInternalState == NS_ERROR_HTMLPARSER_INTERRUPTED ||
+ (mInternalState == NS_ERROR_HTMLPARSER_BLOCK &&
+ aState != NS_ERROR_HTMLPARSER_INTERRUPTED)) {
+ mInternalState = (aState == NS_ERROR_HTMLPARSER_INTERRUPTED ||
+ aState == NS_ERROR_HTMLPARSER_BLOCK)
+ ? aState
+ : NS_ERROR_HTMLPARSER_STOPPARSING;
+ }
+
+ // If we get an error then we need to stop Expat (by calling XML_StopParser
+ // with false as the last argument). If the parser should be blocked or
+ // interrupted we need to pause Expat (by calling XML_StopParser with
+ // true as the last argument).
+ XML_StopParser(mExpatParser, BlockedOrInterrupted());
+ } else if (NS_SUCCEEDED(mInternalState)) {
+ // Only clobber mInternalState with the success code if we didn't block or
+ // interrupt before.
+ mInternalState = aState;
+ }
+}
diff --git a/parser/htmlparser/nsExpatDriver.h b/parser/htmlparser/nsExpatDriver.h
new file mode 100644
index 0000000000..bd0e34abe8
--- /dev/null
+++ b/parser/htmlparser/nsExpatDriver.h
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef NS_EXPAT_DRIVER__
+#define NS_EXPAT_DRIVER__
+
+#include "expat_config.h"
+#include "expat.h"
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "nsIDTD.h"
+#include "nsITokenizer.h"
+#include "nsIInputStream.h"
+#include "nsIParser.h"
+#include "nsCycleCollectionParticipant.h"
+
+class nsIExpatSink;
+struct nsCatalogData;
+
+class nsExpatDriver : public nsIDTD, public nsITokenizer {
+ virtual ~nsExpatDriver();
+
+ public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_NSIDTD
+ NS_DECL_NSITOKENIZER
+ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsExpatDriver, nsIDTD)
+
+ nsExpatDriver();
+
+ int HandleExternalEntityRef(const char16_t* aOpenEntityNames,
+ const char16_t* aBase, const char16_t* aSystemId,
+ const char16_t* aPublicId);
+ static void HandleStartElement(void* aUserData, const char16_t* aName,
+ const char16_t** aAtts);
+ static void HandleStartElementForSystemPrincipal(void* aUserData,
+ const char16_t* aName,
+ const char16_t** aAtts);
+ static void HandleEndElement(void* aUserData, const char16_t* aName);
+ static void HandleEndElementForSystemPrincipal(void* aUserData,
+ const char16_t* aName);
+ nsresult HandleCharacterData(const char16_t* aCData, const uint32_t aLength);
+ nsresult HandleComment(const char16_t* aName);
+ nsresult HandleProcessingInstruction(const char16_t* aTarget,
+ const char16_t* aData);
+ nsresult HandleXMLDeclaration(const char16_t* aVersion,
+ const char16_t* aEncoding, int32_t aStandalone);
+ nsresult HandleDefault(const char16_t* aData, const uint32_t aLength);
+ nsresult HandleStartCdataSection();
+ nsresult HandleEndCdataSection();
+ nsresult HandleStartDoctypeDecl(const char16_t* aDoctypeName,
+ const char16_t* aSysid,
+ const char16_t* aPubid,
+ bool aHasInternalSubset);
+ nsresult HandleEndDoctypeDecl();
+
+ private:
+ // Load up an external stream to get external entity information
+ nsresult OpenInputStreamFromExternalDTD(const char16_t* aFPIStr,
+ const char16_t* aURLStr,
+ const char16_t* aBaseURL,
+ nsIInputStream** aStream,
+ nsAString& aAbsURL);
+
+ /**
+ * Pass a buffer to Expat. If Expat is blocked aBuffer should be null and
+ * aLength should be 0. The result of the call will be stored in
+ * mInternalState. Expat will parse as much of the buffer as it can and store
+ * the rest in its internal buffer.
+ *
+ * @param aBuffer the buffer to pass to Expat. May be null.
+ * @param aLength the length of the buffer to pass to Expat (in number of
+ * char16_t's). Must be 0 if aBuffer is null and > 0 if
+ * aBuffer is not null.
+ * @param aIsFinal whether there will definitely not be any more new buffers
+ * passed in to ParseBuffer
+ * @param aConsumed [out] the number of PRUnichars that Expat consumed. This
+ * doesn't include the PRUnichars that Expat stored in
+ * its buffer but didn't parse yet.
+ */
+ void ParseBuffer(const char16_t* aBuffer, uint32_t aLength, bool aIsFinal,
+ uint32_t* aConsumed);
+ nsresult HandleError();
+
+ void MaybeStopParser(nsresult aState);
+
+ bool BlockedOrInterrupted() {
+ return mInternalState == NS_ERROR_HTMLPARSER_BLOCK ||
+ mInternalState == NS_ERROR_HTMLPARSER_INTERRUPTED;
+ }
+
+ XML_Parser mExpatParser;
+ nsString mLastLine;
+ nsString mCDataText;
+ // Various parts of a doctype
+ nsString mDoctypeName;
+ nsString mSystemID;
+ nsString mPublicID;
+ nsString mInternalSubset;
+ bool mInCData;
+ bool mInInternalSubset;
+ bool mInExternalDTD;
+ bool mMadeFinalCallToExpat;
+
+ // Whether we're sure that we won't be getting more buffers to parse from
+ // Necko
+ bool mIsFinalChunk;
+
+ nsresult mInternalState;
+
+ // The length of the data in Expat's buffer (in number of PRUnichars).
+ uint32_t mExpatBuffered;
+
+ uint16_t mTagDepth;
+
+ // These sinks all refer the same conceptual object. mOriginalSink is
+ // identical with the nsIContentSink* passed to WillBuildModel, and exists
+ // only to avoid QI-ing back to nsIContentSink*.
+ nsCOMPtr<nsIContentSink> mOriginalSink;
+ nsCOMPtr<nsIExpatSink> mSink;
+
+ const nsCatalogData* mCatalogData; // weak
+ nsString mURISpec;
+
+ // Used for error reporting.
+ uint64_t mInnerWindowID;
+};
+
+#endif
diff --git a/parser/htmlparser/nsHTMLTagList.h b/parser/htmlparser/nsHTMLTagList.h
new file mode 100644
index 0000000000..9f9329da00
--- /dev/null
+++ b/parser/htmlparser/nsHTMLTagList.h
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// IWYU pragma: private, include "nsHTMLTags.h"
+
+/******
+
+ This file contains the list of all HTML tags.
+ See nsHTMLTags.h for access to the enum values for tags.
+
+ It is designed to be used as input to various places that will define the
+ HTML_TAG macro in useful ways through the magic of C preprocessing.
+ Additionally, it is consumed by the self-regeneration code in
+ ElementName.java from which nsHtml5ElementName.cpp/h is translated.
+ See parser/html/java/README.txt.
+
+ If you edit this list, you need to re-run ElementName.java
+ self-regeneration and the HTML parser Java to C++ translation.
+
+ All entries must be enclosed in the macro HTML_TAG which will have cruel
+ and unusual things done to it.
+
+ It is recommended (but not strictly necessary) to keep all entries
+ in alphabetical order.
+
+ The first argument to HTML_TAG is the tag name. The second argument is the
+ "creator" method of the form NS_New$TAGNAMEElement, that will be used by
+ nsHTMLContentSink.cpp to create a content object for a tag of that
+ type. Use NOTUSED, if the particular tag has a non-standard creator.
+ The third argument is the interface name specified for this element
+ in the HTML specification. It can be empty if the relevant interface name
+ is "HTMLElement".
+
+ The HTML_OTHER macro is for values in the nsHTMLTag enum that are
+ not strictly tags.
+
+ Entries *must* use only lowercase characters.
+
+ Don't forget to update /editor/libeditor/HTMLEditUtils.cpp as well.
+
+ ** Break these invariants and bad things will happen. **
+
+ ******/
+
+#define HTML_HTMLELEMENT_TAG(_tag) HTML_TAG(_tag, , )
+
+HTML_TAG(a, Anchor, Anchor)
+HTML_HTMLELEMENT_TAG(abbr)
+HTML_HTMLELEMENT_TAG(acronym)
+HTML_HTMLELEMENT_TAG(address)
+HTML_TAG(applet, Unknown, Unknown)
+HTML_TAG(area, Area, Area)
+HTML_HTMLELEMENT_TAG(article)
+HTML_HTMLELEMENT_TAG(aside)
+HTML_TAG(audio, Audio, Audio)
+HTML_HTMLELEMENT_TAG(b)
+HTML_TAG(base, Shared, Base)
+HTML_HTMLELEMENT_TAG(basefont)
+HTML_HTMLELEMENT_TAG(bdi)
+HTML_HTMLELEMENT_TAG(bdo)
+HTML_TAG(bgsound, Unknown, Unknown)
+HTML_HTMLELEMENT_TAG(big)
+HTML_TAG(blockquote, Shared, Quote)
+HTML_TAG(body, Body, Body)
+HTML_TAG(br, BR, BR)
+HTML_TAG(button, Button, Button)
+HTML_TAG(canvas, Canvas, Canvas)
+HTML_TAG(caption, TableCaption, TableCaption)
+HTML_HTMLELEMENT_TAG(center)
+HTML_HTMLELEMENT_TAG(cite)
+HTML_HTMLELEMENT_TAG(code)
+HTML_TAG(col, TableCol, TableCol)
+HTML_TAG(colgroup, TableCol, TableCol)
+HTML_TAG(data, Data, Data)
+HTML_TAG(datalist, DataList, DataList)
+HTML_HTMLELEMENT_TAG(dd)
+HTML_TAG(del, Mod, Mod)
+HTML_TAG(details, Details, Details)
+HTML_HTMLELEMENT_TAG(dfn)
+HTML_TAG(dialog, Dialog, Dialog)
+HTML_TAG(dir, Shared, Directory)
+HTML_TAG(div, Div, Div)
+HTML_TAG(dl, SharedList, DList)
+HTML_HTMLELEMENT_TAG(dt)
+HTML_HTMLELEMENT_TAG(em)
+HTML_TAG(embed, Embed, Embed)
+HTML_TAG(fieldset, FieldSet, FieldSet)
+HTML_HTMLELEMENT_TAG(figcaption)
+HTML_HTMLELEMENT_TAG(figure)
+HTML_TAG(font, Font, Font)
+HTML_HTMLELEMENT_TAG(footer)
+HTML_TAG(form, Form, Form)
+HTML_TAG(frame, Frame, Frame)
+HTML_TAG(frameset, FrameSet, FrameSet)
+HTML_TAG(h1, Heading, Heading)
+HTML_TAG(h2, Heading, Heading)
+HTML_TAG(h3, Heading, Heading)
+HTML_TAG(h4, Heading, Heading)
+HTML_TAG(h5, Heading, Heading)
+HTML_TAG(h6, Heading, Heading)
+HTML_TAG(head, Shared, Head)
+HTML_HTMLELEMENT_TAG(header)
+HTML_HTMLELEMENT_TAG(hgroup)
+HTML_TAG(hr, HR, HR)
+HTML_TAG(html, Shared, Html)
+HTML_HTMLELEMENT_TAG(i)
+HTML_TAG(iframe, IFrame, IFrame)
+HTML_HTMLELEMENT_TAG(image)
+HTML_TAG(img, Image, Image)
+HTML_TAG(input, Input, Input)
+HTML_TAG(ins, Mod, Mod)
+HTML_HTMLELEMENT_TAG(kbd)
+HTML_TAG(keygen, Unknown, Unknown)
+HTML_TAG(label, Label, Label)
+HTML_TAG(legend, Legend, Legend)
+HTML_TAG(li, LI, LI)
+HTML_TAG(link, Link, Link)
+HTML_TAG(listing, Pre, Pre)
+HTML_HTMLELEMENT_TAG(main)
+HTML_TAG(map, Map, Map)
+HTML_HTMLELEMENT_TAG(mark)
+HTML_TAG(marquee, Marquee, Marquee)
+HTML_TAG(menu, Menu, Menu)
+HTML_TAG(menuitem, MenuItem, MenuItem)
+HTML_TAG(meta, Meta, Meta)
+HTML_TAG(meter, Meter, Meter)
+HTML_TAG(multicol, Unknown, Unknown)
+HTML_HTMLELEMENT_TAG(nav)
+HTML_HTMLELEMENT_TAG(nobr)
+HTML_HTMLELEMENT_TAG(noembed)
+HTML_HTMLELEMENT_TAG(noframes)
+HTML_HTMLELEMENT_TAG(noscript)
+HTML_TAG(object, Object, Object)
+HTML_TAG(ol, SharedList, OList)
+HTML_TAG(optgroup, OptGroup, OptGroup)
+HTML_TAG(option, Option, Option)
+HTML_TAG(output, Output, Output)
+HTML_TAG(p, Paragraph, Paragraph)
+HTML_TAG(param, Shared, Param)
+HTML_TAG(picture, Picture, Picture)
+HTML_HTMLELEMENT_TAG(plaintext)
+HTML_TAG(pre, Pre, Pre)
+HTML_TAG(progress, Progress, Progress)
+HTML_TAG(q, Shared, Quote)
+HTML_HTMLELEMENT_TAG(rb)
+HTML_HTMLELEMENT_TAG(rp)
+HTML_HTMLELEMENT_TAG(rt)
+HTML_HTMLELEMENT_TAG(rtc)
+HTML_HTMLELEMENT_TAG(ruby)
+HTML_HTMLELEMENT_TAG(s)
+HTML_HTMLELEMENT_TAG(samp)
+HTML_TAG(script, Script, Script)
+HTML_HTMLELEMENT_TAG(section)
+HTML_TAG(select, Select, Select)
+HTML_HTMLELEMENT_TAG(small)
+HTML_TAG(slot, Slot, Slot)
+HTML_TAG(source, Source, Source)
+HTML_TAG(span, Span, Span)
+HTML_HTMLELEMENT_TAG(strike)
+HTML_HTMLELEMENT_TAG(strong)
+HTML_TAG(style, Style, Style)
+HTML_HTMLELEMENT_TAG(sub)
+HTML_TAG(summary, Summary, )
+HTML_HTMLELEMENT_TAG(sup)
+HTML_TAG(table, Table, Table)
+HTML_TAG(tbody, TableSection, TableSection)
+HTML_TAG(td, TableCell, TableCell)
+HTML_TAG(textarea, TextArea, TextArea)
+HTML_TAG(tfoot, TableSection, TableSection)
+HTML_TAG(th, TableCell, TableCell)
+HTML_TAG(thead, TableSection, TableSection)
+HTML_TAG(template, Template, Template)
+HTML_TAG(time, Time, Time)
+HTML_TAG(title, Title, Title)
+HTML_TAG(tr, TableRow, TableRow)
+HTML_TAG(track, Track, Track)
+HTML_HTMLELEMENT_TAG(tt)
+HTML_HTMLELEMENT_TAG(u)
+HTML_TAG(ul, SharedList, UList)
+HTML_HTMLELEMENT_TAG(var)
+HTML_TAG(video, Video, Video)
+HTML_HTMLELEMENT_TAG(wbr)
+HTML_TAG(xmp, Pre, Pre)
+
+/* These are not for tags. But they will be included in the nsHTMLTag
+ enum anyway */
+
+HTML_OTHER(text)
+HTML_OTHER(whitespace)
+HTML_OTHER(newline)
+HTML_OTHER(comment)
+HTML_OTHER(entity)
+HTML_OTHER(doctypeDecl)
+HTML_OTHER(markupDecl)
+HTML_OTHER(instruction)
+
+#undef HTML_HTMLELEMENT_TAG
diff --git a/parser/htmlparser/nsHTMLTags.cpp b/parser/htmlparser/nsHTMLTags.cpp
new file mode 100644
index 0000000000..512eeb7d6c
--- /dev/null
+++ b/parser/htmlparser/nsHTMLTags.cpp
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsHTMLTags.h"
+#include "nsCRT.h"
+#include "nsDataHashtable.h"
+#include "nsReadableUtils.h"
+#include "nsString.h"
+#include "nsUnicharUtils.h"
+#include "mozilla/HashFunctions.h"
+#include <algorithm>
+
+using namespace mozilla;
+
+// static array of unicode tag names
+#define HTML_TAG(_tag, _classname, _interfacename) (u"" #_tag),
+#define HTML_OTHER(_tag)
+const char16_t* const nsHTMLTags::sTagNames[] = {
+#include "nsHTMLTagList.h"
+};
+#undef HTML_TAG
+#undef HTML_OTHER
+
+int32_t nsHTMLTags::gTableRefCount;
+nsHTMLTags::TagStringHash* nsHTMLTags::gTagTable;
+nsHTMLTags::TagAtomHash* nsHTMLTags::gTagAtomTable;
+
+#define NS_HTMLTAG_NAME_MAX_LENGTH 10
+
+// static
+nsresult nsHTMLTags::AddRefTable(void) {
+ if (gTableRefCount++ == 0) {
+ NS_ASSERTION(!gTagTable && !gTagAtomTable, "pre existing hash!");
+
+ gTagTable = new TagStringHash(64);
+ gTagAtomTable = new TagAtomHash(64);
+
+ // Fill in gTagTable with the above static char16_t strings as
+ // keys and the value of the corresponding enum as the value in
+ // the table.
+
+ for (int32_t i = 0; i < NS_HTML_TAG_MAX; ++i) {
+ const char16_t* tagName = sTagNames[i];
+ const nsHTMLTag tagValue = static_cast<nsHTMLTag>(i + 1);
+
+ // We use AssignLiteral here to avoid a string copy. This is okay
+ // because this is truly static data.
+ nsString tmp;
+ tmp.AssignLiteral(tagName, nsString::char_traits::length(tagName));
+ gTagTable->Put(tmp, tagValue);
+
+ // All the HTML tag names are static atoms within nsGkAtoms, and they are
+ // registered before this code is reached.
+ nsStaticAtom* atom = NS_GetStaticAtom(tmp);
+ MOZ_ASSERT(atom);
+ gTagAtomTable->Put(atom, tagValue);
+ }
+
+#ifdef DEBUG
+ // Check all tagNames are lowercase, and that NS_HTMLTAG_NAME_MAX_LENGTH is
+ // correct.
+ uint32_t maxTagNameLength = 0;
+ for (int i = 0; i < NS_HTML_TAG_MAX; ++i) {
+ const char16_t* tagName = sTagNames[i];
+
+ nsAutoString lowerTagName(tagName);
+ ToLowerCase(lowerTagName);
+ MOZ_ASSERT(lowerTagName.Equals(tagName));
+
+ maxTagNameLength = std::max(NS_strlen(tagName), maxTagNameLength);
+ }
+
+ MOZ_ASSERT(maxTagNameLength == NS_HTMLTAG_NAME_MAX_LENGTH);
+#endif
+ }
+
+ return NS_OK;
+}
+
+// static
+void nsHTMLTags::ReleaseTable(void) {
+ if (0 == --gTableRefCount) {
+ delete gTagTable;
+ delete gTagAtomTable;
+ gTagTable = nullptr;
+ gTagAtomTable = nullptr;
+ }
+}
+
+// static
+nsHTMLTag nsHTMLTags::StringTagToId(const nsAString& aTagName) {
+ uint32_t length = aTagName.Length();
+
+ if (length > NS_HTMLTAG_NAME_MAX_LENGTH) {
+ return eHTMLTag_userdefined;
+ }
+
+ // Setup a stack allocated string buffer with the appropriate length.
+ nsAutoString lowerCase;
+ lowerCase.SetLength(length);
+
+ // Operate on the raw buffers to avoid bounds checks.
+ auto src = aTagName.BeginReading();
+ auto dst = lowerCase.BeginWriting();
+
+ // Fast lowercasing-while-copying of ASCII characters into a
+ // nsString buffer.
+
+ for (uint32_t i = 0; i < length; i++) {
+ char16_t c = src[i];
+
+ if (c <= 'Z' && c >= 'A') {
+ c |= 0x20; // Lowercase the ASCII character.
+ }
+
+ dst[i] = c; // Copy ASCII character.
+ }
+
+ return CaseSensitiveStringTagToId(lowerCase);
+}
+
+#ifdef DEBUG
+void nsHTMLTags::TestTagTable() {
+ const char16_t* tag;
+ nsHTMLTag id;
+ RefPtr<nsAtom> atom;
+
+ nsHTMLTags::AddRefTable();
+ // Make sure we can find everything we are supposed to
+ for (int i = 0; i < NS_HTML_TAG_MAX; ++i) {
+ tag = sTagNames[i];
+ const nsAString& tagString = nsDependentString(tag);
+ id = StringTagToId(tagString);
+ NS_ASSERTION(id != eHTMLTag_userdefined, "can't find tag id");
+
+ nsAutoString uname(tagString);
+ ToUpperCase(uname);
+ NS_ASSERTION(id == StringTagToId(uname), "wrong id");
+
+ NS_ASSERTION(id == CaseSensitiveStringTagToId(tagString), "wrong id");
+
+ atom = NS_Atomize(tag);
+ NS_ASSERTION(id == CaseSensitiveAtomTagToId(atom), "wrong id");
+ }
+
+ // Make sure we don't find things that aren't there
+ id = StringTagToId(u"@"_ns);
+ NS_ASSERTION(id == eHTMLTag_userdefined, "found @");
+ id = StringTagToId(u"zzzzz"_ns);
+ NS_ASSERTION(id == eHTMLTag_userdefined, "found zzzzz");
+
+ atom = NS_Atomize("@");
+ id = CaseSensitiveAtomTagToId(atom);
+ NS_ASSERTION(id == eHTMLTag_userdefined, "found @");
+ atom = NS_Atomize("zzzzz");
+ id = CaseSensitiveAtomTagToId(atom);
+ NS_ASSERTION(id == eHTMLTag_userdefined, "found zzzzz");
+
+ ReleaseTable();
+}
+
+#endif // DEBUG
diff --git a/parser/htmlparser/nsHTMLTags.h b/parser/htmlparser/nsHTMLTags.h
new file mode 100644
index 0000000000..a655f354aa
--- /dev/null
+++ b/parser/htmlparser/nsHTMLTags.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsHTMLTags_h___
+#define nsHTMLTags_h___
+
+#include "nsString.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
+
+/*
+ Declare the enum list using the magic of preprocessing
+ enum values are "eHTMLTag_foo" (where foo is the tag)
+
+ To change the list of tags, see nsHTMLTagList.h
+
+ These enum values are used as the index of array in various places.
+ If we change the structure of the enum by adding entries to it or removing
+ entries from it _directly_, not via nsHTMLTagList.h, don't forget to update
+ dom/bindings/BindingUtils.cpp and dom/html/nsHTMLContentSink.cpp as well.
+ */
+#define HTML_TAG(_tag, _classname, _interfacename) eHTMLTag_##_tag,
+#define HTML_OTHER(_tag) eHTMLTag_##_tag,
+enum nsHTMLTag {
+ /* this enum must be first and must be zero */
+ eHTMLTag_unknown = 0,
+#include "nsHTMLTagList.h"
+
+ /* can't be moved into nsHTMLTagList since gcc3.4 doesn't like a
+ comma at the end of enum list*/
+ eHTMLTag_userdefined
+};
+#undef HTML_TAG
+#undef HTML_OTHER
+
+// All tags before eHTMLTag_text are HTML tags
+#define NS_HTML_TAG_MAX int32_t(eHTMLTag_text - 1)
+
+class nsHTMLTags {
+ public:
+ using TagStringHash = nsDataHashtable<nsStringHashKey, nsHTMLTag>;
+ using TagAtomHash = nsDataHashtable<nsPtrHashKey<nsAtom>, nsHTMLTag>;
+
+ static nsresult AddRefTable(void);
+ static void ReleaseTable(void);
+
+ // Functions for converting string or atom to id
+ static nsHTMLTag StringTagToId(const nsAString& aTagName);
+ static nsHTMLTag AtomTagToId(nsAtom* aTagName) {
+ return StringTagToId(nsDependentAtomString(aTagName));
+ }
+
+ static nsHTMLTag CaseSensitiveStringTagToId(const nsAString& aTagName) {
+ NS_ASSERTION(gTagTable, "no lookup table, needs addref");
+
+ nsHTMLTag* tag = gTagTable->GetValue(aTagName);
+ return tag ? *tag : eHTMLTag_userdefined;
+ }
+ static nsHTMLTag CaseSensitiveAtomTagToId(nsAtom* aTagName) {
+ NS_ASSERTION(gTagAtomTable, "no lookup table, needs addref");
+ NS_ASSERTION(aTagName, "null tagname!");
+
+ nsHTMLTag* tag = gTagAtomTable->GetValue(aTagName);
+ return tag ? *tag : eHTMLTag_userdefined;
+ }
+
+#ifdef DEBUG
+ static void TestTagTable();
+#endif
+
+ private:
+ static const char16_t* const sTagNames[];
+
+ static int32_t gTableRefCount;
+ static TagStringHash* gTagTable;
+ static TagAtomHash* gTagAtomTable;
+};
+
+#endif /* nsHTMLTags_h___ */
diff --git a/parser/htmlparser/nsHTMLTokenizer.cpp b/parser/htmlparser/nsHTMLTokenizer.cpp
new file mode 100644
index 0000000000..ca4a5c7f4f
--- /dev/null
+++ b/parser/htmlparser/nsHTMLTokenizer.cpp
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 et tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * @file nsHTMLTokenizer.cpp
+ * This is an implementation of the nsITokenizer interface.
+ * This file contains the implementation of a tokenizer to tokenize an HTML
+ * document. It attempts to do so, making tradeoffs between compatibility with
+ * older parsers and the SGML specification. Note that most of the real
+ * "tokenization" takes place in nsHTMLTokens.cpp.
+ */
+
+#include "nsHTMLTokenizer.h"
+#include "nsIParser.h"
+
+/************************************************************************
+ And now for the main class -- nsHTMLTokenizer...
+ ************************************************************************/
+
+/**
+ * Satisfy the nsISupports interface.
+ */
+NS_IMPL_ISUPPORTS(nsHTMLTokenizer, nsITokenizer)
+
+/**
+ * Default constructor
+ */
+nsHTMLTokenizer::nsHTMLTokenizer() {
+ // TODO Assert about:blank-ness.
+}
+
+nsresult nsHTMLTokenizer::WillTokenize(bool aIsFinalChunk) { return NS_OK; }
+
+/**
+ * This method is repeatedly called by the tokenizer.
+ * Each time, we determine the kind of token we're about to
+ * read, and then we call the appropriate method to handle
+ * that token type.
+ *
+ * @param aScanner The source of our input.
+ * @param aFlushTokens An OUT parameter to tell the caller whether it should
+ * process our queued tokens up to now (e.g., when we
+ * reach a <script>).
+ * @return Success or error
+ */
+nsresult nsHTMLTokenizer::ConsumeToken(nsScanner& aScanner,
+ bool& aFlushTokens) {
+ return NS_ERROR_HTMLPARSER_EOF;
+}
diff --git a/parser/htmlparser/nsHTMLTokenizer.h b/parser/htmlparser/nsHTMLTokenizer.h
new file mode 100644
index 0000000000..c2e9725ab7
--- /dev/null
+++ b/parser/htmlparser/nsHTMLTokenizer.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * MODULE NOTES:
+ * @update gess 4/1/98
+ *
+ */
+
+#ifndef __NSHTMLTOKENIZER
+#define __NSHTMLTOKENIZER
+
+#include "mozilla/Attributes.h"
+#include "nsISupports.h"
+#include "nsITokenizer.h"
+
+#ifdef _MSC_VER
+# pragma warning(disable : 4275)
+#endif
+
+class nsHTMLTokenizer final : public nsITokenizer {
+ ~nsHTMLTokenizer() {}
+
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSITOKENIZER
+ nsHTMLTokenizer();
+};
+
+#endif
diff --git a/parser/htmlparser/nsIContentSink.h b/parser/htmlparser/nsIContentSink.h
new file mode 100644
index 0000000000..d03429e83d
--- /dev/null
+++ b/parser/htmlparser/nsIContentSink.h
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef nsIContentSink_h___
+#define nsIContentSink_h___
+
+/**
+ * MODULE NOTES:
+ * @update gess 4/1/98
+ *
+ * This pure virtual interface is used as the "glue" that connects the parsing
+ * process to the content model construction process.
+ *
+ * The icontentsink interface is a very lightweight wrapper that represents the
+ * content-sink model building process. There is another one that you may care
+ * about more, which is the IHTMLContentSink interface. (See that file for
+ * details).
+ */
+#include "nsISupports.h"
+#include "nsString.h"
+#include "mozilla/FlushType.h"
+#include "mozilla/NotNull.h"
+#include "nsIDTD.h"
+
+class nsParserBase;
+namespace mozilla {
+class Encoding;
+}
+
+#define NS_ICONTENT_SINK_IID \
+ { \
+ 0xcf9a7cbb, 0xfcbc, 0x4e13, { \
+ 0x8e, 0xf5, 0x18, 0xef, 0x2d, 0x3d, 0x58, 0x29 \
+ } \
+ }
+
+class nsIContentSink : public nsISupports {
+ protected:
+ using Encoding = mozilla::Encoding;
+ template <typename T>
+ using NotNull = mozilla::NotNull<T>;
+
+ public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENT_SINK_IID)
+
+ /**
+ * This method is called by the parser when it is entered from
+ * the event loop. The content sink wants to know how long the
+ * parser has been active since we last processed events on the
+ * main event loop and this call calibrates that measurement.
+ */
+ NS_IMETHOD WillParse(void) = 0;
+
+ /**
+ * This method gets called when the parser begins the process
+ * of building the content model via the content sink.
+ *
+ * Default implementation provided since the sink should have the option of
+ * doing nothing in response to this call.
+ *
+ * @update 5/7/98 gess
+ */
+ NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode) { return NS_OK; }
+
+ /**
+ * This method gets called when the parser concludes the process
+ * of building the content model via the content sink.
+ *
+ * Default implementation provided since the sink should have the option of
+ * doing nothing in response to this call.
+ *
+ * @update 5/7/98 gess
+ */
+ NS_IMETHOD DidBuildModel(bool aTerminated) { return NS_OK; }
+
+ /**
+ * This method gets called when the parser gets i/o blocked,
+ * and wants to notify the sink that it may be a while before
+ * more data is available.
+ *
+ * @update 5/7/98 gess
+ */
+ NS_IMETHOD WillInterrupt(void) = 0;
+
+ /**
+ * This method gets called when the parser i/o gets unblocked,
+ * and we're about to start dumping content again to the sink.
+ *
+ * @update 5/7/98 gess
+ */
+ NS_IMETHOD WillResume(void) = 0;
+
+ /**
+ * This method gets called by the parser so that the content
+ * sink can retain a reference to the parser. The expectation
+ * is that the content sink will drop the reference when it
+ * gets the DidBuildModel notification i.e. when parsing is done.
+ */
+ NS_IMETHOD SetParser(nsParserBase* aParser) = 0;
+
+ /**
+ * Flush content so that the content model is in sync with the state
+ * of the sink.
+ *
+ * @param aType the type of flush to perform
+ */
+ virtual void FlushPendingNotifications(mozilla::FlushType aType) = 0;
+
+ /**
+ * Set the document character set. This should be passed on to the
+ * document itself.
+ */
+ virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) = 0;
+
+ /**
+ * Returns the target object (often a document object) into which
+ * the content built by this content sink is being added, if any
+ * (IOW, may return null).
+ */
+ virtual nsISupports* GetTarget() = 0;
+
+ /**
+ * Returns true if there's currently script executing that we need to hold
+ * parsing for.
+ */
+ virtual bool IsScriptExecuting() { return false; }
+
+ /**
+ * Posts a runnable that continues parsing.
+ */
+ virtual void ContinueInterruptedParsingAsync() {}
+
+ virtual void InitialTranslationCompleted() {}
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIContentSink, NS_ICONTENT_SINK_IID)
+
+#endif /* nsIContentSink_h___ */
diff --git a/parser/htmlparser/nsIDTD.h b/parser/htmlparser/nsIDTD.h
new file mode 100644
index 0000000000..a47938befa
--- /dev/null
+++ b/parser/htmlparser/nsIDTD.h
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsIDTD_h___
+#define nsIDTD_h___
+
+/**
+ * MODULE NOTES:
+ * @update gess 7/20/98
+ *
+ * This interface defines standard interface for DTD's. Note that this
+ * isn't HTML specific. DTD's have several functions within the parser
+ * system:
+ * 1) To coordinate the consumption of an input stream via the
+ * parser
+ * 2) To serve as proxy to represent the containment rules of the
+ * underlying document
+ * 3) To offer autodetection services to the parser (mainly for doc
+ * conversion)
+ * */
+
+#include "nsISupports.h"
+#include "nsString.h"
+#include "nsITokenizer.h"
+
+#define NS_IDTD_IID \
+ { \
+ 0x3de05873, 0xefa7, 0x410d, { \
+ 0xa4, 0x61, 0x80, 0x33, 0xaf, 0xd9, 0xe3, 0x26 \
+ } \
+ }
+
+enum eAutoDetectResult {
+ eUnknownDetect,
+ eValidDetect,
+ ePrimaryDetect,
+ eInvalidDetect
+};
+
+enum nsDTDMode {
+ eDTDMode_unknown = 0,
+ eDTDMode_quirks, // pre 4.0 versions
+ eDTDMode_almost_standards,
+ eDTDMode_full_standards,
+ eDTDMode_autodetect,
+ eDTDMode_fragment
+};
+
+class nsIContentSink;
+class CParserContext;
+
+class nsIDTD : public nsISupports {
+ public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDTD_IID)
+
+ NS_IMETHOD WillBuildModel(const CParserContext& aParserContext,
+ nsITokenizer* aTokenizer,
+ nsIContentSink* aSink) = 0;
+
+ /**
+ * Called by the parser after the parsing process has concluded
+ * @update gess5/18/98
+ * @param anErrorCode - contains error code resulting from parse process
+ * @return
+ */
+ NS_IMETHOD DidBuildModel(nsresult anErrorCode) = 0;
+
+ /**
+ * Called (possibly repeatedly) by the parser to parse tokens and construct
+ * the document model via the sink provided to WillBuildModel.
+ *
+ * @param aTokenizer - tokenizer providing the token stream to be parsed
+ * @param aCountLines - informs the DTD whether to count newlines
+ * (not wanted, e.g., when handling document.write)
+ * @param aCharsetPtr - address of an nsCString containing the charset
+ * that the DTD should use (pointer in case the DTD
+ * opts to ignore this parameter)
+ */
+ NS_IMETHOD BuildModel(nsITokenizer* aTokenizer, nsIContentSink* aSink) = 0;
+
+ /**
+ * This method is called to determine whether or not a tag of one
+ * type can contain a tag of another type.
+ *
+ * @update gess 3/25/98
+ * @param aParent -- int tag of parent container
+ * @param aChild -- int tag of child container
+ * @return true if parent can contain child
+ */
+ NS_IMETHOD_(bool) CanContain(int32_t aParent, int32_t aChild) const = 0;
+
+ /**
+ * This method gets called to determine whether a given
+ * tag is itself a container
+ *
+ * @update gess 3/25/98
+ * @param aTag -- tag to test for containership
+ * @return true if given tag can contain other tags
+ */
+ NS_IMETHOD_(bool) IsContainer(int32_t aTag) const = 0;
+
+ /**
+ * Use this id you want to stop the building content model
+ * --------------[ Sets DTD to STOP mode ]----------------
+ * It's recommended to use this method in accordance with
+ * the parser's terminate() method.
+ *
+ * @update harishd 07/22/99
+ * @param
+ * @return
+ */
+ NS_IMETHOD_(void) Terminate() = 0;
+
+ NS_IMETHOD_(int32_t) GetType() = 0;
+
+ /**
+ * Call this method after calling WillBuildModel to determine what mode the
+ * DTD actually is using, as it may differ from aParserContext.mDTDMode.
+ */
+ NS_IMETHOD_(nsDTDMode) GetMode() const = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIDTD, NS_IDTD_IID)
+
+#define NS_DECL_NSIDTD \
+ NS_IMETHOD WillBuildModel(const CParserContext& aParserContext, \
+ nsITokenizer* aTokenizer, nsIContentSink* aSink) \
+ override; \
+ NS_IMETHOD DidBuildModel(nsresult anErrorCode) override; \
+ NS_IMETHOD BuildModel(nsITokenizer* aTokenizer, nsIContentSink* aSink) \
+ override; \
+ NS_IMETHOD_(bool) \
+ CanContain(int32_t aParent, int32_t aChild) const override; \
+ NS_IMETHOD_(bool) IsContainer(int32_t aTag) const override; \
+ NS_IMETHOD_(void) Terminate() override; \
+ NS_IMETHOD_(int32_t) GetType() override; \
+ NS_IMETHOD_(nsDTDMode) GetMode() const override;
+#endif /* nsIDTD_h___ */
diff --git a/parser/htmlparser/nsIExpatSink.idl b/parser/htmlparser/nsIExpatSink.idl
new file mode 100644
index 0000000000..f505eda8c9
--- /dev/null
+++ b/parser/htmlparser/nsIExpatSink.idl
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+interface nsIScriptError;
+
+/**
+ * This interface should be implemented by any content sink that wants
+ * to get output from expat and do something with it; in other words,
+ * by any sink that handles some sort of XML dialect.
+ */
+
+[scriptable, uuid(01f681af-0f22-4725-a914-0d396114daf0)]
+interface nsIExpatSink : nsISupports
+{
+ /**
+ * Called to handle the opening tag of an element.
+ * @param aName the fully qualified tagname of the element
+ * @param aAtts the array of attribute names and values. There are
+ * aAttsCount/2 names and aAttsCount/2 values, so the total number of
+ * elements in the array is aAttsCount. The names and values
+ * alternate. Thus, if we number attributes starting with 0,
+ * aAtts[2*k] is the name of the k-th attribute and aAtts[2*k+1] is
+ * the value of that attribute Both explicitly specified attributes
+ * and attributes that are defined to have default values in a DTD are
+ * present in aAtts.
+ * @param aAttsCount the number of elements in aAtts.
+ * @param aLineNumber the line number of the start tag in the data stream.
+ * @param aColumnNumber the column number of the start tag in the data stream.
+ */
+ void HandleStartElement(in wstring aName,
+ [array, size_is(aAttsCount)] in wstring aAtts,
+ in unsigned long aAttsCount,
+ in unsigned long aLineNumber,
+ in unsigned long aColumnNumber);
+
+ /**
+ * Called to handle the closing tag of an element.
+ * @param aName the fully qualified tagname of the element
+ */
+ void HandleEndElement(in wstring aName);
+
+ /**
+ * Called to handle a comment
+ * @param aCommentText the text of the comment (not including the
+ * "<!--" and "-->")
+ */
+ void HandleComment(in wstring aCommentText);
+
+ /**
+ * Called to handle a CDATA section
+ * @param aData the text in the CDATA section. This is null-terminated.
+ * @param aLength the length of the aData string
+ */
+ void HandleCDataSection([size_is(aLength)] in wstring aData,
+ in unsigned long aLength);
+
+ /**
+ * Called to handle the doctype declaration
+ */
+ void HandleDoctypeDecl(in AString aSubset,
+ in AString aName,
+ in AString aSystemId,
+ in AString aPublicId,
+ in nsISupports aCatalogData);
+
+ /**
+ * Called to handle character data. Note that this does NOT get
+ * called for the contents of CDATA sections.
+ * @param aData the data to handle. aData is NOT NULL-TERMINATED.
+ * @param aLength the length of the aData string
+ */
+ void HandleCharacterData([size_is(aLength)] in wstring aData,
+ in unsigned long aLength);
+
+ /**
+ * Called to handle a processing instruction
+ * @param aTarget the PI target (e.g. xml-stylesheet)
+ * @param aData all the rest of the data in the PI
+ */
+ void HandleProcessingInstruction(in wstring aTarget,
+ in wstring aData);
+
+ /**
+ * Handle the XML Declaration.
+ *
+ * @param aVersion The version string, can be null if not specified.
+ * @param aEncoding The encoding string, can be null if not specified.
+ * @param aStandalone -1, 0, or 1 indicating respectively that there was no
+ * standalone parameter in the declaration, that it was
+ * given as no, or that it was given as yes.
+ */
+ void HandleXMLDeclaration(in wstring aVersion,
+ in wstring aEncoding,
+ in long aStandalone);
+
+ /**
+ * Ask the content sink if the expat driver should log an error to the console.
+ *
+ * @param aErrorText Error message to pass to content sink.
+ * @param aSourceText Source text of the document we're parsing.
+ * @param aError Script error object with line number & column number
+ *
+ * @retval True if the expat driver should report the error.
+ */
+ boolean ReportError(in wstring aErrorText,
+ in wstring aSourceText,
+ in nsIScriptError aError);
+};
diff --git a/parser/htmlparser/nsIFragmentContentSink.h b/parser/htmlparser/nsIFragmentContentSink.h
new file mode 100644
index 0000000000..5febfe8a9a
--- /dev/null
+++ b/parser/htmlparser/nsIFragmentContentSink.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef nsIFragmentContentSink_h___
+#define nsIFragmentContentSink_h___
+
+#include "nsISupports.h"
+
+namespace mozilla {
+namespace dom {
+class Document;
+class DocumentFragment;
+} // namespace dom
+} // namespace mozilla
+
+#define NS_I_FRAGMENT_CONTENT_SINK_IID \
+ { \
+ 0x1a8ce30b, 0x63fc, 0x441a, { \
+ 0xa3, 0xaa, 0xf7, 0x16, 0xc0, 0xfe, 0x96, 0x69 \
+ } \
+ }
+
+/**
+ * The fragment sink allows a client to parse a fragment of sink, possibly
+ * surrounded in context. Also see nsIParser::ParseFragment().
+ * Note: once you've parsed a fragment, the fragment sink must be re-set on
+ * the parser in order to parse another fragment.
+ */
+class nsIFragmentContentSink : public nsISupports {
+ public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_I_FRAGMENT_CONTENT_SINK_IID)
+ /**
+ * This method is used to obtain the fragment created by
+ * a fragment content sink and to release resources held by the parser.
+ *
+ * The sink drops its reference to the fragment.
+ */
+ NS_IMETHOD FinishFragmentParsing(mozilla::dom::DocumentFragment** aFragment) =
+ 0;
+
+ /**
+ * This method is used to set the target document for this fragment
+ * sink. This document's nodeinfo manager will be used to create
+ * the content objects. This MUST be called before the sink is used.
+ *
+ * @param aDocument the document the new nodes will belong to
+ * (should not be null)
+ */
+ NS_IMETHOD SetTargetDocument(mozilla::dom::Document*) = 0;
+
+ /**
+ * This method is used to indicate to the sink that we're done building
+ * the context and should start paying attention to the incoming content
+ */
+ NS_IMETHOD WillBuildContent() = 0;
+
+ /**
+ * This method is used to indicate to the sink that we're done building
+ * The real content. This is useful if you want to parse additional context
+ * (such as an end context).
+ */
+ NS_IMETHOD DidBuildContent() = 0;
+
+ /**
+ * This method is a total hack to help with parsing fragments. It is called to
+ * tell the fragment sink that a container from the context will be delivered
+ * after the call to WillBuildContent(). This is only relevent for HTML
+ * fragments that use nsHTMLTokenizer/CNavDTD.
+ */
+ NS_IMETHOD IgnoreFirstContainer() = 0;
+
+ /**
+ * Sets whether scripts elements are marked as unexecutable.
+ */
+ NS_IMETHOD SetPreventScriptExecution(bool aPreventScriptExecution) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIFragmentContentSink,
+ NS_I_FRAGMENT_CONTENT_SINK_IID)
+
+nsresult NS_NewXMLFragmentContentSink(
+ nsIFragmentContentSink** aInstancePtrResult);
+
+#endif
diff --git a/parser/htmlparser/nsIHTMLContentSink.h b/parser/htmlparser/nsIHTMLContentSink.h
new file mode 100644
index 0000000000..835044be65
--- /dev/null
+++ b/parser/htmlparser/nsIHTMLContentSink.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef nsIHTMLContentSink_h___
+#define nsIHTMLContentSink_h___
+
+/**
+ * This interface is OBSOLETE and in the process of being REMOVED.
+ * Do NOT implement!
+ *
+ * This file declares the concrete HTMLContentSink class.
+ * This class is used during the parsing process as the
+ * primary interface between the parser and the content
+ * model.
+ *
+ * After the tokenizer completes, the parser iterates over
+ * the known token list. As the parser identifies valid
+ * elements, it calls the contentsink interface to notify
+ * the content model that a new node or child node is being
+ * created and added to the content model.
+ *
+ * The HTMLContentSink interface assumes 4 underlying
+ * containers: HTML, HEAD, BODY and FRAMESET. Before
+ * accessing any these, the parser will call the appropriate
+ * OpennsIHTMLContentSink method: OpenHTML,OpenHead,OpenBody,OpenFrameSet;
+ * likewise, the ClosensIHTMLContentSink version will be called when the
+ * parser is done with a given section.
+ *
+ * IMPORTANT: The parser may Open each container more than
+ * once! This is due to the irregular nature of HTML files.
+ * For example, it is possible to encounter plain text at
+ * the start of an HTML document (that precedes the HTML tag).
+ * Such text is treated as if it were part of the body.
+ * In such cases, the parser will Open the body, pass the text-
+ * node in and then Close the body. The body will likely be
+ * re-Opened later when the actual <BODY> tag has been seen.
+ *
+ * Containers within the body are Opened and Closed
+ * using the OpenContainer(...) and CloseContainer(...) calls.
+ * It is assumed that the document or contentSink is
+ * maintaining its state to manage where new content should
+ * be added to the underlying document.
+ *
+ * NOTE: OpenHTML() and OpenBody() may get called multiple times
+ * in the same document. That's fine, and it doesn't mean
+ * that we have multiple bodies or HTML's.
+ *
+ * NOTE: I haven't figured out how sub-documents (non-frames)
+ * are going to be handled. Stay tuned.
+ */
+#include "nsIContentSink.h"
+#include "nsHTMLTags.h"
+
+#define NS_IHTML_CONTENT_SINK_IID \
+ { \
+ 0xefc5af86, 0x5cfd, 0x4918, { \
+ 0x9d, 0xd3, 0x5f, 0x7a, 0xb2, 0x88, 0xb2, 0x68 \
+ } \
+ }
+
+/**
+ * This interface is OBSOLETE and in the process of being REMOVED.
+ * Do NOT implement!
+ */
+class nsIHTMLContentSink : public nsIContentSink {
+ public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IHTML_CONTENT_SINK_IID)
+
+ enum ElementType { eHTML, eBody };
+
+ /**
+ * This method is used to open a generic container in the sink.
+ *
+ * @update 4/1/98 gess
+ */
+ NS_IMETHOD OpenContainer(ElementType aNodeType) = 0;
+
+ /**
+ * This method gets called by the parser when a close
+ * container tag has been consumed and needs to be closed.
+ *
+ * @param aTag - The tag to be closed.
+ */
+ NS_IMETHOD CloseContainer(ElementType aTag) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIHTMLContentSink, NS_IHTML_CONTENT_SINK_IID)
+
+#endif /* nsIHTMLContentSink_h___ */
diff --git a/parser/htmlparser/nsIParser.h b/parser/htmlparser/nsIParser.h
new file mode 100644
index 0000000000..48dc55d5a2
--- /dev/null
+++ b/parser/htmlparser/nsIParser.h
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef NS_IPARSER___
+#define NS_IPARSER___
+
+/**
+ * This GECKO-INTERNAL interface is on track to being REMOVED (or refactored
+ * to the point of being near-unrecognizable).
+ *
+ * Please DO NOT #include this file in comm-central code, in your XULRunner
+ * app or binary extensions.
+ *
+ * Please DO NOT #include this into new files even inside Gecko. It is more
+ * likely than not that #including this header is the wrong thing to do.
+ */
+
+#include "nsISupports.h"
+#include "nsIStreamListener.h"
+#include "nsIDTD.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nsAtom.h"
+#include "nsParserBase.h"
+#include "mozilla/NotNull.h"
+
+#define NS_IPARSER_IID \
+ { \
+ 0x2c4ad90a, 0x740e, 0x4212, { \
+ 0xba, 0x3f, 0xfe, 0xac, 0xda, 0x4b, 0x92, 0x9e \
+ } \
+ }
+
+class nsIContentSink;
+class nsIRequestObserver;
+class nsIURI;
+class nsIChannel;
+namespace mozilla {
+class Encoding;
+}
+
+enum eParserCommands { eViewNormal, eViewSource, eViewFragment, eViewErrors };
+
+enum eParserDocType { ePlainText = 0, eXML, eHTML_Quirks, eHTML_Strict };
+
+enum eStreamState { eNone, eOnStart, eOnDataAvail, eOnStop };
+
+/**
+ * This GECKO-INTERNAL interface is on track to being REMOVED (or refactored
+ * to the point of being near-unrecognizable).
+ *
+ * Please DO NOT #include this file in comm-central code, in your XULRunner
+ * app or binary extensions.
+ *
+ * Please DO NOT #include this into new files even inside Gecko. It is more
+ * likely than not that #including this header is the wrong thing to do.
+ */
+class nsIParser : public nsParserBase {
+ protected:
+ using Encoding = mozilla::Encoding;
+ template <typename T>
+ using NotNull = mozilla::NotNull<T>;
+
+ public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPARSER_IID)
+
+ /**
+ * Select given content sink into parser for parser output
+ * @update gess5/11/98
+ * @param aSink is the new sink to be used by parser
+ * @return
+ */
+ NS_IMETHOD_(void) SetContentSink(nsIContentSink* aSink) = 0;
+
+ /**
+ * retrieve the sink set into the parser
+ * @update gess5/11/98
+ * @return current sink
+ */
+ NS_IMETHOD_(nsIContentSink*) GetContentSink(void) = 0;
+
+ /**
+ * Call this method once you've created a parser, and want to instruct it
+ * about the command which caused the parser to be constructed. For example,
+ * this allows us to select a DTD which can do, say, view-source.
+ *
+ * @update gess 3/25/98
+ * @param aCommand -- ptrs to string that contains command
+ * @return nada
+ */
+ NS_IMETHOD_(void) GetCommand(nsCString& aCommand) = 0;
+ NS_IMETHOD_(void) SetCommand(const char* aCommand) = 0;
+ NS_IMETHOD_(void) SetCommand(eParserCommands aParserCommand) = 0;
+
+ /**
+ * Call this method once you've created a parser, and want to instruct it
+ * about what charset to load
+ *
+ * @update ftang 4/23/99
+ * @param aCharset- the charest of a document
+ * @param aCharsetSource- the soure of the chares
+ * @return nada
+ */
+ virtual void SetDocumentCharset(NotNull<const Encoding*> aCharset,
+ int32_t aSource) = 0;
+
+ /**
+ * Get the channel associated with this parser
+ * @update harishd,gagan 07/17/01
+ * @param aChannel out param that will contain the result
+ * @return NS_OK if successful
+ */
+ NS_IMETHOD GetChannel(nsIChannel** aChannel) override = 0;
+
+ /**
+ * Get the DTD associated with this parser
+ * @update vidur 9/29/99
+ * @param aDTD out param that will contain the result
+ * @return NS_OK if successful, NS_ERROR_FAILURE for runtime error
+ */
+ NS_IMETHOD GetDTD(nsIDTD** aDTD) = 0;
+
+ /**
+ * Get the nsIStreamListener for this parser
+ */
+ virtual nsIStreamListener* GetStreamListener() = 0;
+
+ /**************************************************************************
+ * Parse methods always begin with an input source, and perform
+ * conversions until you wind up being emitted to the given contentsink
+ * (which may or may not be a proxy for the NGLayout content model).
+ ************************************************************************/
+
+ // Call this method to resume the parser from an unblocked state.
+ // This can happen, for example, if parsing was interrupted and then the
+ // consumer needed to restart the parser without waiting for more data.
+ // This also happens after loading scripts, which unblock the parser in
+ // order to process the output of document.write() and then need to
+ // continue on with the page load on an enabled parser.
+ NS_IMETHOD ContinueInterruptedParsing() = 0;
+
+ // Stops parsing temporarily.
+ NS_IMETHOD_(void) BlockParser() = 0;
+
+ // Open up the parser for tokenization, building up content
+ // model..etc. However, this method does not resume parsing
+ // automatically. It's the callers' responsibility to restart
+ // the parsing engine.
+ NS_IMETHOD_(void) UnblockParser() = 0;
+
+ /**
+ * Asynchronously continues parsing.
+ */
+ NS_IMETHOD_(void) ContinueInterruptedParsingAsync() = 0;
+
+ NS_IMETHOD_(bool) IsParserEnabled() override = 0;
+ NS_IMETHOD_(bool) IsComplete() = 0;
+
+ NS_IMETHOD Parse(nsIURI* aURL, nsIRequestObserver* aListener = nullptr,
+ void* aKey = 0, nsDTDMode aMode = eDTDMode_autodetect) = 0;
+
+ NS_IMETHOD Terminate(void) = 0;
+
+ /**
+ * This method gets called when you want to parse a fragment of HTML or XML
+ * surrounded by the context |aTagStack|. It requires that the parser have
+ * been given a fragment content sink.
+ *
+ * @param aSourceBuffer The XML or HTML that hasn't been parsed yet.
+ * @param aTagStack The context of the source buffer.
+ * @return Success or failure.
+ */
+ NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer,
+ nsTArray<nsString>& aTagStack) = 0;
+
+ /**
+ * This method gets called when the tokens have been consumed, and it's time
+ * to build the model via the content sink.
+ * @update gess5/11/98
+ * @return error code -- 0 if model building went well .
+ */
+ NS_IMETHOD BuildModel(void) = 0;
+
+ /**
+ * Call this method to cancel any pending parsing events.
+ * Parsing events may be pending if all of the document's content
+ * has been passed to the parser but the parser has been interrupted
+ * because processing the tokens took too long.
+ *
+ * @update kmcclusk 05/18/01
+ * @return NS_OK if succeeded else ERROR.
+ */
+
+ NS_IMETHOD CancelParsingEvents() = 0;
+
+ virtual void Reset() = 0;
+
+ /**
+ * True if the insertion point (per HTML5) is defined.
+ */
+ virtual bool IsInsertionPointDefined() = 0;
+
+ /**
+ * Call immediately before starting to evaluate a parser-inserted script or
+ * in general when the spec says to increment the script nesting level.
+ */
+ virtual void IncrementScriptNestingLevel() = 0;
+
+ /**
+ * Call immediately after having evaluated a parser-inserted script or
+ * generally want to restore to the state before the last
+ * IncrementScriptNestingLevel call.
+ */
+ virtual void DecrementScriptNestingLevel() = 0;
+
+ /**
+ * True if this is an HTML5 parser whose script nesting level (in
+ * the sense of
+ * <https://html.spec.whatwg.org/multipage/parsing.html#script-nesting-level>)
+ * is nonzero.
+ */
+ virtual bool HasNonzeroScriptNestingLevel() const = 0;
+
+ /**
+ * Marks the HTML5 parser as not a script-created parser.
+ */
+ virtual void MarkAsNotScriptCreated(const char* aCommand) = 0;
+
+ /**
+ * True if this is a script-created HTML5 parser.
+ */
+ virtual bool IsScriptCreated() = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIParser, NS_IPARSER_IID)
+
+/* ===========================================================*
+ Some useful constants...
+ * ===========================================================*/
+
+#define NS_IPARSER_FLAG_XML 0x00000200
+#define NS_IPARSER_FLAG_HTML 0x00000400
+
+#endif
diff --git a/parser/htmlparser/nsITokenizer.h b/parser/htmlparser/nsITokenizer.h
new file mode 100644
index 0000000000..b51f060f8b
--- /dev/null
+++ b/parser/htmlparser/nsITokenizer.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * MODULE NOTES:
+ * @update gess 4/1/98
+ *
+ */
+
+#ifndef __NSITOKENIZER__
+#define __NSITOKENIZER__
+
+#include "nsISupports.h"
+
+class nsScanner;
+
+#define NS_ITOKENIZER_IID \
+ { \
+ 0Xae98a348, 0X5e91, 0X41a8, { \
+ 0Xa5, 0Xb4, 0Xd2, 0X20, 0Xf3, 0X1f, 0Xc4, 0Xab \
+ } \
+ }
+
+/***************************************************************
+ Notes:
+ ***************************************************************/
+
+class nsITokenizer : public nsISupports {
+ public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITOKENIZER_IID)
+
+ NS_IMETHOD WillTokenize(bool aIsFinalChunk) = 0;
+ NS_IMETHOD ConsumeToken(nsScanner& aScanner, bool& aFlushTokens) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsITokenizer, NS_ITOKENIZER_IID)
+
+#define NS_DECL_NSITOKENIZER \
+ NS_IMETHOD WillTokenize(bool aIsFinalChunk) override; \
+ NS_IMETHOD ConsumeToken(nsScanner& aScanner, bool& aFlushTokens) override;
+
+#endif
diff --git a/parser/htmlparser/nsParser.cpp b/parser/htmlparser/nsParser.cpp
new file mode 100644
index 0000000000..1af3468bd3
--- /dev/null
+++ b/parser/htmlparser/nsParser.cpp
@@ -0,0 +1,1471 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 et tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsAtom.h"
+#include "nsParser.h"
+#include "nsString.h"
+#include "nsCRT.h"
+#include "nsScanner.h"
+#include "plstr.h"
+#include "nsIChannel.h"
+#include "nsIInputStream.h"
+#include "CNavDTD.h"
+#include "prenv.h"
+#include "prlock.h"
+#include "prcvar.h"
+#include "nsParserCIID.h"
+#include "nsReadableUtils.h"
+#include "nsCOMPtr.h"
+#include "nsExpatDriver.h"
+#include "nsIFragmentContentSink.h"
+#include "nsStreamUtils.h"
+#include "nsHTMLTokenizer.h"
+#include "nsDataHashtable.h"
+#include "nsXPCOMCIDInternal.h"
+#include "nsMimeTypes.h"
+#include "mozilla/CondVar.h"
+#include "mozilla/Mutex.h"
+#include "nsCharsetSource.h"
+#include "nsThreadUtils.h"
+#include "nsIHTMLContentSink.h"
+
+#include "mozilla/BinarySearch.h"
+#include "mozilla/dom/ScriptLoader.h"
+#include "mozilla/Encoding.h"
+
+using namespace mozilla;
+
+#define NS_PARSER_FLAG_OBSERVERS_ENABLED 0x00000004
+#define NS_PARSER_FLAG_PENDING_CONTINUE_EVENT 0x00000008
+#define NS_PARSER_FLAG_FLUSH_TOKENS 0x00000020
+#define NS_PARSER_FLAG_CAN_TOKENIZE 0x00000040
+
+//-------------- Begin ParseContinue Event Definition ------------------------
+/*
+The parser can be explicitly interrupted by passing a return value of
+NS_ERROR_HTMLPARSER_INTERRUPTED from BuildModel on the DTD. This will cause
+the parser to stop processing and allow the application to return to the event
+loop. The data which was left at the time of interruption will be processed
+the next time OnDataAvailable is called. If the parser has received its final
+chunk of data then OnDataAvailable will no longer be called by the networking
+module, so the parser will schedule a nsParserContinueEvent which will call
+the parser to process the remaining data after returning to the event loop.
+If the parser is interrupted while processing the remaining data it will
+schedule another ParseContinueEvent. The processing of data followed by
+scheduling of the continue events will proceed until either:
+
+ 1) All of the remaining data can be processed without interrupting
+ 2) The parser has been cancelled.
+
+
+This capability is currently used in CNavDTD and nsHTMLContentSink. The
+nsHTMLContentSink is notified by CNavDTD when a chunk of tokens is going to be
+processed and when each token is processed. The nsHTML content sink records
+the time when the chunk has started processing and will return
+NS_ERROR_HTMLPARSER_INTERRUPTED if the token processing time has exceeded a
+threshold called max tokenizing processing time. This allows the content sink
+to limit how much data is processed in a single chunk which in turn gates how
+much time is spent away from the event loop. Processing smaller chunks of data
+also reduces the time spent in subsequent reflows.
+
+This capability is most apparent when loading large documents. If the maximum
+token processing time is set small enough the application will remain
+responsive during document load.
+
+A side-effect of this capability is that document load is not complete when
+the last chunk of data is passed to OnDataAvailable since the parser may have
+been interrupted when the last chunk of data arrived. The document is complete
+when all of the document has been tokenized and there aren't any pending
+nsParserContinueEvents. This can cause problems if the application assumes
+that it can monitor the load requests to determine when the document load has
+been completed. This is what happens in Mozilla. The document is considered
+completely loaded when all of the load requests have been satisfied. To delay
+the document load until all of the parsing has been completed the
+nsHTMLContentSink adds a dummy parser load request which is not removed until
+the nsHTMLContentSink's DidBuildModel is called. The CNavDTD will not call
+DidBuildModel until the final chunk of data has been passed to the parser
+through the OnDataAvailable and there aren't any pending
+nsParserContineEvents.
+
+Currently the parser is ignores requests to be interrupted during the
+processing of script. This is because a document.write followed by JavaScript
+calls to manipulate the DOM may fail if the parser was interrupted during the
+document.write.
+
+For more details @see bugzilla bug 76722
+*/
+
+class nsParserContinueEvent : public Runnable {
+ public:
+ RefPtr<nsParser> mParser;
+
+ explicit nsParserContinueEvent(nsParser* aParser)
+ : mozilla::Runnable("nsParserContinueEvent"), mParser(aParser) {}
+
+ NS_IMETHOD Run() override {
+ mParser->HandleParserContinueEvent(this);
+ return NS_OK;
+ }
+};
+
+//-------------- End ParseContinue Event Definition ------------------------
+
+/**
+ * default constructor
+ */
+nsParser::nsParser()
+ : mParserContext(nullptr), mCharset(WINDOWS_1252_ENCODING) {
+ Initialize(true);
+}
+
+nsParser::~nsParser() { Cleanup(); }
+
+void nsParser::Initialize(bool aConstructor) {
+ if (aConstructor) {
+ // Raw pointer
+ mParserContext = 0;
+ } else {
+ // nsCOMPtrs
+ mObserver = nullptr;
+ mUnusedInput.Truncate();
+ }
+
+ mContinueEvent = nullptr;
+ mCharsetSource = kCharsetUninitialized;
+ mCharset = WINDOWS_1252_ENCODING;
+ mInternalState = NS_OK;
+ mStreamStatus = NS_OK;
+ mCommand = eViewNormal;
+ mBlocked = 0;
+ mFlags = NS_PARSER_FLAG_OBSERVERS_ENABLED | NS_PARSER_FLAG_CAN_TOKENIZE;
+
+ mProcessingNetworkData = false;
+ mIsAboutBlank = false;
+}
+
+void nsParser::Cleanup() {
+#ifdef DEBUG
+ if (mParserContext && mParserContext->mPrevContext) {
+ NS_WARNING("Extra parser contexts still on the parser stack");
+ }
+#endif
+
+ while (mParserContext) {
+ CParserContext* pc = mParserContext->mPrevContext;
+ delete mParserContext;
+ mParserContext = pc;
+ }
+
+ // It should not be possible for this flag to be set when we are getting
+ // destroyed since this flag implies a pending nsParserContinueEvent, which
+ // has an owning reference to |this|.
+ NS_ASSERTION(!(mFlags & NS_PARSER_FLAG_PENDING_CONTINUE_EVENT), "bad");
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsParser)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsParser)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mDTD)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mSink)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mObserver)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsParser)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDTD)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSink)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObserver)
+ CParserContext* pc = tmp->mParserContext;
+ while (pc) {
+ cb.NoteXPCOMChild(pc->mTokenizer);
+ pc = pc->mPrevContext;
+ }
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsParser)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsParser)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsParser)
+ NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
+ NS_INTERFACE_MAP_ENTRY(nsIParser)
+ NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParser)
+NS_INTERFACE_MAP_END
+
+// The parser continue event is posted only if
+// all of the data to parse has been passed to ::OnDataAvailable
+// and the parser has been interrupted by the content sink
+// because the processing of tokens took too long.
+
+nsresult nsParser::PostContinueEvent() {
+ if (!(mFlags & NS_PARSER_FLAG_PENDING_CONTINUE_EVENT)) {
+ // If this flag isn't set, then there shouldn't be a live continue event!
+ NS_ASSERTION(!mContinueEvent, "bad");
+
+ // This creates a reference cycle between this and the event that is
+ // broken when the event fires.
+ nsCOMPtr<nsIRunnable> event = new nsParserContinueEvent(this);
+ if (NS_FAILED(NS_DispatchToCurrentThread(event))) {
+ NS_WARNING("failed to dispatch parser continuation event");
+ } else {
+ mFlags |= NS_PARSER_FLAG_PENDING_CONTINUE_EVENT;
+ mContinueEvent = event;
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP_(void)
+nsParser::GetCommand(nsCString& aCommand) { aCommand = mCommandStr; }
+
+/**
+ * Call this method once you've created a parser, and want to instruct it
+ * about the command which caused the parser to be constructed. For example,
+ * this allows us to select a DTD which can do, say, view-source.
+ *
+ * @param aCommand the command string to set
+ */
+NS_IMETHODIMP_(void)
+nsParser::SetCommand(const char* aCommand) {
+ mCommandStr.Assign(aCommand);
+ if (mCommandStr.EqualsLiteral("view-source")) {
+ mCommand = eViewSource;
+ } else if (mCommandStr.EqualsLiteral("view-fragment")) {
+ mCommand = eViewFragment;
+ } else {
+ mCommand = eViewNormal;
+ }
+}
+
+/**
+ * Call this method once you've created a parser, and want to instruct it
+ * about the command which caused the parser to be constructed. For example,
+ * this allows us to select a DTD which can do, say, view-source.
+ *
+ * @param aParserCommand the command to set
+ */
+NS_IMETHODIMP_(void)
+nsParser::SetCommand(eParserCommands aParserCommand) {
+ mCommand = aParserCommand;
+}
+
+/**
+ * Call this method once you've created a parser, and want to instruct it
+ * about what charset to load
+ *
+ * @param aCharset- the charset of a document
+ * @param aCharsetSource- the source of the charset
+ */
+void nsParser::SetDocumentCharset(NotNull<const Encoding*> aCharset,
+ int32_t aCharsetSource) {
+ mCharset = aCharset;
+ mCharsetSource = aCharsetSource;
+ if (mParserContext && mParserContext->mScanner) {
+ mParserContext->mScanner->SetDocumentCharset(aCharset, aCharsetSource);
+ }
+}
+
+void nsParser::SetSinkCharset(NotNull<const Encoding*> aCharset) {
+ if (mSink) {
+ mSink->SetDocumentCharset(aCharset);
+ }
+}
+
+/**
+ * This method gets called in order to set the content
+ * sink for this parser to dump nodes to.
+ *
+ * @param nsIContentSink interface for node receiver
+ */
+NS_IMETHODIMP_(void)
+nsParser::SetContentSink(nsIContentSink* aSink) {
+ MOZ_ASSERT(aSink, "sink cannot be null!");
+ mSink = aSink;
+
+ if (mSink) {
+ mSink->SetParser(this);
+ nsCOMPtr<nsIHTMLContentSink> htmlSink = do_QueryInterface(mSink);
+ if (htmlSink) {
+ mIsAboutBlank = true;
+ }
+ }
+}
+
+/**
+ * retrieve the sink set into the parser
+ * @return current sink
+ */
+NS_IMETHODIMP_(nsIContentSink*)
+nsParser::GetContentSink() { return mSink; }
+
+static nsIDTD* FindSuitableDTD(CParserContext& aParserContext) {
+ // We always find a DTD.
+ aParserContext.mAutoDetectStatus = ePrimaryDetect;
+
+ // Quick check for view source.
+ MOZ_ASSERT(aParserContext.mParserCommand != eViewSource,
+ "The old parser is not supposed to be used for View Source "
+ "anymore.");
+
+ // Now see if we're parsing HTML (which, as far as we're concerned, simply
+ // means "not XML").
+ if (aParserContext.mDocType != eXML) {
+ return new CNavDTD();
+ }
+
+ // If we're here, then we'd better be parsing XML.
+ NS_ASSERTION(aParserContext.mDocType == eXML,
+ "What are you trying to send me, here?");
+ return new nsExpatDriver();
+}
+
+NS_IMETHODIMP
+nsParser::CancelParsingEvents() {
+ if (mFlags & NS_PARSER_FLAG_PENDING_CONTINUE_EVENT) {
+ NS_ASSERTION(mContinueEvent, "mContinueEvent is null");
+ // Revoke the pending continue parsing event
+ mContinueEvent = nullptr;
+ mFlags &= ~NS_PARSER_FLAG_PENDING_CONTINUE_EVENT;
+ }
+ return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+/**
+ * Evalutes EXPR1 and EXPR2 exactly once each, in that order. Stores the value
+ * of EXPR2 in RV is EXPR2 fails, otherwise RV contains the result of EXPR1
+ * (which could be success or failure).
+ *
+ * To understand the motivation for this construct, consider these example
+ * methods:
+ *
+ * nsresult nsSomething::DoThatThing(nsIWhatever* obj) {
+ * nsresult rv = NS_OK;
+ * ...
+ * return obj->DoThatThing();
+ * NS_ENSURE_SUCCESS(rv, rv);
+ * ...
+ * return rv;
+ * }
+ *
+ * void nsCaller::MakeThingsHappen() {
+ * return mSomething->DoThatThing(mWhatever);
+ * }
+ *
+ * Suppose, for whatever reason*, we want to shift responsibility for calling
+ * mWhatever->DoThatThing() from nsSomething::DoThatThing up to
+ * nsCaller::MakeThingsHappen. We might rewrite the two methods as follows:
+ *
+ * nsresult nsSomething::DoThatThing() {
+ * nsresult rv = NS_OK;
+ * ...
+ * ...
+ * return rv;
+ * }
+ *
+ * void nsCaller::MakeThingsHappen() {
+ * nsresult rv;
+ * PREFER_LATTER_ERROR_CODE(mSomething->DoThatThing(),
+ * mWhatever->DoThatThing(),
+ * rv);
+ * return rv;
+ * }
+ *
+ * *Possible reasons include: nsCaller doesn't want to give mSomething access
+ * to mWhatever, nsCaller wants to guarantee that mWhatever->DoThatThing() will
+ * be called regardless of how nsSomething::DoThatThing behaves, &c.
+ */
+#define PREFER_LATTER_ERROR_CODE(EXPR1, EXPR2, RV) \
+ { \
+ nsresult RV##__temp = EXPR1; \
+ RV = EXPR2; \
+ if (NS_FAILED(RV)) { \
+ RV = RV##__temp; \
+ } \
+ }
+
+/**
+ * This gets called just prior to the model actually
+ * being constructed. It's important to make this the
+ * last thing that happens right before parsing, so we
+ * can delay until the last moment the resolution of
+ * which DTD to use (unless of course we're assigned one).
+ */
+nsresult nsParser::WillBuildModel(nsString& aFilename) {
+ if (!mParserContext) return NS_ERROR_HTMLPARSER_INVALIDPARSERCONTEXT;
+
+ if (eUnknownDetect != mParserContext->mAutoDetectStatus) return NS_OK;
+
+ if (eDTDMode_unknown == mParserContext->mDTDMode ||
+ eDTDMode_autodetect == mParserContext->mDTDMode) {
+ if (mIsAboutBlank) {
+ mParserContext->mDTDMode = eDTDMode_quirks;
+ mParserContext->mDocType = eHTML_Quirks;
+ } else {
+ mParserContext->mDTDMode = eDTDMode_full_standards;
+ mParserContext->mDocType = eXML;
+ }
+ } // else XML fragment with nested parser context
+
+ NS_ASSERTION(!mDTD || !mParserContext->mPrevContext,
+ "Clobbering DTD for non-root parser context!");
+ mDTD = FindSuitableDTD(*mParserContext);
+ NS_ENSURE_TRUE(mDTD, NS_ERROR_OUT_OF_MEMORY);
+
+ nsITokenizer* tokenizer;
+ nsresult rv = mParserContext->GetTokenizer(mDTD, mSink, tokenizer);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = mDTD->WillBuildModel(*mParserContext, tokenizer, mSink);
+ nsresult sinkResult = mSink->WillBuildModel(mDTD->GetMode());
+ // nsIDTD::WillBuildModel used to be responsible for calling
+ // nsIContentSink::WillBuildModel, but that obligation isn't expressible
+ // in the nsIDTD interface itself, so it's sounder and simpler to give that
+ // responsibility back to the parser. The former behavior of the DTD was to
+ // NS_ENSURE_SUCCESS the sink WillBuildModel call, so if the sink returns
+ // failure we should use sinkResult instead of rv, to preserve the old error
+ // handling behavior of the DTD:
+ return NS_FAILED(sinkResult) ? sinkResult : rv;
+}
+
+/**
+ * This gets called when the parser is done with its input.
+ * Note that the parser may have been called recursively, so we
+ * have to check for a prev. context before closing out the DTD/sink.
+ */
+nsresult nsParser::DidBuildModel(nsresult anErrorCode) {
+ nsresult result = anErrorCode;
+
+ if (IsComplete()) {
+ if (mParserContext && !mParserContext->mPrevContext) {
+ // Let sink know if we're about to end load because we've been terminated.
+ // In that case we don't want it to run deferred scripts.
+ bool terminated = mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING;
+ if (mDTD && mSink) {
+ nsresult dtdResult = mDTD->DidBuildModel(anErrorCode),
+ sinkResult = mSink->DidBuildModel(terminated);
+ // nsIDTD::DidBuildModel used to be responsible for calling
+ // nsIContentSink::DidBuildModel, but that obligation isn't expressible
+ // in the nsIDTD interface itself, so it's sounder and simpler to give
+ // that responsibility back to the parser. The former behavior of the
+ // DTD was to NS_ENSURE_SUCCESS the sink DidBuildModel call, so if the
+ // sink returns failure we should use sinkResult instead of dtdResult,
+ // to preserve the old error handling behavior of the DTD:
+ result = NS_FAILED(sinkResult) ? sinkResult : dtdResult;
+ }
+
+ // Ref. to bug 61462.
+ mParserContext->mRequest = nullptr;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * This method adds a new parser context to the list,
+ * pushing the current one to the next position.
+ *
+ * @param ptr to new context
+ */
+void nsParser::PushContext(CParserContext& aContext) {
+ NS_ASSERTION(aContext.mPrevContext == mParserContext,
+ "Trying to push a context whose previous context differs from "
+ "the current parser context.");
+ mParserContext = &aContext;
+}
+
+/**
+ * This method pops the topmost context off the stack,
+ * returning it to the user. The next context (if any)
+ * becomes the current context.
+ * @update gess7/22/98
+ * @return prev. context
+ */
+CParserContext* nsParser::PopContext() {
+ CParserContext* oldContext = mParserContext;
+ if (oldContext) {
+ mParserContext = oldContext->mPrevContext;
+ if (mParserContext) {
+ // If the old context was blocked, propagate the blocked state
+ // back to the new one. Also, propagate the stream listener state
+ // but don't override onStop state to guarantee the call to
+ // DidBuildModel().
+ if (mParserContext->mStreamListenerState != eOnStop) {
+ mParserContext->mStreamListenerState = oldContext->mStreamListenerState;
+ }
+ }
+ }
+ return oldContext;
+}
+
+/**
+ * Call this when you want control whether or not the parser will parse
+ * and tokenize input (TRUE), or whether it just caches input to be
+ * parsed later (FALSE).
+ *
+ * @param aState determines whether we parse/tokenize or just cache.
+ * @return current state
+ */
+void nsParser::SetUnusedInput(nsString& aBuffer) { mUnusedInput = aBuffer; }
+
+/**
+ * Call this when you want to *force* the parser to terminate the
+ * parsing process altogether. This is binary -- so once you terminate
+ * you can't resume without restarting altogether.
+ */
+NS_IMETHODIMP
+nsParser::Terminate(void) {
+ // We should only call DidBuildModel once, so don't do anything if this is
+ // the second time that Terminate has been called.
+ if (mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING) {
+ return NS_OK;
+ }
+
+ nsresult result = NS_OK;
+ // XXX - [ until we figure out a way to break parser-sink circularity ]
+ // Hack - Hold a reference until we are completely done...
+ nsCOMPtr<nsIParser> kungFuDeathGrip(this);
+ mInternalState = result = NS_ERROR_HTMLPARSER_STOPPARSING;
+
+ // CancelParsingEvents must be called to avoid leaking the nsParser object
+ // @see bug 108049
+ // If NS_PARSER_FLAG_PENDING_CONTINUE_EVENT is set then CancelParsingEvents
+ // will reset it so DidBuildModel will call DidBuildModel on the DTD. Note:
+ // The IsComplete() call inside of DidBuildModel looks at the
+ // pendingContinueEvents flag.
+ CancelParsingEvents();
+
+ // If we got interrupted in the middle of a document.write, then we might
+ // have more than one parser context on our parsercontext stack. This has
+ // the effect of making DidBuildModel a no-op, meaning that we never call
+ // our sink's DidBuildModel and break the reference cycle, causing a leak.
+ // Since we're getting terminated, we manually clean up our context stack.
+ while (mParserContext && mParserContext->mPrevContext) {
+ CParserContext* prev = mParserContext->mPrevContext;
+ delete mParserContext;
+ mParserContext = prev;
+ }
+
+ if (mDTD) {
+ mDTD->Terminate();
+ DidBuildModel(result);
+ } else if (mSink) {
+ // We have no parser context or no DTD yet (so we got terminated before we
+ // got any data). Manually break the reference cycle with the sink.
+ result = mSink->DidBuildModel(true);
+ NS_ENSURE_SUCCESS(result, result);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsParser::ContinueInterruptedParsing() {
+ // If there are scripts executing, then the content sink is jumping the gun
+ // (probably due to a synchronous XMLHttpRequest) and will re-enable us
+ // later, see bug 460706.
+ if (!IsOkToProcessNetworkData()) {
+ return NS_OK;
+ }
+
+ // If the stream has already finished, there's a good chance
+ // that we might start closing things down when the parser
+ // is reenabled. To make sure that we're not deleted across
+ // the reenabling process, hold a reference to ourselves.
+ nsresult result = NS_OK;
+ nsCOMPtr<nsIParser> kungFuDeathGrip(this);
+ nsCOMPtr<nsIContentSink> sinkDeathGrip(mSink);
+
+#ifdef DEBUG
+ if (mBlocked) {
+ NS_WARNING("Don't call ContinueInterruptedParsing on a blocked parser.");
+ }
+#endif
+
+ bool isFinalChunk =
+ mParserContext && mParserContext->mStreamListenerState == eOnStop;
+
+ mProcessingNetworkData = true;
+ if (sinkDeathGrip) {
+ sinkDeathGrip->WillParse();
+ }
+ result = ResumeParse(true, isFinalChunk); // Ref. bug 57999
+ mProcessingNetworkData = false;
+
+ if (result != NS_OK) {
+ result = mInternalState;
+ }
+
+ return result;
+}
+
+/**
+ * Stops parsing temporarily. That is, it will prevent the
+ * parser from building up content model while scripts
+ * are being loaded (either an external script from a web
+ * page, or any number of extension content scripts).
+ */
+NS_IMETHODIMP_(void)
+nsParser::BlockParser() { mBlocked++; }
+
+/**
+ * Open up the parser for tokenization, building up content
+ * model..etc. However, this method does not resume parsing
+ * automatically. It's the callers' responsibility to restart
+ * the parsing engine.
+ */
+NS_IMETHODIMP_(void)
+nsParser::UnblockParser() {
+ MOZ_DIAGNOSTIC_ASSERT(mBlocked > 0);
+ if (MOZ_LIKELY(mBlocked > 0)) {
+ mBlocked--;
+ }
+}
+
+NS_IMETHODIMP_(void)
+nsParser::ContinueInterruptedParsingAsync() {
+ MOZ_ASSERT(mSink);
+ if (MOZ_LIKELY(mSink)) {
+ mSink->ContinueInterruptedParsingAsync();
+ }
+}
+
+/**
+ * Call this to query whether the parser is enabled or not.
+ */
+NS_IMETHODIMP_(bool)
+nsParser::IsParserEnabled() { return !mBlocked; }
+
+/**
+ * Call this to query whether the parser thinks it's done with parsing.
+ */
+NS_IMETHODIMP_(bool)
+nsParser::IsComplete() {
+ return !(mFlags & NS_PARSER_FLAG_PENDING_CONTINUE_EVENT);
+}
+
+void nsParser::HandleParserContinueEvent(nsParserContinueEvent* ev) {
+ // Ignore any revoked continue events...
+ if (mContinueEvent != ev) return;
+
+ mFlags &= ~NS_PARSER_FLAG_PENDING_CONTINUE_EVENT;
+ mContinueEvent = nullptr;
+
+ NS_ASSERTION(IsOkToProcessNetworkData(),
+ "Interrupted in the middle of a script?");
+ ContinueInterruptedParsing();
+}
+
+bool nsParser::IsInsertionPointDefined() { return false; }
+
+void nsParser::IncrementScriptNestingLevel() {}
+
+void nsParser::DecrementScriptNestingLevel() {}
+
+bool nsParser::HasNonzeroScriptNestingLevel() const { return false; }
+
+void nsParser::MarkAsNotScriptCreated(const char* aCommand) {}
+
+bool nsParser::IsScriptCreated() { return false; }
+
+/**
+ * This is the main controlling routine in the parsing process.
+ * Note that it may get called multiple times for the same scanner,
+ * since this is a pushed based system, and all the tokens may
+ * not have been consumed by the scanner during a given invocation
+ * of this method.
+ */
+NS_IMETHODIMP
+nsParser::Parse(nsIURI* aURL, nsIRequestObserver* aListener, void* aKey,
+ nsDTDMode aMode) {
+ MOZ_ASSERT(aURL, "Error: Null URL given");
+
+ nsresult result = NS_ERROR_HTMLPARSER_BADURL;
+ mObserver = aListener;
+
+ if (aURL) {
+ nsAutoCString spec;
+ nsresult rv = aURL->GetSpec(spec);
+ if (rv != NS_OK) {
+ return rv;
+ }
+ NS_ConvertUTF8toUTF16 theName(spec);
+
+ nsScanner* theScanner = new nsScanner(theName, false);
+ CParserContext* pc = new CParserContext(mParserContext, theScanner, aKey,
+ mCommand, aListener);
+ if (pc && theScanner) {
+ pc->mMultipart = true;
+ pc->mContextType = CParserContext::eCTURL;
+ pc->mDTDMode = aMode;
+ PushContext(*pc);
+
+ result = NS_OK;
+ } else {
+ result = mInternalState = NS_ERROR_HTMLPARSER_BADCONTEXT;
+ }
+ }
+ return result;
+}
+
+/**
+ * Used by XML fragment parsing below.
+ *
+ * @param aSourceBuffer contains a string-full of real content
+ */
+nsresult nsParser::Parse(const nsAString& aSourceBuffer, void* aKey,
+ bool aLastCall) {
+ nsresult result = NS_OK;
+
+ // Don't bother if we're never going to parse this.
+ if (mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING) {
+ return result;
+ }
+
+ if (!aLastCall && aSourceBuffer.IsEmpty()) {
+ // Nothing is being passed to the parser so return
+ // immediately. mUnusedInput will get processed when
+ // some data is actually passed in.
+ // But if this is the last call, make sure to finish up
+ // stuff correctly.
+ return result;
+ }
+
+ // Maintain a reference to ourselves so we don't go away
+ // till we're completely done.
+ nsCOMPtr<nsIParser> kungFuDeathGrip(this);
+
+ if (aLastCall || !aSourceBuffer.IsEmpty() || !mUnusedInput.IsEmpty()) {
+ // Note: The following code will always find the parser context associated
+ // with the given key, even if that context has been suspended (e.g., for
+ // another document.write call). This doesn't appear to be exactly what IE
+ // does in the case where this happens, but this makes more sense.
+ CParserContext* pc = mParserContext;
+ while (pc && pc->mKey != aKey) {
+ pc = pc->mPrevContext;
+ }
+
+ if (!pc) {
+ // Only make a new context if we don't have one, OR if we do, but has a
+ // different context key.
+ nsScanner* theScanner = new nsScanner(mUnusedInput);
+ NS_ENSURE_TRUE(theScanner, NS_ERROR_OUT_OF_MEMORY);
+
+ eAutoDetectResult theStatus = eUnknownDetect;
+
+ if (mParserContext &&
+ mParserContext->mMimeType.EqualsLiteral("application/xml")) {
+ // Ref. Bug 90379
+ NS_ASSERTION(mDTD, "How come the DTD is null?");
+
+ if (mParserContext) {
+ theStatus = mParserContext->mAutoDetectStatus;
+ // Added this to fix bug 32022.
+ }
+ }
+
+ pc = new CParserContext(mParserContext, theScanner, aKey, mCommand, 0,
+ theStatus, aLastCall);
+ NS_ENSURE_TRUE(pc, NS_ERROR_OUT_OF_MEMORY);
+
+ PushContext(*pc);
+
+ pc->mMultipart = !aLastCall; // By default
+ if (pc->mPrevContext) {
+ pc->mMultipart |= pc->mPrevContext->mMultipart;
+ }
+
+ // Start fix bug 40143
+ if (pc->mMultipart) {
+ pc->mStreamListenerState = eOnDataAvail;
+ if (pc->mScanner) {
+ pc->mScanner->SetIncremental(true);
+ }
+ } else {
+ pc->mStreamListenerState = eOnStop;
+ if (pc->mScanner) {
+ pc->mScanner->SetIncremental(false);
+ }
+ }
+ // end fix for 40143
+
+ pc->mContextType = CParserContext::eCTString;
+ pc->SetMimeType("application/xml"_ns);
+ pc->mDTDMode = eDTDMode_full_standards;
+
+ mUnusedInput.Truncate();
+
+ pc->mScanner->Append(aSourceBuffer);
+ // Do not interrupt document.write() - bug 95487
+ result = ResumeParse(false, false, false);
+ } else {
+ pc->mScanner->Append(aSourceBuffer);
+ if (!pc->mPrevContext) {
+ // Set stream listener state to eOnStop, on the final context - Fix
+ // 68160, to guarantee DidBuildModel() call - Fix 36148
+ if (aLastCall) {
+ pc->mStreamListenerState = eOnStop;
+ pc->mScanner->SetIncremental(false);
+ }
+
+ if (pc == mParserContext) {
+ // If pc is not mParserContext, then this call to ResumeParse would
+ // do the wrong thing and try to continue parsing using
+ // mParserContext. We need to wait to actually resume parsing on pc.
+ ResumeParse(false, false, false);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+NS_IMETHODIMP
+nsParser::ParseFragment(const nsAString& aSourceBuffer,
+ nsTArray<nsString>& aTagStack) {
+ nsresult result = NS_OK;
+ nsAutoString theContext;
+ uint32_t theCount = aTagStack.Length();
+ uint32_t theIndex = 0;
+
+ // Disable observers for fragments
+ mFlags &= ~NS_PARSER_FLAG_OBSERVERS_ENABLED;
+
+ for (theIndex = 0; theIndex < theCount; theIndex++) {
+ theContext.Append('<');
+ theContext.Append(aTagStack[theCount - theIndex - 1]);
+ theContext.Append('>');
+ }
+
+ if (theCount == 0) {
+ // Ensure that the buffer is not empty. Because none of the DTDs care
+ // about leading whitespace, this doesn't change the result.
+ theContext.Assign(' ');
+ }
+
+ // First, parse the context to build up the DTD's tag stack. Note that we
+ // pass false for the aLastCall parameter.
+ result = Parse(theContext, (void*)&theContext, false);
+ if (NS_FAILED(result)) {
+ mFlags |= NS_PARSER_FLAG_OBSERVERS_ENABLED;
+ return result;
+ }
+
+ if (!mSink) {
+ // Parse must have failed in the XML case and so the sink was killed.
+ return NS_ERROR_HTMLPARSER_STOPPARSING;
+ }
+
+ nsCOMPtr<nsIFragmentContentSink> fragSink = do_QueryInterface(mSink);
+ NS_ASSERTION(fragSink, "ParseFragment requires a fragment content sink");
+
+ fragSink->WillBuildContent();
+ // Now, parse the actual content. Note that this is the last call
+ // for HTML content, but for XML, we will want to build and parse
+ // the end tags. However, if tagStack is empty, it's the last call
+ // for XML as well.
+ if (theCount == 0) {
+ result = Parse(aSourceBuffer, &theContext, true);
+ fragSink->DidBuildContent();
+ } else {
+ // Add an end tag chunk, so expat will read the whole source buffer,
+ // and not worry about ']]' etc.
+ result = Parse(aSourceBuffer + u"</"_ns, &theContext, false);
+ fragSink->DidBuildContent();
+
+ if (NS_SUCCEEDED(result)) {
+ nsAutoString endContext;
+ for (theIndex = 0; theIndex < theCount; theIndex++) {
+ // we already added an end tag chunk above
+ if (theIndex > 0) {
+ endContext.AppendLiteral("</");
+ }
+
+ nsString& thisTag = aTagStack[theIndex];
+ // was there an xmlns=?
+ int32_t endOfTag = thisTag.FindChar(char16_t(' '));
+ if (endOfTag == -1) {
+ endContext.Append(thisTag);
+ } else {
+ endContext.Append(Substring(thisTag, 0, endOfTag));
+ }
+
+ endContext.Append('>');
+ }
+
+ result = Parse(endContext, &theContext, true);
+ }
+ }
+
+ mFlags |= NS_PARSER_FLAG_OBSERVERS_ENABLED;
+
+ return result;
+}
+
+/**
+ * This routine is called to cause the parser to continue parsing its
+ * underlying stream. This call allows the parse process to happen in
+ * chunks, such as when the content is push based, and we need to parse in
+ * pieces.
+ *
+ * An interesting change in how the parser gets used has led us to add extra
+ * processing to this method. The case occurs when the parser is blocked in
+ * one context, and gets a parse(string) call in another context. In this
+ * case, the parserContexts are linked. No problem.
+ *
+ * The problem is that Parse(string) assumes that it can proceed unabated,
+ * but if the parser is already blocked that assumption is false. So we
+ * needed to add a mechanism here to allow the parser to continue to process
+ * (the pop and free) contexts until 1) it get's blocked again; 2) it runs
+ * out of contexts.
+ *
+ *
+ * @param allowItertion : set to true if non-script resumption is requested
+ * @param aIsFinalChunk : tells us when the last chunk of data is provided.
+ * @return error code -- 0 if ok, non-zero if error.
+ */
+nsresult nsParser::ResumeParse(bool allowIteration, bool aIsFinalChunk,
+ bool aCanInterrupt) {
+ nsresult result = NS_OK;
+
+ if (!mBlocked && mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
+ result = WillBuildModel(mParserContext->mScanner->GetFilename());
+ if (NS_FAILED(result)) {
+ mFlags &= ~NS_PARSER_FLAG_CAN_TOKENIZE;
+ return result;
+ }
+
+ if (mDTD) {
+ mSink->WillResume();
+ bool theIterationIsOk = true;
+
+ while (result == NS_OK && theIterationIsOk) {
+ if (!mUnusedInput.IsEmpty() && mParserContext->mScanner) {
+ // -- Ref: Bug# 22485 --
+ // Insert the unused input into the source buffer
+ // as if it was read from the input stream.
+ // Adding UngetReadable() per vidur!!
+ mParserContext->mScanner->UngetReadable(mUnusedInput);
+ mUnusedInput.Truncate(0);
+ }
+
+ // Only allow parsing to be interrupted in the subsequent call to
+ // build model.
+ nsresult theTokenizerResult = (mFlags & NS_PARSER_FLAG_CAN_TOKENIZE)
+ ? Tokenize(aIsFinalChunk)
+ : NS_OK;
+ result = BuildModel();
+
+ if (result == NS_ERROR_HTMLPARSER_INTERRUPTED && aIsFinalChunk) {
+ PostContinueEvent();
+ }
+
+ theIterationIsOk = theTokenizerResult != NS_ERROR_HTMLPARSER_EOF &&
+ result != NS_ERROR_HTMLPARSER_INTERRUPTED;
+
+ // Make sure not to stop parsing too early. Therefore, before shutting
+ // down the parser, it's important to check whether the input buffer
+ // has been scanned to completion (theTokenizerResult should be kEOF).
+ // kEOF -> End of buffer.
+
+ // If we're told to block the parser, we disable all further parsing
+ // (and cache any data coming in) until the parser is re-enabled.
+ if (NS_ERROR_HTMLPARSER_BLOCK == result) {
+ mSink->WillInterrupt();
+ if (!mBlocked) {
+ // If we were blocked by a recursive invocation, don't re-block.
+ BlockParser();
+ }
+ return NS_OK;
+ }
+ if (NS_ERROR_HTMLPARSER_STOPPARSING == result) {
+ // Note: Parser Terminate() calls DidBuildModel.
+ if (mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
+ DidBuildModel(mStreamStatus);
+ mInternalState = result;
+ }
+
+ return NS_OK;
+ }
+ if ((NS_OK == result &&
+ theTokenizerResult == NS_ERROR_HTMLPARSER_EOF) ||
+ result == NS_ERROR_HTMLPARSER_INTERRUPTED) {
+ bool theContextIsStringBased =
+ CParserContext::eCTString == mParserContext->mContextType;
+
+ if (mParserContext->mStreamListenerState == eOnStop ||
+ !mParserContext->mMultipart || theContextIsStringBased) {
+ if (!mParserContext->mPrevContext) {
+ if (mParserContext->mStreamListenerState == eOnStop) {
+ DidBuildModel(mStreamStatus);
+ return NS_OK;
+ }
+ } else {
+ CParserContext* theContext = PopContext();
+ if (theContext) {
+ theIterationIsOk = allowIteration && theContextIsStringBased;
+ if (theContext->mCopyUnused) {
+ if (!theContext->mScanner->CopyUnusedData(mUnusedInput)) {
+ mInternalState = NS_ERROR_OUT_OF_MEMORY;
+ }
+ }
+
+ delete theContext;
+ }
+
+ result = mInternalState;
+ aIsFinalChunk = mParserContext &&
+ mParserContext->mStreamListenerState == eOnStop;
+ // ...then intentionally fall through to mSink->WillInterrupt()...
+ }
+ }
+ }
+
+ if (theTokenizerResult == NS_ERROR_HTMLPARSER_EOF ||
+ result == NS_ERROR_HTMLPARSER_INTERRUPTED) {
+ result = (result == NS_ERROR_HTMLPARSER_INTERRUPTED) ? NS_OK : result;
+ mSink->WillInterrupt();
+ }
+ }
+ } else {
+ mInternalState = result = NS_ERROR_HTMLPARSER_UNRESOLVEDDTD;
+ }
+ }
+
+ return (result == NS_ERROR_HTMLPARSER_INTERRUPTED) ? NS_OK : result;
+}
+
+/**
+ * This is where we loop over the tokens created in the
+ * tokenization phase, and try to make sense out of them.
+ */
+nsresult nsParser::BuildModel() {
+ nsITokenizer* theTokenizer = nullptr;
+
+ nsresult result = NS_OK;
+ if (mParserContext) {
+ result = mParserContext->GetTokenizer(mDTD, mSink, theTokenizer);
+ }
+
+ if (NS_SUCCEEDED(result)) {
+ if (mDTD) {
+ result = mDTD->BuildModel(theTokenizer, mSink);
+ }
+ } else {
+ mInternalState = result = NS_ERROR_HTMLPARSER_BADTOKENIZER;
+ }
+ return result;
+}
+
+/*******************************************************************
+ These methods are used to talk to the netlib system...
+ *******************************************************************/
+
+nsresult nsParser::OnStartRequest(nsIRequest* request) {
+ MOZ_ASSERT(eNone == mParserContext->mStreamListenerState,
+ "Parser's nsIStreamListener API was not setup "
+ "correctly in constructor.");
+
+ if (mObserver) {
+ mObserver->OnStartRequest(request);
+ }
+ mParserContext->mStreamListenerState = eOnStart;
+ mParserContext->mAutoDetectStatus = eUnknownDetect;
+ mParserContext->mRequest = request;
+
+ NS_ASSERTION(!mParserContext->mPrevContext,
+ "Clobbering DTD for non-root parser context!");
+ mDTD = nullptr;
+
+ nsresult rv;
+ nsAutoCString contentType;
+ nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
+ if (channel) {
+ rv = channel->GetContentType(contentType);
+ if (NS_SUCCEEDED(rv)) {
+ mParserContext->SetMimeType(contentType);
+ }
+ }
+
+ rv = NS_OK;
+
+ return rv;
+}
+
+static bool ExtractCharsetFromXmlDeclaration(const unsigned char* aBytes,
+ int32_t aLen,
+ nsCString& oCharset) {
+ // This code is rather pointless to have. Might as well reuse expat as
+ // seen in nsHtml5StreamParser. -- hsivonen
+ oCharset.Truncate();
+ if ((aLen >= 5) && ('<' == aBytes[0]) && ('?' == aBytes[1]) &&
+ ('x' == aBytes[2]) && ('m' == aBytes[3]) && ('l' == aBytes[4])) {
+ int32_t i;
+ bool versionFound = false, encodingFound = false;
+ for (i = 6; i < aLen && !encodingFound; ++i) {
+ // end of XML declaration?
+ if ((((char*)aBytes)[i] == '?') && ((i + 1) < aLen) &&
+ (((char*)aBytes)[i + 1] == '>')) {
+ break;
+ }
+ // Version is required.
+ if (!versionFound) {
+ // Want to avoid string comparisons, hence looking for 'n'
+ // and only if found check the string leading to it. Not
+ // foolproof, but fast.
+ // The shortest string allowed before this is (strlen==13):
+ // <?xml version
+ if ((((char*)aBytes)[i] == 'n') && (i >= 12) &&
+ (0 == PL_strncmp("versio", (char*)(aBytes + i - 6), 6))) {
+ // Fast forward through version
+ char q = 0;
+ for (++i; i < aLen; ++i) {
+ char qi = ((char*)aBytes)[i];
+ if (qi == '\'' || qi == '"') {
+ if (q && q == qi) {
+ // ending quote
+ versionFound = true;
+ break;
+ } else {
+ // Starting quote
+ q = qi;
+ }
+ }
+ }
+ }
+ } else {
+ // encoding must follow version
+ // Want to avoid string comparisons, hence looking for 'g'
+ // and only if found check the string leading to it. Not
+ // foolproof, but fast.
+ // The shortest allowed string before this (strlen==26):
+ // <?xml version="1" encoding
+ if ((((char*)aBytes)[i] == 'g') && (i >= 25) &&
+ (0 == PL_strncmp("encodin", (char*)(aBytes + i - 7), 7))) {
+ int32_t encStart = 0;
+ char q = 0;
+ for (++i; i < aLen; ++i) {
+ char qi = ((char*)aBytes)[i];
+ if (qi == '\'' || qi == '"') {
+ if (q && q == qi) {
+ int32_t count = i - encStart;
+ // encoding value is invalid if it is UTF-16
+ if (count > 0 &&
+ PL_strncasecmp("UTF-16", (char*)(aBytes + encStart),
+ count)) {
+ oCharset.Assign((char*)(aBytes + encStart), count);
+ }
+ encodingFound = true;
+ break;
+ } else {
+ encStart = i + 1;
+ q = qi;
+ }
+ }
+ }
+ }
+ } // if (!versionFound)
+ } // for
+ }
+ return !oCharset.IsEmpty();
+}
+
+inline char GetNextChar(nsACString::const_iterator& aStart,
+ nsACString::const_iterator& aEnd) {
+ NS_ASSERTION(aStart != aEnd, "end of buffer");
+ return (++aStart != aEnd) ? *aStart : '\0';
+}
+
+static nsresult NoOpParserWriteFunc(nsIInputStream* in, void* closure,
+ const char* fromRawSegment,
+ uint32_t toOffset, uint32_t count,
+ uint32_t* writeCount) {
+ *writeCount = count;
+ return NS_OK;
+}
+
+typedef struct {
+ bool mNeedCharsetCheck;
+ nsParser* mParser;
+ nsScanner* mScanner;
+ nsIRequest* mRequest;
+} ParserWriteStruct;
+
+/*
+ * This function is invoked as a result of a call to a stream's
+ * ReadSegments() method. It is called for each contiguous buffer
+ * of data in the underlying stream or pipe. Using ReadSegments
+ * allows us to avoid copying data to read out of the stream.
+ */
+static nsresult ParserWriteFunc(nsIInputStream* in, void* closure,
+ const char* fromRawSegment, uint32_t toOffset,
+ uint32_t count, uint32_t* writeCount) {
+ nsresult result;
+ ParserWriteStruct* pws = static_cast<ParserWriteStruct*>(closure);
+ const unsigned char* buf =
+ reinterpret_cast<const unsigned char*>(fromRawSegment);
+ uint32_t theNumRead = count;
+
+ if (!pws) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (pws->mNeedCharsetCheck) {
+ pws->mNeedCharsetCheck = false;
+ int32_t source;
+ auto preferred = pws->mParser->GetDocumentCharset(source);
+
+ // This code was bogus when I found it. It expects the BOM or the XML
+ // declaration to be entirely in the first network buffer. -- hsivonen
+ const Encoding* encoding;
+ size_t bomLength;
+ Tie(encoding, bomLength) = Encoding::ForBOM(Span(buf, count));
+ Unused << bomLength;
+ if (encoding) {
+ // The decoder will swallow the BOM. The UTF-16 will re-sniff for
+ // endianness. The value of preferred is now "UTF-8", "UTF-16LE"
+ // or "UTF-16BE".
+ preferred = WrapNotNull(encoding);
+ source = kCharsetFromByteOrderMark;
+ } else if (source < kCharsetFromChannel) {
+ nsAutoCString declCharset;
+
+ if (ExtractCharsetFromXmlDeclaration(buf, count, declCharset)) {
+ encoding = Encoding::ForLabel(declCharset);
+ if (encoding) {
+ preferred = WrapNotNull(encoding);
+ source = kCharsetFromMetaTag;
+ }
+ }
+ }
+
+ pws->mParser->SetDocumentCharset(preferred, source);
+ pws->mParser->SetSinkCharset(preferred);
+ }
+
+ result = pws->mScanner->Append(fromRawSegment, theNumRead);
+ if (NS_SUCCEEDED(result)) {
+ *writeCount = count;
+ }
+
+ return result;
+}
+
+nsresult nsParser::OnDataAvailable(nsIRequest* request,
+ nsIInputStream* pIStream,
+ uint64_t sourceOffset, uint32_t aLength) {
+ MOZ_ASSERT((eOnStart == mParserContext->mStreamListenerState ||
+ eOnDataAvail == mParserContext->mStreamListenerState),
+ "Error: OnStartRequest() must be called before OnDataAvailable()");
+ MOZ_ASSERT(NS_InputStreamIsBuffered(pIStream),
+ "Must have a buffered input stream");
+
+ nsresult rv = NS_OK;
+
+ if (mIsAboutBlank) {
+ MOZ_ASSERT(false, "Must not get OnDataAvailable for about:blank");
+ // ... but if an extension tries to feed us data for about:blank in a
+ // release build, silently ignore the data.
+ uint32_t totalRead;
+ rv = pIStream->ReadSegments(NoOpParserWriteFunc, nullptr, aLength,
+ &totalRead);
+ return rv;
+ }
+
+ CParserContext* theContext = mParserContext;
+
+ while (theContext && theContext->mRequest != request) {
+ theContext = theContext->mPrevContext;
+ }
+
+ if (theContext) {
+ theContext->mStreamListenerState = eOnDataAvail;
+
+ if (eInvalidDetect == theContext->mAutoDetectStatus) {
+ if (theContext->mScanner) {
+ nsScannerIterator iter;
+ theContext->mScanner->EndReading(iter);
+ theContext->mScanner->SetPosition(iter, true);
+ }
+ }
+
+ uint32_t totalRead;
+ ParserWriteStruct pws;
+ pws.mNeedCharsetCheck = true;
+ pws.mParser = this;
+ pws.mScanner = theContext->mScanner.get();
+ pws.mRequest = request;
+
+ rv = pIStream->ReadSegments(ParserWriteFunc, &pws, aLength, &totalRead);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ if (IsOkToProcessNetworkData()) {
+ nsCOMPtr<nsIParser> kungFuDeathGrip(this);
+ nsCOMPtr<nsIContentSink> sinkDeathGrip(mSink);
+ mProcessingNetworkData = true;
+ if (sinkDeathGrip) {
+ sinkDeathGrip->WillParse();
+ }
+ rv = ResumeParse();
+ mProcessingNetworkData = false;
+ }
+ } else {
+ rv = NS_ERROR_UNEXPECTED;
+ }
+
+ return rv;
+}
+
+/**
+ * This is called by the networking library once the last block of data
+ * has been collected from the net.
+ */
+nsresult nsParser::OnStopRequest(nsIRequest* request, nsresult status) {
+ nsresult rv = NS_OK;
+
+ CParserContext* pc = mParserContext;
+ while (pc) {
+ if (pc->mRequest == request) {
+ pc->mStreamListenerState = eOnStop;
+ pc->mScanner->SetIncremental(false);
+ break;
+ }
+
+ pc = pc->mPrevContext;
+ }
+
+ mStreamStatus = status;
+
+ if (IsOkToProcessNetworkData() && NS_SUCCEEDED(rv)) {
+ mProcessingNetworkData = true;
+ if (mSink) {
+ mSink->WillParse();
+ }
+ rv = ResumeParse(true, true);
+ mProcessingNetworkData = false;
+ }
+
+ // If the parser isn't enabled, we don't finish parsing till
+ // it is reenabled.
+
+ // XXX Should we wait to notify our observers as well if the
+ // parser isn't yet enabled?
+ if (mObserver) {
+ mObserver->OnStopRequest(request, status);
+ }
+
+ return rv;
+}
+
+/*******************************************************************
+ Here come the tokenization methods...
+ *******************************************************************/
+
+/**
+ * Part of the code sandwich, this gets called right before
+ * the tokenization process begins. The main reason for
+ * this call is to allow the delegate to do initialization.
+ */
+bool nsParser::WillTokenize(bool aIsFinalChunk) {
+ if (!mParserContext) {
+ return true;
+ }
+
+ nsITokenizer* theTokenizer;
+ nsresult result = mParserContext->GetTokenizer(mDTD, mSink, theTokenizer);
+ NS_ENSURE_SUCCESS(result, false);
+ return NS_SUCCEEDED(theTokenizer->WillTokenize(aIsFinalChunk));
+}
+
+/**
+ * This is the primary control routine to consume tokens.
+ * It iteratively consumes tokens until an error occurs or
+ * you run out of data.
+ */
+nsresult nsParser::Tokenize(bool aIsFinalChunk) {
+ nsITokenizer* theTokenizer;
+
+ nsresult result = NS_ERROR_NOT_AVAILABLE;
+ if (mParserContext) {
+ result = mParserContext->GetTokenizer(mDTD, mSink, theTokenizer);
+ }
+
+ if (NS_SUCCEEDED(result)) {
+ bool flushTokens = false;
+
+ bool killSink = false;
+
+ WillTokenize(aIsFinalChunk);
+ while (NS_SUCCEEDED(result)) {
+ mParserContext->mScanner->Mark();
+ result =
+ theTokenizer->ConsumeToken(*mParserContext->mScanner, flushTokens);
+ if (NS_FAILED(result)) {
+ mParserContext->mScanner->RewindToMark();
+ if (NS_ERROR_HTMLPARSER_EOF == result) {
+ break;
+ }
+ if (NS_ERROR_HTMLPARSER_STOPPARSING == result) {
+ killSink = true;
+ result = Terminate();
+ break;
+ }
+ } else if (flushTokens && (mFlags & NS_PARSER_FLAG_OBSERVERS_ENABLED)) {
+ // I added the extra test of NS_PARSER_FLAG_OBSERVERS_ENABLED to fix
+ // Bug# 23931. Flush tokens on seeing </SCRIPT> -- Ref: Bug# 22485 --
+ // Also remember to update the marked position.
+ mFlags |= NS_PARSER_FLAG_FLUSH_TOKENS;
+ mParserContext->mScanner->Mark();
+ break;
+ }
+ }
+
+ if (killSink) {
+ mSink = nullptr;
+ }
+ } else {
+ result = mInternalState = NS_ERROR_HTMLPARSER_BADTOKENIZER;
+ }
+
+ return result;
+}
+
+/**
+ * Get the channel associated with this parser
+ *
+ * @param aChannel out param that will contain the result
+ * @return NS_OK if successful
+ */
+NS_IMETHODIMP
+nsParser::GetChannel(nsIChannel** aChannel) {
+ nsresult result = NS_ERROR_NOT_AVAILABLE;
+ if (mParserContext && mParserContext->mRequest) {
+ result = CallQueryInterface(mParserContext->mRequest, aChannel);
+ }
+ return result;
+}
+
+/**
+ * Get the DTD associated with this parser
+ */
+NS_IMETHODIMP
+nsParser::GetDTD(nsIDTD** aDTD) {
+ if (mParserContext) {
+ NS_IF_ADDREF(*aDTD = mDTD);
+ }
+
+ return NS_OK;
+}
+
+/**
+ * Get this as nsIStreamListener
+ */
+nsIStreamListener* nsParser::GetStreamListener() { return this; }
diff --git a/parser/htmlparser/nsParser.h b/parser/htmlparser/nsParser.h
new file mode 100644
index 0000000000..f081c0507d
--- /dev/null
+++ b/parser/htmlparser/nsParser.h
@@ -0,0 +1,391 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * MODULE NOTES:
+ *
+ * This class does two primary jobs:
+ * 1) It iterates the tokens provided during the
+ * tokenization process, identifing where elements
+ * begin and end (doing validation and normalization).
+ * 2) It controls and coordinates with an instance of
+ * the IContentSink interface, to coordinate the
+ * the production of the content model.
+ *
+ * The basic operation of this class assumes that an HTML
+ * document is non-normalized. Therefore, we don't process
+ * the document in a normalized way. Don't bother to look
+ * for methods like: doHead() or doBody().
+ *
+ * Instead, in order to be backward compatible, we must
+ * scan the set of tokens and perform this basic set of
+ * operations:
+ * 1) Determine the token type (easy, since the tokens know)
+ * 2) Determine the appropriate section of the HTML document
+ * each token belongs in (HTML,HEAD,BODY,FRAMESET).
+ * 3) Insert content into our document (via the sink) into
+ * the correct section.
+ * 4) In the case of tags that belong in the BODY, we must
+ * ensure that our underlying document state reflects
+ * the appropriate context for our tag.
+ *
+ * For example,if we see a <TR>, we must ensure our
+ * document contains a table into which the row can
+ * be placed. This may result in "implicit containers"
+ * created to ensure a well-formed document.
+ *
+ */
+
+#ifndef NS_PARSER__
+#define NS_PARSER__
+
+#include "nsIParser.h"
+#include "nsDeque.h"
+#include "CParserContext.h"
+#include "nsParserCIID.h"
+#include "nsITokenizer.h"
+#include "nsHTMLTags.h"
+#include "nsIContentSink.h"
+#include "nsCOMArray.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsWeakReference.h"
+
+class nsIDTD;
+class nsIRunnable;
+
+#ifdef _MSC_VER
+# pragma warning(disable : 4275)
+#endif
+
+class nsParser final : public nsIParser,
+ public nsIStreamListener,
+ public nsSupportsWeakReference {
+ /**
+ * Destructor
+ * @update gess5/11/98
+ */
+ virtual ~nsParser();
+
+ public:
+ /**
+ * Called on module init
+ */
+ static nsresult Init();
+
+ /**
+ * Called on module shutdown
+ */
+ static void Shutdown();
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsParser, nsIParser)
+
+ /**
+ * default constructor
+ * @update gess5/11/98
+ */
+ nsParser();
+
+ /**
+ * Select given content sink into parser for parser output
+ * @update gess5/11/98
+ * @param aSink is the new sink to be used by parser
+ * @return old sink, or nullptr
+ */
+ NS_IMETHOD_(void) SetContentSink(nsIContentSink* aSink) override;
+
+ /**
+ * retrive the sink set into the parser
+ * @update gess5/11/98
+ * @param aSink is the new sink to be used by parser
+ * @return old sink, or nullptr
+ */
+ NS_IMETHOD_(nsIContentSink*) GetContentSink(void) override;
+
+ /**
+ * Call this method once you've created a parser, and want to instruct it
+ * about the command which caused the parser to be constructed. For example,
+ * this allows us to select a DTD which can do, say, view-source.
+ *
+ * @update gess 3/25/98
+ * @param aCommand -- ptrs to string that contains command
+ * @return nada
+ */
+ NS_IMETHOD_(void) GetCommand(nsCString& aCommand) override;
+ NS_IMETHOD_(void) SetCommand(const char* aCommand) override;
+ NS_IMETHOD_(void) SetCommand(eParserCommands aParserCommand) override;
+
+ /**
+ * Call this method once you've created a parser, and want to instruct it
+ * about what charset to load
+ *
+ * @update ftang 4/23/99
+ * @param aCharset- the charset of a document
+ * @param aCharsetSource- the source of the charset
+ * @return nada
+ */
+ virtual void SetDocumentCharset(NotNull<const Encoding*> aCharset,
+ int32_t aSource) override;
+
+ NotNull<const Encoding*> GetDocumentCharset(int32_t& aSource) {
+ aSource = mCharsetSource;
+ return mCharset;
+ }
+
+ /**
+ * Cause parser to parse input from given URL
+ * @update gess5/11/98
+ * @param aURL is a descriptor for source document
+ * @param aListener is a listener to forward notifications to
+ * @return TRUE if all went well -- FALSE otherwise
+ */
+ NS_IMETHOD Parse(nsIURI* aURL, nsIRequestObserver* aListener = nullptr,
+ void* aKey = 0,
+ nsDTDMode aMode = eDTDMode_autodetect) override;
+
+ /**
+ * This method needs documentation
+ */
+ NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer,
+ nsTArray<nsString>& aTagStack) override;
+
+ /**
+ * This method gets called when the tokens have been consumed, and it's time
+ * to build the model via the content sink.
+ * @update gess5/11/98
+ * @return YES if model building went well -- NO otherwise.
+ */
+ NS_IMETHOD BuildModel(void) override;
+
+ NS_IMETHOD ContinueInterruptedParsing() override;
+ NS_IMETHOD_(void) BlockParser() override;
+ NS_IMETHOD_(void) UnblockParser() override;
+ NS_IMETHOD_(void) ContinueInterruptedParsingAsync() override;
+ NS_IMETHOD Terminate(void) override;
+
+ /**
+ * Call this to query whether the parser is enabled or not.
+ *
+ * @update vidur 4/12/99
+ * @return current state
+ */
+ NS_IMETHOD_(bool) IsParserEnabled() override;
+
+ /**
+ * Call this to query whether the parser thinks it's done with parsing.
+ *
+ * @update rickg 5/12/01
+ * @return complete state
+ */
+ NS_IMETHOD_(bool) IsComplete() override;
+
+ /**
+ * This rather arcane method (hack) is used as a signal between the
+ * DTD and the parser. It allows the DTD to tell the parser that content
+ * that comes through (parser::parser(string)) but not consumed should
+ * propagate into the next string based parse call.
+ *
+ * @update gess 9/1/98
+ * @param aState determines whether we propagate unused string content.
+ * @return current state
+ */
+ void SetUnusedInput(nsString& aBuffer);
+
+ /**
+ * This method gets called (automatically) during incremental parsing
+ * @update gess5/11/98
+ * @return TRUE if all went well, otherwise FALSE
+ */
+ virtual nsresult ResumeParse(bool allowIteration = true,
+ bool aIsFinalChunk = false,
+ bool aCanInterrupt = true);
+
+ //*********************************************
+ // These methods are callback methods used by
+ // net lib to let us know about our inputstream.
+ //*********************************************
+ // nsIRequestObserver methods:
+ NS_DECL_NSIREQUESTOBSERVER
+
+ // nsIStreamListener methods:
+ NS_DECL_NSISTREAMLISTENER
+
+ void PushContext(CParserContext& aContext);
+ CParserContext* PopContext();
+ CParserContext* PeekContext() { return mParserContext; }
+
+ /**
+ * Get the channel associated with this parser
+ * @update harishd,gagan 07/17/01
+ * @param aChannel out param that will contain the result
+ * @return NS_OK if successful
+ */
+ NS_IMETHOD GetChannel(nsIChannel** aChannel) override;
+
+ /**
+ * Get the DTD associated with this parser
+ * @update vidur 9/29/99
+ * @param aDTD out param that will contain the result
+ * @return NS_OK if successful, NS_ERROR_FAILURE for runtime error
+ */
+ NS_IMETHOD GetDTD(nsIDTD** aDTD) override;
+
+ /**
+ * Get the nsIStreamListener for this parser
+ */
+ virtual nsIStreamListener* GetStreamListener() override;
+
+ void SetSinkCharset(NotNull<const Encoding*> aCharset);
+
+ /**
+ * Removes continue parsing events
+ * @update kmcclusk 5/18/98
+ */
+
+ NS_IMETHOD CancelParsingEvents() override;
+
+ /**
+ * Return true.
+ */
+ virtual bool IsInsertionPointDefined() override;
+
+ /**
+ * No-op.
+ */
+ void IncrementScriptNestingLevel() final;
+
+ /**
+ * No-op.
+ */
+ void DecrementScriptNestingLevel() final;
+
+ bool HasNonzeroScriptNestingLevel() const final;
+
+ /**
+ * No-op.
+ */
+ virtual void MarkAsNotScriptCreated(const char* aCommand) override;
+
+ /**
+ * Always false.
+ */
+ virtual bool IsScriptCreated() override;
+
+ /**
+ * Set to parser state to indicate whether parsing tokens can be interrupted
+ * @param aCanInterrupt true if parser can be interrupted, false if it can
+ * not be interrupted.
+ * @update kmcclusk 5/18/98
+ */
+ void SetCanInterrupt(bool aCanInterrupt);
+
+ /**
+ * This is called when the final chunk has been
+ * passed to the parser and the content sink has
+ * interrupted token processing. It schedules
+ * a ParserContinue PL_Event which will ask the parser
+ * to HandleParserContinueEvent when it is handled.
+ * @update kmcclusk6/1/2001
+ */
+ nsresult PostContinueEvent();
+
+ /**
+ * Fired when the continue parse event is triggered.
+ * @update kmcclusk 5/18/98
+ */
+ void HandleParserContinueEvent(class nsParserContinueEvent*);
+
+ virtual void Reset() override {
+ Cleanup();
+ Initialize();
+ }
+
+ bool IsScriptExecuting() { return mSink && mSink->IsScriptExecuting(); }
+
+ bool IsOkToProcessNetworkData() {
+ return !IsScriptExecuting() && !mProcessingNetworkData;
+ }
+
+ protected:
+ void Initialize(bool aConstructor = false);
+ void Cleanup();
+
+ /**
+ *
+ * @update gess5/18/98
+ * @param
+ * @return
+ */
+ nsresult WillBuildModel(nsString& aFilename);
+
+ /**
+ *
+ * @update gess5/18/98
+ * @param
+ * @return
+ */
+ nsresult DidBuildModel(nsresult anErrorCode);
+
+ private:
+ /*******************************************
+ These are the tokenization methods...
+ *******************************************/
+
+ /**
+ * Part of the code sandwich, this gets called right before
+ * the tokenization process begins. The main reason for
+ * this call is to allow the delegate to do initialization.
+ *
+ * @update gess 3/25/98
+ * @param
+ * @return TRUE if it's ok to proceed
+ */
+ bool WillTokenize(bool aIsFinalChunk = false);
+
+ /**
+ * This is the primary control routine. It iteratively
+ * consumes tokens until an error occurs or you run out
+ * of data.
+ *
+ * @update gess 3/25/98
+ * @return error code
+ */
+ nsresult Tokenize(bool aIsFinalChunk = false);
+
+ /**
+ * Pushes XML fragment parsing data to expat without an input stream.
+ */
+ nsresult Parse(const nsAString& aSourceBuffer, void* aKey, bool aLastCall);
+
+ protected:
+ //*********************************************
+ // And now, some data members...
+ //*********************************************
+
+ CParserContext* mParserContext;
+ nsCOMPtr<nsIDTD> mDTD;
+ nsCOMPtr<nsIRequestObserver> mObserver;
+ nsCOMPtr<nsIContentSink> mSink;
+ nsIRunnable* mContinueEvent; // weak ref
+
+ eParserCommands mCommand;
+ nsresult mInternalState;
+ nsresult mStreamStatus;
+ int32_t mCharsetSource;
+
+ uint16_t mFlags;
+ uint32_t mBlocked;
+
+ nsString mUnusedInput;
+ NotNull<const Encoding*> mCharset;
+ nsCString mCommandStr;
+
+ bool mProcessingNetworkData;
+ bool mIsAboutBlank;
+};
+
+nsresult nsParserInitialize();
+
+#endif
diff --git a/parser/htmlparser/nsParserBase.h b/parser/htmlparser/nsParserBase.h
new file mode 100644
index 0000000000..f1518abef6
--- /dev/null
+++ b/parser/htmlparser/nsParserBase.h
@@ -0,0 +1,19 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsParserBase_h_
+#define nsParserBase_h_
+
+#include "nsIChannel.h"
+
+class nsParserBase : public nsISupports {
+ public:
+ NS_IMETHOD_(bool) IsParserEnabled() { return true; }
+ NS_IMETHOD GetChannel(nsIChannel** aChannel) {
+ *aChannel = nullptr;
+ return NS_OK;
+ }
+};
+
+#endif // nsParserBase_h_
diff --git a/parser/htmlparser/nsParserCIID.h b/parser/htmlparser/nsParserCIID.h
new file mode 100644
index 0000000000..67f7c3d52b
--- /dev/null
+++ b/parser/htmlparser/nsParserCIID.h
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsParserCIID_h__
+#define nsParserCIID_h__
+
+// {2ce606b0-bee6-11d1-aad9-00805f8a3e14}
+#define NS_PARSER_CID \
+ { \
+ 0x2ce606b0, 0xbee6, 0x11d1, { \
+ 0xaa, 0xd9, 0x0, 0x80, 0x5f, 0x8a, 0x3e, 0x14 \
+ } \
+ }
+
+#endif
diff --git a/parser/htmlparser/nsParserConstants.h b/parser/htmlparser/nsParserConstants.h
new file mode 100644
index 0000000000..bd6e4d477d
--- /dev/null
+++ b/parser/htmlparser/nsParserConstants.h
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsParserConstants_h_
+#define nsParserConstants_h_
+
+const char16_t kSpace = ' ';
+const char16_t kQuote = '"';
+const char16_t kApostrophe = '\'';
+const char16_t kLessThan = '<';
+const char16_t kGreaterThan = '>';
+const char16_t kAmpersand = '&';
+const char16_t kBackSlash = '\\';
+const char16_t kEqual = '=';
+const char16_t kSemicolon = ';';
+const char16_t kComma = ',';
+const char16_t kNullCh = '\0';
+
+#endif // nsParserConstants_h_
diff --git a/parser/htmlparser/nsParserModule.cpp b/parser/htmlparser/nsParserModule.cpp
new file mode 100644
index 0000000000..a11548b412
--- /dev/null
+++ b/parser/htmlparser/nsParserModule.cpp
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsHTMLTags.h"
+
+nsresult nsParserInitialize() {
+ nsresult rv = nsHTMLTags::AddRefTable();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+#ifdef DEBUG
+ CheckElementTable();
+ nsHTMLTags::TestTagTable();
+#endif
+
+ return rv;
+}
diff --git a/parser/htmlparser/nsParserMsgUtils.cpp b/parser/htmlparser/nsParserMsgUtils.cpp
new file mode 100644
index 0000000000..0d9b020de9
--- /dev/null
+++ b/parser/htmlparser/nsParserMsgUtils.cpp
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIStringBundle.h"
+#include "nsString.h"
+#include "nsParserMsgUtils.h"
+#include "nsNetCID.h"
+#include "mozilla/Services.h"
+
+static nsresult GetBundle(const char* aPropFileName,
+ nsIStringBundle** aBundle) {
+ NS_ENSURE_ARG_POINTER(aPropFileName);
+ NS_ENSURE_ARG_POINTER(aBundle);
+
+ // Create a bundle for the localization
+
+ nsCOMPtr<nsIStringBundleService> stringService =
+ mozilla::services::GetStringBundleService();
+ if (!stringService) return NS_ERROR_FAILURE;
+
+ return stringService->CreateBundle(aPropFileName, aBundle);
+}
+
+nsresult nsParserMsgUtils::GetLocalizedStringByName(const char* aPropFileName,
+ const char* aKey,
+ nsString& oVal) {
+ oVal.Truncate();
+
+ NS_ENSURE_ARG_POINTER(aKey);
+
+ nsCOMPtr<nsIStringBundle> bundle;
+ nsresult rv = GetBundle(aPropFileName, getter_AddRefs(bundle));
+ if (NS_SUCCEEDED(rv) && bundle) {
+ nsAutoString valUni;
+ rv = bundle->GetStringFromName(aKey, valUni);
+ if (NS_SUCCEEDED(rv)) {
+ oVal.Assign(valUni);
+ }
+ }
+
+ return rv;
+}
+
+nsresult nsParserMsgUtils::GetLocalizedStringByID(const char* aPropFileName,
+ uint32_t aID,
+ nsString& oVal) {
+ oVal.Truncate();
+
+ nsCOMPtr<nsIStringBundle> bundle;
+ nsresult rv = GetBundle(aPropFileName, getter_AddRefs(bundle));
+ if (NS_SUCCEEDED(rv) && bundle) {
+ nsAutoString valUni;
+ rv = bundle->GetStringFromID(aID, valUni);
+ if (NS_SUCCEEDED(rv)) {
+ oVal.Assign(valUni);
+ }
+ }
+
+ return rv;
+}
diff --git a/parser/htmlparser/nsParserMsgUtils.h b/parser/htmlparser/nsParserMsgUtils.h
new file mode 100644
index 0000000000..3645610385
--- /dev/null
+++ b/parser/htmlparser/nsParserMsgUtils.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsParserMsgUtils_h
+#define nsParserMsgUtils_h
+
+#include "nsString.h"
+
+#define XMLPARSER_PROPERTIES \
+ "chrome://global/locale/layout/xmlparser.properties"
+
+#define XMLPARSER_PROPERTIES_en_US \
+ "resource://gre/res/locale/layout/xmlparser.properties"
+
+class nsParserMsgUtils {
+ nsParserMsgUtils(); // Currently this is not meant to be created, use the
+ // static methods
+ ~nsParserMsgUtils(); // If perf required, change this to cache values etc.
+ public:
+ static nsresult GetLocalizedStringByName(const char* aPropFileName,
+ const char* aKey, nsString& aVal);
+ static nsresult GetLocalizedStringByID(const char* aPropFileName,
+ uint32_t aID, nsString& aVal);
+};
+
+#endif
diff --git a/parser/htmlparser/nsScanner.cpp b/parser/htmlparser/nsScanner.cpp
new file mode 100644
index 0000000000..7095ef9392
--- /dev/null
+++ b/parser/htmlparser/nsScanner.cpp
@@ -0,0 +1,361 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//#define __INCREMENTAL 1
+
+#include "nsScanner.h"
+
+#include "mozilla/Attributes.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/Encoding.h"
+#include "nsDebug.h"
+#include "nsReadableUtils.h"
+#include "nsUTF8Utils.h" // for LossyConvertEncoding
+#include "nsCRT.h"
+#include "nsParser.h"
+#include "nsCharsetSource.h"
+
+nsReadEndCondition::nsReadEndCondition(const char16_t* aTerminateChars)
+ : mChars(aTerminateChars),
+ mFilter(char16_t(~0)) // All bits set
+{
+ // Build filter that will be used to filter out characters with
+ // bits that none of the terminal chars have. This works very well
+ // because terminal chars often have only the last 4-6 bits set and
+ // normal ascii letters have bit 7 set. Other letters have even higher
+ // bits set.
+
+ // Calculate filter
+ const char16_t* current = aTerminateChars;
+ char16_t terminalChar = *current;
+ while (terminalChar) {
+ mFilter &= ~terminalChar;
+ ++current;
+ terminalChar = *current;
+ }
+}
+
+/**
+ * Use this constructor if you want i/o to be based on
+ * a single string you hand in during construction.
+ * This short cut was added for Javascript.
+ *
+ * @update gess 5/12/98
+ * @param aMode represents the parser mode (nav, other)
+ * @return
+ */
+nsScanner::nsScanner(const nsAString& anHTMLString) {
+ MOZ_COUNT_CTOR(nsScanner);
+
+ mSlidingBuffer = nullptr;
+ if (AppendToBuffer(anHTMLString)) {
+ mSlidingBuffer->BeginReading(mCurrentPosition);
+ } else {
+ /* XXX see hack below, re: bug 182067 */
+ memset(&mCurrentPosition, 0, sizeof(mCurrentPosition));
+ mEndPosition = mCurrentPosition;
+ }
+ mMarkPosition = mCurrentPosition;
+ mIncremental = false;
+ mUnicodeDecoder = nullptr;
+ mCharsetSource = kCharsetUninitialized;
+}
+
+/**
+ * Use this constructor if you want i/o to be based on strings
+ * the scanner receives. If you pass a null filename, you
+ * can still provide data to the scanner via append.
+ */
+nsScanner::nsScanner(nsString& aFilename, bool aCreateStream)
+ : mFilename(aFilename) {
+ MOZ_COUNT_CTOR(nsScanner);
+ NS_ASSERTION(!aCreateStream, "This is always true.");
+
+ mSlidingBuffer = nullptr;
+
+ // XXX This is a big hack. We need to initialize the iterators to something.
+ // What matters is that mCurrentPosition == mEndPosition, so that our methods
+ // believe that we are at EOF (see bug 182067). We null out mCurrentPosition
+ // so that we have some hope of catching null pointer dereferences associated
+ // with this hack. --darin
+ memset(&mCurrentPosition, 0, sizeof(mCurrentPosition));
+ mMarkPosition = mCurrentPosition;
+ mEndPosition = mCurrentPosition;
+
+ mIncremental = true;
+
+ mUnicodeDecoder = nullptr;
+ mCharsetSource = kCharsetUninitialized;
+ // XML defaults to UTF-8 and about:blank is UTF-8, too.
+ SetDocumentCharset(UTF_8_ENCODING, kCharsetFromDocTypeDefault);
+}
+
+nsresult nsScanner::SetDocumentCharset(NotNull<const Encoding*> aEncoding,
+ int32_t aSource) {
+ if (aSource < mCharsetSource) // priority is lower than the current one
+ return NS_OK;
+
+ mCharsetSource = aSource;
+ nsCString charsetName;
+ aEncoding->Name(charsetName);
+ if (!mCharset.IsEmpty() && charsetName.Equals(mCharset)) {
+ return NS_OK; // no difference, don't change it
+ }
+
+ // different, need to change it
+
+ mCharset.Assign(charsetName);
+
+ mUnicodeDecoder = aEncoding->NewDecoderWithBOMRemoval();
+
+ return NS_OK;
+}
+
+/**
+ * default destructor
+ *
+ * @update gess 3/25/98
+ * @param
+ * @return
+ */
+nsScanner::~nsScanner() {
+ delete mSlidingBuffer;
+
+ MOZ_COUNT_DTOR(nsScanner);
+}
+
+/**
+ * Resets current offset position of input stream to marked position.
+ * This allows us to back up to this point if the need should arise,
+ * such as when tokenization gets interrupted.
+ * NOTE: IT IS REALLY BAD FORM TO CALL RELEASE WITHOUT CALLING MARK FIRST!
+ *
+ * @update gess 5/12/98
+ * @param
+ * @return
+ */
+void nsScanner::RewindToMark(void) {
+ if (mSlidingBuffer) {
+ mCurrentPosition = mMarkPosition;
+ }
+}
+
+/**
+ * Records current offset position in input stream. This allows us
+ * to back up to this point if the need should arise, such as when
+ * tokenization gets interrupted.
+ *
+ * @update gess 7/29/98
+ * @param
+ * @return
+ */
+int32_t nsScanner::Mark() {
+ int32_t distance = 0;
+ if (mSlidingBuffer) {
+ nsScannerIterator oldStart;
+ mSlidingBuffer->BeginReading(oldStart);
+
+ distance = Distance(oldStart, mCurrentPosition);
+
+ mSlidingBuffer->DiscardPrefix(mCurrentPosition);
+ mSlidingBuffer->BeginReading(mCurrentPosition);
+ mMarkPosition = mCurrentPosition;
+ }
+
+ return distance;
+}
+
+/**
+ * Insert data to our underlying input buffer as
+ * if it were read from an input stream.
+ *
+ * @update harishd 01/12/99
+ * @return error code
+ */
+bool nsScanner::UngetReadable(const nsAString& aBuffer) {
+ if (!mSlidingBuffer) {
+ return false;
+ }
+
+ mSlidingBuffer->UngetReadable(aBuffer, mCurrentPosition);
+ mSlidingBuffer->BeginReading(
+ mCurrentPosition); // Insertion invalidated our iterators
+ mSlidingBuffer->EndReading(mEndPosition);
+
+ return true;
+}
+
+/**
+ * Append data to our underlying input buffer as
+ * if it were read from an input stream.
+ *
+ * @update gess4/3/98
+ * @return error code
+ */
+nsresult nsScanner::Append(const nsAString& aBuffer) {
+ if (!AppendToBuffer(aBuffer)) return NS_ERROR_OUT_OF_MEMORY;
+ return NS_OK;
+}
+
+/**
+ *
+ *
+ * @update gess 5/21/98
+ * @param
+ * @return
+ */
+nsresult nsScanner::Append(const char* aBuffer, uint32_t aLen) {
+ nsresult res = NS_OK;
+ if (mUnicodeDecoder) {
+ CheckedInt<size_t> needed = mUnicodeDecoder->MaxUTF16BufferLength(aLen);
+ if (!needed.isValid()) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ CheckedInt<uint32_t> allocLen(1); // null terminator due to legacy sadness
+ allocLen += needed.value();
+ if (!allocLen.isValid()) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ nsScannerString::Buffer* buffer =
+ nsScannerString::AllocBuffer(allocLen.value());
+ NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
+ char16_t* unichars = buffer->DataStart();
+
+ uint32_t result;
+ size_t read;
+ size_t written;
+ Tie(result, read, written) =
+ mUnicodeDecoder->DecodeToUTF16WithoutReplacement(
+ AsBytes(Span(aBuffer, aLen)), Span(unichars, needed.value()),
+ false); // Retain bug about failure to handle EOF
+ MOZ_ASSERT(result != kOutputFull);
+ MOZ_ASSERT(read <= aLen);
+ MOZ_ASSERT(written <= needed.value());
+ if (result != kInputEmpty) {
+ // Since about:blank is empty, this line runs only for XML. Use a
+ // character that's illegal in XML instead of U+FFFD in order to make
+ // expat flag the error. There is no need to loop and convert more, since
+ // expat will stop here anyway.
+ unichars[written++] = 0xFFFF;
+ }
+ buffer->SetDataLength(written);
+ // Don't propagate return code of unicode decoder
+ // since it doesn't reflect on our success or failure
+ // - Ref. bug 87110
+ res = NS_OK;
+ if (!AppendToBuffer(buffer)) res = NS_ERROR_OUT_OF_MEMORY;
+ } else {
+ NS_WARNING("No decoder found.");
+ res = NS_ERROR_FAILURE;
+ }
+
+ return res;
+}
+
+/**
+ * retrieve next char from scanners internal input stream
+ *
+ * @update gess 3/25/98
+ * @param
+ * @return error code reflecting read status
+ */
+nsresult nsScanner::GetChar(char16_t& aChar) {
+ if (!mSlidingBuffer || mCurrentPosition == mEndPosition) {
+ aChar = 0;
+ return NS_ERROR_HTMLPARSER_EOF;
+ }
+
+ aChar = *mCurrentPosition++;
+
+ return NS_OK;
+}
+
+void nsScanner::BindSubstring(nsScannerSubstring& aSubstring,
+ const nsScannerIterator& aStart,
+ const nsScannerIterator& aEnd) {
+ aSubstring.Rebind(*mSlidingBuffer, aStart, aEnd);
+}
+
+void nsScanner::CurrentPosition(nsScannerIterator& aPosition) {
+ aPosition = mCurrentPosition;
+}
+
+void nsScanner::EndReading(nsScannerIterator& aPosition) {
+ aPosition = mEndPosition;
+}
+
+void nsScanner::SetPosition(nsScannerIterator& aPosition, bool aTerminate) {
+ if (mSlidingBuffer) {
+ mCurrentPosition = aPosition;
+ if (aTerminate && (mCurrentPosition == mEndPosition)) {
+ mMarkPosition = mCurrentPosition;
+ mSlidingBuffer->DiscardPrefix(mCurrentPosition);
+ }
+ }
+}
+
+bool nsScanner::AppendToBuffer(nsScannerString::Buffer* aBuf) {
+ if (!mSlidingBuffer) {
+ mSlidingBuffer = new nsScannerString(aBuf);
+ if (!mSlidingBuffer) return false;
+ mSlidingBuffer->BeginReading(mCurrentPosition);
+ mMarkPosition = mCurrentPosition;
+ mSlidingBuffer->EndReading(mEndPosition);
+ } else {
+ mSlidingBuffer->AppendBuffer(aBuf);
+ if (mCurrentPosition == mEndPosition) {
+ mSlidingBuffer->BeginReading(mCurrentPosition);
+ }
+ mSlidingBuffer->EndReading(mEndPosition);
+ }
+
+ return true;
+}
+
+/**
+ * call this to copy bytes out of the scanner that have not yet been consumed
+ * by the tokenization process.
+ *
+ * @update gess 5/12/98
+ * @param aCopyBuffer is where the scanner buffer will be copied to
+ * @return true if OK or false on OOM
+ */
+bool nsScanner::CopyUnusedData(nsString& aCopyBuffer) {
+ if (!mSlidingBuffer) {
+ aCopyBuffer.Truncate();
+ return true;
+ }
+
+ nsScannerIterator start, end;
+ start = mCurrentPosition;
+ end = mEndPosition;
+
+ return CopyUnicodeTo(start, end, aCopyBuffer);
+}
+
+/**
+ * Retrieve the name of the file that the scanner is reading from.
+ * In some cases, it's just a given name, because the scanner isn't
+ * really reading from a file.
+ *
+ * @update gess 5/12/98
+ * @return
+ */
+nsString& nsScanner::GetFilename(void) { return mFilename; }
+
+/**
+ * Conduct self test. Actually, selftesting for this class
+ * occurs in the parser selftest.
+ *
+ * @update gess 3/25/98
+ * @param
+ * @return
+ */
+
+void nsScanner::SelfTest(void) {
+#ifdef _DEBUG
+#endif
+}
diff --git a/parser/htmlparser/nsScanner.h b/parser/htmlparser/nsScanner.h
new file mode 100644
index 0000000000..ff849c507c
--- /dev/null
+++ b/parser/htmlparser/nsScanner.h
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * MODULE NOTES:
+ * @update gess 4/1/98
+ *
+ * The scanner is a low-level service class that knows
+ * how to consume characters out of an (internal) stream.
+ * This class also offers a series of utility methods
+ * that most tokenizers want, such as readUntil()
+ * and SkipWhitespace().
+ */
+
+#ifndef SCANNER
+#define SCANNER
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "nsIParser.h"
+#include "mozilla/Encoding.h"
+#include "nsScannerString.h"
+#include "mozilla/CheckedInt.h"
+
+class nsReadEndCondition {
+ public:
+ const char16_t* mChars;
+ char16_t mFilter;
+ explicit nsReadEndCondition(const char16_t* aTerminateChars);
+
+ private:
+ nsReadEndCondition(const nsReadEndCondition& aOther); // No copying
+ void operator=(const nsReadEndCondition& aOther); // No assigning
+};
+
+class nsScanner final {
+ using Encoding = mozilla::Encoding;
+ template <typename T>
+ using NotNull = mozilla::NotNull<T>;
+
+ public:
+ /**
+ * Use this constructor for the XML fragment parsing case
+ */
+ explicit nsScanner(const nsAString& anHTMLString);
+
+ /**
+ * Use this constructor if you want i/o to be based on
+ * a file (therefore a stream) or just data you provide via Append().
+ */
+ nsScanner(nsString& aFilename, bool aCreateStream);
+
+ ~nsScanner();
+
+ /**
+ * retrieve next char from internal input stream
+ *
+ * @update gess 3/25/98
+ * @param ch is the char to accept new value
+ * @return error code reflecting read status
+ */
+ nsresult GetChar(char16_t& ch);
+
+ /**
+ * Records current offset position in input stream. This allows us
+ * to back up to this point if the need should arise, such as when
+ * tokenization gets interrupted.
+ *
+ * @update gess 5/12/98
+ * @param
+ * @return
+ */
+ int32_t Mark(void);
+
+ /**
+ * Resets current offset position of input stream to marked position.
+ * This allows us to back up to this point if the need should arise,
+ * such as when tokenization gets interrupted.
+ * NOTE: IT IS REALLY BAD FORM TO CALL RELEASE WITHOUT CALLING MARK FIRST!
+ *
+ * @update gess 5/12/98
+ * @param
+ * @return
+ */
+ void RewindToMark(void);
+
+ /**
+ *
+ *
+ * @update harishd 01/12/99
+ * @param
+ * @return
+ */
+ bool UngetReadable(const nsAString& aBuffer);
+
+ /**
+ *
+ *
+ * @update gess 5/13/98
+ * @param
+ * @return
+ */
+ nsresult Append(const nsAString& aBuffer);
+
+ /**
+ *
+ *
+ * @update gess 5/21/98
+ * @param
+ * @return
+ */
+ nsresult Append(const char* aBuffer, uint32_t aLen);
+
+ /**
+ * Call this to copy bytes out of the scanner that have not yet been consumed
+ * by the tokenization process.
+ *
+ * @update gess 5/12/98
+ * @param aCopyBuffer is where the scanner buffer will be copied to
+ * @return true if OK or false on OOM
+ */
+ bool CopyUnusedData(nsString& aCopyBuffer);
+
+ /**
+ * Retrieve the name of the file that the scanner is reading from.
+ * In some cases, it's just a given name, because the scanner isn't
+ * really reading from a file.
+ *
+ * @update gess 5/12/98
+ * @return
+ */
+ nsString& GetFilename(void);
+
+ static void SelfTest();
+
+ /**
+ * Use this setter to change the scanner's unicode decoder
+ *
+ * @update ftang 3/02/99
+ * @param aCharset a normalized (alias resolved) charset name
+ * @param aCharsetSource- where the charset info came from
+ * @return
+ */
+ nsresult SetDocumentCharset(NotNull<const Encoding*> aEncoding,
+ int32_t aSource);
+
+ void BindSubstring(nsScannerSubstring& aSubstring,
+ const nsScannerIterator& aStart,
+ const nsScannerIterator& aEnd);
+ void CurrentPosition(nsScannerIterator& aPosition);
+ void EndReading(nsScannerIterator& aPosition);
+ void SetPosition(nsScannerIterator& aPosition, bool aTruncate = false);
+
+ /**
+ * Internal method used to cause the internal buffer to
+ * be filled with data.
+ *
+ * @update gess4/3/98
+ */
+ bool IsIncremental(void) { return mIncremental; }
+ void SetIncremental(bool anIncrValue) { mIncremental = anIncrValue; }
+
+ protected:
+ bool AppendToBuffer(nsScannerString::Buffer* aBuffer);
+ bool AppendToBuffer(const nsAString& aStr) {
+ nsScannerString::Buffer* buf = nsScannerString::AllocBufferFromString(aStr);
+ if (!buf) return false;
+ AppendToBuffer(buf);
+ return true;
+ }
+
+ nsScannerString* mSlidingBuffer;
+ nsScannerIterator mCurrentPosition; // The position we will next read from in
+ // the scanner buffer
+ nsScannerIterator
+ mMarkPosition; // The position last marked (we may rewind to here)
+ nsScannerIterator mEndPosition; // The current end of the scanner buffer
+ nsString mFilename;
+ bool mIncremental;
+ int32_t mCharsetSource;
+ nsCString mCharset;
+ mozilla::UniquePtr<mozilla::Decoder> mUnicodeDecoder;
+
+ private:
+ nsScanner& operator=(const nsScanner&); // Not implemented.
+};
+
+#endif
diff --git a/parser/htmlparser/nsScannerString.cpp b/parser/htmlparser/nsScannerString.cpp
new file mode 100644
index 0000000000..7a00276ca3
--- /dev/null
+++ b/parser/htmlparser/nsScannerString.cpp
@@ -0,0 +1,578 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdlib.h>
+#include "nsScannerString.h"
+#include "mozilla/CheckedInt.h"
+
+/**
+ * nsScannerBufferList
+ */
+
+#define MAX_CAPACITY \
+ ((UINT32_MAX / sizeof(char16_t)) - (sizeof(Buffer) + sizeof(char16_t)))
+
+nsScannerBufferList::Buffer* nsScannerBufferList::AllocBufferFromString(
+ const nsAString& aString) {
+ uint32_t len = aString.Length();
+ Buffer* buf = AllocBuffer(len);
+
+ if (buf) {
+ nsAString::const_iterator source;
+ aString.BeginReading(source);
+ nsCharTraits<char16_t>::copy(buf->DataStart(), source.get(), len);
+ }
+ return buf;
+}
+
+nsScannerBufferList::Buffer* nsScannerBufferList::AllocBuffer(
+ uint32_t capacity) {
+ if (capacity > MAX_CAPACITY) return nullptr;
+
+ void* ptr = malloc(sizeof(Buffer) + (capacity + 1) * sizeof(char16_t));
+ if (!ptr) return nullptr;
+
+ Buffer* buf = new (ptr) Buffer();
+
+ buf->mUsageCount = 0;
+ buf->mDataEnd = buf->DataStart() + capacity;
+
+ // XXX null terminate. this shouldn't be required, but we do it because
+ // nsScanner erroneously thinks it can dereference DataEnd :-(
+ *buf->mDataEnd = char16_t(0);
+ return buf;
+}
+
+void nsScannerBufferList::ReleaseAll() {
+ while (!mBuffers.isEmpty()) {
+ Buffer* node = mBuffers.popFirst();
+ // printf(">>> freeing buffer @%p\n", node);
+ free(node);
+ }
+}
+
+void nsScannerBufferList::SplitBuffer(const Position& pos) {
+ // splitting to the right keeps the work string and any extant token
+ // pointing to and holding a reference count on the same buffer.
+
+ Buffer* bufferToSplit = pos.mBuffer;
+ NS_ASSERTION(bufferToSplit, "null pointer");
+
+ uint32_t splitOffset = pos.mPosition - bufferToSplit->DataStart();
+ NS_ASSERTION(pos.mPosition >= bufferToSplit->DataStart() &&
+ splitOffset <= bufferToSplit->DataLength(),
+ "split offset is outside buffer");
+
+ uint32_t len = bufferToSplit->DataLength() - splitOffset;
+ Buffer* new_buffer = AllocBuffer(len);
+ if (new_buffer) {
+ nsCharTraits<char16_t>::copy(new_buffer->DataStart(),
+ bufferToSplit->DataStart() + splitOffset, len);
+ InsertAfter(new_buffer, bufferToSplit);
+ bufferToSplit->SetDataLength(splitOffset);
+ }
+}
+
+void nsScannerBufferList::DiscardUnreferencedPrefix(Buffer* aBuf) {
+ if (aBuf == Head()) {
+ while (!mBuffers.isEmpty() && !Head()->IsInUse()) {
+ Buffer* buffer = Head();
+ buffer->remove();
+ free(buffer);
+ }
+ }
+}
+
+size_t nsScannerBufferList::Position::Distance(const Position& aStart,
+ const Position& aEnd) {
+ size_t result = 0;
+ if (aStart.mBuffer == aEnd.mBuffer) {
+ result = aEnd.mPosition - aStart.mPosition;
+ } else {
+ result = aStart.mBuffer->DataEnd() - aStart.mPosition;
+ for (Buffer* b = aStart.mBuffer->Next(); b != aEnd.mBuffer; b = b->Next())
+ result += b->DataLength();
+ result += aEnd.mPosition - aEnd.mBuffer->DataStart();
+ }
+ return result;
+}
+
+/**
+ * nsScannerSubstring
+ */
+
+nsScannerSubstring::nsScannerSubstring()
+ : mStart(nullptr, nullptr),
+ mEnd(nullptr, nullptr),
+ mBufferList(nullptr),
+ mLength(0),
+ mIsDirty(true) {}
+
+nsScannerSubstring::nsScannerSubstring(const nsAString& s)
+ : mBufferList(nullptr), mIsDirty(true) {
+ Rebind(s);
+}
+
+nsScannerSubstring::~nsScannerSubstring() {
+ release_ownership_of_buffer_list();
+}
+
+int32_t nsScannerSubstring::CountChar(char16_t c) const {
+ /*
+ re-write this to use a counting sink
+ */
+
+ size_type result = 0;
+ size_type lengthToExamine = Length();
+
+ nsScannerIterator iter;
+ for (BeginReading(iter);;) {
+ int32_t lengthToExamineInThisFragment = iter.size_forward();
+ const char16_t* fromBegin = iter.get();
+ result += size_type(
+ NS_COUNT(fromBegin, fromBegin + lengthToExamineInThisFragment, c));
+ if (!(lengthToExamine -= lengthToExamineInThisFragment)) return result;
+ iter.advance(lengthToExamineInThisFragment);
+ }
+ // never reached; quiets warnings
+ return 0;
+}
+
+void nsScannerSubstring::Rebind(const nsScannerSubstring& aString,
+ const nsScannerIterator& aStart,
+ const nsScannerIterator& aEnd) {
+ // allow for the case where &aString == this
+
+ aString.acquire_ownership_of_buffer_list();
+ release_ownership_of_buffer_list();
+
+ mStart = aStart;
+ mEnd = aEnd;
+ mBufferList = aString.mBufferList;
+ mLength = Distance(aStart, aEnd);
+ mIsDirty = true;
+}
+
+void nsScannerSubstring::Rebind(const nsAString& aString) {
+ release_ownership_of_buffer_list();
+
+ mBufferList = new nsScannerBufferList(AllocBufferFromString(aString));
+ mIsDirty = true;
+
+ init_range_from_buffer_list();
+ acquire_ownership_of_buffer_list();
+}
+
+const nsAString& nsScannerSubstring::AsString() const {
+ if (mIsDirty) {
+ nsScannerSubstring* mutable_this = const_cast<nsScannerSubstring*>(this);
+
+ if (mStart.mBuffer == mEnd.mBuffer) {
+ // We only have a single fragment to deal with, so just return it
+ // as a substring.
+ mutable_this->mFlattenedRep.Rebind(mStart.mPosition, mEnd.mPosition);
+ } else {
+ // Otherwise, we need to copy the data into a flattened buffer.
+ nsScannerIterator start, end;
+ CopyUnicodeTo(BeginReading(start), EndReading(end),
+ mutable_this->mFlattenedRep);
+ }
+
+ mutable_this->mIsDirty = false;
+ }
+
+ return mFlattenedRep;
+}
+
+nsScannerIterator& nsScannerSubstring::BeginReading(
+ nsScannerIterator& iter) const {
+ iter.mOwner = this;
+
+ iter.mFragment.mBuffer = mStart.mBuffer;
+ iter.mFragment.mFragmentStart = mStart.mPosition;
+ if (mStart.mBuffer == mEnd.mBuffer)
+ iter.mFragment.mFragmentEnd = mEnd.mPosition;
+ else
+ iter.mFragment.mFragmentEnd = mStart.mBuffer->DataEnd();
+
+ iter.mPosition = mStart.mPosition;
+ iter.normalize_forward();
+ return iter;
+}
+
+nsScannerIterator& nsScannerSubstring::EndReading(
+ nsScannerIterator& iter) const {
+ iter.mOwner = this;
+
+ iter.mFragment.mBuffer = mEnd.mBuffer;
+ iter.mFragment.mFragmentEnd = mEnd.mPosition;
+ if (mStart.mBuffer == mEnd.mBuffer)
+ iter.mFragment.mFragmentStart = mStart.mPosition;
+ else
+ iter.mFragment.mFragmentStart = mEnd.mBuffer->DataStart();
+
+ iter.mPosition = mEnd.mPosition;
+ // must not |normalize_backward| as that would likely invalidate tests like
+ // |while ( first != last )|
+ return iter;
+}
+
+bool nsScannerSubstring::GetNextFragment(nsScannerFragment& frag) const {
+ // check to see if we are at the end of the buffer list
+ if (frag.mBuffer == mEnd.mBuffer) return false;
+
+ frag.mBuffer = frag.mBuffer->getNext();
+
+ if (frag.mBuffer == mStart.mBuffer)
+ frag.mFragmentStart = mStart.mPosition;
+ else
+ frag.mFragmentStart = frag.mBuffer->DataStart();
+
+ if (frag.mBuffer == mEnd.mBuffer)
+ frag.mFragmentEnd = mEnd.mPosition;
+ else
+ frag.mFragmentEnd = frag.mBuffer->DataEnd();
+
+ return true;
+}
+
+bool nsScannerSubstring::GetPrevFragment(nsScannerFragment& frag) const {
+ // check to see if we are at the beginning of the buffer list
+ if (frag.mBuffer == mStart.mBuffer) return false;
+
+ frag.mBuffer = frag.mBuffer->getPrevious();
+
+ if (frag.mBuffer == mStart.mBuffer)
+ frag.mFragmentStart = mStart.mPosition;
+ else
+ frag.mFragmentStart = frag.mBuffer->DataStart();
+
+ if (frag.mBuffer == mEnd.mBuffer)
+ frag.mFragmentEnd = mEnd.mPosition;
+ else
+ frag.mFragmentEnd = frag.mBuffer->DataEnd();
+
+ return true;
+}
+
+/**
+ * nsScannerString
+ */
+
+nsScannerString::nsScannerString(Buffer* aBuf) {
+ mBufferList = new nsScannerBufferList(aBuf);
+
+ init_range_from_buffer_list();
+ acquire_ownership_of_buffer_list();
+}
+
+void nsScannerString::AppendBuffer(Buffer* aBuf) {
+ mBufferList->Append(aBuf);
+ mLength += aBuf->DataLength();
+
+ mEnd.mBuffer = aBuf;
+ mEnd.mPosition = aBuf->DataEnd();
+
+ mIsDirty = true;
+}
+
+void nsScannerString::DiscardPrefix(const nsScannerIterator& aIter) {
+ Position old_start(mStart);
+ mStart = aIter;
+ mLength -= Position::Distance(old_start, mStart);
+
+ mStart.mBuffer->IncrementUsageCount();
+ old_start.mBuffer->DecrementUsageCount();
+
+ mBufferList->DiscardUnreferencedPrefix(old_start.mBuffer);
+
+ mIsDirty = true;
+}
+
+void nsScannerString::UngetReadable(const nsAString& aReadable,
+ const nsScannerIterator& aInsertPoint)
+/*
+ * Warning: this routine manipulates the shared buffer list in an
+ * unexpected way. The original design did not really allow for
+ * insertions, but this call promises that if called for a point after the
+ * end of all extant token strings, that no token string or the work string
+ * will be invalidated.
+ *
+ * This routine is protected because it is the responsibility of the
+ * derived class to keep those promises.
+ */
+{
+ Position insertPos(aInsertPoint);
+
+ mBufferList->SplitBuffer(insertPos);
+ // splitting to the right keeps the work string and any extant token
+ // pointing to and holding a reference count on the same buffer
+
+ Buffer* new_buffer = AllocBufferFromString(aReadable);
+ // make a new buffer with all the data to insert...
+ // ALERT: we may have empty space to re-use in the split buffer,
+ // measure the cost of this and decide if we should do the work to fill
+ // it
+
+ Buffer* buffer_to_split = insertPos.mBuffer;
+ mBufferList->InsertAfter(new_buffer, buffer_to_split);
+ mLength += aReadable.Length();
+
+ mEnd.mBuffer = mBufferList->Tail();
+ mEnd.mPosition = mEnd.mBuffer->DataEnd();
+
+ mIsDirty = true;
+}
+
+/**
+ * nsScannerSharedSubstring
+ */
+
+void nsScannerSharedSubstring::Rebind(const nsScannerIterator& aStart,
+ const nsScannerIterator& aEnd) {
+ // If the start and end positions are inside the same buffer, we must
+ // acquire ownership of the buffer. If not, we can optimize by not holding
+ // onto it.
+
+ Buffer* buffer = const_cast<Buffer*>(aStart.buffer());
+ bool sameBuffer = buffer == aEnd.buffer();
+
+ nsScannerBufferList* bufferList;
+
+ if (sameBuffer) {
+ bufferList = aStart.mOwner->mBufferList;
+ bufferList->AddRef();
+ buffer->IncrementUsageCount();
+ }
+
+ if (mBufferList) ReleaseBuffer();
+
+ if (sameBuffer) {
+ mBuffer = buffer;
+ mBufferList = bufferList;
+ mString.Rebind(aStart.mPosition, aEnd.mPosition);
+ } else {
+ mBuffer = nullptr;
+ mBufferList = nullptr;
+ CopyUnicodeTo(aStart, aEnd, mString);
+ }
+}
+
+void nsScannerSharedSubstring::ReleaseBuffer() {
+ NS_ASSERTION(mBufferList, "Should only be called with non-null mBufferList");
+ mBuffer->DecrementUsageCount();
+ mBufferList->DiscardUnreferencedPrefix(mBuffer);
+ mBufferList->Release();
+}
+
+void nsScannerSharedSubstring::MakeMutable() {
+ nsString temp(mString); // this will force a copy of the data
+ mString.Assign(temp); // mString will now share the just-allocated buffer
+
+ ReleaseBuffer();
+
+ mBuffer = nullptr;
+ mBufferList = nullptr;
+}
+
+/**
+ * utils -- based on code from nsReadableUtils.cpp
+ */
+
+// private helper function
+static inline nsAString::iterator& copy_multifragment_string(
+ nsScannerIterator& first, const nsScannerIterator& last,
+ nsAString::iterator& result) {
+ typedef nsCharSourceTraits<nsScannerIterator> source_traits;
+ typedef nsCharSinkTraits<nsAString::iterator> sink_traits;
+
+ while (first != last) {
+ uint32_t distance = source_traits::readable_distance(first, last);
+ sink_traits::write(result, source_traits::read(first), distance);
+ NS_ASSERTION(distance > 0,
+ "|copy_multifragment_string| will never terminate");
+ source_traits::advance(first, distance);
+ }
+
+ return result;
+}
+
+bool CopyUnicodeTo(const nsScannerIterator& aSrcStart,
+ const nsScannerIterator& aSrcEnd, nsAString& aDest) {
+ mozilla::CheckedInt<nsAString::size_type> distance(
+ Distance(aSrcStart, aSrcEnd));
+ if (!distance.isValid()) {
+ return false; // overflow detected
+ }
+
+ if (!aDest.SetLength(distance.value(), mozilla::fallible)) {
+ aDest.Truncate();
+ return false; // out of memory
+ }
+ auto writer = aDest.BeginWriting();
+ nsScannerIterator fromBegin(aSrcStart);
+
+ copy_multifragment_string(fromBegin, aSrcEnd, writer);
+ return true;
+}
+
+bool AppendUnicodeTo(const nsScannerIterator& aSrcStart,
+ const nsScannerIterator& aSrcEnd,
+ nsScannerSharedSubstring& aDest) {
+ // Check whether we can just create a dependent string.
+ if (aDest.str().IsEmpty()) {
+ // We can just make |aDest| point to the buffer.
+ // This will take care of copying if the buffer spans fragments.
+ aDest.Rebind(aSrcStart, aSrcEnd);
+ return true;
+ }
+ // The dest string is not empty, so it can't be a dependent substring.
+ return AppendUnicodeTo(aSrcStart, aSrcEnd, aDest.writable());
+}
+
+bool AppendUnicodeTo(const nsScannerIterator& aSrcStart,
+ const nsScannerIterator& aSrcEnd, nsAString& aDest) {
+ const nsAString::size_type oldLength = aDest.Length();
+ mozilla::CheckedInt<nsAString::size_type> newLen(
+ Distance(aSrcStart, aSrcEnd));
+ newLen += oldLength;
+ if (!newLen.isValid()) {
+ return false; // overflow detected
+ }
+
+ if (!aDest.SetLength(newLen.value(), mozilla::fallible))
+ return false; // out of memory
+ auto writer = aDest.BeginWriting();
+ std::advance(writer, oldLength);
+ nsScannerIterator fromBegin(aSrcStart);
+
+ copy_multifragment_string(fromBegin, aSrcEnd, writer);
+ return true;
+}
+
+bool FindCharInReadable(char16_t aChar, nsScannerIterator& aSearchStart,
+ const nsScannerIterator& aSearchEnd) {
+ while (aSearchStart != aSearchEnd) {
+ int32_t fragmentLength;
+ if (SameFragment(aSearchStart, aSearchEnd))
+ fragmentLength = aSearchEnd.get() - aSearchStart.get();
+ else
+ fragmentLength = aSearchStart.size_forward();
+
+ const char16_t* charFoundAt =
+ nsCharTraits<char16_t>::find(aSearchStart.get(), fragmentLength, aChar);
+ if (charFoundAt) {
+ aSearchStart.advance(charFoundAt - aSearchStart.get());
+ return true;
+ }
+
+ aSearchStart.advance(fragmentLength);
+ }
+
+ return false;
+}
+
+bool FindInReadable(const nsAString& aPattern, nsScannerIterator& aSearchStart,
+ nsScannerIterator& aSearchEnd,
+ const nsStringComparator compare) {
+ bool found_it = false;
+
+ // only bother searching at all if we're given a non-empty range to search
+ if (aSearchStart != aSearchEnd) {
+ nsAString::const_iterator aPatternStart, aPatternEnd;
+ aPattern.BeginReading(aPatternStart);
+ aPattern.EndReading(aPatternEnd);
+
+ // outer loop keeps searching till we find it or run out of string to search
+ while (!found_it) {
+ // fast inner loop (that's what it's called, not what it is) looks for a
+ // potential match
+ while (aSearchStart != aSearchEnd &&
+ compare(aPatternStart.get(), aSearchStart.get(), 1, 1))
+ ++aSearchStart;
+
+ // if we broke out of the `fast' loop because we're out of string ...
+ // we're done: no match
+ if (aSearchStart == aSearchEnd) break;
+
+ // otherwise, we're at a potential match, let's see if we really hit one
+ nsAString::const_iterator testPattern(aPatternStart);
+ nsScannerIterator testSearch(aSearchStart);
+
+ // slow inner loop verifies the potential match (found by the `fast' loop)
+ // at the current position
+ for (;;) {
+ // we already compared the first character in the outer loop,
+ // so we'll advance before the next comparison
+ ++testPattern;
+ ++testSearch;
+
+ // if we verified all the way to the end of the pattern, then we found
+ // it!
+ if (testPattern == aPatternEnd) {
+ found_it = true;
+ aSearchEnd = testSearch; // return the exact found range through the
+ // parameters
+ break;
+ }
+
+ // if we got to end of the string we're searching before we hit the end
+ // of the
+ // pattern, we'll never find what we're looking for
+ if (testSearch == aSearchEnd) {
+ aSearchStart = aSearchEnd;
+ break;
+ }
+
+ // else if we mismatched ... it's time to advance to the next search
+ // position
+ // and get back into the `fast' loop
+ if (compare(testPattern.get(), testSearch.get(), 1, 1)) {
+ ++aSearchStart;
+ break;
+ }
+ }
+ }
+ }
+
+ return found_it;
+}
+
+/**
+ * This implementation is simple, but does too much work.
+ * It searches the entire string from left to right, and returns the last match
+ * found, if any. This implementation will be replaced when I get
+ * |reverse_iterator|s working.
+ */
+bool RFindInReadable(const nsAString& aPattern, nsScannerIterator& aSearchStart,
+ nsScannerIterator& aSearchEnd,
+ const nsStringComparator aComparator) {
+ bool found_it = false;
+
+ nsScannerIterator savedSearchEnd(aSearchEnd);
+ nsScannerIterator searchStart(aSearchStart), searchEnd(aSearchEnd);
+
+ while (searchStart != searchEnd) {
+ if (FindInReadable(aPattern, searchStart, searchEnd, aComparator)) {
+ found_it = true;
+
+ // this is the best match so far, so remember it
+ aSearchStart = searchStart;
+ aSearchEnd = searchEnd;
+
+ // ...and get ready to search some more
+ // (it's tempting to set |searchStart=searchEnd| ... but that misses
+ // overlapping patterns)
+ ++searchStart;
+ searchEnd = savedSearchEnd;
+ }
+ }
+
+ // if we never found it, return an empty range
+ if (!found_it) aSearchStart = aSearchEnd;
+
+ return found_it;
+}
diff --git a/parser/htmlparser/nsScannerString.h b/parser/htmlparser/nsScannerString.h
new file mode 100644
index 0000000000..071e4b4761
--- /dev/null
+++ b/parser/htmlparser/nsScannerString.h
@@ -0,0 +1,508 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsScannerString_h___
+#define nsScannerString_h___
+
+#include "nsString.h"
+#include "nsUnicharUtils.h" // for nsCaseInsensitiveStringComparator
+#include "mozilla/LinkedList.h"
+#include <algorithm>
+
+/**
+ * NOTE: nsScannerString (and the other classes defined in this file) are
+ * not related to nsAString or any of the other xpcom/string classes.
+ *
+ * nsScannerString is based on the nsSlidingString implementation that used
+ * to live in xpcom/string. Now that nsAString is limited to representing
+ * only single fragment strings, nsSlidingString can no longer be used.
+ *
+ * An advantage to this design is that it does not employ any virtual
+ * functions.
+ *
+ * This file uses SCC-style indenting in deference to the nsSlidingString
+ * code from which this code is derived ;-)
+ */
+
+class nsScannerIterator;
+class nsScannerSubstring;
+class nsScannerString;
+
+/**
+ * nsScannerBufferList
+ *
+ * This class maintains a list of heap-allocated Buffer objects. The buffers
+ * are maintained in a circular linked list. Each buffer has a usage count
+ * that is decremented by the owning nsScannerSubstring.
+ *
+ * The buffer list itself is reference counted. This allows the buffer list
+ * to be shared by multiple nsScannerSubstring objects. The reference
+ * counting is not threadsafe, which is not at all a requirement.
+ *
+ * When a nsScannerSubstring releases its reference to a buffer list, it
+ * decrements the usage count of the first buffer in the buffer list that it
+ * was referencing. It informs the buffer list that it can discard buffers
+ * starting at that prefix. The buffer list will do so if the usage count of
+ * that buffer is 0 and if it is the first buffer in the list. It will
+ * continue to prune buffers starting from the front of the buffer list until
+ * it finds a buffer that has a usage count that is non-zero.
+ */
+class nsScannerBufferList {
+ public:
+ /**
+ * Buffer objects are directly followed by a data segment. The start
+ * of the data segment is determined by increment the |this| pointer
+ * by 1 unit.
+ */
+ class Buffer : public mozilla::LinkedListElement<Buffer> {
+ public:
+ void IncrementUsageCount() { ++mUsageCount; }
+ void DecrementUsageCount() { --mUsageCount; }
+
+ bool IsInUse() const { return mUsageCount != 0; }
+
+ const char16_t* DataStart() const { return (const char16_t*)(this + 1); }
+ char16_t* DataStart() { return (char16_t*)(this + 1); }
+
+ const char16_t* DataEnd() const { return mDataEnd; }
+ char16_t* DataEnd() { return mDataEnd; }
+
+ const Buffer* Next() const { return getNext(); }
+ Buffer* Next() { return getNext(); }
+
+ const Buffer* Prev() const { return getPrevious(); }
+ Buffer* Prev() { return getPrevious(); }
+
+ uint32_t DataLength() const { return mDataEnd - DataStart(); }
+ void SetDataLength(uint32_t len) { mDataEnd = DataStart() + len; }
+
+ private:
+ friend class nsScannerBufferList;
+
+ int32_t mUsageCount;
+ char16_t* mDataEnd;
+ };
+
+ /**
+ * Position objects serve as lightweight pointers into a buffer list.
+ * The mPosition member must be contained with mBuffer->DataStart()
+ * and mBuffer->DataEnd().
+ */
+ class Position {
+ public:
+ Position() : mBuffer(nullptr), mPosition(nullptr) {}
+
+ Position(Buffer* buffer, char16_t* position)
+ : mBuffer(buffer), mPosition(position) {}
+
+ inline explicit Position(const nsScannerIterator& aIter);
+
+ inline Position& operator=(const nsScannerIterator& aIter);
+
+ static size_t Distance(const Position& p1, const Position& p2);
+
+ Buffer* mBuffer;
+ char16_t* mPosition;
+ };
+
+ static Buffer* AllocBufferFromString(const nsAString&);
+ static Buffer* AllocBuffer(uint32_t capacity); // capacity = number of chars
+
+ explicit nsScannerBufferList(Buffer* buf) : mRefCnt(0) {
+ mBuffers.insertBack(buf);
+ }
+
+ void AddRef() { ++mRefCnt; }
+ void Release() {
+ if (--mRefCnt == 0) delete this;
+ }
+
+ void Append(Buffer* buf) { mBuffers.insertBack(buf); }
+ void InsertAfter(Buffer* buf, Buffer* prev) { prev->setNext(buf); }
+ void SplitBuffer(const Position&);
+ void DiscardUnreferencedPrefix(Buffer*);
+
+ Buffer* Head() { return mBuffers.getFirst(); }
+ const Buffer* Head() const { return mBuffers.getFirst(); }
+
+ Buffer* Tail() { return mBuffers.getLast(); }
+ const Buffer* Tail() const { return mBuffers.getLast(); }
+
+ private:
+ friend class nsScannerSubstring;
+
+ ~nsScannerBufferList() { ReleaseAll(); }
+ void ReleaseAll();
+
+ int32_t mRefCnt;
+ mozilla::LinkedList<Buffer> mBuffers;
+};
+
+/**
+ * nsScannerFragment represents a "slice" of a Buffer object.
+ */
+struct nsScannerFragment {
+ typedef nsScannerBufferList::Buffer Buffer;
+
+ const Buffer* mBuffer;
+ const char16_t* mFragmentStart;
+ const char16_t* mFragmentEnd;
+};
+
+/**
+ * nsScannerSubstring is the base class for nsScannerString. It provides
+ * access to iterators and methods to bind the substring to another
+ * substring or nsAString instance.
+ *
+ * This class owns the buffer list.
+ */
+class nsScannerSubstring {
+ public:
+ typedef nsScannerBufferList::Buffer Buffer;
+ typedef nsScannerBufferList::Position Position;
+ typedef uint32_t size_type;
+
+ nsScannerSubstring();
+ explicit nsScannerSubstring(const nsAString& s);
+
+ ~nsScannerSubstring();
+
+ nsScannerIterator& BeginReading(nsScannerIterator& iter) const;
+ nsScannerIterator& EndReading(nsScannerIterator& iter) const;
+
+ size_type Length() const { return mLength; }
+
+ int32_t CountChar(char16_t) const;
+
+ void Rebind(const nsScannerSubstring&, const nsScannerIterator&,
+ const nsScannerIterator&);
+ void Rebind(const nsAString&);
+
+ const nsAString& AsString() const;
+
+ bool GetNextFragment(nsScannerFragment&) const;
+ bool GetPrevFragment(nsScannerFragment&) const;
+
+ static inline Buffer* AllocBufferFromString(const nsAString& aStr) {
+ return nsScannerBufferList::AllocBufferFromString(aStr);
+ }
+ static inline Buffer* AllocBuffer(size_type aCapacity) {
+ return nsScannerBufferList::AllocBuffer(aCapacity);
+ }
+
+ protected:
+ void acquire_ownership_of_buffer_list() const {
+ mBufferList->AddRef();
+ mStart.mBuffer->IncrementUsageCount();
+ }
+
+ void release_ownership_of_buffer_list() {
+ if (mBufferList) {
+ mStart.mBuffer->DecrementUsageCount();
+ mBufferList->DiscardUnreferencedPrefix(mStart.mBuffer);
+ mBufferList->Release();
+ }
+ }
+
+ void init_range_from_buffer_list() {
+ mStart.mBuffer = mBufferList->Head();
+ mStart.mPosition = mStart.mBuffer->DataStart();
+
+ mEnd.mBuffer = mBufferList->Tail();
+ mEnd.mPosition = mEnd.mBuffer->DataEnd();
+
+ mLength = Position::Distance(mStart, mEnd);
+ }
+
+ Position mStart;
+ Position mEnd;
+ nsScannerBufferList* mBufferList;
+ size_type mLength;
+
+ // these fields are used to implement AsString
+ nsDependentSubstring mFlattenedRep;
+ bool mIsDirty;
+
+ friend class nsScannerSharedSubstring;
+};
+
+/**
+ * nsScannerString provides methods to grow and modify a buffer list.
+ */
+class nsScannerString : public nsScannerSubstring {
+ public:
+ explicit nsScannerString(Buffer*);
+
+ // you are giving ownership to the string, it takes and keeps your
+ // buffer, deleting it when done.
+ // Use AllocBuffer or AllocBufferFromString to create a Buffer object
+ // for use with this function.
+ void AppendBuffer(Buffer*);
+
+ void DiscardPrefix(const nsScannerIterator&);
+ // any other way you want to do this?
+
+ void UngetReadable(const nsAString& aReadable,
+ const nsScannerIterator& aCurrentPosition);
+};
+
+/**
+ * nsScannerSharedSubstring implements copy-on-write semantics for
+ * nsScannerSubstring. When you call .writable(), it will copy the data
+ * and return a mutable string object. This class also manages releasing
+ * the reference to the scanner buffer when it is no longer needed.
+ */
+
+class nsScannerSharedSubstring {
+ public:
+ nsScannerSharedSubstring() : mBuffer(nullptr), mBufferList(nullptr) {}
+
+ ~nsScannerSharedSubstring() {
+ if (mBufferList) ReleaseBuffer();
+ }
+
+ // Acquire a copy-on-write reference to the given substring.
+ void Rebind(const nsScannerIterator& aStart, const nsScannerIterator& aEnd);
+
+ // Get a mutable reference to this string
+ nsAString& writable() {
+ if (mBufferList) MakeMutable();
+
+ return mString;
+ }
+
+ // Get a const reference to this string
+ const nsAString& str() const { return mString; }
+
+ private:
+ typedef nsScannerBufferList::Buffer Buffer;
+
+ void ReleaseBuffer();
+ void MakeMutable();
+
+ nsDependentSubstring mString;
+ Buffer* mBuffer;
+ nsScannerBufferList* mBufferList;
+};
+
+/**
+ * nsScannerIterator works just like nsReadingIterator<CharT> except that
+ * it knows how to iterate over a list of scanner buffers.
+ */
+class nsScannerIterator {
+ public:
+ typedef nsScannerIterator self_type;
+ typedef ptrdiff_t difference_type;
+ typedef char16_t value_type;
+ typedef const char16_t* pointer;
+ typedef const char16_t& reference;
+ typedef nsScannerSubstring::Buffer Buffer;
+
+ protected:
+ nsScannerFragment mFragment;
+ const char16_t* mPosition;
+ const nsScannerSubstring* mOwner;
+
+ friend class nsScannerSubstring;
+ friend class nsScannerSharedSubstring;
+
+ public:
+ // nsScannerIterator(); // auto-generate
+ // default constructor is OK nsScannerIterator( const nsScannerIterator& ); //
+ // auto-generated copy-constructor OK nsScannerIterator& operator=( const
+ // nsScannerIterator& ); // auto-generated copy-assignment operator OK
+
+ inline void normalize_forward();
+ inline void normalize_backward();
+
+ pointer get() const { return mPosition; }
+
+ char16_t operator*() const { return *get(); }
+
+ const nsScannerFragment& fragment() const { return mFragment; }
+
+ const Buffer* buffer() const { return mFragment.mBuffer; }
+
+ self_type& operator++() {
+ ++mPosition;
+ normalize_forward();
+ return *this;
+ }
+
+ self_type operator++(int) {
+ self_type result(*this);
+ ++mPosition;
+ normalize_forward();
+ return result;
+ }
+
+ self_type& operator--() {
+ normalize_backward();
+ --mPosition;
+ return *this;
+ }
+
+ self_type operator--(int) {
+ self_type result(*this);
+ normalize_backward();
+ --mPosition;
+ return result;
+ }
+
+ difference_type size_forward() const {
+ return mFragment.mFragmentEnd - mPosition;
+ }
+
+ difference_type size_backward() const {
+ return mPosition - mFragment.mFragmentStart;
+ }
+
+ self_type& advance(difference_type n) {
+ while (n > 0) {
+ difference_type one_hop = std::min(n, size_forward());
+
+ NS_ASSERTION(one_hop > 0,
+ "Infinite loop: can't advance a reading iterator beyond the "
+ "end of a string");
+ // perhaps I should |break| if |!one_hop|?
+
+ mPosition += one_hop;
+ normalize_forward();
+ n -= one_hop;
+ }
+
+ while (n < 0) {
+ normalize_backward();
+ difference_type one_hop = std::max(n, -size_backward());
+
+ NS_ASSERTION(one_hop < 0,
+ "Infinite loop: can't advance (backward) a reading iterator "
+ "beyond the end of a string");
+ // perhaps I should |break| if |!one_hop|?
+
+ mPosition += one_hop;
+ n -= one_hop;
+ }
+
+ return *this;
+ }
+};
+
+inline bool SameFragment(const nsScannerIterator& a,
+ const nsScannerIterator& b) {
+ return a.fragment().mFragmentStart == b.fragment().mFragmentStart;
+}
+
+/**
+ * this class is needed in order to make use of the methods in nsAlgorithm.h
+ */
+template <>
+struct nsCharSourceTraits<nsScannerIterator> {
+ typedef nsScannerIterator::difference_type difference_type;
+
+ static uint32_t readable_distance(const nsScannerIterator& first,
+ const nsScannerIterator& last) {
+ return uint32_t(SameFragment(first, last) ? last.get() - first.get()
+ : first.size_forward());
+ }
+
+ static const nsScannerIterator::value_type* read(
+ const nsScannerIterator& iter) {
+ return iter.get();
+ }
+
+ static void advance(nsScannerIterator& s, difference_type n) { s.advance(n); }
+};
+
+/**
+ * inline methods follow
+ */
+
+inline void nsScannerIterator::normalize_forward() {
+ while (mPosition == mFragment.mFragmentEnd &&
+ mOwner->GetNextFragment(mFragment))
+ mPosition = mFragment.mFragmentStart;
+}
+
+inline void nsScannerIterator::normalize_backward() {
+ while (mPosition == mFragment.mFragmentStart &&
+ mOwner->GetPrevFragment(mFragment))
+ mPosition = mFragment.mFragmentEnd;
+}
+
+inline bool operator==(const nsScannerIterator& lhs,
+ const nsScannerIterator& rhs) {
+ return lhs.get() == rhs.get();
+}
+
+inline bool operator!=(const nsScannerIterator& lhs,
+ const nsScannerIterator& rhs) {
+ return lhs.get() != rhs.get();
+}
+
+inline nsScannerBufferList::Position::Position(const nsScannerIterator& aIter)
+ : mBuffer(const_cast<Buffer*>(aIter.buffer())),
+ mPosition(const_cast<char16_t*>(aIter.get())) {}
+
+inline nsScannerBufferList::Position& nsScannerBufferList::Position::operator=(
+ const nsScannerIterator& aIter) {
+ mBuffer = const_cast<Buffer*>(aIter.buffer());
+ mPosition = const_cast<char16_t*>(aIter.get());
+ return *this;
+}
+
+/**
+ * scanner string utils
+ *
+ * These methods mimic the API provided by nsReadableUtils in xpcom/string.
+ * Here we provide only the methods that the htmlparser module needs.
+ */
+
+inline size_t Distance(const nsScannerIterator& aStart,
+ const nsScannerIterator& aEnd) {
+ typedef nsScannerBufferList::Position Position;
+ return Position::Distance(Position(aStart), Position(aEnd));
+}
+
+bool CopyUnicodeTo(const nsScannerIterator& aSrcStart,
+ const nsScannerIterator& aSrcEnd, nsAString& aDest);
+
+inline bool CopyUnicodeTo(const nsScannerSubstring& aSrc, nsAString& aDest) {
+ nsScannerIterator begin, end;
+ return CopyUnicodeTo(aSrc.BeginReading(begin), aSrc.EndReading(end), aDest);
+}
+
+bool AppendUnicodeTo(const nsScannerIterator& aSrcStart,
+ const nsScannerIterator& aSrcEnd, nsAString& aDest);
+
+inline bool AppendUnicodeTo(const nsScannerSubstring& aSrc, nsAString& aDest) {
+ nsScannerIterator begin, end;
+ return AppendUnicodeTo(aSrc.BeginReading(begin), aSrc.EndReading(end), aDest);
+}
+
+bool AppendUnicodeTo(const nsScannerIterator& aSrcStart,
+ const nsScannerIterator& aSrcEnd,
+ nsScannerSharedSubstring& aDest);
+
+bool FindCharInReadable(char16_t aChar, nsScannerIterator& aStart,
+ const nsScannerIterator& aEnd);
+
+bool FindInReadable(const nsAString& aPattern, nsScannerIterator& aStart,
+ nsScannerIterator& aEnd,
+ nsStringComparator = nsTDefaultStringComparator);
+
+bool RFindInReadable(const nsAString& aPattern, nsScannerIterator& aStart,
+ nsScannerIterator& aEnd,
+ nsStringComparator = nsTDefaultStringComparator);
+
+inline bool CaseInsensitiveFindInReadable(const nsAString& aPattern,
+ nsScannerIterator& aStart,
+ nsScannerIterator& aEnd) {
+ return FindInReadable(aPattern, aStart, aEnd,
+ nsCaseInsensitiveStringComparator);
+}
+
+#endif // !defined(nsScannerString_h___)
diff --git a/parser/htmlparser/tests/crashtests/121591-1.html b/parser/htmlparser/tests/crashtests/121591-1.html
new file mode 100644
index 0000000000..b411a18518
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/121591-1.html
@@ -0,0 +1,22 @@
+<HTML>
+<body>
+<span>
+<head><link></head>
+ <table border=1>
+ <tr><td>
+ <table border=1 align="left">
+ <tr><td></td></tr>
+ <tr><td>
+ <form>
+ <button></button>
+ </form>
+ </td></tr>
+ </table>
+ </td></tr>
+ </table>
+</span>
+</body>
+</html>
+
+
+
diff --git a/parser/htmlparser/tests/crashtests/1373045-1.html b/parser/htmlparser/tests/crashtests/1373045-1.html
new file mode 100644
index 0000000000..d0bea2fa44
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/1373045-1.html
@@ -0,0 +1 @@
+<object data="data:image/svg+xml;charset=ISO-2022-KR,%30"></object>
diff --git a/parser/htmlparser/tests/crashtests/147179-1.html b/parser/htmlparser/tests/crashtests/147179-1.html
new file mode 100644
index 0000000000..2aaac19844
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/147179-1.html
@@ -0,0 +1,7 @@
+<html><head><title>Testcase for bug 141561</title></head>
+<body>
+
+<script>document.write("<form><input type='password'></form>");</script>
+
+</body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/151956-1.html b/parser/htmlparser/tests/crashtests/151956-1.html
new file mode 100644
index 0000000000..0ae77f6a6c
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/151956-1.html
@@ -0,0 +1,18 @@
+<html>
+<body>
+<!-- script isn't actually required for the crash of bug 151956 -->
+<table border>
+ <tbody>
+ <form>
+ <script>
+ var foo = 42;
+ </script>
+ </form>
+ <tr>
+ <td> X </td>
+ </tr>
+ </tbody>
+</table>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/crashtests/152444-1.html b/parser/htmlparser/tests/crashtests/152444-1.html
new file mode 100644
index 0000000000..6576444544
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/152444-1.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<title>Untitled</title>
+</head>
+<body>
+<table>
+<tbody>
+<form>
+<tr><td colspan=2></td></tr>
+<tr><td></td><td></td></tr>
+</form>
+</tbody>
+</table>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/1534346-1.html b/parser/htmlparser/tests/crashtests/1534346-1.html
new file mode 100644
index 0000000000..34ab7930db
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/1534346-1.html
@@ -0,0 +1 @@
+<svg><script></svg>
diff --git a/parser/htmlparser/tests/crashtests/1604307-1.html b/parser/htmlparser/tests/crashtests/1604307-1.html
new file mode 100644
index 0000000000..28a2e7caf0
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/1604307-1.html
@@ -0,0 +1,10 @@
+<script>
+function go() {
+ b.crossOrigin = ""
+ document.execCommand("insertHTML", false, c.innerHTML)
+}
+</script>
+<image id="b" src="data:;base64,R0lGODlhIAAgAPIBAGbMzP///wAAADOZZpn/zAAAAAAAAAAAACH5BAAAAAAALAAAAAAgACAAAA" onload="go()"></image>
+<data id="c">
+<s contenteditable="true"
+<!-- A -->
diff --git a/parser/htmlparser/tests/crashtests/1606499-1.html b/parser/htmlparser/tests/crashtests/1606499-1.html
new file mode 100644
index 0000000000..5771d73d8d
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/1606499-1.html
@@ -0,0 +1,15 @@
+<html class="reftest-wait">
+<script>
+let alreadyRun = sessionStorage.getItem("ran1606499");
+if (alreadyRun) {
+ document.documentElement.removeAttribute("class");
+} else {
+ sessionStorage.setItem("ran1606499", "ran1606499");
+ document.addEventListener('DOMContentLoaded', () => {
+ setTimeout(() => { document.close() }, 146)
+ setTimeout(() => { location.reload() }, 145)
+ self.stop()
+ document.write('<body></body>')
+ })
+}
+</script>
diff --git a/parser/htmlparser/tests/crashtests/185073-1.html b/parser/htmlparser/tests/crashtests/185073-1.html
new file mode 100644
index 0000000000..39504ede22
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/185073-1.html
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>bug 185073</title>
+ </head>
+ <body>
+ <font>
+ <div id="updateText">
+ <script language=javascript type=text/javascript>
+ document.write('</div>');
+ document.getElementById("updateText").innerHTML = "foo";
+ </script>
+ </div>
+ </font>
+ </body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/188474-1.html b/parser/htmlparser/tests/crashtests/188474-1.html
new file mode 100644
index 0000000000..2e8b03d197
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/188474-1.html
@@ -0,0 +1,13 @@
+<HTML><HEAD>
+<SCRIPT language="javascript" type="text/javascript">
+
+var header ="<body><div id=\"foo\"></div><div id=\"foo2\"><!-- comment -->";
+
+var footer = "</div><!-- comment -->";
+
+</SCRIPT>
+<SCRIPT language="javascript" type="text/javascript">document.write(header);</SCRIPT>
+</HEAD>
+<BODY>
+<SCRIPT language="javascript" type="text/javascript">document.write(footer);</SCRIPT>
+</BODY></HTML>
diff --git a/parser/htmlparser/tests/crashtests/194329-1.html b/parser/htmlparser/tests/crashtests/194329-1.html
new file mode 100644
index 0000000000..c7ab69007e
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/194329-1.html
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title>bug 188474</title>
+ </head>
+ <body>
+ <head>
+ <div>
+ <script>
+ document.write("<\/div>");
+ </script>
+ <noscript>
+ </div>
+ </noscript><!-- End PayPal Logo -->
+ </body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/197052-1.html b/parser/htmlparser/tests/crashtests/197052-1.html
new file mode 100644
index 0000000000..d0b30c761b
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/197052-1.html
@@ -0,0 +1 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"> <html> <head> <title>testcase - crasher</title> </head> <body> <div id="uniqid"> <script language="JavaScript" type="text/JavaScript"> document.write("&gt;"+document.getElementById('uniqid').innerHTML+"&lt;"); </script> </div> </body> </html> \ No newline at end of file
diff --git a/parser/htmlparser/tests/crashtests/220542-1.html b/parser/htmlparser/tests/crashtests/220542-1.html
new file mode 100644
index 0000000000..f664734664
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/220542-1.html
@@ -0,0 +1,2 @@
+<script>document.write('<link href="l:\\" rel=stylesheet>')</script>
+
diff --git a/parser/htmlparser/tests/crashtests/253979-1.html b/parser/htmlparser/tests/crashtests/253979-1.html
new file mode 100644
index 0000000000..5e47ee84c9
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/253979-1.html
@@ -0,0 +1,4 @@
+<html><head></head><body>
+<a><a><p><font><p><font><b><a></font></a>
+</body></html>
+
diff --git a/parser/htmlparser/tests/crashtests/269095-1.html b/parser/htmlparser/tests/crashtests/269095-1.html
new file mode 100644
index 0000000000..83cc52828e
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/269095-1.html
@@ -0,0 +1 @@
+<TABLE > <FRAMESET> <PARAM> <FORM> <MAP> <FORM> <TABLE> <RTABLE> \ No newline at end of file
diff --git a/parser/htmlparser/tests/crashtests/286733-1.html b/parser/htmlparser/tests/crashtests/286733-1.html
new file mode 100644
index 0000000000..04be4f11d3
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/286733-1.html
@@ -0,0 +1,4 @@
+<TABLE>
+<FRAMESET><FRAME></FRAMESET>
+<TR><TD><TABLE>
+ <TR><BR><TD><MAP><TABLE><BR></MAP>
diff --git a/parser/htmlparser/tests/crashtests/286733-2.html b/parser/htmlparser/tests/crashtests/286733-2.html
new file mode 100644
index 0000000000..5fcf7a7ff9
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/286733-2.html
@@ -0,0 +1,4 @@
+<TABLE>
+<FRAMESET><FRAME></FRAMESET>
+<TR><TD><TABLE>
+ <TR><BR><TD><MAP><TABLE><TR><BR></MAP>
diff --git a/parser/htmlparser/tests/crashtests/299036-1.html b/parser/htmlparser/tests/crashtests/299036-1.html
new file mode 100644
index 0000000000..e21ce2b9b7
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/299036-1.html
@@ -0,0 +1,2 @@
+<table><textarea></textarea></table>
+
diff --git a/parser/htmlparser/tests/crashtests/30885-1.html b/parser/htmlparser/tests/crashtests/30885-1.html
new file mode 100644
index 0000000000..2dc0fe035d
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/30885-1.html
@@ -0,0 +1,17 @@
+<HTML>
+ <BODY>
+
+ <TABLE BORDER="1">
+ <TR>
+ <TD>
+ <A HREF="foo.htm">
+ <FONT></A>
+ <A HREF="bar.htm">
+ <FONT>
+ MacDesktops</A>
+ </FONT>
+ </TD>
+ </TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/parser/htmlparser/tests/crashtests/30956-1.html b/parser/htmlparser/tests/crashtests/30956-1.html
new file mode 100644
index 0000000000..508149a97d
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/30956-1.html
@@ -0,0 +1,10 @@
+<HTML>
+
+<body>
+<table>
+ <td>
+ <li><font size="-1">
+ <li><a href="foo.html"></font></a>
+</table>
+</body>
+</html> \ No newline at end of file
diff --git a/parser/htmlparser/tests/crashtests/31392-1.html b/parser/htmlparser/tests/crashtests/31392-1.html
new file mode 100644
index 0000000000..0a4a138b34
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/31392-1.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<title>Crash Test page</title>
+</head>
+<body>
+
+<table>
+<tr>
+<td>
+<LINK REL="stylesheet" HREF="garbagestyle.css" TYPE="text/css">
+</td>
+</tr>
+</table>
+</body>
+</html> \ No newline at end of file
diff --git a/parser/htmlparser/tests/crashtests/31694-1.html b/parser/htmlparser/tests/crashtests/31694-1.html
new file mode 100644
index 0000000000..8be2d47f02
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/31694-1.html
@@ -0,0 +1,8 @@
+<HTML><HEAD>
+<script src="foo.js"></script>
+<csactions>
+<csaction name="bar" class="foobar" type="ONEVENT">
+</csactions>
+</HEAD>
+<BODY>
+<DD></DD></BODY></HTML>
diff --git a/parser/htmlparser/tests/crashtests/31940-1.html b/parser/htmlparser/tests/crashtests/31940-1.html
new file mode 100644
index 0000000000..ec2f370e83
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/31940-1.html
@@ -0,0 +1,15 @@
+<HEAD>
+ <LINK rel="stylesheet">
+ <rdf:RDF>
+ <rdf:Description/>
+ </rdf:RDF>
+</HEAD>
+
+<BODY>
+
+<rdf:RDF>
+<rdfs:Class/>
+</rdf:RDF>
+
+</BODY>
+</HTML>
diff --git a/parser/htmlparser/tests/crashtests/32613-1.html b/parser/htmlparser/tests/crashtests/32613-1.html
new file mode 100644
index 0000000000..f50c342e9f
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/32613-1.html
@@ -0,0 +1,18 @@
+<P><font color="003366" FACE="Serif">
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+<P><FONT size="2"></P>
+</FONT><BR>
diff --git a/parser/htmlparser/tests/crashtests/328751-1.html b/parser/htmlparser/tests/crashtests/328751-1.html
new file mode 100644
index 0000000000..37b46af345
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/328751-1.html
@@ -0,0 +1,9 @@
+<HEAD >
+<OBJECT >
+<APPLET CODE=" >
+<BODY TEXT=https://n%ItGEv5%&N8%6USN5i9"
+<TABLE >
+<ISINDEX >
+<TITLE >
+<TBODY >
+</HEAD > \ No newline at end of file
diff --git a/parser/htmlparser/tests/crashtests/34168-1.html b/parser/htmlparser/tests/crashtests/34168-1.html
new file mode 100644
index 0000000000..a191a03681
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/34168-1.html
@@ -0,0 +1 @@
+<!ENTITY editAwayMessageSpecial3.label " %d = Current date"> \ No newline at end of file
diff --git a/parser/htmlparser/tests/crashtests/34168-1.xml b/parser/htmlparser/tests/crashtests/34168-1.xml
new file mode 100644
index 0000000000..71a058c316
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/34168-1.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE foo [
+<!ENTITY editAwayMessageSpecial3.label " %%d = Current date">
+<!ELEMENT foo EMPTY>
+]>
+<foo/>
diff --git a/parser/htmlparser/tests/crashtests/408939-1.html b/parser/htmlparser/tests/crashtests/408939-1.html
new file mode 100644
index 0000000000..844c70e72e
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/408939-1.html
@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+
+<div>
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+</div>
+
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+
+</body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/41427-1.html b/parser/htmlparser/tests/crashtests/41427-1.html
new file mode 100644
index 0000000000..5612153da5
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/41427-1.html
@@ -0,0 +1 @@
+<A HREF=""><font><B>t</A><head><script>
diff --git a/parser/htmlparser/tests/crashtests/423373-1.html b/parser/htmlparser/tests/crashtests/423373-1.html
new file mode 100644
index 0000000000..4876095480
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/423373-1.html
@@ -0,0 +1 @@
+<body><asdf><legend>
diff --git a/parser/htmlparser/tests/crashtests/44178-1.html b/parser/htmlparser/tests/crashtests/44178-1.html
new file mode 100644
index 0000000000..0ecb40ef77
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/44178-1.html
@@ -0,0 +1,8 @@
+<html>
+<body>
+<div>
+<server>
+</server>
+</div>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/445171-1-inner.svg b/parser/htmlparser/tests/crashtests/445171-1-inner.svg
new file mode 100644
index 0000000000..24ed6f8a70
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/445171-1-inner.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" onload="location = 'file_445171-1.html'">
+
+<rect x="5" y="5" width="50" height="50" />
+
+</svg>
diff --git a/parser/htmlparser/tests/crashtests/445171-1.html b/parser/htmlparser/tests/crashtests/445171-1.html
new file mode 100644
index 0000000000..0abaacdfba
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/445171-1.html
@@ -0,0 +1,9 @@
+<html class="reftest-wait">
+<head>
+<script>
+function done() { document.documentElement.removeAttribute("class"); }
+</script>
+<body>
+<iframe src="445171-1-inner.svg"></iframe>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/46495-1.html b/parser/htmlparser/tests/crashtests/46495-1.html
new file mode 100644
index 0000000000..a0947ff2ca
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/46495-1.html
@@ -0,0 +1,5 @@
+<html>
+ <body>
+ <p ">
+ </body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/468538-1.xhtml b/parser/htmlparser/tests/crashtests/468538-1.xhtml
new file mode 100644
index 0000000000..576b333c19
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/468538-1.xhtml
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<head>
+<script type="text/javascript">
+
+function boom()
+{
+ var v = document.getElementById("v");
+ document.body.removeChild(document.body.firstChild);
+ v.innerHTML = "f";
+}
+
+</script>
+</head>
+<body onload="boom();"><xul:box><div id="v"/></xul:box></body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/50134-1.html b/parser/htmlparser/tests/crashtests/50134-1.html
new file mode 100644
index 0000000000..efe680a1f4
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/50134-1.html
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <title>Mozilla Bug 50134</title>
+ </head>
+ <body>
+ <!--->
+ </body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/502103.html b/parser/htmlparser/tests/crashtests/502103.html
new file mode 100644
index 0000000000..171a2890e5
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/502103.html
@@ -0,0 +1 @@
+<isindex action=""> \ No newline at end of file
diff --git a/parser/htmlparser/tests/crashtests/502869-iframe.html b/parser/htmlparser/tests/crashtests/502869-iframe.html
new file mode 100644
index 0000000000..ff76e020bf
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/502869-iframe.html
@@ -0,0 +1,9 @@
+<html><head><title>[HTML5] Crash [@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster] with document.write and removing stuff</title></head><body><a>
+<script>
+var x=document.getElementsByTagName("*");
+x[1].remove();
+x[2].remove();
+</script>
+<div>
+<script>document.write('<'+'script>document.removeChild(document.documentElement);<'+'/script>');</script>
+</a></body></html>
diff --git a/parser/htmlparser/tests/crashtests/502869.html b/parser/htmlparser/tests/crashtests/502869.html
new file mode 100644
index 0000000000..5da23b5076
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/502869.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait"><head>
+ <meta charset="utf-8">
+ <title>Testcase for bug 502869</title>
+<script>
+function done()
+{
+ document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+<body onload="setTimeout(done,1000)">
+
+<iframe src="502869-iframe.html"></iframe>
+
+
+</body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/50994-1.html b/parser/htmlparser/tests/crashtests/50994-1.html
new file mode 100644
index 0000000000..11bd9aaf07
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/50994-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML>
+ <HEAD>
+ <TITLE>Mozilla Bug 50994</TITLE>
+ </HEAD>
+ <BODY>
+ <P>
+ <FORM action="">
+ <P>
+ </FORM>
+ </BODY>
+</HTML>
diff --git a/parser/htmlparser/tests/crashtests/515278-1.html b/parser/htmlparser/tests/crashtests/515278-1.html
new file mode 100644
index 0000000000..33e01f2224
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/515278-1.html
@@ -0,0 +1,3 @@
+
+<fooz>
+
diff --git a/parser/htmlparser/tests/crashtests/515533-1-inner.html b/parser/htmlparser/tests/crashtests/515533-1-inner.html
new file mode 100644
index 0000000000..6bd0684e21
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/515533-1-inner.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+</head>
+<body>
+<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
+<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
+<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
+<script language="javascript">
+window.location.replace("data:text/plain,");
+</script>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/515533-1.html b/parser/htmlparser/tests/crashtests/515533-1.html
new file mode 100644
index 0000000000..b0d5b570b8
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/515533-1.html
@@ -0,0 +1 @@
+<iframe src="515533-1-inner.html"></iframe>
diff --git a/parser/htmlparser/tests/crashtests/515816-1.html b/parser/htmlparser/tests/crashtests/515816-1.html
new file mode 100644
index 0000000000..c518d2a3cf
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/515816-1.html
@@ -0,0 +1,11 @@
+<html>
+<body>
+<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
+<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
+<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
+<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
+<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
+<!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
+<form>
+<input>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
diff --git a/parser/htmlparser/tests/crashtests/522326-1.html b/parser/htmlparser/tests/crashtests/522326-1.html
new file mode 100644
index 0000000000..d06ab6cf7d
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/522326-1.html
@@ -0,0 +1 @@
+<html><head><META http-equiv="Content-Type" content="text/html; charset=utf-16"><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></head><body>abcd</body></html>
diff --git a/parser/htmlparser/tests/crashtests/525229-1.html b/parser/htmlparser/tests/crashtests/525229-1.html
new file mode 100644
index 0000000000..8bffa7d601
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/525229-1.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<title>Test for bug 525229</title>
+<body>
+<script>
+document.write("<script src='data:text/javascript,'><\/script><div>");
+</script>
+text
diff --git a/parser/htmlparser/tests/crashtests/536097-1.html b/parser/htmlparser/tests/crashtests/536097-1.html
new file mode 100644
index 0000000000..76befb3cc8
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/536097-1.html
@@ -0,0 +1 @@
+<script>document.write("<iframe></iframe\n");</script><img>
diff --git a/parser/htmlparser/tests/crashtests/555462-iframe.html b/parser/htmlparser/tests/crashtests/555462-iframe.html
new file mode 100644
index 0000000000..3ddd6282db
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/555462-iframe.html
@@ -0,0 +1,3 @@
+<!--mmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmm mmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmm mmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmm mmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmm -->
+<textarea><mmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmm mmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmmmmmmmmmm mmmmmmmmmmmmmmm
+</textarea> \ No newline at end of file
diff --git a/parser/htmlparser/tests/crashtests/555462.html b/parser/htmlparser/tests/crashtests/555462.html
new file mode 100644
index 0000000000..f8d4afad71
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/555462.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait"><head>
+ <meta charset="utf-8">
+ <title>Testcase for bug 555462</title>
+<script>
+function f1() {
+ window.frames[0].frameElement.removeAttribute("onload");
+ window.frames[0].location.reload();
+ setTimeout(f2,200);
+}
+function f2() { window.frames[0].location.reload(); setTimeout(done,400); }
+function done() { document.documentElement.removeAttribute("class"); }
+</script>
+</head>
+<body>
+
+<iframe src="555462-iframe.html" onload="setTimeout(f1,100)"></iframe>
+
+
+</body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/563514-1.html b/parser/htmlparser/tests/crashtests/563514-1.html
new file mode 100644
index 0000000000..b96ce14661
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/563514-1.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<script>
+function boom()
+{
+ document.createElement("span").innerHTML = "<body a='b'>";
+}
+</script>
+</head>
+<body onload="boom();"></body> \ No newline at end of file
diff --git a/parser/htmlparser/tests/crashtests/574884-1.html b/parser/htmlparser/tests/crashtests/574884-1.html
new file mode 100644
index 0000000000..19de3c74a4
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/574884-1.html
@@ -0,0 +1 @@
+<svg></html>
diff --git a/parser/htmlparser/tests/crashtests/574884-2.html b/parser/htmlparser/tests/crashtests/574884-2.html
new file mode 100644
index 0000000000..09bec52e6d
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/574884-2.html
@@ -0,0 +1 @@
+<math></html>
diff --git a/parser/htmlparser/tests/crashtests/58455-1.html b/parser/htmlparser/tests/crashtests/58455-1.html
new file mode 100644
index 0000000000..7c235f9806
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/58455-1.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+ <title>Computer Market Online</title>
+ <BASE HREF="http://www.computermarket.com.au/">
+</head>
+
+<body bgcolor="#ffffff">
+
+<table>
+<tr><td><a href='prodDetail.asp?id=6007&catid=241'>This shows</a></td></tr>
+<tr><td><a href='prodDetail.asp?id=6007&catid=241'">This does not show</a></td></tr>
+</table>
+
+</body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/591330-1.html b/parser/htmlparser/tests/crashtests/591330-1.html
new file mode 100644
index 0000000000..31719fac6a
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/591330-1.html
@@ -0,0 +1,284 @@
+<script>
+var sleep = 500; // 0.5 seconds
+var start = Number(new Date());
+while(Number(new Date()) - start < sleep) {
+}
+document.write("<div>"); // make speculation fail
+</script>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+<span>
+
diff --git a/parser/htmlparser/tests/crashtests/60110-1.html b/parser/htmlparser/tests/crashtests/60110-1.html
new file mode 100644
index 0000000000..34f8c406b8
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/60110-1.html
@@ -0,0 +1,22 @@
+<HTML><HEAD>
+<TITLE>Edit parameters</TITLE>
+
+
+</HEAD>
+<BODY BGCOLOR="#FFFFFF" TEXT="#000000"
+LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000" >
+
+<p>
+Any item you check Reset on will get reset to its default value.
+<form method=post action=doeditparams.cgi><table>
+
+<tr><td valign=top><input type=checkbox name=reset-newchangedmail>Reset</td><td>
+<textarea wrap=hard name=newchangedmail rows=10 cols=80>From: bugzilla-daemon&#010;To: %to%&#013;&#010;Cc: %cc%&#013;&#010;Subject: [Bug %bugid%] %neworchanged% - %summary%&#013;&#010;&#013;&#010;%urlbase%show_bug.cgi?id=%bugid%&#013;&#010;&#013;&#010;%diffs%</textarea>
+</td></tr>
+<tr><td valign=top><input type=checkbox name=reset-whinemail>Reset</td><td>
+<textarea wrap=hard name=whinemail rows=10 cols=80>From: bugzilla-daemon&#010;To: %email%&#013;&#010;Subject: Your Bugzilla buglist needs attention.&#013;&#010;&#013;&#010;[This e-mail has been automatically generated.]&#013;&#010;&#013;&#010;You have one or more bugs assigned to you in the Bugzilla &#013;&#010;bugsystem (%urlbase%) that require&#013;&#010;attention.&#013;&#010;&#013;&#010;All of these bugs are in the NEW state, and have not been touched&#013;&#010;in %whinedays% days or more. You need to take a look at them, and &#013;&#010;decide on an initial action.&#013;&#010;&#013;&#010;&#013;&#010;&#013;&#010;</textarea>
+</td></tr>
+<tr><td></td><td>2.11</td></tr></table>
+<input type=reset value="Reset form"><br>
+<input type=submit value="Submit changes">
+</form> \ No newline at end of file
diff --git a/parser/htmlparser/tests/crashtests/616027-1.html b/parser/htmlparser/tests/crashtests/616027-1.html
new file mode 100644
index 0000000000..d4707c9359
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/616027-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+
+
+for (var fuzzRepeat = 0; fuzzRepeat < 500; ++fuzzRepeat) {
+ document.write("<span>");
+}
+document.write("<isindex>");
+
+
+</script>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/650501-1.xhtml b/parser/htmlparser/tests/crashtests/650501-1.xhtml
new file mode 100644
index 0000000000..c701a0c76c
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/650501-1.xhtml
@@ -0,0 +1,22 @@
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+<![CDATA[
+
+function boom()
+{
+ var a = document.createElement("div");
+ a.innerHTML = "<script>1;<\/script>";
+
+ var b = document.createElement("div")
+ try { b.innerHTML = "<"; } catch (invalidXML) { }
+
+ document.documentElement.appendChild(a);
+}
+
+]]>
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/662185-1.html b/parser/htmlparser/tests/crashtests/662185-1.html
new file mode 100644
index 0000000000..41d67e5355
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/662185-1.html
@@ -0,0 +1 @@
+<meta charset=t>
diff --git a/parser/htmlparser/tests/crashtests/696651-1.html b/parser/htmlparser/tests/crashtests/696651-1.html
new file mode 100644
index 0000000000..8c5ee9ed3a
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/696651-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script>
+function runTest() {
+ var iframe = document.getElementsByTagName("iframe")[0];
+ var doc = iframe.contentDocument;
+ doc.write("\u003cscript>document.close();\u003c/script>foo");
+}
+</script>
+<body onload="runTest();">
+<iframe></iframe>
+
diff --git a/parser/htmlparser/tests/crashtests/699347-1.xml b/parser/htmlparser/tests/crashtests/699347-1.xml
new file mode 100644
index 0000000000..c6dd4bfa1b
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/699347-1.xml
@@ -0,0 +1 @@
+<?xml version="1.0"?><root/>
diff --git a/parser/htmlparser/tests/crashtests/721313-1.html b/parser/htmlparser/tests/crashtests/721313-1.html
new file mode 100644
index 0000000000..06497cd65b
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/721313-1.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<script>(new DOMParser()).parseFromString("", "text/html");</script>
diff --git a/parser/htmlparser/tests/crashtests/73331-1.html b/parser/htmlparser/tests/crashtests/73331-1.html
new file mode 100644
index 0000000000..6761a6686a
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/73331-1.html
@@ -0,0 +1,27 @@
+<html>
+<head>
+<script>
+function crashme() {
+ var obj = document.getElementById('popupid');
+ obj.style.visibility='hidden';
+}
+</script>
+</head>
+<body onload="crashme();">
+<a href="http://www.mozilla.org/">http://www.mozilla.org/</a>
+
+<div id="popupid">
+<font>
+<script>
+ document.write('<form>');
+ document.write('<span>');
+ document.write('<input>');
+ document.write('</span>');
+ document.write('<br>');
+ document.write('</form>');
+</script>
+</font>
+</div>
+
+</body>
+</html>
diff --git a/parser/htmlparser/tests/crashtests/742414-1.html b/parser/htmlparser/tests/crashtests/742414-1.html
new file mode 100644
index 0000000000..e35b125603
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/742414-1.html
@@ -0,0 +1,4 @@
+<script></script
+><script></script
+><script></script
+>
diff --git a/parser/htmlparser/tests/crashtests/762726-1.html b/parser/htmlparser/tests/crashtests/762726-1.html
new file mode 100644
index 0000000000..4692b73e1e
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/762726-1.html
@@ -0,0 +1 @@
+<meta charset>
diff --git a/parser/htmlparser/tests/crashtests/92647-1.html b/parser/htmlparser/tests/crashtests/92647-1.html
new file mode 100644
index 0000000000..16be8d98e1
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/92647-1.html
@@ -0,0 +1,33 @@
+<HTML>
+<BODY>
+ <form>
+<TABLE border="1">
+ <TR>
+ <TD>
+ <TABLE border="2">
+ <TR>
+ <TD WIDTH="30%">
+ Member Number:
+ </TD>
+ <TD WIDTH="70%">
+ <INPUT NAME="EchoUser" TYPE="TEXT">
+ </TD>
+ </TR>
+ <TR>
+ <TD>
+ PIN:
+ </TD>
+ <TD>
+ <INPUT TYPE="password">
+ </TD>
+ <TD>
+ </TD>
+ </TR>
+ </TABLE>
+ </TD>
+ </TR>
+</TABLE>
+</Form>
+</BODY>
+</HTML>
+
diff --git a/parser/htmlparser/tests/crashtests/92788-1.html b/parser/htmlparser/tests/crashtests/92788-1.html
new file mode 100644
index 0000000000..955301e3f2
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/92788-1.html
@@ -0,0 +1,20 @@
+<HTML><HEAD><TITLE>Bug #92788</TITLE></HEAD>
+<BODY>
+<TABLE>
+ <TR>
+ <TD>
+ <CENTER>
+ <TR>
+ <TD>
+ <IFRAME
+ marginWidth=0 marginHeight=0 src="foo" frameBorder=0 width=125 scrolling=no
+ height=125><SCRIPT LANGUAGE="JavaScript">document.write('<SCR'+'IPT LANGUAGE="JavaScript" SRC="http://ads1.ad-flow.com/?DC=tweak3d+-+rst&JS=Y&TARGET=_blank"></SCR'+'IPT>');</SCRIPT><NOSCRIPT><A HREF="http://ads1.ad-flow.com/?SHT=tweak3d+-+rst" TARGET="_blank"><IMG SRC="http://ads1.ad-flow.com/?SIT=tweak3d+-+rst" HEIGHT="125" WIDTH="125"></A></NOSCRIPT></IFRAME>--&gt;
+ <FORM name=EmailSub onsubmit="if ( (document.EmailSub.email.length == 0) || (document.EmailSub.email.value.indexOf('@') == -1) || (document.EmailSub.email.value.indexOf('.') == -1) ) {('Invalid Email address');return false;} window.open('http://www.pluginnewsletter.com/nl-popsub.cfm?wsnum=369&amp;' + 'Email=' + document.EmailSub.email.value,'WinOpen','toolbar=no,scrollbars=yes,resizable=yes,width=666,height=666'); return false;">
+ <SCRIPT language=JavaScript src="foo.js"></SCRIPT>
+ <NOSCRIPT><A target=_blank href="http://ads1.ad-flow.com/?SHT=tweak3d-lst" WIDTH="468" HEIGHT="60"><IMG src="Tweak3D_net - Your Freakin' Tweakin' Source!_fichiers/ads1.ad-flow.gif"></A>
+ </NOSCRIPT></CENTER>
+
+ <TR bgColor=#ffffff>
+ <CENTER><IFRAME marginWidth=0 marginHeight=0 src="foo" frameBorder=0 width=468 scrolling=no height=60><SCRIPT LANGUAGE="JavaScript">document.write('<SCR'+'IPT LANGUAGE="JavaScript" SRC="http://ads1.ad-flow.com/?DC=tweak3d-top&JS=Y&TARGET=_blank"></SCR'+'IPT>');</SCRIPT><NOSCRIPT><A HREF="http://ads1.ad-flow.com/?SHT=tweak3d-top" TARGET="_blank"><IMG SRC="http://ads1.ad-flow.com/?SIT=tweak3d-top&SC=Y" HEIGHT="60" WIDTH="468"></A></NOSCRIPT></IFRAME>
+</CENTER></TR>
+</BODY></HTML>
diff --git a/parser/htmlparser/tests/crashtests/981279-1.html b/parser/htmlparser/tests/crashtests/981279-1.html
new file mode 100644
index 0000000000..5f14c8af37
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/981279-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+</head>
+<body>
+<div></div>
+<script>
+var div = document.getElementsByTagName("div")[0];
+div.innerHTML = "<div À Á Â Ã Ä Å ";
+div.innerHTML = "<div a>";
+</script>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/crashtests/982285-1.html b/parser/htmlparser/tests/crashtests/982285-1.html
new file mode 100644
index 0000000000..d3e124d957
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/982285-1.html
@@ -0,0 +1,19 @@
+<q>
+<u>
+<pre>
+<pre>
+<center>
+<em>
+<center>
+<center>
+</rp>
+<address>
+<address>
+<address>
+</rt>
+<q>
+<q>
+<rt>
+</u>
+<pre>
+</em>
diff --git a/parser/htmlparser/tests/crashtests/crashtests.list b/parser/htmlparser/tests/crashtests/crashtests.list
new file mode 100644
index 0000000000..8921ab5e81
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/crashtests.list
@@ -0,0 +1,64 @@
+load 30885-1.html
+load 30956-1.html
+load 31392-1.html
+load 31694-1.html
+load 31940-1.html
+load 32613-1.html
+load 34168-1.html
+load 34168-1.xml
+load 41427-1.html
+load 44178-1.html
+load 46495-1.html
+load 50134-1.html
+load 50994-1.html
+load 58455-1.html
+load 60110-1.html
+load 73331-1.html
+load 92647-1.html
+load 92788-1.html
+load 121591-1.html
+load 147179-1.html
+load 151956-1.html
+load 152444-1.html
+load 185073-1.html
+load 188474-1.html
+load 194329-1.html
+load 197052-1.html
+load 220542-1.html
+load 253979-1.html
+load 269095-1.html
+load 286733-1.html
+load 286733-2.html
+load 299036-1.html
+skip-if(cocoaWidget&&browserIsRemote) load 328751-1.html # Bug 849747
+load 408939-1.html
+load 423373-1.html
+load 445171-1.html
+load 468538-1.xhtml
+load 502103.html
+load 502869.html
+load 515278-1.html
+load 515533-1.html
+load 515816-1.html
+load 522326-1.html
+load 525229-1.html
+load 536097-1.html
+load 555462.html
+load 563514-1.html
+load 574884-1.html
+load 574884-2.html
+load 591330-1.html
+load 616027-1.html
+load 650501-1.xhtml
+load 662185-1.html
+load 696651-1.html
+load view-source:699347-1.xml
+load 721313-1.html
+load view-source:742414-1.html
+load 762726-1.html
+load 981279-1.html
+load 982285-1.html
+load 1373045-1.html
+load 1534346-1.html
+load 1604307-1.html
+load 1606499-1.html
diff --git a/parser/htmlparser/tests/crashtests/file_445171-1.html b/parser/htmlparser/tests/crashtests/file_445171-1.html
new file mode 100644
index 0000000000..de8a5eb065
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/file_445171-1.html
@@ -0,0 +1 @@
+<script>parent.done()</script>
diff --git a/parser/htmlparser/tests/mochitest/.eslintrc.js b/parser/htmlparser/tests/mochitest/.eslintrc.js
new file mode 100644
index 0000000000..7612459de1
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/.eslintrc.js
@@ -0,0 +1,5 @@
+"use strict";
+
+module.exports = {
+ extends: ["plugin:mozilla/browser-test", "plugin:mozilla/mochitest-test"],
+};
diff --git a/parser/htmlparser/tests/mochitest/blue.png b/parser/htmlparser/tests/mochitest/blue.png
new file mode 100644
index 0000000000..8df58f3a5f
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/blue.png
Binary files differ
diff --git a/parser/htmlparser/tests/mochitest/broken_xml.xhtml b/parser/htmlparser/tests/mochitest/broken_xml.xhtml
new file mode 100644
index 0000000000..f81bf3998b
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/broken_xml.xhtml
@@ -0,0 +1,7 @@
+<html>
+ <head>
+ <title>&nonExistingEntity;</title>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/browser.ini b/parser/htmlparser/tests/mochitest/browser.ini
new file mode 100644
index 0000000000..d776756351
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/browser.ini
@@ -0,0 +1,12 @@
+[DEFAULT]
+prefs =
+ # we need to reload the XML file to make the test pass
+ nglayout.debug.disable_xul_cache=true
+
+[browser_viewsource.js]
+support-files =
+ file_viewsource.html
+
+[browser_ysod_telemetry.js]
+support-files =
+ broken_xml.xhtml
diff --git a/parser/htmlparser/tests/mochitest/browser_viewsource.js b/parser/htmlparser/tests/mochitest/browser_viewsource.js
new file mode 100644
index 0000000000..a6842502d3
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/browser_viewsource.js
@@ -0,0 +1,28 @@
+"use strict";
+
+add_task(async function() {
+ const PAGE_URL = getRootDirectory(gTestPath) + "file_viewsource.html";
+ let viewSourceTab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "view-source:" + PAGE_URL
+ );
+
+ let xhrPromise = new Promise(resolve => {
+ let xhr = new XMLHttpRequest();
+ xhr.open("GET", PAGE_URL, true);
+ xhr.onload = event => resolve(event.target.responseText);
+ xhr.send();
+ });
+
+ let viewSourceContentPromise = SpecialPowers.spawn(
+ viewSourceTab.linkedBrowser,
+ [],
+ async function() {
+ return content.document.body.textContent;
+ }
+ );
+
+ let results = await Promise.all([viewSourceContentPromise, xhrPromise]);
+ is(results[0], results[1], "Sources should match");
+ BrowserTestUtils.removeTab(viewSourceTab);
+});
diff --git a/parser/htmlparser/tests/mochitest/browser_ysod_telemetry.js b/parser/htmlparser/tests/mochitest/browser_ysod_telemetry.js
new file mode 100644
index 0000000000..5a709351e7
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/browser_ysod_telemetry.js
@@ -0,0 +1,47 @@
+"use strict";
+
+const { TelemetryTestUtils } = ChromeUtils.import(
+ "resource://testing-common/TelemetryTestUtils.jsm"
+);
+
+add_task(async function test_popup_opened() {
+ Services.telemetry.clearEvents();
+ Services.telemetry.setEventRecordingEnabled("ysod", true);
+
+ const PAGE_URL = getRootDirectory(gTestPath) + "broken_xml.xhtml";
+ let viewSourceTab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ PAGE_URL
+ );
+
+ let content = await SpecialPowers.spawn(
+ viewSourceTab.linkedBrowser,
+ [],
+ async function() {
+ return content.document.documentElement.innerHTML;
+ }
+ );
+
+ ok(content.includes("XML"), "Document shows XML error");
+
+ TelemetryTestUtils.assertEvents(
+ [
+ {
+ method: "shown",
+ object: "ysod",
+ value: PAGE_URL.substr(0, 80),
+ extra: {
+ error_code: "11",
+ location: "3:12",
+ last_line: " <title>&nonExistingEntity;</title>",
+ last_line_len: "38",
+ },
+ },
+ ],
+ {
+ category: "ysod",
+ },
+ { process: "parent" }
+ );
+ BrowserTestUtils.removeTab(viewSourceTab);
+});
diff --git a/parser/htmlparser/tests/mochitest/bug_502091_iframe.html b/parser/htmlparser/tests/mochitest/bug_502091_iframe.html
new file mode 100644
index 0000000000..076d3ed662
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/bug_502091_iframe.html
@@ -0,0 +1,17 @@
+<html>
+<head>
+<title>Crash [@ nsContentSink::ProcessHeaderData] with meta in innerHTML</title>
+</head>
+<body>
+<div id="testdiv">
+ testdiv
+ </div>
+<script>
+var x = document.createElement("div");
+x.innerHTML = '<meta http-equiv="Content-Type" content="text/html;"></meta>';
+document.getElementById("testdiv").appendChild(x);
+</script>
+some text here
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/dir_bug534293/file_bug534293.sjs b/parser/htmlparser/tests/mochitest/dir_bug534293/file_bug534293.sjs
new file mode 100644
index 0000000000..ec3d3c80d8
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/dir_bug534293/file_bug534293.sjs
@@ -0,0 +1,14 @@
+function handleRequest(request, response)
+{
+ response.setHeader("Content-Type", "text/javascript", false);
+ if (request.queryString.indexOf("report") != -1) {
+ if (getState("loaded") == "loaded") {
+ response.write("ok(true, 'This script was supposed to get fetched.');");
+ } else {
+ response.write("ok(false, 'This script was supposed to get fetched.');");
+ }
+ } else {
+ setState("loaded", "loaded");
+ response.write("ok(true, 'This script is supposed to run.');");
+ }
+}
diff --git a/parser/htmlparser/tests/mochitest/file_async_bug1104732.sjs b/parser/htmlparser/tests/mochitest/file_async_bug1104732.sjs
new file mode 100644
index 0000000000..b2ea43fdda
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_async_bug1104732.sjs
@@ -0,0 +1,14 @@
+var timer = null;
+
+function handleRequest(request, response)
+{
+ response.processAsync();
+ response.setHeader("Content-Type", "application/javascript", false);
+ response.write("asyncState = 'mid-async';\n");
+
+ timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.write("asyncState = 'loaded';\n");
+ response.finish();
+ }, 5 * 1000 /* milliseconds */, timer.TYPE_ONE_SHOT);
+}
diff --git a/parser/htmlparser/tests/mochitest/file_bug102699.sjs b/parser/htmlparser/tests/mochitest/file_bug102699.sjs
new file mode 100644
index 0000000000..8f4075ae7c
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug102699.sjs
@@ -0,0 +1,15 @@
+function handleRequest(request, response)
+{
+ response.setHeader("Content-Type", "text/javascript", false);
+ if (request.queryString.indexOf("report") != -1) {
+ if (getState("loaded") == "loaded") {
+ response.write("ok(false, 'This script was not supposed to get fetched.'); continueAfterReport();");
+ } else {
+ response.write("ok(true, 'This script was not supposed to get fetched.'); continueAfterReport();");
+ }
+ } else {
+ setState("loaded", "loaded");
+ response.write('document.documentElement.setAttribute("data-fail", "FAIL");');
+ }
+}
+
diff --git a/parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs b/parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs
new file mode 100644
index 0000000000..ec456f3ebd
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs
@@ -0,0 +1,14 @@
+var timer;
+
+function handleRequest(request, response)
+{
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/javascript", false);
+ response.write("ok(true, 'Slow script ran.');");
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.finish();
+ }, 500, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
diff --git a/parser/htmlparser/tests/mochitest/file_bug534293.sjs b/parser/htmlparser/tests/mochitest/file_bug534293.sjs
new file mode 100644
index 0000000000..02b1a1ede8
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug534293.sjs
@@ -0,0 +1,14 @@
+function handleRequest(request, response)
+{
+ response.setHeader("Content-Type", "text/javascript", false);
+ if (request.queryString.indexOf("report") != -1) {
+ if (getState("loaded") == "loaded") {
+ response.write("ok(false, 'This script was not supposed to get fetched.');");
+ } else {
+ response.write("ok(true, 'This script was not supposed to get fetched.');");
+ }
+ } else {
+ setState("loaded", "loaded");
+ response.write("ok(false, 'This script is not supposed to run.');");
+ }
+}
diff --git a/parser/htmlparser/tests/mochitest/file_bug543062.sjs b/parser/htmlparser/tests/mochitest/file_bug543062.sjs
new file mode 100644
index 0000000000..cb693d2f54
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug543062.sjs
@@ -0,0 +1,32 @@
+var timer;
+
+function armTimer(response) {
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ if (getState("docwritepreloadssecond") == "second" && getState("docwritepreloadsthird") == "third") {
+ response.write("ok(true, 'Second and third scripts should have started loading while the first one is loading');");
+ response.finish();
+ } else {
+ armTimer(response);
+ }
+ }, 20, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
+
+function handleRequest(request, response)
+{
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/javascript", false);
+ if (request.queryString.indexOf("first") != -1) {
+ response.write("// first\n");
+ response.processAsync();
+ armTimer(response);
+ } else if (request.queryString.indexOf("second") != -1) {
+ response.write("// second\n");
+ setState("docwritepreloadssecond", "second");
+ } else {
+ response.write("// third\n");
+ setState("docwritepreloadsthird", "third");
+ }
+}
+
diff --git a/parser/htmlparser/tests/mochitest/file_bug568470-script.sjs b/parser/htmlparser/tests/mochitest/file_bug568470-script.sjs
new file mode 100644
index 0000000000..f9150a0948
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug568470-script.sjs
@@ -0,0 +1,16 @@
+var timer = null; // Declare outside to prevent premature GC
+
+function handleRequest(request, response)
+{
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/javascript", false);
+ response.write("var i = 0;");
+ response.bodyOutputStream.flush();
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.finish();
+ }, 500, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
+
diff --git a/parser/htmlparser/tests/mochitest/file_bug568470.sjs b/parser/htmlparser/tests/mochitest/file_bug568470.sjs
new file mode 100644
index 0000000000..ddc3d0141c
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug568470.sjs
@@ -0,0 +1,21 @@
+var timer; // Place timer in global scope to avoid it getting GC'ed prematurely
+
+function handleRequest(request, response)
+{
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("<script src='file_bug568470-script.sjs'></script>");
+ response.write("<div id='flushable'>");
+ for (var i = 0; i < 2000; i++) {
+ response.write("Lorem ipsum dolor sit amet. ");
+ }
+ response.write("</div>");
+ response.bodyOutputStream.flush();
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.finish();
+ }, 1200, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
+
diff --git a/parser/htmlparser/tests/mochitest/file_bug594730-1.html b/parser/htmlparser/tests/mochitest/file_bug594730-1.html
new file mode 100644
index 0000000000..8877311e21
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug594730-1.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta charset="Windows-1250">
+<script>parent.is("", "\u0159", "Decoded bytes should have matched the Unicode escape.");</script>
diff --git a/parser/htmlparser/tests/mochitest/file_bug594730-2.html b/parser/htmlparser/tests/mochitest/file_bug594730-2.html
new file mode 100644
index 0000000000..f609df3976
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug594730-2.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta http-equiv="content-TYPE" content="text/html; charset=Windows-1250">
+<script>parent.is("", "\u0159", "Decoded bytes should have matched the Unicode escape.");</script>
diff --git a/parser/htmlparser/tests/mochitest/file_bug594730-3.html b/parser/htmlparser/tests/mochitest/file_bug594730-3.html
new file mode 100644
index 0000000000..d6470d80fc
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug594730-3.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta content="text/html; charset=Windows-1250" http-equiv="content-TYPE">
+<script>parent.is("", "\u0159", "Decoded bytes should have matched the Unicode escape.");</script>
diff --git a/parser/htmlparser/tests/mochitest/file_bug594730-4.html b/parser/htmlparser/tests/mochitest/file_bug594730-4.html
new file mode 100644
index 0000000000..bdce353a59
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug594730-4.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta content="text/html; charset=Windows-1250">
+<script>parent.isnot("", "\u0159", "Decoded bytes should not have matched the Unicode escape.");</script>
diff --git a/parser/htmlparser/tests/mochitest/file_bug594730-5.html b/parser/htmlparser/tests/mochitest/file_bug594730-5.html
new file mode 100644
index 0000000000..9fdbdded5c
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug594730-5.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta charset="Windows-1250" content="text/html; charset=Windows-1252">
+<script>parent.is("", "\u0159", "Decoded bytes should have matched the Unicode escape.");</script>
diff --git a/parser/htmlparser/tests/mochitest/file_bug594730-6.html b/parser/htmlparser/tests/mochitest/file_bug594730-6.html
new file mode 100644
index 0000000000..570fa460bc
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug594730-6.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta charset="Windows-1250" http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+<script>parent.is("", "\u0159", "Decoded bytes should have matched the Unicode escape.");</script>
diff --git a/parser/htmlparser/tests/mochitest/file_bug594730-7.html b/parser/htmlparser/tests/mochitest/file_bug594730-7.html
new file mode 100644
index 0000000000..92c19c8ffa
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug594730-7.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta content="text/html; charset=Windows-1250" http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+<script>parent.is("", "\u0159", "Decoded bytes should have matched the Unicode escape.");</script>
diff --git a/parser/htmlparser/tests/mochitest/file_bug594730-8.html b/parser/htmlparser/tests/mochitest/file_bug594730-8.html
new file mode 100644
index 0000000000..a9e7525c2c
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug594730-8.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta charset="Windows-1250" charset="Windows-1252">
+<script>parent.is("", "\u0159", "Decoded bytes should have matched the Unicode escape.");</script>
diff --git a/parser/htmlparser/tests/mochitest/file_bug594730-9.html b/parser/htmlparser/tests/mochitest/file_bug594730-9.html
new file mode 100644
index 0000000000..60fab3a399
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug594730-9.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="
+ Windows-1250
+ ">
+<script>parent.is("", "\u0159", "Decoded bytes should have matched the Unicode escape.");</script>
diff --git a/parser/htmlparser/tests/mochitest/file_bug642908.sjs b/parser/htmlparser/tests/mochitest/file_bug642908.sjs
new file mode 100644
index 0000000000..73ba20288d
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug642908.sjs
@@ -0,0 +1,16 @@
+function handleRequest(request, response)
+{
+ if (request.queryString.indexOf("report") != -1) {
+ response.setHeader("Content-Type", "text/javascript", false);
+ if (getState("loaded") == "loaded") {
+ response.write("ok(false, 'There was an attempt to preload the image.');");
+ } else {
+ response.write("ok(true, 'There was no attempt to preload the image.');");
+ }
+ response.write("SimpleTest.finish();");
+ } else {
+ setState("loaded", "loaded");
+ response.setHeader("Content-Type", "image/svg", false);
+ response.write("<svg xmlns='http://www.w3.org/2000/svg'>Not supposed to load this</svg>");
+ }
+}
diff --git a/parser/htmlparser/tests/mochitest/file_bug655682.sjs b/parser/htmlparser/tests/mochitest/file_bug655682.sjs
new file mode 100644
index 0000000000..2b5316b2d1
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug655682.sjs
@@ -0,0 +1,37 @@
+var timer;
+var callback;
+
+function handleRequest(request, response)
+{
+ if (request.queryString.indexOf("trigger") != -1) {
+ setState("triggered", "triggered");
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/javascript; charset=utf-8", false);
+ response.write(";");
+ } else {
+ // Reset the state when running more than once in same browser session.
+ setState("triggered", "");
+
+ response.processAsync();
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html; charset=utf-8", false);
+ response.write("<table><tr><td>A</td> ");
+ response.bodyOutputStream.flush();
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+
+ callback = function() {
+ if (getState("triggered") == "triggered") {
+ response.write("<td>B</td></tr></table>");
+ response.finish();
+ } else {
+ timer.initWithCallback(callback,
+ 10,
+ Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+ }
+ }
+ timer.initWithCallback(callback,
+ 10,
+ Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+ }
+}
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_bomless_utf16.html b/parser/htmlparser/tests/mochitest/file_bug672453_bomless_utf16.html
new file mode 100644
index 0000000000..104d503998
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_bomless_utf16.html
Binary files differ
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html b/parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html
new file mode 100644
index 0000000000..0e76edd65b
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html
@@ -0,0 +1 @@
+<!DOCTYPE html>
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html^headers^ b/parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html^headers^
new file mode 100644
index 0000000000..35885d0cc1
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html^headers^
@@ -0,0 +1,2 @@
+HTTP 200 OK
+Content-Type: text/html; charset=bogus
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_late_meta.html b/parser/htmlparser/tests/mochitest/file_bug672453_late_meta.html
new file mode 100644
index 0000000000..1e0b5870f7
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_late_meta.html
@@ -0,0 +1,1028 @@
+<!DOCTYPE html>
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+<meta charset="UTF-8">
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_meta_non_superset.html b/parser/htmlparser/tests/mochitest/file_bug672453_meta_non_superset.html
new file mode 100644
index 0000000000..dab8635286
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_meta_non_superset.html
@@ -0,0 +1 @@
+<meta charset="x-imap4-modified-utf7">
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_meta_restart.html b/parser/htmlparser/tests/mochitest/file_bug672453_meta_restart.html
new file mode 100644
index 0000000000..84bd1d3641
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_meta_restart.html
@@ -0,0 +1,1028 @@
+<!DOCTYPE html>
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+<meta charset="ISO-8859-2">
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_meta_unsupported.html b/parser/htmlparser/tests/mochitest/file_bug672453_meta_unsupported.html
new file mode 100644
index 0000000000..91111d7e74
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_meta_unsupported.html
@@ -0,0 +1 @@
+<meta charset="bogus">
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_meta_userdefined.html b/parser/htmlparser/tests/mochitest/file_bug672453_meta_userdefined.html
new file mode 100644
index 0000000000..250f6fa67c
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_meta_userdefined.html
@@ -0,0 +1 @@
+<meta charset="x-user-defined">
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_meta_utf16.html b/parser/htmlparser/tests/mochitest/file_bug672453_meta_utf16.html
new file mode 100644
index 0000000000..2e6fb9c8b7
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_meta_utf16.html
@@ -0,0 +1 @@
+<meta charset="UTF-16">
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_not_declared.html b/parser/htmlparser/tests/mochitest/file_bug672453_not_declared.html
new file mode 100644
index 0000000000..0e76edd65b
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_not_declared.html
@@ -0,0 +1 @@
+<!DOCTYPE html>
diff --git a/parser/htmlparser/tests/mochitest/file_bug688580.js b/parser/htmlparser/tests/mochitest/file_bug688580.js
new file mode 100644
index 0000000000..bee04dde23
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug688580.js
@@ -0,0 +1,8 @@
+/* globals state:true */
+is(
+ document.readyState,
+ "interactive",
+ "readyState should be interactive during defer."
+);
+is(state, "readyState interactive", "Bad state upon defer");
+state = "defer";
diff --git a/parser/htmlparser/tests/mochitest/file_bug716579-16.html b/parser/htmlparser/tests/mochitest/file_bug716579-16.html
new file mode 100644
index 0000000000..1cd07ca9a5
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug716579-16.html
Binary files differ
diff --git a/parser/htmlparser/tests/mochitest/file_bug716579-16.html^headers^ b/parser/htmlparser/tests/mochitest/file_bug716579-16.html^headers^
new file mode 100644
index 0000000000..3fadd3bad3
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug716579-16.html^headers^
@@ -0,0 +1 @@
+Content-Type: text/html; charset=windows-874
diff --git a/parser/htmlparser/tests/mochitest/file_bug716579-16.xhtml b/parser/htmlparser/tests/mochitest/file_bug716579-16.xhtml
new file mode 100644
index 0000000000..cc828a7ce7
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug716579-16.xhtml
Binary files differ
diff --git a/parser/htmlparser/tests/mochitest/file_bug716579-16.xhtml^headers^ b/parser/htmlparser/tests/mochitest/file_bug716579-16.xhtml^headers^
new file mode 100644
index 0000000000..208b923e8f
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug716579-16.xhtml^headers^
@@ -0,0 +1 @@
+Content-Type: application/xhtml+xml; charset=windows-874
diff --git a/parser/htmlparser/tests/mochitest/file_bug716579-8.html b/parser/htmlparser/tests/mochitest/file_bug716579-8.html
new file mode 100644
index 0000000000..bbeb036db1
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug716579-8.html
@@ -0,0 +1,3 @@
+<script>
+parent.html8 = "€";
+</script>
diff --git a/parser/htmlparser/tests/mochitest/file_bug716579-8.html^headers^ b/parser/htmlparser/tests/mochitest/file_bug716579-8.html^headers^
new file mode 100644
index 0000000000..3fadd3bad3
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug716579-8.html^headers^
@@ -0,0 +1 @@
+Content-Type: text/html; charset=windows-874
diff --git a/parser/htmlparser/tests/mochitest/file_bug716579-8.xhtml b/parser/htmlparser/tests/mochitest/file_bug716579-8.xhtml
new file mode 100644
index 0000000000..a1221cafc7
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug716579-8.xhtml
@@ -0,0 +1,7 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+<script>
+parent.xml8 = "€";
+</script>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/file_bug716579-8.xhtml^headers^ b/parser/htmlparser/tests/mochitest/file_bug716579-8.xhtml^headers^
new file mode 100644
index 0000000000..208b923e8f
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug716579-8.xhtml^headers^
@@ -0,0 +1 @@
+Content-Type: application/xhtml+xml; charset=windows-874
diff --git a/parser/htmlparser/tests/mochitest/file_bug717180.html b/parser/htmlparser/tests/mochitest/file_bug717180.html
new file mode 100644
index 0000000000..ff43ca4091
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug717180.html
@@ -0,0 +1 @@
+SUCCESS
diff --git a/parser/htmlparser/tests/mochitest/file_defer_bug1104732.js b/parser/htmlparser/tests/mochitest/file_defer_bug1104732.js
new file mode 100644
index 0000000000..5ba15f287b
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_defer_bug1104732.js
@@ -0,0 +1,7 @@
+/* globals state:true */
+is(
+ document.readyState,
+ "interactive",
+ "readyState should be interactive during defer."
+);
+state = "defer";
diff --git a/parser/htmlparser/tests/mochitest/file_img_picture_preload.html b/parser/htmlparser/tests/mochitest/file_img_picture_preload.html
new file mode 100644
index 0000000000..a5a55a56a3
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_img_picture_preload.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html>
+<!--
+ Helper for test_img_picture_preload.htm. Can be merged in to the test file
+ when dom.image.{picture,srcset} are removed and we don't need to do pref
+ flipping before the load.
+
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1067345
+-->
+<head>
+ <title>Test for Bug 1067345</title>
+</head>
+<body onload="afterLoad();">
+ <script type="text/javascript">
+ var is = window.parent.is;
+ var ok = window.parent.ok;
+ var SimpleTest = window.parent.SimpleTest;
+ // Called with number of requests made
+ var notifyTestFinished = window.parent.childTestFinished;
+ var currentDPI = window.parent.currentDPI;
+
+ // This script is intentionally blocking the images below from
+ // loading. It issues sync XHRs to the sjs to wait for the files
+ // to be requested before unblocking DOM creation, then asserts
+ // that the same sources were selected by the preloader and the
+ // real DOM.
+
+ // Number of images to wait for before unblocking load
+ const EXPECTED_PRELOADS = 11;
+
+ function busyWait(waitms) {
+ var start = Date.now();
+ while (Date.now() < start + waitms);
+ }
+
+ // Send sync XHRs asking the sjs what images it's seen until we
+ // see EXPECTED_PRELOADS images. (If this test is timing out, you broke
+ // the preloader)
+ var preloadedImages = [];
+ while (preloadedImages.length < EXPECTED_PRELOADS) {
+ var request = new XMLHttpRequest();
+ request.open("GET", "./file_img_picture_preload.sjs?status", false);
+ request.send(null);
+ is(request.status, 200, "Getting status from sjs helper should succeed");
+ if (request.status === 200) {
+ preloadedImages = JSON.parse(request.responseText);
+ }
+ }
+
+ // Ensure the DOM is still blocked on us before proceeding
+ is(document.querySelector("img"), null, "No <img> elements should exist yet");
+ </script>
+
+ <!-- All images below will be checked, use sources of the format
+ ./file_img_picture_preload.sjs?imgName:sourceName
+ Update numImages when adding or removing images below -->
+
+ <!-- Basic src -->
+ <img id="img1"
+ src="./file_img_picture_preload.sjs?img1:source1">
+ <!-- Basic srcset, no src -->
+ <img id="img2"
+ srcset="./file_img_picture_preload.sjs?img2:source1, ./file_img_picture_preload.sjs?img2:source2 2x, ./file_img_picture_preload.sjs?img2:source3 0.5x">
+ <!-- srcset + src, srcset should shadow entirley -->
+ <img id="img3"
+ srcset="./file_img_picture_preload.sjs?img3:source1, ./file_img_picture_preload.sjs?img3:source2 2x, ./file_img_picture_preload.sjs?img3:source3 0.5x">
+ <!-- Ditto with sizes selector -->
+ <img id="img4"
+ sizes="50vw"
+ srcset="./file_img_picture_preload.sjs?img4:source1 500w, ./file_img_picture_preload.sjs?img4:source2 200w, ./file_img_picture_preload.sjs?img4:source3 5w">
+ <!-- Default source shouldn't be selected -->
+ <img id="img5"
+ srcset="./file_img_picture_preload.sjs?img5:source1, ./file_img_picture_preload.sjs?img5:source2 2x"
+ src="./file_img_picture_preload.sjs?img5:source3">
+ <!-- Default source should be the 1x source, but srcset for others -->
+ <img id="img6"
+ srcset="./file_img_picture_preload.sjs?img6:source1 0.5x, ./file_img_picture_preload.sjs?img6:source2 2x"
+ src="./file_img_picture_preload.sjs?img6:source3">
+
+ <!-- Ensure we skip various invalid sources -->
+ <picture>
+ <source type="image/png">
+ <source type="image/png" srcset="">
+ <source media="(min-width: 1px)">
+ <source media="(min-width: 1px)" srcset=" ">
+ <source type="invalid/x-bogus-type" srcset="./file_img_picture_preload.sjs?img7:source1">
+ <source media="(unknown-query-value-thing: 1000something)" srcset="./file_img_picture_preload.sjs?img7:source2">
+ <source media="(unknown-query-value-thing: 1000something)" srcset="bogus ./file_img_picture_preload.sjs?img7:source3 ./file_img_picture_preload.sjs?img7:source4">
+ <img id="img7" src="./file_img_picture_preload.sjs?img7:source5">
+ </picture>
+
+ <!-- Should select matching sources with known type, and shouldn't select later sources that have closer densities-->
+ <picture>
+ <source type="invalid/x-unsupported-image-type" srcset="./file_img_picture_preload.sjs?img8:source1">
+ <source type="image/png" srcset="./file_img_picture_preload.sjs?img8:source2 2x">
+ <source type="image/png" srcset="./file_img_picture_preload.sjs?img8:source3 1x">
+ <img id="img8" src="./file_img_picture_preload.sjs?img8:source4" srcset="./file_img_picture_preload.sjs?img8:source5 2x">
+ </picture>
+
+ <!-- Should select matching sources by media, and shouldn't select later sources that have closer densities -->
+ <picture>
+ <source media="(bogusxx)" srcset="./file_img_picture_preload.sjs?img9:source1">
+ <source media="(minimum-width: 1px)" srcset="./file_img_picture_preload.sjs?img9:source2 2x">
+ <source media="(max-resolution: 0.5dppx)" srcset="./file_img_picture_preload.sjs?img9:source3 1x">
+ <source media="(min-resolution: 2dppx)" srcset="./file_img_picture_preload.sjs?img9:source4 1x">
+ <source media="(min-resolution: 1dppx)" srcset="./file_img_picture_preload.sjs?img9:source5 1x">
+ <source media="(min-resolution: 1dppx)" srcset="./file_img_picture_preload.sjs?img9:source6 2x">
+ <img id="img9" src="./file_img_picture_preload.sjs?img9:source7" srcset="./file_img_picture_preload.sjs?img9:source8 2x">
+ </picture>
+
+ <!-- Make sure we consider sizes properly in sources -->
+ <picture>
+ <source type="image/png"
+ sizes="10px"
+ srcset="./file_img_picture_preload.sjs?img10:source1 10w, ./file_img_picture_preload.sjs?img10:source2 20w">
+ <img id="img10" src="./file_img_picture_preload.sjs?img10:source3">
+ </picture>
+
+ <!-- Make sure we consider sizes properly -->
+ <img id="img11" sizes="10px"
+ srcset="./file_img_picture_preload.sjs?img11:source1 10w, ./file_img_picture_preload.sjs?img11:source2 20w"
+ src="./file_img_picture_preload.sjs?img11:source3">
+
+ <script type="text/javascript">
+ function afterLoad() {
+ // All images should have picked a source of the format
+ // imgName:sourceName, ensure we have one source per image and
+ // that it was preloaded.
+
+ is(preloadedImages.length, EXPECTED_PRELOADS,
+ "Should have exactly " + EXPECTED_PRELOADS + " preloaded URLs");
+
+ // Split "imgName:source" sources we saw preload by img name
+ var preloadByName = {};
+ for (var preload of preloadedImages) {
+ var split = preload.split(":");
+ // Ensure we didn't preload two sources for the same image
+ ok(preloadByName[split[0]] === undefined,
+ "Should not have queried multiple sources for " + split[0] +
+ " (got " + split[1] + ", already had " + preloadByName[split[0]] + ")");
+ preloadByName[split[0]] = split[1];
+ }
+
+ // Check all images, ensure each one had a preload
+ var images = document.querySelectorAll("img");
+ for (var img of images) {
+ var imgName = img.id;
+ if (img.currentSrc) {
+ split = img.currentSrc.split("?")[1].split(":");
+ is(split[0], imgName,
+ "image " + imgName + " source matches element id");
+ is(split[1], preloadByName[imgName],
+ "image " + imgName + " source should match preloaded source");
+ // Remove from array
+ delete preloadByName[imgName];
+ } else {
+ // img loaded nothing
+ is(preloadByName[imgName], null,
+ "Should not have preloaded anything for image " + imgName);
+ }
+ }
+
+ notifyTestFinished(preloadedImages.length);
+ }
+ </script>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/file_img_picture_preload.sjs b/parser/htmlparser/tests/mochitest/file_img_picture_preload.sjs
new file mode 100644
index 0000000000..e4a3ba7807
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_img_picture_preload.sjs
@@ -0,0 +1,28 @@
+// Return a PNG, saving an array of query strings we see as state. When query
+// string is 'status', return array as JSON
+
+function handleRequest(request, response)
+{
+ var seenImages = getState("seenImages");
+ seenImages = seenImages ? JSON.parse(seenImages) : [];
+
+ response.setHeader("Cache-Control", "must-revalidate", false);
+
+ if (request.queryString == "status") {
+ response.setHeader("Content-Type", "text/javascript", false);
+ response.write(JSON.stringify(seenImages));
+ } else if (request.queryString == "reset") {
+ // Respond with how many requests we had seen, drop them
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write(String(seenImages.length));
+ seenImages = [];
+ } else {
+ // Return an image
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", "blue.png", false);
+ dump(request.queryString + '\n');
+ seenImages.push(request.queryString);
+ }
+
+ setState("seenImages", JSON.stringify(seenImages));
+}
diff --git a/parser/htmlparser/tests/mochitest/file_viewsource.html b/parser/htmlparser/tests/mochitest/file_viewsource.html
new file mode 100644
index 0000000000..3ed00150a7
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_viewsource.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Test for view source</title>
+ </head>
+
+ <body>
+
+<!--
+ this is a multi-line comment
+-->
+
+ <script class="testbody" type="text/javascript">
+ // This is a script comment / text.
+ </script>
+
+ </body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/html5_tree_construction_exceptions.js b/parser/htmlparser/tests/mochitest/html5_tree_construction_exceptions.js
new file mode 100644
index 0000000000..fed7e353e2
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5_tree_construction_exceptions.js
@@ -0,0 +1,11 @@
+/*
+ * These are the tests we don't pass. The test data comes from the .dat
+ * files under html5lib_tree_construction/. Please see
+ * html5lib_tree_construction/html5lib_license.txt for the license for these
+ * tests.
+ */
+var html5Exceptions = {
+ "<select><keygen>": true, // Bug 101019
+ "<p><table></p>": true, // parser_web_testrunner.js uses srcdoc which forces quirks mode
+ "<p><table></table>": true, // parser_web_testrunner.js uses srcdoc which forces quirks mode
+};
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/README.md b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/README.md
new file mode 100644
index 0000000000..be41fa44f8
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/README.md
@@ -0,0 +1,104 @@
+Tree Construction Tests
+=======================
+
+Each file containing tree construction tests consists of any number of
+tests separated by two newlines (LF) and a single newline before the end
+of the file. For instance:
+
+ [TEST]LF
+ LF
+ [TEST]LF
+ LF
+ [TEST]LF
+
+Where [TEST] is the following format:
+
+Each test must begin with a string "\#data" followed by a newline (LF).
+All subsequent lines until a line that says "\#errors" are the test data
+and must be passed to the system being tested unchanged, except with the
+final newline (on the last line) removed.
+
+Then there must be a line that says "\#errors". It must be followed by
+one line per parse error that a conformant checker would return. It
+doesn't matter what those lines are, although they can't be
+"\#document-fragment", "\#document", "\#script-off", "\#script-on", or
+empty, the only thing that matters is that there be the right number
+of parse errors.
+
+Then there \*may\* be a line that says "\#document-fragment", which must
+be followed by a newline (LF), followed by a string of characters that
+indicates the context element, followed by a newline (LF). If the string
+of characters starts with "svg ", the context element is in the SVG
+namespace and the substring after "svg " is the local name. If the
+string of characters starts with "math ", the context element is in the
+MathML namespace and the substring after "math " is the local name.
+Otherwise, the context element is in the HTML namespace and the string
+is the local name. If this line is present the "\#data" must be parsed
+using the HTML fragment parsing algorithm with the context element as
+context.
+
+Then there \*may\* be a line that says "\#script-off" or
+"\#script-in". If a line that says "\#script-off" is present, the
+parser must set the scripting flag to disabled. If a line that says
+"\#script-on" is present, it must set it to enabled. Otherwise, the
+test should be run in both modes.
+
+Then there must be a line that says "\#document", which must be followed
+by a dump of the tree of the parsed DOM. Each node must be represented
+by a single line. Each line must start with "| ", followed by two spaces
+per parent node that the node has before the root document node.
+
+- Element nodes must be represented by a "`<`" then the *tag name
+ string* "`>`", and all the attributes must be given, sorted
+ lexicographically by UTF-16 code unit according to their *attribute
+ name string*, on subsequent lines, as if they were children of the
+ element node.
+- Attribute nodes must have the *attribute name string*, then an "="
+ sign, then the attribute value in double quotes (").
+- Text nodes must be the string, in double quotes. Newlines aren't
+ escaped.
+- Comments must be "`<`" then "`!-- `" then the data then "` -->`".
+- DOCTYPEs must be "`<!DOCTYPE `" then the name then if either of the
+ system id or public id is non-empty a space, public id in
+ double-quotes, another space an the system id in double-quotes, and
+ then in any case "`>`".
+- Processing instructions must be "`<?`", then the target, then a
+ space, then the data and then "`>`". (The HTML parser cannot emit
+ processing instructions, but scripts can, and the WebVTT to DOM
+ rules can emit them.)
+- Template contents are represented by the string "content" with the
+ children below it.
+
+The *tag name string* is the local name prefixed by a namespace
+designator. For the HTML namespace, the namespace designator is the
+empty string, i.e. there's no prefix. For the SVG namespace, the
+namespace designator is "svg ". For the MathML namespace, the namespace
+designator is "math ".
+
+The *attribute name string* is the local name prefixed by a namespace
+designator. For no namespace, the namespace designator is the empty
+string, i.e. there's no prefix. For the XLink namespace, the namespace
+designator is "xlink ". For the XML namespace, the namespace designator
+is "xml ". For the XMLNS namespace, the namespace designator is "xmlns
+". Note the difference between "xlink:href" which is an attribute in no
+namespace with the local name "xlink:href" and "xlink href" which is an
+attribute in the xlink namespace with the local name "href".
+
+If there is also a "\#document-fragment" the bit following "\#document"
+must be a representation of the HTML fragment serialization for the
+context element given by "\#document-fragment".
+
+For example:
+
+ #data
+ <p>One<p>Two
+ #errors
+ 3: Missing document type declaration
+ #document
+ | <html>
+ | <head>
+ | <body>
+ | <p>
+ | "One"
+ | <p>
+ | "Two"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/adoption01.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/adoption01.dat
new file mode 100644
index 0000000000..2e1127e517
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/adoption01.dat
@@ -0,0 +1,337 @@
+#data
+<a><p></a></p>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,10): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <p>
+| <a>
+
+#data
+<a>1<p>2</a>3</p>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,12): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <p>
+| <a>
+| "2"
+| "3"
+
+#data
+<a>1<button>2</a>3</button>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,17): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <button>
+| <a>
+| "2"
+| "3"
+
+#data
+<a>1<b>2</a>3</b>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,12): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <b>
+| "2"
+| <b>
+| "3"
+
+#data
+<a>1<div>2<div>3</a>4</div>5</div>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,20): adoption-agency-1.3
+(1,20): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <div>
+| <a>
+| "2"
+| <div>
+| <a>
+| "3"
+| "4"
+| "5"
+
+#data
+<table><a>1<p>2</a>3</p>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,10): unexpected-start-tag-implies-table-voodoo
+(1,11): unexpected-character-implies-table-voodoo
+(1,14): unexpected-start-tag-implies-table-voodoo
+(1,15): unexpected-character-implies-table-voodoo
+(1,19): unexpected-end-tag-implies-table-voodoo
+(1,19): adoption-agency-1.3
+(1,20): unexpected-character-implies-table-voodoo
+(1,24): unexpected-end-tag-implies-table-voodoo
+(1,24): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <p>
+| <a>
+| "2"
+| "3"
+| <table>
+
+#data
+<b><b><a><p></a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,16): adoption-agency-1.3
+(1,16): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <b>
+| <a>
+| <p>
+| <a>
+
+#data
+<b><a><b><p></a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,16): adoption-agency-1.3
+(1,16): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <a>
+| <b>
+| <b>
+| <p>
+| <a>
+
+#data
+<a><b><b><p></a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,16): adoption-agency-1.3
+(1,16): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <b>
+| <b>
+| <p>
+| <a>
+
+#data
+<p>1<s id="A">2<b id="B">3</p>4</s>5</b>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,30): unexpected-end-tag
+(1,35): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| "1"
+| <s>
+| id="A"
+| "2"
+| <b>
+| id="B"
+| "3"
+| <s>
+| id="A"
+| <b>
+| id="B"
+| "4"
+| <b>
+| id="B"
+| "5"
+
+#data
+<table><a>1<td>2</td>3</table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,10): unexpected-start-tag-implies-table-voodoo
+(1,11): unexpected-character-implies-table-voodoo
+(1,15): unexpected-cell-in-table-body
+(1,30): unexpected-implied-end-tag-in-table-view
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "1"
+| <a>
+| "3"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "2"
+
+#data
+<table>A<td>B</td>C</table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,8): unexpected-character-implies-table-voodoo
+(1,12): unexpected-cell-in-table-body
+(1,22): unexpected-character-implies-table-voodoo
+#document
+| <html>
+| <head>
+| <body>
+| "AC"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "B"
+
+#data
+<a><svg><tr><input></a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,23): unexpected-end-tag
+(1,23): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <svg svg>
+| <svg tr>
+| <svg input>
+
+#data
+<div><a><b><div><div><div><div><div><div><div><div><div><div></a>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,65): adoption-agency-1.3
+(1,65): adoption-agency-1.3
+(1,65): adoption-agency-1.3
+(1,65): adoption-agency-1.3
+(1,65): adoption-agency-1.3
+(1,65): adoption-agency-1.3
+(1,65): adoption-agency-1.3
+(1,65): adoption-agency-1.3
+(1,65): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <a>
+| <b>
+| <b>
+| <div>
+| <a>
+| <div>
+| <a>
+| <div>
+| <a>
+| <div>
+| <a>
+| <div>
+| <a>
+| <div>
+| <a>
+| <div>
+| <a>
+| <div>
+| <a>
+| <div>
+| <div>
+
+#data
+<div><a><b><u><i><code><div></a>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,32): adoption-agency-1.3
+(1,32): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <a>
+| <b>
+| <u>
+| <i>
+| <code>
+| <u>
+| <i>
+| <code>
+| <div>
+| <a>
+
+#data
+<b><b><b><b>x</b></b></b></b>y
+#errors
+(1,3): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <b>
+| <b>
+| <b>
+| "x"
+| "y"
+
+#data
+<p><b><b><b><b><p>x
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,18): unexpected-end-tag
+(1,19): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <b>
+| <b>
+| <b>
+| <p>
+| <b>
+| <b>
+| <b>
+| "x"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/adoption02.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/adoption02.dat
new file mode 100644
index 0000000000..0502cf3021
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/adoption02.dat
@@ -0,0 +1,99 @@
+#data
+<b>1<i>2<p>3</b>4
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,16): adoption-agency-1.3
+(1,17): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "1"
+| <i>
+| "2"
+| <i>
+| <p>
+| <b>
+| "3"
+| "4"
+
+#data
+<a><div><style></style><address><a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,35): unexpected-start-tag-implies-end-tag
+(1,35): adoption-agency-1.3
+(1,35): adoption-agency-1.3
+(1,35): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <div>
+| <a>
+| <style>
+| <address>
+| <a>
+| <a>
+
+#data
+<b><i><a><s><tt><div></b>first</b></div></tt></s></a>second</i>
+#errors
+3: Start tag seen without seeing a doctype first. Expected "<!DOCTYPE html>".
+25: End tag "b" violates nesting rules.
+34: Stray end tag "b".
+63: Stray end tag "i".
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <i>
+| <a>
+| <s>
+| <tt>
+| <a>
+| <s>
+| <tt>
+| <div>
+| <b>
+| "first"
+| "second"
+
+#data
+<code foo="bar"><code><code><code><code></code></code></code></code>text</code>
+#errors
+16: Start tag seen without seeing a doctype first. Expected "<!DOCTYPE html>".
+#document
+| <html>
+| <head>
+| <body>
+| <code>
+| foo="bar"
+| <code>
+| <code>
+| <code>
+| <code>
+| "text"
+
+#data
+<code foo="bar"><code><code><code><div><code></div></code></code></code></code>text</code>
+#errors
+16: Start tag seen without seeing a doctype first. Expected "<!DOCTYPE html>".
+51: End tag "div" seen, but there were open elements.
+45: Unclosed element "code".
+58: No "code" element in scope but a "code" end tag seen.
+#document
+| <html>
+| <head>
+| <body>
+| <code>
+| foo="bar"
+| <code>
+| <code>
+| <code>
+| <div>
+| <code>
+| "text"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/comments01.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/comments01.dat
new file mode 100644
index 0000000000..32021e15ca
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/comments01.dat
@@ -0,0 +1,206 @@
+#data
+FOO<!-- BAR -->BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -->
+| "BAZ"
+
+#data
+FOO<!-- BAR --!>BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,15): unexpected-bang-after-double-dash-in-comment
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -->
+| "BAZ"
+
+#data
+FOO<!-- BAR --! >BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+#new-errors
+(1:20) eof-in-comment
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR --! >BAZ -->
+
+#data
+FOO<!-- BAR --!
+>BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+#new-errors
+(1:20) eof-in-comment
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR --!
+>BAZ -->
+
+#data
+FOO<!-- BAR -- >BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,15): unexpected-char-in-comment
+(1,21): eof-in-comment
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- >BAZ -->
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -->BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,15): unexpected-char-in-comment
+(1,24): unexpected-char-in-comment
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX --!>BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,15): unexpected-char-in-comment
+(1,24): unexpected-char-in-comment
+(1,31): unexpected-bang-after-double-dash-in-comment
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -- >BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,15): unexpected-char-in-comment
+(1,24): unexpected-char-in-comment
+(1,31): unexpected-char-in-comment
+(1,35): eof-in-comment
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -- >BAZ -->
+
+#data
+FOO<!---->BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+FOO<!--->BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,9): incorrect-comment
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+FOO<!-->BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,8): incorrect-comment
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+<?xml version="1.0">Hi
+#errors
+(1,1): expected-tag-name-but-got-question-mark
+(1,22): expected-doctype-but-got-chars
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+| <head>
+| <body>
+| "Hi"
+
+#data
+<?xml version="1.0">
+#errors
+(1,1): expected-tag-name-but-got-question-mark
+(1,20): expected-doctype-but-got-eof
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?xml version
+#errors
+(1,1): expected-tag-name-but-got-question-mark
+(1,13): expected-doctype-but-got-eof
+#document
+| <!-- ?xml version -->
+| <html>
+| <head>
+| <body>
+
+#data
+FOO<!----->BAZ
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,10): unexpected-dash-after-double-dash-in-comment
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- - -->
+| "BAZ"
+
+#data
+<html><!-- comment --><title>Comment before head</title>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <!-- comment -->
+| <head>
+| <title>
+| "Comment before head"
+| <body>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/doctype01.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/doctype01.dat
new file mode 100644
index 0000000000..cec6638971
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/doctype01.dat
@@ -0,0 +1,424 @@
+#data
+<!DOCTYPE html>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!dOctYpE HtMl>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPEhtml>Hello
+#errors
+(1,9): need-space-after-doctype
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE>Hello
+#errors
+(1,9): need-space-after-doctype
+(1,10): expected-doctype-name-but-got-right-bracket
+(1,10): unknown-doctype
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE >Hello
+#errors
+(1,11): expected-doctype-name-but-got-right-bracket
+(1,11): unknown-doctype
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato>Hello
+#errors
+(1,17): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato >Hello
+#errors
+(1,18): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato taco>Hello
+#errors
+(1,17): expected-space-or-right-bracket-in-doctype
+(1,22): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato taco "ddd>Hello
+#errors
+(1,17): expected-space-or-right-bracket-in-doctype
+(1,27): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM>Hello
+#errors
+(1,24): unexpected-char-in-doctype
+(1,24): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM >Hello
+#errors
+(1,28): unexpected-char-in-doctype
+(1,28): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM ggg>Hello
+#errors
+(1,34): unexpected-char-in-doctype
+(1,37): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM taco >Hello
+#errors
+(1,25): unexpected-char-in-doctype
+(1,31): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM 'taco"'>Hello
+#errors
+(1,32): unknown-doctype
+#document
+| <!DOCTYPE potato "" "taco"">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "taco">Hello
+#errors
+(1,31): unknown-doctype
+#document
+| <!DOCTYPE potato "" "taco">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "tai'co">Hello
+#errors
+(1,33): unknown-doctype
+#document
+| <!DOCTYPE potato "" "tai'co">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEMtaco "ddd">Hello
+#errors
+(1,24): unexpected-char-in-doctype
+(1,34): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato grass SYSTEM taco>Hello
+#errors
+(1,17): expected-space-or-right-bracket-in-doctype
+(1,35): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc>Hello
+#errors
+(1,24): unexpected-end-of-doctype
+(1,24): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc >Hello
+#errors
+(1,25): unexpected-end-of-doctype
+(1,25): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIcgoof>Hello
+#errors
+(1,24): unexpected-char-in-doctype
+(1,28): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC goof>Hello
+#errors
+(1,25): unexpected-char-in-doctype
+(1,29): unknown-doctype
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "go'of">Hello
+#errors
+(1,32): unknown-doctype
+#document
+| <!DOCTYPE potato "go'of" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go'of'>Hello
+#errors
+(1,29): unexpected-char-in-doctype
+(1,32): unknown-doctype
+#document
+| <!DOCTYPE potato "go" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go:hh of' >Hello
+#errors
+(1,38): unknown-doctype
+#document
+| <!DOCTYPE potato "go:hh of" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "W3C-//dfdf" SYSTEM ggg>Hello
+#errors
+(1,38): unexpected-char-in-doctype
+(1,48): unknown-doctype
+#document
+| <!DOCTYPE potato "W3C-//dfdf" "">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">Hello
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE ...>Hello
+#errors
+(1,14): unknown-doctype
+#document
+| <!DOCTYPE ...>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+#errors
+(2,58): unknown-doctype
+#document
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+#errors
+(2,54): unknown-doctype
+#document
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] "uri" [
+<!-- internal declarations -->
+]>
+#errors
+(1,23): expected-space-or-right-bracket-in-doctype
+(2,30): unknown-doctype
+#document
+| <!DOCTYPE root-element>
+| <html>
+| <head>
+| <body>
+| "]>"
+
+#data
+<!DOCTYPE html PUBLIC
+ "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
+ "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+#errors
+(3,53): unknown-doctype
+#document
+| <!DOCTYPE html "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML SYSTEM "http://www.w3.org/DTD/HTML4-strict.dtd"><body><b>Mine!</b></body>
+#errors
+(1,63): unknown-doctype
+#document
+| <!DOCTYPE html "" "http://www.w3.org/DTD/HTML4-strict.dtd">
+| <html>
+| <head>
+| <body>
+| <b>
+| "Mine!"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
+#errors
+(1,50): unexpected-char-in-doctype
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+(1,50): unexpected-char-in-doctype
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+(1,21): unexpected-char-in-doctype
+(1,49): unexpected-char-in-doctype
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC'-//W3C//DTD HTML 4.01//EN''http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+(1,21): unexpected-char-in-doctype
+(1,49): unexpected-char-in-doctype
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/domjs-unsafe.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/domjs-unsafe.dat
new file mode 100644
index 0000000000..34b4e62716
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/domjs-unsafe.dat
Binary files differ
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/entities01.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/entities01.dat
new file mode 100644
index 0000000000..b271f8220f
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/entities01.dat
@@ -0,0 +1,792 @@
+#data
+FOO&gt;BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>BAR"
+
+#data
+FOO&gtBAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,6): named-entity-without-semicolon
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>BAR"
+
+#data
+FOO&gt BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,6): named-entity-without-semicolon
+#document
+| <html>
+| <head>
+| <body>
+| "FOO> BAR"
+
+#data
+FOO&gt;;;BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>;;BAR"
+
+#data
+I'm &notit; I tell you
+#errors
+(1,4): expected-doctype-but-got-chars
+(1,9): named-entity-without-semicolon
+#document
+| <html>
+| <head>
+| <body>
+| "I'm ¬it; I tell you"
+
+#data
+I'm &notin; I tell you
+#errors
+(1,4): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "I'm ∉ I tell you"
+
+#data
+FOO& BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO& BAR"
+
+#data
+FOO&<BAR>
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,9): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&"
+| <bar>
+
+#data
+FOO&&&&gt;BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&&&>BAR"
+
+#data
+FOO&#41;BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO)BAR"
+
+#data
+FOO&#x41;BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOOABAR"
+
+#data
+FOO&#X41;BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOOABAR"
+
+#data
+FOO&#BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,5): expected-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#BAR"
+
+#data
+FOO&#ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,5): expected-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#ZOO"
+
+#data
+FOO&#xBAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,7): expected-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOºR"
+
+#data
+FOO&#xZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,6): expected-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#xZOO"
+
+#data
+FOO&#XZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,6): expected-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#XZOO"
+
+#data
+FOO&#41BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,7): numeric-entity-without-semicolon
+#document
+| <html>
+| <head>
+| <body>
+| "FOO)BAR"
+
+#data
+FOO&#x41BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,10): numeric-entity-without-semicolon
+#document
+| <html>
+| <head>
+| <body>
+| "FOO䆺R"
+
+#data
+FOO&#x41ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,8): numeric-entity-without-semicolon
+#document
+| <html>
+| <head>
+| <body>
+| "FOOAZOO"
+
+#data
+FOO&#x0000;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#x0078;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOOxZOO"
+
+#data
+FOO&#x0079;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOOyZOO"
+
+#data
+FOO&#x0080;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO€ZOO"
+
+#data
+FOO&#x0081;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x0082;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‚ZOO"
+
+#data
+FOO&#x0083;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOƒZOO"
+
+#data
+FOO&#x0084;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO„ZOO"
+
+#data
+FOO&#x0085;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO…ZOO"
+
+#data
+FOO&#x0086;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO†ZOO"
+
+#data
+FOO&#x0087;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‡ZOO"
+
+#data
+FOO&#x0088;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOˆZOO"
+
+#data
+FOO&#x0089;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‰ZOO"
+
+#data
+FOO&#x008A;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŠZOO"
+
+#data
+FOO&#x008B;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‹ZOO"
+
+#data
+FOO&#x008C;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŒZOO"
+
+#data
+FOO&#x008D;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x008E;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŽZOO"
+
+#data
+FOO&#x008F;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x0090;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x0091;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‘ZOO"
+
+#data
+FOO&#x0092;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO’ZOO"
+
+#data
+FOO&#x0093;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO“ZOO"
+
+#data
+FOO&#x0094;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO”ZOO"
+
+#data
+FOO&#x0095;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO•ZOO"
+
+#data
+FOO&#x0096;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO–ZOO"
+
+#data
+FOO&#x0097;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO—ZOO"
+
+#data
+FOO&#x0098;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO˜ZOO"
+
+#data
+FOO&#x0099;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO™ZOO"
+
+#data
+FOO&#x009A;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOšZOO"
+
+#data
+FOO&#x009B;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO›ZOO"
+
+#data
+FOO&#x009C;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOœZOO"
+
+#data
+FOO&#x009D;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x009E;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOžZOO"
+
+#data
+FOO&#x009F;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŸZOO"
+
+#data
+FOO&#x00A0;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO ZOO"
+
+#data
+FOO&#xD7FF;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO퟿ZOO"
+
+#data
+FOO&#xD800;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xD801;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xDFFE;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xDFFF;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,11): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xE000;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x10FFFE;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,13): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO􏿾ZOO"
+
+#data
+FOO&#x1087D4;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO􈟔ZOO"
+
+#data
+FOO&#x10FFFF;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,13): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO􏿿ZOO"
+
+#data
+FOO&#x110000;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,13): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xFFFFFF;ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,13): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#11111111111
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,13): illegal-codepoint-for-numeric-entity
+(1,13): eof-in-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�"
+
+#data
+FOO&#1111111111
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,13): illegal-codepoint-for-numeric-entity
+(1,13): eof-in-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�"
+
+#data
+FOO&#111111111111
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,13): illegal-codepoint-for-numeric-entity
+(1,13): eof-in-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�"
+
+#data
+FOO&#11111111111ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,13): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#1111111111ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,13): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#111111111111ZOO
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,13): illegal-codepoint-for-numeric-entity
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/entities02.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/entities02.dat
new file mode 100644
index 0000000000..f117f068a0
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/entities02.dat
@@ -0,0 +1,283 @@
+#data
+<div bar="ZZ&gt;YY"></div>
+#errors
+(1,20): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>YY"
+
+#data
+<div bar="ZZ&"></div>
+#errors
+(1,15): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar='ZZ&'></div>
+#errors
+(1,15): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar=ZZ&></div>
+#errors
+(1,13): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar="ZZ&gt=YY"></div>
+#errors
+(1,15): named-entity-without-semicolon
+(1,20): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gt=YY"
+
+#data
+<div bar="ZZ&gt0YY"></div>
+#errors
+(1,20): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gt0YY"
+
+#data
+<div bar="ZZ&gt9YY"></div>
+#errors
+(1,20): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gt9YY"
+
+#data
+<div bar="ZZ&gtaYY"></div>
+#errors
+(1,20): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gtaYY"
+
+#data
+<div bar="ZZ&gtZYY"></div>
+#errors
+(1,20): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gtZYY"
+
+#data
+<div bar="ZZ&gt YY"></div>
+#errors
+(1,15): named-entity-without-semicolon
+(1,20): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ> YY"
+
+#data
+<div bar="ZZ&gt"></div>
+#errors
+(1,15): named-entity-without-semicolon
+(1,17): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
+
+#data
+<div bar='ZZ&gt'></div>
+#errors
+(1,15): named-entity-without-semicolon
+(1,17): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
+
+#data
+<div bar=ZZ&gt></div>
+#errors
+(1,14): named-entity-without-semicolon
+(1,15): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
+
+#data
+<div bar="ZZ&pound_id=23"></div>
+#errors
+(1,18): named-entity-without-semicolon
+(1,26): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ&prod_id=23"></div>
+#errors
+(1,25): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&prod_id=23"
+
+#data
+<div bar="ZZ&pound;_id=23"></div>
+#errors
+(1,27): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ&prod;_id=23"></div>
+#errors
+(1,26): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ∏_id=23"
+
+#data
+<div bar="ZZ&pound=23"></div>
+#errors
+(1,18): named-entity-without-semicolon
+(1,23): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&pound=23"
+
+#data
+<div bar="ZZ&prod=23"></div>
+#errors
+(1,22): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&prod=23"
+
+#data
+<div>ZZ&pound_id=23</div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,13): named-entity-without-semicolon
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£_id=23"
+
+#data
+<div>ZZ&prod_id=23</div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ&prod_id=23"
+
+#data
+<div>ZZ&pound;_id=23</div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£_id=23"
+
+#data
+<div>ZZ&prod;_id=23</div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ∏_id=23"
+
+#data
+<div>ZZ&pound=23</div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,13): named-entity-without-semicolon
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£=23"
+
+#data
+<div>ZZ&prod=23</div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ&prod=23"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/foreign-fragment.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/foreign-fragment.dat
new file mode 100644
index 0000000000..2e3cb6c6f6
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/foreign-fragment.dat
@@ -0,0 +1,550 @@
+#data
+<nobr>X
+#errors
+6: HTML start tag “nobr” in a foreign namespace context.
+7: End of file seen and there were open elements.
+6: Unclosed element “nobr”.
+#document-fragment
+svg path
+#document
+| <svg nobr>
+| "X"
+
+#data
+<font color></font>X
+#errors
+12: HTML start tag “font” in a foreign namespace context.
+#document-fragment
+svg path
+#document
+| <svg font>
+| color=""
+| "X"
+
+#data
+<font></font>X
+#errors
+#document-fragment
+svg path
+#document
+| <svg font>
+| "X"
+
+#data
+<g></path>X
+#errors
+10: End tag “path” did not match the name of the current open element (“g”).
+11: End of file seen and there were open elements.
+3: Unclosed element “g”.
+#document-fragment
+svg path
+#document
+| <svg g>
+| "X"
+
+#data
+</path>X
+#errors
+5: Stray end tag “path”.
+#document-fragment
+svg path
+#document
+| "X"
+
+#data
+</foreignObject>X
+#errors
+5: Stray end tag “foreignobject”.
+#document-fragment
+svg foreignObject
+#document
+| "X"
+
+#data
+</desc>X
+#errors
+5: Stray end tag “desc”.
+#document-fragment
+svg desc
+#document
+| "X"
+
+#data
+</title>X
+#errors
+5: Stray end tag “title”.
+#document-fragment
+svg title
+#document
+| "X"
+
+#data
+</svg>X
+#errors
+5: Stray end tag “svg”.
+#document-fragment
+svg svg
+#document
+| "X"
+
+#data
+</mfenced>X
+#errors
+5: Stray end tag “mfenced”.
+#document-fragment
+math mfenced
+#document
+| "X"
+
+#data
+</malignmark>X
+#errors
+5: Stray end tag “malignmark”.
+#document-fragment
+math malignmark
+#document
+| "X"
+
+#data
+</math>X
+#errors
+5: Stray end tag “math”.
+#document-fragment
+math math
+#document
+| "X"
+
+#data
+</annotation-xml>X
+#errors
+5: Stray end tag “annotation-xml”.
+#document-fragment
+math annotation-xml
+#document
+| "X"
+
+#data
+</mtext>X
+#errors
+5: Stray end tag “mtext”.
+#document-fragment
+math mtext
+#document
+| "X"
+
+#data
+</mi>X
+#errors
+5: Stray end tag “mi”.
+#document-fragment
+math mi
+#document
+| "X"
+
+#data
+</mo>X
+#errors
+5: Stray end tag “mo”.
+#document-fragment
+math mo
+#document
+| "X"
+
+#data
+</mn>X
+#errors
+5: Stray end tag “mn”.
+#document-fragment
+math mn
+#document
+| "X"
+
+#data
+</ms>X
+#errors
+5: Stray end tag “ms”.
+#document-fragment
+math ms
+#document
+| "X"
+
+#data
+<b></b><mglyph/><i></i><malignmark/><u></u><ms/>X
+#errors
+51: Self-closing syntax (“/>”) used on a non-void HTML element. Ignoring the slash and treating as a start tag.
+52: End of file seen and there were open elements.
+51: Unclosed element “ms”.
+#document-fragment
+math ms
+#document
+| <b>
+| <math mglyph>
+| <i>
+| <math malignmark>
+| <u>
+| <ms>
+| "X"
+
+#data
+<malignmark></malignmark>
+#errors
+#document-fragment
+math ms
+#document
+| <math malignmark>
+
+#data
+<div></div>
+#errors
+#document-fragment
+math ms
+#document
+| <div>
+
+#data
+<figure></figure>
+#errors
+#document-fragment
+math ms
+#document
+| <figure>
+
+#data
+<b></b><mglyph/><i></i><malignmark/><u></u><mn/>X
+#errors
+51: Self-closing syntax (“/>”) used on a non-void HTML element. Ignoring the slash and treating as a start tag.
+52: End of file seen and there were open elements.
+51: Unclosed element “mn”.
+#document-fragment
+math mn
+#document
+| <b>
+| <math mglyph>
+| <i>
+| <math malignmark>
+| <u>
+| <mn>
+| "X"
+
+#data
+<malignmark></malignmark>
+#errors
+#document-fragment
+math mn
+#document
+| <math malignmark>
+
+#data
+<div></div>
+#errors
+#document-fragment
+math mn
+#document
+| <div>
+
+#data
+<figure></figure>
+#errors
+#document-fragment
+math mn
+#document
+| <figure>
+
+#data
+<b></b><mglyph/><i></i><malignmark/><u></u><mo/>X
+#errors
+51: Self-closing syntax (“/>”) used on a non-void HTML element. Ignoring the slash and treating as a start tag.
+52: End of file seen and there were open elements.
+51: Unclosed element “mo”.
+#document-fragment
+math mo
+#document
+| <b>
+| <math mglyph>
+| <i>
+| <math malignmark>
+| <u>
+| <mo>
+| "X"
+
+#data
+<malignmark></malignmark>
+#errors
+#document-fragment
+math mo
+#document
+| <math malignmark>
+
+#data
+<div></div>
+#errors
+#document-fragment
+math mo
+#document
+| <div>
+
+#data
+<figure></figure>
+#errors
+#document-fragment
+math mo
+#document
+| <figure>
+
+#data
+<b></b><mglyph/><i></i><malignmark/><u></u><mi/>X
+#errors
+51: Self-closing syntax (“/>”) used on a non-void HTML element. Ignoring the slash and treating as a start tag.
+52: End of file seen and there were open elements.
+51: Unclosed element “mi”.
+#document-fragment
+math mi
+#document
+| <b>
+| <math mglyph>
+| <i>
+| <math malignmark>
+| <u>
+| <mi>
+| "X"
+
+#data
+<malignmark></malignmark>
+#errors
+#document-fragment
+math mi
+#document
+| <math malignmark>
+
+#data
+<div></div>
+#errors
+#document-fragment
+math mi
+#document
+| <div>
+
+#data
+<figure></figure>
+#errors
+#document-fragment
+math mi
+#document
+| <figure>
+
+#data
+<b></b><mglyph/><i></i><malignmark/><u></u><mtext/>X
+#errors
+51: Self-closing syntax (“/>”) used on a non-void HTML element. Ignoring the slash and treating as a start tag.
+52: End of file seen and there were open elements.
+51: Unclosed element “mtext”.
+#document-fragment
+math mtext
+#document
+| <b>
+| <math mglyph>
+| <i>
+| <math malignmark>
+| <u>
+| <mtext>
+| "X"
+
+#data
+<malignmark></malignmark>
+#errors
+#document-fragment
+math mtext
+#document
+| <math malignmark>
+
+#data
+<div></div>
+#errors
+#document-fragment
+math mtext
+#document
+| <div>
+
+#data
+<figure></figure>
+#errors
+#document-fragment
+math mtext
+#document
+| <figure>
+
+#data
+<div></div>
+#errors
+5: HTML start tag “div” in a foreign namespace context.
+#document-fragment
+math annotation-xml
+#document
+| <math div>
+
+#data
+<figure></figure>
+#errors
+#document-fragment
+math annotation-xml
+#document
+| <math figure>
+
+#data
+<div></div>
+#errors
+5: HTML start tag “div” in a foreign namespace context.
+#document-fragment
+math math
+#document
+| <math div>
+
+#data
+<figure></figure>
+#errors
+#document-fragment
+math math
+#document
+| <math figure>
+
+#data
+<div></div>
+#errors
+#document-fragment
+svg foreignObject
+#document
+| <div>
+
+#data
+<figure></figure>
+#errors
+#document-fragment
+svg foreignObject
+#document
+| <figure>
+
+#data
+<div></div>
+#errors
+#document-fragment
+svg title
+#document
+| <div>
+
+#data
+<figure></figure>
+#errors
+#document-fragment
+svg title
+#document
+| <figure>
+
+#data
+<figure></figure>
+#errors
+#document-fragment
+svg desc
+#document
+| <figure>
+
+#data
+<div><h1>X</h1></div>
+#errors
+5: HTML start tag “div” in a foreign namespace context.
+9: HTML start tag “h1” in a foreign namespace context.
+#document-fragment
+svg svg
+#document
+| <svg div>
+| <svg h1>
+| "X"
+
+#data
+<div></div>
+#errors
+5: HTML start tag “div” in a foreign namespace context.
+#document-fragment
+svg svg
+#document
+| <svg div>
+
+#data
+<div></div>
+#errors
+#document-fragment
+svg desc
+#document
+| <div>
+
+#data
+<figure></figure>
+#errors
+#document-fragment
+svg desc
+#document
+| <figure>
+
+#data
+<plaintext><foo>
+#errors
+16: End of file seen and there were open elements.
+11: Unclosed element “plaintext”.
+#document-fragment
+svg desc
+#document
+| <plaintext>
+| "<foo>"
+
+#data
+<frameset>X
+#errors
+6: Stray start tag “frameset”.
+#document-fragment
+svg desc
+#document
+| "X"
+
+#data
+<head>X
+#errors
+6: Stray start tag “head”.
+#document-fragment
+svg desc
+#document
+| "X"
+
+#data
+<body>X
+#errors
+6: Stray start tag “body”.
+#document-fragment
+svg desc
+#document
+| "X"
+
+#data
+<html>X
+#errors
+6: Stray start tag “html”.
+#document-fragment
+svg desc
+#document
+| "X"
+
+#data
+<html class="foo">X
+#errors
+6: Stray start tag “html”.
+#document-fragment
+svg desc
+#document
+| "X"
+
+#data
+<body class="foo">X
+#errors
+6: Stray start tag “body”.
+#document-fragment
+svg desc
+#document
+| "X"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5lib_license.txt b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5lib_license.txt
new file mode 100644
index 0000000000..63faa963ea
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5lib_license.txt
@@ -0,0 +1,21 @@
+Copyright (c) 2006-2010 The Authors
+
+Contributors:
+James Graham - jg307@cam.ac.uk
+Anne van Kesteren - annevankesteren@gmail.com
+Lachlan Hunt - lachlan.hunt@lachy.id.au
+Matt McDonald - kanashii@kanashii.ca
+Sam Ruby - rubys@intertwingly.net
+Ian Hickson (Google) - ian@hixie.ch
+Thomas Broyer - t.broyer@ltgt.net
+Jacques Distler - distler@golem.ph.utexas.edu
+Henri Sivonen - hsivonen@iki.fi
+Adam Barth - abarth@webkit.org
+Eric Seidel - eric@webkit.org
+The Mozilla Foundation (contributions from Henri Sivonen since 2008)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5lib_upstream.txt b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5lib_upstream.txt
new file mode 100644
index 0000000000..5b466c614c
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5lib_upstream.txt
@@ -0,0 +1,11 @@
+The test data in this directory comes from the html5lib project
+(http://code.google.com/p/html5lib/). Please avoid making
+mozilla-central-specific changes to these files. If Gecko doesn't pass a test,
+please add the test's input data to ../html5_tree_construction_exceptions.js
+instead of removing it.
+
+If you add or edit tests, please push the test to upstream and then
+resynchronize this directory with the upstream.
+
+See html5lib_license.txt for the license that covers the files in this
+directory.
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5test-com.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5test-com.dat
new file mode 100644
index 0000000000..8c6ec40cd7
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/html5test-com.dat
@@ -0,0 +1,291 @@
+#data
+<div<div>
+#errors
+(1,9): expected-doctype-but-got-start-tag
+(1,9): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div<div>
+
+#data
+<div foo<bar=''>
+#errors
+(1,9): invalid-character-in-attribute-name
+(1,16): expected-doctype-but-got-start-tag
+(1,16): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo<bar=""
+
+#data
+<div foo=`bar`>
+#errors
+(1,10): equals-in-unquoted-attribute-value
+(1,14): unexpected-character-in-unquoted-attribute-value
+(1,15): expected-doctype-but-got-start-tag
+(1,15): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo="`bar`"
+
+#data
+<div \"foo=''>
+#errors
+(1,7): invalid-character-in-attribute-name
+(1,14): expected-doctype-but-got-start-tag
+(1,14): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| \"foo=""
+
+#data
+<a href='\nbar'></a>
+#errors
+(1,16): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="\nbar"
+
+#data
+<!DOCTYPE html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+&lang;&rang;
+#errors
+(1,6): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "⟨⟩"
+
+#data
+&apos;
+#errors
+(1,6): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "'"
+
+#data
+&ImaginaryI;
+#errors
+(1,12): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "ⅈ"
+
+#data
+&Kopf;
+#errors
+(1,6): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "𝕂"
+
+#data
+&notinva;
+#errors
+(1,9): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "∉"
+
+#data
+<?import namespace="foo" implementation="#bar">
+#errors
+(1,1): expected-tag-name-but-got-question-mark
+(1,47): expected-doctype-but-got-eof
+#document
+| <!-- ?import namespace="foo" implementation="#bar" -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!--foo--bar-->
+#errors
+(1,10): unexpected-char-in-comment
+(1,15): expected-doctype-but-got-eof
+#document
+| <!-- foo--bar -->
+| <html>
+| <head>
+| <body>
+
+#data
+<![CDATA[x]]>
+#errors
+(1,2): expected-dashes-or-doctype
+(1,13): expected-doctype-but-got-eof
+#document
+| <!-- [CDATA[x]] -->
+| <html>
+| <head>
+| <body>
+
+#data
+<textarea><!--</textarea>--></textarea>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,39): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--"
+| "-->"
+
+#data
+<textarea><!--</textarea>-->
+#errors
+(1,10): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--"
+| "-->"
+
+#data
+<style><!--</style>--></style>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,30): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "-->"
+
+#data
+<style><!--</style>-->
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "-->"
+
+#data
+<ul><li>A </li> <li>B</li></ul>
+#errors
+(1,4): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| "A "
+| " "
+| <li>
+| "B"
+
+#data
+<table><form><input type=hidden><input></form><div></div></table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,13): unexpected-form-in-table
+(1,32): unexpected-hidden-input-in-table
+(1,39): unexpected-start-tag-implies-table-voodoo
+(1,46): unexpected-end-tag-implies-table-voodoo
+(1,46): unexpected-end-tag
+(1,51): unexpected-start-tag-implies-table-voodoo
+(1,57): unexpected-end-tag-implies-table-voodoo
+#document
+| <html>
+| <head>
+| <body>
+| <input>
+| <div>
+| <table>
+| <form>
+| <input>
+| type="hidden"
+
+#data
+<i>A<b>B<p></i>C</b>D
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,15): adoption-agency-1.3
+(1,20): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <i>
+| "A"
+| <b>
+| "B"
+| <b>
+| <p>
+| <b>
+| <i>
+| "C"
+| "D"
+
+#data
+<div></div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<svg></svg>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<math></math>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/inbody01.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/inbody01.dat
new file mode 100644
index 0000000000..10f6520f6f
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/inbody01.dat
@@ -0,0 +1,54 @@
+#data
+<button>1</foo>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,15): unexpected-end-tag
+(1,15): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <button>
+| "1"
+
+#data
+<foo>1<p>2</foo>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,16): unexpected-end-tag
+(1,16): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| "1"
+| <p>
+| "2"
+
+#data
+<dd>1</foo>
+#errors
+(1,4): expected-doctype-but-got-start-tag
+(1,11): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <dd>
+| "1"
+
+#data
+<foo>1<dd>2</foo>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,17): unexpected-end-tag
+(1,17): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| "1"
+| <dd>
+| "2"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/isindex.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/isindex.dat
new file mode 100644
index 0000000000..733f82ea8e
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/isindex.dat
@@ -0,0 +1,49 @@
+#data
+<isindex>
+#errors
+(1,9): expected-doctype-but-got-start-tag
+(1,9): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <isindex>
+
+#data
+<isindex name="A" action="B" prompt="C" foo="D">
+#errors
+(1,48): expected-doctype-but-got-start-tag
+(1,48): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <isindex>
+| action="B"
+| foo="D"
+| name="A"
+| prompt="C"
+
+#data
+<form><isindex>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,15): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+| <isindex>
+
+#data
+<!doctype html><isindex>x</isindex>x
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <isindex>
+| "x"
+| "x"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/main-element.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/main-element.dat
new file mode 100644
index 0000000000..0d2102ed3f
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/main-element.dat
@@ -0,0 +1,44 @@
+#data
+<!doctype html><p>foo<main>bar<p>baz
+#errors
+(1,36): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "foo"
+| <main>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!doctype html><main><p>foo</main>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <main>
+| <p>
+| "foo"
+| "bar"
+
+#data
+<!DOCTYPE html>xxx<svg><x><g><a><main><b>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "xxx"
+| <svg svg>
+| <svg x>
+| <svg g>
+| <svg a>
+| <svg main>
+| <b>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/pending-spec-changes-plain-text-unsafe.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/pending-spec-changes-plain-text-unsafe.dat
new file mode 100644
index 0000000000..3ee8cec904
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/pending-spec-changes-plain-text-unsafe.dat
Binary files differ
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/pending-spec-changes.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/pending-spec-changes.dat
new file mode 100644
index 0000000000..1647d7f23a
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/pending-spec-changes.dat
@@ -0,0 +1,46 @@
+#data
+<input type="hidden"><frameset>
+#errors
+(1,21): expected-doctype-but-got-start-tag
+(1,31): unexpected-start-tag
+(1,31): eof-in-frameset
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><table><caption><svg>foo</table>bar
+#errors
+(1,47): unexpected-end-tag
+(1,47): end-table-tag-in-caption
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| "foo"
+| "bar"
+
+#data
+<table><tr><td><svg><desc><td></desc><circle>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,30): unexpected-cell-end-tag
+(1,37): unexpected-end-tag
+(1,45): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg desc>
+| <td>
+| <circle>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/plain-text-unsafe.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/plain-text-unsafe.dat
new file mode 100644
index 0000000000..f40dd57607
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/plain-text-unsafe.dat
Binary files differ
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/ruby.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/ruby.dat
new file mode 100644
index 0000000000..1ca8016cf1
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/ruby.dat
@@ -0,0 +1,298 @@
+#data
+<html><ruby>a<rb>b<rb></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rb>
+| "b"
+| <rb>
+
+#data
+<html><ruby>a<rb>b<rt></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rb>
+| "b"
+| <rt>
+
+#data
+<html><ruby>a<rb>b<rtc></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rb>
+| "b"
+| <rtc>
+
+#data
+<html><ruby>a<rb>b<rp></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rb>
+| "b"
+| <rp>
+
+#data
+<html><ruby>a<rb>b<span></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rb>
+| "b"
+| <span>
+
+#data
+<html><ruby>a<rt>b<rb></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rt>
+| "b"
+| <rb>
+
+#data
+<html><ruby>a<rt>b<rt></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rt>
+| "b"
+| <rt>
+
+#data
+<html><ruby>a<rt>b<rtc></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rt>
+| "b"
+| <rtc>
+
+#data
+<html><ruby>a<rt>b<rp></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rt>
+| "b"
+| <rp>
+
+#data
+<html><ruby>a<rt>b<span></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rt>
+| "b"
+| <span>
+
+#data
+<html><ruby>a<rtc>b<rb></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rtc>
+| "b"
+| <rb>
+
+#data
+<html><ruby>a<rtc>b<rt>c<rt>d</ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rtc>
+| "b"
+| <rt>
+| "c"
+| <rt>
+| "d"
+
+#data
+<html><ruby>a<rtc>b<rtc></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rtc>
+| "b"
+| <rtc>
+
+#data
+<html><ruby>a<rtc>b<rp></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rtc>
+| "b"
+| <rp>
+
+#data
+<html><ruby>a<rtc>b<span></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rtc>
+| "b"
+| <span>
+
+#data
+<html><ruby>a<rp>b<rb></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rp>
+| "b"
+| <rb>
+
+#data
+<html><ruby>a<rp>b<rt></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rp>
+| "b"
+| <rt>
+
+#data
+<html><ruby>a<rp>b<rtc></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rp>
+| "b"
+| <rtc>
+
+#data
+<html><ruby>a<rp>b<rp></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rp>
+| "b"
+| <rp>
+
+#data
+<html><ruby>a<rp>b<span></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rp>
+| "b"
+| <span>
+
+#data
+<html><ruby><rtc><ruby>a<rb>b<rt></ruby></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <rtc>
+| <ruby>
+| "a"
+| <rb>
+| "b"
+| <rt>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scriptdata01.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scriptdata01.dat
new file mode 100644
index 0000000000..710f5414b6
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scriptdata01.dat
@@ -0,0 +1,352 @@
+#data
+FOO<script>'Hello'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'Hello'"
+| "BAR"
+
+#data
+FOO<script></script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script >BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script/>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,21): self-closing-flag-on-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script/ >BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,20): unexpected-character-after-solidus-in-tag
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script type="text/plain"></scriptx>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,42): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "</scriptx>BAR"
+
+#data
+FOO<script></script foo=">" dd>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,31): attributes-in-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script>'<'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<'"
+| "BAR"
+
+#data
+FOO<script>'<!'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!'"
+| "BAR"
+
+#data
+FOO<script>'<!-'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-'"
+| "BAR"
+
+#data
+FOO<script>'<!--'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!--'"
+| "BAR"
+
+#data
+FOO<script>'<!---'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!---'"
+| "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-->'"
+| "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-->'"
+| "BAR"
+
+#data
+FOO<script>'<!-- potato'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- potato'"
+| "BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- <sCrIpt'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt>'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,56): expected-script-data-but-got-eof
+(1,56): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,58): expected-script-data-but-got-eof
+(1,58): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> -'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,59): expected-script-data-but-got-eof
+(1,59): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> --'</script>BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt> -->'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- <sCrIpt> -->'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --!>'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,61): expected-script-data-but-got-eof
+(1,61): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> --!>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -- >'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,61): expected-script-data-but-got-eof
+(1,61): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> -- >'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt '</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,56): expected-script-data-but-got-eof
+(1,56): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt '</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+(1,56): expected-script-data-but-got-eof
+(1,56): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt/'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt\'</script>BAR
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt\'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR</script>QUX
+#errors
+(1,3): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt/'</script>BAR"
+| "QUX"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/adoption01.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/adoption01.dat
new file mode 100644
index 0000000000..4e08d0e84a
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/adoption01.dat
@@ -0,0 +1,15 @@
+#data
+<p><b id="A"><script>document.getElementById("A").id = "B"</script></p>TEXT</b>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| id="B"
+| <script>
+| "document.getElementById("A").id = "B""
+| <b>
+| id="A"
+| "TEXT"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/ark.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/ark.dat
new file mode 100644
index 0000000000..acbac41df1
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/ark.dat
@@ -0,0 +1,26 @@
+#data
+<p><font size=4><font size=4><font size=4><script>document.getElementsByTagName("font")[2].setAttribute("size", "5");</script><font size=4><p>X
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="5"
+| <script>
+| "document.getElementsByTagName("font")[2].setAttribute("size", "5");"
+| <font>
+| size="4"
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| "X"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/webkit01.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/webkit01.dat
new file mode 100644
index 0000000000..ef4a41ca00
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/scripted/webkit01.dat
@@ -0,0 +1,28 @@
+#data
+1<script>document.write("2")</script>3
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "1"
+| <script>
+| "document.write("2")"
+| "23"
+
+#data
+1<script>document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")</script>4
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "1"
+| <script>
+| "document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")"
+| <script>
+| "document.write('2')"
+| "2"
+| <script>
+| "document.write('3')"
+| "34"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tables01.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tables01.dat
new file mode 100644
index 0000000000..f0caaa3c5f
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tables01.dat
@@ -0,0 +1,286 @@
+#data
+<table><th>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,11): unexpected-cell-in-table-body
+(1,11): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <th>
+
+#data
+<table><td>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,11): unexpected-cell-in-table-body
+(1,11): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><col foo='bar'>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,22): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <col>
+| foo="bar"
+
+#data
+<table><colgroup></html>foo
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,24): unexpected-end-tag
+(1,27): foster-parenting-character-in-table
+(1,27): foster-parenting-character-in-table
+(1,27): foster-parenting-character-in-table
+(1,27): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| "foo"
+| <table>
+| <colgroup>
+
+#data
+<table></table><p>foo
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <p>
+| "foo"
+
+#data
+<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr><td>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,14): unexpected-end-tag
+(1,24): unexpected-end-tag
+(1,30): unexpected-end-tag
+(1,41): unexpected-end-tag
+(1,48): unexpected-end-tag
+(1,56): unexpected-end-tag
+(1,61): unexpected-end-tag
+(1,69): unexpected-end-tag
+(1,74): unexpected-end-tag
+(1,82): unexpected-end-tag
+(1,87): unexpected-end-tag
+(1,91): unexpected-cell-in-table-body
+(1,91): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><select><option>3</select></table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,15): unexpected-start-tag-implies-table-voodoo
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| "3"
+| <table>
+
+#data
+<table><select><table></table></select></table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,15): unexpected-start-tag-implies-table-voodoo
+(1,22): unexpected-table-element-start-tag-in-select-in-table
+(1,22): unexpected-start-tag-implies-end-tag
+(1,39): unexpected-end-tag
+(1,47): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+| <table>
+
+#data
+<table><select></table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,15): unexpected-start-tag-implies-table-voodoo
+(1,23): unexpected-table-element-end-tag-in-select-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+
+#data
+<table><select><option>A<tr><td>B</td></tr></table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,15): unexpected-start-tag-implies-table-voodoo
+(1,28): unexpected-table-element-start-tag-in-select-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| "A"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "B"
+
+#data
+<table><td></body></caption></col></colgroup></html>foo
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,11): unexpected-cell-in-table-body
+(1,18): unexpected-end-tag
+(1,28): unexpected-end-tag
+(1,34): unexpected-end-tag
+(1,45): unexpected-end-tag
+(1,52): unexpected-end-tag
+(1,55): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "foo"
+
+#data
+<table><td>A</table>B
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,11): unexpected-cell-in-table-body
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "A"
+| "B"
+
+#data
+<table><tr><caption>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,20): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <caption>
+
+#data
+<table><tr></body></caption></col></colgroup></html></td></th><td>foo
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,18): unexpected-end-tag-in-table-row
+(1,28): unexpected-end-tag-in-table-row
+(1,34): unexpected-end-tag-in-table-row
+(1,45): unexpected-end-tag-in-table-row
+(1,52): unexpected-end-tag-in-table-row
+(1,57): unexpected-end-tag-in-table-row
+(1,62): unexpected-end-tag-in-table-row
+(1,69): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "foo"
+
+#data
+<table><td><tr>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,11): unexpected-cell-in-table-body
+(1,15): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <tr>
+
+#data
+<table><td><button><td>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,11): unexpected-cell-in-table-body
+(1,23): unexpected-cell-end-tag
+(1,23): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <button>
+| <td>
+
+#data
+<table><tr><td><svg><desc><td>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,30): unexpected-cell-end-tag
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg desc>
+| <td>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/template.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/template.dat
new file mode 100644
index 0000000000..daf587e2d7
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/template.dat
@@ -0,0 +1,1406 @@
+#data
+<body><template>Hello</template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| "Hello"
+
+#data
+<template>Hello</template>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| "Hello"
+| <body>
+
+#data
+<template></template><div></div>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <body>
+| <div>
+
+#data
+<html><template>Hello</template>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| "Hello"
+| <body>
+
+#data
+<head><template><div></div></template></head>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <div>
+| <body>
+
+#data
+<div><template><div><span></template><b>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <template>
+| content
+| <div>
+| <span>
+| <b>
+
+#data
+<div><template></div>Hello
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <template>
+| content
+| "Hello"
+
+#data
+<div></template></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<table><template></template></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <template>
+| content
+
+#data
+<table><template></template></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <template>
+| content
+
+#data
+<table><div><template></template></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <template>
+| content
+| <table>
+
+#data
+<table><template></template><div></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <table>
+| <template>
+| content
+
+#data
+<table> <template></template></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <template>
+| content
+
+#data
+<table><tbody><template></template></tbody>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <template>
+| content
+
+#data
+<table><tbody><template></tbody></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <template>
+| content
+
+#data
+<table><tbody><template></template></tbody></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <template>
+| content
+
+#data
+<table><thead><template></template></thead>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <thead>
+| <template>
+| content
+
+#data
+<table><tfoot><template></template></tfoot>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tfoot>
+| <template>
+| content
+
+#data
+<select><template></template></select>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <template>
+| content
+
+#data
+<select><template><option></option></template></select>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <template>
+| content
+| <option>
+
+#data
+<template><option></option></select><option></option></template>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <option>
+| <option>
+| <body>
+
+#data
+<select><template></template><option></select>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <template>
+| content
+| <option>
+
+#data
+<select><option><template></template></select>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <template>
+| content
+
+#data
+<select><template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <template>
+| content
+
+#data
+<select><option></option><template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <template>
+| content
+
+#data
+<select><option></option><template><option>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <template>
+| content
+| <option>
+
+#data
+<table><thead><template><td></template></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <thead>
+| <template>
+| content
+| <td>
+
+#data
+<table><template><thead></template></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <template>
+| content
+| <thead>
+
+#data
+<body><table><template><td></tr><div></template></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <template>
+| content
+| <td>
+| <div>
+
+#data
+<table><template><thead></template></thead></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <template>
+| content
+| <thead>
+
+#data
+<table><thead><template><tr></template></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <thead>
+| <template>
+| content
+| <tr>
+
+#data
+<table><template><tr></template></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <template>
+| content
+| <tr>
+
+#data
+<table><tr><template><td>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <template>
+| content
+| <td>
+
+#data
+<table><template><tr><template><td></template></tr></template></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <template>
+| content
+| <tr>
+| <template>
+| content
+| <td>
+
+#data
+<table><template><tr><template><td></td></template></tr></template></table>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <template>
+| content
+| <tr>
+| <template>
+| content
+| <td>
+
+#data
+<table><template><td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <template>
+| content
+| <td>
+
+#data
+<body><template><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <td>
+
+#data
+<body><template><template><tr></tr></template><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <template>
+| content
+| <tr>
+| <td>
+
+#data
+<table><colgroup><template><col>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <template>
+| content
+| <col>
+
+#data
+<frameset><template><frame></frame></template></frameset>
+#errors
+#document
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<template><frame></frame></frameset><frame></frame></template>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <body>
+
+#data
+<template><div><frameset><span></span></div><span></span></template>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <div>
+| <span>
+| <span>
+| <body>
+
+#data
+<body><template><div><frameset><span></span></div><span></span></template></body>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <div>
+| <span>
+| <span>
+
+#data
+<body><template><script>var i = 1;</script><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <script>
+| "var i = 1;"
+| <td>
+
+#data
+<body><template><tr><div></div></tr></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <tr>
+| <div>
+
+#data
+<body><template><tr>Foo</tr></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <tr>
+| "Foo"
+
+#data
+<body><template><tr></tr><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <tr>
+| <tr>
+| <td>
+
+#data
+<body><template><td></td></tr><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <td>
+| <td>
+
+#data
+<body><template><td></td><tbody><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <td>
+| <td>
+
+#data
+<body><template><td></td><caption></caption><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <td>
+| <td>
+
+#data
+<body><template><td></td><colgroup></caption><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <td>
+| <td>
+
+#data
+<body><template><td></td></table><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <td>
+| <td>
+
+#data
+<body><template><tr></tr><tbody><tr></tr></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <tr>
+| <tr>
+
+#data
+<body><template><tr></tr><caption><tr></tr></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <tr>
+| <tr>
+
+#data
+<body><template><tr></tr></table><tr></tr></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <tr>
+| <tr>
+
+#data
+<body><template><thead></thead><caption></caption><tbody></tbody></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <thead>
+| <caption>
+| <tbody>
+
+#data
+<body><template><thead></thead></table><tbody></tbody></template></body>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <thead>
+| <tbody>
+
+#data
+<body><template><div><tr></tr></div></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <div>
+
+#data
+<body><template><em>Hello</em></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <em>
+| "Hello"
+
+#data
+<body><template><!--comment--></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <!-- comment -->
+
+#data
+<body><template><style></style><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <style>
+| <td>
+
+#data
+<body><template><meta><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <meta>
+| <td>
+
+#data
+<body><template><link><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <link>
+| <td>
+
+#data
+<body><template><template><tr></tr></template><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <template>
+| content
+| <tr>
+| <td>
+
+#data
+<body><table><colgroup><template><col></col></template></colgroup></table></body>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <template>
+| content
+| <col>
+
+#data
+<body a=b><template><div></div><body c=d><div></div></body></template></body>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| a="b"
+| <template>
+| content
+| <div>
+| <div>
+
+#data
+<html a=b><template><div><html b=c><span></template>
+#errors
+#document
+| <html>
+| a="b"
+| <head>
+| <template>
+| content
+| <div>
+| <span>
+| <body>
+
+#data
+<html a=b><template><col></col><html b=c><col></col></template>
+#errors
+#document
+| <html>
+| a="b"
+| <head>
+| <template>
+| content
+| <col>
+| <col>
+| <body>
+
+#data
+<html a=b><template><frame></frame><html b=c><frame></frame></template>
+#errors
+#document
+| <html>
+| a="b"
+| <head>
+| <template>
+| content
+| <body>
+
+#data
+<body><template><tr></tr><template></template><td></td></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <tr>
+| <template>
+| content
+| <tr>
+| <td>
+
+#data
+<body><template><thead></thead><template><tr></tr></template><tr></tr><tfoot></tfoot></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <thead>
+| <template>
+| content
+| <tr>
+| <tbody>
+| <tr>
+| <tfoot>
+
+#data
+<body><template><template><b><template></template></template>text</template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <template>
+| content
+| <b>
+| <template>
+| content
+| "text"
+
+#data
+<body><template><col><colgroup>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <col>
+
+#data
+<body><template><col></colgroup>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <col>
+
+#data
+<body><template><col><colgroup></template></body>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <col>
+
+#data
+<body><template><col><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <col>
+
+#data
+<body><template><col></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <col>
+
+#data
+<body><template><col>Hello
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <col>
+
+#data
+<body><template><i><menu>Foo</i>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <i>
+| <menu>
+| <i>
+| "Foo"
+
+#data
+<body><template></div><div>Foo</div><template></template><tr></tr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <div>
+| "Foo"
+| <template>
+| content
+
+#data
+<body><div><template></div><tr><td>Foo</td></tr></template>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <template>
+| content
+| <tr>
+| <td>
+| "Foo"
+
+#data
+<template></figcaption><sub><table></table>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <sub>
+| <table>
+| <body>
+
+#data
+<template><template>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <body>
+
+#data
+<template><div>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <div>
+| <body>
+
+#data
+<template><template><div>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <div>
+| <body>
+
+#data
+<template><template><table>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <table>
+| <body>
+
+#data
+<template><template><tbody>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <tbody>
+| <body>
+
+#data
+<template><template><tr>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <tr>
+| <body>
+
+#data
+<template><template><td>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <td>
+| <body>
+
+#data
+<template><template><caption>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <caption>
+| <body>
+
+#data
+<template><template><colgroup>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <colgroup>
+| <body>
+
+#data
+<template><template><col>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <col>
+| <body>
+
+#data
+<template><template><tbody><select>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <tbody>
+| <select>
+| <body>
+
+#data
+<template><template><table>Foo
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| "Foo"
+| <table>
+| <body>
+
+#data
+<template><template><table><div>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <div>
+| <table>
+| <body>
+
+#data
+<template><template><frame>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <body>
+
+#data
+<template><template><script>var i
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <script>
+| "var i"
+| <body>
+
+#data
+<template><template><style>var i
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <template>
+| content
+| <style>
+| "var i"
+| <body>
+
+#data
+<template><table></template><body><span>Foo
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <table>
+| <body>
+| <span>
+| "Foo"
+
+#data
+<template><td></template><body><span>Foo
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <td>
+| <body>
+| <span>
+| "Foo"
+
+#data
+<template><object></template><body><span>Foo
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <object>
+| <body>
+| <span>
+| "Foo"
+
+#data
+<template><svg><template>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <svg svg>
+| <svg template>
+| <body>
+
+#data
+<template><svg><foo><template><foreignObject><div></template><div>
+#errors
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <svg svg>
+| <svg foo>
+| <svg template>
+| <svg foreignObject>
+| <div>
+| <body>
+| <div>
+
+#data
+<dummy><template><span></dummy>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <dummy>
+| <template>
+| content
+| <span>
+
+#data
+<body><table><tr><td><select><template>Foo</template><caption>A</table>
+#errors
+(1,62): unexpected-caption-in-select-in-table
+(1,71): unexpected-table-end-in-caption
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| <template>
+| content
+| "Foo"
+| <caption>
+| "A"
+
+#data
+<body></body><template>
+#errors
+(1,23): template-after-body
+(1,24): eof-in-template
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+
+#data
+<head></head><template>
+#errors
+(1,23): template-after-head
+(1,24): eof-in-template
+#document
+| <html>
+| <head>
+| <template>
+| content
+| <body>
+
+#data
+<head></head><template>Foo</template>
+#errors
+(1,23): template-after-head
+#document
+| <html>
+| <head>
+| <template>
+| content
+| "Foo"
+| <body>
+
+#data
+<body><form><template><form>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+| <template>
+| content
+| <form>
+
+#data
+<body><template><table><form>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <table>
+
+#data
+<body><template><form><form>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <template>
+| content
+| <form>
+| <form>
+
+#data
+<body><form><template><isindex>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+| <template>
+| content
+| <isindex>
+
+#data
+<body><form><template><isindex><form>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+| <template>
+| content
+| <isindex>
+| <form>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests1.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests1.dat
new file mode 100644
index 0000000000..f12e87178c
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests1.dat
@@ -0,0 +1,1959 @@
+#data
+Test
+#errors
+(1,0): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<p>One<p>Two
+#errors
+(1,3): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| "One"
+| <p>
+| "Two"
+
+#data
+Line1<br>Line2<br>Line3<br>Line4
+#errors
+(1,0): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "Line1"
+| <br>
+| "Line2"
+| <br>
+| "Line3"
+| <br>
+| "Line4"
+
+#data
+<html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<head>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<body>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head><body>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head><body></body>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head><body></body></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></body></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head><body></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><body></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<body></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<head></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</head>
+#errors
+(1,7): expected-doctype-but-got-end-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</body>
+#errors
+(1,7): expected-doctype-but-got-end-tag element.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</html>
+#errors
+(1,7): expected-doctype-but-got-end-tag element.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<b><table><td><i></table>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,14): unexpected-cell-in-table-body
+(1,25): unexpected-cell-end-tag
+(1,25): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<b><table><td></b><i></table>X
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,14): unexpected-cell-in-table-body
+(1,18): unexpected-end-tag
+(1,29): unexpected-cell-end-tag
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+| "X"
+
+#data
+<h1>Hello<h2>World
+#errors
+(1,4): expected-doctype-but-got-start-tag
+(1,13): unexpected-start-tag
+(1,18): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| "Hello"
+| <h2>
+| "World"
+
+#data
+<a><p>X<a>Y</a>Z</p></a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,10): unexpected-start-tag-implies-end-tag
+(1,10): adoption-agency-1.3
+(1,24): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <p>
+| <a>
+| "X"
+| <a>
+| "Y"
+| "Z"
+
+#data
+<b><button>foo</b>bar
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,18): adoption-agency-1.3
+(1,21): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <button>
+| <b>
+| "foo"
+| "bar"
+
+#data
+<!DOCTYPE html><span><button>foo</span>bar
+#errors
+(1,39): unexpected-end-tag
+(1,42): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <span>
+| <button>
+| "foobar"
+
+#data
+<p><b><div><marquee></p></b></div>X
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,11): unexpected-end-tag
+(1,24): unexpected-end-tag
+(1,28): unexpected-end-tag
+(1,34): end-tag-too-early
+(1,35): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <div>
+| <b>
+| <marquee>
+| <p>
+| "X"
+
+#data
+<script><div></script></div><title><p></title><p><p>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,28): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<div>"
+| <title>
+| "<p>"
+| <body>
+| <p>
+| <p>
+
+#data
+<!--><div>--<!-->
+#errors
+(1,5): incorrect-comment
+(1,10): expected-doctype-but-got-start-tag
+(1,17): incorrect-comment
+(1,17): expected-closing-tag-but-got-eof
+#document
+| <!-- -->
+| <html>
+| <head>
+| <body>
+| <div>
+| "--"
+| <!-- -->
+
+#data
+<p><hr></p>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,11): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <hr>
+| <p>
+
+#data
+<select><b><option><select><option></b></select>X
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,11): unexpected-start-tag-in-select
+(1,27): unexpected-select-in-select
+(1,39): unexpected-end-tag
+(1,48): unexpected-end-tag
+(1,49): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <option>
+| "X"
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><b>X</b>C<a>Y
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,14): unexpected-cell-in-table-body
+(1,35): unexpected-start-tag-implies-end-tag
+(1,40): unexpected-cell-end-tag
+(1,43): unexpected-start-tag-implies-table-voodoo
+(1,43): unexpected-start-tag-implies-end-tag
+(1,43): unexpected-end-tag
+(1,63): unexpected-start-tag-implies-end-tag
+(1,64): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| <table>
+| <a>
+| <a>
+| <b>
+| "X"
+| "C"
+| <a>
+| "Y"
+
+#data
+<a X>0<b>1<a Y>2
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,15): unexpected-start-tag-implies-end-tag
+(1,15): adoption-agency-1.3
+(1,16): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| x=""
+| "0"
+| <b>
+| "1"
+| <b>
+| <a>
+| y=""
+| "2"
+
+#data
+<!-----><font><div>hello<table>excite!<b>me!<th><i>please!</tr><!--X-->
+#errors
+(1,7): unexpected-dash-after-double-dash-in-comment
+(1,14): expected-doctype-but-got-start-tag
+(1,41): unexpected-start-tag-implies-table-voodoo
+(1,48): foster-parenting-character-in-table
+(1,48): foster-parenting-character-in-table
+(1,48): foster-parenting-character-in-table
+(1,48): foster-parenting-character-in-table
+(1,48): foster-parenting-character-in-table
+(1,48): foster-parenting-character-in-table
+(1,48): foster-parenting-character-in-table
+(1,48): foster-parenting-start-tag-in-table
+(1,48): foster-parenting-character-in-table
+(1,48): foster-parenting-character-in-table
+(1,48): foster-parenting-character-in-table
+(1,48): unexpected-cell-in-table-body
+(1,63): unexpected-cell-end-tag
+(1,71): eof-in-table
+#document
+| <!-- - -->
+| <html>
+| <head>
+| <body>
+| <font>
+| <div>
+| "helloexcite!"
+| <b>
+| "me!"
+| <table>
+| <tbody>
+| <tr>
+| <th>
+| <i>
+| "please!"
+| <!-- X -->
+
+#data
+<!DOCTYPE html><li>hello<li>world<ul>how<li>do</ul>you</body><!--do-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <li>
+| "hello"
+| <li>
+| "world"
+| <ul>
+| "how"
+| <li>
+| "do"
+| "you"
+| <!-- do -->
+
+#data
+<!DOCTYPE html>A<option>B<optgroup>C<select>D</option>E
+#errors
+(1,54): unexpected-end-tag-in-select
+(1,55): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "A"
+| <option>
+| "B"
+| <optgroup>
+| "C"
+| <select>
+| "DE"
+
+#data
+<
+#errors
+(1,1): expected-tag-name
+(1,1): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "<"
+
+#data
+<#
+#errors
+(1,1): expected-tag-name
+(1,1): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "<#"
+
+#data
+</
+#errors
+(1,2): expected-closing-tag-but-got-eof
+(1,2): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "</"
+
+#data
+</#
+#errors
+(1,2): expected-closing-tag-but-got-char
+(1,3): expected-doctype-but-got-eof
+#document
+| <!-- # -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?
+#errors
+(1,1): expected-tag-name-but-got-question-mark
+(1,2): expected-doctype-but-got-eof
+#document
+| <!-- ? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?#
+#errors
+(1,1): expected-tag-name-but-got-question-mark
+(1,3): expected-doctype-but-got-eof
+#document
+| <!-- ?# -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!
+#errors
+(1,2): expected-dashes-or-doctype
+(1,2): expected-doctype-but-got-eof
+#document
+| <!-- -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!#
+#errors
+(1,2): expected-dashes-or-doctype
+(1,3): expected-doctype-but-got-eof
+#document
+| <!-- # -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?COMMENT?>
+#errors
+(1,1): expected-tag-name-but-got-question-mark
+(1,11): expected-doctype-but-got-eof
+#document
+| <!-- ?COMMENT? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!COMMENT>
+#errors
+(1,2): expected-dashes-or-doctype
+(1,10): expected-doctype-but-got-eof
+#document
+| <!-- COMMENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+</ COMMENT >
+#errors
+(1,2): expected-closing-tag-but-got-char
+(1,12): expected-doctype-but-got-eof
+#document
+| <!-- COMMENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?COM--MENT?>
+#errors
+(1,1): expected-tag-name-but-got-question-mark
+(1,13): expected-doctype-but-got-eof
+#document
+| <!-- ?COM--MENT? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!COM--MENT>
+#errors
+(1,2): expected-dashes-or-doctype
+(1,12): expected-doctype-but-got-eof
+#document
+| <!-- COM--MENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+</ COM--MENT >
+#errors
+(1,2): expected-closing-tag-but-got-char
+(1,14): expected-doctype-but-got-eof
+#document
+| <!-- COM--MENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><style> EOF
+#errors
+(1,26): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| " EOF"
+| <body>
+
+#data
+<!DOCTYPE html><script> <!-- </script> --> </script> EOF
+#errors
+(1,52): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| " <!-- "
+| " "
+| <body>
+| "--> EOF"
+
+#data
+<b><p></b>TEST
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,10): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <p>
+| <b>
+| "TEST"
+
+#data
+<p id=a><b><p id=b></b>TEST
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,19): unexpected-end-tag
+(1,23): adoption-agency-1.2
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| id="a"
+| <b>
+| <p>
+| id="b"
+| "TEST"
+
+#data
+<b id=a><p><b id=b></p></b>TEST
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,23): unexpected-end-tag
+(1,27): adoption-agency-1.2
+(1,31): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| id="a"
+| <p>
+| <b>
+| id="b"
+| "TEST"
+
+#data
+<!DOCTYPE html><title>U-test</title><body><div><p>Test<u></p></div></body>
+#errors
+(1,61): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "U-test"
+| <body>
+| <div>
+| <p>
+| "Test"
+| <u>
+
+#data
+<!DOCTYPE html><font><table></font></table></font>
+#errors
+(1,35): unexpected-end-tag-implies-table-voodoo
+(1,35): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <table>
+
+#data
+<font><p>hello<b>cruel</font>world
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,29): adoption-agency-1.3
+(1,29): adoption-agency-1.3
+(1,34): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <font>
+| "hello"
+| <b>
+| "cruel"
+| <b>
+| "world"
+
+#data
+<b>Test</i>Test
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,11): unexpected-end-tag
+(1,15): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "TestTest"
+
+#data
+<b>A<cite>B<div>C
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,17): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| "C"
+
+#data
+<b>A<cite>B<div>C</cite>D
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,24): unexpected-end-tag
+(1,25): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| "CD"
+
+#data
+<b>A<cite>B<div>C</b>D
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,21): adoption-agency-1.3
+(1,22): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| <b>
+| "C"
+| "D"
+
+#data
+
+#errors
+(1,0): expected-doctype-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<DIV>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,5): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<DIV> abc
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,9): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc"
+
+#data
+<DIV> abc <B>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,13): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+
+#data
+<DIV> abc <B> def
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,17): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def"
+
+#data
+<DIV> abc <B> def <I>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,21): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+
+#data
+<DIV> abc <B> def <I> ghi
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,25): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi"
+
+#data
+<DIV> abc <B> def <I> ghi <P>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,29): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <p>
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,33): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <p>
+| " jkl"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,38): adoption-agency-1.3
+(1,38): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <b>
+| " jkl "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,38): adoption-agency-1.3
+(1,42): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <b>
+| " jkl "
+| " mno"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,38): adoption-agency-1.3
+(1,47): adoption-agency-1.3
+(1,47): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,38): adoption-agency-1.3
+(1,47): adoption-agency-1.3
+(1,51): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,38): adoption-agency-1.3
+(1,47): adoption-agency-1.3
+(1,56): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P> stu
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,38): adoption-agency-1.3
+(1,47): adoption-agency-1.3
+(1,60): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr "
+| " stu"
+
+#data
+<test attribute---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
+#errors
+(1,1040): expected-doctype-but-got-start-tag
+(1,1040): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <test>
+| attribute----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------=""
+
+#data
+<a href="blah">aba<table><a href="foo">br<tr><td></td></tr>x</table>aoe
+#errors
+(1,15): expected-doctype-but-got-start-tag
+(1,39): unexpected-start-tag-implies-table-voodoo
+(1,39): unexpected-start-tag-implies-end-tag
+(1,39): unexpected-end-tag
+(1,45): foster-parenting-character-in-table
+(1,45): foster-parenting-character-in-table
+(1,68): foster-parenting-character-in-table
+(1,71): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "aba"
+| <a>
+| href="foo"
+| "br"
+| <a>
+| href="foo"
+| "x"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "aoe"
+
+#data
+<a href="blah">aba<table><tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+(1,15): expected-doctype-but-got-start-tag
+(1,54): unexpected-cell-end-tag
+(1,71): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "abax"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "br"
+| "aoe"
+
+#data
+<table><a href="blah">aba<tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,22): unexpected-start-tag-implies-table-voodoo
+(1,29): foster-parenting-character-in-table
+(1,29): foster-parenting-character-in-table
+(1,29): foster-parenting-character-in-table
+(1,54): unexpected-cell-end-tag
+(1,68): foster-parenting-character-in-table
+(1,71): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "aba"
+| <a>
+| href="blah"
+| "x"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "br"
+| <a>
+| href="blah"
+| "aoe"
+
+#data
+<a href=a>aa<marquee>aa<a href=b>bb</marquee>aa
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,45): end-tag-too-early
+(1,47): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="a"
+| "aa"
+| <marquee>
+| "aa"
+| <a>
+| href="b"
+| "bb"
+| "aa"
+
+#data
+<wbr><strike><code></strike><code><strike></code>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,28): adoption-agency-1.3
+(1,49): adoption-agency-1.3
+(1,49): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <wbr>
+| <strike>
+| <code>
+| <code>
+| <code>
+| <strike>
+
+#data
+<!DOCTYPE html><spacer>foo
+#errors
+(1,26): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <spacer>
+| "foo"
+
+#data
+<title><meta></title><link><title><meta></title>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <title>
+| "<meta>"
+| <link>
+| <title>
+| "<meta>"
+| <body>
+
+#data
+<style><!--</style><meta><script>--><link></script>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <meta>
+| <script>
+| "--><link>"
+| <body>
+
+#data
+<head><meta></head><link>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,25): unexpected-start-tag-out-of-my-head
+#document
+| <html>
+| <head>
+| <meta>
+| <link>
+| <body>
+
+#data
+<table><tr><tr><td><td><span><th><span>X</table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,33): unexpected-cell-end-tag
+(1,48): unexpected-cell-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <tr>
+| <td>
+| <td>
+| <span>
+| <th>
+| <span>
+| "X"
+
+#data
+<body><body><base><link><meta><title><p></title><body><p></body>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,12): unexpected-start-tag
+(1,54): unexpected-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <base>
+| <link>
+| <meta>
+| <title>
+| "<p>"
+| <p>
+
+#data
+<textarea><p></textarea>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<p>"
+
+#data
+<p><image></p>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,10): unexpected-start-tag-treated-as
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <img>
+
+#data
+<a><table><a></table><p><a><div><a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,13): unexpected-start-tag-implies-table-voodoo
+(1,13): unexpected-start-tag-implies-end-tag
+(1,13): adoption-agency-1.3
+(1,27): unexpected-start-tag-implies-end-tag
+(1,27): adoption-agency-1.2
+(1,32): unexpected-end-tag
+(1,35): unexpected-start-tag-implies-end-tag
+(1,35): adoption-agency-1.2
+(1,35): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <p>
+| <a>
+| <div>
+| <a>
+
+#data
+<head></p><meta><p>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,10): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <meta>
+| <body>
+| <p>
+
+#data
+<head></html><meta><p>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,19): expected-eof-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <meta>
+| <p>
+
+#data
+<b><table><td><i></table>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,14): unexpected-cell-in-table-body
+(1,25): unexpected-cell-end-tag
+(1,25): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<b><table><td></b><i></table>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,14): unexpected-cell-in-table-body
+(1,18): unexpected-end-tag
+(1,29): unexpected-cell-end-tag
+(1,29): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<h1><h2>
+#errors
+(1,4): expected-doctype-but-got-start-tag
+(1,8): unexpected-start-tag
+(1,8): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| <h2>
+
+#data
+<a><p><a></a></p></a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,9): unexpected-start-tag-implies-end-tag
+(1,9): adoption-agency-1.3
+(1,21): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <p>
+| <a>
+| <a>
+
+#data
+<b><button></b></button></b>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,15): adoption-agency-1.3
+(1,28): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <button>
+| <b>
+
+#data
+<p><b><div><marquee></p></b></div>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,11): unexpected-end-tag
+(1,24): unexpected-end-tag
+(1,28): unexpected-end-tag
+(1,34): end-tag-too-early
+(1,34): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <div>
+| <b>
+| <marquee>
+| <p>
+
+#data
+<script></script></div><title></title><p><p>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,23): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <script>
+| <title>
+| <body>
+| <p>
+| <p>
+
+#data
+<p><hr></p>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,11): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <hr>
+| <p>
+
+#data
+<select><b><option><select><option></b></select>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,11): unexpected-start-tag-in-select
+(1,27): unexpected-select-in-select
+(1,39): unexpected-end-tag
+(1,48): unexpected-end-tag
+(1,48): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <option>
+
+#data
+<html><head><title></title><body></body></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <title>
+| <body>
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,14): unexpected-cell-in-table-body
+(1,35): unexpected-start-tag-implies-end-tag
+(1,40): unexpected-cell-end-tag
+(1,43): unexpected-start-tag-implies-table-voodoo
+(1,43): unexpected-start-tag-implies-end-tag
+(1,43): unexpected-end-tag
+(1,54): unexpected-start-tag-implies-end-tag
+(1,54): adoption-agency-1.2
+(1,54): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| <table>
+| <a>
+| <a>
+
+#data
+<ul><li></li><div><li></div><li><li><div><li><address><li><b><em></b><li></ul>
+#errors
+(1,4): expected-doctype-but-got-start-tag
+(1,45): end-tag-too-early
+(1,58): end-tag-too-early
+(1,69): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| <li>
+| <li>
+| <li>
+| <div>
+| <li>
+| <address>
+| <li>
+| <b>
+| <em>
+| <li>
+
+#data
+<ul><li><ul></li><li>a</li></ul></li></ul>
+#errors
+(1,4): expected-doctype-but-got-start-tag
+(1,17): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <ul>
+| <li>
+| "a"
+
+#data
+<frameset><frame><frameset><frame></frameset><noframes></noframes></frameset>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <frameset>
+| <frame>
+| <frameset>
+| <frame>
+| <noframes>
+
+#data
+<h1><table><td><h3></table><h3></h1>
+#errors
+(1,4): expected-doctype-but-got-start-tag
+(1,15): unexpected-cell-in-table-body
+(1,27): unexpected-cell-end-tag
+(1,31): unexpected-start-tag
+(1,36): end-tag-too-early
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <h3>
+| <h3>
+
+#data
+<table><colgroup><col><colgroup><col><col><col><colgroup><col><col><thead><tr><td></table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <col>
+| <colgroup>
+| <col>
+| <col>
+| <col>
+| <colgroup>
+| <col>
+| <col>
+| <thead>
+| <tr>
+| <td>
+
+#data
+<table><col><tbody><col><tr><col><td><col></table><col>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,37): unexpected-cell-in-table-body
+(1,55): unexpected-start-tag-ignored
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <td>
+| <colgroup>
+| <col>
+
+#data
+<table><colgroup><tbody><colgroup><tr><colgroup><td><colgroup></table><colgroup>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,52): unexpected-cell-in-table-body
+(1,80): unexpected-start-tag-ignored
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <tbody>
+| <colgroup>
+| <tbody>
+| <tr>
+| <colgroup>
+| <tbody>
+| <tr>
+| <td>
+| <colgroup>
+
+#data
+</strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
+#errors
+(1,9): expected-doctype-but-got-end-tag
+(1,9): unexpected-end-tag-before-html
+(1,13): unexpected-end-tag-before-html
+(1,18): unexpected-end-tag-before-html
+(1,22): unexpected-end-tag-before-html
+(1,26): unexpected-end-tag-before-html
+(1,35): unexpected-end-tag-before-html
+(1,39): unexpected-end-tag-before-html
+(1,47): unexpected-end-tag-before-html
+(1,52): unexpected-end-tag-before-html
+(1,58): unexpected-end-tag-before-html
+(1,64): unexpected-end-tag-before-html
+(1,72): unexpected-end-tag-before-html
+(1,79): unexpected-end-tag-before-html
+(1,88): unexpected-end-tag-before-html
+(1,93): unexpected-end-tag-before-html
+(1,98): unexpected-end-tag-before-html
+(1,103): unexpected-end-tag-before-html
+(1,108): unexpected-end-tag-before-html
+(1,113): unexpected-end-tag-before-html
+(1,118): unexpected-end-tag-before-html
+(1,130): unexpected-end-tag-after-body
+(1,130): unexpected-end-tag-treated-as
+(1,134): unexpected-end-tag
+(1,140): unexpected-end-tag
+(1,148): unexpected-end-tag
+(1,155): unexpected-end-tag
+(1,163): unexpected-end-tag
+(1,172): unexpected-end-tag
+(1,180): unexpected-end-tag
+(1,185): unexpected-end-tag
+(1,190): unexpected-end-tag
+(1,195): unexpected-end-tag
+(1,203): unexpected-end-tag
+(1,210): unexpected-end-tag
+(1,217): unexpected-end-tag
+(1,225): unexpected-end-tag
+(1,230): unexpected-end-tag
+(1,238): unexpected-end-tag
+(1,244): unexpected-end-tag
+(1,251): unexpected-end-tag
+(1,258): unexpected-end-tag
+(1,269): unexpected-end-tag
+(1,279): unexpected-end-tag
+(1,287): unexpected-end-tag
+(1,296): unexpected-end-tag
+(1,300): unexpected-end-tag
+(1,305): unexpected-end-tag
+(1,310): unexpected-end-tag
+(1,320): unexpected-end-tag
+(1,331): unexpected-end-tag
+(1,339): unexpected-end-tag
+(1,347): unexpected-end-tag
+(1,355): unexpected-end-tag
+(1,365): end-tag-too-early
+(1,378): end-tag-too-early
+(1,387): end-tag-too-early
+(1,393): end-tag-too-early
+(1,399): end-tag-too-early
+(1,404): end-tag-too-early
+(1,415): end-tag-too-early
+(1,425): end-tag-too-early
+(1,432): end-tag-too-early
+(1,437): end-tag-too-early
+(1,442): end-tag-too-early
+(1,447): unexpected-end-tag
+(1,454): unexpected-end-tag
+(1,460): unexpected-end-tag
+(1,467): unexpected-end-tag
+(1,476): end-tag-too-early
+(1,486): end-tag-too-early
+(1,495): end-tag-too-early
+(1,513): expected-eof-but-got-end-tag
+(1,513): unexpected-end-tag
+(1,520): unexpected-end-tag
+(1,529): unexpected-end-tag
+(1,537): unexpected-end-tag
+(1,547): unexpected-end-tag
+(1,557): unexpected-end-tag
+(1,568): unexpected-end-tag
+(1,579): unexpected-end-tag
+(1,590): unexpected-end-tag
+(1,599): unexpected-end-tag
+(1,611): unexpected-end-tag
+(1,622): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+| <p>
+
+#data
+<table><tr></strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,20): unexpected-end-tag-implies-table-voodoo
+(1,20): unexpected-end-tag
+(1,24): unexpected-end-tag-implies-table-voodoo
+(1,24): unexpected-end-tag
+(1,29): unexpected-end-tag-implies-table-voodoo
+(1,29): unexpected-end-tag
+(1,33): unexpected-end-tag-implies-table-voodoo
+(1,33): unexpected-end-tag
+(1,37): unexpected-end-tag-implies-table-voodoo
+(1,37): unexpected-end-tag
+(1,46): unexpected-end-tag-implies-table-voodoo
+(1,46): unexpected-end-tag
+(1,50): unexpected-end-tag-implies-table-voodoo
+(1,50): unexpected-end-tag
+(1,58): unexpected-end-tag-implies-table-voodoo
+(1,58): unexpected-end-tag
+(1,63): unexpected-end-tag-implies-table-voodoo
+(1,63): unexpected-end-tag
+(1,69): unexpected-end-tag-implies-table-voodoo
+(1,69): end-tag-too-early
+(1,75): unexpected-end-tag-implies-table-voodoo
+(1,75): unexpected-end-tag
+(1,83): unexpected-end-tag-implies-table-voodoo
+(1,83): unexpected-end-tag
+(1,90): unexpected-end-tag-implies-table-voodoo
+(1,90): unexpected-end-tag
+(1,99): unexpected-end-tag-implies-table-voodoo
+(1,99): unexpected-end-tag
+(1,104): unexpected-end-tag-implies-table-voodoo
+(1,104): end-tag-too-early
+(1,109): unexpected-end-tag-implies-table-voodoo
+(1,109): end-tag-too-early
+(1,114): unexpected-end-tag-implies-table-voodoo
+(1,114): end-tag-too-early
+(1,119): unexpected-end-tag-implies-table-voodoo
+(1,119): end-tag-too-early
+(1,124): unexpected-end-tag-implies-table-voodoo
+(1,124): end-tag-too-early
+(1,129): unexpected-end-tag-implies-table-voodoo
+(1,129): end-tag-too-early
+(1,136): unexpected-end-tag-in-table-row
+(1,141): unexpected-end-tag-implies-table-voodoo
+(1,141): unexpected-end-tag-treated-as
+(1,145): unexpected-end-tag-implies-table-voodoo
+(1,145): unexpected-end-tag
+(1,151): unexpected-end-tag-implies-table-voodoo
+(1,151): unexpected-end-tag
+(1,159): unexpected-end-tag-implies-table-voodoo
+(1,159): unexpected-end-tag
+(1,166): unexpected-end-tag-implies-table-voodoo
+(1,166): unexpected-end-tag
+(1,174): unexpected-end-tag-implies-table-voodoo
+(1,174): unexpected-end-tag
+(1,183): unexpected-end-tag-implies-table-voodoo
+(1,183): unexpected-end-tag
+(1,196): unexpected-end-tag
+(1,201): unexpected-end-tag
+(1,206): unexpected-end-tag
+(1,214): unexpected-end-tag
+(1,221): unexpected-end-tag
+(1,228): unexpected-end-tag
+(1,236): unexpected-end-tag
+(1,241): unexpected-end-tag
+(1,249): unexpected-end-tag
+(1,255): unexpected-end-tag
+(1,262): unexpected-end-tag
+(1,269): unexpected-end-tag
+(1,280): unexpected-end-tag
+(1,290): unexpected-end-tag
+(1,298): unexpected-end-tag
+(1,307): unexpected-end-tag
+(1,311): unexpected-end-tag
+(1,316): unexpected-end-tag
+(1,321): unexpected-end-tag
+(1,331): unexpected-end-tag
+(1,342): unexpected-end-tag
+(1,350): unexpected-end-tag
+(1,358): unexpected-end-tag
+(1,366): unexpected-end-tag
+(1,376): end-tag-too-early
+(1,389): end-tag-too-early
+(1,398): end-tag-too-early
+(1,404): end-tag-too-early
+(1,410): end-tag-too-early
+(1,415): end-tag-too-early
+(1,426): end-tag-too-early
+(1,436): end-tag-too-early
+(1,443): end-tag-too-early
+(1,448): end-tag-too-early
+(1,453): end-tag-too-early
+(1,458): unexpected-end-tag
+(1,465): unexpected-end-tag
+(1,471): unexpected-end-tag
+(1,478): unexpected-end-tag
+(1,487): end-tag-too-early
+(1,497): end-tag-too-early
+(1,506): end-tag-too-early
+(1,524): expected-eof-but-got-end-tag
+(1,524): unexpected-end-tag
+(1,531): unexpected-end-tag
+(1,540): unexpected-end-tag
+(1,548): unexpected-end-tag
+(1,558): unexpected-end-tag
+(1,568): unexpected-end-tag
+(1,579): unexpected-end-tag
+(1,590): unexpected-end-tag
+(1,601): unexpected-end-tag
+(1,610): unexpected-end-tag
+(1,622): unexpected-end-tag
+(1,633): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+| <table>
+| <tbody>
+| <tr>
+| <p>
+
+#data
+<frameset>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,10): eof-in-frameset
+#document
+| <html>
+| <head>
+| <frameset>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests10.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests10.dat
new file mode 100644
index 0000000000..87d94786b1
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests10.dat
@@ -0,0 +1,847 @@
+#data
+<!DOCTYPE html><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<!DOCTYPE html><svg></svg><![CDATA[a]]>
+#errors
+(1,28) expected-dashes-or-doctype
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <!-- [CDATA[a]] -->
+
+#data
+<!DOCTYPE html><body><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<!DOCTYPE html><body><select><svg></svg></select>
+#errors
+(1,34) unexpected-start-tag-in-select
+(1,40) unexpected-end-tag-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!DOCTYPE html><body><select><option><svg></svg></option></select>
+#errors
+(1,42) unexpected-start-tag-in-select
+(1,48) unexpected-end-tag-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!DOCTYPE html><body><table><svg></svg></table>
+#errors
+(1,33) foster-parenting-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g></svg></table>
+#errors
+(1,33) foster-parenting-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g><g>bar</g></svg></table>
+#errors
+(1,33) foster-parenting-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><svg><g>foo</g><g>bar</g></svg></tbody></table>
+#errors
+(1,40) foster-parenting-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+| <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><svg><g>foo</g><g>bar</g></svg></tr></tbody></table>
+#errors
+(1,44) foster-parenting-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g></svg><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+(1,65) unexpected-html-element-in-foreign-content
+(1,76) XXX-undefined-error
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g>baz</table><p>quux
+#errors
+(1,73) unexpected-end-tag
+(1,73) expected-one-end-tag-but-got-another
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+(1,43) foster-parenting-start-tag
+(1,66) foster-parenting-start-tag
+(1,67) foster-parenting-character
+(1,68) foster-parenting-character
+(1,69) foster-parenting-character
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+| <table>
+| <colgroup>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+(1,49) unexpected-start-tag-in-select
+(1,52) unexpected-start-tag-in-select
+(1,59) unexpected-end-tag-in-select
+(1,62) unexpected-start-tag-in-select
+(1,69) unexpected-end-tag-in-select
+(1,72) unexpected-start-tag-in-select
+(1,83) unexpected-table-element-end-tag-in-select-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| "foobarbaz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+(1,36) unexpected-start-tag-implies-table-voodoo
+(1,41) unexpected-start-tag-in-select
+(1,44) unexpected-start-tag-in-select
+(1,51) unexpected-end-tag-in-select
+(1,54) unexpected-start-tag-in-select
+(1,61) unexpected-end-tag-in-select
+(1,64) unexpected-start-tag-in-select
+(1,75) unexpected-table-element-end-tag-in-select-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "foobarbaz"
+| <table>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body></body></html><svg><g>foo</g><g>bar</g><p>baz
+#errors
+(1,40) expected-eof-but-got-start-tag
+(1,63) unexpected-html-element-in-foreign-content
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body></body><svg><g>foo</g><g>bar</g><p>baz
+#errors
+(1,33) unexpected-start-tag-after-body
+(1,56) unexpected-html-element-in-foreign-content
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><frameset><svg><g></g><g></g><p><span>
+#errors
+(1,30) unexpected-start-tag-in-frameset
+(1,33) unexpected-start-tag-in-frameset
+(1,37) unexpected-end-tag-in-frameset
+(1,40) unexpected-start-tag-in-frameset
+(1,44) unexpected-end-tag-in-frameset
+(1,47) unexpected-start-tag-in-frameset
+(1,53) unexpected-start-tag-in-frameset
+(1,53) eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><svg><g></g><g></g><p><span>
+#errors
+(1,41) unexpected-start-tag-after-frameset
+(1,44) unexpected-start-tag-after-frameset
+(1,48) unexpected-end-tag-after-frameset
+(1,51) unexpected-start-tag-after-frameset
+(1,55) unexpected-end-tag-after-frameset
+(1,58) unexpected-start-tag-after-frameset
+(1,64) unexpected-start-tag-after-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><svg xlink:href=foo></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| <svg svg>
+| xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo></g></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo />bar</svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+| "bar"
+
+#data
+<svg></path>
+#errors
+(1,5) expected-doctype-but-got-start-tag
+(1,12) unexpected-end-tag
+(1,12) unexpected-end-tag
+(1,12) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<div><svg></div>a
+#errors
+(1,5) expected-doctype-but-got-start-tag
+(1,16) unexpected-end-tag
+(1,16) end-tag-too-early
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| "a"
+
+#data
+<div><svg><path></div>a
+#errors
+(1,5) expected-doctype-but-got-start-tag
+(1,22) unexpected-end-tag
+(1,22) end-tag-too-early
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| "a"
+
+#data
+<div><svg><path></svg><path>
+#errors
+(1,5) expected-doctype-but-got-start-tag
+(1,22) unexpected-end-tag
+(1,28) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <path>
+
+#data
+<div><svg><path><foreignObject><math></div>a
+#errors
+(1,5) expected-doctype-but-got-start-tag
+(1,43) unexpected-end-tag
+(1,43) end-tag-too-early
+(1,44) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <math math>
+| "a"
+
+#data
+<div><svg><path><foreignObject><p></div>a
+#errors
+(1,5) expected-doctype-but-got-start-tag
+(1,40) end-tag-too-early
+(1,41) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <p>
+| "a"
+
+#data
+<!DOCTYPE html><svg><desc><div><svg><ul>a
+#errors
+(1,40) unexpected-html-element-in-foreign-content
+(1,41) expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg desc>
+| <div>
+| <svg svg>
+| <ul>
+| "a"
+
+#data
+<!DOCTYPE html><svg><desc><svg><ul>a
+#errors
+(1,35) unexpected-html-element-in-foreign-content
+(1,36) expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg desc>
+| <svg svg>
+| <ul>
+| "a"
+
+#data
+<!DOCTYPE html><p><svg><desc><p>
+#errors
+(1,32) expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <svg svg>
+| <svg desc>
+| <p>
+
+#data
+<!DOCTYPE html><p><svg><title><p>
+#errors
+(1,33) expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <svg svg>
+| <svg title>
+| <p>
+
+#data
+<div><svg><path><foreignObject><p></foreignObject><p>
+#errors
+(1,5) expected-doctype-but-got-start-tag
+(1,50) unexpected-end-tag
+(1,53) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <p>
+| <p>
+
+#data
+<math><mi><div><object><div><span></span></div></object></div></mi><mi>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,71) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <div>
+| <object>
+| <div>
+| <span>
+| <math mi>
+
+#data
+<math><mi><svg><foreignObject><div><div></div></div></foreignObject></svg></mi><mi>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,83) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <svg svg>
+| <svg foreignObject>
+| <div>
+| <div>
+| <math mi>
+
+#data
+<svg><script></script><path>
+#errors
+(1,5) expected-doctype-but-got-start-tag
+(1,28) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg script>
+| <svg path>
+
+#data
+<table><svg></svg><tr>
+#errors
+(1,7) expected-doctype-but-got-start-tag
+(1,12) unexpected-start-tag-implies-table-voodoo
+(1,22) eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<math><mi><mglyph>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,18) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <math mglyph>
+
+#data
+<math><mi><malignmark>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,22) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <math malignmark>
+
+#data
+<math><mo><mglyph>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,18) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mo>
+| <math mglyph>
+
+#data
+<math><mo><malignmark>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,22) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mo>
+| <math malignmark>
+
+#data
+<math><mn><mglyph>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,18) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mn>
+| <math mglyph>
+
+#data
+<math><mn><malignmark>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,22) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mn>
+| <math malignmark>
+
+#data
+<math><ms><mglyph>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,18) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math ms>
+| <math mglyph>
+
+#data
+<math><ms><malignmark>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,22) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math ms>
+| <math malignmark>
+
+#data
+<math><mtext><mglyph>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,21) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mtext>
+| <math mglyph>
+
+#data
+<math><mtext><malignmark>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,25) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mtext>
+| <math malignmark>
+
+#data
+<math><annotation-xml><svg></svg></annotation-xml><mi>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,54) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><div><math><mi></mi></math><span></span></div></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,144) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <svg foreignObject>
+| <div>
+| <math math>
+| <math mi>
+| <span>
+| <svg path>
+| <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><math><mi><svg></svg></mi><mo></mo></math><span></span></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+(1,6) expected-doctype-but-got-start-tag
+(1,153) expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <svg foreignObject>
+| <math math>
+| <math mi>
+| <svg svg>
+| <math mo>
+| <span>
+| <svg path>
+| <math mi>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests11.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests11.dat
new file mode 100644
index 0000000000..ad62cdf659
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests11.dat
@@ -0,0 +1,482 @@
+#data
+<!DOCTYPE html><body><svg attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentscripttype=""
+| contentstyletype=""
+| diffuseConstant=""
+| edgeMode=""
+| externalresourcesrequired=""
+| filterUnits=""
+| filterres=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><BODY><SVG ATTRIBUTENAME='' ATTRIBUTETYPE='' BASEFREQUENCY='' BASEPROFILE='' CALCMODE='' CLIPPATHUNITS='' CONTENTSCRIPTTYPE='' CONTENTSTYLETYPE='' DIFFUSECONSTANT='' EDGEMODE='' EXTERNALRESOURCESREQUIRED='' FILTERRES='' FILTERUNITS='' GLYPHREF='' GRADIENTTRANSFORM='' GRADIENTUNITS='' KERNELMATRIX='' KERNELUNITLENGTH='' KEYPOINTS='' KEYSPLINES='' KEYTIMES='' LENGTHADJUST='' LIMITINGCONEANGLE='' MARKERHEIGHT='' MARKERUNITS='' MARKERWIDTH='' MASKCONTENTUNITS='' MASKUNITS='' NUMOCTAVES='' PATHLENGTH='' PATTERNCONTENTUNITS='' PATTERNTRANSFORM='' PATTERNUNITS='' POINTSATX='' POINTSATY='' POINTSATZ='' PRESERVEALPHA='' PRESERVEASPECTRATIO='' PRIMITIVEUNITS='' REFX='' REFY='' REPEATCOUNT='' REPEATDUR='' REQUIREDEXTENSIONS='' REQUIREDFEATURES='' SPECULARCONSTANT='' SPECULAREXPONENT='' SPREADMETHOD='' STARTOFFSET='' STDDEVIATION='' STITCHTILES='' SURFACESCALE='' SYSTEMLANGUAGE='' TABLEVALUES='' TARGETX='' TARGETY='' TEXTLENGTH='' VIEWBOX='' VIEWTARGET='' XCHANNELSELECTOR='' YCHANNELSELECTOR='' ZOOMANDPAN=''></SVG>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentscripttype=""
+| contentstyletype=""
+| diffuseConstant=""
+| edgeMode=""
+| externalresourcesrequired=""
+| filterUnits=""
+| filterres=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><body><svg attributename='' attributetype='' basefrequency='' baseprofile='' calcmode='' clippathunits='' contentscripttype='' contentstyletype='' diffuseconstant='' edgemode='' externalresourcesrequired='' filterres='' filterunits='' glyphref='' gradienttransform='' gradientunits='' kernelmatrix='' kernelunitlength='' keypoints='' keysplines='' keytimes='' lengthadjust='' limitingconeangle='' markerheight='' markerunits='' markerwidth='' maskcontentunits='' maskunits='' numoctaves='' pathlength='' patterncontentunits='' patterntransform='' patternunits='' pointsatx='' pointsaty='' pointsatz='' preservealpha='' preserveaspectratio='' primitiveunits='' refx='' refy='' repeatcount='' repeatdur='' requiredextensions='' requiredfeatures='' specularconstant='' specularexponent='' spreadmethod='' startoffset='' stddeviation='' stitchtiles='' surfacescale='' systemlanguage='' tablevalues='' targetx='' targety='' textlength='' viewbox='' viewtarget='' xchannelselector='' ychannelselector='' zoomandpan=''></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentscripttype=""
+| contentstyletype=""
+| diffuseConstant=""
+| edgeMode=""
+| externalresourcesrequired=""
+| filterUnits=""
+| filterres=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><body><math attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| attributename=""
+| attributetype=""
+| basefrequency=""
+| baseprofile=""
+| calcmode=""
+| clippathunits=""
+| contentscripttype=""
+| contentstyletype=""
+| diffuseconstant=""
+| edgemode=""
+| externalresourcesrequired=""
+| filterres=""
+| filterunits=""
+| glyphref=""
+| gradienttransform=""
+| gradientunits=""
+| kernelmatrix=""
+| kernelunitlength=""
+| keypoints=""
+| keysplines=""
+| keytimes=""
+| lengthadjust=""
+| limitingconeangle=""
+| markerheight=""
+| markerunits=""
+| markerwidth=""
+| maskcontentunits=""
+| maskunits=""
+| numoctaves=""
+| pathlength=""
+| patterncontentunits=""
+| patterntransform=""
+| patternunits=""
+| pointsatx=""
+| pointsaty=""
+| pointsatz=""
+| preservealpha=""
+| preserveaspectratio=""
+| primitiveunits=""
+| refx=""
+| refy=""
+| repeatcount=""
+| repeatdur=""
+| requiredextensions=""
+| requiredfeatures=""
+| specularconstant=""
+| specularexponent=""
+| spreadmethod=""
+| startoffset=""
+| stddeviation=""
+| stitchtiles=""
+| surfacescale=""
+| systemlanguage=""
+| tablevalues=""
+| targetx=""
+| targety=""
+| textlength=""
+| viewbox=""
+| viewtarget=""
+| xchannelselector=""
+| ychannelselector=""
+| zoomandpan=""
+
+#data
+<!DOCTYPE html><body><svg><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><body><svg><altglyph /><altglyphdef /><altglyphitem /><animatecolor /><animatemotion /><animatetransform /><clippath /><feblend /><fecolormatrix /><fecomponenttransfer /><fecomposite /><feconvolvematrix /><fediffuselighting /><fedisplacementmap /><fedistantlight /><feflood /><fefunca /><fefuncb /><fefuncg /><fefuncr /><fegaussianblur /><feimage /><femerge /><femergenode /><femorphology /><feoffset /><fepointlight /><fespecularlighting /><fespotlight /><fetile /><feturbulence /><foreignobject /><glyphref /><lineargradient /><radialgradient /><textpath /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><BODY><SVG><ALTGLYPH /><ALTGLYPHDEF /><ALTGLYPHITEM /><ANIMATECOLOR /><ANIMATEMOTION /><ANIMATETRANSFORM /><CLIPPATH /><FEBLEND /><FECOLORMATRIX /><FECOMPONENTTRANSFER /><FECOMPOSITE /><FECONVOLVEMATRIX /><FEDIFFUSELIGHTING /><FEDISPLACEMENTMAP /><FEDISTANTLIGHT /><FEFLOOD /><FEFUNCA /><FEFUNCB /><FEFUNCG /><FEFUNCR /><FEGAUSSIANBLUR /><FEIMAGE /><FEMERGE /><FEMERGENODE /><FEMORPHOLOGY /><FEOFFSET /><FEPOINTLIGHT /><FESPECULARLIGHTING /><FESPOTLIGHT /><FETILE /><FETURBULENCE /><FOREIGNOBJECT /><GLYPHREF /><LINEARGRADIENT /><RADIALGRADIENT /><TEXTPATH /></SVG>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><body><math><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math altglyph>
+| <math altglyphdef>
+| <math altglyphitem>
+| <math animatecolor>
+| <math animatemotion>
+| <math animatetransform>
+| <math clippath>
+| <math feblend>
+| <math fecolormatrix>
+| <math fecomponenttransfer>
+| <math fecomposite>
+| <math feconvolvematrix>
+| <math fediffuselighting>
+| <math fedisplacementmap>
+| <math fedistantlight>
+| <math feflood>
+| <math fefunca>
+| <math fefuncb>
+| <math fefuncg>
+| <math fefuncr>
+| <math fegaussianblur>
+| <math feimage>
+| <math femerge>
+| <math femergenode>
+| <math femorphology>
+| <math feoffset>
+| <math fepointlight>
+| <math fespecularlighting>
+| <math fespotlight>
+| <math fetile>
+| <math feturbulence>
+| <math foreignobject>
+| <math glyphref>
+| <math lineargradient>
+| <math radialgradient>
+| <math textpath>
+
+#data
+<!DOCTYPE html><body><svg><solidColor /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg solidcolor>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests12.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests12.dat
new file mode 100644
index 0000000000..63107d277b
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests12.dat
@@ -0,0 +1,62 @@
+#data
+<!DOCTYPE html><body><p>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "foo"
+| <math math>
+| <math mtext>
+| <i>
+| "baz"
+| <math annotation-xml>
+| <svg svg>
+| <svg desc>
+| <b>
+| "eggs"
+| <svg g>
+| <svg foreignObject>
+| <p>
+| "spam"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <img>
+| <svg g>
+| "quux"
+| "bar"
+
+#data
+<!DOCTYPE html><body>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "foo"
+| <math math>
+| <math mtext>
+| <i>
+| "baz"
+| <math annotation-xml>
+| <svg svg>
+| <svg desc>
+| <b>
+| "eggs"
+| <svg g>
+| <svg foreignObject>
+| <p>
+| "spam"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <img>
+| <svg g>
+| "quux"
+| "bar"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests14.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests14.dat
new file mode 100644
index 0000000000..a08b7649eb
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests14.dat
@@ -0,0 +1,75 @@
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xyz:abc>
+
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc><span></span>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xyz:abc>
+| <span>
+
+#data
+<!DOCTYPE html><html><html abc:def=gh><xyz:abc></xyz:abc>
+#errors
+(1,38): non-html-root
+#document
+| <!DOCTYPE html>
+| <html>
+| abc:def="gh"
+| <head>
+| <body>
+| <xyz:abc>
+
+#data
+<!DOCTYPE html><html xml:lang=bar><html xml:lang=foo>
+#errors
+(1,53): non-html-root
+#document
+| <!DOCTYPE html>
+| <html>
+| xml:lang="bar"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html 123=456>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| 123="456"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html 123=456><html 789=012>
+#errors
+(1,43): non-html-root
+#document
+| <!DOCTYPE html>
+| <html>
+| 123="456"
+| 789="012"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html><body 789=012>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| 789="012"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests15.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests15.dat
new file mode 100644
index 0000000000..93d06a8717
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests15.dat
@@ -0,0 +1,216 @@
+#data
+<!DOCTYPE html><p><b><i><u></p> <p>X
+#errors
+(1,31): unexpected-end-tag
+(1,36): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <i>
+| <u>
+| <b>
+| <i>
+| <u>
+| " "
+| <p>
+| "X"
+
+#data
+<p><b><i><u></p>
+<p>X
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,16): unexpected-end-tag
+(2,4): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <i>
+| <u>
+| <b>
+| <i>
+| <u>
+| "
+"
+| <p>
+| "X"
+
+#data
+<!doctype html></html> <head>
+#errors
+(1,29): expected-eof-but-got-start-tag
+(1,29): unexpected-start-tag-ignored
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " "
+
+#data
+<!doctype html></body><meta>
+#errors
+(1,28): unexpected-start-tag-after-body
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <meta>
+
+#data
+<html></html><!-- foo -->
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <!-- foo -->
+
+#data
+<!doctype html></body><title>X</title>
+#errors
+(1,29): unexpected-start-tag-after-body
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+
+#data
+<!doctype html><table> X<meta></table>
+#errors
+(1,23): foster-parenting-character
+(1,24): foster-parenting-character
+(1,30): foster-parenting-start-character
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " X"
+| <meta>
+| <table>
+
+#data
+<!doctype html><table> x</table>
+#errors
+(1,23): foster-parenting-character
+(1,24): foster-parenting-character
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x"
+| <table>
+
+#data
+<!doctype html><table> x </table>
+#errors
+(1,23): foster-parenting-character
+(1,24): foster-parenting-character
+(1,25): foster-parenting-character
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x "
+| <table>
+
+#data
+<!doctype html><table><tr> x</table>
+#errors
+(1,27): foster-parenting-character
+(1,28): foster-parenting-character
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table>X<style> <tr>x </style> </table>
+#errors
+(1,23): foster-parenting-character
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <style>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div>
+#errors
+(1,30): foster-parenting-start-tag
+(1,31): foster-parenting-character
+(1,32): foster-parenting-character
+(1,33): foster-parenting-character
+(1,37): foster-parenting-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <a>
+| "foo"
+| <table>
+| " "
+| <tbody>
+| <tr>
+| <td>
+| "bar"
+| " "
+
+#data
+<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,7): unexpected-start-tag-ignored
+(1,15): unexpected-end-tag
+(1,23): unexpected-end-tag
+(1,33): unexpected-start-tag
+(1,99): expected-named-closing-tag-but-got-eof
+(1,99): eof-in-frameset
+#document
+| <html>
+| <head>
+| <frameset>
+| <frame>
+| <frameset>
+| <frame>
+| <noframes>
+| "</frameset><noframes>"
+
+#data
+<!DOCTYPE html><object></html>
+#errors
+(1,30): expected-body-in-scope
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <object>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests16.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests16.dat
new file mode 100644
index 0000000000..1c57f14a32
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests16.dat
@@ -0,0 +1,2396 @@
+#data
+<!doctype html><script>
+#errors
+(1,23): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script>a
+#errors
+(1,24): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "a"
+| <body>
+
+#data
+<!doctype html><script><
+#errors
+(1,24): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<"
+| <body>
+
+#data
+<!doctype html><script></
+#errors
+(1,25): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</"
+| <body>
+
+#data
+<!doctype html><script></S
+#errors
+(1,26): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</S"
+| <body>
+
+#data
+<!doctype html><script></SC
+#errors
+(1,27): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SC"
+| <body>
+
+#data
+<!doctype html><script></SCR
+#errors
+(1,28): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCR"
+| <body>
+
+#data
+<!doctype html><script></SCRI
+#errors
+(1,29): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRI"
+| <body>
+
+#data
+<!doctype html><script></SCRIP
+#errors
+(1,30): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRIP"
+| <body>
+
+#data
+<!doctype html><script></SCRIPT
+#errors
+(1,31): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRIPT"
+| <body>
+
+#data
+<!doctype html><script></SCRIPT
+#errors
+(1,32): expected-attribute-name-but-got-eof
+(1,32): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script></s
+#errors
+(1,26): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</s"
+| <body>
+
+#data
+<!doctype html><script></sc
+#errors
+(1,27): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</sc"
+| <body>
+
+#data
+<!doctype html><script></scr
+#errors
+(1,28): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scr"
+| <body>
+
+#data
+<!doctype html><script></scri
+#errors
+(1,29): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scri"
+| <body>
+
+#data
+<!doctype html><script></scrip
+#errors
+(1,30): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scrip"
+| <body>
+
+#data
+<!doctype html><script></script
+#errors
+(1,31): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</script"
+| <body>
+
+#data
+<!doctype html><script></script
+#errors
+(1,32): expected-attribute-name-but-got-eof
+(1,32): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script><!
+#errors
+(1,25): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!"
+| <body>
+
+#data
+<!doctype html><script><!a
+#errors
+(1,26): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!a"
+| <body>
+
+#data
+<!doctype html><script><!-
+#errors
+(1,26): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!-"
+| <body>
+
+#data
+<!doctype html><script><!-a
+#errors
+(1,27): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!-a"
+| <body>
+
+#data
+<!doctype html><script><!--
+#errors
+(1,27): expected-named-closing-tag-but-got-eof
+(1,27): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<!doctype html><script><!--a
+#errors
+(1,28): expected-named-closing-tag-but-got-eof
+(1,28): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--a"
+| <body>
+
+#data
+<!doctype html><script><!--<
+#errors
+(1,28): expected-named-closing-tag-but-got-eof
+(1,28): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<"
+| <body>
+
+#data
+<!doctype html><script><!--<a
+#errors
+(1,29): expected-named-closing-tag-but-got-eof
+(1,29): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<a"
+| <body>
+
+#data
+<!doctype html><script><!--</
+#errors
+(1,29): expected-named-closing-tag-but-got-eof
+(1,29): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--</"
+| <body>
+
+#data
+<!doctype html><script><!--</script
+#errors
+(1,35): expected-named-closing-tag-but-got-eof
+(1,35): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--</script"
+| <body>
+
+#data
+<!doctype html><script><!--</script
+#errors
+(1,36): expected-attribute-name-but-got-eof
+(1,36): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<!doctype html><script><!--<s
+#errors
+(1,29): expected-named-closing-tag-but-got-eof
+(1,29): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<s"
+| <body>
+
+#data
+<!doctype html><script><!--<script
+#errors
+(1,34): expected-named-closing-tag-but-got-eof
+(1,34): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script"
+| <body>
+
+#data
+<!doctype html><script><!--<script
+#errors
+(1,35): eof-in-script-in-script
+(1,35): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script "
+| <body>
+
+#data
+<!doctype html><script><!--<script <
+#errors
+(1,36): eof-in-script-in-script
+(1,36): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script <"
+| <body>
+
+#data
+<!doctype html><script><!--<script <a
+#errors
+(1,37): eof-in-script-in-script
+(1,37): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script <a"
+| <body>
+
+#data
+<!doctype html><script><!--<script </
+#errors
+(1,37): eof-in-script-in-script
+(1,37): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </"
+| <body>
+
+#data
+<!doctype html><script><!--<script </s
+#errors
+(1,38): eof-in-script-in-script
+(1,38): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </s"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script
+#errors
+(1,43): eof-in-script-in-script
+(1,43): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script"
+| <body>
+
+#data
+<!doctype html><script><!--<script </scripta
+#errors
+(1,44): eof-in-script-in-script
+(1,44): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </scripta"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script
+#errors
+(1,44): expected-named-closing-tag-but-got-eof
+(1,44): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script>
+#errors
+(1,44): expected-named-closing-tag-but-got-eof
+(1,44): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script>"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script/
+#errors
+(1,44): expected-named-closing-tag-but-got-eof
+(1,44): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script/"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script <
+#errors
+(1,45): expected-named-closing-tag-but-got-eof
+(1,45): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script <a
+#errors
+(1,46): expected-named-closing-tag-but-got-eof
+(1,46): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <a"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </
+#errors
+(1,46): expected-named-closing-tag-but-got-eof
+(1,46): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script
+#errors
+(1,52): expected-named-closing-tag-but-got-eof
+(1,52): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </script"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script
+#errors
+(1,53): expected-attribute-name-but-got-eof
+(1,53): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script/
+#errors
+(1,53): unexpected-EOF-after-solidus-in-tag
+(1,53): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script -
+#errors
+(1,36): eof-in-script-in-script
+(1,36): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -"
+| <body>
+
+#data
+<!doctype html><script><!--<script -a
+#errors
+(1,37): eof-in-script-in-script
+(1,37): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -a"
+| <body>
+
+#data
+<!doctype html><script><!--<script -<
+#errors
+(1,37): eof-in-script-in-script
+(1,37): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -<"
+| <body>
+
+#data
+<!doctype html><script><!--<script --
+#errors
+(1,37): eof-in-script-in-script
+(1,37): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --"
+| <body>
+
+#data
+<!doctype html><script><!--<script --a
+#errors
+(1,38): eof-in-script-in-script
+(1,38): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --a"
+| <body>
+
+#data
+<!doctype html><script><!--<script --<
+#errors
+(1,38): eof-in-script-in-script
+(1,38): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --<"
+| <body>
+
+#data
+<!doctype html><script><!--<script -->
+#errors
+(1,38): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --><
+#errors
+(1,39): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --><"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></
+#errors
+(1,40): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --></"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script
+#errors
+(1,46): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --></script"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script
+#errors
+(1,47): expected-attribute-name-but-got-eof
+(1,47): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script/
+#errors
+(1,47): unexpected-EOF-after-solidus-in-tag
+(1,47): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script><\/script>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script><\/script>-->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt>-->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>--><!--</script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>--><!--"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-- ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>-- >"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- -></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- ->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- - ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- - >"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>->"
+| <body>
+
+#data
+<!doctype html><script><!--<script>--!></script>X
+#errors
+(1,49): expected-named-closing-tag-but-got-eof
+(1,49): unexpected-EOF-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script>--!></script>X"
+| <body>
+
+#data
+<!doctype html><script><!--<scr'+'ipt></script>--></script>
+#errors
+(1,59): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<scr'+'ipt>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt></script>X
+#errors
+(1,57): expected-named-closing-tag-but-got-eof
+(1,57): unexpected-eof-in-text-mode
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt></script>X"
+| <body>
+
+#data
+<!doctype html><style><!--<style></style>--></style>
+#errors
+(1,52): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--<style>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><style><!--</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "X"
+
+#data
+<!doctype html><style><!--...</style>...--></style>
+#errors
+(1,51): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <body>
+| "...-->"
+
+#data
+<!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+| <body>
+| "X"
+
+#data
+<!doctype html><style><!--...<style><!--...--!></style>--></style>
+#errors
+(1,66): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--...<style><!--...--!>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><style><!--...</style><!-- --><style>@import ...</style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <!-- -->
+| <style>
+| "@import ..."
+| <body>
+
+#data
+<!doctype html><style>...<style><!--...</style><!-- --></style>
+#errors
+(1,63): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "...<style><!--..."
+| <!-- -->
+| <body>
+
+#data
+<!doctype html><style>...<!--[if IE]><style>...</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "...<!--[if IE]><style>..."
+| <body>
+| "X"
+
+#data
+<!doctype html><title><!--<title></title>--></title>
+#errors
+(1,52): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "<!--<title>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><title>&lt;/title></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "</title>"
+| <body>
+
+#data
+<!doctype html><title>foo/title><link></head><body>X
+#errors
+(1,52): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "foo/title><link></head><body>X"
+| <body>
+
+#data
+<!doctype html><noscript><!--<noscript></noscript>--></noscript>
+#errors
+(1,64): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<!--<noscript>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "X"
+| <noscript>
+| "-->"
+
+#data
+<!doctype html><noscript><iframe></noscript>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<iframe>"
+| <body>
+| "X"
+
+#data
+<!doctype html><noframes><!--<noframes></noframes>--></noframes>
+#errors
+(1,64): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noframes>
+| "<!--<noframes>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><noframes><body><script><!--...</script></body></noframes></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noframes>
+| "<body><script><!--...</script></body>"
+| <body>
+
+#data
+<!doctype html><textarea><!--<textarea></textarea>--></textarea>
+#errors
+(1,64): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--<textarea>"
+| "-->"
+
+#data
+<!doctype html><textarea>&lt;/textarea></textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "</textarea>"
+
+#data
+<!doctype html><textarea>&lt;</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<"
+
+#data
+<!doctype html><textarea>a&lt;b</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "a<b"
+
+#data
+<!doctype html><iframe><!--<iframe></iframe>--></iframe>
+#errors
+(1,56): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "<!--<iframe>"
+| "-->"
+
+#data
+<!doctype html><iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "...<!--X->...<!--/X->..."
+
+#data
+<!doctype html><xmp><!--<xmp></xmp>--></xmp>
+#errors
+(1,44): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xmp>
+| "<!--<xmp>"
+| "-->"
+
+#data
+<!doctype html><style></style</style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "</style"
+| <body>
+
+#data
+<!doctype html><style></stylee</style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "</stylee"
+| <body>
+
+#data
+<!doctype html><noembed><!--<noembed></noembed>--></noembed>
+#errors
+(1,60): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <noembed>
+| "<!--<noembed>"
+| "-->"
+
+#data
+<script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,8): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script>a
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,9): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "a"
+| <body>
+
+#data
+<script><
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,9): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<"
+| <body>
+
+#data
+<script></
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,10): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</"
+| <body>
+
+#data
+<script></S
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,11): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</S"
+| <body>
+
+#data
+<script></SC
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,12): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</SC"
+| <body>
+
+#data
+<script></SCR
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,13): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</SCR"
+| <body>
+
+#data
+<script></SCRI
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,14): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRI"
+| <body>
+
+#data
+<script></SCRIP
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,15): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRIP"
+| <body>
+
+#data
+<script></SCRIPT
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,16): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRIPT"
+| <body>
+
+#data
+<script></SCRIPT
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,17): expected-attribute-name-but-got-eof
+(1,17): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script></s
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,11): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</s"
+| <body>
+
+#data
+<script></sc
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,12): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</sc"
+| <body>
+
+#data
+<script></scr
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,13): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</scr"
+| <body>
+
+#data
+<script></scri
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,14): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</scri"
+| <body>
+
+#data
+<script></scrip
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,15): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</scrip"
+| <body>
+
+#data
+<script></script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,16): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</script"
+| <body>
+
+#data
+<script></script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,17): expected-attribute-name-but-got-eof
+(1,17): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script><!
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,10): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!"
+| <body>
+
+#data
+<script><!a
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,11): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!a"
+| <body>
+
+#data
+<script><!-
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,11): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!-"
+| <body>
+
+#data
+<script><!-a
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,12): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!-a"
+| <body>
+
+#data
+<script><!--
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,12): expected-named-closing-tag-but-got-eof
+(1,12): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<script><!--a
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,13): expected-named-closing-tag-but-got-eof
+(1,13): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--a"
+| <body>
+
+#data
+<script><!--<
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,13): expected-named-closing-tag-but-got-eof
+(1,13): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<"
+| <body>
+
+#data
+<script><!--<a
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,14): expected-named-closing-tag-but-got-eof
+(1,14): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<a"
+| <body>
+
+#data
+<script><!--</
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,14): expected-named-closing-tag-but-got-eof
+(1,14): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--</"
+| <body>
+
+#data
+<script><!--</script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,20): expected-named-closing-tag-but-got-eof
+(1,20): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--</script"
+| <body>
+
+#data
+<script><!--</script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,21): expected-attribute-name-but-got-eof
+(1,21): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<script><!--<s
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,14): expected-named-closing-tag-but-got-eof
+(1,14): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<s"
+| <body>
+
+#data
+<script><!--<script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,19): expected-named-closing-tag-but-got-eof
+(1,19): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script"
+| <body>
+
+#data
+<script><!--<script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,20): eof-in-script-in-script
+(1,20): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script "
+| <body>
+
+#data
+<script><!--<script <
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,21): eof-in-script-in-script
+(1,21): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script <"
+| <body>
+
+#data
+<script><!--<script <a
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,22): eof-in-script-in-script
+(1,22): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script <a"
+| <body>
+
+#data
+<script><!--<script </
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,22): eof-in-script-in-script
+(1,22): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </"
+| <body>
+
+#data
+<script><!--<script </s
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,23): eof-in-script-in-script
+(1,23): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </s"
+| <body>
+
+#data
+<script><!--<script </script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,28): eof-in-script-in-script
+(1,28): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script"
+| <body>
+
+#data
+<script><!--<script </scripta
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,29): eof-in-script-in-script
+(1,29): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </scripta"
+| <body>
+
+#data
+<script><!--<script </script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,29): expected-named-closing-tag-but-got-eof
+(1,29): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,29): expected-named-closing-tag-but-got-eof
+(1,29): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script>"
+| <body>
+
+#data
+<script><!--<script </script/
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,29): expected-named-closing-tag-but-got-eof
+(1,29): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script/"
+| <body>
+
+#data
+<script><!--<script </script <
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,30): expected-named-closing-tag-but-got-eof
+(1,30): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <"
+| <body>
+
+#data
+<script><!--<script </script <a
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,31): expected-named-closing-tag-but-got-eof
+(1,31): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <a"
+| <body>
+
+#data
+<script><!--<script </script </
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,31): expected-named-closing-tag-but-got-eof
+(1,31): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </"
+| <body>
+
+#data
+<script><!--<script </script </script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,37): expected-named-closing-tag-but-got-eof
+(1,37): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </script"
+| <body>
+
+#data
+<script><!--<script </script </script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,38): expected-attribute-name-but-got-eof
+(1,38): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script </script/
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,38): unexpected-EOF-after-solidus-in-tag
+(1,38): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script </script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script -
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,21): eof-in-script-in-script
+(1,21): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -"
+| <body>
+
+#data
+<script><!--<script -a
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,22): eof-in-script-in-script
+(1,22): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -a"
+| <body>
+
+#data
+<script><!--<script --
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,22): eof-in-script-in-script
+(1,22): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --"
+| <body>
+
+#data
+<script><!--<script --a
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,23): eof-in-script-in-script
+(1,23): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --a"
+| <body>
+
+#data
+<script><!--<script -->
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,23): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --><
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,24): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --><"
+| <body>
+
+#data
+<script><!--<script --></
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,25): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --></"
+| <body>
+
+#data
+<script><!--<script --></script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,31): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --></script"
+| <body>
+
+#data
+<script><!--<script --></script
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,32): expected-attribute-name-but-got-eof
+(1,32): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --></script/
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,32): unexpected-EOF-after-solidus-in-tag
+(1,32): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --></script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script><\/script>--></script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script><\/script>-->"
+| <body>
+
+#data
+<script><!--<script></scr'+'ipt>--></script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt>-->"
+| <body>
+
+#data
+<script><!--<script></script><script></script></script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>"
+| <body>
+
+#data
+<script><!--<script></script><script></script>--><!--</script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>--><!--"
+| <body>
+
+#data
+<script><!--<script></script><script></script>-- ></script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>-- >"
+| <body>
+
+#data
+<script><!--<script></script><script></script>- -></script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- ->"
+| <body>
+
+#data
+<script><!--<script></script><script></script>- - ></script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- - >"
+| <body>
+
+#data
+<script><!--<script></script><script></script>-></script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>->"
+| <body>
+
+#data
+<script><!--<script>--!></script>X
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,34): expected-named-closing-tag-but-got-eof
+(1,34): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script>--!></script>X"
+| <body>
+
+#data
+<script><!--<scr'+'ipt></script>--></script>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,44): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<scr'+'ipt>"
+| <body>
+| "-->"
+
+#data
+<script><!--<script></scr'+'ipt></script>X
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,42): expected-named-closing-tag-but-got-eof
+(1,42): unexpected-eof-in-text-mode
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt></script>X"
+| <body>
+
+#data
+<style><!--<style></style>--></style>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,37): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <style>
+| "<!--<style>"
+| <body>
+| "-->"
+
+#data
+<style><!--</style>X
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "X"
+
+#data
+<style><!--...</style>...--></style>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,36): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <body>
+| "...-->"
+
+#data
+<style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <style>
+| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+| <body>
+| "X"
+
+#data
+<style><!--...<style><!--...--!></style>--></style>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,51): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <style>
+| "<!--...<style><!--...--!>"
+| <body>
+| "-->"
+
+#data
+<style><!--...</style><!-- --><style>@import ...</style>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <!-- -->
+| <style>
+| "@import ..."
+| <body>
+
+#data
+<style>...<style><!--...</style><!-- --></style>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,48): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <style>
+| "...<style><!--..."
+| <!-- -->
+| <body>
+
+#data
+<style>...<!--[if IE]><style>...</style>X
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <style>
+| "...<!--[if IE]><style>..."
+| <body>
+| "X"
+
+#data
+<title><!--<title></title>--></title>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,37): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <title>
+| "<!--<title>"
+| <body>
+| "-->"
+
+#data
+<title>&lt;/title></title>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <title>
+| "</title>"
+| <body>
+
+#data
+<title>foo/title><link></head><body>X
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,37): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <title>
+| "foo/title><link></head><body>X"
+| <body>
+
+#data
+<noscript><!--<noscript></noscript>--></noscript>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,49): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--<noscript>"
+| <body>
+| "-->"
+
+#data
+<noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "X"
+| <noscript>
+| "-->"
+
+#data
+<noscript><iframe></noscript>X
+#errors
+(1,10): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <noscript>
+| "<iframe>"
+| <body>
+| "X"
+
+#data
+<noframes><!--<noframes></noframes>--></noframes>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,49): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <noframes>
+| "<!--<noframes>"
+| <body>
+| "-->"
+
+#data
+<noframes><body><script><!--...</script></body></noframes></html>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <noframes>
+| "<body><script><!--...</script></body>"
+| <body>
+
+#data
+<textarea><!--<textarea></textarea>--></textarea>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,49): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--<textarea>"
+| "-->"
+
+#data
+<textarea>&lt;/textarea></textarea>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "</textarea>"
+
+#data
+<iframe><!--<iframe></iframe>--></iframe>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,41): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "<!--<iframe>"
+| "-->"
+
+#data
+<iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "...<!--X->...<!--/X->..."
+
+#data
+<xmp><!--<xmp></xmp>--></xmp>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,29): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <xmp>
+| "<!--<xmp>"
+| "-->"
+
+#data
+<noembed><!--<noembed></noembed>--></noembed>
+#errors
+(1,9): expected-doctype-but-got-start-tag
+(1,45): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <noembed>
+| "<!--<noembed>"
+| "-->"
+
+#data
+<!doctype html><table>
+
+#errors
+(2,0): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| "
+"
+
+#data
+<!doctype html><table><td><span><font></span><span>
+#errors
+(1,26): unexpected-cell-in-table-body
+(1,45): unexpected-end-tag
+(1,51): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <span>
+| <font>
+| <font>
+| <span>
+
+#data
+<!doctype html><form><table></form><form></table></form>
+#errors
+(1,35): unexpected-end-tag-implies-table-voodoo
+(1,35): unexpected-end-tag
+(1,41): unexpected-form-in-table
+(1,56): unexpected-end-tag
+(1,56): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <table>
+| <form>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests17.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests17.dat
new file mode 100644
index 0000000000..37a7be4187
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests17.dat
@@ -0,0 +1,180 @@
+#data
+<!doctype html><table><tbody><select><tr>
+#errors
+(1,37): unexpected-start-tag-implies-table-voodoo
+(1,41): unexpected-table-element-start-tag-in-select-in-table
+(1,41): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table><tr><select><td>
+#errors
+(1,34): unexpected-start-tag-implies-table-voodoo
+(1,38): unexpected-table-element-start-tag-in-select-in-table
+(1,38): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<!doctype html><table><tr><td><select><td>
+#errors
+(1,42): unexpected-table-element-start-tag-in-select-in-table
+(1,42): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| <td>
+
+#data
+<!doctype html><table><tr><th><select><td>
+#errors
+(1,42): unexpected-table-element-start-tag-in-select-in-table
+(1,42): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <th>
+| <select>
+| <td>
+
+#data
+<!doctype html><table><caption><select><tr>
+#errors
+(1,43): unexpected-table-element-start-tag-in-select-in-table
+(1,43): XXX-undefined-error
+(1,43): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <select>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><select><tr>
+#errors
+(1,27): unexpected-start-tag-in-select
+(1,27): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><td>
+#errors
+(1,27): unexpected-start-tag-in-select
+(1,27): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><th>
+#errors
+(1,27): unexpected-start-tag-in-select
+(1,27): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><tbody>
+#errors
+(1,30): unexpected-start-tag-in-select
+(1,30): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><thead>
+#errors
+(1,30): unexpected-start-tag-in-select
+(1,30): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><tfoot>
+#errors
+(1,30): unexpected-start-tag-in-select
+(1,30): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><select><caption>
+#errors
+(1,32): unexpected-start-tag-in-select
+(1,32): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><table><tr></table>a
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| "a"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests18.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests18.dat
new file mode 100644
index 0000000000..926bccb387
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests18.dat
@@ -0,0 +1,322 @@
+#data
+<!doctype html><plaintext></plaintext>
+#errors
+(1,38): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!doctype html><table><plaintext></plaintext>
+#errors
+(1,33): foster-parenting-start-tag
+(1,34): foster-parenting-character
+(1,35): foster-parenting-character
+(1,36): foster-parenting-character
+(1,37): foster-parenting-character
+(1,38): foster-parenting-character
+(1,39): foster-parenting-character
+(1,40): foster-parenting-character
+(1,41): foster-parenting-character
+(1,42): foster-parenting-character
+(1,43): foster-parenting-character
+(1,44): foster-parenting-character
+(1,45): foster-parenting-character
+(1,45): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+| <table>
+
+#data
+<!doctype html><table><tbody><plaintext></plaintext>
+#errors
+(1,40): foster-parenting-start-tag
+(1,41): foster-parenting-character
+(1,41): foster-parenting-character
+(1,41): foster-parenting-character
+(1,41): foster-parenting-character
+(1,41): foster-parenting-character
+(1,41): foster-parenting-character
+(1,41): foster-parenting-character
+(1,41): foster-parenting-character
+(1,41): foster-parenting-character
+(1,41): foster-parenting-character
+(1,41): foster-parenting-character
+(1,41): foster-parenting-character
+(1,52): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+| <table>
+| <tbody>
+
+#data
+<!doctype html><table><tbody><tr><plaintext></plaintext>
+#errors
+(1,44): foster-parenting-start-tag
+(1,45): foster-parenting-character
+(1,46): foster-parenting-character
+(1,47): foster-parenting-character
+(1,48): foster-parenting-character
+(1,49): foster-parenting-character
+(1,50): foster-parenting-character
+(1,51): foster-parenting-character
+(1,52): foster-parenting-character
+(1,53): foster-parenting-character
+(1,54): foster-parenting-character
+(1,55): foster-parenting-character
+(1,56): foster-parenting-character
+(1,56): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table><td><plaintext></plaintext>
+#errors
+(1,26): unexpected-cell-in-table-body
+(1,49): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!doctype html><table><caption><plaintext></plaintext>
+#errors
+(1,54): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!doctype html><table><tr><style></script></style>abc
+#errors
+(1,51): foster-parenting-character
+(1,52): foster-parenting-character
+(1,53): foster-parenting-character
+(1,53): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "abc"
+| <table>
+| <tbody>
+| <tr>
+| <style>
+| "</script>"
+
+#data
+<!doctype html><table><tr><script></style></script>abc
+#errors
+(1,52): foster-parenting-character
+(1,53): foster-parenting-character
+(1,54): foster-parenting-character
+(1,54): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "abc"
+| <table>
+| <tbody>
+| <tr>
+| <script>
+| "</style>"
+
+#data
+<!doctype html><table><caption><style></script></style>abc
+#errors
+(1,58): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <style>
+| "</script>"
+| "abc"
+
+#data
+<!doctype html><table><td><style></script></style>abc
+#errors
+(1,26): unexpected-cell-in-table-body
+(1,53): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <style>
+| "</script>"
+| "abc"
+
+#data
+<!doctype html><select><script></style></script>abc
+#errors
+(1,51): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <script>
+| "</style>"
+| "abc"
+
+#data
+<!doctype html><table><select><script></style></script>abc
+#errors
+(1,30): unexpected-start-tag-implies-table-voodoo
+(1,58): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <script>
+| "</style>"
+| "abc"
+| <table>
+
+#data
+<!doctype html><table><tr><select><script></style></script>abc
+#errors
+(1,34): unexpected-start-tag-implies-table-voodoo
+(1,62): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <script>
+| "</style>"
+| "abc"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><frameset></frameset><noframes>abc
+#errors
+(1,49): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+
+#data
+<!doctype html><frameset></frameset><noframes>abc</noframes><!--abc-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+| <!-- abc -->
+
+#data
+<!doctype html><frameset></frameset></html><noframes>abc
+#errors
+(1,56): expected-named-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+
+#data
+<!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <noframes>
+| "abc"
+| <!-- abc -->
+
+#data
+<!doctype html><table><tr></tbody><tfoot>
+#errors
+(1,41): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <tfoot>
+
+#data
+<!doctype html><table><td><svg></svg>abc<td>
+#errors
+(1,26): unexpected-cell-in-table-body
+(1,44): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| "abc"
+| <td>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests19.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests19.dat
new file mode 100644
index 0000000000..a1897774df
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests19.dat
@@ -0,0 +1,1454 @@
+#data
+<!doctype html><math><mn DefinitionUrl="foo">
+#errors
+(1,45): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mn>
+| definitionURL="foo"
+
+#data
+<!doctype html><html></p><!--foo-->
+#errors
+(1,25): end-tag-after-implied-root
+#document
+| <!DOCTYPE html>
+| <html>
+| <!-- foo -->
+| <head>
+| <body>
+
+#data
+<!doctype html><head></head></p><!--foo-->
+#errors
+(1,32): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <!-- foo -->
+| <body>
+
+#data
+<!doctype html><body><p><pre>
+#errors
+(1,29): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <pre>
+
+#data
+<!doctype html><body><p><listing>
+#errors
+(1,33): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <listing>
+
+#data
+<!doctype html><p><plaintext>
+#errors
+(1,29): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <plaintext>
+
+#data
+<!doctype html><p><h1>
+#errors
+(1,22): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <h1>
+
+#data
+<!doctype html><isindex type="hidden">
+#errors
+(1,38): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <isindex>
+| type="hidden"
+
+#data
+<!doctype html><ruby><p><rp>
+#errors
+(1,28): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <p>
+| <rp>
+
+#data
+<!doctype html><ruby><div><span><rp>
+#errors
+(1,36): XXX-undefined-error
+(1,36): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <span>
+| <rp>
+
+#data
+<!doctype html><ruby><div><p><rp>
+#errors
+(1,33): XXX-undefined-error
+(1,33): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <p>
+| <rp>
+
+#data
+<!doctype html><ruby><p><rt>
+#errors
+(1,28): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <p>
+| <rt>
+
+#data
+<!doctype html><ruby><div><span><rt>
+#errors
+(1,36): XXX-undefined-error
+(1,36): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <span>
+| <rt>
+
+#data
+<!doctype html><ruby><div><p><rt>
+#errors
+(1,33): XXX-undefined-error
+(1,33): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <p>
+| <rt>
+
+#data
+<html><ruby>a<rb>b<rt></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rb>
+| "b"
+| <rt>
+
+#data
+<html><ruby>a<rp>b<rt></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rp>
+| "b"
+| <rt>
+
+#data
+<html><ruby>a<rt>b<rt></ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rt>
+| "b"
+| <rt>
+
+#data
+<html><ruby>a<rtc>b<rt>c<rb>d</ruby></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| "a"
+| <rtc>
+| "b"
+| <rt>
+| "c"
+| <rb>
+| "d"
+
+#data
+<!doctype html><math/><foo>
+#errors
+(1,27): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <foo>
+
+#data
+<!doctype html><svg/><foo>
+#errors
+(1,26): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <foo>
+
+#data
+<!doctype html><div></body><!--foo-->
+#errors
+(1,27): expected-one-end-tag-but-got-another
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <!-- foo -->
+
+#data
+<!doctype html><h1><div><h3><span></h1>foo
+#errors
+(1,39): end-tag-too-early
+(1,42): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <h1>
+| <div>
+| <h3>
+| <span>
+| "foo"
+
+#data
+<!doctype html><p></h3>foo
+#errors
+(1,23): end-tag-too-early
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "foo"
+
+#data
+<!doctype html><h3><li>abc</h2>foo
+#errors
+(1,31): end-tag-too-early
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <h3>
+| <li>
+| "abc"
+| "foo"
+
+#data
+<!doctype html><table>abc<!--foo-->
+#errors
+(1,23): foster-parenting-character
+(1,24): foster-parenting-character
+(1,25): foster-parenting-character
+(1,35): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "abc"
+| <table>
+| <!-- foo -->
+
+#data
+<!doctype html><table> <!--foo-->
+#errors
+(1,34): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <!-- foo -->
+
+#data
+<!doctype html><table> b <!--foo-->
+#errors
+(1,23): foster-parenting-character
+(1,24): foster-parenting-character
+(1,25): foster-parenting-character
+(1,35): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " b "
+| <table>
+| <!-- foo -->
+
+#data
+<!doctype html><select><option><option>
+#errors
+(1,39): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <option>
+
+#data
+<!doctype html><select><option></optgroup>
+#errors
+(1,42): unexpected-end-tag-in-select
+(1,42): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!doctype html><select><option></optgroup>
+#errors
+(1,42): unexpected-end-tag-in-select
+(1,42): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!doctype html><dd><optgroup><dd>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <dd>
+| <optgroup>
+| <dd>
+
+#data
+<!doctype html><p><math><mi><p><h1>
+#errors
+(1,35): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mi>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><mo><p><h1>
+#errors
+(1,35): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mo>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><mn><p><h1>
+#errors
+(1,35): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mn>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><ms><p><h1>
+#errors
+(1,35): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math ms>
+| <p>
+| <h1>
+
+#data
+<!doctype html><p><math><mtext><p><h1>
+#errors
+(1,38): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mtext>
+| <p>
+| <h1>
+
+#data
+<!doctype html><frameset></noframes>
+#errors
+(1,36): unexpected-end-tag-in-frameset
+(1,36): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html c=d><body></html><html a=b>
+#errors
+(1,48): non-html-root
+#document
+| <!DOCTYPE html>
+| <html>
+| a="b"
+| c="d"
+| <head>
+| <body>
+
+#data
+<!doctype html><html c=d><frameset></frameset></html><html a=b>
+#errors
+(1,63): non-html-root
+#document
+| <!DOCTYPE html>
+| <html>
+| a="b"
+| c="d"
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html><!--foo-->
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <!-- foo -->
+
+#data
+<!doctype html><html><frameset></frameset></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| " "
+
+#data
+<!doctype html><html><frameset></frameset></html>abc
+#errors
+(1,50): expected-eof-but-got-char
+(1,51): expected-eof-but-got-char
+(1,52): expected-eof-but-got-char
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html><p>
+#errors
+(1,52): expected-eof-but-got-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><html><frameset></frameset></html></p>
+#errors
+(1,53): expected-eof-but-got-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<html><frameset></frameset></html><!doctype html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,49): unexpected-doctype
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><body><frameset>
+#errors
+(1,31): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!doctype html><p><frameset><frame>
+#errors
+(1,28): unexpected-start-tag
+(1,35): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><p>a<frameset>
+#errors
+(1,29): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "a"
+
+#data
+<!doctype html><p> <frameset><frame>
+#errors
+(1,29): unexpected-start-tag
+(1,36): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><pre><frameset>
+#errors
+(1,30): unexpected-start-tag
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+
+#data
+<!doctype html><listing><frameset>
+#errors
+(1,34): unexpected-start-tag
+(1,34): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <listing>
+
+#data
+<!doctype html><li><frameset>
+#errors
+(1,29): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <li>
+
+#data
+<!doctype html><dd><frameset>
+#errors
+(1,29): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <dd>
+
+#data
+<!doctype html><dt><frameset>
+#errors
+(1,29): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <dt>
+
+#data
+<!doctype html><button><frameset>
+#errors
+(1,33): unexpected-start-tag
+(1,33): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <button>
+
+#data
+<!doctype html><applet><frameset>
+#errors
+(1,33): unexpected-start-tag
+(1,33): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <applet>
+
+#data
+<!doctype html><marquee><frameset>
+#errors
+(1,34): unexpected-start-tag
+(1,34): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <marquee>
+
+#data
+<!doctype html><object><frameset>
+#errors
+(1,33): unexpected-start-tag
+(1,33): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <object>
+
+#data
+<!doctype html><table><frameset>
+#errors
+(1,32): unexpected-start-tag-implies-table-voodoo
+(1,32): unexpected-start-tag
+(1,32): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+
+#data
+<!doctype html><area><frameset>
+#errors
+(1,31): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <area>
+
+#data
+<!doctype html><basefont><frameset>
+#errors
+(1,35): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <basefont>
+| <frameset>
+
+#data
+<!doctype html><bgsound><frameset>
+#errors
+(1,34): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <bgsound>
+| <frameset>
+
+#data
+<!doctype html><br><frameset>
+#errors
+(1,29): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <br>
+
+#data
+<!doctype html><embed><frameset>
+#errors
+(1,32): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <embed>
+
+#data
+<!doctype html><img><frameset>
+#errors
+(1,30): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <img>
+
+#data
+<!doctype html><input><frameset>
+#errors
+(1,32): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+
+#data
+<!doctype html><keygen><frameset>
+#errors
+(1,33): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <keygen>
+
+#data
+<!doctype html><wbr><frameset>
+#errors
+(1,30): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <wbr>
+
+#data
+<!doctype html><hr><frameset>
+#errors
+(1,29): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <hr>
+
+#data
+<!doctype html><textarea></textarea><frameset>
+#errors
+(1,46): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+
+#data
+<!doctype html><xmp></xmp><frameset>
+#errors
+(1,36): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xmp>
+
+#data
+<!doctype html><iframe></iframe><frameset>
+#errors
+(1,42): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <iframe>
+
+#data
+<!doctype html><select></select><frameset>
+#errors
+(1,42): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!doctype html><svg></svg><frameset><frame>
+#errors
+(1,36): unexpected-start-tag
+(1,43): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><math></math><frameset><frame>
+#errors
+(1,38): unexpected-start-tag
+(1,45): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><svg><foreignObject><div> <frameset><frame>
+#errors
+(1,51): unexpected-start-tag
+(1,58): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<!doctype html><svg>a</svg><frameset><frame>
+#errors
+(1,37): unexpected-start-tag
+(1,44): unexpected-start-tag-ignored
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "a"
+
+#data
+<!doctype html><svg> </svg><frameset><frame>
+#errors
+(1,37): unexpected-start-tag
+(1,44): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| <frame>
+
+#data
+<html>aaa<frameset></frameset>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,19): unexpected-start-tag
+(1,30): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| "aaa"
+
+#data
+<html> a <frameset></frameset>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,19): unexpected-start-tag
+(1,30): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| "a "
+
+#data
+<!doctype html><div><frameset>
+#errors
+(1,30): unexpected-start-tag
+(1,30): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><div><body><frameset>
+#errors
+(1,26): unexpected-start-tag
+(1,36): unexpected-start-tag
+(1,36): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<!doctype html><p><math></p>a
+#errors
+(1,28): unexpected-end-tag
+(1,28): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| "a"
+
+#data
+<!doctype html><p><math><mn><span></p>a
+#errors
+(1,38): unexpected-end-tag
+(1,39): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <math math>
+| <math mn>
+| <span>
+| <p>
+| "a"
+
+#data
+<!doctype html><math></html>
+#errors
+(1,28): unexpected-end-tag
+(1,28): expected-one-end-tag-but-got-another
+(1,28): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+
+#data
+<!doctype html><meta charset="ascii">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <meta>
+| charset="ascii"
+| <body>
+
+#data
+<!doctype html><meta http-equiv="content-type" content="text/html;charset=ascii">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <meta>
+| content="text/html;charset=ascii"
+| http-equiv="content-type"
+| <body>
+
+#data
+<!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset="utf8">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <!-- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -->
+| <meta>
+| charset="utf8"
+| <body>
+
+#data
+<!doctype html><html a=b><head></head><html c=d>
+#errors
+(1,48): non-html-root
+#document
+| <!DOCTYPE html>
+| <html>
+| a="b"
+| c="d"
+| <head>
+| <body>
+
+#data
+<!doctype html><image/>
+#errors
+(1,23): image-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <img>
+
+#data
+<!doctype html>a<i>b<table>c<b>d</i>e</b>f
+#errors
+(1,28): foster-parenting-character
+(1,31): foster-parenting-start-tag
+(1,32): foster-parenting-character
+(1,36): foster-parenting-end-tag
+(1,36): adoption-agency-1.3
+(1,37): foster-parenting-character
+(1,41): foster-parenting-end-tag
+(1,42): foster-parenting-character
+(1,42): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "a"
+| <i>
+| "bc"
+| <b>
+| "de"
+| "f"
+| <table>
+
+#data
+<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+(1,25): foster-parenting-start-tag
+(1,26): foster-parenting-character
+(1,29): foster-parenting-start-tag
+(1,30): foster-parenting-character
+(1,35): foster-parenting-start-tag
+(1,36): foster-parenting-character
+(1,39): foster-parenting-start-tag
+(1,40): foster-parenting-character
+(1,44): foster-parenting-end-tag
+(1,44): adoption-agency-1.3
+(1,44): adoption-agency-1.3
+(1,45): foster-parenting-character
+(1,49): foster-parenting-end-tag
+(1,49): adoption-agency-1.3
+(1,49): adoption-agency-1.3
+(1,50): foster-parenting-character
+(1,50): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <b>
+| <i>
+| "c"
+| <a>
+| "d"
+| <a>
+| "e"
+| <a>
+| "f"
+| <table>
+
+#data
+<!doctype html><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+(1,37): adoption-agency-1.3
+(1,37): adoption-agency-1.3
+(1,42): adoption-agency-1.3
+(1,42): adoption-agency-1.3
+(1,43): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <b>
+| <i>
+| "c"
+| <a>
+| "d"
+| <a>
+| "e"
+| <a>
+| "f"
+
+#data
+<!doctype html><table><i>a<b>b<div>c</i>
+#errors
+(1,25): foster-parenting-start-tag
+(1,26): foster-parenting-character
+(1,29): foster-parenting-start-tag
+(1,30): foster-parenting-character
+(1,35): foster-parenting-start-tag
+(1,36): foster-parenting-character
+(1,40): foster-parenting-end-tag
+(1,40): adoption-agency-1.3
+(1,40): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <i>
+| "c"
+| <table>
+
+#data
+<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
+#errors
+(1,25): foster-parenting-start-tag
+(1,26): foster-parenting-character
+(1,29): foster-parenting-start-tag
+(1,30): foster-parenting-character
+(1,35): foster-parenting-start-tag
+(1,36): foster-parenting-character
+(1,39): foster-parenting-start-tag
+(1,40): foster-parenting-character
+(1,44): foster-parenting-end-tag
+(1,44): adoption-agency-1.3
+(1,44): adoption-agency-1.3
+(1,45): foster-parenting-character
+(1,49): foster-parenting-end-tag
+(1,44): adoption-agency-1.3
+(1,44): adoption-agency-1.3
+(1,50): foster-parenting-character
+(1,50): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <b>
+| "b"
+| <b>
+| <div>
+| <b>
+| <i>
+| "c"
+| <a>
+| "d"
+| <a>
+| "e"
+| <a>
+| "f"
+| <table>
+
+#data
+<!doctype html><table><i>a<div>b<tr>c<b>d</i>e
+#errors
+(1,25): foster-parenting-start-tag
+(1,26): foster-parenting-character
+(1,31): foster-parenting-start-tag
+(1,32): foster-parenting-character
+(1,37): foster-parenting-character
+(1,40): foster-parenting-start-tag
+(1,41): foster-parenting-character
+(1,45): foster-parenting-end-tag
+(1,45): adoption-agency-1.3
+(1,46): foster-parenting-character
+(1,46): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <i>
+| "a"
+| <div>
+| "b"
+| <i>
+| "c"
+| <b>
+| "d"
+| <b>
+| "e"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table><td><table><i>a<div>b<b>c</i>d
+#errors
+(1,26): unexpected-cell-in-table-body
+(1,36): foster-parenting-start-tag
+(1,37): foster-parenting-character
+(1,42): foster-parenting-start-tag
+(1,43): foster-parenting-character
+(1,46): foster-parenting-start-tag
+(1,47): foster-parenting-character
+(1,51): foster-parenting-end-tag
+(1,51): adoption-agency-1.3
+(1,51): adoption-agency-1.3
+(1,52): foster-parenting-character
+(1,52): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+| "a"
+| <div>
+| <i>
+| "b"
+| <b>
+| "c"
+| <b>
+| "d"
+| <table>
+
+#data
+<!doctype html><body><bgsound>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <bgsound>
+
+#data
+<!doctype html><body><basefont>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <basefont>
+
+#data
+<!doctype html><a><b></a><basefont>
+#errors
+(1,25): adoption-agency-1.3
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <basefont>
+
+#data
+<!doctype html><a><b></a><bgsound>
+#errors
+(1,25): adoption-agency-1.3
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <bgsound>
+
+#data
+<!doctype html><figcaption><article></figcaption>a
+#errors
+(1,49): end-tag-too-early
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <figcaption>
+| <article>
+| "a"
+
+#data
+<!doctype html><summary><article></summary>a
+#errors
+(1,43): end-tag-too-early
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <summary>
+| <article>
+| "a"
+
+#data
+<!doctype html><p><a><plaintext>b
+#errors
+(1,32): unexpected-end-tag
+(1,33): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <a>
+| <plaintext>
+| <a>
+| "b"
+
+#data
+<!DOCTYPE html><div>a<a></div>b<p>c</p>d
+#errors
+(1,30): end-tag-too-early
+(1,40): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| "a"
+| <a>
+| <a>
+| "b"
+| <p>
+| "c"
+| "d"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests2.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests2.dat
new file mode 100644
index 0000000000..b44fec4d76
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests2.dat
@@ -0,0 +1,821 @@
+#data
+<!DOCTYPE html>Test
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<textarea>test</div>test
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,24): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "test</div>test"
+
+#data
+<table><td>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,11): unexpected-cell-in-table-body
+(1,11): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><td>test</tbody></table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,11): unexpected-cell-in-table-body
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "test"
+
+#data
+<frame>test
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,7): unexpected-start-tag-ignored
+#document
+| <html>
+| <head>
+| <body>
+| "test"
+
+#data
+<!DOCTYPE html><frameset>test
+#errors
+(1,29): unexpected-char-in-frameset
+(1,29): unexpected-char-in-frameset
+(1,29): unexpected-char-in-frameset
+(1,29): unexpected-char-in-frameset
+(1,29): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset> te st
+#errors
+(1,29): unexpected-char-in-frameset
+(1,29): unexpected-char-in-frameset
+(1,29): unexpected-char-in-frameset
+(1,29): unexpected-char-in-frameset
+(1,29): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| " "
+
+#data
+<!DOCTYPE html><frameset></frameset> te st
+#errors
+(1,29): unexpected-char-after-frameset
+(1,29): unexpected-char-after-frameset
+(1,29): unexpected-char-after-frameset
+(1,29): unexpected-char-after-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+| " "
+
+#data
+<!DOCTYPE html><frameset><!DOCTYPE html>
+#errors
+(1,40): unexpected-doctype
+(1,40): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><font><p><b>test</font>
+#errors
+(1,38): adoption-agency-1.3
+(1,38): adoption-agency-1.3
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <font>
+| <b>
+| "test"
+
+#data
+<!DOCTYPE html><dt><div><dd>
+#errors
+(1,28): end-tag-too-early
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <dt>
+| <div>
+| <dd>
+
+#data
+<script></x
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,11): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <script>
+| "</x"
+| <body>
+
+#data
+<table><plaintext><td>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,18): unexpected-start-tag-implies-table-voodoo
+(1,22): foster-parenting-character-in-table
+(1,22): foster-parenting-character-in-table
+(1,22): foster-parenting-character-in-table
+(1,22): foster-parenting-character-in-table
+(1,22): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "<td>"
+| <table>
+
+#data
+<plaintext></plaintext>
+#errors
+(1,11): expected-doctype-but-got-start-tag
+(1,23): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!DOCTYPE html><table><tr>TEST
+#errors
+(1,30): foster-parenting-character-in-table
+(1,30): foster-parenting-character-in-table
+(1,30): foster-parenting-character-in-table
+(1,30): foster-parenting-character-in-table
+(1,30): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "TEST"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4>
+#errors
+(1,37): unexpected-start-tag
+(1,53): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| t1="1"
+| t2="2"
+| t3="3"
+| t4="4"
+
+#data
+</b test
+#errors
+(1,8): eof-in-attribute-name
+(1,8): expected-doctype-but-got-eof
+#new-errors
+(1:9) eof-in-tag
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html></b test<b &=&amp>X
+#errors
+(1,24): invalid-character-in-attribute-name
+(1,32): named-entity-without-semicolon
+(1,33): attributes-in-end-tag
+(1,33): unexpected-end-tag-before-html
+#new-errors
+(1:24) unexpected-character-in-attribute-name
+(1:33) missing-semicolon-after-character-reference
+(1:33) end-tag-with-attributes
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+
+#data
+<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt
+#errors
+(1,9): need-space-after-doctype
+(1,54): expected-named-closing-tag-but-got-eof
+#new-errors
+(1:10) missing-whitespace-before-doctype-name
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| type="text/x-foobar;baz"
+| "X</SCRipt"
+| <body>
+
+#data
+&
+#errors
+(1,1): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "&"
+
+#data
+&#
+#errors
+(1,2): expected-numeric-entity
+(1,2): expected-doctype-but-got-chars
+#new-errors
+(1:3) absence-of-digits-in-numeric-character-reference
+#document
+| <html>
+| <head>
+| <body>
+| "&#"
+
+#data
+&#X
+#errors
+(1,3): expected-numeric-entity
+(1,3): expected-doctype-but-got-chars
+#new-errors
+(1:4) absence-of-digits-in-numeric-character-reference
+#document
+| <html>
+| <head>
+| <body>
+| "&#X"
+
+#data
+&#x
+#errors
+(1,3): expected-numeric-entity
+(1,3): expected-doctype-but-got-chars
+#new-errors
+(1:4) absence-of-digits-in-numeric-character-reference
+#document
+| <html>
+| <head>
+| <body>
+| "&#x"
+
+#data
+&#45
+#errors
+(1,4): numeric-entity-without-semicolon
+(1,4): expected-doctype-but-got-chars
+#new-errors
+(1:5) missing-semicolon-after-character-reference
+#document
+| <html>
+| <head>
+| <body>
+| "-"
+
+#data
+&x-test
+#errors
+(1,2): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "&x-test"
+
+#data
+<!doctypehtml><p><li>
+#errors
+(1,9): need-space-after-doctype
+#new-errors
+(1:10) missing-whitespace-before-doctype-name
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <li>
+
+#data
+<!doctypehtml><p><dt>
+#errors
+(1,9): need-space-after-doctype
+#new-errors
+(1:10) missing-whitespace-before-doctype-name
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <dt>
+
+#data
+<!doctypehtml><p><dd>
+#errors
+(1,9): need-space-after-doctype
+#new-errors
+(1:10) missing-whitespace-before-doctype-name
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <dd>
+
+#data
+<!doctypehtml><p><form>
+#errors
+(1,9): need-space-after-doctype
+(1,23): expected-closing-tag-but-got-eof
+#new-errors
+(1:10) missing-whitespace-before-doctype-name
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <form>
+
+#data
+<!DOCTYPE html><p></P>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "X"
+
+#data
+&AMP
+#errors
+(1,4): named-entity-without-semicolon
+(1,4): expected-doctype-but-got-chars
+#new-errors
+(1:5) missing-semicolon-after-character-reference
+#document
+| <html>
+| <head>
+| <body>
+| "&"
+
+#data
+&AMp;
+#errors
+(1,3): expected-named-entity
+(1,3): expected-doctype-but-got-chars
+#new-errors
+(1:5) unknown-named-character-reference
+#document
+| <html>
+| <head>
+| <body>
+| "&AMp;"
+
+#data
+<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY>
+#errors
+(1,110): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly>
+
+#data
+<!DOCTYPE html>X</body>X
+#errors
+(1,24): unexpected-char-after-body
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "XX"
+
+#data
+<!DOCTYPE html><!-- X
+#errors
+(1,21): eof-in-comment
+#new-errors
+(1:22) eof-in-comment
+#document
+| <!DOCTYPE html>
+| <!-- X -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><table><caption>test TEST</caption><td>test
+#errors
+(1,54): unexpected-cell-in-table-body
+(1,58): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| "test TEST"
+| <tbody>
+| <tr>
+| <td>
+| "test"
+
+#data
+<!DOCTYPE html><select><option><optgroup>
+#errors
+(1,41): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <optgroup>
+
+#data
+<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option>
+#errors
+(1,68): unexpected-select-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+| <option>
+| <option>
+| <option>
+
+#data
+<!DOCTYPE html><select><optgroup><option><optgroup>
+#errors
+(1,51): eof-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+| <option>
+| <optgroup>
+
+#data
+<!DOCTYPE html><datalist><option>foo</datalist>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <datalist>
+| <option>
+| "foo"
+| "bar"
+
+#data
+<!DOCTYPE html><font><input><input></font>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <input>
+| <input>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX
+#errors
+(1,29): eof-in-comment
+#new-errors
+(1:30) eof-in-comment
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+test
+test
+#errors
+(2,4): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "test
+test"
+
+#data
+<!DOCTYPE html><body><title>test</body></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "test</body>"
+
+#data
+<!DOCTYPE html><body><title>X</title><meta name=z><link rel=foo><style>
+x { content:"</style" } </style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+| <meta>
+| name="z"
+| <link>
+| rel="foo"
+| <style>
+| "
+x { content:"</style" } "
+
+#data
+<!DOCTYPE html><select><optgroup></optgroup></select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+
+#data
+
+
+#errors
+(2,1): expected-doctype-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html> <html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><script>
+</script> <title>x</title> </head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "
+"
+| " "
+| <title>
+| "x"
+| " "
+| <body>
+
+#data
+<!DOCTYPE html><html><body><html id=x>
+#errors
+(1,38): non-html-root
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html>X</body><html id="x">
+#errors
+(1,36): non-html-root
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+| "X"
+
+#data
+<!DOCTYPE html><head><html id=x>
+#errors
+(1,32): non-html-root
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html>X</html>X
+#errors
+(1,24): expected-eof-but-got-char
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "XX"
+
+#data
+<!DOCTYPE html>X</html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X "
+
+#data
+<!DOCTYPE html>X</html><p>X
+#errors
+(1,26): expected-eof-but-got-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <p>
+| "X"
+
+#data
+<!DOCTYPE html>X<p/x/y/z>
+#errors
+(1,19): unexpected-character-after-solidus-in-tag
+(1,21): unexpected-character-after-solidus-in-tag
+(1,23): unexpected-character-after-solidus-in-tag
+#new-errors
+(1:20) unexpected-solidus-in-tag
+(1:22) unexpected-solidus-in-tag
+(1:24) unexpected-solidus-in-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <p>
+| x=""
+| y=""
+| z=""
+
+#data
+<!DOCTYPE html><!--x--
+#errors
+(1,22): eof-in-comment-double-dash
+#new-errors
+(1:23) eof-in-comment
+#document
+| <!DOCTYPE html>
+| <!-- x -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><table><tr><td></p></table>
+#errors
+(1,34): unexpected-end-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <p>
+
+#data
+<!DOCTYPE <!DOCTYPE HTML>><!--<!--x-->-->
+#errors
+(1,20): expected-space-or-right-bracket-in-doctype
+(1,25): unknown-doctype
+(1,35): unexpected-char-in-comment
+#new-errors
+(1:21) invalid-character-sequence-after-doctype-name
+(1:35) nested-comment
+#document
+| <!DOCTYPE <!doctype>
+| <html>
+| <head>
+| <body>
+| ">"
+| <!-- <!--x -->
+| "-->"
+
+#data
+<!doctype html><div><form></form><div></div></div>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <form>
+| <div>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests20.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests20.dat
new file mode 100644
index 0000000000..52c5acdc6e
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests20.dat
@@ -0,0 +1,516 @@
+#data
+<!doctype html><p><button><button>
+#errors
+(1,34): unexpected-start-tag-implies-end-tag
+(1,34): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <button>
+
+#data
+<!doctype html><p><button><address>
+#errors
+(1,35): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <address>
+
+#data
+<!doctype html><p><button><blockquote>
+#errors
+(1,38): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <blockquote>
+
+#data
+<!doctype html><p><button><menu>
+#errors
+(1,32): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <menu>
+
+#data
+<!doctype html><p><button><p>
+#errors
+(1,29): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <p>
+
+#data
+<!doctype html><p><button><ul>
+#errors
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <ul>
+
+#data
+<!doctype html><p><button><h1>
+#errors
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <h1>
+
+#data
+<!doctype html><p><button><h6>
+#errors
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <h6>
+
+#data
+<!doctype html><p><button><listing>
+#errors
+(1,35): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <listing>
+
+#data
+<!doctype html><p><button><pre>
+#errors
+(1,31): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <pre>
+
+#data
+<!doctype html><p><button><form>
+#errors
+(1,32): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <form>
+
+#data
+<!doctype html><p><button><li>
+#errors
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <li>
+
+#data
+<!doctype html><p><button><dd>
+#errors
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <dd>
+
+#data
+<!doctype html><p><button><dt>
+#errors
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <dt>
+
+#data
+<!doctype html><p><button><plaintext>
+#errors
+(1,37): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <plaintext>
+
+#data
+<!doctype html><p><button><table>
+#errors
+(1,33): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <table>
+
+#data
+<!doctype html><p><button><hr>
+#errors
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <hr>
+
+#data
+<!doctype html><p><button><xmp>
+#errors
+(1,31): expected-named-closing-tag-but-got-eof
+(1,31): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <xmp>
+
+#data
+<!doctype html><p><button></p>
+#errors
+(1,30): unexpected-end-tag
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <button>
+| <p>
+
+#data
+<!doctype html><address><button></address>a
+#errors
+(1,42): end-tag-too-early
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <address>
+| <button>
+| "a"
+
+#data
+<!doctype html><address><button></address>a
+#errors
+(1,42): end-tag-too-early
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <address>
+| <button>
+| "a"
+
+#data
+<p><table></p>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,14): unexpected-end-tag-implies-table-voodoo
+(1,14): unexpected-end-tag
+(1,14): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <p>
+| <table>
+
+#data
+<!doctype html><svg>
+#errors
+(1,20): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<!doctype html><p><figcaption>
+#errors
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <figcaption>
+
+#data
+<!doctype html><p><summary>
+#errors
+(1,27): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <summary>
+
+#data
+<!doctype html><form><table><form>
+#errors
+(1,34): unexpected-form-in-table
+(1,34): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <table>
+
+#data
+<!doctype html><table><form><form>
+#errors
+(1,28): unexpected-form-in-table
+(1,34): unexpected-form-in-table
+(1,34): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <form>
+
+#data
+<!doctype html><table><form></table><form>
+#errors
+(1,28): unexpected-form-in-table
+(1,42): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <form>
+
+#data
+<!doctype html><svg><foreignObject><p>
+#errors
+(1,38): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg foreignObject>
+| <p>
+
+#data
+<!doctype html><svg><title>abc
+#errors
+(1,30): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| "abc"
+
+#data
+<option><span><option>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,22): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <option>
+| <span>
+| <option>
+
+#data
+<option><option>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,16): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <option>
+| <option>
+
+#data
+<math><annotation-xml><div>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,27): unexpected-html-element-in-foreign-content
+(1,27): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <div>
+
+#data
+<math><annotation-xml encoding="application/svg+xml"><div>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,58): unexpected-html-element-in-foreign-content
+(1,58): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="application/svg+xml"
+| <div>
+
+#data
+<math><annotation-xml encoding="application/xhtml+xml"><div>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,60): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="application/xhtml+xml"
+| <div>
+
+#data
+<math><annotation-xml encoding="aPPlication/xhtmL+xMl"><div>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,60): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="aPPlication/xhtmL+xMl"
+| <div>
+
+#data
+<math><annotation-xml encoding="text/html"><div>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,48): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="text/html"
+| <div>
+
+#data
+<math><annotation-xml encoding="Text/htmL"><div>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,48): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding="Text/htmL"
+| <div>
+
+#data
+<math><annotation-xml encoding=" text/html "><div>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,50): unexpected-html-element-in-foreign-content
+(1,50): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| encoding=" text/html "
+| <div>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests21.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests21.dat
new file mode 100644
index 0000000000..d384a55564
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests21.dat
@@ -0,0 +1,305 @@
+#data
+<svg><![CDATA[foo]]>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,20): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo"
+
+#data
+<math><![CDATA[foo]]>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,21): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| "foo"
+
+#data
+<div><![CDATA[foo]]>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,7): expected-dashes-or-doctype
+(1,20): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <!-- [CDATA[foo]] -->
+
+#data
+<svg><![CDATA[foo
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,17): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo"
+
+#data
+<svg><![CDATA[foo
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,17): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo"
+
+#data
+<svg><![CDATA[
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,14): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<svg><![CDATA[]]>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,17): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<svg><![CDATA[]] >]]>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,21): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]] >"
+
+#data
+<svg><![CDATA[]] >]]>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,21): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]] >"
+
+#data
+<svg><![CDATA[]]
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,16): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]]"
+
+#data
+<svg><![CDATA[]
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,15): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]"
+
+#data
+<svg><![CDATA[]>a
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,17): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "]>a"
+
+#data
+<!DOCTYPE html><svg><![CDATA[foo]]]>
+#errors
+(1,36): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo]"
+
+#data
+<!DOCTYPE html><svg><![CDATA[foo]]]]>
+#errors
+(1,37): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo]]"
+
+#data
+<!DOCTYPE html><svg><![CDATA[foo]]]]]>
+#errors
+(1,38): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "foo]]]"
+
+#data
+<svg><foreignObject><div><![CDATA[foo]]>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,27): expected-dashes-or-doctype
+(1,40): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg foreignObject>
+| <div>
+| <!-- [CDATA[foo]] -->
+
+#data
+<svg><![CDATA[<svg>]]>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,22): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+
+#data
+<svg><![CDATA[</svg>a]]>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,24): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "</svg>a"
+
+#data
+<svg><![CDATA[<svg>a
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,20): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>a"
+
+#data
+<svg><![CDATA[</svg>a
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,21): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "</svg>a"
+
+#data
+<svg><![CDATA[<svg>]]><path>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,28): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+| <svg path>
+
+#data
+<svg><![CDATA[<svg>]]></path>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,29): unexpected-end-tag
+(1,29): unexpected-end-tag
+(1,29): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+
+#data
+<svg><![CDATA[<svg>]]><!--path-->
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,33): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>"
+| <!-- path -->
+
+#data
+<svg><![CDATA[<svg>]]>path
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,26): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<svg>path"
+
+#data
+<svg><![CDATA[<!--svg-->]]>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,27): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| "<!--svg-->"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests22.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests22.dat
new file mode 100644
index 0000000000..31e6d9e331
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests22.dat
@@ -0,0 +1,190 @@
+#data
+<a><b><big><em><strong><div>X</a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,33): adoption-agency-1.3
+(1,33): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <big>
+| <em>
+| <strong>
+| <big>
+| <em>
+| <strong>
+| <div>
+| <a>
+| "X"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8>A</a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,91): adoption-agency-1.3
+(1,91): adoption-agency-1.3
+(1,91): adoption-agency-1.3
+(1,91): adoption-agency-1.3
+(1,91): adoption-agency-1.3
+(1,91): adoption-agency-1.3
+(1,91): adoption-agency-1.3
+(1,91): adoption-agency-1.3
+(1,91): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <div>
+| id="1"
+| <a>
+| <div>
+| id="2"
+| <a>
+| <div>
+| id="3"
+| <a>
+| <div>
+| id="4"
+| <a>
+| <div>
+| id="5"
+| <a>
+| <div>
+| id="6"
+| <a>
+| <div>
+| id="7"
+| <a>
+| <div>
+| id="8"
+| <a>
+| "A"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9>A</a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,101): adoption-agency-1.3
+(1,101): adoption-agency-1.3
+(1,101): adoption-agency-1.3
+(1,101): adoption-agency-1.3
+(1,101): adoption-agency-1.3
+(1,101): adoption-agency-1.3
+(1,101): adoption-agency-1.3
+(1,101): adoption-agency-1.3
+(1,101): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <div>
+| id="1"
+| <a>
+| <div>
+| id="2"
+| <a>
+| <div>
+| id="3"
+| <a>
+| <div>
+| id="4"
+| <a>
+| <div>
+| id="5"
+| <a>
+| <div>
+| id="6"
+| <a>
+| <div>
+| id="7"
+| <a>
+| <div>
+| id="8"
+| <a>
+| <div>
+| id="9"
+| "A"
+
+#data
+<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9><div id=10>A</a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,112): adoption-agency-1.3
+(1,112): adoption-agency-1.3
+(1,112): adoption-agency-1.3
+(1,112): adoption-agency-1.3
+(1,112): adoption-agency-1.3
+(1,112): adoption-agency-1.3
+(1,112): adoption-agency-1.3
+(1,112): adoption-agency-1.3
+(1,112): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <b>
+| <b>
+| <div>
+| id="1"
+| <a>
+| <div>
+| id="2"
+| <a>
+| <div>
+| id="3"
+| <a>
+| <div>
+| id="4"
+| <a>
+| <div>
+| id="5"
+| <a>
+| <div>
+| id="6"
+| <a>
+| <div>
+| id="7"
+| <a>
+| <div>
+| id="8"
+| <a>
+| <div>
+| id="9"
+| <div>
+| id="10"
+| "A"
+
+#data
+<cite><b><cite><i><cite><i><cite><i><div>X</b>TEST
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,46): adoption-agency-1.3
+(1,50): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <cite>
+| <b>
+| <cite>
+| <i>
+| <cite>
+| <i>
+| <cite>
+| <i>
+| <i>
+| <i>
+| <div>
+| <b>
+| "X"
+| "TEST"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests23.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests23.dat
new file mode 100644
index 0000000000..49e4a4ace5
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests23.dat
@@ -0,0 +1,168 @@
+#data
+<p><font size=4><font color=red><font size=4><font size=4><font size=4><font size=4><font size=4><font color=red><p>X
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,116): unexpected-end-tag
+(1,117): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| size="4"
+| <font>
+| color="red"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| color="red"
+| <p>
+| <font>
+| color="red"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| color="red"
+| "X"
+
+#data
+<p><font size=4><font size=4><font size=4><font size=4><p>X
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,58): unexpected-end-tag
+(1,59): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| "X"
+
+#data
+<p><font size=4><font size=4><font size=4><font size="5"><font size=4><p>X
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,73): unexpected-end-tag
+(1,74): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="5"
+| <font>
+| size="4"
+| <p>
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="5"
+| <font>
+| size="4"
+| "X"
+
+#data
+<p><font size=4 id=a><font size=4 id=b><font size=4><font size=4><p>X
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,68): unexpected-end-tag
+(1,69): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <font>
+| id="a"
+| size="4"
+| <font>
+| id="b"
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| <p>
+| <font>
+| id="a"
+| size="4"
+| <font>
+| id="b"
+| size="4"
+| <font>
+| size="4"
+| <font>
+| size="4"
+| "X"
+
+#data
+<p><b id=a><b id=a><b id=a><b><object><b id=a><b id=a>X</object><p>Y
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,64): end-tag-too-early
+(1,67): unexpected-end-tag
+(1,68): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| <object>
+| <b>
+| id="a"
+| <b>
+| id="a"
+| "X"
+| <p>
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| id="a"
+| <b>
+| "Y"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests24.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests24.dat
new file mode 100644
index 0000000000..f6dc7eb48a
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests24.dat
@@ -0,0 +1,79 @@
+#data
+<!DOCTYPE html>&NotEqualTilde;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "≂̸"
+
+#data
+<!DOCTYPE html>&NotEqualTilde;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "≂̸A"
+
+#data
+<!DOCTYPE html>&ThickSpace;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "  "
+
+#data
+<!DOCTYPE html>&ThickSpace;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "  A"
+
+#data
+<!DOCTYPE html>&NotSubset;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "⊂⃒"
+
+#data
+<!DOCTYPE html>&NotSubset;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "⊂⃒A"
+
+#data
+<!DOCTYPE html>&Gopf;
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "𝔾"
+
+#data
+<!DOCTYPE html>&Gopf;A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "𝔾A"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests25.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests25.dat
new file mode 100644
index 0000000000..cbc00512b1
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests25.dat
@@ -0,0 +1,220 @@
+#data
+<!DOCTYPE html><body><foo>A
+#errors
+(1,27): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <foo>
+| "A"
+
+#data
+<!DOCTYPE html><body><area>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <area>
+| "A"
+
+#data
+<!DOCTYPE html><body><base>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <base>
+| "A"
+
+#data
+<!DOCTYPE html><body><basefont>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <basefont>
+| "A"
+
+#data
+<!DOCTYPE html><body><bgsound>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <bgsound>
+| "A"
+
+#data
+<!DOCTYPE html><body><br>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <br>
+| "A"
+
+#data
+<!DOCTYPE html><body><col>A
+#errors
+(1,26): unexpected-start-tag-ignored
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "A"
+
+#data
+<!DOCTYPE html><body><command>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <command>
+| "A"
+
+#data
+<!DOCTYPE html><body><embed>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <embed>
+| "A"
+
+#data
+<!DOCTYPE html><body><frame>A
+#errors
+(1,28): unexpected-start-tag-ignored
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "A"
+
+#data
+<!DOCTYPE html><body><hr>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <hr>
+| "A"
+
+#data
+<!DOCTYPE html><body><img>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <img>
+| "A"
+
+#data
+<!DOCTYPE html><body><input>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+| "A"
+
+#data
+<!DOCTYPE html><body><keygen>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <keygen>
+| "A"
+
+#data
+<!DOCTYPE html><body><link>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <link>
+| "A"
+
+#data
+<!DOCTYPE html><body><meta>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <meta>
+| "A"
+
+#data
+<!DOCTYPE html><body><param>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <param>
+| "A"
+
+#data
+<!DOCTYPE html><body><source>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <source>
+| "A"
+
+#data
+<!DOCTYPE html><body><track>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <track>
+| "A"
+
+#data
+<!DOCTYPE html><body><wbr>A
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <wbr>
+| "A"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests26.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests26.dat
new file mode 100644
index 0000000000..867bbeecd5
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests26.dat
@@ -0,0 +1,411 @@
+#data
+<!DOCTYPE html><body><a href='#1'><nobr>1<nobr></a><br><a href='#2'><nobr>2<nobr></a><br><a href='#3'><nobr>3<nobr></a>
+#errors
+(1,47): unexpected-start-tag-implies-end-tag
+(1,51): adoption-agency-1.3
+(1,74): unexpected-start-tag-implies-end-tag
+(1,74): adoption-agency-1.3
+(1,81): unexpected-start-tag-implies-end-tag
+(1,85): adoption-agency-1.3
+(1,108): unexpected-start-tag-implies-end-tag
+(1,108): adoption-agency-1.3
+(1,115): unexpected-start-tag-implies-end-tag
+(1,119): adoption-agency-1.3
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <a>
+| href="#1"
+| <nobr>
+| "1"
+| <nobr>
+| <nobr>
+| <br>
+| <a>
+| href="#2"
+| <a>
+| href="#2"
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| <br>
+| <a>
+| href="#3"
+| <a>
+| href="#3"
+| <nobr>
+| "3"
+| <nobr>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr></b><i><nobr>2<nobr></i>3
+#errors
+(1,37): unexpected-start-tag-implies-end-tag
+(1,41): adoption-agency-1.3
+(1,50): unexpected-start-tag-implies-end-tag
+(1,50): adoption-agency-1.3
+(1,57): unexpected-start-tag-implies-end-tag
+(1,61): adoption-agency-1.3
+(1,62): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<table><nobr></b><i><nobr>2<nobr></i>3
+#errors
+(1,44): foster-parenting-start-tag
+(1,48): foster-parenting-end-tag
+(1,48): adoption-agency-1.3
+(1,51): foster-parenting-start-tag
+(1,57): foster-parenting-start-tag
+(1,57): nobr-already-in-scope
+(1,57): adoption-agency-1.2
+(1,58): foster-parenting-character
+(1,64): foster-parenting-start-tag
+(1,64): nobr-already-in-scope
+(1,68): foster-parenting-end-tag
+(1,68): adoption-agency-1.2
+(1,69): foster-parenting-character
+(1,69): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+| <table>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<table><tr><td><nobr></b><i><nobr>2<nobr></i>3
+#errors
+(1,56): unexpected-end-tag
+(1,65): unexpected-start-tag-implies-end-tag
+(1,65): adoption-agency-1.3
+(1,72): unexpected-start-tag-implies-end-tag
+(1,76): adoption-agency-1.3
+(1,77): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<div><nobr></b><i><nobr>2<nobr></i>3
+#errors
+(1,42): unexpected-start-tag-implies-end-tag
+(1,42): adoption-agency-1.3
+(1,46): adoption-agency-1.3
+(1,46): adoption-agency-1.3
+(1,55): unexpected-start-tag-implies-end-tag
+(1,55): adoption-agency-1.3
+(1,62): unexpected-start-tag-implies-end-tag
+(1,66): adoption-agency-1.3
+(1,67): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <div>
+| <b>
+| <nobr>
+| <nobr>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr></b><div><i><nobr>2<nobr></i>3
+#errors
+(1,37): unexpected-start-tag-implies-end-tag
+(1,41): adoption-agency-1.3
+(1,55): unexpected-start-tag-implies-end-tag
+(1,55): adoption-agency-1.3
+(1,62): unexpected-start-tag-implies-end-tag
+(1,66): adoption-agency-1.3
+(1,67): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <div>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+| <nobr>
+| <nobr>
+| "3"
+
+#data
+<!DOCTYPE html><body><b><nobr>1<nobr><ins></b><i><nobr>
+#errors
+(1,37): unexpected-start-tag-implies-end-tag
+(1,46): adoption-agency-1.3
+(1,55): unexpected-start-tag-implies-end-tag
+(1,55): adoption-agency-1.3
+(1,55): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <nobr>
+| <ins>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+
+#data
+<!DOCTYPE html><body><b><nobr>1<ins><nobr></b><i>2
+#errors
+(1,42): unexpected-start-tag-implies-end-tag
+(1,42): adoption-agency-1.3
+(1,46): adoption-agency-1.3
+(1,50): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| <nobr>
+| "1"
+| <ins>
+| <nobr>
+| <nobr>
+| <i>
+| "2"
+
+#data
+<!DOCTYPE html><body><b>1<nobr></b><i><nobr>2</i>
+#errors
+(1,35): adoption-agency-1.3
+(1,44): unexpected-start-tag-implies-end-tag
+(1,44): adoption-agency-1.3
+(1,49): adoption-agency-1.3
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| "1"
+| <nobr>
+| <nobr>
+| <i>
+| <i>
+| <nobr>
+| "2"
+
+#data
+<p><code x</code></p>
+
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,11): invalid-character-in-attribute-name
+(1,12): unexpected-character-after-solidus-in-tag
+(1,21): unexpected-end-tag
+(2,0): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <code>
+| code=""
+| x<=""
+| <code>
+| code=""
+| x<=""
+| "
+"
+
+#data
+<!DOCTYPE html><svg><foreignObject><p><i></p>a
+#errors
+(1,45): unexpected-end-tag
+(1,46): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg foreignObject>
+| <p>
+| <i>
+| <i>
+| "a"
+
+#data
+<!DOCTYPE html><table><tr><td><svg><foreignObject><p><i></p>a
+#errors
+(1,60): unexpected-end-tag
+(1,61): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg foreignObject>
+| <p>
+| <i>
+| <i>
+| "a"
+
+#data
+<!DOCTYPE html><math><mtext><p><i></p>a
+#errors
+(1,38): unexpected-end-tag
+(1,39): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mtext>
+| <p>
+| <i>
+| <i>
+| "a"
+
+#data
+<!DOCTYPE html><table><tr><td><math><mtext><p><i></p>a
+#errors
+(1,53): unexpected-end-tag
+(1,54): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <math math>
+| <math mtext>
+| <p>
+| <i>
+| <i>
+| "a"
+
+#data
+<!DOCTYPE html><body><div><!/div>a
+#errors
+(1,28): expected-dashes-or-doctype
+(1,34): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <!-- /div -->
+| "a"
+
+#data
+<button><p><button>
+#errors
+Line 1 Col 8 Unexpected start tag (button). Expected DOCTYPE.
+Line 1 Col 19 Unexpected start tag (button) implies end tag (button).
+Line 1 Col 19 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <button>
+| <p>
+| <button>
+
+#data
+<!DOCTYPE html><html><frameset></frameset></html></frameset>
+#errors
+60: Stray end tag “frameset”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><html><frameset></frameset></html>XXX</frameset>
+#errors
+52: Non-space character in page trailer.
+52: Non-space character in page trailer.
+52: Non-space character in page trailer.
+63: Stray end tag “frameset”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests3.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests3.dat
new file mode 100644
index 0000000000..423e2b3cab
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests3.dat
@@ -0,0 +1,306 @@
+#data
+<head></head><style></style>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,20): unexpected-start-tag-out-of-my-head
+#document
+| <html>
+| <head>
+| <style>
+| <body>
+
+#data
+<head></head><script></script>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,21): unexpected-start-tag-out-of-my-head
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<head></head><!-- --><style></style><!-- --><script></script>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,28): unexpected-start-tag-out-of-my-head
+(1,52): unexpected-start-tag-out-of-my-head
+#document
+| <html>
+| <head>
+| <style>
+| <script>
+| <!-- -->
+| <!-- -->
+| <body>
+
+#data
+<head></head><!-- -->x<style></style><!-- --><script></script>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <!-- -->
+| <body>
+| "x"
+| <style>
+| <!-- -->
+| <script>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "foo
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x</pre><span>
+</span></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x"
+| <span>
+| "
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x
+y</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x
+y"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x<div>
+y</pre></body></html>
+#errors
+(2,7): end-tag-too-early
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x"
+| <div>
+| "
+y"
+
+#data
+<!DOCTYPE html><pre>&#x0a;&#x0a;A</pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "
+A"
+
+#data
+<!DOCTYPE html><HTML><META><HEAD></HEAD></HTML>
+#errors
+(1,33): two-heads-are-not-better-than-one
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <meta>
+| <body>
+
+#data
+<!DOCTYPE html><HTML><HEAD><head></HEAD></HTML>
+#errors
+(1,33): two-heads-are-not-better-than-one
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<textarea>foo<span>bar</span><i>baz
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,35): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "foo<span>bar</span><i>baz"
+
+#data
+<title>foo<span>bar</em><i>baz
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,30): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <title>
+| "foo<span>bar</em><i>baz"
+| <body>
+
+#data
+<!DOCTYPE html><textarea>
+</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+
+#data
+<!DOCTYPE html><textarea>
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "foo"
+
+#data
+<!DOCTYPE html><textarea>
+
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><ul><li><div><p><li></ul></body></html>
+#errors
+(1,60): end-tag-too-early
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| <p>
+| <li>
+
+#data
+<!doctype html><nobr><nobr><nobr>
+#errors
+(1,27): unexpected-start-tag-implies-end-tag
+(1,33): unexpected-start-tag-implies-end-tag
+(1,33): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <nobr>
+| <nobr>
+| <nobr>
+
+#data
+<!doctype html><nobr><nobr></nobr><nobr>
+#errors
+(1,27): unexpected-start-tag-implies-end-tag
+(1,40): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <nobr>
+| <nobr>
+| <nobr>
+
+#data
+<!doctype html><html><body><p><table></table></body></html>
+#errors
+Not known
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <table>
+
+#data
+<p><table></table>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <table>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests4.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests4.dat
new file mode 100644
index 0000000000..0a6174c36c
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests4.dat
@@ -0,0 +1,58 @@
+#data
+direct div content
+#errors
+#document-fragment
+div
+#document
+| "direct div content"
+
+#data
+direct textarea content
+#errors
+#document-fragment
+textarea
+#document
+| "direct textarea content"
+
+#data
+textarea content with <em>pseudo</em> <foo>markup
+#errors
+#document-fragment
+textarea
+#document
+| "textarea content with <em>pseudo</em> <foo>markup"
+
+#data
+this is &#x0043;DATA inside a <style> element
+#errors
+#document-fragment
+style
+#document
+| "this is &#x0043;DATA inside a <style> element"
+
+#data
+</plaintext>
+#errors
+#document-fragment
+plaintext
+#document
+| "</plaintext>"
+
+#data
+setting html's innerHTML
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| "setting html's innerHTML"
+
+#data
+<title>setting head's innerHTML</title>
+#errors
+#document-fragment
+head
+#document
+| <title>
+| "setting head's innerHTML"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests5.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests5.dat
new file mode 100644
index 0000000000..4d5fcd7a79
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests5.dat
@@ -0,0 +1,197 @@
+#data
+<style> <!-- </style>x
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <style>
+| " <!-- "
+| <body>
+| "x"
+
+#data
+<style> <!-- </style> --> </style>x
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,34): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <style>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<style> <!--> </style>x
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <style>
+| " <!--> "
+| <body>
+| "x"
+
+#data
+<style> <!---> </style>x
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <style>
+| " <!---> "
+| <body>
+| "x"
+
+#data
+<iframe> <!---> </iframe>x
+#errors
+(1,8): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| " <!---> "
+| "x"
+
+#data
+<iframe> <!--- </iframe>->x</iframe> --> </iframe>x
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,36): unexpected-end-tag
+(1,50): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| " <!--- "
+| "->x --> x"
+
+#data
+<script> <!-- </script> --> </script>x
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,37): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <script>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<title> <!-- </title> --> </title>x
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,34): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <title>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<textarea> <!--- </textarea>->x</textarea> --> </textarea>x
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,42): unexpected-end-tag
+(1,58): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| " <!--- "
+| "->x --> x"
+
+#data
+<style> <!</-- </style>x
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <style>
+| " <!</-- "
+| <body>
+| "x"
+
+#data
+<p><xmp></xmp>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <xmp>
+
+#data
+<xmp> <!-- > --> </xmp>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <xmp>
+| " <!-- > --> "
+
+#data
+<title>&amp;</title>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <title>
+| "&"
+| <body>
+
+#data
+<title><!--&amp;--></title>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <title>
+| "<!--&-->"
+| <body>
+
+#data
+<title><!--</title>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <title>
+| "<!--"
+| <body>
+
+#data
+<noscript><!--</noscript>--></noscript>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,39): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "-->"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests6.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests6.dat
new file mode 100644
index 0000000000..fedc64e938
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests6.dat
@@ -0,0 +1,662 @@
+#data
+<!doctype html></head> <head>
+#errors
+(1,29): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| " "
+| <body>
+
+#data
+<!doctype html><form><div></form><div>
+#errors
+(1,33): end-tag-too-early-ignored
+(1,38): expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <div>
+| <div>
+
+#data
+<!doctype html><title>&amp;</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "&"
+| <body>
+
+#data
+<!doctype html><title><!--&amp;--></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "<!--&-->"
+| <body>
+
+#data
+<!doctype>
+#errors
+(1,9): need-space-after-doctype
+(1,10): expected-doctype-name-but-got-right-bracket
+(1,10): unknown-doctype
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+
+#data
+<!---x
+#errors
+(1,6): eof-in-comment
+(1,6): expected-doctype-but-got-eof
+#document
+| <!-- -x -->
+| <html>
+| <head>
+| <body>
+
+#data
+<body>
+<div>
+#errors
+(1,6): unexpected-start-tag
+(2,5): expected-closing-tag-but-got-eof
+#document-fragment
+div
+#document
+| "
+"
+| <div>
+
+#data
+<frameset></frameset>
+foo
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(2,1): unexpected-char-after-frameset
+(2,2): unexpected-char-after-frameset
+(2,3): unexpected-char-after-frameset
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+<noframes>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(2,10): expected-named-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+| <noframes>
+
+#data
+<frameset></frameset>
+<div>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(2,5): unexpected-start-tag-after-frameset
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+</html>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+</div>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(2,6): unexpected-end-tag-after-frameset
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<form><form>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,12): unexpected-start-tag
+(1,12): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+
+#data
+<button><button>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,16): unexpected-start-tag-implies-end-tag
+(1,16): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <button>
+| <button>
+
+#data
+<table><tr><td></th>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,20): unexpected-end-tag
+(1,20): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><caption><td>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,20): XXX-undefined-error
+(1,20): unexpected-cell-in-table-body
+(1,20): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><caption><div>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,21): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+</caption><div>
+#errors
+(1,10): XXX-undefined-error
+(1,15): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption><div></caption>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,31): expected-one-end-tag-but-got-another
+(1,31): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+<table><caption></table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,24): end-table-tag-in-caption
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+
+#data
+</table><div>
+#errors
+(1,8): unexpected-end-tag
+(1,13): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption></body></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,23): unexpected-end-tag
+(1,29): unexpected-end-tag
+(1,40): unexpected-end-tag
+(1,47): unexpected-end-tag
+(1,55): unexpected-end-tag
+(1,60): unexpected-end-tag
+(1,68): unexpected-end-tag
+(1,73): unexpected-end-tag
+(1,81): unexpected-end-tag
+(1,86): unexpected-end-tag
+(1,86): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+
+#data
+<table><caption><div></div>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,27): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+<table><tr><td></body></caption></col></colgroup></html>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,22): unexpected-end-tag
+(1,32): unexpected-end-tag
+(1,38): unexpected-end-tag
+(1,49): unexpected-end-tag
+(1,56): unexpected-end-tag
+(1,56): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+</table></tbody></tfoot></thead></tr><div>
+#errors
+(1,8): unexpected-end-tag
+(1,16): unexpected-end-tag
+(1,24): unexpected-end-tag
+(1,32): unexpected-end-tag
+(1,37): unexpected-end-tag
+(1,42): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <div>
+
+#data
+<table><colgroup>foo
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,18): foster-parenting-character-in-table
+(1,19): foster-parenting-character-in-table
+(1,20): foster-parenting-character-in-table
+(1,20): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| "foo"
+| <table>
+| <colgroup>
+
+#data
+foo<col>
+#errors
+(1,1): unexpected-character-in-colgroup
+(1,2): unexpected-character-in-colgroup
+(1,3): unexpected-character-in-colgroup
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<table><colgroup></col>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,23): no-end-tag
+(1,23): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+
+#data
+<frameset><div>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,15): unexpected-start-tag-in-frameset
+(1,15): eof-in-frameset
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</frameset><frame>
+#errors
+(1,11): unexpected-frameset-in-frameset-innerhtml
+#document-fragment
+frameset
+#document
+| <frame>
+
+#data
+<frameset></div>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+(1,16): unexpected-end-tag-in-frameset
+(1,16): eof-in-frameset
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</body><div>
+#errors
+(1,7): unexpected-close-tag
+(1,12): expected-closing-tag-but-got-eof
+#document-fragment
+body
+#document
+| <div>
+
+#data
+<table><tr><div>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,16): unexpected-start-tag-implies-table-voodoo
+(1,16): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+</tr><td>
+#errors
+(1,5): unexpected-end-tag
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+</tbody></tfoot></thead><td>
+#errors
+(1,8): unexpected-end-tag
+(1,16): unexpected-end-tag
+(1,24): unexpected-end-tag
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<table><tr><div><td>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,16): foster-parenting-start-tag
+(1,20): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<caption><col><colgroup><tbody><tfoot><thead><tr>
+#errors
+(1,9): unexpected-start-tag
+(1,14): unexpected-start-tag
+(1,24): unexpected-start-tag
+(1,31): unexpected-start-tag
+(1,38): unexpected-start-tag
+(1,45): unexpected-start-tag
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></thead>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,22): unexpected-end-tag-in-table-body
+(1,22): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+</table><tr>
+#errors
+(1,8): unexpected-end-tag
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></body></caption></col></colgroup></html></td></th></tr>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,21): unexpected-end-tag-in-table-body
+(1,31): unexpected-end-tag-in-table-body
+(1,37): unexpected-end-tag-in-table-body
+(1,48): unexpected-end-tag-in-table-body
+(1,55): unexpected-end-tag-in-table-body
+(1,60): unexpected-end-tag-in-table-body
+(1,65): unexpected-end-tag-in-table-body
+(1,70): unexpected-end-tag-in-table-body
+(1,70): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+<table><tbody></div>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,20): unexpected-end-tag-implies-table-voodoo
+(1,20): end-tag-too-early
+(1,20): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+<table><table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,14): unexpected-start-tag-implies-end-tag
+(1,14): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <table>
+
+#data
+<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,14): unexpected-end-tag
+(1,24): unexpected-end-tag
+(1,30): unexpected-end-tag
+(1,41): unexpected-end-tag
+(1,48): unexpected-end-tag
+(1,56): unexpected-end-tag
+(1,61): unexpected-end-tag
+(1,69): unexpected-end-tag
+(1,74): unexpected-end-tag
+(1,82): unexpected-end-tag
+(1,87): unexpected-end-tag
+(1,87): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+
+#data
+</table><tr>
+#errors
+(1,8): unexpected-end-tag
+#document-fragment
+table
+#document
+| <tbody>
+| <tr>
+
+#data
+<body></body></html>
+#errors
+(1,20): unexpected-end-tag-after-body-innerhtml
+#document-fragment
+html
+#document
+| <head>
+| <body>
+
+#data
+<html><frameset></frameset></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <frameset>
+| " "
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"><html></html>
+#errors
+(1,50): unknown-doctype element.
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "">
+| <html>
+| <head>
+| <body>
+
+#data
+<param><frameset></frameset>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,17): unexpected-start-tag
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<source><frameset></frameset>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,18): unexpected-start-tag
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<track><frameset></frameset>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,17): unexpected-start-tag
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</html><frameset></frameset>
+#errors
+(1,7): expected-doctype-but-got-end-tag
+(1,17): expected-eof-but-got-start-tag
+(1,17): unexpected-start-tag
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</body><frameset></frameset>
+#errors
+(1,7): expected-doctype-but-got-end-tag
+(1,17): unexpected-start-tag-after-body
+(1,17): unexpected-start-tag
+#document
+| <html>
+| <head>
+| <frameset>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests7.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests7.dat
new file mode 100644
index 0000000000..f9471b9a34
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests7.dat
@@ -0,0 +1,402 @@
+#data
+<!doctype html><body><title>X</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+
+#data
+<!doctype html><table><title>X</title></table>
+#errors
+(1,29): unexpected-start-tag-implies-table-voodoo
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+| <table>
+
+#data
+<!doctype html><head></head><title>X</title>
+#errors
+(1,35): unexpected-start-tag-out-of-my-head
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "X"
+| <body>
+
+#data
+<!doctype html></head><title>X</title>
+#errors
+(1,29): unexpected-start-tag-out-of-my-head
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "X"
+| <body>
+
+#data
+<!doctype html><table><meta></table>
+#errors
+(1,28): unexpected-start-tag-implies-table-voodoo
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <meta>
+| <table>
+
+#data
+<!doctype html><table>X<tr><td><table> <meta></table></table>
+#errors
+(1,45): unexpected-start-tag-implies-table-voodoo
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <meta>
+| <table>
+| " "
+
+#data
+<!doctype html><html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!doctype html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!doctype html><table><style> <tr>x </style> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <style>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><table><TBODY><script> <tr>x </script> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <script>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><p><applet><p>X</p></applet>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <applet>
+| <p>
+| "X"
+
+#data
+<!doctype html><listing>
+X</listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <listing>
+| "X"
+
+#data
+<!doctype html><select><input>X
+#errors
+(1,30): unexpected-input-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <input>
+| "X"
+
+#data
+<!doctype html><select><select>X
+#errors
+(1,31): unexpected-select-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+
+#data
+<!doctype html><table><input type=hidDEN></table>
+#errors
+(1,41): unexpected-hidden-input-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table>X<input type=hidDEN></table>
+#errors
+(1,23): foster-parenting-character
+(1,42): unexpected-hidden-input-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table> <input type=hidDEN></table>
+#errors
+(1,43): unexpected-hidden-input-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table> <input type='hidDEN'></table>
+#errors
+(1,45): unexpected-hidden-input-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table><input type=" hidden"><input type=hidDEN></table>
+#errors
+(1,44): unexpected-start-tag-implies-table-voodoo
+(1,63): unexpected-hidden-input-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+| type=" hidden"
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table><select>X<tr>
+#errors
+(1,30): unexpected-start-tag-implies-table-voodoo
+(1,35): unexpected-table-element-start-tag-in-select-in-table
+(1,35): eof-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><select>X</select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+
+#data
+<!DOCTYPE hTmL><html></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML><html></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<body>X</body></body>
+#errors
+(1,21): unexpected-end-tag-after-body
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| "X"
+
+#data
+<div><p>a</x> b
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,13): unexpected-end-tag
+(1,15): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <p>
+| "a b"
+
+#data
+<table><tr><td><code></code> </table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <code>
+| " "
+
+#data
+<table><b><tr><td>aaa</td></tr>bbb</table>ccc
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,10): foster-parenting-start-tag
+(1,32): foster-parenting-character
+(1,33): foster-parenting-character
+(1,34): foster-parenting-character
+(1,45): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <b>
+| "bbb"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "aaa"
+| <b>
+| "ccc"
+
+#data
+A<table><tr> B</tr> B</table>
+#errors
+(1,1): expected-doctype-but-got-chars
+(1,13): foster-parenting-character
+(1,14): foster-parenting-character
+(1,20): foster-parenting-character
+(1,21): foster-parenting-character
+#document
+| <html>
+| <head>
+| <body>
+| "A B B"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+A<table><tr> B</tr> </em>C</table>
+#errors
+(1,1): expected-doctype-but-got-chars
+(1,13): foster-parenting-character
+(1,14): foster-parenting-character
+(1,20): foster-parenting-character
+(1,25): unexpected-end-tag
+(1,26): foster-parenting-character
+#document
+| <html>
+| <head>
+| <body>
+| "A BC"
+| <table>
+| <tbody>
+| <tr>
+| " "
+
+#data
+<select><keygen>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,16): unexpected-input-in-select
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <keygen>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests8.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests8.dat
new file mode 100644
index 0000000000..93289f39c5
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests8.dat
@@ -0,0 +1,149 @@
+#data
+<div>
+<div></div>
+</span>x
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(3,7): unexpected-end-tag
+(3,8): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "
+"
+| <div>
+| "
+x"
+
+#data
+<div>x<div></div>
+</span>x
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(2,7): unexpected-end-tag
+(2,8): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "
+x"
+
+#data
+<div>x<div></div>x</span>x
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,25): unexpected-end-tag
+(1,26): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "xx"
+
+#data
+<div>x<div></div>y</span>z
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,25): unexpected-end-tag
+(1,26): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "yz"
+
+#data
+<table><div>x<div></div>x</span>x
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,12): foster-parenting-start-tag
+(1,13): foster-parenting-character
+(1,18): foster-parenting-start-tag
+(1,24): foster-parenting-end-tag
+(1,25): foster-parenting-start-tag
+(1,32): foster-parenting-end-tag
+(1,32): unexpected-end-tag
+(1,33): foster-parenting-character
+(1,33): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "xx"
+| <table>
+
+#data
+x<table>x
+#errors
+(1,1): expected-doctype-but-got-chars
+(1,9): foster-parenting-character
+#document
+| <html>
+| <head>
+| <body>
+| "xx"
+| <table>
+
+#data
+x<table><table>x
+#errors
+(1,1): expected-doctype-but-got-chars
+(1,15): unexpected-start-tag-implies-end-tag
+(1,16): foster-parenting-character
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <table>
+| "x"
+| <table>
+
+#data
+<b>a<div></div><div></b>y
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,24): adoption-agency-1.3
+(1,25): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "a"
+| <div>
+| <div>
+| <b>
+| "y"
+
+#data
+<a><div><p></a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,15): adoption-agency-1.3
+(1,15): adoption-agency-1.3
+(1,15): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <div>
+| <a>
+| <p>
+| <a>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests9.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests9.dat
new file mode 100644
index 0000000000..40651a0613
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests9.dat
@@ -0,0 +1,473 @@
+#data
+<!DOCTYPE html><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+
+#data
+<!DOCTYPE html><body><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+
+#data
+<!DOCTYPE html><math><mi>
+#errors
+(1,25) expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+
+#data
+<!DOCTYPE html><math><annotation-xml><svg><u>
+#errors
+(1,45) unexpected-html-element-in-foreign-content
+(1,45) expected-closing-tag-but-got-eof
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <u>
+
+#data
+<!DOCTYPE html><body><select><math></math></select>
+#errors
+(1,35) unexpected-start-tag-in-select
+(1,42) unexpected-end-tag-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!DOCTYPE html><body><select><option><math></math></option></select>
+#errors
+(1,43) unexpected-start-tag-in-select
+(1,50) unexpected-end-tag-in-select
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!DOCTYPE html><body><table><math></math></table>
+#errors
+(1,34) unexpected-start-tag-implies-table-voodoo
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi></math></table>
+#errors
+(1,34) foster-parenting-start-token
+(1,39) foster-parenting-character
+(1,40) foster-parenting-character
+(1,41) foster-parenting-character
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi><mi>bar</mi></math></table>
+#errors
+(1,34) foster-parenting-start-tag
+(1,39) foster-parenting-character
+(1,40) foster-parenting-character
+(1,41) foster-parenting-character
+(1,51) foster-parenting-character
+(1,52) foster-parenting-character
+(1,53) foster-parenting-character
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><math><mi>foo</mi><mi>bar</mi></math></tbody></table>
+#errors
+(1,41) foster-parenting-start-tag
+(1,46) foster-parenting-character
+(1,47) foster-parenting-character
+(1,48) foster-parenting-character
+(1,58) foster-parenting-character
+(1,59) foster-parenting-character
+(1,60) foster-parenting-character
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+| <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><math><mi>foo</mi><mi>bar</mi></math></tr></tbody></table>
+#errors
+(1,45) foster-parenting-start-tag
+(1,50) foster-parenting-character
+(1,51) foster-parenting-character
+(1,52) foster-parenting-character
+(1,62) foster-parenting-character
+(1,63) foster-parenting-character
+(1,64) foster-parenting-character
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi></math><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+(1,70) unexpected-html-element-in-foreign-content
+(1,81) XXX-undefined-error
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi>baz</table><p>quux
+#errors
+(1,78) unexpected-end-tag
+(1,78) expected-one-end-tag-but-got-another
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+(1,44) foster-parenting-start-tag
+(1,49) foster-parenting-character
+(1,50) foster-parenting-character
+(1,51) foster-parenting-character
+(1,61) foster-parenting-character
+(1,62) foster-parenting-character
+(1,63) foster-parenting-character
+(1,71) unexpected-html-element-in-foreign-content
+(1,71) foster-parenting-start-tag
+(1,63) foster-parenting-character
+(1,63) foster-parenting-character
+(1,63) foster-parenting-character
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+| <table>
+| <colgroup>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+(1,50) unexpected-start-tag-in-select
+(1,54) unexpected-start-tag-in-select
+(1,62) unexpected-end-tag-in-select
+(1,66) unexpected-start-tag-in-select
+(1,74) unexpected-end-tag-in-select
+(1,77) unexpected-start-tag-in-select
+(1,88) unexpected-table-element-end-tag-in-select-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| "foobarbaz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+(1,36) unexpected-start-tag-implies-table-voodoo
+(1,42) unexpected-start-tag-in-select
+(1,46) unexpected-start-tag-in-select
+(1,54) unexpected-end-tag-in-select
+(1,58) unexpected-start-tag-in-select
+(1,66) unexpected-end-tag-in-select
+(1,69) unexpected-start-tag-in-select
+(1,80) unexpected-table-element-end-tag-in-select-in-table
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "foobarbaz"
+| <table>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body></body></html><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+(1,41) expected-eof-but-got-start-tag
+(1,68) unexpected-html-element-in-foreign-content
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body></body><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+(1,34) unexpected-start-tag-after-body
+(1,61) unexpected-html-element-in-foreign-content
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><frameset><math><mi></mi><mi></mi><p><span>
+#errors
+(1,31) unexpected-start-tag-in-frameset
+(1,35) unexpected-start-tag-in-frameset
+(1,40) unexpected-end-tag-in-frameset
+(1,44) unexpected-start-tag-in-frameset
+(1,49) unexpected-end-tag-in-frameset
+(1,52) unexpected-start-tag-in-frameset
+(1,58) unexpected-start-tag-in-frameset
+(1,58) eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><math><mi></mi><mi></mi><p><span>
+#errors
+(1,42) unexpected-start-tag-after-frameset
+(1,46) unexpected-start-tag-after-frameset
+(1,51) unexpected-end-tag-after-frameset
+(1,55) unexpected-start-tag-after-frameset
+(1,60) unexpected-end-tag-after-frameset
+(1,63) unexpected-start-tag-after-frameset
+(1,69) unexpected-start-tag-after-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><math xlink:href=foo></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| <math math>
+| xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo></mi></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo /></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo />bar</math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+| "bar"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests_innerHTML_1.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests_innerHTML_1.dat
new file mode 100644
index 0000000000..5ede639bcc
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tests_innerHTML_1.dat
@@ -0,0 +1,902 @@
+#data
+<body><span>
+#errors
+(1,6): unexpected-start-tag
+(1,12): expected-closing-tag-but-got-eof
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><body>
+#errors
+(1,12): unexpected-start-tag
+(1,12): expected-closing-tag-but-got-eof
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><body>
+#errors
+(1,12): unexpected-start-tag
+(1,12): expected-closing-tag-but-got-eof
+#document-fragment
+div
+#document
+| <span>
+
+#data
+<body><span>
+#errors
+(1,12): expected-closing-tag-but-got-eof
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| <span>
+
+#data
+<frameset><span>
+#errors
+(1,10): unexpected-start-tag
+(1,16): expected-closing-tag-but-got-eof
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><frameset>
+#errors
+(1,16): unexpected-start-tag
+(1,16): expected-closing-tag-but-got-eof
+#document-fragment
+body
+#document
+| <span>
+
+#data
+<span><frameset>
+#errors
+(1,16): unexpected-start-tag
+(1,16): expected-closing-tag-but-got-eof
+#document-fragment
+div
+#document
+| <span>
+
+#data
+<frameset><span>
+#errors
+(1,16): unexpected-start-tag-in-frameset
+(1,16): eof-in-frameset
+#document-fragment
+html
+#document
+| <head>
+| <frameset>
+
+#data
+<table><tr>
+#errors
+(1,7): unexpected-start-tag
+#document-fragment
+table
+#document
+| <tbody>
+| <tr>
+
+#data
+</table><tr>
+#errors
+(1,8): unexpected-end-tag
+#document-fragment
+table
+#document
+| <tbody>
+| <tr>
+
+#data
+<a>
+#errors
+(1,3): unexpected-start-tag-implies-table-voodoo
+(1,3): eof-in-table
+#document-fragment
+table
+#document
+| <a>
+
+#data
+<a>
+#errors
+(1,3): unexpected-start-tag-implies-table-voodoo
+(1,3): eof-in-table
+#document-fragment
+table
+#document
+| <a>
+
+#data
+<a><caption>a
+#errors
+(1,3): unexpected-start-tag-implies-table-voodoo
+(1,13): expected-closing-tag-but-got-eof
+#document-fragment
+table
+#document
+| <a>
+| <caption>
+| "a"
+
+#data
+<a><colgroup><col>
+#errors
+(1,3): foster-parenting-start-token
+(1,18): expected-closing-tag-but-got-eof
+#document-fragment
+table
+#document
+| <a>
+| <colgroup>
+| <col>
+
+#data
+<a><tbody><tr>
+#errors
+(1,3): foster-parenting-start-tag
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+
+#data
+<a><tfoot><tr>
+#errors
+(1,3): foster-parenting-start-tag
+#document-fragment
+table
+#document
+| <a>
+| <tfoot>
+| <tr>
+
+#data
+<a><thead><tr>
+#errors
+(1,3): foster-parenting-start-tag
+#document-fragment
+table
+#document
+| <a>
+| <thead>
+| <tr>
+
+#data
+<a><tr>
+#errors
+(1,3): foster-parenting-start-tag
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+
+#data
+<a><th>
+#errors
+(1,3): unexpected-start-tag-implies-table-voodoo
+(1,7): unexpected-cell-in-table-body
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+| <th>
+
+#data
+<a><td>
+#errors
+(1,3): unexpected-start-tag-implies-table-voodoo
+(1,7): unexpected-cell-in-table-body
+#document-fragment
+table
+#document
+| <a>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table></table><tbody>
+#errors
+(1,22): unexpected-start-tag
+#document-fragment
+caption
+#document
+| <table>
+
+#data
+</table><span>
+#errors
+(1,8): unexpected-end-tag
+(1,14): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+<span></table>
+#errors
+(1,14): unexpected-end-tag
+(1,14): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+</caption><span>
+#errors
+(1,10): XXX-undefined-error
+(1,16): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+
+#data
+<span></caption><span>
+#errors
+(1,16): XXX-undefined-error
+(1,22): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><caption><span>
+#errors
+(1,15): unexpected-start-tag
+(1,21): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><col><span>
+#errors
+(1,11): unexpected-start-tag
+(1,17): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><colgroup><span>
+#errors
+(1,16): unexpected-start-tag
+(1,22): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><html><span>
+#errors
+(1,12): non-html-root
+(1,18): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><tbody><span>
+#errors
+(1,13): unexpected-start-tag
+(1,19): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><td><span>
+#errors
+(1,10): unexpected-start-tag
+(1,16): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><tfoot><span>
+#errors
+(1,13): unexpected-start-tag
+(1,19): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><thead><span>
+#errors
+(1,13): unexpected-start-tag
+(1,19): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><th><span>
+#errors
+(1,10): unexpected-start-tag
+(1,16): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span><tr><span>
+#errors
+(1,10): unexpected-start-tag
+(1,16): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+<span></table><span>
+#errors
+(1,14): unexpected-end-tag
+(1,20): expected-closing-tag-but-got-eof
+#document-fragment
+caption
+#document
+| <span>
+| <span>
+
+#data
+</colgroup><col>
+#errors
+(1,11): XXX-undefined-error
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<a><col>
+#errors
+(1,3): XXX-undefined-error
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<caption><a>
+#errors
+(1,9): XXX-undefined-error
+(1,12): unexpected-start-tag-implies-table-voodoo
+(1,12): eof-in-table
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<col><a>
+#errors
+(1,5): XXX-undefined-error
+(1,8): unexpected-start-tag-implies-table-voodoo
+(1,8): eof-in-table
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<colgroup><a>
+#errors
+(1,10): XXX-undefined-error
+(1,13): unexpected-start-tag-implies-table-voodoo
+(1,13): eof-in-table
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<tbody><a>
+#errors
+(1,7): XXX-undefined-error
+(1,10): unexpected-start-tag-implies-table-voodoo
+(1,10): eof-in-table
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<tfoot><a>
+#errors
+(1,7): XXX-undefined-error
+(1,10): unexpected-start-tag-implies-table-voodoo
+(1,10): eof-in-table
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<thead><a>
+#errors
+(1,7): XXX-undefined-error
+(1,10): unexpected-start-tag-implies-table-voodoo
+(1,10): eof-in-table
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+</table><a>
+#errors
+(1,8): XXX-undefined-error
+(1,11): unexpected-start-tag-implies-table-voodoo
+(1,11): eof-in-table
+#document-fragment
+tbody
+#document
+| <a>
+
+#data
+<a><tr>
+#errors
+(1,3): unexpected-start-tag-implies-table-voodoo
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+
+#data
+<a><td>
+#errors
+(1,3): unexpected-start-tag-implies-table-voodoo
+(1,7): unexpected-cell-in-table-body
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+| <td>
+
+#data
+<a><td>
+#errors
+(1,3): unexpected-start-tag-implies-table-voodoo
+(1,7): unexpected-cell-in-table-body
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+| <td>
+
+#data
+<a><td>
+#errors
+(1,3): unexpected-start-tag-implies-table-voodoo
+(1,7): unexpected-cell-in-table-body
+#document-fragment
+tbody
+#document
+| <a>
+| <tr>
+| <td>
+
+#data
+<td><table><tbody><a><tr>
+#errors
+(1,4): unexpected-cell-in-table-body
+(1,21): unexpected-start-tag-implies-table-voodoo
+(1,25): eof-in-table
+#document-fragment
+tbody
+#document
+| <tr>
+| <td>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+</tr><td>
+#errors
+(1,5): XXX-undefined-error
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<td><table><a><tr></tr><tr>
+#errors
+(1,14): unexpected-start-tag-implies-table-voodoo
+(1,27): eof-in-table
+#document-fragment
+tr
+#document
+| <td>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+| <tr>
+
+#data
+<caption><td>
+#errors
+(1,9): XXX-undefined-error
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<col><td>
+#errors
+(1,5): XXX-undefined-error
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<colgroup><td>
+#errors
+(1,10): XXX-undefined-error
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tbody><td>
+#errors
+(1,7): XXX-undefined-error
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tfoot><td>
+#errors
+(1,7): XXX-undefined-error
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<thead><td>
+#errors
+(1,7): XXX-undefined-error
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<tr><td>
+#errors
+(1,4): XXX-undefined-error
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+</table><td>
+#errors
+(1,8): XXX-undefined-error
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<td><table></table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+| <table>
+| <td>
+
+#data
+<td><table></table><td>
+#errors
+#document-fragment
+tr
+#document
+| <td>
+| <table>
+| <td>
+
+#data
+<caption><a>
+#errors
+(1,9): XXX-undefined-error
+(1,12): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<col><a>
+#errors
+(1,5): XXX-undefined-error
+(1,8): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<colgroup><a>
+#errors
+(1,10): XXX-undefined-error
+(1,13): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tbody><a>
+#errors
+(1,7): XXX-undefined-error
+(1,10): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tfoot><a>
+#errors
+(1,7): XXX-undefined-error
+(1,10): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<th><a>
+#errors
+(1,4): XXX-undefined-error
+(1,7): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<thead><a>
+#errors
+(1,7): XXX-undefined-error
+(1,10): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<tr><a>
+#errors
+(1,4): XXX-undefined-error
+(1,7): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</table><a>
+#errors
+(1,8): XXX-undefined-error
+(1,11): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tbody><a>
+#errors
+(1,8): XXX-undefined-error
+(1,11): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</td><a>
+#errors
+(1,5): unexpected-end-tag
+(1,8): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tfoot><a>
+#errors
+(1,8): XXX-undefined-error
+(1,11): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</thead><a>
+#errors
+(1,8): XXX-undefined-error
+(1,11): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</th><a>
+#errors
+(1,5): unexpected-end-tag
+(1,8): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+</tr><a>
+#errors
+(1,5): XXX-undefined-error
+(1,8): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <a>
+
+#data
+<table><td><td>
+#errors
+(1,11): unexpected-cell-in-table-body
+(1,15): expected-closing-tag-but-got-eof
+#document-fragment
+td
+#document
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <td>
+
+#data
+</select><option>
+#errors
+(1,9): XXX-undefined-error
+(1,17): eof-in-select
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<input><option>
+#errors
+(1,7): unexpected-input-in-select
+(1,15): eof-in-select
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<keygen><option>
+#errors
+(1,8): unexpected-input-in-select
+(1,16): eof-in-select
+#document-fragment
+select
+#document
+| <option>
+
+#data
+<textarea><option>
+#errors
+(1,10): unexpected-input-in-select
+(1,18): eof-in-select
+#document-fragment
+select
+#document
+| <option>
+
+#data
+</html><!--abc-->
+#errors
+(1,7): unexpected-end-tag-after-body-innerhtml
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| <!-- abc -->
+
+#data
+</frameset><frame>
+#errors
+(1,11): unexpected-frameset-in-frameset-innerhtml
+#document-fragment
+frameset
+#document
+| <frame>
+
+#data
+#errors
+#document-fragment
+html
+#document
+| <head>
+| <body>
+
+#data
+<head></head><script></script>
+#errors
+21: “script” element between “head” and “body”.
+#document-fragment
+html
+#document
+| <head>
+| <script>
+| <body>
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tricky01.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tricky01.dat
new file mode 100644
index 0000000000..f7065214ea
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/tricky01.dat
@@ -0,0 +1,334 @@
+#data
+<b><p>Bold </b> Not bold</p>
+Also not bold.
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,15): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <p>
+| <b>
+| "Bold "
+| " Not bold"
+| "
+Also not bold."
+
+#data
+<html>
+<font color=red><i>Italic and Red<p>Italic and Red </font> Just italic.</p> Italic only.</i> Plain
+<p>I should not be red. <font color=red>Red. <i>Italic and red.</p>
+<p>Italic and red. </i> Red.</font> I should not be red.</p>
+<b>Bold <i>Bold and italic</b> Only Italic </i> Plain
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(2,58): adoption-agency-1.3
+(3,67): unexpected-end-tag
+(4,23): adoption-agency-1.3
+(4,35): adoption-agency-1.3
+(5,30): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <font>
+| color="red"
+| <i>
+| "Italic and Red"
+| <i>
+| <p>
+| <font>
+| color="red"
+| "Italic and Red "
+| " Just italic."
+| " Italic only."
+| " Plain
+"
+| <p>
+| "I should not be red. "
+| <font>
+| color="red"
+| "Red. "
+| <i>
+| "Italic and red."
+| <font>
+| color="red"
+| <i>
+| "
+"
+| <p>
+| <font>
+| color="red"
+| <i>
+| "Italic and red. "
+| " Red."
+| " I should not be red."
+| "
+"
+| <b>
+| "Bold "
+| <i>
+| "Bold and italic"
+| <i>
+| " Only Italic "
+| " Plain"
+
+#data
+<html><body>
+<p><font size="7">First paragraph.</p>
+<p>Second paragraph.</p></font>
+<b><p><i>Bold and Italic</b> Italic</p>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(2,38): unexpected-end-tag
+(4,28): adoption-agency-1.3
+(4,28): adoption-agency-1.3
+(4,39): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| "
+"
+| <p>
+| <font>
+| size="7"
+| "First paragraph."
+| <font>
+| size="7"
+| "
+"
+| <p>
+| "Second paragraph."
+| "
+"
+| <b>
+| <p>
+| <b>
+| <i>
+| "Bold and Italic"
+| <i>
+| " Italic"
+
+#data
+<html>
+<dl>
+<dt><b>Boo
+<dd>Goo?
+</dl>
+</html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(4,4): end-tag-too-early
+(5,5): end-tag-too-early
+(6,7): expected-one-end-tag-but-got-another
+#document
+| <html>
+| <head>
+| <body>
+| <dl>
+| "
+"
+| <dt>
+| <b>
+| "Boo
+"
+| <dd>
+| <b>
+| "Goo?
+"
+| <b>
+| "
+"
+
+#data
+<html><body>
+<label><a><div>Hello<div>World</div></a></label>
+</body></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(2,40): adoption-agency-1.3
+(2,48): unexpected-end-tag
+(3,7): expected-one-end-tag-but-got-another
+#document
+| <html>
+| <head>
+| <body>
+| "
+"
+| <label>
+| <a>
+| <div>
+| <a>
+| "Hello"
+| <div>
+| "World"
+| "
+"
+
+#data
+<table><center> <font>a</center> <img> <tr><td> </td> </tr> </table>
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,15): foster-parenting-start-tag
+(1,16): foster-parenting-character
+(1,22): foster-parenting-start-tag
+(1,23): foster-parenting-character
+(1,32): foster-parenting-end-tag
+(1,32): end-tag-too-early
+(1,33): foster-parenting-character
+(1,38): foster-parenting-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <center>
+| " "
+| <font>
+| "a"
+| <font>
+| <img>
+| " "
+| <table>
+| " "
+| <tbody>
+| <tr>
+| <td>
+| " "
+| " "
+| " "
+
+#data
+<table><tr><p><a><p>You should see this text.
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,14): unexpected-start-tag-implies-table-voodoo
+(1,17): unexpected-start-tag-implies-table-voodoo
+(1,20): unexpected-start-tag-implies-table-voodoo
+(1,20): closing-non-current-p-element
+(1,21): foster-parenting-character
+(1,22): foster-parenting-character
+(1,23): foster-parenting-character
+(1,24): foster-parenting-character
+(1,25): foster-parenting-character
+(1,26): foster-parenting-character
+(1,27): foster-parenting-character
+(1,28): foster-parenting-character
+(1,29): foster-parenting-character
+(1,30): foster-parenting-character
+(1,31): foster-parenting-character
+(1,32): foster-parenting-character
+(1,33): foster-parenting-character
+(1,34): foster-parenting-character
+(1,35): foster-parenting-character
+(1,36): foster-parenting-character
+(1,37): foster-parenting-character
+(1,38): foster-parenting-character
+(1,39): foster-parenting-character
+(1,40): foster-parenting-character
+(1,41): foster-parenting-character
+(1,42): foster-parenting-character
+(1,43): foster-parenting-character
+(1,44): foster-parenting-character
+(1,45): foster-parenting-character
+(1,45): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <a>
+| <p>
+| <a>
+| "You should see this text."
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<TABLE>
+<TR>
+<CENTER><CENTER><TD></TD></TR><TR>
+<FONT>
+<TABLE><tr></tr></TABLE>
+</P>
+<a></font><font></a>
+This page contains an insanely badly-nested tag sequence.
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(3,8): unexpected-start-tag-implies-table-voodoo
+(3,16): unexpected-start-tag-implies-table-voodoo
+(4,6): unexpected-start-tag-implies-table-voodoo
+(5,7): unexpected-start-tag-implies-end-tag
+(7,10): adoption-agency-1.3
+(7,20): adoption-agency-1.3
+(8,57): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <center>
+| <center>
+| <font>
+| "
+"
+| <table>
+| "
+"
+| <tbody>
+| <tr>
+| "
+"
+| <td>
+| <tr>
+| "
+"
+| <table>
+| <tbody>
+| <tr>
+| <font>
+| "
+"
+| <p>
+| "
+"
+| <a>
+| <a>
+| <font>
+| <font>
+| "
+This page contains an insanely badly-nested tag sequence."
+
+#data
+<html>
+<body>
+<b><nobr><div>This text is in a div inside a nobr</nobr>More text that should not be in the nobr, i.e., the
+nobr should have closed the div inside it implicitly. </b><pre>A pre tag outside everything else.</pre>
+</body>
+</html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(3,56): adoption-agency-1.3
+(4,58): adoption-agency-1.3
+(5,7): expected-one-end-tag-but-got-another
+#document
+| <html>
+| <head>
+| <body>
+| "
+"
+| <b>
+| <nobr>
+| <div>
+| <b>
+| <nobr>
+| "This text is in a div inside a nobr"
+| "More text that should not be in the nobr, i.e., the
+nobr should have closed the div inside it implicitly. "
+| <pre>
+| "A pre tag outside everything else."
+| "
+
+"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/webkit01.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/webkit01.dat
new file mode 100644
index 0000000000..c480accd95
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/webkit01.dat
@@ -0,0 +1,705 @@
+#data
+Test
+#errors
+(1,4): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<div></div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<div>Test</div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Test"
+
+#data
+<di
+#errors
+(1,3): eof-in-tag-name
+(1,3): expected-doctype-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<div>Hello</div>
+<script>
+console.log("PASS");
+</script>
+<div>Bye</div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Hello"
+| "
+"
+| <script>
+| "
+console.log("PASS");
+"
+| "
+"
+| <div>
+| "Bye"
+
+#data
+<div foo="bar">Hello</div>
+#errors
+(1,15): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo="bar"
+| "Hello"
+
+#data
+<div>Hello</div>
+<script>
+console.log("FOO<span>BAR</span>BAZ");
+</script>
+<div>Bye</div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Hello"
+| "
+"
+| <script>
+| "
+console.log("FOO<span>BAR</span>BAZ");
+"
+| "
+"
+| <div>
+| "Bye"
+
+#data
+<foo bar="baz"></foo><potato quack="duck"></potato>
+#errors
+(1,15): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| bar="baz"
+| <potato>
+| quack="duck"
+
+#data
+<foo bar="baz"><potato quack="duck"></potato></foo>
+#errors
+(1,15): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| bar="baz"
+| <potato>
+| quack="duck"
+
+#data
+<foo></foo bar="baz"><potato></potato quack="duck">
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,21): attributes-in-end-tag
+(1,51): attributes-in-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| <potato>
+
+#data
+</ tttt>
+#errors
+(1,2): expected-closing-tag-but-got-char
+(1,8): expected-doctype-but-got-eof
+#document
+| <!-- tttt -->
+| <html>
+| <head>
+| <body>
+
+#data
+<div FOO ><img><img></div>
+#errors
+(1,10): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo=""
+| <img>
+| <img>
+
+#data
+<p>Test</p<p>Test2</p>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,13): unexpected-end-tag
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| "TestTest2"
+
+#data
+<rdar://problem/6869687>
+#errors
+(1,7): unexpected-character-after-solidus-in-tag
+(1,8): unexpected-character-after-solidus-in-tag
+(1,16): unexpected-character-after-solidus-in-tag
+(1,24): expected-doctype-but-got-start-tag
+(1,24): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <rdar:>
+| 6869687=""
+| problem=""
+
+#data
+<A>test< /A>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,8): expected-tag-name
+(1,12): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "test< /A>"
+
+#data
+&lt;
+#errors
+(1,4): expected-doctype-but-got-chars
+#document
+| <html>
+| <head>
+| <body>
+| "<"
+
+#data
+<body foo='bar'><body foo='baz' yo='mama'>
+#errors
+(1,16): expected-doctype-but-got-start-tag
+(1,42): unexpected-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| foo="bar"
+| yo="mama"
+
+#data
+<body></br foo="bar"></body>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,21): attributes-in-end-tag
+(1,21): unexpected-end-tag-treated-as
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+
+#data
+<bdy><br foo="bar"></body>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,26): expected-one-end-tag-but-got-another
+#document
+| <html>
+| <head>
+| <body>
+| <bdy>
+| <br>
+| foo="bar"
+
+#data
+<body></body></br foo="bar">
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,28): attributes-in-end-tag
+(1,28): unexpected-end-tag-after-body
+(1,28): unexpected-end-tag-treated-as
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+
+#data
+<bdy></body><br foo="bar">
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,12): expected-one-end-tag-but-got-another
+(1,26): unexpected-start-tag-after-body
+(1,26): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <bdy>
+| <br>
+| foo="bar"
+
+#data
+<html><body></body></html><!-- Hi there -->
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <!-- Hi there -->
+
+#data
+<html><body></body></html>x<!-- Hi there -->
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,27): expected-eof-but-got-char
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></html><!-- Again -->
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,27): expected-eof-but-got-char
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+| <!-- Again -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></body></html><!-- Again -->
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,27): expected-eof-but-got-char
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+| <!-- Again -->
+
+#data
+<html><body><ruby><div><rp>xx</rp></div></ruby></body></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,27): XXX-undefined-error
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <rp>
+| "xx"
+
+#data
+<html><body><ruby><div><rt>xx</rt></div></ruby></body></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,27): XXX-undefined-error
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <rt>
+| "xx"
+
+#data
+<html><frameset><!--1--><noframes>A</noframes><!--2--></frameset><!--3--><noframes>B</noframes><!--4--></html><!--5--><noframes>C</noframes><!--6-->
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <frameset>
+| <!-- 1 -->
+| <noframes>
+| "A"
+| <!-- 2 -->
+| <!-- 3 -->
+| <noframes>
+| "B"
+| <!-- 4 -->
+| <noframes>
+| "C"
+| <!-- 5 -->
+| <!-- 6 -->
+
+#data
+<select><option>A<select><option>B<select><option>C<select><option>D<select><option>E<select><option>F<select><option>G<select>
+#errors
+(1,8): expected-doctype-but-got-start-tag
+(1,25): unexpected-select-in-select
+(1,59): unexpected-select-in-select
+(1,93): unexpected-select-in-select
+(1,127): unexpected-select-in-select
+(1,127): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| "A"
+| <option>
+| "B"
+| <select>
+| <option>
+| "C"
+| <option>
+| "D"
+| <select>
+| <option>
+| "E"
+| <option>
+| "F"
+| <select>
+| <option>
+| "G"
+
+#data
+<dd><dd><dt><dt><dd><li><li>
+#errors
+(1,4): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <dd>
+| <dd>
+| <dt>
+| <dt>
+| <dd>
+| <li>
+| <li>
+
+#data
+<div><b></div><div><nobr>a<nobr>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,14): end-tag-too-early
+(1,32): unexpected-start-tag-implies-end-tag
+(1,32): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <b>
+| <div>
+| <b>
+| <nobr>
+| "a"
+| <nobr>
+
+#data
+<head></head>
+<body></body>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| "
+"
+| <body>
+
+#data
+<head></head> <style></style>ddd
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,21): unexpected-start-tag-out-of-my-head
+#document
+| <html>
+| <head>
+| <style>
+| " "
+| <body>
+| "ddd"
+
+#data
+<kbd><table></kbd><col><select><tr>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,18): unexpected-end-tag-implies-table-voodoo
+(1,18): unexpected-end-tag
+(1,31): unexpected-start-tag-implies-table-voodoo
+(1,35): unexpected-table-element-start-tag-in-select-in-table
+(1,35): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| <kbd>
+| <select>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+
+#data
+<kbd><table></kbd><col><select><tr></table><div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,18): unexpected-end-tag-implies-table-voodoo
+(1,18): unexpected-end-tag
+(1,31): unexpected-start-tag-implies-table-voodoo
+(1,35): unexpected-table-element-start-tag-in-select-in-table
+(1,48): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <kbd>
+| <select>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <div>
+
+#data
+<a><li><style></style><title></title></a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,41): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <li>
+| <a>
+| <style>
+| <title>
+
+#data
+<font></p><p><meta><title></title></font>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,10): unexpected-end-tag
+(1,41): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <p>
+| <font>
+| <meta>
+| <title>
+
+#data
+<a><center><title></title><a>
+#errors
+(1,3): expected-doctype-but-got-start-tag
+(1,29): unexpected-start-tag-implies-end-tag
+(1,29): adoption-agency-1.3
+(1,29): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <center>
+| <a>
+| <title>
+| <a>
+
+#data
+<svg><title><div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,17): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <div>
+
+#data
+<svg><title><rect><div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,23): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <rect>
+| <div>
+
+#data
+<svg><title><svg><div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,22): unexpected-html-element-in-foreign-content
+(1,22): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <svg svg>
+| <div>
+
+#data
+<img <="" FAIL>
+#errors
+(1,6): invalid-character-in-attribute-name
+(1,15): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <img>
+| <=""
+| fail=""
+
+#data
+<ul><li><div id='foo'/>A</li><li>B<div>C</div></li></ul>
+#errors
+(1,4): expected-doctype-but-got-start-tag
+(1,23): non-void-element-with-trailing-solidus
+(1,29): end-tag-too-early
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| id="foo"
+| "A"
+| <li>
+| "B"
+| <div>
+| "C"
+
+#data
+<svg><em><desc></em>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,9): unexpected-html-element-in-foreign-content
+(1,20): adoption-agency-1.3
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <em>
+| <desc>
+
+#data
+<svg><tfoot></mi><td>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+(1,17): unexpected-end-tag
+(1,17): unexpected-end-tag
+(1,21): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg tfoot>
+| <svg td>
+
+#data
+<math><mrow><mrow><mn>1</mn></mrow><mi>a</mi></mrow></math>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mrow>
+| <math mrow>
+| <math mn>
+| "1"
+| <math mi>
+| "a"
+
+#data
+<!doctype html><input type="hidden"><frameset>
+#errors
+(1,46): unexpected-start-tag
+(1,46): eof-in-frameset
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><input type="button"><frameset>
+#errors
+(1,46): unexpected-start-tag
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+| type="button"
diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/webkit02.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/webkit02.dat
new file mode 100644
index 0000000000..647fcfd41f
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/webkit02.dat
@@ -0,0 +1,116 @@
+#data
+<foo bar=qux/>
+#errors
+(1,14): expected-doctype-but-got-start-tag
+(1,14): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| bar="qux/"
+
+#data
+<p id="status"><noscript><strong>A</strong></noscript><span>B</span></p>
+#errors
+(1,15): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| id="status"
+| <noscript>
+| "<strong>A</strong>"
+| <span>
+| "B"
+
+#data
+<div><sarcasm><div></div></sarcasm></div>
+#errors
+(1,5): expected-doctype-but-got-start-tag
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <sarcasm>
+| <div>
+
+#data
+<html><body><img src="" border="0" alt="><div>A</div></body></html>
+#errors
+(1,6): expected-doctype-but-got-start-tag
+(1,67): eof-in-attribute-value-double-quote
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<table><td></tbody>A
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,11): unexpected-cell-in-table-body
+(1,20): foster-parenting-character
+(1,20): eof-in-table
+#document
+| <html>
+| <head>
+| <body>
+| "A"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><td></thead>A
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,11): unexpected-cell-in-table-body
+(1,19): XXX-undefined-error
+(1,20): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "A"
+
+#data
+<table><td></tfoot>A
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,11): unexpected-cell-in-table-body
+(1,19): XXX-undefined-error
+(1,20): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "A"
+
+#data
+<table><thead><td></tbody>A
+#errors
+(1,7): expected-doctype-but-got-start-tag
+(1,18): unexpected-cell-in-table-body
+(1,26): XXX-undefined-error
+(1,27): expected-closing-tag-but-got-eof
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <thead>
+| <tr>
+| <td>
+| "A"
diff --git a/parser/htmlparser/tests/mochitest/invalidchar.xml b/parser/htmlparser/tests/mochitest/invalidchar.xml
new file mode 100644
index 0000000000..d4ad7f0571
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/invalidchar.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<root>
+ <fail> This is an invalid byte in UTF-8: </fail>
+</root>
diff --git a/parser/htmlparser/tests/mochitest/mochitest.ini b/parser/htmlparser/tests/mochitest/mochitest.ini
new file mode 100644
index 0000000000..5aa9c5e133
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/mochitest.ini
@@ -0,0 +1,152 @@
+[DEFAULT]
+support-files =
+ bug_502091_iframe.html
+ file_bug102699.sjs
+ file_bug534293-slow.sjs
+ file_bug534293.sjs
+ file_bug543062.sjs
+ file_bug594730-1.html
+ file_bug594730-2.html
+ file_bug594730-3.html
+ file_bug594730-4.html
+ file_bug594730-5.html
+ file_bug594730-6.html
+ file_bug594730-7.html
+ file_bug594730-8.html
+ file_bug594730-9.html
+ file_bug642908.sjs
+ file_bug655682.sjs
+ file_bug672453_bomless_utf16.html
+ file_bug672453_http_unsupported.html
+ file_bug672453_http_unsupported.html^headers^
+ file_bug672453_late_meta.html
+ file_bug672453_meta_non_superset.html
+ file_bug672453_meta_restart.html
+ file_bug672453_meta_unsupported.html
+ file_bug672453_meta_utf16.html
+ file_bug688580.js
+ file_bug672453_not_declared.html
+ file_bug672453_meta_userdefined.html
+ file_bug716579-16.html
+ file_bug716579-16.html^headers^
+ file_bug716579-16.xhtml
+ file_bug716579-16.xhtml^headers^
+ file_bug716579-8.html
+ file_bug716579-8.html^headers^
+ file_bug716579-8.xhtml
+ file_bug716579-8.xhtml^headers^
+ file_bug717180.html
+ file_img_picture_preload.html
+ file_img_picture_preload.sjs
+ html5_tree_construction_exceptions.js
+ invalidchar.xml
+ parser_datreader.js
+ parser_web_testrunner.js
+ dir_bug534293/file_bug534293.sjs
+ html5lib_tree_construction/adoption01.dat
+ html5lib_tree_construction/adoption02.dat
+ html5lib_tree_construction/comments01.dat
+ html5lib_tree_construction/doctype01.dat
+ html5lib_tree_construction/domjs-unsafe.dat
+ html5lib_tree_construction/entities01.dat
+ html5lib_tree_construction/entities02.dat
+ html5lib_tree_construction/foreign-fragment.dat
+ html5lib_tree_construction/html5test-com.dat
+ html5lib_tree_construction/inbody01.dat
+ html5lib_tree_construction/isindex.dat
+ html5lib_tree_construction/pending-spec-changes.dat
+ html5lib_tree_construction/pending-spec-changes-plain-text-unsafe.dat
+ html5lib_tree_construction/plain-text-unsafe.dat
+ html5lib_tree_construction/scriptdata01.dat
+ html5lib_tree_construction/tables01.dat
+ html5lib_tree_construction/template.dat
+ html5lib_tree_construction/tests10.dat
+ html5lib_tree_construction/tests11.dat
+ html5lib_tree_construction/tests12.dat
+ html5lib_tree_construction/tests14.dat
+ html5lib_tree_construction/tests15.dat
+ html5lib_tree_construction/tests16.dat
+ html5lib_tree_construction/tests17.dat
+ html5lib_tree_construction/tests18.dat
+ html5lib_tree_construction/tests19.dat
+ html5lib_tree_construction/tests1.dat
+ html5lib_tree_construction/tests20.dat
+ html5lib_tree_construction/tests21.dat
+ html5lib_tree_construction/tests22.dat
+ html5lib_tree_construction/tests23.dat
+ html5lib_tree_construction/tests24.dat
+ html5lib_tree_construction/tests25.dat
+ html5lib_tree_construction/tests26.dat
+ html5lib_tree_construction/tests2.dat
+ html5lib_tree_construction/tests3.dat
+ html5lib_tree_construction/tests4.dat
+ html5lib_tree_construction/tests5.dat
+ html5lib_tree_construction/tests6.dat
+ html5lib_tree_construction/tests7.dat
+ html5lib_tree_construction/tests8.dat
+ html5lib_tree_construction/tests9.dat
+ html5lib_tree_construction/tests_innerHTML_1.dat
+ html5lib_tree_construction/tricky01.dat
+ html5lib_tree_construction/webkit01.dat
+ html5lib_tree_construction/webkit02.dat
+ html5lib_tree_construction/main-element.dat
+ html5lib_tree_construction/ruby.dat
+ html5lib_tree_construction/scripted/adoption01.dat
+ html5lib_tree_construction/scripted/webkit01.dat
+ html5lib_tree_construction/scripted/ark.dat
+ blue.png
+
+[test_bug102699.html]
+[test_bug174351.html]
+[test_bug213517.html]
+[test_bug339350.xhtml]
+[test_bug358797.html]
+[test_bug396568.html]
+[test_bug418464.html]
+[test_bug460437.xhtml]
+skip-if = (xorigin && debug)
+[test_bug502091.html]
+[test_bug543062.html]
+[test_bug552938-2.html]
+[test_bug552938.html]
+[test_bug563322.xhtml]
+[test_bug566879.html]
+[test_bug594730.html]
+[test_bug613662.html]
+[test_bug613662.xhtml]
+skip-if = (xorigin && debug)
+[test_bug639362.html]
+[test_bug642908.html]
+[test_bug645115.html]
+[test_bug655682.html]
+[test_bug667533.html]
+[test_bug672453.html]
+[test_bug688580.html]
+[test_bug688580.xhtml]
+[test_bug709083.html]
+[test_bug715112.html]
+[test_bug715739.html]
+[test_bug716579.html]
+[test_bug717180.html]
+[test_bug1104732.html]
+support-files =
+ file_defer_bug1104732.js
+ file_async_bug1104732.sjs
+
+[test_compatmode.html]
+[test_html5_tree_construction.html]
+[test_html5_tree_construction_part2.html]
+[test_img_picture_preload.html]
+skip-if = (verify && debug && (os == 'linux' || os == 'mac'))
+[test_xml_mislabeled.html]
+# Disabled test due to orange on Linux
+# test_bug568470.html
+# file_bug568470.sjs
+# file_bug568470-script.sjs
+# Disable test due to frequent orange on Mac
+# test_bug534293.html
+[test_bug1209658.html]
+[test_bug1364399.html]
+[test_bug1646140-1.html]
+[test_bug1646140-2.html]
+skip-if = headless # Bug 1685088
diff --git a/parser/htmlparser/tests/mochitest/parser_datreader.js b/parser/htmlparser/tests/mochitest/parser_datreader.js
new file mode 100644
index 0000000000..de31037150
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/parser_datreader.js
@@ -0,0 +1,216 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * A test suite that runs WHATWG HTML parser tests.
+ * The tests are from html5lib.
+ *
+ * http://html5lib.googlecode.com/
+ */
+
+/**
+ * A few utility functions.
+ */
+function log(entry) {}
+
+function startsWith(s, s2) {
+ return s.indexOf(s2) == 0;
+}
+
+function trimString(s) {
+ return s.replace(/^\s+/, "").replace(/\s+$/, "");
+}
+
+/**
+ * Parses an individual testcase into an array containing the input
+ * string, a string representing the expected tree (DOM), and a list
+ * of error messages.
+ *
+ * @param A string containing a single testcase
+ */
+function parseTestcase(testcase) {
+ var lines = testcase.split("\n");
+
+ /* check that the first non-empty, non-comment line is #data */
+ for (let line of lines) {
+ if (!line || startsWith(line, "##")) {
+ continue;
+ }
+ if (line == "#data") {
+ break;
+ }
+ log(lines);
+ throw new Error("Unknown test format.");
+ }
+
+ var input = [];
+ var output = [];
+ var errors = [];
+ var fragment = [];
+ var currentList = input;
+ for (let line of lines) {
+ if (startsWith(line, "##todo")) {
+ todo(false, line.substring(6));
+ continue;
+ }
+ if (
+ !(
+ startsWith(line, "#error") ||
+ startsWith(line, "#document") ||
+ startsWith(line, "#document-fragment") ||
+ startsWith(line, "#data")
+ )
+ ) {
+ currentList.push(line);
+ } else if (line == "#errors") {
+ currentList = errors;
+ } else if (line == "#document") {
+ currentList = output;
+ } else if (line == "#document-fragment") {
+ currentList = fragment;
+ }
+ }
+ while (!output[output.length - 1]) {
+ output.pop(); // zap trailing blank lines
+ }
+ // logger.log(input.length, output.length, errors.length);
+ return [input.join("\n"), output.join("\n"), errors, fragment[0]];
+}
+
+/**
+ * A generator function that accepts a list of strings. Each list
+ * member corresponds to the contents of a ".dat" file from the
+ * html5lib test suite.
+ *
+ * @param The list of strings
+ */
+function* test_parser(testlist) {
+ for (var testgroup of testlist) {
+ var tests = testgroup.split("#data\n");
+ tests = tests.filter(test => test).map(test => "#data\n" + test);
+ for (var test of tests) {
+ yield parseTestcase(test);
+ }
+ }
+}
+
+/**
+ * Transforms a DOM document to a string matching the format in
+ * the test cases.
+ *
+ * @param the DOM document
+ */
+function docToTestOutput(doc) {
+ var walker = doc.createTreeWalker(doc, NodeFilter.SHOW_ALL, null);
+ return addLevels(walker, "", "| ").slice(0, -1); // remove the last newline
+}
+
+/**
+ * Creates a walker for a fragment that skips over the root node.
+ *
+ * @param an element
+ */
+function createFragmentWalker(elt) {
+ return elt.ownerDocument.createTreeWalker(elt, NodeFilter.SHOW_ALL, function(
+ node
+ ) {
+ return elt == node ? NodeFilter.FILTER_SKIP : NodeFilter.FILTER_ACCEPT;
+ });
+}
+
+/**
+ * Transforms the descendants of an element to a string matching the format
+ * in the test cases.
+ *
+ * @param an element
+ */
+function fragmentToTestOutput(elt) {
+ var walker = createFragmentWalker(elt);
+ return addLevels(walker, "", "| ").slice(0, -1); // remove the last newline
+}
+
+function addLevels(walker, buf, indent) {
+ if (walker.firstChild()) {
+ do {
+ buf += indent;
+ switch (walker.currentNode.nodeType) {
+ case Node.ELEMENT_NODE:
+ buf += "<";
+ var ns = walker.currentNode.namespaceURI;
+ if ("http://www.w3.org/1998/Math/MathML" == ns) {
+ buf += "math ";
+ } else if ("http://www.w3.org/2000/svg" == ns) {
+ buf += "svg ";
+ } else if ("http://www.w3.org/1999/xhtml" != ns) {
+ buf += "otherns ";
+ }
+ buf += walker.currentNode.localName + ">";
+ if (walker.currentNode.hasAttributes()) {
+ var valuesByName = {};
+ var attrs = walker.currentNode.attributes;
+ for (let i = 0; i < attrs.length; ++i) {
+ var localName = attrs[i].localName;
+ var name;
+ var attrNs = attrs[i].namespaceURI;
+ if (null == attrNs) {
+ name = localName;
+ } else if ("http://www.w3.org/XML/1998/namespace" == attrNs) {
+ name = "xml " + localName;
+ } else if ("http://www.w3.org/1999/xlink" == attrNs) {
+ name = "xlink " + localName;
+ } else if ("http://www.w3.org/2000/xmlns/" == attrNs) {
+ name = "xmlns " + localName;
+ } else {
+ name = "otherns " + localName;
+ }
+ valuesByName[name] = attrs[i].value;
+ }
+ var keys = Object.keys(valuesByName).sort();
+ for (let i = 0; i < keys.length; ++i) {
+ buf +=
+ "\n" +
+ indent +
+ " " +
+ keys[i] +
+ '="' +
+ valuesByName[keys[i]] +
+ '"';
+ }
+ }
+ break;
+ case Node.DOCUMENT_TYPE_NODE:
+ buf += "<!DOCTYPE " + walker.currentNode.name;
+ if (walker.currentNode.publicId || walker.currentNode.systemId) {
+ buf += ' "';
+ buf += walker.currentNode.publicId;
+ buf += '" "';
+ buf += walker.currentNode.systemId;
+ buf += '"';
+ }
+ buf += ">";
+ break;
+ case Node.COMMENT_NODE:
+ buf += "<!-- " + walker.currentNode.nodeValue + " -->";
+ break;
+ case Node.TEXT_NODE:
+ buf += '"' + walker.currentNode.nodeValue + '"';
+ break;
+ }
+ buf += "\n";
+ // In the case of template elements, children do not get inserted as
+ // children of the template element, instead they are inserted
+ // as children of the template content (which is a document fragment).
+ if (walker.currentNode instanceof HTMLTemplateElement) {
+ buf += indent + " content\n";
+ // Walk through the template content.
+ var templateWalker = createFragmentWalker(walker.currentNode.content);
+ buf = addLevels(templateWalker, buf, indent + " ");
+ }
+ buf = addLevels(walker, buf, indent + " ");
+ } while (walker.nextSibling());
+ walker.parentNode();
+ }
+ return buf;
+}
diff --git a/parser/htmlparser/tests/mochitest/parser_web_testrunner.js b/parser/htmlparser/tests/mochitest/parser_web_testrunner.js
new file mode 100644
index 0000000000..57807f5b6c
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/parser_web_testrunner.js
@@ -0,0 +1,149 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Runs html5lib-formatted test cases in the browser. Requires SimpleTest.
+ *
+ * Define an array named parserDatFiles before loading this script,
+ * and it will load each of those dat files into an array, then run
+ * the test parser on each and run the tests by assigning the input
+ * data to an iframe's url.
+ *
+ * Your test document should have an element with id "display" and
+ * an iframe with id "testframe".
+ */
+
+/* import-globals-from ./parser_datreader.js */
+/* import-globals-from ./html5_tree_construction_exceptions.js */
+/* globals parserDatFiles */
+
+var functionsToRunAsync = [];
+
+window.addEventListener(
+ "message",
+ function(event) {
+ if (event.source == window && event.data == "async-run") {
+ event.stopPropagation();
+ var fn = functionsToRunAsync.shift();
+ fn();
+ }
+ },
+ true
+);
+
+function asyncRun(fn) {
+ functionsToRunAsync.push(fn);
+ window.postMessage("async-run", "*");
+}
+
+function writeErrorSummary(input, expected, got, isTodo) {
+ if (isTodo) {
+ $("display").appendChild(createEl("h2", null, "Unexpected Success:"));
+ } else {
+ $("display").appendChild(createEl("h2", null, "Unexpected Failure:"));
+ }
+ $("display").appendChild(createEl("br"));
+ $("display").appendChild(createEl("span", null, "Matched: "));
+ $("display").appendChild(document.createTextNode("" + (expected == got)));
+ var pre = createEl("pre");
+ pre.appendChild(document.createTextNode("Input: \n" + input, "\n-\n"));
+ pre.appendChild(document.createTextNode("Expected:\n" + expected, "\n-\n"));
+ pre.appendChild(document.createTextNode("Output:\n" + got + "\n-\n"));
+ $("display").appendChild(pre);
+ $("display").appendChild(createEl("hr"));
+}
+
+/**
+ * Control will bounce back and forth between nextTest() and the
+ * event handler returned by makeTestChecker() or the callback returned by
+ * makeFragmentTestChecker() until the 'testcases' iterator is spent.
+ */
+function makeTestChecker(input, expected, errors) {
+ return function(e) {
+ var domAsString = docToTestOutput(e.target.contentDocument);
+ if (html5Exceptions[input]) {
+ todo_is(domAsString, expected, "HTML5 expected success.");
+ if (domAsString == expected) {
+ writeErrorSummary(input, expected, domAsString, true);
+ }
+ } else {
+ is(domAsString, expected, "HTML5 expected success.");
+ if (domAsString != expected) {
+ writeErrorSummary(input, expected, domAsString, false);
+ }
+ }
+ nextTest(e.target);
+ };
+}
+
+function makeFragmentTestChecker(input, expected, errors, fragment, testframe) {
+ return function() {
+ var context;
+ if (fragment.startsWith("svg ")) {
+ context = document.createElementNS(
+ "http://www.w3.org/2000/svg",
+ fragment.substring(4)
+ );
+ } else if (fragment.startsWith("math ")) {
+ context = document.createElementNS(
+ "http://www.w3.org/1998/Math/MathML",
+ fragment.substring(5)
+ );
+ } else {
+ context = document.createElementNS(
+ "http://www.w3.org/1999/xhtml",
+ fragment
+ );
+ }
+ // eslint-disable-next-line no-unsanitized/property
+ context.innerHTML = input;
+ var domAsString = fragmentToTestOutput(context);
+ is(domAsString, expected, "HTML5 expected success. " + new Date());
+ if (domAsString != expected) {
+ writeErrorSummary(input, expected, domAsString, false);
+ }
+ nextTest(testframe);
+ };
+}
+
+var testcases;
+function nextTest(testframe) {
+ var { done, value } = testcases.next();
+ if (done) {
+ SimpleTest.finish();
+ return;
+ }
+ var [input, output, errors, fragment] = value;
+ if (fragment) {
+ asyncRun(
+ makeFragmentTestChecker(input, output, errors, fragment, testframe)
+ );
+ } else {
+ testframe.onload = makeTestChecker(input, output, errors);
+ testframe.srcdoc = input;
+ }
+}
+
+var testFileContents = [];
+function loadNextTestFile() {
+ var datFile = parserDatFiles.shift();
+ if (datFile) {
+ var xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = function() {
+ if (this.readyState == 4) {
+ testFileContents.push(this.responseText);
+ loadNextTestFile();
+ }
+ };
+ xhr.open("GET", "html5lib_tree_construction/" + datFile);
+ xhr.send();
+ } else {
+ testcases = test_parser(testFileContents);
+ nextTest($("testframe"));
+ }
+}
+
+addLoadEvent(loadNextTestFile);
+SimpleTest.waitForExplicitFinish();
diff --git a/parser/htmlparser/tests/mochitest/test_bug102699.html b/parser/htmlparser/tests/mochitest/test_bug102699.html
new file mode 100644
index 0000000000..f7d88910cf
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug102699.html
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=102699
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 102699</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=102699">Mozilla Bug 102699</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 102699 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var p = new DOMParser();
+
+var d = p.parseFromString(
+'<meta charset="windows-1252">' +
+"\u003cscript>" +
+'document.documentElement.setAttribute("data-fail", "FAIL");' +
+"\u003c/script>" +
+'\u003cscript src="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug102699.sjs">\u003c/script>' +
+'\u003cscript src="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug102699.sjs" defer>\u003c/script>' +
+'\u003cscript src="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug102699.sjs" async>\u003c/script>' +
+'<link type="stylesheet" href="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug102699.sjs">' +
+'<body onload=\'document.documentElement.setAttribute("data-fail", "FAIL");\'>' +
+'<img src="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug102699.sjs">' +
+'<iframe src="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug102699.sjs"></iframe>' +
+'<video poster="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug102699.sjs" src="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug102699.sjs"></video>' +
+'<object data="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug102699.sjs"></object>' +
+'<noscript><div></div></noscript>"', "text/html");
+
+is(d.createElement("div").tagName, "DIV", "The created document should have HTML nature.");
+
+is(d.getElementsByTagName("div").length, 1, "There should be one div.");
+
+is(d.contentType, "text/html", "contentType should be text/html");
+
+is(d.characterSet, "UTF-8", "Expected the <meta> to be ignored.");
+
+is(d.compatMode, "BackCompat", "Should be in the quirks mode.");
+
+var scripts = d.getElementsByTagName("script");
+is(scripts.length, 4, "Unexpected number of scripts.");
+while (scripts.length) {
+ // These should not run when moved to another doc
+ document.body.appendChild(scripts[0]);
+}
+var s = document.createElement("script");
+s.src = "file_bug102699.sjs?report=1";
+document.body.appendChild(s);
+
+function continueAfterReport() {
+ ok(!d.documentElement.hasAttribute("data-fail"), "Should not have a data-fail attribute.");
+
+ d = p.parseFromString("<!DOCTYPE html>", "text/html");
+ is(d.compatMode, "CSS1Compat", "Should be in the standards mode.");
+
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug1104732.html b/parser/htmlparser/tests/mochitest/test_bug1104732.html
new file mode 100644
index 0000000000..7a77e5936d
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug1104732.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1104732
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1104732</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1104732 **/
+
+ // Expected order of the values of the "state" variable:
+ // Test starting
+ // defer
+ // DOMContentLoaded
+ // load
+
+ // In the meantime, the async script load should happen before load.
+ // Ideally, we would want to assert that it happens after DOMContentLoaded,
+ // because it shouldn't be holding up DOMContentLoaded, but there is
+ // no *guarantee* that this is the case, so we cannot assert it.
+
+ var state = "Test starting";
+ var asyncState = "not loaded";
+ SimpleTest.waitForExplicitFinish();
+ is(document.readyState, "loading", "Document should have been loading.");
+ document.addEventListener("DOMContentLoaded", function() {
+ is(document.readyState, "interactive", "readyState should be interactive during DOMContentLoaded.");
+ is(state, "defer", "Bad state upon DOMContentLoaded");
+ state = "DOMContentLoaded";
+ // This doesn't work (see above), but we can't "todo" this assertion either, because
+ // it will sometimes be the case...
+ // isnot(asyncState, "loaded", "Async script should not have delayed domcontentloaded");
+ });
+ window.addEventListener("load", function() {
+ is(document.readyState, "complete", "readyState should be complete during load.");
+ is(state, "DOMContentLoaded", "Bad state upon load");
+ state = "load";
+ is(asyncState, "loaded", "Async script should be loaded upon document load event");
+ SimpleTest.finish();
+ });
+ </script>
+ <script defer src="file_defer_bug1104732.js"></script>
+ <script async src="file_async_bug1104732.sjs"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1104732">Mozilla Bug 1104732</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_bug1209658.html b/parser/htmlparser/tests/mochitest/test_bug1209658.html
new file mode 100644
index 0000000000..3ef27d1925
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug1209658.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1209658
+-->
+<head>
+ <title>Test for Bug 1209658</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1209658">Mozilla Bug 1209658</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+addLoadEvent(function loaded() {
+ for (var iframe of document.querySelectorAll("iframe")) {
+ is(SpecialPowers.wrap(iframe).contentWindow.location.href, iframe.src, "should load correct URL");
+ is(SpecialPowers.wrap(iframe).contentDocument.body.textContent, '{"<p>Hello</p>": null}',
+ iframe.getAttribute("mimeType") + " should be treated as text");
+ }
+ SimpleTest.finish();
+});
+</script>
+<iframe src="data:text/json,{&quot;<p>Hello</p>&quot;:%20null}"
+ mimeType="text/json"></iframe>
+<!-- Totally not valid VTT data, but doesn't matter for our purposes here -->
+<iframe src="data:text/vtt,{&quot;<p>Hello</p>&quot;:%20null}"
+ mimeType="text/vtt"></iframe>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug1364399.html b/parser/htmlparser/tests/mochitest/test_bug1364399.html
new file mode 100644
index 0000000000..84d9a38aed
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug1364399.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1364399
+-->
+<head>
+ <title>Test for Bug 1364399</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1364399">Mozilla Bug 1364399</a>
+<p id="display"></p>
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1364399 **/
+// Non-data: version at dom/base/test/test_bug518104.html
+SimpleTest.waitForExplicitFinish();
+
+function done() {
+ // document.write should have gotten ignored due to the
+ // ignore-destructive-writes counter. Then document.close should
+ // have gotten ignored due to the parser still being not-script-created.
+ var iframe = document.getElementById("iframe");
+ var divs = iframe.contentWindow.document.getElementsByTagName("div").length;
+ is(divs, 2, "<div>s are still there.");
+ var ps = iframe.contentWindow.document.getElementsByTagName("p").length;
+ is(ps, 0, "<p> did not get written.");
+ SimpleTest.finish();
+}
+
+</script>
+<div id="content" style="display: none">
+ <iframe id='iframe' srcdoc="
+ <div></div><div></div>
+ <script defer src='data:application/javascript,document.write(&quot;<p></p>&quot;);parent.done();document.close();'></script>">
+ </iframe>
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug1646140-1.html b/parser/htmlparser/tests/mochitest/test_bug1646140-1.html
new file mode 100644
index 0000000000..8592d0d17f
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug1646140-1.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<div id="div">
+<script>
+/* globals div svgRanScript */
+SimpleTest.waitForExplicitFinish();
+
+window.svgRanScript = false;
+const o = new MutationObserver(mutations => {
+ o.disconnect();
+ setTimeout(() => {
+ ok(!svgRanScript, "svg onload must not fire");
+ SimpleTest.finish();
+ });
+});
+o.observe(div, {childList: true});
+const p = (new DOMParser()).parseFromString("<svg onload=\"window.svgRanScript=true\"></svg>", "text/html");
+div.appendChild(p.body);
+</script>
diff --git a/parser/htmlparser/tests/mochitest/test_bug1646140-2.html b/parser/htmlparser/tests/mochitest/test_bug1646140-2.html
new file mode 100644
index 0000000000..11c370d401
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug1646140-2.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<div id="div" contenteditable></div>
+<script>
+/* globals div svgRanScript */
+window.svgRanScript = false;
+document.addEventListener("copy", ev => {
+ ev.preventDefault();
+ ev.clipboardData.setData('text/html', "<svg><style><svg/onload=\"window.svgRanScript=true\">");
+});
+const o = new MutationObserver(mutations => {
+ o.disconnect();
+ setTimeout(() => {
+ ok(!svgRanScript, "svg onload must not fire");
+ SimpleTest.finish()
+ });
+});
+o.observe(div, {childList: true});
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(() => {
+ getSelection().collapse(div);
+ SpecialPowers.doCommand(window, "cmd_copy");
+ SpecialPowers.doCommand(window, "cmd_paste");
+});
+</script>
diff --git a/parser/htmlparser/tests/mochitest/test_bug174351.html b/parser/htmlparser/tests/mochitest/test_bug174351.html
new file mode 100644
index 0000000000..a370d9fefc
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug174351.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=174351
+-->
+<head>
+ <title>Test for Bug 174351</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=174351">Mozilla Bug 174351</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+ var iframe = document.createElement("iframe");
+ iframe.src = "invalidchar.xml";
+ iframe.onload = function() {
+ var doc = document.getElementById("test").childNodes[1].contentDocument;
+ ok(doc.documentElement.tagName != "root", "Since XML has invalid enconding, must throw error");
+ };
+
+ document.getElementById("test").appendChild(iframe);
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_bug213517.html b/parser/htmlparser/tests/mochitest/test_bug213517.html
new file mode 100644
index 0000000000..b5bb5afa74
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug213517.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=213517
+-->
+<head>
+ <meta charset="x-user-defined">
+ <title>Test for Bug 213517</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 213517 **/
+
+ is(document.characterSet, "windows-1252", "x-user-defined in <meta> should have gotten mapped to windows-1252");
+
+
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=213517">Mozilla Bug 213517</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug339350.xhtml b/parser/htmlparser/tests/mochitest/test_bug339350.xhtml
new file mode 100644
index 0000000000..6c16e56cb7
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug339350.xhtml
@@ -0,0 +1,61 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+Tests by Sam Ruby - WTFPL License (http://sam.zoy.org/wtfpl/)
+
+http://www.intertwingly.net/blog/2006/10/03/Firefox-XHTML-innerHTML-quirk#comments
+https://bugzilla.mozilla.org/show_bug.cgi?id=339350
+-->
+<head>
+ <!-- XHTML needs the packed version -->
+ <script src="/tests/SimpleTest/SimpleTest.js"/>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=339350">Mozilla Bug 339350</a>
+<div style="display: none">
+ <table border="1" cellspacing="0">
+ <thead>
+ <th></th>
+ <th>plain</th>
+ <th>brackets</th>
+ <th>braces</th>
+ </thead>
+
+ <tr>
+ <th>innerHTML</th>
+ <td><div id="i1"/></td>
+ <td style="background:yellow"><div id="i2"/></td>
+ <td><div id="i3"/></td>
+ </tr>
+ <tr>
+ <th>textNode</th>
+ <td><div id="t1"/></td>
+ <td><div id="t2"/></td>
+ <td><div id="t3"/></td>
+ </tr>
+ </table>
+</div>
+<pre id="test">
+<script type="text/javascript">
+/* eslint-disable no-unsanitized/property */
+var text1 = "foo bar";
+var text2 = "foo [bar]";
+var text3 = "foo {bar}";
+
+// This is the long way to write this stuff,
+// you can use MochiKit functions too
+document.getElementById("i1").innerHTML = text1;
+document.getElementById("i2").innerHTML = text2;
+document.getElementById("i3").innerHTML = text3;
+
+document.getElementById("t1").appendChild(document.createTextNode(text1));
+document.getElementById("t2").appendChild(document.createTextNode(text2));
+document.getElementById("t3").appendChild(document.createTextNode(text3));
+
+<!-- The is() function is one way to add a test -->
+is(document.getElementById("i2").innerHTML, text2, "XHTML innerHTML with trailing brackets ']]'");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug358797.html b/parser/htmlparser/tests/mochitest/test_bug358797.html
new file mode 100644
index 0000000000..f142c42c88
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug358797.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=358797
+-->
+<head>
+ <title>Test for Bug 358797</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=358797">Mozilla Bug 358797</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 358797 **/
+
+var range = document.createRange();
+range.selectNode(document.firstChild);
+var cf = range.createContextualFragment("<span></span>");
+ok(cf != null,
+ "range.createContextualFragment() should work when range node is DocType");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug396568.html b/parser/htmlparser/tests/mochitest/test_bug396568.html
new file mode 100644
index 0000000000..d4152e7971
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug396568.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=396568
+-->
+<head>
+ <title>Test for Bug 396568</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <!--These script tags are part of the test, complete with indentation!-->
+ <script language="javascript"
+
+
+
+
+
+
+
+ type="text/javascript"></script>
+ <script language="javascript"
+ type="text/javascript"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=396568">Mozilla Bug 396568</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 396568 **/
+
+ var reached = false;
+ try {
+ // eslint-disable-next-line no-undef
+ noSuchIdentifier;
+ reached = true;
+ } catch (e) {
+ is(e.lineNumber, 37, "Unexpected line number"); // this line number is dependent on the line number of noSuchIdentifier
+ }
+ is(reached, false, "Exception needed to be thrown");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_bug418464.html b/parser/htmlparser/tests/mochitest/test_bug418464.html
new file mode 100644
index 0000000000..c9c6f585e3
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug418464.html
@@ -0,0 +1,43 @@
+<form name="formGo" method="post">
+ <input type="hidden">
+</form>
+<script>
+ var form1 = document.formGo;
+</script>
+<form name="formGo2" method="post">
+ <input type="Hidden">
+</form>
+<script>
+ var form2 = document.formGo2;
+</script>
+ <!-- NOTE: The forms and scripts above this comment _must_ come first in this file-->
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=418464
+-->
+<head>
+ <title>Test for Bug 418464</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418464">Mozilla Bug 418464</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 418464 **/
+ is(form1 instanceof HTMLFormElement, true,
+ "Should have a form here");
+ is(form2 instanceof HTMLFormElement, true,
+ "Should have a form here");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_bug460437.xhtml b/parser/htmlparser/tests/mochitest/test_bug460437.xhtml
new file mode 100644
index 0000000000..c6fd25d0b3
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug460437.xhtml
@@ -0,0 +1,40 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=460437
+-->
+<head>
+ <title>Test for Bug 460437</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=460437">Mozilla Bug 460437</a>
+<p id="display"><b id="test460437">orig</b></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+/* eslint-disable no-unsanitized/property */
+<![CDATA[
+
+SimpleTest.expectAssertions(1);
+
+/** Test for Bug 460437 **/
+
+var s = "<i>invalid</i";
+try {
+ document.getElementById("test460437").innerHTML = s;
+} catch (e) {
+}
+is(document.getElementById("test460437").innerHTML, "", "setting invalid innerHTML should clear it");
+s = "<i>valid</i>";
+document.getElementById("test460437").innerHTML = s;
+is(document.getElementById("test460437").innerHTML, "<i xmlns=\"http://www.w3.org/1999/xhtml\">valid</i>", "failed to set valid innerHTML");
+
+
+]]>
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug502091.html b/parser/htmlparser/tests/mochitest/test_bug502091.html
new file mode 100644
index 0000000000..e6c318e7c6
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug502091.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=502091
+
+Adding a <meta> element by writing to innerHTML should work correctly.
+-->
+<head>
+ <title>Test for Bug 502091</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=502091">Mozilla Bug 502091</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="test">
+<script class="testbody" type="text/javascript">
+ function $(id) { return document.getElementById(id); }
+
+ var iframe = document.createElement("iframe");
+ iframe.setAttribute("id", "iframe");
+ iframe.src = "bug_502091_iframe.html";
+ iframe.onload = function() {
+ var div = $("iframe").contentDocument.getElementById("testdiv");
+ var meta = div.getElementsByTagName("meta");
+ is(meta.length, 1, "meta element not added to div");
+ };
+ $("test").appendChild(iframe);
+
+</script>
+</div>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_bug534293.html b/parser/htmlparser/tests/mochitest/test_bug534293.html
new file mode 100644
index 0000000000..62a9605dcd
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug534293.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=534293
+-->
+<head>
+ <title>Test for Bug 534293</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs"></script>
+ <base href="dir_bug534293/">
+ <script src="file_bug534293.sjs"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=534293">Mozilla Bug 534293</a>
+
+<script src="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug534293.sjs?report=1"></script>
+<script src="http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/dir_bug534293/file_bug534293.sjs?report=1"></script>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_bug543062.html b/parser/htmlparser/tests/mochitest/test_bug543062.html
new file mode 100644
index 0000000000..8a966df383
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug543062.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=543062
+-->
+<head>
+ <title>Test for Bug 543062</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=543062">Mozilla Bug 543062</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+document.write("\u003Cscript src='file_bug543062.sjs?first'>\u003C/script>\u003Cscript src='file_bug543062.sjs?second'>\u003C/script>");
+document.write("\u003Cscript src='file_bug543062.sjs?third'>\u003C/script>");
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_bug552938-2.html b/parser/htmlparser/tests/mochitest/test_bug552938-2.html
new file mode 100644
index 0000000000..87996765d0
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug552938-2.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=552938
+-->
+<head>
+ <title>Test for Bug 552938</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload='runTest();'>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=552938">Mozilla Bug 552938</a>
+<script>
+var svgLoadFired = false;
+</script>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <svg>
+ <script>
+ document.getElementsByTagName("svg")[0].addEventListener("SVGLoad",
+ function() { svgLoadFired = true; });
+ </script>
+ </svg>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 552938 **/
+function runTest() {
+ ok(svgLoadFired, "The SVG load event should have fired.");
+ SimpleTest.finish();
+}
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug552938.html b/parser/htmlparser/tests/mochitest/test_bug552938.html
new file mode 100644
index 0000000000..77d96691a6
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug552938.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=552938
+-->
+<head>
+ <title>Test for Bug 552938</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload='runTest();'>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=552938">Mozilla Bug 552938</a>
+<script>
+var svgLoadFired = false;
+</script>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <svg onload="svgLoadFired = true;"></svg>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 552938 **/
+function runTest() {
+ ok(svgLoadFired, "The SVG load event should have fired.");
+ SimpleTest.finish();
+}
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug563322.xhtml b/parser/htmlparser/tests/mochitest/test_bug563322.xhtml
new file mode 100644
index 0000000000..35239cb69a
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug563322.xhtml
@@ -0,0 +1,33 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=563322
+-->
+<head>
+ <title>Test for Bug 563322</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=563322">Mozilla Bug 563322</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 563322 **/
+
+var div = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
+div.innerHTML = "<script>ok(false, 'Script ran but should not have')</script><script>ok(false, 'Script ran but should not have')</script>";
+
+document.getElementById("content").appendChild(div);
+
+ok(true, "Keep the harness happy");
+
+]]>
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug566879.html b/parser/htmlparser/tests/mochitest/test_bug566879.html
new file mode 100644
index 0000000000..1704100bfd
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug566879.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=566879
+-->
+<head>
+ <title>Test for Bug 566879</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload='runTest();'>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=566879">Mozilla Bug 566879</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<form>
+<input type=text id=textfield name=textfield>
+<input type=checkbox id=checkbox name=checkbox>
+<input type=radio id=radio1 name=radio>
+<input type=radio id=radio2 name=radio>
+<textarea name=textarea id=textarea></textarea>
+<select name=select id=select>
+<option value=foo>Foo</option>
+<option value=bar selected>Bar</option>
+</select>
+</form>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var initialState;
+
+function runTest() {
+ initialState = document.getElementById("content").innerHTML;
+ document.getElementById("textfield").value = "foo";
+ document.getElementById("checkbox").checked = true;
+ document.getElementById("radio2").checked = true;
+ document.getElementById("textarea").value = "foo";
+ document.getElementById("select").value = "foo";
+ setTimeout(continuation1, 1);
+}
+
+function continuation1() {
+ // eslint-disable-next-line no-unsanitized/property
+ document.getElementById("content").innerHTML = initialState;
+ setTimeout(continuation2, 1);
+}
+
+function continuation2() {
+ is(document.getElementById("textfield").value, "", "The text field should have gone back to its initial state.");
+ ok(!document.getElementById("checkbox").checked, "The checkbox should have gone back to its initial state.");
+ ok(!document.getElementById("radio2").checked, "The second radio button should have gone back to its initial state.");
+ is(document.getElementById("textarea").value, "", "The text area should have gone back to its initial state.");
+ is(document.getElementById("select").value, "bar", "The select should have gone back to its initial state.");
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_bug568470.html b/parser/htmlparser/tests/mochitest/test_bug568470.html
new file mode 100644
index 0000000000..fc8f26f5d4
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug568470.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=568470
+-->
+<head>
+ <title>Test for Bug 568470</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=568470">Mozilla Bug 568470</a>
+<p id="display"></p>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 568470 **/
+SimpleTest.waitForExplicitFinish();
+
+// assuming the test runs in less than a year...
+var time = new Date().getTime() + 1000 * 60 * 60 * 24 * 365;
+
+var interval = setInterval(function() {
+ var iframe = document.getElementsByTagName("iframe")[0];
+ if (iframe) {
+ var doc = iframe.contentDocument;
+ if (doc) {
+ if (doc.getElementById("flushable")) {
+ time = new Date();
+ clearInterval(interval);
+ }
+ }
+ }
+}, 25);
+
+function finish() {
+ clearInterval(interval);
+ var elapsed = new Date().getTime() - time;
+ ok(elapsed > 350,
+ "Content flush time and parse end time not enough apart.");
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+<div id="content" style="display: none">
+ <iframe onload="finish();" src="file_bug568470.sjs"></iframe>
+</div>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_bug594730.html b/parser/htmlparser/tests/mochitest/test_bug594730.html
new file mode 100644
index 0000000000..5042c8ae32
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug594730.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=594730
+-->
+<head>
+ <title>Test for Bug 594730</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=594730">Mozilla Bug 594730</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe src=file_bug594730-1.html></iframe>
+<iframe src=file_bug594730-2.html></iframe>
+<iframe src=file_bug594730-3.html></iframe>
+<iframe src=file_bug594730-4.html></iframe>
+<iframe src=file_bug594730-5.html></iframe>
+<iframe src=file_bug594730-6.html></iframe>
+<iframe src=file_bug594730-7.html></iframe>
+<iframe src=file_bug594730-8.html></iframe>
+<iframe src=file_bug594730-9.html></iframe>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_bug613662.html b/parser/htmlparser/tests/mochitest/test_bug613662.html
new file mode 100644
index 0000000000..a35f52e453
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug613662.html
@@ -0,0 +1,132 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=613662
+-->
+<head>
+ <title>Test for Bug 613662</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613662">Mozilla Bug 613662</a>
+<p id="display"></p><div id="content" style="display: none"></div><div id="content2" style="display: none"></div><pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 613662 **/
+
+function testPositions(node) {
+ node.insertAdjacentHTML("beforeBegin", "\u003Cscript>ok(false, 'script should not have run');\u003C/script><i></i>");
+ is(node.previousSibling.localName, "i", "Should have had <i> as previous sibling");
+ node.insertAdjacentHTML("Afterbegin", "<b></b>\u003Cscript>ok(false, 'script should not have run');\u003C/script>");
+ is(node.firstChild.localName, "b", "Should have had <b> as first child");
+ node.insertAdjacentHTML("BeforeEnd", "\u003Cscript>ok(false, 'script should not have run');\u003C/script><u></u>");
+ is(node.lastChild.localName, "u", "Should have had <u> as last child");
+ node.insertAdjacentHTML("afterend", "<a></a>\u003Cscript>ok(false, 'script should not have run');\u003C/script>");
+ is(node.nextSibling.localName, "a", "Should have had <a> as next sibling");
+}
+
+var content = document.getElementById("content");
+testPositions(content); // without next sibling
+testPositions(content); // test again when there's next sibling
+
+try {
+ content.insertAdjacentHTML("bar", "foo");
+ ok(false, "insertAdjacentHTML should have thrown");
+} catch (e) {
+ is(e.name, "SyntaxError", "insertAdjacentHTML should throw SyntaxError");
+ is(e.code, 12, "insertAdjacentHTML should throw SYNTAX_ERR");
+}
+
+var parent = document.createElement("div");
+var child = document.createElement("div");
+
+try {
+ child.insertAdjacentHTML("Beforebegin", "foo");
+ ok(false, "insertAdjacentHTML should have thrown");
+} catch (e) {
+ is(e.name, "NoModificationAllowedError", "insertAdjacentHTML should throw NoModificationAllowedError");
+ is(e.code, 7, "insertAdjacentHTML should throw NO_MODIFICATION_ALLOWED_ERR");
+}
+
+try {
+ child.insertAdjacentHTML("AfterEnd", "foo");
+ ok(false, "insertAdjacentHTML should have thrown");
+} catch (e) {
+ is(e.name, "NoModificationAllowedError", "insertAdjacentHTML should throw NoModificationAllowedError");
+ is(e.code, 7, "insertAdjacentHTML should throw NO_MODIFICATION_ALLOWED_ERR");
+}
+
+child.insertAdjacentHTML("afterBegin", "foo"); // mustn't throw
+child.insertAdjacentHTML("beforeend", "foo"); // mustn't throw
+
+parent.appendChild(child);
+testPositions(child); // node not in tree but has parent
+
+content.appendChild(parent); // must not run scripts
+
+try {
+ document.documentElement.insertAdjacentHTML("afterend", "<div></div>");
+ ok(false, "insertAdjacentHTML should have thrown");
+} catch (e) {
+ is(e.name, "NoModificationAllowedError", "insertAdjacentHTML should throw NoModificationAllowedError");
+ is(e.code, 7, "insertAdjacentHTML should throw NO_MODIFICATION_ALLOWED_ERR");
+}
+
+var content2 = document.getElementById("content2");
+
+var events = [
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMSubtreeModified", null ],
+];
+
+function mutationEventListener(evt) {
+ var expected = events.shift();
+ is(evt.type, expected[0], "Unexpected mutation type");
+ is(evt.relatedNode, expected[1], "Unexpected related node");
+}
+/*
+document.addEventListener("DOMSubtreeModified", mutationEventListener, false);
+document.addEventListener("DOMNodeInserted", mutationEventListener, false);
+document.addEventListener("DOMNodeRemoved", mutationEventListener, false);
+document.addEventListener("DOMNodeRemovedFromDocument", mutationEventListener, false);
+document.addEventListener("DOMNodeInsertedIntoDocument", mutationEventListener, false);
+document.addEventListener("DOMAttrModified", mutationEventListener, false);
+document.addEventListener("DOMCharacterDataModified", mutationEventListener, false);
+
+testPositions(content2); // without next sibling
+testPositions(content2); // test again when there's next sibling
+
+is(events.length, 0, "Not all expected events fired.");
+*/
+// HTML only
+document.body.insertAdjacentHTML("afterend", "<p>");
+document.head.insertAdjacentHTML("beforebegin", "<p>");
+is(document.getElementsByTagName("head").length, 1, "Should still have one head");
+is(document.getElementsByTagName("body").length, 1, "Should still have one body");
+
+</script>
+</pre>
+</body></html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug613662.xhtml b/parser/htmlparser/tests/mochitest/test_bug613662.xhtml
new file mode 100644
index 0000000000..b6a5c63670
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug613662.xhtml
@@ -0,0 +1,137 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=613662
+-->
+<head>
+ <title>Test for Bug 613662</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613662">Mozilla Bug 613662</a>
+<p id="display"></p><div id="content" style="display: none"></div><div id="content2" style="display: none"></div><pre id="test">
+<script type="application/javascript"><![CDATA[
+
+SimpleTest.expectAssertions(1);
+
+/** Test for Bug 613662 **/
+
+function testPositions(node) {
+ node.insertAdjacentHTML("beforeBegin", "\u003Cscript>ok(false, 'script should not have run');\u003C/script><i></i>");
+ is(node.previousSibling.localName, "i", "Should have had <i> as previous sibling");
+ node.insertAdjacentHTML("Afterbegin", "<b></b>\u003Cscript>ok(false, 'script should not have run');\u003C/script>");
+ is(node.firstChild.localName, "b", "Should have had <b> as first child");
+ node.insertAdjacentHTML("BeforeEnd", "\u003Cscript>ok(false, 'script should not have run');\u003C/script><u></u>");
+ is(node.lastChild.localName, "u", "Should have had <u> as last child");
+ node.insertAdjacentHTML("afterend", "<a></a>\u003Cscript>ok(false, 'script should not have run');\u003C/script>");
+ is(node.nextSibling.localName, "a", "Should have had <a> as next sibling");
+}
+
+var content = document.getElementById("content");
+testPositions(content); // without next sibling
+testPositions(content); // test again when there's next sibling
+
+try {
+ content.insertAdjacentHTML("bar", "foo");
+ ok(false, "insertAdjacentHTML should have thrown");
+} catch (e) {
+ is(e.name, "SyntaxError", "insertAdjacentHTML should throw SyntaxError");
+ is(e.code, 12, "insertAdjacentHTML should throw SYNTAX_ERR");
+}
+
+var parent = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
+var child = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
+
+try {
+ child.insertAdjacentHTML("Beforebegin", "foo");
+ ok(false, "insertAdjacentHTML should have thrown");
+} catch (e) {
+ is(e.name, "NoModificationAllowedError", "insertAdjacentHTML should throw NoModificationAllowedError");
+ is(e.code, 7, "insertAdjacentHTML should throw NO_MODIFICATION_ALLOWED_ERR");
+}
+
+try {
+ child.insertAdjacentHTML("AfterEnd", "foo");
+ ok(false, "insertAdjacentHTML should have thrown");
+} catch (e) {
+ is(e.name, "NoModificationAllowedError", "insertAdjacentHTML should throw NoModificationAllowedError");
+ is(e.code, 7, "insertAdjacentHTML should throw NO_MODIFICATION_ALLOWED_ERR");
+}
+
+child.insertAdjacentHTML("afterBegin", "foo"); // mustn't throw
+child.insertAdjacentHTML("beforeend", "foo"); // mustn't throw
+
+parent.appendChild(child);
+testPositions(child); // node not in tree but has parent
+
+content.appendChild(parent); // must not run scripts
+
+try {
+ document.documentElement.insertAdjacentHTML("afterend", "<div></div>");
+ ok(false, "insertAdjacentHTML should have thrown");
+} catch (e) {
+ is(e.name, "NoModificationAllowedError", "insertAdjacentHTML should throw NoModificationAllowedError");
+ is(e.code, 7, "insertAdjacentHTML should throw NO_MODIFICATION_ALLOWED_ERR");
+}
+
+var content2 = document.getElementById("content2");
+
+var events = [
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMNodeInserted", content2 ],
+ [ "DOMSubtreeModified", null ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMNodeInserted", document.body ],
+ [ "DOMSubtreeModified", null ],
+];
+
+function mutationEventListener(evt) {
+ var expected = events.shift();
+ is(evt.type, expected[0], "Unexpected mutation type");
+ is(evt.relatedNode, expected[1], "Unexpected related node");
+}
+
+document.addEventListener("DOMSubtreeModified", mutationEventListener);
+document.addEventListener("DOMNodeInserted", mutationEventListener);
+document.addEventListener("DOMNodeRemoved", mutationEventListener);
+document.addEventListener("DOMNodeRemovedFromDocument", mutationEventListener);
+document.addEventListener("DOMNodeInsertedIntoDocument", mutationEventListener);
+document.addEventListener("DOMAttrModified", mutationEventListener);
+document.addEventListener("DOMCharacterDataModified", mutationEventListener);
+
+testPositions(content2); // without next sibling
+testPositions(content2); // test again when there's next sibling
+
+is(events.length, 0, "Not all expected events fired.");
+
+// XML-only:
+try {
+ content.insertAdjacentHTML("beforeend", "<p>");
+ ok(false, "insertAdjacentHTML should have thrown");
+} catch (e) {
+ is(e.name, "SyntaxError", "insertAdjacentHTML should throw SyntaxError");
+ is(e.code, 12, "insertAdjacentHTML should throw SYNTAX_ERR");
+}
+
+]]></script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug639362.html b/parser/htmlparser/tests/mochitest/test_bug639362.html
new file mode 100644
index 0000000000..665f3c7910
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug639362.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=639362
+-->
+<head>
+ <title>Test for Bug 639362</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=639362">Mozilla Bug 639362</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+function loaded(iframe) {
+ is(SpecialPowers.wrap(iframe).contentWindow.location.href, iframe.src, "should load correct URL");
+ is(SpecialPowers.wrap(iframe).contentDocument.body.textContent, "CACHE MANIFEST", "text/cache-manifest should be treated as text");
+ SimpleTest.finish();
+}
+</script>
+<iframe src="data:text/cache-manifest,CACHE MANIFEST" onload="loaded(this);"></iframe>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug642908.html b/parser/htmlparser/tests/mochitest/test_bug642908.html
new file mode 100644
index 0000000000..10fd735363
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug642908.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=642908
+-->
+<head>
+ <title>Test for Bug 642908</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="loaded();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=642908">Mozilla Bug 642908</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+document.write("\u003Cscript src='data:text/javascript,1;'>\u003C/script>");
+document.write("<noscript><img src='file_bug642908.sjs'></noscript>");
+
+function loaded() {
+ var s = document.createElement("script");
+ s.src = "file_bug642908.sjs?report=1";
+ document.body.appendChild(s);
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug645115.html b/parser/htmlparser/tests/mochitest/test_bug645115.html
new file mode 100644
index 0000000000..74f4e8be4f
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug645115.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=645115
+-->
+<head>
+ <title>Test for Bug 645115</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=645115">Mozilla Bug 645115</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 645115 **/
+var div = document.createElement("div");
+div.innerHTML = "\u003Cscript>ok(false, 'innerHTML script ran');\u003C/script>\u003Cscript>";
+document.getElementById("content").appendChild(div);
+
+ok(true, "Keep the test harness happy.");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_bug655682.html b/parser/htmlparser/tests/mochitest/test_bug655682.html
new file mode 100644
index 0000000000..7011d3044c
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug655682.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=655682
+-->
+<head>
+ <title>Test for Bug 655682</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=655682">Mozilla Bug 655682</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe src=file_bug655682.sjs></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 655682 **/
+
+var gotOnload = false;
+var finishedTesting = false;
+
+function tryFinishTest() {
+ if (gotOnload && finishedTesting) {
+ SimpleTest.finish();
+ }
+}
+
+addLoadEvent(function() {
+ // Hit the event loop again just to make sure that we're not ending the test
+ // before all activity we care about is done.
+ SimpleTest.executeSoon(function() {
+ gotOnload = true;
+ tryFinishTest();
+ });
+});
+
+var tdsSeen = 0;
+
+var triggeredSecondTd = false;
+
+var iframe = document.getElementsByTagName("iframe")[0];
+
+SimpleTest.waitForExplicitFinish();
+
+function probe() {
+ var tds = iframe.contentDocument.getElementsByTagName("td").length;
+ switch (tds) {
+ case 0:
+ setTimeout(probe, 0);
+ return;
+ case 1:
+ tdsSeen = tds;
+ if (!triggeredSecondTd) {
+ triggeredSecondTd = true;
+ var script = document.createElement("script");
+ script.src = "file_bug655682.sjs?trigger=1";
+ document.head.appendChild(script);
+ }
+ setTimeout(probe, 0);
+ return;
+ case 2:
+ is(tdsSeen, 1, "Should have seen one td before seeing two.");
+ finishedTesting = true;
+ tryFinishTest();
+ return;
+ default:
+ ok(false, "Wrong number of tds");
+ SimpleTest.finish();
+ }
+}
+
+setTimeout(probe, 0);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug667533.html b/parser/htmlparser/tests/mochitest/test_bug667533.html
new file mode 100644
index 0000000000..c531d4cec3
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug667533.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=667533
+-->
+<head>
+ <title>Test for Bug 667533</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=667533">Mozilla Bug 667533</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+function loaded(iframe) {
+ is(SpecialPowers.wrap(iframe).contentWindow.location.href, iframe.src, "should load correct URL");
+ is(SpecialPowers.wrap(iframe).contentDocument.body.textContent, '{"<p>Hello</p>": null}', "application/json should be treated as text");
+ SimpleTest.finish();
+}
+</script>
+<iframe src="data:application/json,{&quot;<p>Hello</p>&quot;:%20null}" onload="loaded(this);"></iframe>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug672453.html b/parser/htmlparser/tests/mochitest/test_bug672453.html
new file mode 100644
index 0000000000..bd8fabd947
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug672453.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=672453
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 672453</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=672453"
+ >Mozilla Bug 672453</a>
+<iframe></iframe>
+<script>
+/** Test for Bug 672453 **/
+
+var tests = [
+ "file_bug672453_not_declared.html",
+ "file_bug672453_late_meta.html",
+ "file_bug672453_meta_restart.html",
+ "file_bug672453_meta_unsupported.html",
+ "file_bug672453_http_unsupported.html",
+ "file_bug672453_bomless_utf16.html",
+ "file_bug672453_meta_utf16.html",
+ "file_bug672453_meta_non_superset.html",
+ "file_bug672453_meta_userdefined.html",
+];
+
+var expectedErrors = [
+ { errorMessage: "The character encoding of a framed document was not declared. The document may appear different if viewed without the document framing it.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_not_declared.html",
+ lineNumber: 0,
+ isWarning: true },
+ { errorMessage: "The character encoding declaration of the framed HTML document was not found when prescanning the first 1024 bytes of the file. When viewed without the document framing it, the page will reload automatically. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_late_meta.html",
+ lineNumber: 1028,
+ isWarning: true },
+ { errorMessage: "The page was reloaded, because the character encoding declaration of the HTML document was not found when prescanning the first 1024 bytes of the file. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_restart.html",
+ lineNumber: 1028,
+ isWarning: true },
+ { errorMessage: "An unsupported character encoding was declared for the HTML document using a meta tag. The declaration was ignored.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_unsupported.html",
+ lineNumber: 1,
+ isWarning: false },
+ { errorMessage: "An unsupported character encoding was declared on the transfer protocol level. The declaration was ignored.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html",
+ lineNumber: 0,
+ isWarning: false },
+ { errorMessage: "Detected UTF-16-encoded Basic Latin-only text without a byte order mark and without a transfer protocol-level declaration. Encoding this content in UTF-16 is inefficient and the character encoding should have been declared in any case.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_bomless_utf16.html",
+ lineNumber: 0,
+ isWarning: false },
+ { errorMessage: "A meta tag was used to declare the character encoding as UTF-16. This was interpreted as an UTF-8 declaration instead.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_utf16.html",
+ lineNumber: 1,
+ isWarning: false },
+ { errorMessage: "An unsupported character encoding was declared for the HTML document using a meta tag. The declaration was ignored.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_non_superset.html",
+ lineNumber: 1,
+ isWarning: false },
+ { errorMessage: "A meta tag was used to declare the character encoding as x-user-defined. This was interpreted as a windows-1252 declaration instead for compatibility with intentionally mis-encoded legacy fonts. This site should migrate to Unicode.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_userdefined.html",
+ lineNumber: 1,
+ isWarning: false },
+];
+
+SimpleTest.waitForExplicitFinish();
+
+window.onload = function() {
+ var iframe = document.getElementsByTagName("iframe")[0];
+
+ function runNextTest() {
+ var url = tests.shift();
+ if (!url) {
+ SimpleTest.endMonitorConsole();
+ return;
+ }
+ iframe.src = url;
+ }
+ iframe.onload = runNextTest;
+
+ SimpleTest.monitorConsole(SimpleTest.finish, expectedErrors);
+ runNextTest();
+};
+</script>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug688580.html b/parser/htmlparser/tests/mochitest/test_bug688580.html
new file mode 100644
index 0000000000..1d18cc5f78
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug688580.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=688580
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 688580</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 688580 **/
+
+ // Expected order:
+ // Test starting
+ // readyState interactive
+ // defer
+ // DOMContentLoaded
+ // readyState complete
+ // load
+
+ var state = "Test starting";
+ var readyStateCall = 0;
+ SimpleTest.waitForExplicitFinish();
+ is(document.readyState, "loading", "Document should have been loading.");
+ document.addEventListener("DOMContentLoaded", function() {
+ is(document.readyState, "interactive", "readyState should be interactive during DOMContentLoaded.");
+ is(state, "defer", "Bad state upon DOMContentLoaded");
+ state = "DOMContentLoaded";
+ });
+ document.addEventListener("readystatechange", function() {
+ readyStateCall++;
+ if (readyStateCall == 1) {
+ is(document.readyState, "interactive", "readyState should have changed to interactive.");
+ is(state, "Test starting", "Bad state upon first readystatechange.");
+ state = "readyState interactive";
+ } else if (readyStateCall == 2) {
+ is(document.readyState, "complete", "readyState should have changed to complete.");
+ is(state, "DOMContentLoaded", "Bad state upon second readystatechange.");
+ state = "readyState complete";
+ } else {
+ ok(false, "Too many readystatechanges");
+ }
+ });
+ window.addEventListener("load", function() {
+ is(document.readyState, "complete", "readyState should be complete during load.");
+ is(state, "readyState complete", "Bad state upon load");
+ state = "load";
+ SimpleTest.finish();
+ });
+ </script>
+ <script defer src="file_bug688580.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=688580">Mozilla Bug 688580</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug688580.xhtml b/parser/htmlparser/tests/mochitest/test_bug688580.xhtml
new file mode 100644
index 0000000000..a4046dfa76
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug688580.xhtml
@@ -0,0 +1,62 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=688580
+-->
+<head>
+ <title>Test for Bug 688580</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 688580 **/
+
+ // Expected order:
+ // Test starting
+ // readyState interactive
+ // defer
+ // DOMContentLoaded
+ // readyState complete
+ // load
+
+ var state = "Test starting";
+ var readyStateCall = 0;
+ SimpleTest.waitForExplicitFinish();
+ is(document.readyState, "loading", "Document should have been loading.");
+ document.addEventListener("DOMContentLoaded", function() {
+ is(document.readyState, "interactive", "readyState should be interactive during DOMContentLoaded.");
+ is(state, "defer", "Bad state upon DOMContentLoaded");
+ state = "DOMContentLoaded";
+ });
+ document.addEventListener("readystatechange", function() {
+ readyStateCall++;
+ if (readyStateCall == 1) {
+ is(document.readyState, "interactive", "readyState should have changed to interactive.");
+ is(state, "Test starting", "Bad state upon first readystatechange.");
+ state = "readyState interactive";
+ } else if (readyStateCall == 2) {
+ is(document.readyState, "complete", "readyState should have changed to complete.");
+ is(state, "DOMContentLoaded", "Bad state upon second readystatechange.");
+ state = "readyState complete";
+ } else {
+ ok(false, "Too many readystatechanges");
+ }
+ });
+ window.addEventListener("load", function() {
+ is(document.readyState, "complete", "readyState should be complete during load.");
+ is(state, "readyState complete", "Bad state upon load");
+ state = "load";
+ SimpleTest.finish();
+ });
+ </script>
+ <script defer="" src="file_bug688580.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=688580">Mozilla Bug 688580</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug709083.html b/parser/htmlparser/tests/mochitest/test_bug709083.html
new file mode 100644
index 0000000000..74f39c38d5
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug709083.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=709083
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 709083</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=709083">Mozilla Bug 709083</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<video muted>
+<script type="application/javascript">
+
+/** Test for Bug 709083 **/
+
+ok(document.getElementsByTagName("video")[0].muted, "Should be muted already.");
+
+</script>
+</video>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug715112.html b/parser/htmlparser/tests/mochitest/test_bug715112.html
new file mode 100644
index 0000000000..1b81f2da2a
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug715112.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=715112
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 715112</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=715112">Mozilla Bug 715112</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 715112 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var expected = [
+ "First",
+ "Second",
+];
+
+function log(str) {
+ is(str, expected.shift(), "Unexpected log string.");
+}
+
+var w = window.open();
+w.document.open();
+w.document.addEventListener("DOMContentLoaded", function() {
+ is(expected.length, 0, "Not all expected messages were logged.");
+ is(w.document.getElementsByTagName("script").length, 3, "The document should have 3 scripts.");
+ w.close();
+ SimpleTest.finish();
+});
+w.document.write("\u003cscript>opener.log('First');\u003c/script>");
+w.document.write("\u003cscript>document.close();\u003c/script>");
+w.document.write("\u003cscript>opener.log('Second');\u003c/script>");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug715739.html b/parser/htmlparser/tests/mochitest/test_bug715739.html
new file mode 100644
index 0000000000..914459c2ce
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug715739.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=715739
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 715739</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="tick()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=715739">Mozilla Bug 715739</a>
+<p id="display"></p>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 715739 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var runNumber = 0;
+
+function textChildren(node) {
+ var s = "";
+ var n = node.firstChild;
+ while (n) {
+ if (n.nodeType == Node.TEXT_NODE) {
+ s += n.nodeValue;
+ }
+ n = n.nextSibling;
+ }
+ return s;
+}
+
+var f, d;
+
+function tick() {
+ runNumber++;
+ f = document.getElementsByTagName("iframe")[0];
+ d = f.contentDocument;
+ var text;
+
+ if (runNumber == 1) {
+ frames[1].setTimeout(`
+ var d = parent.d;
+ var f = parent.f;
+ d.open();
+ f.addEventListener("load", parent.tick);
+ d.write("X");
+ d.write("\u003cscript>document.write('Y');\u003c/script>");
+ d.write("Z");
+ d.close();
+ `);
+ return;
+ }
+
+ if (runNumber == 2) {
+ text = textChildren(d.body);
+ is(text, "XYZ", "Wrong text before reload.");
+ f.contentWindow.location.reload();
+ return;
+ }
+
+ if (runNumber == 3) {
+ text = textChildren(d.body);
+ is(text, "ABC", "Wrong text after reload.");
+ SimpleTest.finish();
+ }
+}
+
+// We want to trigger a document.open/write with a different window as the
+// entry global. Let's give that window a blob URL so we don't have to set up
+// extra helper files.
+var blob = new Blob(["ABC"], { type: "text/html" });
+var blobURL = URL.createObjectURL(blob);
+
+</script>
+</pre>
+<div id="content" style="display: none">
+ <iframe></iframe>
+ <iframe></iframe>
+</div>
+<script>
+ document.querySelectorAll("iframe")[1].src = blobURL;
+</script>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug716579.html b/parser/htmlparser/tests/mochitest/test_bug716579.html
new file mode 100644
index 0000000000..32ae13a611
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug716579.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=716579
+-->
+<head>
+ <meta charset="windows-1251">
+ <title>Test for Bug 716579</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=716579">Mozilla Bug 716579</a>
+<p id="display"></p>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 716579 **/
+
+var html8 = "FAIL";
+var html16 = "FAIL";
+var xml8 = "FAIL";
+var xml16 = "FAIL";
+
+SimpleTest.waitForExplicitFinish();
+
+window.onload = function() {
+ is(html8, "\u20AC", "HTML UTF-8 failed.");
+ is(html16, "\u20AC", "HTML UTF-16 failed.");
+ is(xml8, "\u20AC", "XML UTF-8 failed.");
+ is(xml16, "\u20AC", "XML UTF-16 failed.");
+ SimpleTest.finish();
+};
+
+</script>
+</pre>
+<div id="content" style="display: none">
+<iframe src="file_bug716579-8.html"></iframe>
+<iframe src="file_bug716579-16.html"></iframe>
+<iframe src="file_bug716579-8.xhtml"></iframe>
+<iframe src="file_bug716579-16.xhtml"></iframe>
+</div>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_bug717180.html b/parser/htmlparser/tests/mochitest/test_bug717180.html
new file mode 100644
index 0000000000..7351264562
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug717180.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=717180
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 717180</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717180">Mozilla Bug 717180</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <iframe></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 717180 **/
+
+SimpleTest.waitForExplicitFinish();
+
+window.addEventListener("load", function() {
+ var iframe = document.getElementsByTagName("iframe")[0];
+ var d = iframe.contentDocument;
+ d.open();
+ iframe.addEventListener("load", function() {
+ is(iframe.contentDocument.body.textContent, "SUCCESS\n", "Wrong text");
+ SimpleTest.finish();
+ });
+ d.write("\u003Cscript>");
+ d.write("window.location = 'file_bug717180.html';");
+ d.write("\u003C/script>");
+ d.write("FAIL");
+ d.close();
+ is(iframe.contentDocument.body, null, "The document should not have a body right now.");
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_compatmode.html b/parser/htmlparser/tests/mochitest/test_compatmode.html
new file mode 100644
index 0000000000..82121b2fd6
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_compatmode.html
@@ -0,0 +1,100 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <title>Mochitest for DOCTYPE parsing</title>
+
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=363883">Mozilla Bug 363883</a>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var doctypes = [
+/* from bug 363883 */
+"BackCompat", "<!DOCTYPE>",
+"BackCompat", "<!DOCTYPEz>",
+"BackCompat", "<! DOCTYPE>",
+"BackCompat", "<!zDOCTYPE>",
+"CSS1Compat", "<!DOCTYPEHTML>",
+"BackCompat", "<!DOCTYPEz HTML>",
+"CSS1Compat", "<!DOCTYPE HTML>",
+"BackCompat", "<!zDOCTYPE HTML>",
+"BackCompat", "<!DOCTYPE HTMLz>",
+"BackCompat", "<!DOCTYPE zHTML>",
+"BackCompat", "<!DOCTYPE XHTML>",
+"BackCompat", "<!DOCTYPE zzHTML>",
+"BackCompat", "<!DOCTYPEzHTML>",
+"BackCompat", "<!DOCTYPEzzHTML>",
+"BackCompat", '<!DOCTYPE "bla">',
+"BackCompat", '<!DOCTYPE HTML "bla">',
+"BackCompat", '<!DOCTYPE HTML "html">',
+"BackCompat", "<!DOCTYPE PUBLIC>",
+"BackCompat", '<!DOCTYPE PUBLIC "bla">',
+"BackCompat", '<!DOCTYPE PUBLIC "html">',
+"CSS1Compat", '<!DOCTYPE HTML PUBLIC "bla">',
+"BackCompat", '<!DOCTYPE HTML PUBLIC "html">',
+"BackCompat", '<!DOCTYPEz HTML PUBLIC "html">',
+"BackCompat", '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.2//en">',
+"BackCompat", '<!DOCTYPEz HTML PUBLIC "-//IETF//DTD HTML 3.2//en">',
+"BackCompat", '<!DOCTYPE HTMLz PUBLIC "DTD HTML 3.2">',
+"BackCompat", '<!DOCTYPE "DTD HTML 3.2">',
+/* end from bug 363883 */
+// from bug 502600
+"BackCompat", '<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">',
+];
+
+window.addEventListener("message", verifyResult);
+
+function verifyResult(event) {
+ let i = event.data.index;
+ let curFrame = document.getElementById("test" + i);
+ let mode = SpecialPowers.wrap(curFrame).contentDocument.compatMode;
+ is(mode, doctypes[i], doctypes[i + 1]);
+ if (i == doctypes.length - 2) {
+ window.removeEventListener("message", verifyResult);
+ SimpleTest.finish();
+ }
+}
+
+// //
+// Insert a hidden iframe into the document, with the src
+// containing the test doctype. The iframe's onload
+// function is set to call the test's verification step.
+//
+function insert_iframe(index, doctype) {
+ var elm = document.createElement("iframe");
+ elm.setAttribute("id", "test" + index);
+ elm.setAttribute("src", "data:text/html," + doctype +
+ '<html><body onload="parent.postMessage({index:' + index + '},\'*\');"></body>');
+ elm.setAttribute("style", "display:none");
+ document.getElementsByTagName("body")[0].appendChild(elm);
+}
+
+// //
+// Iterate over the tests
+//
+function doTest() {
+ for (var i = 0; i < doctypes.length; i += 2) {
+ insert_iframe(i, doctypes[i + 1]);
+ }
+}
+
+// //
+// Run the compatbility mode tests.
+//
+SimpleTest.waitForExplicitFinish();
+doTest();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_html5_tree_construction.html b/parser/htmlparser/tests/mochitest/test_html5_tree_construction.html
new file mode 100644
index 0000000000..fe755a7248
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_html5_tree_construction.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=366936
+-->
+<head>
+ <meta charset=utf-8>
+ <title>Test for Bug 366936</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+ <script type="application/javascript"
+ src="parser_datreader.js"></script>
+ <script type="application/javascript"
+ src="html5_tree_construction_exceptions.js"></script>
+ <script class="testbody" type="application/javascript">
+ var parserDatFiles = ["adoption01.dat",
+ "adoption02.dat",
+ "comments01.dat",
+ "doctype01.dat",
+ "domjs-unsafe.dat",
+ "entities01.dat",
+ "entities02.dat",
+ "html5test-com.dat",
+ "inbody01.dat",
+ "isindex.dat",
+ "pending-spec-changes.dat",
+ "pending-spec-changes-plain-text-unsafe.dat",
+ "plain-text-unsafe.dat",
+ "scripted/adoption01.dat",
+ "scripted/webkit01.dat",
+ "scripted/ark.dat",
+ "scriptdata01.dat",
+ "tables01.dat",
+ "template.dat",
+ "tests10.dat",
+ "tests11.dat",
+ "tests12.dat",
+ "tests14.dat",
+ "tests15.dat",
+ "tests16.dat"];
+
+ </script>
+ <script type="application/javascript"
+ src="parser_web_testrunner.js"></script>
+</head>
+<body>
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=366936"
+ target="_blank">Mozilla Bug 366936</a>
+<div id="content">
+<iframe src="" id="testframe"></iframe>
+</div>
+See https://github.com/html5lib/html5lib-tests for original test data<br>
+<div id="display">
+
+</div>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_html5_tree_construction_part2.html b/parser/htmlparser/tests/mochitest/test_html5_tree_construction_part2.html
new file mode 100644
index 0000000000..fa64788fc0
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_html5_tree_construction_part2.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=366936
+-->
+<head>
+ <meta charset=utf-8>
+ <title>Test for Bug 366936</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+ <script type="application/javascript"
+ src="parser_datreader.js"></script>
+ <script type="application/javascript"
+ src="html5_tree_construction_exceptions.js"></script>
+ <script class="testbody" type="application/javascript">
+ var parserDatFiles = ["tests17.dat",
+ "tests18.dat",
+ "tests19.dat",
+ "tests1.dat",
+ "tests20.dat",
+ "tests21.dat",
+ "tests22.dat",
+ "tests23.dat",
+ "tests24.dat",
+ "tests25.dat",
+ "tests26.dat",
+ "tests2.dat",
+ "tests3.dat",
+ "tests4.dat",
+ "tests5.dat",
+ "tests6.dat",
+ "tests7.dat",
+ "tests8.dat",
+ "tests9.dat",
+ "tests_innerHTML_1.dat",
+ "tricky01.dat",
+ "webkit01.dat",
+ "webkit02.dat",
+ "main-element.dat",
+ "foreign-fragment.dat",
+ "ruby.dat"];
+ </script>
+ <script type="application/javascript"
+ src="parser_web_testrunner.js"></script>
+</head>
+<body>
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=366936"
+ target="_blank">Mozilla Bug 366936</a>
+<div id="content">
+<iframe src="" id="testframe"></iframe>
+</div>
+See https://github.com/html5lib/html5lib-tests for original test data<br>
+<div id="display">
+
+</div>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_img_picture_preload.html b/parser/htmlparser/tests/mochitest/test_img_picture_preload.html
new file mode 100644
index 0000000000..63b916f340
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_img_picture_preload.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1067345
+-->
+<head>
+ <title>Test for Bug 1067345</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+ <script type="text/javascript">
+ // Ensure srcset/picture are enabled, re-run the test at different DPI
+ // levels to ensure preload step does the right responsive image selection
+
+ SimpleTest.waitForExplicitFinish();
+
+ var testDPIs = [ "1.0", "0.5", "2.0", "1.5" ];
+ var iframe = document.createElement("iframe");
+
+ // These accessed by child frame
+ var currentDPI;
+
+ document.body.appendChild(iframe);
+
+ SpecialPowers.pushPrefEnv({"set": [ [ "dom.image.srcset.enabled", true ],
+ [ "dom.image.picture.enabled", true ]] },
+ function() {
+ // Reset the sjs helper so repeat runs work
+ resetRequests();
+ setTimeout(nextTest, 0);
+ });
+
+ function resetRequests() {
+ // Ask the SJS to reset requests
+ var request = new XMLHttpRequest();
+ request.open("GET", "./file_img_picture_preload.sjs?reset", false);
+ request.send(null);
+ is(request.status, 200, "Sending reset to helper should succeed");
+ // Script responds with pre-reset request count
+ var previousRequests = +request.responseText;
+
+ return previousRequests;
+ }
+
+ // Called when iframe is finished
+ function childTestFinished(requestsMade) {
+ setTimeout(function() {
+ // Reset sjs, ensure no new requests appeared after test finished
+ var requestsCleared = resetRequests();
+ is(requestsCleared, requestsMade,
+ "Should not have recorded new requests after test iteration completed");
+
+ setTimeout(nextTest, 0);
+ }, 0);
+ }
+
+ function nextTest() {
+ // Re-run test for each DPI level
+ if (testDPIs.length) {
+ currentDPI = testDPIs.pop();
+ info("Starting test for DPI: " + currentDPI);
+ // To avoid spurious image loads being reported when the resolution changes,
+ // load an intermediate iframe.
+ iframe.src = "about:blank";
+ iframe.addEventListener("load", function() {
+ SpecialPowers.pushPrefEnv({"set": [ [ "layout.css.devPixelsPerPx", currentDPI ]] },
+ function() {
+ // Clear image cache for next run (we don't try to validate cached items
+ // in preload).
+ SpecialPowers.Cc["@mozilla.org/image/tools;1"]
+ .getService(SpecialPowers.Ci.imgITools)
+ .getImgCacheForDocument(iframe.contentDocument)
+ .clearCache(false);
+ iframe.src = "./file_img_picture_preload.html?" + currentDPI;
+ });
+ }, {once: true});
+ } else {
+ SimpleTest.finish();
+ }
+ }
+ </script>
+
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/test_xml_mislabeled.html b/parser/htmlparser/tests/mochitest/test_xml_mislabeled.html
new file mode 100644
index 0000000000..0865647389
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_xml_mislabeled.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html><meta charset=utf-8>
+<title>Test for mislabeled or unlabeled XML entities with U+xxD8</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
+<body>
+<script class="testbody">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+var declaredEncodings = [null, "utf-8", "uTf-8", "UTF-8", "utf-16", "uTf-16", "UTF-16"];
+var actualEncodings = ["utf-8", "utf-16be", "utf-16le"];
+var i = 0, j = 0;
+testxhr(declaredEncodings[i], actualEncodings[j]);
+
+function testxhr(declaredEncoding, actualEncoding) {
+ // utf-16 XML requres the BOM
+ var bom = actualEncoding.startsWith("utf-16") ? "\uFEFF" : "";
+ var xmlDecl = declaredEncoding ? '<?xml version="1.0" encoding="' + declaredEncoding + '" ?>\n' : "";
+ // The test string need to contain U+xxD8 (bug 860180)
+ var xmlString = bom + xmlDecl + "<test>testハヒフヘホ</test>";
+ var xml = new TextEncoder(actualEncoding).encode(xmlString);
+ var description = declaredEncoding ? " labeled with " + declaredEncoding : " without XML declaration";
+ if (!declaredEncoding || actualEncoding !== declaredEncoding.toLowerCase()) {
+ description += " but actually encoded with " + actualEncoding;
+ }
+ var xhr = new XMLHttpRequest();
+ var url = URL.createObjectURL(new Blob([xml], {type: "text/xml"}));
+ xhr.open("GET", url);
+ xhr.send();
+ xhr.onload = xhr.onerror = function(e) {
+ URL.revokeObjectURL(url);
+ is(e.type, "load", "xhr loading should succeed for XML" + description);
+ is(xhr.responseXML.documentElement.textContent, "testハヒフヘホ",
+ "response should be available for XML" + description);
+ testiframe(description, xml);
+ };
+}
+
+function testiframe(description, xml) {
+ var iframe = document.createElement("iframe");
+ var url = URL.createObjectURL(new Blob([xml], {type: "text/xml"}));
+ iframe.src = url;
+ iframe.onload = iframe.onerror = function(e) {
+ URL.revokeObjectURL(url);
+ is(e.type, "load", "iframe loading should succeed for XML" + description);
+ is(iframe.contentDocument.documentElement.textContent, "testハヒフヘホ",
+ "iframe content should be available for XML" + description);
+ if (++i >= declaredEncodings.length) {
+ i = 0;
+ if (++j >= actualEncodings.length) {
+ SimpleTest.finish();
+ return;
+ }
+ }
+ testxhr(declaredEncodings[i], actualEncodings[j]);
+ };
+ document.body.appendChild(iframe);
+}
+</script>
+<div id="display"></div>
+</body>
diff --git a/parser/htmlparser/tests/reftest/bug1636607-1-ref.html b/parser/htmlparser/tests/reftest/bug1636607-1-ref.html
new file mode 100644
index 0000000000..b5e24f87a7
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1636607-1-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<style>
+div { border: medium solid blue }
+span { background: #9090ff; }
+span.test::before {
+ white-space: pre;
+ content: "\A";
+}
+</style>
+<p>This document is in <span id="mode"></span> mode.</p>
+<p>This is a test for the line height quirk which is present in limited-quirks mode <b>and</b> quirks mode:</p>
+<div><span style="font-size: 50%">hello<br>hello</span></div>
+<p>This is a test for the hashless hex color quirk which is present in quirks mode <b>only</b>:</p>
+<div style="background-color: 9090ff">test</div>
+
+<script>
+document.getElementById("mode").innerText = document.compatMode;
+</script>
diff --git a/parser/htmlparser/tests/reftest/bug1636607-1.html b/parser/htmlparser/tests/reftest/bug1636607-1.html
new file mode 100644
index 0000000000..af2c2cb3e8
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1636607-1.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//FR" "http://www.w3.org/TR/html4/loose.dtd">
+<style>
+div { border: medium solid blue }
+span { background: #9090ff; }
+span.test::before {
+ white-space: pre;
+ content: "\A";
+}
+</style>
+<p>This document is in <span id="mode"></span> mode.</p>
+<p>This is a test for the line height quirk which is present in limited-quirks mode <b>and</b> quirks mode:</p>
+<div><span style="font-size: 50%">hello<br>hello</span></div>
+<p>This is a test for the hashless hex color quirk which is present in quirks mode <b>only</b>:</p>
+<div style="background-color: 9090ff">test</div>
+
+<script>
+document.getElementById("mode").innerText = document.compatMode;
+</script>
diff --git a/parser/htmlparser/tests/reftest/bug1636607-2-ref.html b/parser/htmlparser/tests/reftest/bug1636607-2-ref.html
new file mode 100644
index 0000000000..e82fd73824
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1636607-2-ref.html
@@ -0,0 +1,17 @@
+<style>
+div { border: medium solid blue }
+span { background: #9090ff; }
+span.test::before {
+ white-space: pre;
+ content: "\A";
+}
+</style>
+<p>This document is in <span id="mode"></span> mode.</p>
+<p>This is a test for the line height quirk which is present in limited-quirks mode <b>and</b> quirks mode:</p>
+<div><span style="font-size: 50%">hello<br>hello</span></div>
+<p>This is a test for the hashless hex color quirk which is present in quirks mode <b>only</b>:</p>
+<div style="background-color: 9090ff">test</div>
+
+<script>
+document.getElementById("mode").innerText = document.compatMode;
+</script>
diff --git a/parser/htmlparser/tests/reftest/bug1636607-2.html b/parser/htmlparser/tests/reftest/bug1636607-2.html
new file mode 100644
index 0000000000..f551df5ac1
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1636607-2.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//FR">
+<style>
+div { border: medium solid blue }
+span { background: #9090ff; }
+span.test::before {
+ white-space: pre;
+ content: "\A";
+}
+</style>
+<p>This document is in <span id="mode"></span> mode.</p>
+<p>This is a test for the line height quirk which is present in limited-quirks mode <b>and</b> quirks mode:</p>
+<div><span style="font-size: 50%">hello<br>hello</span></div>
+<p>This is a test for the hashless hex color quirk which is present in quirks mode <b>only</b>:</p>
+<div style="background-color: 9090ff">test</div>
+
+<script>
+document.getElementById("mode").innerText = document.compatMode;
+</script>
diff --git a/parser/htmlparser/tests/reftest/bug482921-1-ref.html b/parser/htmlparser/tests/reftest/bug482921-1-ref.html
new file mode 100644
index 0000000000..71c0f91c08
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug482921-1-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="wrap highlight"><pre id><span class="doctype">&lt;!DOCTYPE html&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">html</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">head</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">title</span>&gt;</span><span>Title</span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">script</span>&gt;</span>
+<span id></span>var lt = "&lt;";
+<span id></span>&lt;!--
+<span id></span>var s = "&lt;script&gt;foo&lt;/script&gt;";
+<span id></span>--&gt;
+<span id></span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span></span><span class="comment">&lt;!-- Comment. --&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">style</span>&gt;</span>
+<span id></span>/* &lt;/foo&gt; */
+<span id></span><span>&lt;/<span class="end-tag">style</span>&gt;</span>
+<span id></span><span>&lt;/<span class="end-tag">head</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">body</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Entity: <span class="entity"><span>&amp;</span>amp; </span></span><span>&lt;/<span class="end-tag">p</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">iframe</span>&gt;</span>&lt;img&gt;<span>&lt;/<span class="end-tag">iframe</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">noscript</span>&gt;</span>&lt;p&gt;Not para&lt;/p&gt;<span>&lt;/<span class="end-tag">noscript</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">svg</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">title</span>&gt;</span><span></span><span class="cdata">&lt;![CDATA[bar]]&gt;</span><span></span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span class="comment">&lt;!-- this is a comment --&gt;</span><span></span><span>&lt;/<span class="end-tag">script</span>&gt;</span>
+<span id></span><span>&lt;/<span class="end-tag">svg</span>&gt;</span>
+<span id></span><span>&lt;/<span class="end-tag">body</span>&gt;</span>
+<span id></span><span>&lt;/<span class="end-tag">html</span>&gt;</span>
+<span id></span>
+</pre>
+<!-- View source CSS matches the <pre id> and <span id> elements and produces line numbers. -->
diff --git a/parser/htmlparser/tests/reftest/bug482921-1.html b/parser/htmlparser/tests/reftest/bug482921-1.html
new file mode 100644
index 0000000000..ca603844f2
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug482921-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Title</title>
+<script>
+var lt = "<";
+<!--
+var s = "<script>foo</script>";
+-->
+</script><!-- Comment. -->
+<style>
+/* </foo> */
+</style>
+</head>
+<body>
+<p>Entity: &amp; </p>
+<iframe><img></iframe>
+<noscript><p>Not para</p></noscript>
+<svg>
+<title><![CDATA[bar]]></title>
+<script><!-- this is a comment --></script>
+</svg>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/reftest/bug482921-2-ref.html b/parser/htmlparser/tests/reftest/bug482921-2-ref.html
new file mode 100644
index 0000000000..d764c70bca
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug482921-2-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="wrap highlight"><pre id><span class="pi">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
+<span id></span><span class="pi">&lt;?foo bar?&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">html</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">head</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">title</span>&gt;</span><span>Title</span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">script</span>&gt;</span>
+<span id></span>var s = "<span>&lt;<span class="start-tag">script</span>&gt;</span><span>foo</span><span>&lt;/<span class="end-tag">script</span>&gt;</span>";
+<span id></span><span class="comment">&lt;!--
+<span id></span>var s = "&lt;script&gt;foo&lt;/script&gt;";
+<span id></span>--&gt;</span>
+<span id></span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span></span>
+<span id></span><span>&lt;<span class="start-tag">style</span>&gt;</span>
+<span id></span>/* <span>&lt;<span class="start-tag">foo</span><span>/</span>&gt;</span> */
+<span id></span><span>&lt;/<span class="end-tag">style</span>&gt;</span>
+<span id></span><span>&lt;/<span class="end-tag">head</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">body</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Entity: <span class="entity"><span>&amp;</span>amp; </span></span><span>&lt;/<span class="end-tag">p</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">iframe</span>&gt;</span><span></span><span>&lt;<span class="start-tag">img</span>&gt;</span><span>&lt;/<span class="end-tag">iframe</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">noscript</span>&gt;</span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Not para</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>&lt;/<span class="end-tag">noscript</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">svg</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">title</span>&gt;</span><span></span><span class="cdata">&lt;![CDATA[bar]]&gt;</span><span></span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
+<span id></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span class="comment">&lt;!-- this is a comment --&gt;</span><span></span><span>&lt;/<span class="end-tag">script</span>&gt;</span>
+<span id></span><span>&lt;/<span class="end-tag">svg</span>&gt;</span>
+<span id></span><span>&lt;/<span class="end-tag">body</span>&gt;</span>
+<span id></span><span>&lt;/<span class="end-tag">html</span>&gt;</span>
+<span id></span>
+</pre>
+<!-- View source CSS matches the <pre id> and <span id> elements and produces line numbers. -->
diff --git a/parser/htmlparser/tests/reftest/bug482921-2.xhtml b/parser/htmlparser/tests/reftest/bug482921-2.xhtml
new file mode 100644
index 0000000000..4d3f0b6a73
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug482921-2.xhtml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<?foo bar?>
+<html>
+<head>
+<title>Title</title>
+<script>
+var s = "<script>foo</script>";
+<!--
+var s = "<script>foo</script>";
+-->
+</script>
+<style>
+/* <foo/> */
+</style>
+</head>
+<body>
+<p>Entity: &amp; </p>
+<iframe><img></iframe>
+<noscript><p>Not para</p></noscript>
+<svg>
+<title><![CDATA[bar]]></title>
+<script><!-- this is a comment --></script>
+</svg>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/reftest/bug535530-1-ref.html b/parser/htmlparser/tests/reftest/bug535530-1-ref.html
new file mode 100644
index 0000000000..22d0dc0b0b
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug535530-1-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html><meta charset=utf-8>
+XX&amp;XX XX&amp;nXX XX&amp;noXX XX¬XX XX¬iXX XX¬inXX XX&amp;;XX XX&amp;n;XX XX&amp;no;XX XX¬XX XX¬i;XX XX∉XX
diff --git a/parser/htmlparser/tests/reftest/bug535530-1.html b/parser/htmlparser/tests/reftest/bug535530-1.html
new file mode 100644
index 0000000000..63f2d8782e
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug535530-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+XX&XX
+XX&nXX
+XX&noXX
+XX&notXX
+XX&notiXX
+XX&notinXX
+XX&;XX
+XX&n;XX
+XX&no;XX
+XX&not;XX
+XX&noti;XX
+XX&notin;XX
+
diff --git a/parser/htmlparser/tests/reftest/bug535530-2-ref.html b/parser/htmlparser/tests/reftest/bug535530-2-ref.html
new file mode 100644
index 0000000000..54c1291218
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug535530-2-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="wrap highlight"><pre id><span class="doctype">&lt;!DOCTYPE html&gt;</span>
+<span id></span>XX<span class="error">&amp;</span>XX
+<span id></span>XX<span class="error">&amp;</span>nXX
+<span id></span>XX<span class="error">&amp;</span>noXX
+<span id></span>XX<span class="error entity">&amp;not</span>XX
+<span id></span>XX<span class="error entity">&amp;noti</span>XX
+<span id></span>XX<span class="error entity">&amp;notin</span>XX
+<span id></span>XX<span class="error">&amp;</span>;XX
+<span id></span>XX<span class="error">&amp;</span>n;XX
+<span id></span>XX<span class="error">&amp;</span>no;XX
+<span id></span>XX<span class="entity">&amp;not;</span>XX
+<span id></span>XX<span class="error entity">&amp;noti</span>;XX
+<span id></span>XX<span class="entity">&amp;notin;</span>XX
+<span id></span>
+<span id></span>
+</pre>
+<!-- View source CSS matches the <pre id> and <span id> elements and produces line numbers. -->
diff --git a/parser/htmlparser/tests/reftest/bug535530-2.html b/parser/htmlparser/tests/reftest/bug535530-2.html
new file mode 100644
index 0000000000..63f2d8782e
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug535530-2.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+XX&XX
+XX&nXX
+XX&noXX
+XX&notXX
+XX&notiXX
+XX&notinXX
+XX&;XX
+XX&n;XX
+XX&no;XX
+XX&not;XX
+XX&noti;XX
+XX&notin;XX
+
diff --git a/parser/htmlparser/tests/reftest/bug566280-1-ref.html b/parser/htmlparser/tests/reftest/bug566280-1-ref.html
new file mode 100644
index 0000000000..6585cac38f
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug566280-1-ref.html
@@ -0,0 +1,2 @@
+<body>hello world
+
diff --git a/parser/htmlparser/tests/reftest/bug566280-1.html b/parser/htmlparser/tests/reftest/bug566280-1.html
new file mode 100644
index 0000000000..3aa60caf34
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug566280-1.html
Binary files differ
diff --git a/parser/htmlparser/tests/reftest/bug569229-1-ref.xml b/parser/htmlparser/tests/reftest/bug569229-1-ref.xml
new file mode 100644
index 0000000000..652f1d7da8
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug569229-1-ref.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="yes" ?>
+<html xmlns="http://www.w3.org/1999/xhtml"><p>abcd</p></html>
diff --git a/parser/htmlparser/tests/reftest/bug569229-1.xml b/parser/htmlparser/tests/reftest/bug569229-1.xml
new file mode 100644
index 0000000000..2e1ff75603
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug569229-1.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" standalone="yes" ?>
+<!DOCTYPE html [
+ <!ENTITY inner "<script src='script.js'></script><p>abcd</p>">
+ <!ENTITY outer "&inner;">
+]>
+<html xmlns="http://www.w3.org/1999/xhtml">&outer;</html>
diff --git a/parser/htmlparser/tests/reftest/bug577418-1-ref.html b/parser/htmlparser/tests/reftest/bug577418-1-ref.html
new file mode 100644
index 0000000000..ff773d5364
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug577418-1-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<style>
+html {
+ background-color: lime;
+}
+</style>
diff --git a/parser/htmlparser/tests/reftest/bug577418-1.html b/parser/htmlparser/tests/reftest/bug577418-1.html
new file mode 100644
index 0000000000..cfd53be0a8
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug577418-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html style="width:100%;height:100%;margin:0;border:0;overflow:hidden">
+<body style="width:100%;height:100%;margin:0;border:0;overflow:hidden">
+<svg style="width:100%;height:100%">
+ <rect height="100%" width="100%" fill="red"/>
+ <foreignObject>
+ <html>
+ <body>
+ </body>
+ </html>
+ </foreignObject>
+ <rect height="100%" width="100%" fill="lime"/>
+</svg>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/reftest/bug582788-1-ref.html b/parser/htmlparser/tests/reftest/bug582788-1-ref.html
new file mode 100644
index 0000000000..c1f684807a
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug582788-1-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+<title>Not ISO-10646</title>
+</head>
+<body>
+<p>Not ISO-10646</p>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/reftest/bug582788-1.html b/parser/htmlparser/tests/reftest/bug582788-1.html
new file mode 100644
index 0000000000..ee31b3de9d
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug582788-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-10646">
+<title>Not ISO-10646</title>
+</head>
+<body>
+<p>Not ISO-10646</p>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/reftest/bug582940-1-ref.html b/parser/htmlparser/tests/reftest/bug582940-1-ref.html
new file mode 100644
index 0000000000..7209c8e69e
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug582940-1-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<head>
+<meta charset=utf-8>
+<title>Fragment nav</title>
+<script>
+function loaded() {
+ document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+<body onload='setTimeout(loaded, 10);'>
+<iframe src="frame582940-ref.html#ref"></iframe>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/reftest/bug582940-1.html b/parser/htmlparser/tests/reftest/bug582940-1.html
new file mode 100644
index 0000000000..fd721a8bc3
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug582940-1.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<head>
+<meta charset=utf-8>
+<title>Fragment nav</title>
+<script>
+function loaded() {
+ document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+<body onload='setTimeout(loaded, 10);'>
+<iframe src="frame582940.html#ref%20ref"></iframe>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/reftest/bug592656-1-ref.html b/parser/htmlparser/tests/reftest/bug592656-1-ref.html
new file mode 100644
index 0000000000..824d815633
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug592656-1-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>document.write() from script-inserted inline scripts and script@onload</title>
+</head>
+<body>
+1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
+</body>
+</html>
diff --git a/parser/htmlparser/tests/reftest/bug592656-1.html b/parser/htmlparser/tests/reftest/bug592656-1.html
new file mode 100644
index 0000000000..769f62f648
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug592656-1.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>document.write() from script-inserted inline scripts and script@onload</title>
+</head>
+<body>
+1
+<script>
+function write(num) {
+ document.write(num + " ");
+}
+function scriptload() {
+ document.write("\u003Cscript src='data:text/javascript,write(9)'>\u003C/script> 10 \u003Cscript>write(11)\u003C/script>");
+ write(12);
+}
+function scripterror() {
+ document.write("\u003Cscript src='data:text/javascript,write(16)'>\u003C/script> 17 \u003Cscript>write(18)\u003C/script>");
+ write(19);
+}
+write(2);
+document.write("\u003Cscript src='data:text/javascript,write(3)'>\u003C/script> 4 \u003Cscript>write(5)\u003C/script>");
+var s = document.createElement("script");
+s.textContent = "write(6)";
+document.body.appendChild(s);
+write(7);
+document.write("\u003Cscript src='data:text/javascript,write(8)' onload='scriptload()'>\u003C/script> 13 \u003Cscript>write(14)\u003C/script>");
+write(15);
+document.write(`\u003Cscript src='nosuchscriptoutthere.js' onload='write("fail")' onerror='scripterror()'>\u003C/script> 20 \u003Cscript>write(21)\u003C/script>`);
+write(22);
+</script>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/reftest/bug599320-1-ref.html b/parser/htmlparser/tests/reftest/bug599320-1-ref.html
new file mode 100644
index 0000000000..bb48fe5d25
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug599320-1-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset=utf-8>
+<meta content="width=device-width, initial-scale=1" name="viewport">
+<title>UTF-16 doc</title>
+</head>
+<body>
+<h1>UTF-16 doc</h1>
+
+<p>Euro sign: €</p>
+<p>iframe:</p>
+<iframe src=frame599320-1-ref.html width=300 height=400></iframe>
+
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/reftest/bug599320-1.html b/parser/htmlparser/tests/reftest/bug599320-1.html
new file mode 100644
index 0000000000..590e9126c3
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug599320-1.html
Binary files differ
diff --git a/parser/htmlparser/tests/reftest/bug608373-1-ref.html b/parser/htmlparser/tests/reftest/bug608373-1-ref.html
new file mode 100644
index 0000000000..69fec47d0f
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug608373-1-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+ <iframe src="data:text/html,TEXT"></iframe>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/reftest/bug608373-1.html b/parser/htmlparser/tests/reftest/bug608373-1.html
new file mode 100644
index 0000000000..7bc47552f7
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug608373-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<head>
+<script>
+function write() {
+ document.getElementsByTagName("iframe")[0].contentDocument.write('\u003Cscript src="data:text/javascript,var i = 0;">\u003C\/script>TEXT\u003Cscript>parent.document.documentElement.removeAttribute("class");\u003c/script>');
+}
+</script>
+</head>
+<body onload="write();">
+ <iframe></iframe>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/reftest/bug659763-1-ref.html b/parser/htmlparser/tests/reftest/bug659763-1-ref.html
new file mode 100644
index 0000000000..99429bf4e7
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-1-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<iframe src="data:text/html,<i>foo</i>"></iframe>
diff --git a/parser/htmlparser/tests/reftest/bug659763-1.html b/parser/htmlparser/tests/reftest/bug659763-1.html
new file mode 100644
index 0000000000..46dbde092e
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-1.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<iframe></iframe>
+<script>
+var iframe = document.getElementsByTagName("iframe")[0];
+var doc = iframe.contentDocument;
+doc.open("text/plain");
+doc.write("<i>foo</i>");
+doc.close();
+</script>
diff --git a/parser/htmlparser/tests/reftest/bug659763-2-ref.html b/parser/htmlparser/tests/reftest/bug659763-2-ref.html
new file mode 100644
index 0000000000..99429bf4e7
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-2-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<iframe src="data:text/html,<i>foo</i>"></iframe>
diff --git a/parser/htmlparser/tests/reftest/bug659763-2.html b/parser/htmlparser/tests/reftest/bug659763-2.html
new file mode 100644
index 0000000000..c6152193aa
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-2.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<iframe></iframe>
+<script>
+var iframe = document.getElementsByTagName("iframe")[0];
+var doc = iframe.contentDocument;
+doc.open("TEXT/PLAIN");
+doc.write("<i>foo</i>");
+doc.close();
+</script>
diff --git a/parser/htmlparser/tests/reftest/bug659763-3-ref.html b/parser/htmlparser/tests/reftest/bug659763-3-ref.html
new file mode 100644
index 0000000000..99429bf4e7
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-3-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<iframe src="data:text/html,<i>foo</i>"></iframe>
diff --git a/parser/htmlparser/tests/reftest/bug659763-3.html b/parser/htmlparser/tests/reftest/bug659763-3.html
new file mode 100644
index 0000000000..bd2ed094bc
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-3.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<iframe></iframe>
+<script>
+var iframe = document.getElementsByTagName("iframe")[0];
+var doc = iframe.contentDocument;
+doc.open("foo/bar");
+doc.write("<i>foo</i>");
+doc.close();
+</script>
diff --git a/parser/htmlparser/tests/reftest/bug659763-4-ref.html b/parser/htmlparser/tests/reftest/bug659763-4-ref.html
new file mode 100644
index 0000000000..99429bf4e7
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-4-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<iframe src="data:text/html,<i>foo</i>"></iframe>
diff --git a/parser/htmlparser/tests/reftest/bug659763-4.html b/parser/htmlparser/tests/reftest/bug659763-4.html
new file mode 100644
index 0000000000..5317186351
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-4.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<iframe></iframe>
+<script>
+var iframe = document.getElementsByTagName("iframe")[0];
+var doc = iframe.contentDocument;
+doc.open("text/html");
+doc.write("<i>foo</i>");
+doc.close();
+</script>
diff --git a/parser/htmlparser/tests/reftest/bug659763-5-ref.html b/parser/htmlparser/tests/reftest/bug659763-5-ref.html
new file mode 100644
index 0000000000..99429bf4e7
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-5-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<iframe src="data:text/html,<i>foo</i>"></iframe>
diff --git a/parser/htmlparser/tests/reftest/bug659763-5.html b/parser/htmlparser/tests/reftest/bug659763-5.html
new file mode 100644
index 0000000000..23e9fd8e6f
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-5.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<iframe></iframe>
+<script>
+var iframe = document.getElementsByTagName("iframe")[0];
+var doc = iframe.contentDocument;
+doc.open();
+doc.write("<i>foo</i>");
+doc.close();
+</script>
diff --git a/parser/htmlparser/tests/reftest/bug659763-6-ref.html b/parser/htmlparser/tests/reftest/bug659763-6-ref.html
new file mode 100644
index 0000000000..99429bf4e7
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-6-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<iframe src="data:text/html,<i>foo</i>"></iframe>
diff --git a/parser/htmlparser/tests/reftest/bug659763-6.html b/parser/htmlparser/tests/reftest/bug659763-6.html
new file mode 100644
index 0000000000..f0a5ea8d3f
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug659763-6.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<iframe></iframe>
+<script>
+var iframe = document.getElementsByTagName("iframe")[0];
+var doc = iframe.contentDocument;
+doc.open("TEXT/HTML");
+doc.write("<i>foo</i>");
+doc.close();
+</script>
diff --git a/parser/htmlparser/tests/reftest/bug673094-1-ref.html b/parser/htmlparser/tests/reftest/bug673094-1-ref.html
new file mode 100644
index 0000000000..f8f8ce5939
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug673094-1-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>bidi in attribute</title>
+</head>
+<body>
+<p>Persian <a href="http://en.wiktionary.org/wiki/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C" title="wikt:فارسی‎" >فارسی</a></p>
+</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/bug673094-1.html b/parser/htmlparser/tests/reftest/bug673094-1.html
new file mode 100644
index 0000000000..2fbdbfb10d
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug673094-1.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>bidi in attribute</title>
+</head>
+<body>
+<p>Persian <a href="http://en.wiktionary.org/wiki/%D9%81%D8%A7%D8%B1%D8%B3%DB%8C" title="wikt:فارسی" >فارسی</a></p>
+</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/bug696651-1-ref.html b/parser/htmlparser/tests/reftest/bug696651-1-ref.html
new file mode 100644
index 0000000000..02f59b7ae6
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug696651-1-ref.html
@@ -0,0 +1 @@
+<!DOCTYPE html>CcBbAa
diff --git a/parser/htmlparser/tests/reftest/bug696651-1.html b/parser/htmlparser/tests/reftest/bug696651-1.html
new file mode 100644
index 0000000000..50a9135aa3
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug696651-1.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<body><script>document.write("\u003cscript>document.write(\"\\u003cscript src='bug696651-external.js'>\\u003c/script>B\"); document.write(\"b\");\u003c/script>A"); document.write("a");</script>
diff --git a/parser/htmlparser/tests/reftest/bug696651-2-ref.html b/parser/htmlparser/tests/reftest/bug696651-2-ref.html
new file mode 100644
index 0000000000..7999785c09
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug696651-2-ref.html
@@ -0,0 +1 @@
+<!DOCTYPE html><iframe src="data:text/html,<!DOCTYPE html>CcBbAa"></iframe>
diff --git a/parser/htmlparser/tests/reftest/bug696651-2.html b/parser/htmlparser/tests/reftest/bug696651-2.html
new file mode 100644
index 0000000000..2d3515b6af
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug696651-2.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<body>
+<iframe></iframe>
+<script>
+var doc = document.getElementsByTagName("iframe")[0].contentDocument;
+doc.open(); doc.write("\u003cscript>document.write(\"\\u003cscript src='bug696651-external.js'>\\u003c/script>B\"); document.write(\"b\");\u003c/script>A"); doc.write("a"); doc.close();</script>
diff --git a/parser/htmlparser/tests/reftest/bug696651-external.js b/parser/htmlparser/tests/reftest/bug696651-external.js
new file mode 100644
index 0000000000..c1c2a8f788
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug696651-external.js
@@ -0,0 +1 @@
+document.write("C"); document.write("c");
diff --git a/parser/htmlparser/tests/reftest/bug700260-1-ref.html b/parser/htmlparser/tests/reftest/bug700260-1-ref.html
new file mode 100644
index 0000000000..0ba4495a09
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug700260-1-ref.html
@@ -0,0 +1,3 @@
+ 1
+ 2
+ 3
diff --git a/parser/htmlparser/tests/reftest/bug700260-1.html b/parser/htmlparser/tests/reftest/bug700260-1.html
new file mode 100644
index 0000000000..37d3008347
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug700260-1.html
@@ -0,0 +1,3 @@
+ 1
+ 2
+ 3
diff --git a/parser/htmlparser/tests/reftest/bug704667-1-ref.html b/parser/htmlparser/tests/reftest/bug704667-1-ref.html
new file mode 100644
index 0000000000..a7a939f3a4
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug704667-1-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="wrap highlight"><pre id><span class="error comment">&lt;!--&gt;</span> <span class="error comment">&lt;!X&gt;</span>
+<span id></span>
+</pre>
+<!-- View source CSS matches the <pre id> and <span id> elements and produces line numbers. -->
diff --git a/parser/htmlparser/tests/reftest/bug704667-1.html b/parser/htmlparser/tests/reftest/bug704667-1.html
new file mode 100644
index 0000000000..553c62b309
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug704667-1.html
@@ -0,0 +1 @@
+<!--> <!X>
diff --git a/parser/htmlparser/tests/reftest/bug731234-1-ref.html b/parser/htmlparser/tests/reftest/bug731234-1-ref.html
new file mode 100644
index 0000000000..897b73ea1b
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug731234-1-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="wrap highlight"><pre id><span class="doctype">&lt;!DOCTYPE html&gt;</span><span>
+<span id></span></span><span>&lt;<span class="start-tag">body</span>&gt;</span><span>
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;/<span class="end-tag">script</span> &gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;/<span class="end-tag">script</span>
+<span id></span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span title="End tag had attributes." class="error">&lt;/<span class="end-tag">script</span> <span class="attribute-name">foo</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span title="End tag had attributes." class="error">&lt;/<span class="end-tag">script</span> <span class="attribute-name">foo</span>=<a class="attribute-value">bar</a>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span title="End tag had attributes." class="error">&lt;/<span class="end-tag">script</span> <span class="attribute-name">foo</span>="<a class="attribute-value">bar</a>"&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>--</span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>-- </span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>-- </span><span>&lt;/<span class="end-tag">script</span> &gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>-- </span><span>&lt;/<span class="end-tag">script</span>
+<span id></span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>-- </span><span title="End tag had attributes." class="error">&lt;/<span class="end-tag">script</span> <span class="attribute-name">foo</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>-- </span><span title="End tag had attributes." class="error">&lt;/<span class="end-tag">script</span> <span class="attribute-name">foo</span>=<a class="attribute-value">bar</a>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>-- </span><span title="End tag had attributes." class="error">&lt;/<span class="end-tag">script</span> <span class="attribute-name">foo</span>="<a class="attribute-value">bar</a>"&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>-- -</span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>-- --</span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>-- --&gt;</span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>--</span><span>&lt;s</span><span>cript&gt; &lt;/script&gt; </span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>--</span><span>&lt;s</span><span>cript&gt; &lt;/script&gt; --&gt;</span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>--</span><span>&lt;s</span><span>cript &lt;/script&gt; --&gt;</span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>--</span><span>&lt;s</span><span>cript&gt; &lt;/script &gt; --&gt;</span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>--</span><span>&lt;s</span><span>cript&gt; &lt;/script foo&gt; --&gt;</span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>--</span><span>&lt;s</span><span>cript&gt; &lt;/script foo=bar&gt; --&gt;</span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span>&lt;!</span><span>--</span><span>&lt;s</span><span>cript&gt; &lt;/script foo="bar"&gt; --&gt;</span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span>X
+<span id></span></span>
+</pre>
+<!-- View source CSS matches the <pre id> and <span id> elements and produces line numbers. -->
diff --git a/parser/htmlparser/tests/reftest/bug731234-1.html b/parser/htmlparser/tests/reftest/bug731234-1.html
new file mode 100644
index 0000000000..313e44cca7
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug731234-1.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<body>
+<script></script>X
+<script></script >X
+<script></script
+>X
+<script></script foo>X
+<script></script foo=bar>X
+<script></script foo="bar">X
+<script><!--</script>X
+<script><!-- </script>X
+<script><!-- </script >X
+<script><!-- </script
+>X
+<script><!-- </script foo>X
+<script><!-- </script foo=bar>X
+<script><!-- </script foo="bar">X
+<script><!-- -</script>X
+<script><!-- --</script>X
+<script><!-- --></script>X
+<script><!--<script> </script> </script>X
+<script><!--<script> </script> --></script>X
+<script><!--<script </script> --></script>X
+<script><!--<script> </script > --></script>X
+<script><!--<script> </script foo> --></script>X
+<script><!--<script> </script foo=bar> --></script>X
+<script><!--<script> </script foo="bar"> --></script>X
diff --git a/parser/htmlparser/tests/reftest/bug820508-1-ref.html b/parser/htmlparser/tests/reftest/bug820508-1-ref.html
new file mode 100644
index 0000000000..e624b16885
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug820508-1-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<title>main { display: block; }</title>
+<style>div {
+ border: 2px solid blue;
+}</style>
+<div>foo</div><div>bar</div>
diff --git a/parser/htmlparser/tests/reftest/bug820508-1.html b/parser/htmlparser/tests/reftest/bug820508-1.html
new file mode 100644
index 0000000000..60eabee67d
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug820508-1.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<title>main { display: block; }</title>
+<style>main {
+ border: 2px solid blue;
+}</style>
+<main>foo</main><main>bar</main>
diff --git a/parser/htmlparser/tests/reftest/bug910588-1-ref.html b/parser/htmlparser/tests/reftest/bug910588-1-ref.html
new file mode 100644
index 0000000000..46133dd2c4
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug910588-1-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="-moz-tab-size: 4"><pre id="line1"><span></span><span class="doctype">&lt;!DOCTYPE html&gt;</span><span></span><span>&lt;<span class="start-tag">table</span>&gt;</span><span></span><span title="Start tag “input” seen in “table”." class="error">&lt;<span class="start-tag">input</span> <span class="attribute-name">type</span>=<a class="attribute-value">hidden</a>&gt;</span><span></span><span>&lt;/<span class="end-tag">table</span>&gt;</span><span>
+<span id="line2"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/bug910588-1.html b/parser/htmlparser/tests/reftest/bug910588-1.html
new file mode 100644
index 0000000000..d0f5958582
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug910588-1.html
@@ -0,0 +1 @@
+<!DOCTYPE html><table><input type=hidden></table>
diff --git a/parser/htmlparser/tests/reftest/frame582940-ref.html b/parser/htmlparser/tests/reftest/frame582940-ref.html
new file mode 100644
index 0000000000..ac665679b5
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/frame582940-ref.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Fragment nav</title>
+</head>
+<body>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p><a name='ref'>Ref!</a></p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/reftest/frame582940.html b/parser/htmlparser/tests/reftest/frame582940.html
new file mode 100644
index 0000000000..646b7d5a71
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/frame582940.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>Fragment nav</title>
+</head>
+<body>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p><a name='ref%20ref'>Ref!</a></p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+<p>Filler</p>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/reftest/frame599320-1-ref.html b/parser/htmlparser/tests/reftest/frame599320-1-ref.html
new file mode 100644
index 0000000000..735c368f8b
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/frame599320-1-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset=utf-8>
+<meta content="width=device-width, initial-scale=1" name="viewport">
+<title>Non-UTF-16 doc</title>
+</head>
+<body>
+<h1>Non-UTF-16 doc</h1>
+
+<p>Euro sign: €</p>
+
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/reftest/frame599320-1.html b/parser/htmlparser/tests/reftest/frame599320-1.html
new file mode 100644
index 0000000000..145ee94ba8
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/frame599320-1.html
@@ -0,0 +1,1092 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<!-- More than 1 KB of space -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<meta charset=utf-8>
+<meta content="width=device-width, initial-scale=1" name="viewport">
+<title>Non-UTF-16 doc</title>
+</head>
+<body>
+<h1>Non-UTF-16 doc</h1>
+
+<p>Euro sign: €</p>
+<script>
+window.onload = function() {
+ window.requestAnimationFrame(function() {
+ parent.document.documentElement.removeAttribute("class");
+ });
+}
+</script>
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/reftest/reftest.list b/parser/htmlparser/tests/reftest/reftest.list
new file mode 100644
index 0000000000..837ba05e85
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/reftest.list
@@ -0,0 +1,28 @@
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == bug535530-1.html bug535530-1-ref.html # Bug 1392106
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == view-source:bug535530-2.html bug535530-2-ref.html # Bug 1392106
+== bug566280-1.html bug566280-1-ref.html
+== bug569229-1.xml bug569229-1-ref.xml
+== bug577418-1.html bug577418-1-ref.html
+== bug582788-1.html bug582788-1-ref.html
+fuzzy-if(skiaContent,0-2,0-5) skip-if(OSX) == bug582940-1.html bug582940-1-ref.html
+== bug592656-1.html bug592656-1-ref.html
+fuzzy-if(skiaContent,0-1,0-5) == bug599320-1.html bug599320-1-ref.html
+fuzzy-if(skiaContent,0-2,0-5) == bug608373-1.html bug608373-1-ref.html
+fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,0-73,0-1) == view-source:bug482921-1.html bug482921-1-ref.html
+== view-source:bug482921-2.xhtml bug482921-2-ref.html
+fuzzy-if(skiaContent,0-2,0-5) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == bug659763-1.html bug659763-1-ref.html # Bug 1392106
+fuzzy-if(skiaContent,0-1,0-5) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == bug659763-2.html bug659763-2-ref.html # Bug 1392106
+fuzzy-if(skiaContent,0-1,0-5) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == bug659763-3.html bug659763-3-ref.html # Bug 1392106
+fuzzy-if(skiaContent,0-2,0-3) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == bug659763-4.html bug659763-4-ref.html # Bug 1392106
+fuzzy-if(skiaContent,0-1,0-5) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == bug659763-5.html bug659763-5-ref.html # Bug 1392106
+fuzzy-if(skiaContent,0-1,0-5) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == bug659763-6.html bug659763-6-ref.html # Bug 1392106
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == view-source:bug673094-1.html view-source:bug673094-1-ref.html # Bug 1392106
+== bug696651-1.html bug696651-1-ref.html
+== bug696651-2.html bug696651-2-ref.html
+== view-source:bug700260-1.html view-source:bug700260-1-ref.html
+== view-source:bug704667-1.html bug704667-1-ref.html
+== view-source:bug731234-1.html bug731234-1-ref.html
+== bug820508-1.html bug820508-1-ref.html
+== view-source:bug910588-1.html bug910588-1-ref.html
+== bug1636607-1.html bug1636607-1-ref.html
+== bug1636607-2.html bug1636607-2-ref.html