summaryrefslogtreecommitdiffstats
path: root/parser/htmlparser
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /parser/htmlparser
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'parser/htmlparser')
-rw-r--r--parser/htmlparser/CNavDTD.cpp44
-rw-r--r--parser/htmlparser/CNavDTD.h32
-rw-r--r--parser/htmlparser/CParserContext.cpp60
-rw-r--r--parser/htmlparser/CParserContext.h60
-rw-r--r--parser/htmlparser/moz.build52
-rw-r--r--parser/htmlparser/nsElementTable.cpp205
-rw-r--r--parser/htmlparser/nsElementTable.h21
-rw-r--r--parser/htmlparser/nsExpatDriver.cpp1747
-rw-r--r--parser/htmlparser/nsExpatDriver.h256
-rw-r--r--parser/htmlparser/nsHTMLTagList.h198
-rw-r--r--parser/htmlparser/nsHTMLTags.cpp167
-rw-r--r--parser/htmlparser/nsHTMLTags.h80
-rw-r--r--parser/htmlparser/nsIContentSink.h143
-rw-r--r--parser/htmlparser/nsIDTD.h88
-rw-r--r--parser/htmlparser/nsIExpatSink.idl111
-rw-r--r--parser/htmlparser/nsIFragmentContentSink.h85
-rw-r--r--parser/htmlparser/nsIHTMLContentSink.h96
-rw-r--r--parser/htmlparser/nsIParser.h186
-rw-r--r--parser/htmlparser/nsParser.cpp1075
-rw-r--r--parser/htmlparser/nsParser.h312
-rw-r--r--parser/htmlparser/nsParserBase.h15
-rw-r--r--parser/htmlparser/nsParserConstants.h22
-rw-r--r--parser/htmlparser/nsParserMsgUtils.cpp62
-rw-r--r--parser/htmlparser/nsParserMsgUtils.h28
-rw-r--r--parser/htmlparser/nsRLBoxExpatDriver.h27
-rw-r--r--parser/htmlparser/nsScanner.cpp331
-rw-r--r--parser/htmlparser/nsScanner.h188
-rw-r--r--parser/htmlparser/nsScannerString.cpp379
-rw-r--r--parser/htmlparser/nsScannerString.h459
-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/1547895-1.html10
-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/1747514.html13
-rw-r--r--parser/htmlparser/tests/crashtests/1810896-1.html1081
-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.list67
-rw-r--r--parser/htmlparser/tests/crashtests/file_445171-1.html1
-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.ini17
-rw-r--r--parser/htmlparser/tests/mochitest/browser_elementindtd.dtd2
-rw-r--r--parser/htmlparser/tests/mochitest/browser_elementindtd.js31
-rw-r--r--parser/htmlparser/tests/mochitest/browser_elementindtd.xml8
-rw-r--r--parser/htmlparser/tests/mochitest/browser_viewsource.js28
-rw-r--r--parser/htmlparser/tests/mochitest/browser_ysod_telemetry.js49
-rw-r--r--parser/htmlparser/tests/mochitest/bug_502091_iframe.html17
-rw-r--r--parser/htmlparser/tests/mochitest/dir_bug534293/file_bug534293.sjs13
-rw-r--r--parser/htmlparser/tests/mochitest/file_async_bug1104732.sjs17
-rw-r--r--parser/htmlparser/tests/mochitest/file_base_csp_img.sjs18
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug102699.sjs19
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs16
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug534293.sjs17
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug543062.sjs38
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug568470-script.sjs17
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug568470.sjs22
-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.sjs19
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug655682.sjs31
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_enc_error.html10
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_enc_error_inherited.html9
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_http_replacement.html1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_http_replacement.html^headers^2
-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_after_head.html10
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_meta_non_superset.html1
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_meta_replacement.html10
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_meta_restart.html1028
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_meta_speculation_fail.html10
-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_bug672453_xml_decl.html10
-rw-r--r--parser/htmlparser/tests/mochitest/file_bug672453_xml_speculation_fail.html10
-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.sjs27
-rw-r--r--parser/htmlparser/tests/mochitest/file_viewsource.html18
-rw-r--r--parser/htmlparser/tests/mochitest/file_xml_parse_error.js1
-rw-r--r--parser/htmlparser/tests/mochitest/file_xml_parse_error.xml3
-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.ini181
-rw-r--r--parser/htmlparser/tests/mochitest/parser_datreader.js218
-rw-r--r--parser/htmlparser/tests/mochitest/parser_web_testrunner.js149
-rw-r--r--parser/htmlparser/tests/mochitest/test_base_csp_img.html35
-rw-r--r--parser/htmlparser/tests/mochitest/test_base_header_csp_img.html32
-rw-r--r--parser/htmlparser/tests/mochitest/test_base_header_csp_img.html^headers^1
-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.html131
-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.html88
-rw-r--r--parser/htmlparser/tests/mochitest/test_xml_mislabeled.html62
-rw-r--r--parser/htmlparser/tests/mochitest/test_xml_parse_error.html79
-rw-r--r--parser/htmlparser/tests/reftest/after-1kb-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/after-1kb.html955
-rw-r--r--parser/htmlparser/tests/reftest/after-bogus-after-1kb-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/after-bogus-after-1kb.html933
-rw-r--r--parser/htmlparser/tests/reftest/after-bogus-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/after-bogus.html10
-rw-r--r--parser/htmlparser/tests/reftest/after-head-after-1kb-crlf-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/after-head-after-1kb-crlf.html927
-rw-r--r--parser/htmlparser/tests/reftest/after-head-after-1kb-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/after-head-after-1kb.html933
-rw-r--r--parser/htmlparser/tests/reftest/after-head-in-1kb-crlf-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/after-head-in-1kb-crlf.html932
-rw-r--r--parser/htmlparser/tests/reftest/after-head-in-1kb-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/after-head-in-1kb.html938
-rw-r--r--parser/htmlparser/tests/reftest/baseline-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/baseline.html10
-rw-r--r--parser/htmlparser/tests/reftest/bug1153920-1-ref.html4
-rw-r--r--parser/htmlparser/tests/reftest/bug1153920-1.html3
-rw-r--r--parser/htmlparser/tests/reftest/bug1319410-1-ref.html6
-rw-r--r--parser/htmlparser/tests/reftest/bug1319410-1.html5
-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/bug1650087-1-ref.html8
-rw-r--r--parser/htmlparser/tests/reftest/bug1650087-1.html7
-rw-r--r--parser/htmlparser/tests/reftest/bug1726374-1-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/bug1726374-1.html1
-rw-r--r--parser/htmlparser/tests/reftest/bug1749522-1-ref.txt3
-rw-r--r--parser/htmlparser/tests/reftest/bug1749522-1.txt3
-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/document-write-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/document-write.html10
-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/in-comment-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/in-comment.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-noscript-after-template-after-1kb-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/in-noscript-after-template-after-1kb.html894
-rw-r--r--parser/htmlparser/tests/reftest/in-noscript-after-template-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/in-noscript-after-template.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-noscript-ncr-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/in-noscript-ncr.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-noscript-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/in-noscript.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-object-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/in-object.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-script-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/in-script.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-style-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/in-style.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-svg-in-cdata-after-gt-ref.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-svg-in-cdata-after-gt.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-svg-in-cdata-ref.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-svg-in-cdata.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-svg-ref.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-svg.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-template-after-1kb-ref.html8
-rw-r--r--parser/htmlparser/tests/reftest/in-template-after-1kb.html1046
-rw-r--r--parser/htmlparser/tests/reftest/in-template-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/in-template.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-title-ref.html10
-rw-r--r--parser/htmlparser/tests/reftest/in-title.html10
-rw-r--r--parser/htmlparser/tests/reftest/incomplete-xml-decl-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/incomplete-xml-decl.xml1
-rw-r--r--parser/htmlparser/tests/reftest/ncr-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/ncr.html10
-rw-r--r--parser/htmlparser/tests/reftest/non-ascii-in-comment-before-ref.html9
-rw-r--r--parser/htmlparser/tests/reftest/non-ascii-in-comment-before.html11
-rw-r--r--parser/htmlparser/tests/reftest/non-ascii-in-title-before-ref.html10
-rw-r--r--parser/htmlparser/tests/reftest/non-ascii-in-title-before.html11
-rw-r--r--parser/htmlparser/tests/reftest/reftest.list73
-rw-r--r--parser/htmlparser/tests/reftest/view-source-bom-ref.html10
-rw-r--r--parser/htmlparser/tests/reftest/view-source-bom.html9
-rw-r--r--parser/htmlparser/tests/reftest/vs-after-head-after-1kb-ref.html11
-rw-r--r--parser/htmlparser/tests/reftest/vs-after-head-after-1kb.html10
-rw-r--r--parser/htmlparser/tests/reftest/vs-after-head-in-1kb-ref.html12
-rw-r--r--parser/htmlparser/tests/reftest/vs-after-head-in-1kb.html11
-rw-r--r--parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before-ref.html12
-rw-r--r--parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before.html11
-rw-r--r--parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before.sjs16
-rw-r--r--parser/htmlparser/tests/reftest/xml-1.xml1
-rw-r--r--parser/htmlparser/tests/reftest/xml-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/xml-trickle-1.sjs17
-rw-r--r--parser/htmlparser/tests/reftest/xml-trickle-2.sjs17
-rw-r--r--parser/htmlparser/tests/reftest/xml-trickle-3.sjs21
-rw-r--r--parser/htmlparser/tests/reftest/xml-trickle-4.sjs17
-rw-r--r--parser/htmlparser/tests/reftest/xml-trickle-5.sjs17
-rw-r--r--parser/htmlparser/tests/reftest/xml-trickle-6.sjs21
-rw-r--r--parser/htmlparser/tests/reftest/xml-utf-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/xml-without-tags-ref.html2
-rw-r--r--parser/htmlparser/tests/reftest/xml-without-tags.xml1
416 files changed, 45303 insertions, 0 deletions
diff --git a/parser/htmlparser/CNavDTD.cpp b/parser/htmlparser/CNavDTD.cpp
new file mode 100644
index 0000000000..d18aacfcb2
--- /dev/null
+++ b/parser/htmlparser/CNavDTD.cpp
@@ -0,0 +1,44 @@
+/* -*- 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::BuildModel(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;
+}
+
+void CNavDTD::DidBuildModel() {}
+
+NS_IMETHODIMP_(void)
+CNavDTD::Terminate() {}
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..d57c9855cc
--- /dev/null
+++ b/parser/htmlparser/CParserContext.cpp
@@ -0,0 +1,60 @@
+/* -*- 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 "nsMimeTypes.h"
+
+CParserContext::CParserContext(nsIURI* aURI, eParserCommands aCommand)
+ : mScanner(aURI),
+ mDTDMode(eDTDMode_autodetect),
+ mDocType(eUnknown),
+ mStreamListenerState(eNone),
+ mContextType(eCTURL),
+ mParserCommand(aCommand),
+ mMultipart(true),
+ mCopyUnused(false) {
+ MOZ_COUNT_CTOR(CParserContext);
+}
+
+CParserContext::CParserContext(const nsAString& aBuffer,
+ eParserCommands aCommand, bool aLastBuffer)
+ : mScanner(aBuffer, !aLastBuffer),
+ mMimeType("application/xml"_ns),
+ mDTDMode(eDTDMode_full_standards),
+ mDocType(eXML),
+ mStreamListenerState(aLastBuffer ? eOnStop : eOnDataAvail),
+ mContextType(eCTString),
+ mParserCommand(aCommand),
+ mMultipart(!aLastBuffer),
+ mCopyUnused(aLastBuffer) {
+ 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 = eUnknown;
+
+ 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;
+}
diff --git a/parser/htmlparser/CParserContext.h b/parser/htmlparser/CParserContext.h
new file mode 100644
index 0000000000..b32436795b
--- /dev/null
+++ b/parser/htmlparser/CParserContext.h
@@ -0,0 +1,60 @@
+/* -*- 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"
+
+class nsITokenizer;
+
+/**
+ * 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 { eCTURL, eCTString };
+
+ CParserContext(nsIURI* aURI, eParserCommands aCommand);
+ CParserContext(const nsAString& aBuffer, eParserCommands aCommand,
+ bool aLastBuffer);
+
+ ~CParserContext();
+
+ void SetMimeType(const nsACString& aMimeType);
+
+ nsCOMPtr<nsIRequest>
+ mRequest; // provided by necko to differnciate different input streams
+ // why is mRequest strongly referenced? see bug 102376.
+ nsScanner mScanner;
+
+ nsCString mMimeType;
+ nsDTDMode mDTDMode;
+
+ eParserDocType mDocType;
+ eStreamState mStreamListenerState;
+ eContextType mContextType;
+ eAutoDetectResult mAutoDetectStatus = eUnknownDetect;
+ eParserCommands mParserCommand;
+
+ bool mMultipart;
+ bool mCopyUnused;
+};
+
+#endif
diff --git a/parser/htmlparser/moz.build b/parser/htmlparser/moz.build
new file mode 100644
index 0000000000..ceac572399
--- /dev/null
+++ b/parser/htmlparser/moz.build
@@ -0,0 +1,52 @@
+# -*- 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",
+ "nsParserBase.h",
+ "nsParserConstants.h",
+ "nsRLBoxExpatDriver.h",
+ "nsScannerString.h",
+]
+
+UNIFIED_SOURCES += [
+ "CNavDTD.cpp",
+ "CParserContext.cpp",
+ "nsElementTable.cpp",
+ "nsExpatDriver.cpp",
+ "nsHTMLTags.cpp",
+ "nsParser.cpp",
+ "nsParserMsgUtils.cpp",
+ "nsScanner.cpp",
+ "nsScannerString.cpp",
+]
+
+include("/ipc/chromium/chromium-config.mozbuild")
+
+FINAL_LIBRARY = "xul"
+
+LOCAL_INCLUDES += [
+ "!/security/rlbox",
+]
diff --git a/parser/htmlparser/nsElementTable.cpp b/parser/htmlparser/nsElementTable.cpp
new file mode 100644
index 0000000000..e6bf6b8dae
--- /dev/null
+++ b/parser/htmlparser/nsElementTable.cpp
@@ -0,0 +1,205 @@
+/* -*- 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(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..4da2444f84
--- /dev/null
+++ b/parser/htmlparser/nsExpatDriver.cpp
@@ -0,0 +1,1747 @@
+/* -*- 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 "mozilla/fallible.h"
+#include "nsCOMPtr.h"
+#include "CParserContext.h"
+#include "nsIExpatSink.h"
+#include "nsIContentSink.h"
+#include "nsIDocShell.h"
+#include "nsParserMsgUtils.h"
+#include "nsIURL.h"
+#include "nsIUnicharInputStream.h"
+#include "nsIProtocolHandler.h"
+#include "nsNetUtil.h"
+#include "nsString.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/Array.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/BasePrincipal.h"
+#include "mozilla/IntegerTypeTraits.h"
+#include "mozilla/NullPrincipal.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/TelemetryComms.h"
+
+#include "nsThreadUtils.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/RLBoxUtils.h"
+#include "mozilla/UniquePtr.h"
+
+#include "mozilla/Logging.h"
+
+using mozilla::fallible;
+using mozilla::LogLevel;
+using mozilla::MakeStringSpan;
+using mozilla::Maybe;
+using mozilla::Unused;
+using mozilla::dom::Document;
+
+// We only pass chunks of length sMaxChunkLength to Expat in the RLBOX sandbox.
+// The RLBOX sandbox has a limited amount of memory, and we have to account for
+// other memory use by Expat (including the buffering it does).
+// Note that sMaxChunkLength is in number of characters.
+#ifdef DEBUG
+// On debug builds we set a much lower limit (1kB) to try to hit boundary
+// conditions more frequently.
+static const uint32_t sMaxChunkLength = 1024 / sizeof(char16_t);
+#else
+static const uint32_t sMaxChunkLength = (128 * 1024) / sizeof(char16_t);
+#endif
+
+#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;
+
+/***************************** RLBOX HELPERS ********************************/
+// Helpers for calling sandboxed expat functions in handlers
+
+#define RLBOX_EXPAT_SAFE_CALL(foo, verifier, ...) \
+ aSandbox.invoke_sandbox_function(foo, self->mExpatParser, ##__VA_ARGS__) \
+ .copy_and_verify(verifier)
+
+#define RLBOX_EXPAT_SAFE_MCALL(foo, verifier, ...) \
+ Sandbox() \
+ ->invoke_sandbox_function(foo, mExpatParser, ##__VA_ARGS__) \
+ .copy_and_verify(verifier)
+
+#define RLBOX_EXPAT_CALL(foo, ...) \
+ aSandbox.invoke_sandbox_function(foo, self->mExpatParser, ##__VA_ARGS__)
+
+#define RLBOX_EXPAT_MCALL(foo, ...) \
+ Sandbox()->invoke_sandbox_function(foo, mExpatParser, ##__VA_ARGS__)
+
+#define RLBOX_SAFE_PRINT "Value used only for printing"
+#define MOZ_RELEASE_ASSERT_TAINTED(cond, ...) \
+ MOZ_RELEASE_ASSERT((cond).unverified_safe_because("Sanity check"), \
+ ##__VA_ARGS__)
+
+/* safe_unverified is used whenever it's safe to not use a validator */
+template <typename T>
+static T safe_unverified(T val) {
+ return val;
+}
+
+/* status_verifier is a type validator for XML_Status */
+inline enum XML_Status status_verifier(enum XML_Status s) {
+ MOZ_RELEASE_ASSERT(s >= XML_STATUS_ERROR && s <= XML_STATUS_SUSPENDED,
+ "unexpected status code");
+ return s;
+}
+
+/* error_verifier is a type validator for XML_Error */
+inline enum XML_Error error_verifier(enum XML_Error code) {
+ MOZ_RELEASE_ASSERT(
+ code >= XML_ERROR_NONE && code <= XML_ERROR_INVALID_ARGUMENT,
+ "unexpected XML error code");
+ return code;
+}
+
+/* We use unverified_xml_string to just expose sandbox expat strings to Firefox
+ * without any validation. On 64-bit we have guard pages at the sandbox
+ * boundary; on 32-bit we don't and a string could be used to read beyond the
+ * sandbox boundary. In our attacker model this is okay (the attacker can just
+ * Spectre).
+ *
+ * Nevertheless, we should try to add strings validators to the consumer code
+ * of expat whenever we have some semantics. At the very lest we should make
+ * sure that the strings are never written to. Bug 1693991 tracks this.
+ */
+static const XML_Char* unverified_xml_string(uintptr_t ptr) {
+ return reinterpret_cast<const XML_Char*>(ptr);
+}
+
+/* The TransferBuffer class is used to copy (or directly expose in the
+ * noop-sandbox case) buffers into the expat sandbox (and automatically
+ * when out of scope).
+ */
+template <typename T>
+using TransferBuffer =
+ mozilla::RLBoxTransferBufferToSandbox<T, rlbox_expat_sandbox_type>;
+
+/*************************** END RLBOX HELPERS ******************************/
+
+/***************************** EXPAT CALL BACKS ******************************/
+// The callback handlers that get called from the expat parser.
+
+static void Driver_HandleXMLDeclaration(
+ rlbox_sandbox_expat& aSandbox, tainted_expat<void*> /* aUserData */,
+ tainted_expat<const XML_Char*> aVersion,
+ tainted_expat<const XML_Char*> aEncoding, tainted_expat<int> aStandalone) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(driver);
+
+ int standalone = aStandalone.copy_and_verify([&](auto a) {
+ // Standalone argument can be -1, 0, or 1 (see
+ // /parser/expat/lib/expat.h#185)
+ MOZ_RELEASE_ASSERT(a >= -1 && a <= 1, "Unexpected standalone parameter");
+ return a;
+ });
+
+ const auto* version = aVersion.copy_and_verify_address(unverified_xml_string);
+ const auto* encoding =
+ aEncoding.copy_and_verify_address(unverified_xml_string);
+ driver->HandleXMLDeclaration(version, encoding, standalone);
+}
+
+static void Driver_HandleCharacterData(rlbox_sandbox_expat& aSandbox,
+ tainted_expat<void*> /* aUserData */,
+ tainted_expat<const XML_Char*> aData,
+ tainted_expat<int> aLength) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(driver);
+ // aData is not null terminated; even with bad length we will not span beyond
+ // sandbox boundary
+ uint32_t length =
+ static_cast<uint32_t>(aLength.copy_and_verify(safe_unverified<int>));
+ const auto* data = aData.unverified_safe_pointer_because(
+ length, "Only care that the data is within sandbox boundary.");
+ driver->HandleCharacterData(data, length);
+}
+
+static void Driver_HandleComment(rlbox_sandbox_expat& aSandbox,
+ tainted_expat<void*> /* aUserData */,
+ tainted_expat<const XML_Char*> aName) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(driver);
+ const auto* name = aName.copy_and_verify_address(unverified_xml_string);
+ driver->HandleComment(name);
+}
+
+static void Driver_HandleProcessingInstruction(
+ rlbox_sandbox_expat& aSandbox, tainted_expat<void*> /* aUserData */,
+ tainted_expat<const XML_Char*> aTarget,
+ tainted_expat<const XML_Char*> aData) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(driver);
+ const auto* target = aTarget.copy_and_verify_address(unverified_xml_string);
+ const auto* data = aData.copy_and_verify_address(unverified_xml_string);
+ driver->HandleProcessingInstruction(target, data);
+}
+
+static void Driver_HandleDefault(rlbox_sandbox_expat& aSandbox,
+ tainted_expat<void*> /* aUserData */,
+ tainted_expat<const XML_Char*> aData,
+ tainted_expat<int> aLength) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(driver);
+ // aData is not null terminated; even with bad length we will not span
+ // beyond sandbox boundary
+ uint32_t length =
+ static_cast<uint32_t>(aLength.copy_and_verify(safe_unverified<int>));
+ const auto* data = aData.unverified_safe_pointer_because(
+ length, "Only care that the data is within sandbox boundary.");
+ driver->HandleDefault(data, length);
+}
+
+static void Driver_HandleStartCdataSection(
+ rlbox_sandbox_expat& aSandbox, tainted_expat<void*> /* aUserData */) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(driver);
+ driver->HandleStartCdataSection();
+}
+
+static void Driver_HandleEndCdataSection(rlbox_sandbox_expat& aSandbox,
+ tainted_expat<void*> /* aUserData */) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(driver);
+ driver->HandleEndCdataSection();
+}
+
+static void Driver_HandleStartDoctypeDecl(
+ rlbox_sandbox_expat& aSandbox, tainted_expat<void*> /* aUserData */,
+ tainted_expat<const XML_Char*> aDoctypeName,
+ tainted_expat<const XML_Char*> aSysid,
+ tainted_expat<const XML_Char*> aPubid,
+ tainted_expat<int> aHasInternalSubset) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(driver);
+ const auto* doctypeName =
+ aDoctypeName.copy_and_verify_address(unverified_xml_string);
+ const auto* sysid = aSysid.copy_and_verify_address(unverified_xml_string);
+ const auto* pubid = aPubid.copy_and_verify_address(unverified_xml_string);
+ bool hasInternalSubset =
+ !!(aHasInternalSubset.copy_and_verify(safe_unverified<int>));
+ driver->HandleStartDoctypeDecl(doctypeName, sysid, pubid, hasInternalSubset);
+}
+
+static void Driver_HandleEndDoctypeDecl(rlbox_sandbox_expat& aSandbox,
+ tainted_expat<void*> /* aUserData */) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(driver);
+ driver->HandleEndDoctypeDecl();
+}
+
+static tainted_expat<int> Driver_HandleExternalEntityRef(
+ rlbox_sandbox_expat& aSandbox, tainted_expat<XML_Parser> /* aParser */,
+ tainted_expat<const XML_Char*> aOpenEntityNames,
+ tainted_expat<const XML_Char*> aBase,
+ tainted_expat<const XML_Char*> aSystemId,
+ tainted_expat<const XML_Char*> aPublicId) {
+ nsExpatDriver* driver = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(driver);
+
+ const auto* openEntityNames =
+ aOpenEntityNames.copy_and_verify_address(unverified_xml_string);
+ const auto* base = aBase.copy_and_verify_address(unverified_xml_string);
+ const auto* systemId =
+ aSystemId.copy_and_verify_address(unverified_xml_string);
+ const auto* publicId =
+ aPublicId.copy_and_verify_address(unverified_xml_string);
+ return driver->HandleExternalEntityRef(openEntityNames, base, systemId,
+ publicId);
+}
+
+/***************************** 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(nsIDTD)
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+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),
+ mInParser(false),
+ mInternalState(NS_OK),
+ mExpatBuffered(0),
+ mTagDepth(0),
+ mCatalogData(nullptr),
+ mInnerWindowID(0) {}
+
+nsExpatDriver::~nsExpatDriver() { Destroy(); }
+
+void nsExpatDriver::Destroy() {
+ if (mSandboxPoolData) {
+ SandboxData()->DetachDriver();
+ if (mExpatParser) {
+ RLBOX_EXPAT_MCALL(MOZ_XML_ParserFree);
+ }
+ }
+ mSandboxPoolData.reset();
+ mURIs.Clear();
+ mExpatParser = nullptr;
+}
+
+// The AllocAttrs class is used to speed up copying attributes from the
+// sandboxed expat by fast allocating attributes on the stack and only falling
+// back to malloc when we need to allocate lots of attributes.
+class MOZ_STACK_CLASS AllocAttrs {
+#define NUM_STACK_SLOTS 16
+ public:
+ const char16_t** Init(size_t size) {
+ if (size <= NUM_STACK_SLOTS) {
+ return mInlineArr;
+ }
+ mHeapPtr = mozilla::MakeUnique<const char16_t*[]>(size);
+ return mHeapPtr.get();
+ }
+
+ private:
+ const char16_t* mInlineArr[NUM_STACK_SLOTS];
+ mozilla::UniquePtr<const char16_t*[]> mHeapPtr;
+#undef NUM_STACK_SLOTS
+};
+
+/* static */
+void nsExpatDriver::HandleStartElement(rlbox_sandbox_expat& aSandbox,
+ tainted_expat<void*> /* aUserData */,
+ tainted_expat<const char16_t*> aName,
+ tainted_expat<const char16_t**> aAttrs) {
+ nsExpatDriver* self = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(self && self->mSink);
+
+ const auto* name = aName.copy_and_verify_address(unverified_xml_string);
+
+ // Calculate the total number of elements in aAttrs.
+ // XML_GetSpecifiedAttributeCount will only give us the number of specified
+ // attrs (twice that number, actually), so we have to check for default
+ // attrs ourselves.
+ tainted_expat<int> count =
+ RLBOX_EXPAT_CALL(MOZ_XML_GetSpecifiedAttributeCount);
+ MOZ_RELEASE_ASSERT_TAINTED(count >= 0, "Unexpected attribute count");
+
+ tainted_expat<uint64_t> attrArrayLengthTainted;
+ for (attrArrayLengthTainted = rlbox::sandbox_static_cast<uint64_t>(count);
+ (aAttrs[attrArrayLengthTainted] != nullptr)
+ .unverified_safe_because("Bad length is checked later");
+ attrArrayLengthTainted += 2) {
+ // Just looping till we find out what the length is
+ }
+
+ uint32_t attrArrayLength =
+ attrArrayLengthTainted.copy_and_verify([&](uint64_t value) {
+ // A malicious length could result in an overflow when we allocate
+ // aAttrs and then access elements of the array.
+ MOZ_RELEASE_ASSERT(value < UINT32_MAX, "Overflow attempt");
+ return value;
+ });
+
+ // Copy tainted aAttrs from sandbox
+ AllocAttrs allocAttrs;
+ const char16_t** attrs = allocAttrs.Init(attrArrayLength + 1);
+ if (NS_WARN_IF(!aAttrs || !attrs)) {
+ self->MaybeStopParser(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+
+ for (uint32_t i = 0; i < attrArrayLength; i++) {
+ attrs[i] = aAttrs[i].copy_and_verify_address(unverified_xml_string);
+ }
+ attrs[attrArrayLength] = nullptr;
+
+ 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(
+ name, attrs, attrArrayLength,
+ RLBOX_EXPAT_SAFE_CALL(MOZ_XML_GetCurrentLineNumber,
+ safe_unverified<XML_Size>),
+ RLBOX_EXPAT_SAFE_CALL(MOZ_XML_GetCurrentColumnNumber,
+ safe_unverified<XML_Size>));
+ self->MaybeStopParser(rv);
+ }
+}
+
+/* static */
+void nsExpatDriver::HandleStartElementForSystemPrincipal(
+ rlbox_sandbox_expat& aSandbox, tainted_expat<void*> aUserData,
+ tainted_expat<const char16_t*> aName,
+ tainted_expat<const char16_t**> aAttrs) {
+ nsExpatDriver* self = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(self);
+ if (!RLBOX_EXPAT_SAFE_CALL(MOZ_XML_ProcessingEntityValue,
+ safe_unverified<XML_Bool>)) {
+ HandleStartElement(aSandbox, aUserData, aName, aAttrs);
+ } else {
+ nsCOMPtr<Document> doc =
+ do_QueryInterface(self->mOriginalSink->GetTarget());
+
+ // Adjust the column number so that it is one based rather than zero
+ // based.
+ tainted_expat<XML_Size> colNumber =
+ RLBOX_EXPAT_CALL(MOZ_XML_GetCurrentColumnNumber) + 1;
+ tainted_expat<XML_Size> lineNumber =
+ RLBOX_EXPAT_CALL(MOZ_XML_GetCurrentLineNumber);
+
+ int32_t nameSpaceID;
+ RefPtr<nsAtom> prefix, localName;
+ const auto* name = aName.copy_and_verify_address(unverified_xml_string);
+ nsContentUtils::SplitExpatName(name, 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.unverified_safe_because(RLBOX_SAFE_PRINT),
+ colNumber.unverified_safe_because(RLBOX_SAFE_PRINT));
+ }
+}
+
+/* static */
+void nsExpatDriver::HandleEndElement(rlbox_sandbox_expat& aSandbox,
+ tainted_expat<void*> aUserData,
+ tainted_expat<const char16_t*> aName) {
+ nsExpatDriver* self = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(self);
+ const auto* name = aName.copy_and_verify_address(unverified_xml_string);
+
+ 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(name);
+ --self->mTagDepth;
+ self->MaybeStopParser(rv);
+ }
+}
+
+/* static */
+void nsExpatDriver::HandleEndElementForSystemPrincipal(
+ rlbox_sandbox_expat& aSandbox, tainted_expat<void*> aUserData,
+ tainted_expat<const char16_t*> aName) {
+ nsExpatDriver* self = static_cast<nsExpatDriver*>(aSandbox.sandbox_storage);
+ MOZ_ASSERT(self);
+ if (!RLBOX_EXPAT_SAFE_CALL(MOZ_XML_ProcessingEntityValue,
+ safe_unverified<XML_Bool>)) {
+ HandleEndElement(aSandbox, 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;
+}
+
+// Wrapper class for passing the sandbox data and parser as a closure to
+// ExternalDTDStreamReaderFunc.
+class RLBoxExpatClosure {
+ public:
+ RLBoxExpatClosure(RLBoxExpatSandboxData* aSbxData,
+ tainted_expat<XML_Parser> aExpatParser)
+ : mSbxData(aSbxData), mExpatParser(aExpatParser){};
+ inline rlbox_sandbox_expat* Sandbox() const { return mSbxData->Sandbox(); };
+ inline tainted_expat<XML_Parser> Parser() const { return mExpatParser; };
+
+ private:
+ RLBoxExpatSandboxData* mSbxData;
+ tainted_expat<XML_Parser> mExpatParser;
+};
+
+static nsresult ExternalDTDStreamReaderFunc(nsIUnicharInputStream* aIn,
+ void* aClosure,
+ const char16_t* aFromSegment,
+ uint32_t aToOffset, uint32_t aCount,
+ uint32_t* aWriteCount) {
+ MOZ_ASSERT(aClosure && aFromSegment && aWriteCount);
+
+ *aWriteCount = 0;
+
+ // Get sandbox and parser
+ auto* closure = reinterpret_cast<RLBoxExpatClosure*>(aClosure);
+ MOZ_ASSERT(closure);
+
+ // Transfer segment into the sandbox
+ auto fromSegment =
+ TransferBuffer<char16_t>(closure->Sandbox(), aFromSegment, aCount);
+ NS_ENSURE_TRUE(*fromSegment, NS_ERROR_OUT_OF_MEMORY);
+
+ // Pass the buffer to expat for parsing.
+ if (closure->Sandbox()
+ ->invoke_sandbox_function(
+ MOZ_XML_Parse, closure->Parser(),
+ rlbox::sandbox_reinterpret_cast<const char*>(*fromSegment),
+ aCount * sizeof(char16_t), 0)
+ .copy_and_verify(status_verifier) == XML_STATUS_OK) {
+ *aWriteCount = aCount;
+ return NS_OK;
+ }
+
+ 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(';'));
+ }
+
+ nsCOMPtr<nsIURI> baseURI = GetBaseURI(base);
+ NS_ENSURE_TRUE(baseURI, 1);
+
+ // Load the external entity into a buffer.
+ nsCOMPtr<nsIInputStream> in;
+ nsCOMPtr<nsIURI> absURI;
+ nsresult rv = OpenInputStreamFromExternalDTD(
+ publicId, systemId, baseURI, getter_AddRefs(in), getter_AddRefs(absURI));
+ 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 \"";
+ message.Append(baseURI->GetSpecOrDefault());
+ message += "\" URL \"";
+ if (absURI) {
+ message.Append(absURI->GetSpecOrDefault());
+ }
+ 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) {
+ auto utf16 = TransferBuffer<char16_t>(
+ Sandbox(), kUTF16, nsCharTraits<char16_t>::length(kUTF16) + 1);
+ NS_ENSURE_TRUE(*utf16, 1);
+ tainted_expat<XML_Parser> entParser;
+ entParser =
+ RLBOX_EXPAT_MCALL(MOZ_XML_ExternalEntityParserCreate, nullptr, *utf16);
+ if (entParser) {
+ auto baseURI = GetExpatBaseURI(absURI);
+ auto url = TransferBuffer<XML_Char>(Sandbox(), &baseURI[0],
+ ArrayLength(baseURI));
+ NS_ENSURE_TRUE(*url, 1);
+ Sandbox()->invoke_sandbox_function(MOZ_XML_SetBase, entParser, *url);
+
+ mInExternalDTD = true;
+
+ bool inParser = mInParser; // Save in-parser status
+ mInParser = true;
+
+ RLBoxExpatClosure closure(SandboxData(), entParser);
+ uint32_t totalRead;
+ do {
+ rv = uniIn->ReadSegments(ExternalDTDStreamReaderFunc, &closure,
+ uint32_t(-1), &totalRead);
+ } while (NS_SUCCEEDED(rv) && totalRead > 0);
+
+ result =
+ Sandbox()
+ ->invoke_sandbox_function(MOZ_XML_Parse, entParser, nullptr, 0, 1)
+ .copy_and_verify(status_verifier);
+
+ mInParser = inParser; // Restore in-parser status
+ mInExternalDTD = false;
+
+ Sandbox()->invoke_sandbox_function(MOZ_XML_ParserFree, entParser);
+ }
+ }
+
+ return result;
+}
+
+nsresult nsExpatDriver::OpenInputStreamFromExternalDTD(const char16_t* aFPIStr,
+ const char16_t* aURLStr,
+ nsIURI* aBaseURI,
+ nsIInputStream** aStream,
+ nsIURI** aAbsURI) {
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(aURLStr),
+ nullptr, aBaseURI);
+ // 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);
+ }
+ }
+
+ uri.forget(aAbsURI);
+
+ channel->SetContentType("application/xml"_ns);
+ return channel->Open(aStream);
+}
+
+static nsresult CreateErrorText(const char16_t* aDescription,
+ const char16_t* aSourceURL,
+ tainted_expat<XML_Size> aLineNumber,
+ tainted_expat<XML_Size> 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.unverified_safe_because(RLBOX_SAFE_PRINT),
+ aColNumber.unverified_safe_because(RLBOX_SAFE_PRINT));
+ return NS_OK;
+}
+
+static nsresult AppendErrorPointer(tainted_expat<XML_Size> aColNumber,
+ const char16_t* aSourceLine,
+ size_t aSourceLineLength,
+ nsString& aSourceString) {
+ aSourceString.Append(char16_t('\n'));
+
+ MOZ_RELEASE_ASSERT_TAINTED(aColNumber != static_cast<XML_Size>(0),
+ "Unexpected value of column");
+
+ // Last character will be '^'.
+ XML_Size last =
+ (aColNumber - 1).copy_and_verify([&](XML_Size val) -> XML_Size {
+ if (val > aSourceLineLength) {
+ // Unexpected value of last column, just return a safe value
+ return 0;
+ }
+ return val;
+ });
+
+ XML_Size 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 =
+ RLBOX_EXPAT_MCALL(MOZ_XML_GetErrorCode).copy_and_verify(error_verifier);
+
+ // 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 =
+ RLBOX_EXPAT_MCALL(MOZ_XML_GetMismatchedTag)
+ .copy_and_verify_address(unverified_xml_string);
+ 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.
+ tainted_expat<XML_Size> colNumber =
+ RLBOX_EXPAT_MCALL(MOZ_XML_GetCurrentColumnNumber) + 1;
+ tainted_expat<XML_Size> lineNumber =
+ RLBOX_EXPAT_MCALL(MOZ_XML_GetCurrentLineNumber);
+
+ // Copy out the two character bufer that holds the expatBase
+ const std::unique_ptr<XML_Char[]> expatBase =
+ RLBOX_EXPAT_MCALL(MOZ_XML_GetBase)
+ .copy_and_verify_range(
+ [](std::unique_ptr<XML_Char[]> val) {
+ // No additional checks needed as this is sent to GetBaseURI
+ // which checks its inputs
+ return val;
+ },
+ ExpatBaseURI::Length);
+ nsAutoString uri;
+ nsCOMPtr<nsIURI> baseURI;
+ if (expatBase && (baseURI = GetBaseURI(expatBase.get()))) {
+ // Let's ignore if this fails, we're already reporting a parse error.
+ Unused << CopyUTF8toUTF16(baseURI->GetSpecOrDefault(), uri, fallible);
+ }
+ nsAutoString errorText;
+ CreateErrorText(description.get(), uri.get(), lineNumber, colNumber,
+ errorText, spoofEnglish);
+
+ nsAutoString sourceText(mLastLine);
+ AppendErrorPointer(colNumber, mLastLine.get(), mLastLine.Length(),
+ sourceText);
+
+ if (doc && nsContentUtils::IsChromeDoc(doc)) {
+ nsCString path = doc->GetDocumentURI()->GetSpecOrDefault();
+ nsCOMPtr<nsISupports> container = doc->GetContainer();
+ nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
+ nsCString docShellDestroyed("unknown"_ns);
+ if (docShell) {
+ bool destroyed = false;
+ docShell->IsBeingDestroyed(&destroyed);
+ docShellDestroyed.Assign(destroyed ? "true"_ns : "false"_ns);
+ }
+
+ 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(
+ "%lu:%lu",
+ lineNumber.unverified_safe_because(RLBOX_SAFE_PRINT),
+ colNumber.unverified_safe_because(RLBOX_SAFE_PRINT))},
+ mozilla::Telemetry::EventExtraEntry{
+ "last_line"_ns, NS_ConvertUTF16toUTF8(mLastLine)},
+ mozilla::Telemetry::EventExtraEntry{
+ "last_line_len"_ns, nsPrintfCString("%zu", mLastLine.Length())},
+ mozilla::Telemetry::EventExtraEntry{
+ "hidden"_ns, doc->Hidden() ? "true"_ns : "false"_ns},
+ mozilla::Telemetry::EventExtraEntry{"destroyed"_ns,
+ docShellDestroyed},
+ });
+
+ 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->InitWithSourceURI(
+ errorText, mURIs.SafeElementAt(0), mLastLine,
+ lineNumber.unverified_safe_because(RLBOX_SAFE_PRINT),
+ colNumber.unverified_safe_because(RLBOX_SAFE_PRINT),
+ 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;
+}
+
+// Because we need to allocate a buffer in the RLBOX sandbox, and copy the data
+// to it for Expat to parse, we are limited in size by the memory available in
+// the RLBOX sandbox. nsExpatDriver::ChunkAndParseBuffer divides the buffer into
+// chunks of sMaxChunkLength characters or less, and passes them to
+// nsExpatDriver::ParseBuffer. That should ensure that we almost never run out
+// of memory in the sandbox.
+void nsExpatDriver::ChunkAndParseBuffer(const char16_t* aBuffer,
+ uint32_t aLength, bool aIsFinal,
+ uint32_t* aPassedToExpat,
+ uint32_t* aConsumed,
+ XML_Size* aLastLineLength) {
+ *aConsumed = 0;
+ *aLastLineLength = 0;
+
+ uint32_t remainder = aLength;
+ while (remainder > sMaxChunkLength) {
+ ParseChunk(aBuffer, sMaxChunkLength, ChunkOrBufferIsFinal::None, aConsumed,
+ aLastLineLength);
+ aBuffer += sMaxChunkLength;
+ remainder -= sMaxChunkLength;
+ if (NS_FAILED(mInternalState)) {
+ // Stop parsing if there's an error (including if we're blocked or
+ // interrupted).
+ *aPassedToExpat = aLength - remainder;
+ return;
+ }
+ }
+
+ ParseChunk(aBuffer, remainder,
+ aIsFinal ? ChunkOrBufferIsFinal::FinalChunkAndBuffer
+ : ChunkOrBufferIsFinal::FinalChunk,
+ aConsumed, aLastLineLength);
+ *aPassedToExpat = aLength;
+}
+
+void nsExpatDriver::ParseChunk(const char16_t* aBuffer, uint32_t aLength,
+ ChunkOrBufferIsFinal aIsFinal,
+ uint32_t* aConsumed, XML_Size* aLastLineLength) {
+ NS_ASSERTION((aBuffer && aLength != 0) || (!aBuffer && aLength == 0), "?");
+ NS_ASSERTION(mInternalState != NS_OK ||
+ (aIsFinal == ChunkOrBufferIsFinal::FinalChunkAndBuffer) ||
+ aBuffer,
+ "Useless call, we won't call Expat");
+ MOZ_ASSERT(!BlockedOrInterrupted() || !aBuffer,
+ "Non-null buffer when resuming");
+ MOZ_ASSERT(mExpatParser);
+
+ auto parserBytesBefore_verifier = [&](auto parserBytesBefore) {
+ MOZ_RELEASE_ASSERT(parserBytesBefore >= 0, "Unexpected value");
+ MOZ_RELEASE_ASSERT(parserBytesBefore % sizeof(char16_t) == 0,
+ "Consumed part of a char16_t?");
+ return parserBytesBefore;
+ };
+ int32_t parserBytesBefore = RLBOX_EXPAT_SAFE_MCALL(
+ XML_GetCurrentByteIndex, parserBytesBefore_verifier);
+
+ if (mInternalState != NS_OK && !BlockedOrInterrupted()) {
+ return;
+ }
+
+ XML_Status status;
+ bool inParser = mInParser; // Save in-parser status
+ mInParser = true;
+ Maybe<TransferBuffer<char16_t>> buffer;
+ if (BlockedOrInterrupted()) {
+ mInternalState = NS_OK; // Resume in case we're blocked.
+ status = RLBOX_EXPAT_SAFE_MCALL(MOZ_XML_ResumeParser, status_verifier);
+ } else {
+ buffer.emplace(Sandbox(), aBuffer, aLength);
+ MOZ_RELEASE_ASSERT(!aBuffer || !!*buffer.ref(),
+ "Chunking should avoid OOM in ParseBuffer");
+
+ status = RLBOX_EXPAT_SAFE_MCALL(
+ MOZ_XML_Parse, status_verifier,
+ rlbox::sandbox_reinterpret_cast<const char*>(*buffer.ref()),
+ aLength * sizeof(char16_t),
+ aIsFinal == ChunkOrBufferIsFinal::FinalChunkAndBuffer);
+ }
+ mInParser = inParser; // Restore in-parser status
+
+ auto parserBytesConsumed_verifier = [&](auto parserBytesConsumed) {
+ MOZ_RELEASE_ASSERT(parserBytesConsumed >= 0, "Unexpected value");
+ MOZ_RELEASE_ASSERT(parserBytesConsumed >= parserBytesBefore,
+ "How'd this happen?");
+ MOZ_RELEASE_ASSERT(parserBytesConsumed % sizeof(char16_t) == 0,
+ "Consumed part of a char16_t?");
+ return parserBytesConsumed;
+ };
+ int32_t parserBytesConsumed = RLBOX_EXPAT_SAFE_MCALL(
+ XML_GetCurrentByteIndex, parserBytesConsumed_verifier);
+
+ // Consumed something.
+ *aConsumed += (parserBytesConsumed - parserBytesBefore) / sizeof(char16_t);
+
+ NS_ASSERTION(status != XML_STATUS_SUSPENDED || BlockedOrInterrupted(),
+ "Inconsistent expat suspension state.");
+
+ if (status == XML_STATUS_ERROR) {
+ mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
+ }
+
+ if (*aConsumed > 0 &&
+ (aIsFinal != ChunkOrBufferIsFinal::None || NS_FAILED(mInternalState))) {
+ *aLastLineLength = RLBOX_EXPAT_SAFE_MCALL(MOZ_XML_GetCurrentColumnNumber,
+ safe_unverified<XML_Size>);
+ }
+}
+
+nsresult nsExpatDriver::ResumeParse(nsScanner& aScanner, bool aIsFinalChunk) {
+ // 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 || (aIsFinalChunk && !mMadeFinalCallToExpat) ||
+ (BlockedOrInterrupted() && mExpatBuffered > 0)) {
+ bool noMoreBuffers = start == end && aIsFinalChunk;
+ 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 passedToExpat;
+ uint32_t consumed;
+ XML_Size lastLineLength;
+ ChunkAndParseBuffer(buffer, length, noMoreBuffers, &passedToExpat,
+ &consumed, &lastLineLength);
+ MOZ_ASSERT_IF(passedToExpat != length, NS_FAILED(mInternalState));
+ MOZ_ASSERT(consumed <= passedToExpat + mExpatBuffered);
+ 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).
+
+ 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 += passedToExpat - 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 (RLBOX_EXPAT_SAFE_MCALL(MOZ_XML_GetErrorCode, error_verifier) !=
+ 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;
+}
+
+mozilla::UniquePtr<mozilla::RLBoxSandboxDataBase>
+RLBoxExpatSandboxPool::CreateSandboxData(uint64_t aSize) {
+ // Create expat sandbox
+ auto sandbox = mozilla::MakeUnique<rlbox_sandbox_expat>();
+
+#ifdef MOZ_WASM_SANDBOXING_EXPAT
+ const w2c_mem_capacity capacity =
+ get_valid_wasm2c_memory_capacity(aSize, true /* 32-bit wasm memory*/);
+ bool create_ok = sandbox->create_sandbox(/* infallible = */ false, &capacity);
+#else
+ bool create_ok = sandbox->create_sandbox();
+#endif
+
+ NS_ENSURE_TRUE(create_ok, nullptr);
+
+ mozilla::UniquePtr<RLBoxExpatSandboxData> sbxData =
+ mozilla::MakeUnique<RLBoxExpatSandboxData>(aSize);
+
+ // Register callbacks common to both system and non-system principals
+ sbxData->mHandleXMLDeclaration =
+ sandbox->register_callback(Driver_HandleXMLDeclaration);
+ sbxData->mHandleCharacterData =
+ sandbox->register_callback(Driver_HandleCharacterData);
+ sbxData->mHandleProcessingInstruction =
+ sandbox->register_callback(Driver_HandleProcessingInstruction);
+ sbxData->mHandleDefault = sandbox->register_callback(Driver_HandleDefault);
+ sbxData->mHandleExternalEntityRef =
+ sandbox->register_callback(Driver_HandleExternalEntityRef);
+ sbxData->mHandleComment = sandbox->register_callback(Driver_HandleComment);
+ sbxData->mHandleStartCdataSection =
+ sandbox->register_callback(Driver_HandleStartCdataSection);
+ sbxData->mHandleEndCdataSection =
+ sandbox->register_callback(Driver_HandleEndCdataSection);
+ sbxData->mHandleStartDoctypeDecl =
+ sandbox->register_callback(Driver_HandleStartDoctypeDecl);
+ sbxData->mHandleEndDoctypeDecl =
+ sandbox->register_callback(Driver_HandleEndDoctypeDecl);
+
+ sbxData->mSandbox = std::move(sandbox);
+
+ return sbxData;
+}
+
+mozilla::StaticRefPtr<RLBoxExpatSandboxPool> RLBoxExpatSandboxPool::sSingleton;
+
+void RLBoxExpatSandboxPool::Initialize(size_t aDelaySeconds) {
+ mozilla::AssertIsOnMainThread();
+ RLBoxExpatSandboxPool::sSingleton = new RLBoxExpatSandboxPool(aDelaySeconds);
+ ClearOnShutdown(&RLBoxExpatSandboxPool::sSingleton);
+}
+
+void RLBoxExpatSandboxData::AttachDriver(bool aIsSystemPrincipal,
+ void* aDriver) {
+ MOZ_ASSERT(!mSandbox->sandbox_storage);
+ MOZ_ASSERT(mHandleStartElement.is_unregistered());
+ MOZ_ASSERT(mHandleEndElement.is_unregistered());
+
+ if (aIsSystemPrincipal) {
+ mHandleStartElement = mSandbox->register_callback(
+ nsExpatDriver::HandleStartElementForSystemPrincipal);
+ mHandleEndElement = mSandbox->register_callback(
+ nsExpatDriver::HandleEndElementForSystemPrincipal);
+ } else {
+ mHandleStartElement =
+ mSandbox->register_callback(nsExpatDriver::HandleStartElement);
+ mHandleEndElement =
+ mSandbox->register_callback(nsExpatDriver::HandleEndElement);
+ }
+
+ mSandbox->sandbox_storage = aDriver;
+}
+
+void RLBoxExpatSandboxData::DetachDriver() {
+ mSandbox->sandbox_storage = nullptr;
+ mHandleStartElement.unregister();
+ mHandleEndElement.unregister();
+}
+
+RLBoxExpatSandboxData::~RLBoxExpatSandboxData() {
+ MOZ_ASSERT(mSandbox);
+
+ // DetachDriver should always be called before a sandbox goes back into the
+ // pool, and thus before it's freed.
+ MOZ_ASSERT(!mSandbox->sandbox_storage);
+ MOZ_ASSERT(mHandleStartElement.is_unregistered());
+ MOZ_ASSERT(mHandleEndElement.is_unregistered());
+
+ // Unregister callbacks
+ mHandleXMLDeclaration.unregister();
+ mHandleCharacterData.unregister();
+ mHandleProcessingInstruction.unregister();
+ mHandleDefault.unregister();
+ mHandleExternalEntityRef.unregister();
+ mHandleComment.unregister();
+ mHandleStartCdataSection.unregister();
+ mHandleEndCdataSection.unregister();
+ mHandleStartDoctypeDecl.unregister();
+ mHandleEndDoctypeDecl.unregister();
+ // Destroy sandbox
+ mSandbox->destroy_sandbox();
+ MOZ_COUNT_DTOR(RLBoxExpatSandboxData);
+}
+
+nsresult nsExpatDriver::Initialize(nsIURI* aURI, 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 char16_t kExpatSeparator[] = {kExpatSeparatorChar, '\0'};
+
+ // Get the doc if any
+ 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();
+ }
+ }
+
+ // Create sandbox
+ //
+ // We have to make sure the sandbox is large enough. We unscientifically
+ // request two MB. Note that the parsing itself is chunked so as not to
+ // require a large sandbox.
+ static const uint64_t minSandboxSize = 2 * 1024 * 1024;
+ MOZ_ASSERT(!mSandboxPoolData);
+ mSandboxPoolData =
+ RLBoxExpatSandboxPool::sSingleton->PopOrCreate(minSandboxSize);
+ NS_ENSURE_TRUE(mSandboxPoolData, NS_ERROR_OUT_OF_MEMORY);
+
+ MOZ_ASSERT(SandboxData());
+
+ SandboxData()->AttachDriver(doc && doc->NodePrincipal()->IsSystemPrincipal(),
+ static_cast<void*>(this));
+
+ // Create expat parser.
+ // We need to copy the encoding and namespace separator into the sandbox.
+ // For the noop sandbox we pass in the memsuite; for the Wasm sandbox, we
+ // pass in nullptr to let expat use the standard library memory suite.
+ auto expatSeparator = TransferBuffer<char16_t>(
+ Sandbox(), kExpatSeparator,
+ nsCharTraits<char16_t>::length(kExpatSeparator) + 1);
+ MOZ_RELEASE_ASSERT(*expatSeparator);
+ auto utf16 = TransferBuffer<char16_t>(
+ Sandbox(), kUTF16, nsCharTraits<char16_t>::length(kUTF16) + 1);
+ MOZ_RELEASE_ASSERT(*utf16);
+ mExpatParser = Sandbox()->invoke_sandbox_function(
+ MOZ_XML_ParserCreate_MM, *utf16, nullptr, *expatSeparator);
+ NS_ENSURE_TRUE(mExpatParser, NS_ERROR_FAILURE);
+
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetReturnNSTriplet, XML_TRUE);
+
+#ifdef XML_DTD
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetParamEntityParsing,
+ XML_PARAM_ENTITY_PARSING_ALWAYS);
+#endif
+
+ auto baseURI = GetExpatBaseURI(aURI);
+ auto uri =
+ TransferBuffer<XML_Char>(Sandbox(), &baseURI[0], ArrayLength(baseURI));
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetBase, *uri);
+
+ // Set up the callbacks
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetXmlDeclHandler,
+ SandboxData()->mHandleXMLDeclaration);
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetElementHandler,
+ SandboxData()->mHandleStartElement,
+ SandboxData()->mHandleEndElement);
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetCharacterDataHandler,
+ SandboxData()->mHandleCharacterData);
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetProcessingInstructionHandler,
+ SandboxData()->mHandleProcessingInstruction);
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetDefaultHandlerExpand,
+ SandboxData()->mHandleDefault);
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetExternalEntityRefHandler,
+ SandboxData()->mHandleExternalEntityRef);
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetCommentHandler, SandboxData()->mHandleComment);
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetCdataSectionHandler,
+ SandboxData()->mHandleStartCdataSection,
+ SandboxData()->mHandleEndCdataSection);
+
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetParamEntityParsing,
+ XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
+ RLBOX_EXPAT_MCALL(MOZ_XML_SetDoctypeDeclHandler,
+ SandboxData()->mHandleStartDoctypeDecl,
+ SandboxData()->mHandleEndDoctypeDecl);
+
+ return mInternalState;
+}
+
+NS_IMETHODIMP
+nsExpatDriver::BuildModel(nsIContentSink* aSink) { return mInternalState; }
+
+void nsExpatDriver::DidBuildModel() {
+ if (!mInParser) {
+ // Because nsExpatDriver is cycle-collected, it gets destroyed
+ // asynchronously. We want to eagerly release the sandbox back into the
+ // pool so that it can be reused immediately, unless this is a reentrant
+ // call (which we track with mInParser).
+ Destroy();
+ }
+ mOriginalSink = nullptr;
+ mSink = nullptr;
+}
+
+NS_IMETHODIMP_(void)
+nsExpatDriver::Terminate() {
+ // XXX - not sure what happens to the unparsed data.
+ if (mExpatParser) {
+ RLBOX_EXPAT_MCALL(MOZ_XML_StopParser, XML_FALSE);
+ }
+ mInternalState = NS_ERROR_HTMLPARSER_STOPPARSING;
+}
+
+/*************************** Unused methods **********************************/
+
+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).
+
+ // Note that due to Bug 1742913, we need to explicitly cast the parameter to
+ // an int so that the value is correctly zero extended.
+ int resumable = BlockedOrInterrupted();
+ RLBOX_EXPAT_MCALL(MOZ_XML_StopParser, resumable);
+ } else if (NS_SUCCEEDED(mInternalState)) {
+ // Only clobber mInternalState with the success code if we didn't block or
+ // interrupt before.
+ mInternalState = aState;
+ }
+}
+
+nsExpatDriver::ExpatBaseURI nsExpatDriver::GetExpatBaseURI(nsIURI* aURI) {
+ mURIs.AppendElement(aURI);
+
+ MOZ_RELEASE_ASSERT(mURIs.Length() <= std::numeric_limits<XML_Char>::max());
+
+ return ExpatBaseURI(static_cast<XML_Char>(mURIs.Length()), XML_T('\0'));
+}
+
+nsIURI* nsExpatDriver::GetBaseURI(const XML_Char* aBase) const {
+ MOZ_ASSERT(aBase[0] != '\0' && aBase[1] == '\0');
+
+ if (aBase[0] == '\0' || aBase[1] != '\0') {
+ return nullptr;
+ }
+
+ uint32_t index = aBase[0] - 1;
+ MOZ_ASSERT(index < mURIs.Length());
+
+ return mURIs.SafeElementAt(index);
+}
+
+inline RLBoxExpatSandboxData* nsExpatDriver::SandboxData() const {
+ return reinterpret_cast<RLBoxExpatSandboxData*>(
+ mSandboxPoolData->SandboxData());
+}
+
+inline rlbox_sandbox_expat* nsExpatDriver::Sandbox() const {
+ return SandboxData()->Sandbox();
+}
diff --git a/parser/htmlparser/nsExpatDriver.h b/parser/htmlparser/nsExpatDriver.h
new file mode 100644
index 0000000000..b07ba72b6b
--- /dev/null
+++ b/parser/htmlparser/nsExpatDriver.h
@@ -0,0 +1,256 @@
+/* -*- 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 "nsIInputStream.h"
+#include "nsIParser.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsScanner.h"
+
+#include "rlbox_expat.h"
+#include "nsRLBoxExpatDriver.h"
+#include "mozilla/UniquePtr.h"
+
+class nsIExpatSink;
+struct nsCatalogData;
+class RLBoxExpatSandboxData;
+namespace mozilla {
+template <typename, size_t>
+class Array;
+}
+
+class nsExpatDriver : public nsIDTD {
+ virtual ~nsExpatDriver();
+
+ public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL
+ NS_DECL_NSIDTD
+ NS_DECL_CYCLE_COLLECTION_CLASS(nsExpatDriver)
+
+ nsExpatDriver();
+
+ nsresult Initialize(nsIURI* aURI, nsIContentSink* aSink);
+
+ nsresult ResumeParse(nsScanner& aScanner, bool aIsFinalChunk);
+
+ int HandleExternalEntityRef(const char16_t* aOpenEntityNames,
+ const char16_t* aBase, const char16_t* aSystemId,
+ const char16_t* aPublicId);
+ static void HandleStartElement(rlbox_sandbox_expat& aSandbox,
+ tainted_expat<void*> aUserData,
+ tainted_expat<const char16_t*> aName,
+ tainted_expat<const char16_t**> aAtts);
+ static void HandleStartElementForSystemPrincipal(
+ rlbox_sandbox_expat& aSandbox, tainted_expat<void*> aUserData,
+ tainted_expat<const char16_t*> aName,
+ tainted_expat<const char16_t**> aAtts);
+ static void HandleEndElement(rlbox_sandbox_expat& aSandbox,
+ tainted_expat<void*> aUserData,
+ tainted_expat<const char16_t*> aName);
+ static void HandleEndElementForSystemPrincipal(
+ rlbox_sandbox_expat& aSandbox, tainted_expat<void*> aUserData,
+ tainted_expat<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,
+ nsIURI* aBaseURI,
+ nsIInputStream** aStream,
+ nsIURI** aAbsURI);
+
+ enum class ChunkOrBufferIsFinal {
+ None,
+ FinalChunk,
+ FinalChunkAndBuffer,
+ };
+
+ /**
+ * 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 this is the last chunk in a row passed to
+ * ParseChunk, and if so whether it's the last chunk and
+ * buffer passed to ParseChunk (meaning there will be no more
+ * calls to ParseChunk for the document being parsed).
+ * @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.
+ * @param aLastLineLength [out] the length of the last line that Expat has
+ * consumed. This will only be computed if
+ * aIsFinal is not None or mInternalState is set
+ * to a failure.
+ */
+ void ParseChunk(const char16_t* aBuffer, uint32_t aLength,
+ ChunkOrBufferIsFinal aIsFinal, uint32_t* aConsumed,
+ XML_Size* aLastLineLength);
+ /**
+ * Wrapper for ParseBuffer. If the buffer is too large to be copied into the
+ * sandbox all at once, splits it into chunks and invokes ParseBuffer in a
+ * loop.
+ *
+ * @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.
+ * @param aLastLineLength [out] the length of the last line that Expat has
+ * consumed.
+ */
+ void ChunkAndParseBuffer(const char16_t* aBuffer, uint32_t aLength,
+ bool aIsFinal, uint32_t* aPassedToExpat,
+ uint32_t* aConsumed, XML_Size* aLastLineLength);
+
+ nsresult HandleError();
+
+ void MaybeStopParser(nsresult aState);
+
+ bool BlockedOrInterrupted() {
+ return mInternalState == NS_ERROR_HTMLPARSER_BLOCK ||
+ mInternalState == NS_ERROR_HTMLPARSER_INTERRUPTED;
+ }
+
+ // Expat allows us to set the base URI for entities. It doesn't use the base
+ // URI itself, but just passes it along to all the entity handlers (just the
+ // external entity reference handler for us). It does expect the base URI as a
+ // null-terminated string, with the same character type as the parsed buffers
+ // (char16_t in our case). Because nsIURI stores a UTF-8 string we have to do
+ // a conversion to UTF-16 for Expat. We also RLBox the Expat parser, so we
+ // also do 2 copies (into RLBox sandbox, and Expat does a copy into its pool).
+ // Most of the time this base URI is unused (the external entity handler is
+ // rarely called), but when it is we also convert it back to a nsIURI, so we
+ // convert the string back to UTF-8.
+ //
+ // We'd rather not do any of these conversions and copies, so we use a (hacky)
+ // workaround. We store all base URIs in an array of nsIURIs. Instead of
+ // passing the real URI to Expat as a string, we pass it a null-terminated
+ // 2-character buffer. The first character of that buffer stores the index of
+ // the corresponding nsIURI in the array (incremented with 1 because 0 is used
+ // to terminate a string). The entity handler can then use the index from the
+ // base URI that Expat passes it to look up the right nsIURI from the array.
+ //
+ // GetExpatBaseURI pushes the nsIURI to the array, and creates the
+ // two-character buffer for it.
+ //
+ // GetBaseURI looks up the right nsIURI in the array, based on the index from
+ // the two-character buffer.
+ using ExpatBaseURI = mozilla::Array<XML_Char, 2>;
+ ExpatBaseURI GetExpatBaseURI(nsIURI* aURI);
+ nsIURI* GetBaseURI(const XML_Char* aBase) const;
+
+ RLBoxExpatSandboxData* SandboxData() const;
+ rlbox_sandbox_expat* Sandbox() const;
+
+ // Destroy expat parser and return sandbox to pool
+ void Destroy();
+
+ mozilla::UniquePtr<mozilla::RLBoxSandboxPoolData> mSandboxPoolData;
+ tainted_expat<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;
+
+ // Used to track if we're in the parser.
+ bool mInParser;
+
+ 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
+ nsTArray<nsCOMPtr<nsIURI>> mURIs;
+
+ // Used for error reporting.
+ uint64_t mInnerWindowID;
+};
+
+class RLBoxExpatSandboxData : public mozilla::RLBoxSandboxDataBase {
+ friend class RLBoxExpatSandboxPool;
+ friend class nsExpatDriver;
+
+ public:
+ explicit RLBoxExpatSandboxData(uint64_t aSize)
+ : mozilla::RLBoxSandboxDataBase(aSize) {
+ MOZ_COUNT_CTOR(RLBoxExpatSandboxData);
+ }
+ ~RLBoxExpatSandboxData();
+ rlbox_sandbox_expat* Sandbox() const { return mSandbox.get(); }
+ // After getting a sandbox from the pool we need to register the
+ // Handle{Start,End}Element callbacks and associate the driver with the
+ // sandbox.
+ void AttachDriver(bool IsSystemPrincipal, void* aDriver);
+ void DetachDriver();
+
+ private:
+ mozilla::UniquePtr<rlbox_sandbox_expat> mSandbox;
+ // Common expat callbacks that persist across calls to {Attach,Detach}Driver,
+ // and consequently across sandbox reuses.
+ sandbox_callback_expat<XML_XmlDeclHandler> mHandleXMLDeclaration;
+ sandbox_callback_expat<XML_CharacterDataHandler> mHandleCharacterData;
+ sandbox_callback_expat<XML_ProcessingInstructionHandler>
+ mHandleProcessingInstruction;
+ sandbox_callback_expat<XML_DefaultHandler> mHandleDefault;
+ sandbox_callback_expat<XML_ExternalEntityRefHandler> mHandleExternalEntityRef;
+ sandbox_callback_expat<XML_CommentHandler> mHandleComment;
+ sandbox_callback_expat<XML_StartCdataSectionHandler> mHandleStartCdataSection;
+ sandbox_callback_expat<XML_EndCdataSectionHandler> mHandleEndCdataSection;
+ sandbox_callback_expat<XML_StartDoctypeDeclHandler> mHandleStartDoctypeDecl;
+ sandbox_callback_expat<XML_EndDoctypeDeclHandler> mHandleEndDoctypeDecl;
+ // Expat callbacks specific to each driver, and thus (re)set across sandbox
+ // reuses.
+ sandbox_callback_expat<XML_StartElementHandler> mHandleStartElement;
+ sandbox_callback_expat<XML_EndElementHandler> mHandleEndElement;
+};
+
+#endif
diff --git a/parser/htmlparser/nsHTMLTagList.h b/parser/htmlparser/nsHTMLTagList.h
new file mode 100644
index 0000000000..b64dea4854
--- /dev/null
+++ b/parser/htmlparser/nsHTMLTagList.h
@@ -0,0 +1,198 @@
+/* -*- 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(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..ec3c4f322d
--- /dev/null
+++ b/parser/htmlparser/nsHTMLTags.cpp
@@ -0,0 +1,167 @@
+/* -*- 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 "nsElementTable.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->InsertOrUpdate(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->InsertOrUpdate(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);
+
+ CheckElementTable();
+ TestTagTable();
+#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..eb7e3aaa25
--- /dev/null
+++ b/parser/htmlparser/nsHTMLTags.h
@@ -0,0 +1,80 @@
+/* -*- 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 "nsAtom.h"
+#include "nsString.h"
+#include "nsTHashMap.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 = nsTHashMap<nsStringHashKey, nsHTMLTag>;
+ using TagAtomHash = nsTHashMap<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");
+
+ return gTagTable->MaybeGet(aTagName).valueOr(eHTMLTag_userdefined);
+ }
+ static nsHTMLTag CaseSensitiveAtomTagToId(nsAtom* aTagName) {
+ NS_ASSERTION(gTagAtomTable, "no lookup table, needs addref");
+ NS_ASSERTION(aTagName, "null tagname!");
+
+ return gTagAtomTable->MaybeGet(aTagName).valueOr(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/nsIContentSink.h b/parser/htmlparser/nsIContentSink.h
new file mode 100644
index 0000000000..aa77c192c7
--- /dev/null
+++ b/parser/htmlparser/nsIContentSink.h
@@ -0,0 +1,143 @@
+/* -*- 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.
+ */
+ virtual void WillResume() = 0;
+
+ /**
+ * This method returns nullptr unless `this` can
+ * be cast as nsHtml5TreeOpExecutor.
+ */
+ virtual nsIContentSink* AsExecutor() { return nullptr; }
+
+ /**
+ * 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..67f7af4ec2
--- /dev/null
+++ b/parser/htmlparser/nsIDTD.h
@@ -0,0 +1,88 @@
+/* -*- 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"
+
+#define NS_IDTD_IID \
+ { \
+ 0x3de05873, 0xefa7, 0x410d, { \
+ 0xa4, 0x61, 0x80, 0x33, 0xaf, 0xd9, 0xe3, 0x26 \
+ } \
+ }
+
+enum eAutoDetectResult {
+ eUnknownDetect,
+ ePrimaryDetect,
+};
+
+enum nsDTDMode {
+ eDTDMode_quirks, // pre 4.0 versions
+ eDTDMode_full_standards,
+ eDTDMode_autodetect
+};
+
+class nsIContentSink;
+class CParserContext;
+
+class nsIDTD : public nsISupports {
+ public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDTD_IID)
+
+ /**
+ * Called by the parser after the parsing process has concluded
+ */
+ virtual void DidBuildModel() = 0;
+
+ /**
+ * Called (possibly repeatedly) by the parser to parse tokens and construct
+ * the document model via the sink provided to WillBuildModel.
+ *
+ * @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(nsIContentSink* aSink) = 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_DEFINE_STATIC_IID_ACCESSOR(nsIDTD, NS_IDTD_IID)
+
+#define NS_DECL_NSIDTD \
+ void DidBuildModel() override; \
+ NS_IMETHOD BuildModel(nsIContentSink* aSink) override; \
+ NS_IMETHOD_(void) Terminate() 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..351963cfa3
--- /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 nsParser::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..3e81d5d770
--- /dev/null
+++ b/parser/htmlparser/nsIHTMLContentSink.h
@@ -0,0 +1,96 @@
+/* -*- 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;
+
+ /**
+ * This method returns true if there are more than one
+ * pending style sheets, false otherwise.
+ */
+ virtual bool WaitForPendingSheets() = 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..8cf3940ffb
--- /dev/null
+++ b/parser/htmlparser/nsIParser.h
@@ -0,0 +1,186 @@
+/* -*- 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 { eUnknown = 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
+ * @param aForceAutoDetection- whether Repair Text Encoding menu item was
+ * invoked
+ * @return nada
+ */
+ virtual void SetDocumentCharset(NotNull<const Encoding*> aCharset,
+ int32_t aSource,
+ bool aForceAutoDetection = false) = 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) = 0;
+
+ NS_IMETHOD Terminate(void) = 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;
+
+ /**
+ * True if this is a script-created HTML5 parser.
+ */
+ virtual bool IsScriptCreated() = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIParser, NS_IPARSER_IID)
+
+#endif
diff --git a/parser/htmlparser/nsParser.cpp b/parser/htmlparser/nsParser.cpp
new file mode 100644
index 0000000000..04d02e2084
--- /dev/null
+++ b/parser/htmlparser/nsParser.cpp
@@ -0,0 +1,1075 @@
+/* -*- 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 "nsReadableUtils.h"
+#include "nsCOMPtr.h"
+#include "nsExpatDriver.h"
+#include "nsIFragmentContentSink.h"
+#include "nsStreamUtils.h"
+#include "nsXPCOMCIDInternal.h"
+#include "nsMimeTypes.h"
+#include "nsCharsetSource.h"
+#include "nsThreadUtils.h"
+#include "nsIHTMLContentSink.h"
+
+#include "mozilla/BinarySearch.h"
+#include "mozilla/CondVar.h"
+#include "mozilla/dom/ScriptLoader.h"
+#include "mozilla/Encoding.h"
+#include "mozilla/Mutex.h"
+
+using namespace mozilla;
+
+#define NS_PARSER_FLAG_PENDING_CONTINUE_EVENT 0x00000001
+#define NS_PARSER_FLAG_CAN_TOKENIZE 0x00000002
+
+//-------------- 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() : mCharset(WINDOWS_1252_ENCODING) { Initialize(); }
+
+nsParser::~nsParser() { Cleanup(); }
+
+void nsParser::Initialize() {
+ mContinueEvent = nullptr;
+ mCharsetSource = kCharsetUninitialized;
+ mCharset = WINDOWS_1252_ENCODING;
+ mInternalState = NS_OK;
+ mStreamStatus = NS_OK;
+ mCommand = eViewNormal;
+ mBlocked = 0;
+ mFlags = NS_PARSER_FLAG_CAN_TOKENIZE;
+
+ mProcessingNetworkData = false;
+ mIsAboutBlank = false;
+}
+
+void nsParser::Cleanup() {
+ // 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_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_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,
+ bool aForceAutoDetection) {
+ mCharset = aCharset;
+ mCharsetSource = aCharsetSource;
+ if (mParserContext) {
+ 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; }
+
+////////////////////////////////////////////////////////////////////////
+
+/**
+ * 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() {
+ if (!mParserContext) return NS_ERROR_HTMLPARSER_INVALIDPARSERCONTEXT;
+
+ if (mInternalState == NS_ERROR_OUT_OF_MEMORY) {
+ // Checking NS_ERROR_OUT_OF_MEMORY instead of NS_FAILED
+ // to avoid introducing unintentional changes to behavior.
+ return mInternalState;
+ }
+
+ if (eUnknownDetect != mParserContext->mAutoDetectStatus) return NS_OK;
+
+ if (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
+
+ // We always find a DTD.
+ mParserContext->mAutoDetectStatus = ePrimaryDetect;
+
+ // Quick check for view source.
+ MOZ_ASSERT(mParserContext->mParserCommand != eViewSource,
+ "The old parser is not supposed to be used for View Source "
+ "anymore.");
+
+ // Now see if we're parsing XML or HTML (which, as far as we're concerned,
+ // simply means "not XML").
+ if (mParserContext->mDocType == eXML) {
+ RefPtr<nsExpatDriver> expat = new nsExpatDriver();
+ nsresult rv = expat->Initialize(mParserContext->mScanner.GetURI(), mSink);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mDTD = expat.forget();
+ } else {
+ mDTD = new CNavDTD();
+ }
+
+ return mSink->WillBuildModel(mParserContext->mDTDMode);
+}
+
+/**
+ * This gets called when the parser is done with its input.
+ */
+void nsParser::DidBuildModel() {
+ if (IsComplete() && mParserContext) {
+ // 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) {
+ mDTD->DidBuildModel();
+ mSink->DidBuildModel(terminated);
+ }
+
+ // Ref. to bug 61462.
+ mParserContext->mRequest = nullptr;
+ }
+}
+
+/**
+ * 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;
+
+ // @see bug 108049
+ // If NS_PARSER_FLAG_PENDING_CONTINUE_EVENT is set then reset it so
+ // DidBuildModel will call DidBuildModel on the DTD. Note: The IsComplete()
+ // call inside of DidBuildModel looks at the pendingContinueEvents flag.
+ 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;
+ }
+
+ if (mDTD) {
+ mDTD->Terminate();
+ DidBuildModel();
+ } 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 (mInternalState == NS_ERROR_OUT_OF_MEMORY) {
+ // Checking NS_ERROR_OUT_OF_MEMORY instead of NS_FAILED
+ // to avoid introducing unintentional changes to behavior.
+ return mInternalState;
+ }
+
+ // 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; }
+
+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) {
+ MOZ_ASSERT(aURL, "Error: Null URL given");
+
+ if (mInternalState == NS_ERROR_OUT_OF_MEMORY) {
+ // Checking NS_ERROR_OUT_OF_MEMORY instead of NS_FAILED
+ // to avoid introducing unintentional changes to behavior.
+ return mInternalState;
+ }
+
+ if (!aURL) {
+ return NS_ERROR_HTMLPARSER_BADURL;
+ }
+
+ MOZ_ASSERT(!mParserContext, "We expect mParserContext to be null.");
+
+ mParserContext = MakeUnique<CParserContext>(aURL, mCommand);
+
+ return NS_OK;
+}
+
+/**
+ * Used by XML fragment parsing below.
+ *
+ * @param aSourceBuffer contains a string-full of real content
+ */
+nsresult nsParser::Parse(const nsAString& aSourceBuffer, bool aLastCall) {
+ if (mInternalState == NS_ERROR_OUT_OF_MEMORY) {
+ // Checking NS_ERROR_OUT_OF_MEMORY instead of NS_FAILED
+ // to avoid introducing unintentional changes to behavior.
+ return mInternalState;
+ }
+
+ // Don't bother if we're never going to parse this.
+ if (mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING) {
+ return NS_OK;
+ }
+
+ 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 NS_OK;
+ }
+
+ // Maintain a reference to ourselves so we don't go away
+ // till we're completely done.
+ nsCOMPtr<nsIParser> kungFuDeathGrip(this);
+
+ if (!mParserContext) {
+ // Only make a new context if we don't have one.
+ mParserContext =
+ MakeUnique<CParserContext>(mUnusedInput, mCommand, aLastCall);
+
+ mUnusedInput.Truncate();
+ } else if (aLastCall) {
+ // Set stream listener state to eOnStop, on the final context - Fix
+ // 68160, to guarantee DidBuildModel() call - Fix 36148
+ mParserContext->mStreamListenerState = eOnStop;
+ mParserContext->mScanner.SetIncremental(false);
+ }
+
+ mParserContext->mScanner.Append(aSourceBuffer);
+ return ResumeParse(false, false, false);
+}
+
+nsresult nsParser::ParseFragment(const nsAString& aSourceBuffer,
+ nsTArray<nsString>& aTagStack) {
+ if (mInternalState == NS_ERROR_OUT_OF_MEMORY) {
+ // Checking NS_ERROR_OUT_OF_MEMORY instead of NS_FAILED
+ // to avoid introducing unintentional changes to behavior.
+ return mInternalState;
+ }
+
+ nsresult result = NS_OK;
+ nsAutoString theContext;
+ uint32_t theCount = aTagStack.Length();
+ uint32_t theIndex = 0;
+
+ 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, false);
+ if (NS_FAILED(result)) {
+ 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, 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, 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, true);
+ }
+ }
+
+ mParserContext.reset();
+
+ 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) {
+ if (mInternalState == NS_ERROR_OUT_OF_MEMORY) {
+ // Checking NS_ERROR_OUT_OF_MEMORY instead of NS_FAILED
+ // to avoid introducing unintentional changes to behavior.
+ return mInternalState;
+ }
+
+ nsresult result = NS_OK;
+
+ if (!mBlocked && mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
+ result = WillBuildModel();
+ 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()) {
+ // -- 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;
+ if (mFlags & NS_PARSER_FLAG_CAN_TOKENIZE) {
+ mParserContext->mScanner.Mark();
+ if (mParserContext->mDocType == eXML &&
+ mParserContext->mParserCommand != eViewSource) {
+ nsExpatDriver* expat = static_cast<nsExpatDriver*>(mDTD.get());
+ theTokenizerResult =
+ expat->ResumeParse(mParserContext->mScanner, aIsFinalChunk);
+ if (NS_FAILED(theTokenizerResult)) {
+ mParserContext->mScanner.RewindToMark();
+ if (NS_ERROR_HTMLPARSER_STOPPARSING == theTokenizerResult) {
+ theTokenizerResult = Terminate();
+ mSink = nullptr;
+ }
+ }
+ } else {
+ // Nothing to do for non-XML. Note that this should only be
+ // about:blank at this point, we're also checking for view-source
+ // above, but that shouldn't end up here anymore.
+ theTokenizerResult = NS_ERROR_HTMLPARSER_EOF;
+ }
+ } else {
+ theTokenizerResult = NS_OK;
+ }
+
+ result = mDTD->BuildModel(mSink);
+ 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 the parser has been blocked, 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();
+ return NS_OK;
+ }
+ if (NS_ERROR_HTMLPARSER_STOPPARSING == result) {
+ // Note: Parser Terminate() calls DidBuildModel.
+ if (mInternalState != NS_ERROR_HTMLPARSER_STOPPARSING) {
+ DidBuildModel();
+ mInternalState = result;
+ }
+
+ return NS_OK;
+ }
+ if (((NS_OK == result &&
+ theTokenizerResult == NS_ERROR_HTMLPARSER_EOF) ||
+ result == NS_ERROR_HTMLPARSER_INTERRUPTED) &&
+ mParserContext->mStreamListenerState == eOnStop) {
+ DidBuildModel();
+ return NS_OK;
+ }
+
+ 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;
+}
+
+/*******************************************************************
+ These methods are used to talk to the netlib system...
+ *******************************************************************/
+
+nsresult nsParser::OnStartRequest(nsIRequest* request) {
+ if (mInternalState == NS_ERROR_OUT_OF_MEMORY) {
+ // Checking NS_ERROR_OUT_OF_MEMORY instead of NS_FAILED
+ // to avoid introducing unintentional changes to behavior.
+ return mInternalState;
+ }
+
+ MOZ_ASSERT(eNone == mParserContext->mStreamListenerState,
+ "Parser's nsIStreamListener API was not setup "
+ "correctly in constructor.");
+
+ mParserContext->mStreamListenerState = eOnStart;
+ mParserContext->mAutoDetectStatus = eUnknownDetect;
+ mParserContext->mRequest = request;
+
+ 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 == 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 == 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;
+ std::tie(encoding, std::ignore) = Encoding::ForBOM(Span(buf, count));
+ 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, false);
+ 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) {
+ if (mInternalState == NS_ERROR_OUT_OF_MEMORY) {
+ // Checking NS_ERROR_OUT_OF_MEMORY instead of NS_FAILED
+ // to avoid introducing unintentional changes to behavior.
+ return mInternalState;
+ }
+
+ 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;
+ }
+
+ if (mParserContext->mRequest == request) {
+ mParserContext->mStreamListenerState = eOnDataAvail;
+
+ uint32_t totalRead;
+ ParserWriteStruct pws;
+ pws.mNeedCharsetCheck = true;
+ pws.mParser = this;
+ pws.mScanner = &mParserContext->mScanner;
+ 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) {
+ if (mInternalState == NS_ERROR_OUT_OF_MEMORY) {
+ // Checking NS_ERROR_OUT_OF_MEMORY instead of NS_FAILED
+ // to avoid introducing unintentional changes to behavior.
+ return mInternalState;
+ }
+
+ nsresult rv = NS_OK;
+
+ if (mParserContext->mRequest == request) {
+ mParserContext->mStreamListenerState = eOnStop;
+ mParserContext->mScanner.SetIncremental(false);
+ }
+
+ 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.
+
+ return rv;
+}
+
+/**
+ * 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..95782e954b
--- /dev/null
+++ b/parser/htmlparser/nsParser.h
@@ -0,0 +1,312 @@
+/* -*- 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 "nsHTMLTags.h"
+#include "nsIContentSink.h"
+#include "nsCOMArray.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsWeakReference.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/UniquePtr.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
+ * @param aChannelHadCharset- ignored
+ * @return nada
+ */
+ virtual void SetDocumentCharset(NotNull<const Encoding*> aCharset,
+ int32_t aSource,
+ bool aForceAutoDetection) override;
+
+ NotNull<const Encoding*> GetDocumentCharset(int32_t& aSource) {
+ aSource = mCharsetSource;
+ return mCharset;
+ }
+
+ /**
+ * Cause parser to parse input from given URL
+ */
+ NS_IMETHOD Parse(nsIURI* aURL) override;
+
+ /**
+ * This method gets called when you want to parse a fragment of XML surrounded
+ * by the context |aTagStack|. It requires that the parser have been given a
+ * fragment content sink.
+ *
+ * @param aSourceBuffer The XML that hasn't been parsed yet.
+ * @param aTagStack The context of the source buffer.
+ */
+ nsresult ParseFragment(const nsAString& aSourceBuffer,
+ nsTArray<nsString>& aTagStack);
+
+ 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 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
+
+ /**
+ * Get the nsIStreamListener for this parser
+ */
+ virtual nsIStreamListener* GetStreamListener() override;
+
+ void SetSinkCharset(NotNull<const Encoding*> aCharset);
+
+ /**
+ * Return true.
+ */
+ virtual bool IsInsertionPointDefined() override;
+
+ /**
+ * No-op.
+ */
+ void IncrementScriptNestingLevel() final;
+
+ /**
+ * No-op.
+ */
+ void DecrementScriptNestingLevel() final;
+
+ bool HasNonzeroScriptNestingLevel() const final;
+
+ /**
+ * Always false.
+ */
+ virtual bool IsScriptCreated() override;
+
+ /**
+ * 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*);
+
+ void Reset() {
+ Cleanup();
+ mUnusedInput.Truncate();
+ Initialize();
+ }
+
+ bool IsScriptExecuting() { return mSink && mSink->IsScriptExecuting(); }
+
+ bool IsOkToProcessNetworkData() {
+ return !IsScriptExecuting() && !mProcessingNetworkData;
+ }
+
+ // Returns Nothing() if we haven't determined yet what the parser is being
+ // used for. Else returns whether this parser is used for parsing XML.
+ mozilla::Maybe<bool> IsForParsingXML() {
+ if (!mParserContext || mParserContext->mDTDMode == eDTDMode_autodetect) {
+ return mozilla::Nothing();
+ }
+
+ return mozilla::Some(mParserContext->mDocType == eXML);
+ }
+
+ protected:
+ void Initialize();
+ void Cleanup();
+
+ /**
+ *
+ * @update gess5/18/98
+ * @param
+ * @return
+ */
+ nsresult WillBuildModel();
+
+ /**
+ * Called when parsing is done.
+ */
+ void DidBuildModel();
+
+ private:
+ /**
+ * Pushes XML fragment parsing data to expat without an input stream.
+ */
+ nsresult Parse(const nsAString& aSourceBuffer, bool aLastCall);
+
+ protected:
+ //*********************************************
+ // And now, some data members...
+ //*********************************************
+
+ mozilla::UniquePtr<CParserContext> mParserContext;
+ nsCOMPtr<nsIDTD> mDTD;
+ 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;
+};
+
+#endif
diff --git a/parser/htmlparser/nsParserBase.h b/parser/htmlparser/nsParserBase.h
new file mode 100644
index 0000000000..13c8883d4c
--- /dev/null
+++ b/parser/htmlparser/nsParserBase.h
@@ -0,0 +1,15 @@
+/* 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; }
+};
+
+#endif // nsParserBase_h_
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/nsParserMsgUtils.cpp b/parser/htmlparser/nsParserMsgUtils.cpp
new file mode 100644
index 0000000000..a629bcc5e3
--- /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/Components.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::components::StringBundle::Service();
+ 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/nsRLBoxExpatDriver.h b/parser/htmlparser/nsRLBoxExpatDriver.h
new file mode 100644
index 0000000000..84236f3365
--- /dev/null
+++ b/parser/htmlparser/nsRLBoxExpatDriver.h
@@ -0,0 +1,27 @@
+/* -*- 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_RLBOX_EXPAT_DRIVER__
+#define NS_RLBOX_EXPAT_DRIVER__
+
+#include "mozilla/RLBoxSandboxPool.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/UniquePtr.h"
+
+class RLBoxExpatSandboxPool : public mozilla::RLBoxSandboxPool {
+ public:
+ explicit RLBoxExpatSandboxPool(size_t aDelaySeconds)
+ : RLBoxSandboxPool(aDelaySeconds) {}
+
+ static mozilla::StaticRefPtr<RLBoxExpatSandboxPool> sSingleton;
+ static void Initialize(size_t aDelaySeconds = 10);
+
+ protected:
+ mozilla::UniquePtr<mozilla::RLBoxSandboxDataBase> CreateSandboxData(
+ uint64_t aSize) override;
+ ~RLBoxExpatSandboxPool() = default;
+};
+
+#endif
diff --git a/parser/htmlparser/nsScanner.cpp b/parser/htmlparser/nsScanner.cpp
new file mode 100644
index 0000000000..36a14e1083
--- /dev/null
+++ b/parser/htmlparser/nsScanner.cpp
@@ -0,0 +1,331 @@
+/* -*- 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 "mozilla/UniquePtr.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, bool aIncremental)
+ : mIncremental(aIncremental) {
+ MOZ_COUNT_CTOR(nsScanner);
+
+ AppendToBuffer(anHTMLString);
+ MOZ_ASSERT(mMarkPosition == mCurrentPosition);
+}
+
+/**
+ * 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(nsIURI* aURI) : mURI(aURI), mIncremental(true) {
+ MOZ_COUNT_CTOR(nsScanner);
+
+ // 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;
+
+ // 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() { 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) {
+ mozilla::CheckedInt<size_t> needed =
+ mUnicodeDecoder->MaxUTF16BufferLength(aLen);
+ if (!needed.isValid()) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ mozilla::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;
+ // Do not use structured binding lest deal with [-Werror=unused-variable]
+ std::tie(result, read, written) =
+ mUnicodeDecoder->DecodeToUTF16WithoutReplacement(
+ AsBytes(mozilla::Span(aBuffer, aLen)),
+ mozilla::Span(unichars, needed.value()),
+ false); // Retain bug about failure to handle EOF
+ MOZ_ASSERT(result != mozilla::kOutputFull);
+ MOZ_ASSERT(read <= aLen);
+ MOZ_ASSERT(written <= needed.value());
+ if (result != mozilla::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;
+ AppendToBuffer(buffer);
+ } 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);
+ }
+ }
+}
+
+void nsScanner::AppendToBuffer(nsScannerString::Buffer* aBuf) {
+ if (!mSlidingBuffer) {
+ mSlidingBuffer = mozilla::MakeUnique<nsScannerString>(aBuf);
+ mSlidingBuffer->BeginReading(mCurrentPosition);
+ mMarkPosition = mCurrentPosition;
+ } else {
+ mSlidingBuffer->AppendBuffer(aBuf);
+ if (mCurrentPosition == mEndPosition) {
+ mSlidingBuffer->BeginReading(mCurrentPosition);
+ }
+ }
+ mSlidingBuffer->EndReading(mEndPosition);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * 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..ca0e51bc5e
--- /dev/null
+++ b/parser/htmlparser/nsScanner.h
@@ -0,0 +1,188 @@
+/* -*- 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 "nsCharsetSource.h"
+#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
+ */
+ nsScanner(const nsAString& anHTMLString, bool aIncremental);
+
+ /**
+ * Use this constructor if you want i/o to be based on
+ * a file (therefore a stream) or just data you provide via Append().
+ */
+ explicit nsScanner(nsIURI* aURI);
+
+ ~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 URI 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.
+ */
+ nsIURI* GetURI(void) const { return mURI; }
+
+ 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:
+ void AppendToBuffer(nsScannerString::Buffer* aBuffer);
+ bool AppendToBuffer(const nsAString& aStr) {
+ nsScannerString::Buffer* buf = nsScannerString::AllocBufferFromString(aStr);
+ if (!buf) return false;
+ AppendToBuffer(buf);
+ return true;
+ }
+
+ mozilla::UniquePtr<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
+ nsCOMPtr<nsIURI> mURI;
+ bool mIncremental;
+ int32_t mCharsetSource = kCharsetUninitialized;
+ 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..2c7f09cfdd
--- /dev/null
+++ b/parser/htmlparser/nsScannerString.cpp
@@ -0,0 +1,379 @@
+/* -*- 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) {}
+
+nsScannerSubstring::nsScannerSubstring(const nsAString& s)
+ : mBufferList(nullptr) {
+ Rebind(s);
+}
+
+nsScannerSubstring::~nsScannerSubstring() {
+ release_ownership_of_buffer_list();
+}
+
+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);
+}
+
+void nsScannerSubstring::Rebind(const nsAString& aString) {
+ release_ownership_of_buffer_list();
+
+ mBufferList = new nsScannerBufferList(AllocBufferFromString(aString));
+
+ init_range_from_buffer_list();
+ acquire_ownership_of_buffer_list();
+}
+
+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();
+}
+
+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);
+}
+
+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();
+}
+
+/**
+ * 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();
+}
+
+/**
+ * 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, 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;
+}
diff --git a/parser/htmlparser/nsScannerString.h b/parser/htmlparser/nsScannerString.h
new file mode 100644
index 0000000000..195e63e4bb
--- /dev/null
+++ b/parser/htmlparser/nsScannerString.h
@@ -0,0 +1,459 @@
+/* -*- 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; }
+
+ void Rebind(const nsScannerSubstring&, const nsScannerIterator&,
+ const nsScannerIterator&);
+ void Rebind(const nsAString&);
+
+ 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;
+
+ 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. 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 const reference to this string
+ const nsAString& str() const { return mString; }
+
+ private:
+ typedef nsScannerBufferList::Buffer Buffer;
+
+ void ReleaseBuffer();
+
+ 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);
+
+bool AppendUnicodeTo(const nsScannerIterator& aSrcStart,
+ const nsScannerIterator& aSrcEnd, nsAString& aDest);
+
+#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/1547895-1.html b/parser/htmlparser/tests/crashtests/1547895-1.html
new file mode 100644
index 0000000000..72d19c6caa
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/1547895-1.html
@@ -0,0 +1,10 @@
+<script>
+var func0 = async function(a) {
+ a.currentTarget.close()
+}
+document.addEventListener('DOMContentLoaded', () => {
+ document.write()
+ document.addEventListener('readystatechange', func0, true)
+ setTimeout(window.close, 0)
+})
+</script>
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/1747514.html b/parser/htmlparser/tests/crashtests/1747514.html
new file mode 100644
index 0000000000..e8a93b9280
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/1747514.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script>
+ // Generate an SVG data URI whose URI string will consume 20 MB in expat
+ // (which uses two-byte chars).
+ let img = document.createElement('img');
+ let rect = "<rect />";
+ let src = "data:image/svg+xml;utf8,<svg>" + rect.repeat(20 * 1000 * 1000 / rect.length / 2) + "</svg>";
+ img.src = src;
+ document.body.appendChild(img);
+ </script>
+
diff --git a/parser/htmlparser/tests/crashtests/1810896-1.html b/parser/htmlparser/tests/crashtests/1810896-1.html
new file mode 100644
index 0000000000..2c16456302
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/1810896-1.html
@@ -0,0 +1,1081 @@
+<!DOCTYPE html>
+<head>
+<title>$B$"(B</title>
+</head>
+<body>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ あ
+</body>
+
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..bc630b2a6d
--- /dev/null
+++ b/parser/htmlparser/tests/crashtests/crashtests.list
@@ -0,0 +1,67 @@
+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
+load 1547895-1.html
+skip-if(Android) skip-if(isDebugBuild) load 1747514.html # Bug 1780219
+HTTP load 1810896-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/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..6b7a43b105
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/browser.ini
@@ -0,0 +1,17 @@
+[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
+
+[browser_elementindtd.js]
+support-files =
+ browser_elementindtd.xml
+ browser_elementindtd.dtd
diff --git a/parser/htmlparser/tests/mochitest/browser_elementindtd.dtd b/parser/htmlparser/tests/mochitest/browser_elementindtd.dtd
new file mode 100644
index 0000000000..1c2acdcda8
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/browser_elementindtd.dtd
@@ -0,0 +1,2 @@
+<!ENTITY entitywithelement
+'<p id="fromdtd">From dtd</p>'>
diff --git a/parser/htmlparser/tests/mochitest/browser_elementindtd.js b/parser/htmlparser/tests/mochitest/browser_elementindtd.js
new file mode 100644
index 0000000000..bc146ba73e
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/browser_elementindtd.js
@@ -0,0 +1,31 @@
+/* Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/*
+ * Test for bug 1539759
+ * Loads a chrome XML document that has an exteernal DTD file with an entity
+ * that contains an element, and verifies that that element was not inserted
+ * into the document (but its content was).
+ */
+
+add_task(async function test() {
+ await BrowserTestUtils.withNewTab(
+ getRootDirectory(gTestPath) + "browser_elementindtd.xml",
+ async function (newBrowser) {
+ // NB: We load the chrome:// page in the parent process.
+ testNoElementFromEntity(newBrowser);
+ }
+ );
+});
+
+function testNoElementFromEntity(newBrowser) {
+ let doc = newBrowser.contentDocument;
+ is(doc.body.textContent, "From dtd", "Should load DTD.");
+ is(
+ doc.body.firstElementChild,
+ null,
+ "Shouldn't have an element inserted from the DTD"
+ );
+}
diff --git a/parser/htmlparser/tests/mochitest/browser_elementindtd.xml b/parser/htmlparser/tests/mochitest/browser_elementindtd.xml
new file mode 100644
index 0000000000..937c896f43
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/browser_elementindtd.xml
@@ -0,0 +1,8 @@
+<!DOCTYPE html
+[
+ <!ENTITY % externaldtd SYSTEM "chrome://mochitests/content/browser/parser/htmlparser/tests/mochitest/browser_elementindtd.dtd" >
+ %externaldtd;
+]>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>&entitywithelement;</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/browser_viewsource.js b/parser/htmlparser/tests/mochitest/browser_viewsource.js
new file mode 100644
index 0000000000..e4d44e05be
--- /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..d7a654cad0
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/browser_ysod_telemetry.js
@@ -0,0 +1,49 @@
+"use strict";
+
+const { TelemetryTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TelemetryTestUtils.sys.mjs"
+);
+
+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",
+ hidden: "false",
+ destroyed: "false",
+ },
+ },
+ ],
+ {
+ 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..faf44df66c
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/dir_bug534293/file_bug534293.sjs
@@ -0,0 +1,13 @@
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/javascript", false);
+ if (request.queryString.includes("report")) {
+ 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..5e83e50510
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_async_bug1104732.sjs
@@ -0,0 +1,17 @@
+var timer = null;
+
+function handleRequest(request, response) {
+ response.processAsync();
+ response.setHeader("Content-Type", "application/javascript", false);
+ response.write("asyncState = 'mid-async';\n");
+
+ timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.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_base_csp_img.sjs b/parser/htmlparser/tests/mochitest/file_base_csp_img.sjs
new file mode 100644
index 0000000000..aae7bde6a1
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_base_csp_img.sjs
@@ -0,0 +1,18 @@
+function handleRequest(request, response) {
+ var hosts = getState("hosts");
+ hosts = hosts ? JSON.parse(hosts) : [];
+
+ if (request.queryString == "result") {
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/json", false);
+ response.write(JSON.stringify(hosts));
+
+ setState("hosts", "[]");
+ } else {
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", "blue.png", false);
+
+ hosts.push(request.host);
+ setState("hosts", JSON.stringify(hosts));
+ }
+}
diff --git a/parser/htmlparser/tests/mochitest/file_bug102699.sjs b/parser/htmlparser/tests/mochitest/file_bug102699.sjs
new file mode 100644
index 0000000000..6e7c57cae4
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug102699.sjs
@@ -0,0 +1,19 @@
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/javascript", false);
+ if (request.queryString.includes("report")) {
+ 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..d2236de612
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs
@@ -0,0 +1,16 @@
+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 = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ timer.initWithCallback(
+ function () {
+ response.finish();
+ },
+ 500,
+ Ci.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..279897c567
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug534293.sjs
@@ -0,0 +1,17 @@
+function handleRequest(request, response) {
+ response.setHeader("Content-Type", "text/javascript", false);
+ if (request.queryString.includes("report")) {
+ 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..508cde5644
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug543062.sjs
@@ -0,0 +1,38 @@
+var timer;
+
+function armTimer(response) {
+ timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.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,
+ Ci.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.includes("first")) {
+ response.write("// first\n");
+ response.processAsync();
+ armTimer(response);
+ } else if (request.queryString.includes("second")) {
+ 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..7cd25ddc08
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug568470-script.sjs
@@ -0,0 +1,17 @@
+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 = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ timer.initWithCallback(
+ function () {
+ response.finish();
+ },
+ 500,
+ Ci.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..57559e2f6e
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug568470.sjs
@@ -0,0 +1,22 @@
+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 = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ timer.initWithCallback(
+ function () {
+ response.finish();
+ },
+ 1200,
+ Ci.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..6d83609216
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug642908.sjs
@@ -0,0 +1,19 @@
+function handleRequest(request, response) {
+ if (request.queryString.includes("report")) {
+ 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..2f1e0211c3
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug655682.sjs
@@ -0,0 +1,31 @@
+var timer;
+var callback;
+
+function handleRequest(request, response) {
+ if (request.queryString.includes("trigger")) {
+ 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 = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+
+ callback = function () {
+ if (getState("triggered") == "triggered") {
+ response.write("<td>B</td></tr></table>");
+ response.finish();
+ } else {
+ timer.initWithCallback(callback, 10, Ci.nsITimer.TYPE_ONE_SHOT);
+ }
+ };
+ timer.initWithCallback(callback, 10, Ci.nsITimer.TYPE_ONE_SHOT);
+ }
+}
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_enc_error.html b/parser/htmlparser/tests/mochitest/file_bug672453_enc_error.html
new file mode 100644
index 0000000000..07d037497d
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_enc_error.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Encoding error</title>
+</head>
+<body>
+<p></p>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_enc_error_inherited.html b/parser/htmlparser/tests/mochitest/file_bug672453_enc_error_inherited.html
new file mode 100644
index 0000000000..06d44ba9b1
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_enc_error_inherited.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Encoding error</title>
+</head>
+<body>
+<p></p>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_http_replacement.html b/parser/htmlparser/tests/mochitest/file_bug672453_http_replacement.html
new file mode 100644
index 0000000000..0e76edd65b
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_http_replacement.html
@@ -0,0 +1 @@
+<!DOCTYPE html>
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_http_replacement.html^headers^ b/parser/htmlparser/tests/mochitest/file_bug672453_http_replacement.html^headers^
new file mode 100644
index 0000000000..0cb0a6b1bf
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_http_replacement.html^headers^
@@ -0,0 +1,2 @@
+HTTP 200 OK
+Content-Type: text/html; charset=iso-2022-kr
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_after_head.html b/parser/htmlparser/tests/mochitest/file_bug672453_meta_after_head.html
new file mode 100644
index 0000000000..3def05a535
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_meta_after_head.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Meta after head</title>
+</head>
+<body>
+<meta charset="windows-1251">
+<p>Meta after head</p>
+</body>
+</html>
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_replacement.html b/parser/htmlparser/tests/mochitest/file_bug672453_meta_replacement.html
new file mode 100644
index 0000000000..9bbbe52313
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_meta_replacement.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="iso-2022-kr">
+ <title>Replacement encoding</title>
+</head>
+<body>
+<p>Replacement encoding</p>
+</body>
+</html>
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_speculation_fail.html b/parser/htmlparser/tests/mochitest/file_bug672453_meta_speculation_fail.html
new file mode 100644
index 0000000000..b63255e981
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_meta_speculation_fail.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Speculation filure</title>
+ <meta charset="windows-1252">
+</head>
+<body>
+<p>Speculation fails</p>
+</body>
+</html>
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_bug672453_xml_decl.html b/parser/htmlparser/tests/mochitest/file_bug672453_xml_decl.html
new file mode 100644
index 0000000000..ed350a1157
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_xml_decl.html
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Has only XML decl</title>
+</head>
+<body>
+<p>Only XML decl</p>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/mochitest/file_bug672453_xml_speculation_fail.html b/parser/htmlparser/tests/mochitest/file_bug672453_xml_speculation_fail.html
new file mode 100644
index 0000000000..08ba678590
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_bug672453_xml_speculation_fail.html
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="windows-1252"?>
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Speculation filure</title>
+</head>
+<body>
+<p>Speculation fails</p>
+</body>
+</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..e91da04352
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_img_picture_preload.sjs
@@ -0,0 +1,27 @@
+// 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/file_xml_parse_error.js b/parser/htmlparser/tests/mochitest/file_xml_parse_error.js
new file mode 100644
index 0000000000..8ab5425bce
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_xml_parse_error.js
@@ -0,0 +1 @@
+parent.ok(true, "Loaded script.");
diff --git a/parser/htmlparser/tests/mochitest/file_xml_parse_error.xml b/parser/htmlparser/tests/mochitest/file_xml_parse_error.xml
new file mode 100644
index 0000000000..d75a4525e4
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/file_xml_parse_error.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" standalone="yes" ?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<p> <script src="file_xml_parse_error.js" /> Not a <<b>well-formed</b> xml string</p></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..77b31d4f4f
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/mochitest.ini
@@ -0,0 +1,181 @@
+[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_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_bug672453_xml_decl.html
+ file_bug672453_meta_after_head.html
+ file_bug672453_meta_replacement.html
+ file_bug672453_http_replacement.html
+ file_bug672453_http_replacement.html^headers^
+ file_bug672453_enc_error.html
+ file_bug672453_enc_error_inherited.html
+ file_bug672453_meta_speculation_fail.html
+ file_bug672453_xml_speculation_fail.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_base_csp_img.html]
+support-files =
+ blue.png
+ file_base_csp_img.sjs
+skip-if =
+ http3
+[test_base_header_csp_img.html]
+support-files =
+ blue.png
+ file_base_csp_img.sjs
+ test_base_header_csp_img.html^headers^
+skip-if =
+ http3
+[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)
+ http3
+[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]
+skip-if =
+ http3
+[test_bug667533.html]
+[test_bug672453.html]
+skip-if =
+ http3
+[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]
+[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
+[test_xml_parse_error.html]
+support-files =
+ file_xml_parse_error.js
+ file_xml_parse_error.xml
diff --git a/parser/htmlparser/tests/mochitest/parser_datreader.js b/parser/htmlparser/tests/mochitest/parser_datreader.js
new file mode 100644
index 0000000000..d3d3ea2c89
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/parser_datreader.js
@@ -0,0 +1,218 @@
+/* -*- 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.constructor.name === "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..45df6ea2c6
--- /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_base_csp_img.html b/parser/htmlparser/tests/mochitest/test_base_csp_img.html
new file mode 100644
index 0000000000..d17a99c657
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_base_csp_img.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Base with base-uri CSP</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" />
+
+ <!-- Set CSP -->
+ <meta http-equiv="Content-Security-Policy" content="base-uri 'self';">
+
+ <!-- Base should be ignored -->
+ <base href="http://example.org/">
+</head>
+<body>
+
+<img src="/tests/parser/htmlparser/tests/mochitest/file_base_csp_img.sjs?image" width=10 height=10>
+
+<script>
+add_task(async function() {
+ let response = await fetch(
+ "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_base_csp_img.sjs?result"
+ );
+ let hosts = await response.json();
+
+ is(hosts.length, 1, "One host");
+ is(hosts[0], "mochi.test", "Host was not influenced by base");
+
+ info("finished");
+});
+</script>
+
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_base_header_csp_img.html b/parser/htmlparser/tests/mochitest/test_base_header_csp_img.html
new file mode 100644
index 0000000000..f0becc4080
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_base_header_csp_img.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Base with base-uri CSP header</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" />
+
+ <!-- Base should be ignored -->
+ <base href="http://example.org/">
+</head>
+<body>
+
+<img src="/tests/parser/htmlparser/tests/mochitest/file_base_csp_img.sjs?image" width=10 height=10>
+
+<script>
+add_task(async function() {
+ let response = await fetch(
+ "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_base_csp_img.sjs?result"
+ );
+ let hosts = await response.json();
+
+ is(hosts.length, 1, "One host");
+ is(hosts[0], "mochi.test", "Host was not influenced by base");
+
+ info("finished");
+});
+</script>
+
+</body>
+</html>
+
diff --git a/parser/htmlparser/tests/mochitest/test_base_header_csp_img.html^headers^ b/parser/htmlparser/tests/mochitest/test_base_header_csp_img.html^headers^
new file mode 100644
index 0000000000..3c02326419
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_base_header_csp_img.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: base-uri 'self';
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..312757cb58
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_bug672453.html
@@ -0,0 +1,131 @@
+<!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_xml_decl.html",
+ "file_bug672453_late_meta.html",
+ "file_bug672453_meta_restart.html",
+ "file_bug672453_meta_after_head.html",
+ "file_bug672453_meta_unsupported.html",
+ "file_bug672453_http_unsupported.html",
+ "file_bug672453_meta_utf16.html",
+ "file_bug672453_meta_non_superset.html",
+ "file_bug672453_meta_userdefined.html",
+ "file_bug672453_meta_replacement.html",
+ "file_bug672453_http_replacement.html",
+ "file_bug672453_enc_error.html",
+ "file_bug672453_enc_error_inherited.html",
+ "file_bug672453_meta_speculation_fail.html",
+ "file_bug672453_xml_speculation_fail.html",
+];
+
+// The general idea here is that encoding substitutions or failures to declare the encoding
+// (except when inherited or, not tested here, all-ASCII) are errors and ineffeciencies
+// or risks about things failing under further editing (i.e. meta after head but within
+// the extended scan zone) are warnings.
+
+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 of an HTML document was declared using the XML declaration syntax. This is non-conforming, and declaring the encoding using a meta tag at the start of the head part is more efficient.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_xml_decl.html",
+ lineNumber: 1,
+ isWarning: true },
+ { errorMessage: "A meta tag attempting to declare the character encoding declaration was found too late, and the encoding of the parent document was used instead. The meta tag needs to be moved to the start of the head part of the document.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_late_meta.html",
+ lineNumber: 1028,
+ isWarning: false },
+ { errorMessage: "A meta tag attempting to declare the character encoding declaration was found too late, and the encoding of the parent document was used instead. The meta tag needs to be moved to the start of the head part of the document.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_restart.html",
+ lineNumber: 1028,
+ isWarning: false },
+ { errorMessage: "The meta tag declaring the character encoding of the document should be moved to start of the head part of the document.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_after_head.html",
+ lineNumber: 7,
+ 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: "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 },
+ { errorMessage: "A meta tag was used to declare an encoding that is a cross-site scripting hazard. The replacement encoding was used instead.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_replacement.html",
+ lineNumber: 0,
+ isWarning: false },
+ { errorMessage: "An encoding that is a cross-site scripting hazard was declared on the transfer protocol level. The replacement encoding was used instead.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_http_replacement.html",
+ lineNumber: 0,
+ isWarning: false },
+ { errorMessage: "The byte stream was erroneous according to the character encoding that was declared. The character encoding declaration may be incorrect.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_enc_error.html",
+ lineNumber: 0,
+ isWarning: false },
+ { errorMessage: "The byte stream was erroneous according to the character encoding that was inherited from the parent document. The character encoding needs to be declared in the Content-Type HTTP header, using a meta tag, or using a byte order mark.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_enc_error_inherited.html",
+ lineNumber: 0,
+ isWarning: false },
+ { errorMessage: "The start of the document was reparsed, because there were non-ASCII characters before the meta tag that declared the encoding. The meta should be the first child of head without non-ASCII comments before.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_speculation_fail.html",
+ lineNumber: 5,
+ isWarning: true },
+ { errorMessage: "The start of the document was reparsed, because there were non-ASCII characters in the part of the document that was unsuccessfully searched for a meta tag before falling back to the XML declaration syntax. A meta tag at the start of the head part should be used instead of the XML declaration syntax.",
+ sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_xml_speculation_fail.html",
+ lineNumber: 10,
+ isWarning: true },
+];
+
+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..295993060b
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_img_picture_preload.html
@@ -0,0 +1,88 @@
+<!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>
+ // 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() {
+ // Make sure we trigger a layout flush so that the frame is sized
+ // appropriately after the DPI changes.
+ iframe.getBoundingClientRect();
+ // 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/mochitest/test_xml_parse_error.html b/parser/htmlparser/tests/mochitest/test_xml_parse_error.html
new file mode 100644
index 0000000000..5c023ecfbd
--- /dev/null
+++ b/parser/htmlparser/tests/mochitest/test_xml_parse_error.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title><!-- TODO: insert title here --></title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ function getExpectedError(string, filename=location.href) {
+ let lines = string.split(/\r\n|\r|\n/);
+ let line, column;
+ let errorLine;
+ for (line = 0; line < lines.length; ++line) {
+ errorLine = lines[line];
+ // The error starts at the opening '<' of '<b>'.
+ column = errorLine.search("<<b>") + 1;
+ if (column > 0) {
+ // Line and column are 1-based.
+ line += 1;
+ column += 1;
+ break;
+ }
+ }
+
+ let expectedError = `XML Parsing Error: not well-formed
+Location: ${filename}
+Line Number ${line}, Column ${column}:${errorLine}
+${"^".padStart(column, "-")}`;
+ return expectedError;
+ }
+
+ function getParseError(string) {
+ let error = new window.DOMParser()
+ .parseFromString(string, "text/xml")
+ .getElementsByTagName("parsererror")[0].textContent;
+ return [error, getExpectedError(string)];
+ }
+
+ SimpleTest.waitForExplicitFinish();
+
+ function runTest() {
+ let [error, expectedError] = getParseError("<p>Not a <<b>well-formed</b> xml string</p>");
+ is(error, expectedError, "Check that parsererror contains the right data.");
+
+ [error, expectedError] = getParseError("<p>Not \na <<b>well-formed</b> xml string</p>");
+ is(error, expectedError, "Check that parsererror contains the right data.");
+
+ [error, expectedError] = getParseError("<p>Not \na <<b>well-formed</b> xml string</p>");
+ is(error, expectedError, "Check that parsererror contains the right data.");
+
+ [error, expectedError] = getParseError("<p>Not a <<b>well-fo\nrmed</b> xml string</p>");
+ is(error, expectedError, "Check that parsererror contains the right data.");
+
+ [error, expectedError] = getParseError(`<p>Not ${' '.repeat(512)} a <<b>well-formed</b> xml string</p>`);
+ is(error, expectedError, "Check that parsererror contains the right data.");
+
+ [error, expectedError] = getParseError(`<p>${' '.repeat(505)}<br>${' '.repeat(512)}<<b>Not a well-formed</b> xml string</p>`);
+ is(error, expectedError, "Check that parsererror contains the right data.");
+
+ [error, expectedError] = getParseError(`<p>${' '.repeat(2048)}<br>${' '.repeat(512)}<<b>Not a well-formed</b> xml string</p>`);
+ is(error, expectedError, "Check that parsererror contains the right data.");
+
+ fetch("file_xml_parse_error.xml").then(response => response.text()).then(string => {
+ let doc = document.getElementById("frame").contentDocument;
+ error = doc.documentElement.textContent;
+ expectedError = getExpectedError(string, doc.location);
+ is(error, expectedError, "Check that parsererror contains the right data.");
+
+ SimpleTest.finish();
+ });
+ }
+ </script>
+</head>
+<body onload="runTest()">
+<p id="display"><iframe id="frame" src="file_xml_parse_error.xml"></iframe></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/reftest/after-1kb-ref.html b/parser/htmlparser/tests/reftest/after-1kb-ref.html
new file mode 100644
index 0000000000..edb0ae9c72
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-1kb-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>In <code>head</code>, after first kilobyte.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-1kb.html b/parser/htmlparser/tests/reftest/after-1kb.html
new file mode 100644
index 0000000000..01eedca187
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-1kb.html
@@ -0,0 +1,955 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/after-1kb-ref.html">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<meta charset="windows-1251">
+</head>
+<body>
+<p>In <code>head</code>, after first kilobyte.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-bogus-after-1kb-ref.html b/parser/htmlparser/tests/reftest/after-bogus-after-1kb-ref.html
new file mode 100644
index 0000000000..c6f129a89e
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-bogus-after-1kb-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>After <code>bogus</code>, before <code>head</code> end tag, after first kilobyte.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-bogus-after-1kb.html b/parser/htmlparser/tests/reftest/after-bogus-after-1kb.html
new file mode 100644
index 0000000000..f44fda1e6d
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-bogus-after-1kb.html
@@ -0,0 +1,933 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/after-bogus-after-1kb-ref.html">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<bogus><meta charset="windows-1251">
+</head>
+<body>
+<p>After <code>bogus</code>, before <code>head</code> end tag, after first kilobyte.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-bogus-ref.html b/parser/htmlparser/tests/reftest/after-bogus-ref.html
new file mode 100644
index 0000000000..f8080e60aa
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-bogus-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Meta after <code>bogus</code>.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-bogus.html b/parser/htmlparser/tests/reftest/after-bogus.html
new file mode 100644
index 0000000000..7eeedde7af
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-bogus.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/after-bogus-ref.html">
+<bogus><meta charset="windows-1251">
+</head>
+<body>
+<p>Meta after <code>bogus</code>.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-head-after-1kb-crlf-ref.html b/parser/htmlparser/tests/reftest/after-head-after-1kb-crlf-ref.html
new file mode 100644
index 0000000000..868a9639bf
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-head-after-1kb-crlf-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>After <code>head</code>, before <code>body</code>, after first kilobyte, with a CRLF in the first kilobyte.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-head-after-1kb-crlf.html b/parser/htmlparser/tests/reftest/after-head-after-1kb-crlf.html
new file mode 100644
index 0000000000..10a6d1c3d7
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-head-after-1kb-crlf.html
@@ -0,0 +1,927 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/after-head-after-1kb-crlf-ref.html">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</head>
+<meta charset="windows-1251">
+<body>
+<p>After <code>head</code>, before <code>body</code>, after first kilobyte, with a CRLF in the first kilobyte.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-head-after-1kb-ref.html b/parser/htmlparser/tests/reftest/after-head-after-1kb-ref.html
new file mode 100644
index 0000000000..bde4745b26
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-head-after-1kb-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>After <code>head</code>, before <code>body</code>, after first kilobyte.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-head-after-1kb.html b/parser/htmlparser/tests/reftest/after-head-after-1kb.html
new file mode 100644
index 0000000000..d514fdfbff
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-head-after-1kb.html
@@ -0,0 +1,933 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/after-head-after-1kb-ref.html">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</head>
+<meta charset="windows-1251">
+<body>
+<p>After <code>head</code>, before <code>body</code>, after first kilobyte.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-head-in-1kb-crlf-ref.html b/parser/htmlparser/tests/reftest/after-head-in-1kb-crlf-ref.html
new file mode 100644
index 0000000000..0676d7374e
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-head-in-1kb-crlf-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>After <code>head</code>, before <code>body</code>, within first kilobyte, with a CRLF in the first kilobyte.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-head-in-1kb-crlf.html b/parser/htmlparser/tests/reftest/after-head-in-1kb-crlf.html
new file mode 100644
index 0000000000..e5c95e7036
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-head-in-1kb-crlf.html
@@ -0,0 +1,932 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/after-head-in-1kb-crlf-ref.html">
+</head>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<meta charset="windows-1251">
+<body>
+<p>After <code>head</code>, before <code>body</code>, within first kilobyte, with a CRLF in the first kilobyte.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-head-in-1kb-ref.html b/parser/htmlparser/tests/reftest/after-head-in-1kb-ref.html
new file mode 100644
index 0000000000..75fc2dd618
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-head-in-1kb-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>After <code>head</code>, before <code>body</code>, within first kilobyte.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/after-head-in-1kb.html b/parser/htmlparser/tests/reftest/after-head-in-1kb.html
new file mode 100644
index 0000000000..e73522d373
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/after-head-in-1kb.html
@@ -0,0 +1,938 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/after-head-in-1kb-ref.html">
+</head>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<meta charset="windows-1251">
+<body>
+<p>After <code>head</code>, before <code>body</code>, within first kilobyte.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/baseline-ref.html b/parser/htmlparser/tests/reftest/baseline-ref.html
new file mode 100644
index 0000000000..21b939efe0
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/baseline-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Normal meta.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/baseline.html b/parser/htmlparser/tests/reftest/baseline.html
new file mode 100644
index 0000000000..40bce2f63f
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/baseline.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/baseline-ref.html">
+<meta charset="windows-1251">
+</head>
+<body>
+<p>Normal meta.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/bug1153920-1-ref.html b/parser/htmlparser/tests/reftest/bug1153920-1-ref.html
new file mode 100644
index 0000000000..6c7e8fb13c
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1153920-1-ref.html
@@ -0,0 +1,4 @@
+<html><head><meta name="viewport" content="width=device-width"><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span></span><span class="doctype">&lt;!DOCTYPE html&gt;</span><span>
+<span id="line2"></span></span><span>&lt;<span class="start-tag">a</span> <span class="attribute-name">href</span>='<a class="attribute-value" href="?a=b&amp;c=d&amp;a0b=c&amp;copy=1&amp;noti=n&amp;not=in&amp;notin=%26%238713%3B%AC&amp;;&amp;%20&amp;">?a=b<span><span>&amp;</span>c</span>=d<span><span>&amp;</span>a</span>0b=c<span><span>&amp;</span>copy</span>=1<span><span>&amp;</span>noti</span>=n<span><span>&amp;</span>not</span>=in<span><span>&amp;</span>notin</span>=<span class="entity"><span>&amp;</span>notin;</span><span class="entity"><span>&amp;</span>not;</span><span><span>&amp;</span></span>;<span><span>&amp;</span></span> <span><span>&amp;</span></span></a>'&gt;</span><span>Link</span><span>&lt;/<span class="end-tag">a</span>&gt;</span><span>
+<span id="line3"></span></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Text: ?a=b<span><span>&amp;</span>c</span>=d<span><span>&amp;</span>a</span>0b=c<span class="error entity" title="Named character reference was not terminated by a semicolon. (Or “&amp;” should have been escaped as “&amp;amp;”.)"><span>&amp;</span>copy</span>=1<span class="error entity" title="Named character reference was not terminated by a semicolon. (Or “&amp;” should have been escaped as “&amp;amp;”.)"><span>&amp;</span>noti</span>=n<span class="error entity" title="Named character reference was not terminated by a semicolon. (Or “&amp;” should have been escaped as “&amp;amp;”.)"><span>&amp;</span>not</span>=in<span class="error entity" title="Named character reference was not terminated by a semicolon. (Or “&amp;” should have been escaped as “&amp;amp;”.)"><span>&amp;</span>notin</span>=<span class="entity"><span>&amp;</span>notin;</span><span class="entity"><span>&amp;</span>not;</span><span><span>&amp;</span></span>;<span><span>&amp;</span></span> <span><span>&amp;</span></span></span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>
+<span id="line4"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/bug1153920-1.html b/parser/htmlparser/tests/reftest/bug1153920-1.html
new file mode 100644
index 0000000000..f36b2b0581
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1153920-1.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<a href='?a=b&c=d&a0b=c&copy=1&noti=n&not=in&notin=&notin;&not;&;& &'>Link</a>
+<p>Text: ?a=b&c=d&a0b=c&copy=1&noti=n&not=in&notin=&notin;&not;&;& &</p>
diff --git a/parser/htmlparser/tests/reftest/bug1319410-1-ref.html b/parser/htmlparser/tests/reftest/bug1319410-1-ref.html
new file mode 100644
index 0000000000..abce6d8540
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1319410-1-ref.html
@@ -0,0 +1,6 @@
+<html><head><meta name="viewport" content="width=device-width"><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span></span><span class="doctype">&lt;!DOCTYPE html&gt;</span><span>
+<span id="line2"></span></span><span class="comment">&lt;!-- -- --&gt;</span><span>
+<span id="line3"></span></span><span class="error comment" title="Saw “<!--” within a comment. Probable cause: Nested comment (not allowed).">&lt;!-- &lt;!-- --&gt;</span><span> --&gt;
+<span id="line4"></span></span><span class="error comment" title="Premature end of comment. Use “-->” to end a comment properly.">&lt;!--&gt;</span><span>
+<span id="line5"></span></span><span class="comment">&lt;!--&lt;!--&gt;
+<span id="line6"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/bug1319410-1.html b/parser/htmlparser/tests/reftest/bug1319410-1.html
new file mode 100644
index 0000000000..04363210af
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1319410-1.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<!-- -- -->
+<!-- <!-- --> -->
+<!-->
+<!--<!-->
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/bug1650087-1-ref.html b/parser/htmlparser/tests/reftest/bug1650087-1-ref.html
new file mode 100644
index 0000000000..284f097100
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1650087-1-ref.html
@@ -0,0 +1,8 @@
+<html><head><meta name="viewport" content="width=device-width"><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span></span><span class="doctype">&lt;!DOCTYPE html&gt;</span><span>
+<span id="line2"></span></span><span>&lt;<span class="start-tag">template</span>&gt;</span><span></span><span>&lt;<span class="start-tag">td</span>&gt;</span><span></span><span>&lt;/<span class="end-tag">template</span>&gt;</span><span>
+<span id="line3"></span></span><span>&lt;<span class="start-tag">template</span>&gt;</span><span></span><span>&lt;<span class="start-tag">tr</span>&gt;</span><span></span><span>&lt;/<span class="end-tag">template</span>&gt;</span><span>
+<span id="line4"></span></span><span>&lt;<span class="start-tag">template</span>&gt;</span><span></span><span>&lt;<span class="start-tag">thead</span>&gt;</span><span></span><span>&lt;/<span class="end-tag">template</span>&gt;</span><span>
+<span id="line5"></span></span><span>&lt;<span class="start-tag">template</span>&gt;</span><span></span><span>&lt;<span class="start-tag">tbody</span>&gt;</span><span></span><span>&lt;/<span class="end-tag">template</span>&gt;</span><span>
+<span id="line6"></span></span><span>&lt;<span class="start-tag">template</span>&gt;</span><span></span><span>&lt;<span class="start-tag">tfoot</span>&gt;</span><span></span><span>&lt;/<span class="end-tag">template</span>&gt;</span><span>
+<span id="line7"></span></span><span>&lt;<span class="start-tag">template</span>&gt;</span><span></span><span>&lt;<span class="start-tag">colgroup</span>&gt;</span><span></span><span>&lt;/<span class="end-tag">template</span>&gt;</span><span>
+<span id="line8"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/bug1650087-1.html b/parser/htmlparser/tests/reftest/bug1650087-1.html
new file mode 100644
index 0000000000..c5b92f1615
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1650087-1.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<template><td></template>
+<template><tr></template>
+<template><thead></template>
+<template><tbody></template>
+<template><tfoot></template>
+<template><colgroup></template>
diff --git a/parser/htmlparser/tests/reftest/bug1726374-1-ref.html b/parser/htmlparser/tests/reftest/bug1726374-1-ref.html
new file mode 100644
index 0000000000..1bd351963d
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1726374-1-ref.html
@@ -0,0 +1,2 @@
+<html><head><meta name="viewport" content="width=device-width"><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span></span><span class="doctype">&lt;!DOCTYPE html&gt;</span><span></span><span class="comment">&lt;!-- a &lt;!--&gt;</span><span>b
+<span id="line2"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/bug1726374-1.html b/parser/htmlparser/tests/reftest/bug1726374-1.html
new file mode 100644
index 0000000000..edcb3952c5
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1726374-1.html
@@ -0,0 +1 @@
+<!DOCTYPE html><!-- a <!-->b
diff --git a/parser/htmlparser/tests/reftest/bug1749522-1-ref.txt b/parser/htmlparser/tests/reftest/bug1749522-1-ref.txt
new file mode 100644
index 0000000000..c95d7230fd
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1749522-1-ref.txt
@@ -0,0 +1,3 @@
+<script>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+To jest test kodowania znaków. W przypadku niektórych języków, które używają znaków łacińskich, potrzebujemy więcej danych, aby podjąć decyzję.
+</script>
diff --git a/parser/htmlparser/tests/reftest/bug1749522-1.txt b/parser/htmlparser/tests/reftest/bug1749522-1.txt
new file mode 100644
index 0000000000..3520d89838
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/bug1749522-1.txt
@@ -0,0 +1,3 @@
+<script>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+To jest test kodowania znakw. W przypadku niektrych jzykw, ktre uywaj znakw aciskich, potrzebujemy wicej danych, aby podj decyzj.
+</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..174e94dc8b
--- /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&amp;XX
+<span id></span>XX&amp;nXX
+<span id></span>XX&amp;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&amp;;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/document-write-ref.html b/parser/htmlparser/tests/reftest/document-write-ref.html
new file mode 100644
index 0000000000..9902cf77d1
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/document-write-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Meta from <code>document.write</code> (with concatenation in the middle of <code>charset</code> to require execution for effect).</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/document-write.html b/parser/htmlparser/tests/reftest/document-write.html
new file mode 100644
index 0000000000..b70a15c567
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/document-write.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/document-write-ref.html">
+<script>document.write('<meta char' + 'set="windows-1251">');</script>
+</head>
+<body>
+<p>Meta from <code>document.write</code> (with concatenation in the middle of <code>charset</code> to require execution for effect).</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
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/in-comment-ref.html b/parser/htmlparser/tests/reftest/in-comment-ref.html
new file mode 100644
index 0000000000..94b2016e0d
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-comment-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Meta inside comment.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-comment.html b/parser/htmlparser/tests/reftest/in-comment.html
new file mode 100644
index 0000000000..65828a1872
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-comment.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/in-comment-ref.html">
+<!--<meta charset="windows-1251">-->
+</head>
+<body>
+<p>Meta inside comment.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-noscript-after-template-after-1kb-ref.html b/parser/htmlparser/tests/reftest/in-noscript-after-template-after-1kb-ref.html
new file mode 100644
index 0000000000..12e9b93626
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-noscript-after-template-after-1kb-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Meta in <code>noscript</code> after <code>template</code> (which is also inside the <code>noscript</code>) after 1kb of padding following the template.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-noscript-after-template-after-1kb.html b/parser/htmlparser/tests/reftest/in-noscript-after-template-after-1kb.html
new file mode 100644
index 0000000000..d22e83aaa7
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-noscript-after-template-after-1kb.html
@@ -0,0 +1,894 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/in-noscript-after-template-after-1kb-ref.html">
+<noscript><template></template>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<meta charset="windows-1251"></noscript>
+</head>
+<body>
+<p>Meta in <code>noscript</code> after <code>template</code> (which is also inside the <code>noscript</code>) after 1kb of padding following the template.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-noscript-after-template-ref.html b/parser/htmlparser/tests/reftest/in-noscript-after-template-ref.html
new file mode 100644
index 0000000000..27defe54c0
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-noscript-after-template-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Meta in <code>noscript</code> after <code>template</code> (which is also inside the <code>noscript</code>).</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-noscript-after-template.html b/parser/htmlparser/tests/reftest/in-noscript-after-template.html
new file mode 100644
index 0000000000..71ef9144e0
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-noscript-after-template.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/in-noscript-after-template-ref.html">
+<noscript><template></template><meta charset="windows-1251"></noscript>
+</head>
+<body>
+<p>Meta in <code>noscript</code> after <code>template</code> (which is also inside the <code>noscript</code>).</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-noscript-ncr-ref.html b/parser/htmlparser/tests/reftest/in-noscript-ncr-ref.html
new file mode 100644
index 0000000000..3581ab68db
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-noscript-ncr-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Meta with NCR in the encoding label in <code>noscript</code>.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-noscript-ncr.html b/parser/htmlparser/tests/reftest/in-noscript-ncr.html
new file mode 100644
index 0000000000..645f151b26
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-noscript-ncr.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/in-noscript-ncr-ref.html">
+<noscript><meta charset="&#119;indows-1251"></noscript>
+</head>
+<body>
+<p>Meta with NCR in the encoding label in <code>noscript</code>.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-noscript-ref.html b/parser/htmlparser/tests/reftest/in-noscript-ref.html
new file mode 100644
index 0000000000..9bb9f24b88
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-noscript-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Meta in <code>noscript</code>.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-noscript.html b/parser/htmlparser/tests/reftest/in-noscript.html
new file mode 100644
index 0000000000..e76054d618
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-noscript.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/in-noscript-ref.html">
+<noscript><meta charset="windows-1251"></noscript>
+</head>
+<body>
+<p>Meta in <code>noscript</code>.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-object-ref.html b/parser/htmlparser/tests/reftest/in-object-ref.html
new file mode 100644
index 0000000000..3f52d0efe9
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-object-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Meta in <code>object</code>.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-object.html b/parser/htmlparser/tests/reftest/in-object.html
new file mode 100644
index 0000000000..32535b8eba
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-object.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/in-object-ref.html">
+<object><meta charset="windows-1251"></object>
+</head>
+<body>
+<p>Meta in <code>object</code>.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-script-ref.html b/parser/htmlparser/tests/reftest/in-script-ref.html
new file mode 100644
index 0000000000..bbb63fd931
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-script-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Meta in <code>script</code>.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-script.html b/parser/htmlparser/tests/reftest/in-script.html
new file mode 100644
index 0000000000..0c18a4435e
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-script.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/in-script-ref.html">
+<script><meta charset="windows-1251"></script>
+</head>
+<body>
+<p>Meta in <code>script</code>.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-style-ref.html b/parser/htmlparser/tests/reftest/in-style-ref.html
new file mode 100644
index 0000000000..9669146eb5
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-style-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Meta in <code>style</code>.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-style.html b/parser/htmlparser/tests/reftest/in-style.html
new file mode 100644
index 0000000000..69d8fa429c
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-style.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/in-style-ref.html">
+<style><meta charset="windows-1251"></style>
+</head>
+<body>
+<p>Meta in <code>style</code>.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-svg-in-cdata-after-gt-ref.html b/parser/htmlparser/tests/reftest/in-svg-in-cdata-after-gt-ref.html
new file mode 100644
index 0000000000..2868f47fc2
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-svg-in-cdata-after-gt-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<svg></svg>
+<p>In SVG in CDATA after greater-than sign in the CDATA (after head).</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-svg-in-cdata-after-gt.html b/parser/htmlparser/tests/reftest/in-svg-in-cdata-after-gt.html
new file mode 100644
index 0000000000..56783b7afc
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-svg-in-cdata-after-gt.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/in-svg-in-cdata-after-gt-ref.html">
+</head>
+<body>
+<svg><![CDATA[><meta charset="windows-1251">]]></svg>
+<p>In SVG in CDATA after greater-than sign in the CDATA (after head).</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-svg-in-cdata-ref.html b/parser/htmlparser/tests/reftest/in-svg-in-cdata-ref.html
new file mode 100644
index 0000000000..1d17d2720b
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-svg-in-cdata-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<svg></svg>
+<p>In SVG in CDATA (after head).</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-svg-in-cdata.html b/parser/htmlparser/tests/reftest/in-svg-in-cdata.html
new file mode 100644
index 0000000000..d1c4ca12b3
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-svg-in-cdata.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/in-svg-in-cdata-ref.html">
+</head>
+<body>
+<svg><![CDATA[<meta charset="windows-1251">]]></svg>
+<p>In SVG in CDATA (after head).</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-svg-ref.html b/parser/htmlparser/tests/reftest/in-svg-ref.html
new file mode 100644
index 0000000000..c9e41aa177
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-svg-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<svg></svg>
+<p>In SVG (after head).</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-svg.html b/parser/htmlparser/tests/reftest/in-svg.html
new file mode 100644
index 0000000000..cb29164289
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-svg.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/in-svg-ref.html">
+</head>
+<body>
+<svg><meta charset="windows-1251"></svg>
+<p>In SVG (after head).</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-template-after-1kb-ref.html b/parser/htmlparser/tests/reftest/in-template-after-1kb-ref.html
new file mode 100644
index 0000000000..df20eba39b
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-template-after-1kb-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<head>
+</head>
+<body>
+<p>In <code>template</code>, before <code>head</code> end tag, after first kilobyte.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-template-after-1kb.html b/parser/htmlparser/tests/reftest/in-template-after-1kb.html
new file mode 100644
index 0000000000..ae77decea2
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-template-after-1kb.html
@@ -0,0 +1,1046 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/in-template-after-1kb-ref.html">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<template><meta charset="windows-1251"></template>
+</head>
+<body>
+<p>In <code>template</code>, before <code>head</code> end tag, after first kilobyte.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-template-ref.html b/parser/htmlparser/tests/reftest/in-template-ref.html
new file mode 100644
index 0000000000..83c0e93072
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-template-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Meta in <code>template</code>.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-template.html b/parser/htmlparser/tests/reftest/in-template.html
new file mode 100644
index 0000000000..264affc269
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-template.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/in-template-ref.html">
+<template><meta charset="windows-1251"></template>
+</head>
+<body>
+<p>Meta in <code>template</code>.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-title-ref.html b/parser/htmlparser/tests/reftest/in-title-ref.html
new file mode 100644
index 0000000000..5fb8a05f2d
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-title-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+<title><meta charset="windows-1251"></title>
+</head>
+<body>
+<p>Meta in <code>title</code>.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/in-title.html b/parser/htmlparser/tests/reftest/in-title.html
new file mode 100644
index 0000000000..7b72c48dd8
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/in-title.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/in-title-ref.html">
+<title><meta charset="windows-1251"></title>
+</head>
+<body>
+<p>Meta in <code>title</code>.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/incomplete-xml-decl-ref.html b/parser/htmlparser/tests/reftest/incomplete-xml-decl-ref.html
new file mode 100644
index 0000000000..201fe664d5
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/incomplete-xml-decl-ref.html
@@ -0,0 +1,2 @@
+<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>incomplete-xml-decl.xml</title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span></span><span class="pi">&lt;?xml
+<span id="line2"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/incomplete-xml-decl.xml b/parser/htmlparser/tests/reftest/incomplete-xml-decl.xml
new file mode 100644
index 0000000000..1b345b6c84
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/incomplete-xml-decl.xml
@@ -0,0 +1 @@
+<?xml
diff --git a/parser/htmlparser/tests/reftest/ncr-ref.html b/parser/htmlparser/tests/reftest/ncr-ref.html
new file mode 100644
index 0000000000..1d25b4d23d
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/ncr-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>NCR in encoding label.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/ncr.html b/parser/htmlparser/tests/reftest/ncr.html
new file mode 100644
index 0000000000..9f8b7308ad
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/ncr.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/ncr-ref.html">
+<meta charset="&#119;indows-1251">
+</head>
+<body>
+<p>NCR in encoding label.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/non-ascii-in-comment-before-ref.html b/parser/htmlparser/tests/reftest/non-ascii-in-comment-before-ref.html
new file mode 100644
index 0000000000..bd2acd274c
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/non-ascii-in-comment-before-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<p>Normal meta. Non-ASCII in comment before.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/non-ascii-in-comment-before.html b/parser/htmlparser/tests/reftest/non-ascii-in-comment-before.html
new file mode 100644
index 0000000000..148c6544a3
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/non-ascii-in-comment-before.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/non-ascii-in-comment-before-ref.html">
+<!-- -->
+<meta charset="windows-1251">
+</head>
+<body>
+<p>Normal meta. Non-ASCII in comment before.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/non-ascii-in-title-before-ref.html b/parser/htmlparser/tests/reftest/non-ascii-in-title-before-ref.html
new file mode 100644
index 0000000000..4f54732432
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/non-ascii-in-title-before-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+<title>ж</title>
+</head>
+<body>
+<p>Normal meta. Non-ASCII in title before.</p>
+<p>Test: ж</p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/non-ascii-in-title-before.html b/parser/htmlparser/tests/reftest/non-ascii-in-title-before.html
new file mode 100644
index 0000000000..aac0ca94c1
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/non-ascii-in-title-before.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/non-ascii-in-title-before-ref.html">
+<title></title>
+<meta charset="windows-1251">
+</head>
+<body>
+<p>Normal meta. Non-ASCII in title before.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/reftest.list b/parser/htmlparser/tests/reftest/reftest.list
new file mode 100644
index 0000000000..52b5bc45b0
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/reftest.list
@@ -0,0 +1,73 @@
+== bug535530-1.html bug535530-1-ref.html
+== view-source:bug535530-2.html bug535530-2-ref.html
+== 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(0-2,0-5) skip-if(OSX) == bug582940-1.html bug582940-1-ref.html
+== bug592656-1.html bug592656-1-ref.html
+fuzzy(0-1,0-5) == bug599320-1.html bug599320-1-ref.html
+fuzzy(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(0-2,0-5) == bug659763-1.html bug659763-1-ref.html
+fuzzy(0-1,0-5) == bug659763-2.html bug659763-2-ref.html
+fuzzy(0-1,0-5) == bug659763-3.html bug659763-3-ref.html
+fuzzy(0-2,0-3) == bug659763-4.html bug659763-4-ref.html
+fuzzy(0-1,0-5) == bug659763-5.html bug659763-5-ref.html
+fuzzy(0-1,0-5) == bug659763-6.html bug659763-6-ref.html
+== view-source:bug673094-1.html view-source:bug673094-1-ref.html
+== 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
+== view-source:bug1319410-1.html bug1319410-1-ref.html
+== view-source:bug1650087-1.html bug1650087-1-ref.html
+== view-source:bug1726374-1.html bug1726374-1-ref.html
+== view-source:bug1153920-1.html bug1153920-1-ref.html
+== after-1kb.html after-1kb-ref.html
+!= after-bogus-after-1kb.html after-bogus-after-1kb-ref.html
+== after-bogus.html after-bogus-ref.html
+!= after-head-after-1kb-crlf.html after-head-after-1kb-crlf-ref.html
+!= after-head-after-1kb.html after-head-after-1kb-ref.html
+== after-head-in-1kb-crlf.html after-head-in-1kb-crlf-ref.html
+== after-head-in-1kb.html after-head-in-1kb-ref.html
+== baseline.html baseline-ref.html
+!= document-write.html document-write-ref.html
+!= in-comment.html in-comment-ref.html
+!= in-noscript-after-template-after-1kb.html in-noscript-after-template-after-1kb-ref.html
+!= in-noscript-after-template.html in-noscript-after-template-ref.html
+!= in-noscript.html in-noscript-ref.html
+!= in-noscript-ncr.html in-noscript-ncr-ref.html
+== in-object.html in-object-ref.html
+!= in-script.html in-script-ref.html
+!= in-style.html in-style-ref.html
+== in-svg.html in-svg-ref.html
+!= in-svg-in-cdata-after-gt.html in-svg-in-cdata-after-gt-ref.html
+!= in-svg-in-cdata.html in-svg-in-cdata-ref.html
+!= in-template-after-1kb.html in-template-after-1kb-ref.html
+== in-template.html in-template-ref.html
+!= in-title.html in-title-ref.html
+== ncr.html ncr-ref.html
+== non-ascii-in-comment-before.html non-ascii-in-comment-before-ref.html
+== non-ascii-in-title-before.html non-ascii-in-title-before-ref.html
+== view-source:xml-1.xml xml-ref.html
+HTTP(..) == view-source:xml-trickle-1.sjs xml-ref.html
+HTTP(..) == view-source:xml-trickle-2.sjs xml-ref.html
+HTTP(..) == view-source:xml-trickle-3.sjs xml-ref.html
+HTTP(..) == view-source:xml-trickle-4.sjs xml-utf-ref.html
+HTTP(..) == view-source:xml-trickle-5.sjs xml-utf-ref.html
+HTTP(..) == view-source:xml-trickle-6.sjs xml-utf-ref.html
+skip-if(Android) HTTP(..) == view-source:vs-after-head-in-1kb.html vs-after-head-in-1kb-ref.html # Skipped on Android due to inconsistent scrollbar display
+HTTP(..) != view-source:vs-after-head-after-1kb.html vs-after-head-after-1kb-ref.html
+HTTP(..) == view-source:vs-non-ascii-in-comment-before.html vs-non-ascii-in-comment-before-ref.html
+HTTP(..) == view-source:vs-non-ascii-in-comment-before.sjs vs-non-ascii-in-comment-before-ref.html
+== view-source:xml-without-tags.xml xml-without-tags-ref.html
+== view-source:incomplete-xml-decl.xml incomplete-xml-decl-ref.html
+== view-source:view-source-bom.html view-source-bom-ref.html
+skip-if(Android) == bug1749522-1.txt bug1749522-1-ref.txt # Skipped on Android due to suspicion of harness bug
diff --git a/parser/htmlparser/tests/reftest/view-source-bom-ref.html b/parser/htmlparser/tests/reftest/view-source-bom-ref.html
new file mode 100644
index 0000000000..0ed26be850
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/view-source-bom-ref.html
@@ -0,0 +1,10 @@
+<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>view-source-bom.html</title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span></span><span class="doctype">&lt;!DOCTYPE html&gt;</span><span>
+<span id="line2"></span></span><span>&lt;<span class="start-tag">html</span>&gt;</span><span>
+<span id="line3"></span></span><span>&lt;<span class="start-tag">head</span>&gt;</span><span>
+<span id="line4"></span> </span><span>&lt;<span class="start-tag">title</span>&gt;</span><span>UTF-8 file with a BOM</span><span>&lt;/<span class="end-tag">title</span>&gt;</span><span>
+<span id="line5"></span></span><span>&lt;/<span class="end-tag">head</span>&gt;</span><span>
+<span id="line6"></span></span><span>&lt;<span class="start-tag">body</span>&gt;</span><span>
+<span id="line7"></span></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>UTF-8 file with a BOM. Euro sign: €</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>
+<span id="line8"></span></span><span>&lt;/<span class="end-tag">body</span>&gt;</span><span>
+<span id="line9"></span></span><span>&lt;/<span class="end-tag">html</span>&gt;</span><span>
+<span id="line10"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/view-source-bom.html b/parser/htmlparser/tests/reftest/view-source-bom.html
new file mode 100644
index 0000000000..d10d94fbee
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/view-source-bom.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>UTF-8 file with a BOM</title>
+</head>
+<body>
+<p>UTF-8 file with a BOM. Euro sign: €</p>
+</body>
+</html>
diff --git a/parser/htmlparser/tests/reftest/vs-after-head-after-1kb-ref.html b/parser/htmlparser/tests/reftest/vs-after-head-after-1kb-ref.html
new file mode 100644
index 0000000000..5a721755b1
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/vs-after-head-after-1kb-ref.html
@@ -0,0 +1,11 @@
+<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>vs-after-head-after-1kb.html</title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span></span><span class="doctype">&lt;!DOCTYPE html&gt;</span><span>
+<span id="line2"></span></span><span>&lt;<span class="start-tag">head</span>&gt;</span><span>
+<span id="line3"></span></span><span>&lt;<span class="start-tag">link</span> <span class="attribute-name">rel</span>="<a class="attribute-value">mismatch</a>" <span class="attribute-name">href</span>="<a class="attribute-value" href="view-source:references/after-head-after-1kb-ref.html">references/after-head-after-1kb-ref.html</a>"&gt;</span><span>
+<span id="line4"></span> </span><span>&lt;/<span class="end-tag">head</span>&gt;</span><span>
+<span id="line5"></span></span><span class="error" title="“meta” element between “head” and “body”.">&lt;<span class="start-tag">meta</span> <span class="attribute-name">charset</span>="<a class="attribute-value">windows-1251</a>"&gt;</span><span>
+<span id="line6"></span></span><span>&lt;<span class="start-tag">body</span>&gt;</span><span>
+<span id="line7"></span></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>After </span><span>&lt;<span class="start-tag">code</span>&gt;</span><span>head</span><span>&lt;/<span class="end-tag">code</span>&gt;</span><span>, before </span><span>&lt;<span class="start-tag">code</span>&gt;</span><span>body</span><span>&lt;/<span class="end-tag">code</span>&gt;</span><span>, after first kilobyte.</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>
+<span id="line8"></span></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Test: ж</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>
+<span id="line9"></span></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>If <span class="entity"><span>&amp;</span>#x0436;</span>, meta takes effect</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>
+<span id="line10"></span></span><span>&lt;/<span class="end-tag">body</span>&gt;</span><span>
+<span id="line11"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/vs-after-head-after-1kb.html b/parser/htmlparser/tests/reftest/vs-after-head-after-1kb.html
new file mode 100644
index 0000000000..6637a2a8c5
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/vs-after-head-after-1kb.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<head>
+<link rel="mismatch" href="references/after-head-after-1kb-ref.html">
+ </head>
+<meta charset="windows-1251">
+<body>
+<p>After <code>head</code>, before <code>body</code>, after first kilobyte.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/vs-after-head-in-1kb-ref.html b/parser/htmlparser/tests/reftest/vs-after-head-in-1kb-ref.html
new file mode 100644
index 0000000000..706c20da6e
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/vs-after-head-in-1kb-ref.html
@@ -0,0 +1,12 @@
+<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>vs-after-head-in-1kb.html</title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span></span><span class="doctype">&lt;!DOCTYPE html&gt;</span><span>
+<span id="line2"></span></span><span>&lt;<span class="start-tag">head</span>&gt;</span><span>
+<span id="line3"></span></span><span>&lt;<span class="start-tag">link</span> <span class="attribute-name">rel</span>="<a class="attribute-value">match</a>" <span class="attribute-name">href</span>="<a class="attribute-value" href="view-source:references/after-head-in-1kb-ref.html">references/after-head-in-1kb-ref.html</a>"&gt;</span><span>
+<span id="line4"></span></span><span>&lt;/<span class="end-tag">head</span>&gt;</span><span>
+<span id="line5"></span>
+<span id="line6"></span></span><span class="error" title="“meta” element between “head” and “body”.">&lt;<span class="start-tag">meta</span> <span class="attribute-name">charset</span>="<a class="attribute-value">windows-1251</a>"&gt;</span><span>
+<span id="line7"></span></span><span>&lt;<span class="start-tag">body</span>&gt;</span><span>
+<span id="line8"></span></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>After </span><span>&lt;<span class="start-tag">code</span>&gt;</span><span>head</span><span>&lt;/<span class="end-tag">code</span>&gt;</span><span>, before </span><span>&lt;<span class="start-tag">code</span>&gt;</span><span>body</span><span>&lt;/<span class="end-tag">code</span>&gt;</span><span>, within first kilobyte.</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>
+<span id="line9"></span></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Test: ж</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>
+<span id="line10"></span></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>If <span class="entity"><span>&amp;</span>#x0436;</span>, meta takes effect</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>
+<span id="line11"></span></span><span>&lt;/<span class="end-tag">body</span>&gt;</span><span>
+<span id="line12"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/vs-after-head-in-1kb.html b/parser/htmlparser/tests/reftest/vs-after-head-in-1kb.html
new file mode 100644
index 0000000000..af63f06acb
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/vs-after-head-in-1kb.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/after-head-in-1kb-ref.html">
+</head>
+
+<meta charset="windows-1251">
+<body>
+<p>After <code>head</code>, before <code>body</code>, within first kilobyte.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before-ref.html b/parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before-ref.html
new file mode 100644
index 0000000000..66f0338658
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before-ref.html
@@ -0,0 +1,12 @@
+<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>vs-non-ascii-in-comment-before.html</title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span></span><span class="doctype">&lt;!DOCTYPE html&gt;</span><span>
+<span id="line2"></span></span><span>&lt;<span class="start-tag">head</span>&gt;</span><span>
+<span id="line3"></span></span><span>&lt;<span class="start-tag">link</span> <span class="attribute-name">rel</span>="<a class="attribute-value">match</a>" <span class="attribute-name">href</span>="<a class="attribute-value" href="view-source:references/non-ascii-in-comment-before-ref.html">references/non-ascii-in-comment-before-ref.html</a>"&gt;</span><span>
+<span id="line4"></span></span><span class="comment">&lt;!-- ж --&gt;</span><span>
+<span id="line5"></span></span><span>&lt;<span class="start-tag">meta</span> <span class="attribute-name">charset</span>="<a class="attribute-value">windows-1251</a>"&gt;</span><span>
+<span id="line6"></span></span><span>&lt;/<span class="end-tag">head</span>&gt;</span><span>
+<span id="line7"></span></span><span>&lt;<span class="start-tag">body</span>&gt;</span><span>
+<span id="line8"></span></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Normal meta. Non-ASCII in comment before.</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>
+<span id="line9"></span></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Test: ж</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>
+<span id="line10"></span></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>If <span class="entity"><span>&amp;</span>#x0436;</span>, meta takes effect</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>
+<span id="line11"></span></span><span>&lt;/<span class="end-tag">body</span>&gt;</span><span>
+<span id="line12"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before.html b/parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before.html
new file mode 100644
index 0000000000..148c6544a3
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<head>
+<link rel="match" href="references/non-ascii-in-comment-before-ref.html">
+<!-- -->
+<meta charset="windows-1251">
+</head>
+<body>
+<p>Normal meta. Non-ASCII in comment before.</p>
+<p>Test: </p>
+<p>If &#x0436;, meta takes effect</p>
+</body>
diff --git a/parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before.sjs b/parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before.sjs
new file mode 100644
index 0000000000..12b1919ff8
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/vs-non-ascii-in-comment-before.sjs
@@ -0,0 +1,16 @@
+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('<!DOCTYPE html>\n<head>\n<link rel="match" href="references/non-ascii-in-comment-before-ref.html">\n<!-- \u00E6 -->\n');
+ response.bodyOutputStream.flush();
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.write('<meta charset="windows-1251">\n</head>\n<body>\n<p>Normal meta. Non-ASCII in comment before.</p>\n<p>Test: \u00E6</p>\n<p>If &#x0436;, meta takes effect</p>\n</body>\n');
+ response.finish();
+ }, 10, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
diff --git a/parser/htmlparser/tests/reftest/xml-1.xml b/parser/htmlparser/tests/reftest/xml-1.xml
new file mode 100644
index 0000000000..a6ac350ad3
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/xml-1.xml
@@ -0,0 +1 @@
+<?xml version='1.0' encoding='windows-1251'?><root></root>
diff --git a/parser/htmlparser/tests/reftest/xml-ref.html b/parser/htmlparser/tests/reftest/xml-ref.html
new file mode 100644
index 0000000000..3bf58fb763
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/xml-ref.html
@@ -0,0 +1,2 @@
+<html><meta charset="utf-8"><head><meta name="viewport" content="width=device-width"><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span></span><span class="pi">&lt;?xml version='1.0' encoding='windows-1251'?&gt;</span><span></span><span>&lt;<span class="start-tag">root</span>&gt;</span><span>ж</span><span>&lt;/<span class="end-tag">root</span>&gt;</span><span>
+<span id="line2"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/xml-trickle-1.sjs b/parser/htmlparser/tests/reftest/xml-trickle-1.sjs
new file mode 100644
index 0000000000..eaec0e37fc
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/xml-trickle-1.sjs
@@ -0,0 +1,17 @@
+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", "application/xml", false);
+ response.write("<");
+ response.bodyOutputStream.flush();
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.write("?xml version='1.0' encoding='windows-1251'?><root>\u00E6</root>\n");
+ response.finish();
+ }, 10, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
+
diff --git a/parser/htmlparser/tests/reftest/xml-trickle-2.sjs b/parser/htmlparser/tests/reftest/xml-trickle-2.sjs
new file mode 100644
index 0000000000..04c1354fa3
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/xml-trickle-2.sjs
@@ -0,0 +1,17 @@
+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", "application/xml", false);
+ response.write("<?");
+ response.bodyOutputStream.flush();
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.write("xml version='1.0' encoding='windows-1251'?><root>\u00E6</root>\n");
+ response.finish();
+ }, 10, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
+
diff --git a/parser/htmlparser/tests/reftest/xml-trickle-3.sjs b/parser/htmlparser/tests/reftest/xml-trickle-3.sjs
new file mode 100644
index 0000000000..e601f69038
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/xml-trickle-3.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", "application/xml", false);
+ response.write("<?");
+ response.bodyOutputStream.flush();
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.write("xml");
+ response.bodyOutputStream.flush();
+ timer.initWithCallback(function() {
+ response.write(" version='1.0' encoding='windows-1251'?><root>\u00E6</root>\n");
+ response.finish();
+ }, 10, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+ }, 10, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
+
diff --git a/parser/htmlparser/tests/reftest/xml-trickle-4.sjs b/parser/htmlparser/tests/reftest/xml-trickle-4.sjs
new file mode 100644
index 0000000000..0ac01d84da
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/xml-trickle-4.sjs
@@ -0,0 +1,17 @@
+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", "application/xml", false);
+ response.write("<");
+ response.bodyOutputStream.flush();
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.write("?xml version='1.0'?><root>\u00D0\u00B6</root>\n");
+ response.finish();
+ }, 10, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
+
diff --git a/parser/htmlparser/tests/reftest/xml-trickle-5.sjs b/parser/htmlparser/tests/reftest/xml-trickle-5.sjs
new file mode 100644
index 0000000000..815295ac30
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/xml-trickle-5.sjs
@@ -0,0 +1,17 @@
+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", "application/xml", false);
+ response.write("<?");
+ response.bodyOutputStream.flush();
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.write("xml version='1.0'?><root>\u00D0\u00B6</root>\n");
+ response.finish();
+ }, 10, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
+
diff --git a/parser/htmlparser/tests/reftest/xml-trickle-6.sjs b/parser/htmlparser/tests/reftest/xml-trickle-6.sjs
new file mode 100644
index 0000000000..9e96687d19
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/xml-trickle-6.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", "application/xml", false);
+ response.write("<?");
+ response.bodyOutputStream.flush();
+ response.processAsync();
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.write("xml");
+ response.bodyOutputStream.flush();
+ timer.initWithCallback(function() {
+ response.write(" version='1.0'?><root>\u00D0\u00B6</root>\n");
+ response.finish();
+ }, 10, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+ }, 10, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
+
diff --git a/parser/htmlparser/tests/reftest/xml-utf-ref.html b/parser/htmlparser/tests/reftest/xml-utf-ref.html
new file mode 100644
index 0000000000..98a3100b24
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/xml-utf-ref.html
@@ -0,0 +1,2 @@
+<html><meta charset="utf-8"><head><meta name="viewport" content="width=device-width"><title></title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span></span><span class="pi">&lt;?xml version='1.0'?&gt;</span><span></span><span>&lt;<span class="start-tag">root</span>&gt;</span><span>ж</span><span>&lt;/<span class="end-tag">root</span>&gt;</span><span>
+<span id="line2"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/xml-without-tags-ref.html b/parser/htmlparser/tests/reftest/xml-without-tags-ref.html
new file mode 100644
index 0000000000..d853e67634
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/xml-without-tags-ref.html
@@ -0,0 +1,2 @@
+<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>xml-without-tags.xml</title><link rel="stylesheet" type="text/css" href="resource://content-accessible/viewsource.css"></head><body id="viewsource" class="highlight" style="tab-size: 4"><pre id="line1"><span>ill-formed
+<span id="line2"></span></span></pre></body></html>
diff --git a/parser/htmlparser/tests/reftest/xml-without-tags.xml b/parser/htmlparser/tests/reftest/xml-without-tags.xml
new file mode 100644
index 0000000000..ddc2f2135d
--- /dev/null
+++ b/parser/htmlparser/tests/reftest/xml-without-tags.xml
@@ -0,0 +1 @@
+ill-formed