LibXML+LibWeb: Use existing HTML entities table for XML parsing too
For XHTML documents, resolve named character entities (e.g., ) using the HTML entity table via a getEntity SAX callback. This avoids parsing a large embedded DTD on every document and matches the approach used by Blink and WebKit. This also removes the now-unused DTD infrastructure: - Remove resolve_external_resource callback from Parser::Options - Remove resolve_xml_resource() function and its ~60KB embedded DTD - Remove all call sites passing the unused callback
This commit is contained in:
parent
35bb1e20ee
commit
1b41659efd
43 changed files with 28321 additions and 55 deletions
|
|
@ -56,7 +56,7 @@ bool build_xml_document(DOM::Document& document, ByteBuffer const& data, Optiona
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto source = decoder->to_utf8(data).release_value_but_fixme_should_propagate_errors();
|
auto source = decoder->to_utf8(data).release_value_but_fixme_should_propagate_errors();
|
||||||
XML::Parser parser(source, { .resolve_external_resource = resolve_xml_resource });
|
XML::Parser parser(source, { .resolve_named_html_entity = resolve_named_html_entity });
|
||||||
XMLDocumentBuilder builder { document };
|
XMLDocumentBuilder builder { document };
|
||||||
auto result = parser.parse_with_listener(builder);
|
auto result = parser.parse_with_listener(builder);
|
||||||
return !result.is_error() && !builder.has_error();
|
return !result.is_error() && !builder.has_error();
|
||||||
|
|
@ -189,7 +189,7 @@ static WebIDL::ExceptionOr<GC::Ref<DOM::Document>> load_xml_document(HTML::Navig
|
||||||
}
|
}
|
||||||
// NB: If document is part of session history traversal, resolve the signal_to_continue_session_history_processing.
|
// NB: If document is part of session history traversal, resolve the signal_to_continue_session_history_processing.
|
||||||
signal_to_continue_session_history_processing->resolve({});
|
signal_to_continue_session_history_processing->resolve({});
|
||||||
XML::Parser parser(source.value(), { .preserve_cdata = true, .preserve_comments = true, .resolve_external_resource = resolve_xml_resource });
|
XML::Parser parser(source.value(), { .preserve_cdata = true, .preserve_comments = true, .resolve_named_html_entity = resolve_named_html_entity });
|
||||||
XMLDocumentBuilder builder { document };
|
XMLDocumentBuilder builder { document };
|
||||||
auto result = parser.parse_with_listener(builder);
|
auto result = parser.parse_with_listener(builder);
|
||||||
if (result.is_error()) {
|
if (result.is_error()) {
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ WebIDL::ExceptionOr<GC::Root<DOM::Document>> DOMParser::parse_from_string(Truste
|
||||||
|
|
||||||
// 1. Create an XML parser parse, associated with document, and with XML scripting support disabled.
|
// 1. Create an XML parser parse, associated with document, and with XML scripting support disabled.
|
||||||
auto const utf8_complaint_string = compliant_string.to_utf8_but_should_be_ported_to_utf16();
|
auto const utf8_complaint_string = compliant_string.to_utf8_but_should_be_ported_to_utf16();
|
||||||
XML::Parser parser(utf8_complaint_string, { .resolve_external_resource = resolve_xml_resource });
|
XML::Parser parser(utf8_complaint_string, { .resolve_named_html_entity = resolve_named_html_entity });
|
||||||
XMLDocumentBuilder builder { *document, XMLScriptingSupport::Disabled };
|
XMLDocumentBuilder builder { *document, XMLScriptingSupport::Disabled };
|
||||||
// 2. Parse compliantString using parser.
|
// 2. Parse compliantString using parser.
|
||||||
auto result = parser.parse_with_listener(builder);
|
auto result = parser.parse_with_listener(builder);
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ ErrorOr<GC::Ref<SVGDecodedImageData>> SVGDecodedImageData::create(JS::Realm& rea
|
||||||
auto& window = as<HTML::Window>(HTML::relevant_global_object(document));
|
auto& window = as<HTML::Window>(HTML::relevant_global_object(document));
|
||||||
document->browsing_context()->window_proxy()->set_window(window);
|
document->browsing_context()->window_proxy()->set_window(window);
|
||||||
|
|
||||||
XML::Parser parser(data, { .resolve_external_resource = resolve_xml_resource });
|
XML::Parser parser(data, { .resolve_named_html_entity = resolve_named_html_entity });
|
||||||
XMLDocumentBuilder builder { document };
|
XMLDocumentBuilder builder { document };
|
||||||
auto result = parser.parse_with_listener(builder);
|
auto result = parser.parse_with_listener(builder);
|
||||||
(void)result;
|
(void)result;
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -21,7 +21,7 @@ enum class XMLScriptingSupport {
|
||||||
Enabled,
|
Enabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
ErrorOr<Variant<ByteString, Vector<XML::MarkupDeclaration>>> resolve_xml_resource(XML::SystemID const&, Optional<XML::PublicID> const&);
|
Optional<String> resolve_named_html_entity(StringView entity_name);
|
||||||
|
|
||||||
class XMLDocumentBuilder final : public XML::Listener {
|
class XMLDocumentBuilder final : public XML::Listener {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ WebIDL::ExceptionOr<Vector<GC::Root<DOM::Node>>> XMLFragmentParser::parse_xml_fr
|
||||||
if (allow_declarative_shadow_roots == HTML::HTMLParser::AllowDeclarativeShadowRoots::Yes)
|
if (allow_declarative_shadow_roots == HTML::HTMLParser::AllowDeclarativeShadowRoots::Yes)
|
||||||
document->set_allow_declarative_shadow_roots(true);
|
document->set_allow_declarative_shadow_roots(true);
|
||||||
|
|
||||||
XML::Parser parser(feed.string_view());
|
XML::Parser parser(feed.string_view(), { .resolve_named_html_entity = resolve_named_html_entity });
|
||||||
XMLDocumentBuilder builder { *document, XMLScriptingSupport::Disabled };
|
XMLDocumentBuilder builder { *document, XMLScriptingSupport::Disabled };
|
||||||
auto result = parser.parse_with_listener(builder);
|
auto result = parser.parse_with_listener(builder);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ struct ParserContext {
|
||||||
|
|
||||||
Vector<ParseError> parse_errors;
|
Vector<ParseError> parse_errors;
|
||||||
|
|
||||||
|
Parser::Options const* options { nullptr };
|
||||||
|
bool is_xhtml_document { false };
|
||||||
int depth { 0 };
|
int depth { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -53,6 +55,82 @@ static StringView xml_char_to_string_view(xmlChar const* str)
|
||||||
return StringView(reinterpret_cast<char const*>(str), strlen(reinterpret_cast<char const*>(str)));
|
return StringView(reinterpret_cast<char const*>(str), strlen(reinterpret_cast<char const*>(str)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_known_xhtml_public_id(StringView public_id)
|
||||||
|
{
|
||||||
|
return public_id.is_one_of(
|
||||||
|
"-//W3C//DTD XHTML 1.0 Transitional//EN"sv,
|
||||||
|
"-//W3C//DTD XHTML 1.1//EN"sv,
|
||||||
|
"-//W3C//DTD XHTML 1.0 Strict//EN"sv,
|
||||||
|
"-//W3C//DTD XHTML 1.0 Frameset//EN"sv,
|
||||||
|
"-//W3C//DTD XHTML Basic 1.0//EN"sv,
|
||||||
|
"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN"sv,
|
||||||
|
"-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"sv,
|
||||||
|
"-//W3C//DTD MathML 2.0//EN"sv,
|
||||||
|
"-//WAPFORUM//DTD XHTML Mobile 1.0//EN"sv,
|
||||||
|
"-//WAPFORUM//DTD XHTML Mobile 1.1//EN"sv,
|
||||||
|
"-//WAPFORUM//DTD XHTML Mobile 1.2//EN"sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void external_subset_handler(void* ctx, xmlChar const*, xmlChar const* external_id, xmlChar const*)
|
||||||
|
{
|
||||||
|
auto* parser_ctx = static_cast<xmlParserCtxtPtr>(ctx);
|
||||||
|
auto* context = static_cast<ParserContext*>(parser_ctx->_private);
|
||||||
|
if (!context || !external_id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto public_id = xml_char_to_string_view(external_id);
|
||||||
|
if (is_known_xhtml_public_id(public_id))
|
||||||
|
context->is_xhtml_document = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xmlEntity s_xhtml_entity_result;
|
||||||
|
static char s_xhtml_entity_utf8_buffer[32];
|
||||||
|
|
||||||
|
static xmlEntityPtr get_entity_handler(void* ctx, xmlChar const* name)
|
||||||
|
{
|
||||||
|
auto* parser_ctx = static_cast<xmlParserCtxtPtr>(ctx);
|
||||||
|
|
||||||
|
auto* predefined = xmlGetPredefinedEntity(name);
|
||||||
|
if (predefined)
|
||||||
|
return predefined;
|
||||||
|
|
||||||
|
if (parser_ctx->myDoc) {
|
||||||
|
auto* doc_entity = xmlGetDocEntity(parser_ctx->myDoc, name);
|
||||||
|
if (doc_entity)
|
||||||
|
return doc_entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* context = static_cast<ParserContext*>(parser_ctx->_private);
|
||||||
|
if (!context || !context->is_xhtml_document)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// For XHTML documents, resolve named character entities (e.g., ) using the
|
||||||
|
// HTML entity table. This avoids parsing a large embedded DTD on every document
|
||||||
|
// and matches the approach used by Blink and WebKit.
|
||||||
|
if (!context->options || !context->options->resolve_named_html_entity)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto entity_name = xml_char_to_string_view(name);
|
||||||
|
auto resolved = context->options->resolve_named_html_entity(entity_name);
|
||||||
|
if (!resolved.has_value())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto utf8_bytes = resolved->bytes_as_string_view();
|
||||||
|
if (utf8_bytes.length() >= sizeof(s_xhtml_entity_utf8_buffer))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
(void)utf8_bytes.copy_characters_to_buffer(s_xhtml_entity_utf8_buffer, sizeof(s_xhtml_entity_utf8_buffer));
|
||||||
|
|
||||||
|
s_xhtml_entity_result = {};
|
||||||
|
s_xhtml_entity_result.type = XML_ENTITY_DECL;
|
||||||
|
s_xhtml_entity_result.name = name;
|
||||||
|
s_xhtml_entity_result.content = reinterpret_cast<xmlChar*>(s_xhtml_entity_utf8_buffer);
|
||||||
|
s_xhtml_entity_result.length = static_cast<int>(utf8_bytes.length());
|
||||||
|
s_xhtml_entity_result.etype = XML_INTERNAL_PREDEFINED_ENTITY;
|
||||||
|
|
||||||
|
return &s_xhtml_entity_result;
|
||||||
|
}
|
||||||
|
|
||||||
static void start_document_handler(void* ctx)
|
static void start_document_handler(void* ctx)
|
||||||
{
|
{
|
||||||
auto* parser_ctx = static_cast<xmlParserCtxtPtr>(ctx);
|
auto* parser_ctx = static_cast<xmlParserCtxtPtr>(ctx);
|
||||||
|
|
@ -345,7 +423,7 @@ static void structured_error_handler(void* ctx, xmlError const* error)
|
||||||
context->error = move(parse_error);
|
context->error = move(parse_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static xmlSAXHandler create_sax_handler(bool preserve_comments)
|
static xmlSAXHandler create_sax_handler(bool preserve_comments, bool resolve_html_entities)
|
||||||
{
|
{
|
||||||
xmlSAXHandler handler = {};
|
xmlSAXHandler handler = {};
|
||||||
handler.initialized = XML_SAX2_MAGIC;
|
handler.initialized = XML_SAX2_MAGIC;
|
||||||
|
|
@ -360,6 +438,10 @@ static xmlSAXHandler create_sax_handler(bool preserve_comments)
|
||||||
handler.serror = structured_error_handler;
|
handler.serror = structured_error_handler;
|
||||||
if (preserve_comments)
|
if (preserve_comments)
|
||||||
handler.comment = comment_handler;
|
handler.comment = comment_handler;
|
||||||
|
if (resolve_html_entities) {
|
||||||
|
handler.externalSubset = external_subset_handler;
|
||||||
|
handler.getEntity = get_entity_handler;
|
||||||
|
}
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -371,8 +453,10 @@ ErrorOr<void, ParseError> Parser::parse_with_listener(Listener& listener)
|
||||||
|
|
||||||
ParserContext context;
|
ParserContext context;
|
||||||
context.listener = &listener;
|
context.listener = &listener;
|
||||||
|
context.options = &m_options;
|
||||||
|
|
||||||
auto sax_handler = create_sax_handler(m_options.preserve_comments);
|
bool resolve_html_entities = static_cast<bool>(m_options.resolve_named_html_entity);
|
||||||
|
auto sax_handler = create_sax_handler(m_options.preserve_comments, resolve_html_entities);
|
||||||
|
|
||||||
int options = XML_PARSE_NONET | XML_PARSE_NOWARNING;
|
int options = XML_PARSE_NONET | XML_PARSE_NOWARNING;
|
||||||
if (!m_options.preserve_cdata)
|
if (!m_options.preserve_cdata)
|
||||||
|
|
@ -412,8 +496,10 @@ ErrorOr<void, ParseError> Parser::parse_with_listener(Listener& listener)
|
||||||
ErrorOr<Document, ParseError> Parser::parse()
|
ErrorOr<Document, ParseError> Parser::parse()
|
||||||
{
|
{
|
||||||
ParserContext context;
|
ParserContext context;
|
||||||
|
context.options = &m_options;
|
||||||
|
|
||||||
auto sax_handler = create_sax_handler(m_options.preserve_comments);
|
bool resolve_html_entities = static_cast<bool>(m_options.resolve_named_html_entity);
|
||||||
|
auto sax_handler = create_sax_handler(m_options.preserve_comments, resolve_html_entities);
|
||||||
|
|
||||||
int options = XML_PARSE_NONET | XML_PARSE_NOWARNING;
|
int options = XML_PARSE_NONET | XML_PARSE_NOWARNING;
|
||||||
if (!m_options.preserve_cdata)
|
if (!m_options.preserve_cdata)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <AK/GenericLexer.h>
|
#include <AK/GenericLexer.h>
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
|
#include <AK/Optional.h>
|
||||||
#include <AK/OwnPtr.h>
|
#include <AK/OwnPtr.h>
|
||||||
|
#include <AK/String.h>
|
||||||
#include <LibXML/DOM/Document.h>
|
#include <LibXML/DOM/Document.h>
|
||||||
#include <LibXML/DOM/DocumentTypeDeclaration.h>
|
#include <LibXML/DOM/DocumentTypeDeclaration.h>
|
||||||
#include <LibXML/DOM/Node.h>
|
#include <LibXML/DOM/Node.h>
|
||||||
|
|
@ -51,7 +53,7 @@ public:
|
||||||
bool preserve_cdata { true };
|
bool preserve_cdata { true };
|
||||||
bool preserve_comments { false };
|
bool preserve_comments { false };
|
||||||
bool treat_errors_as_fatal { true };
|
bool treat_errors_as_fatal { true };
|
||||||
Function<ErrorOr<Variant<ByteString, Vector<MarkupDeclaration>>>(SystemID const&, Optional<PublicID> const&)> resolve_external_resource {};
|
Function<Optional<String>(StringView)> resolve_named_html_entity {};
|
||||||
};
|
};
|
||||||
|
|
||||||
Parser(StringView source, Options options)
|
Parser(StringView source, Options options)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!doctype html>
|
||||||
|
<title>Test reference</title>
|
||||||
|
<style>
|
||||||
|
html, body { margin: 0 }
|
||||||
|
</style>
|
||||||
|
<iframe src="about:blank"></iframe>
|
||||||
|
<div>
|
||||||
|
PASS
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
Test passes if it correctly shows Á in the subframe.
|
||||||
|
<hr>
|
||||||
|
<iframe srcdoc="&Aacute"></iframe>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<!doctype html>
|
||||||
|
<title>Appending from the parser after adopting in an XML document doesn't miss notifications</title>
|
||||||
|
<link rel="match" href="../../../../../expected/wpt-import/html/the-xhtml-syntax/parsing-xhtml-documents/adopt-while-parsing-001-ref.html">
|
||||||
|
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1511329">
|
||||||
|
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||||
|
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||||
|
<style>
|
||||||
|
html, body { margin: 0 }
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
// If we don't get notified of the <div> insertion, the PASS text will never appear.
|
||||||
|
function parsingInterrupted() {
|
||||||
|
let frameDoc = document.querySelector("iframe").contentDocument;
|
||||||
|
let root = frameDoc.documentElement;
|
||||||
|
document.documentElement.appendChild(root);
|
||||||
|
root.offsetTop;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<iframe src="support/adopt-while-parsing.xhtml"></iframe>
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
-->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>
|
||||||
|
Test that an XHTML document with a data: URL still handles the XHTML DTD
|
||||||
|
properly even if the DTD URL is given as a relative URL.
|
||||||
|
</title>
|
||||||
|
<link rel="author" title="Boris Zbarsky" href="bzbarsky@mit.edu">
|
||||||
|
<link rel="match" href="../../../../../expected/wpt-import/html/the-xhtml-syntax/parsing-xhtml-documents/data-xhtml-with-dtd-ref.html">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Test passes if it correctly shows Á in the subframe.
|
||||||
|
<hr>
|
||||||
|
<!-- Document in the subframe is:
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<body>
|
||||||
|
Á
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
-->
|
||||||
|
<iframe src='data:application/xml,%3C%3Fxml%20version%3D%221.0%22%3F%3E%0A%3C!DOCTYPE%20html%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20XHTML%201.0%20Strict%2F%2FEN%22%20%22DTD%2Fxhtml1-strict.dtd%22%3E%0A%3Chtml%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%3E%0A%20%20%3Cbody%3E%0A%20%20%20%20%26Aacute%3B%0A%20%20%3C%2Fbody%3E%0A%3C%2Fhtml%3E%0A'></iframe>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
window.parent.parsingInterrupted();
|
||||||
|
</script>
|
||||||
|
<div>
|
||||||
|
PASS
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,6 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Fail
|
||||||
|
Fail xml-stylesheet blocks script execution and rendering
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1 @@
|
||||||
|
:root { z-index: 3 }
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<script>
|
||||||
|
var parser = new DOMParser();
|
||||||
|
var parse = parser.parseFromString.bind(parser);
|
||||||
|
|
||||||
|
function generateTestFunction(entitystring, expectedString, publicId, systemId, mimeType, friendlyMime) {
|
||||||
|
return function () {
|
||||||
|
var doctypeString = '<!DOCTYPE html';
|
||||||
|
if (publicId != null)
|
||||||
|
doctypeString += ' PUBLIC "' + publicId + '" "' + systemId + '">';
|
||||||
|
else if (systemId != null)
|
||||||
|
doctypeString += ' SYSTEM "' + systemId + '">';
|
||||||
|
else // both are null
|
||||||
|
doctypeString += '>';
|
||||||
|
var doc = parse(doctypeString + "<html><head></head><body id='test'>"+entitystring+"</body></html>", mimeType);
|
||||||
|
var root = doc.getElementById('test');
|
||||||
|
parent.assert_not_equals(root, null, friendlyMime + " parsing the entity reference caused a parse error;");
|
||||||
|
parent.assert_true(!!root.firstChild);
|
||||||
|
// Next line because some browsers include the partial parsed result in the parser error returned document.
|
||||||
|
parent.assert_equals(root.firstChild.nodeType, 3/*Text*/, friendlyMime + " parsing the entity reference caused a parse error;");
|
||||||
|
var text = root.firstChild.data;
|
||||||
|
for (var i = 0, len = expectedString.length; i < len; i++) {
|
||||||
|
parent.assert_equals(text.charCodeAt(i),expectedString.charCodeAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupTests(jsonEntities, publicId, systemId, mimeType, friendlyMime) {
|
||||||
|
for (entityName in jsonEntities) {
|
||||||
|
if ((mimeType == "text/html") || /;$/.test(entityName)) {
|
||||||
|
parent.test(generateTestFunction(entityName, jsonEntities[entityName].characters, publicId, systemId, mimeType, friendlyMime), friendlyMime + " parsing " + entityName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.setup(function() {}, {explicit_done: true});
|
||||||
|
|
||||||
|
function run(row) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open("GET", "entities.json");
|
||||||
|
xhr.onload = function () {
|
||||||
|
var entitiesJSON = JSON.parse(xhr.response);
|
||||||
|
setupTests(entitiesJSON, row[1], row[2], row[0], row[3]);
|
||||||
|
parent.done();
|
||||||
|
}
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["application/xhtml+xml", "-//W3C//DTD XHTML 1.0 Transitional//EN", "foo", "XHTML1.0 Transitional"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["text/html", null, null, "HTML"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["application/xhtml+xml", "-//WAPFORUM//DTD XHTML Mobile 1.1//EN", "foo", "XHTML Mobile 1.1"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["application/xhtml+xml", "-//WAPFORUM//DTD XHTML Mobile 1.2//EN", "foo", "XHTML Mobile 1.2"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["application/xhtml+xml", "-//W3C//DTD XHTML 1.1//EN", "foo", "XHTML1.1"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["application/xhtml+xml", "-//W3C//DTD XHTML 1.0 Strict//EN", "foo", "XHTML1.0 Strict"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["application/xhtml+xml", "-//W3C//DTD XHTML 1.0 Frameset//EN", "foo", "XHTML1.0 Frameset"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["application/xhtml+xml", "-//W3C//DTD XHTML Basic 1.0//EN", "foo", "XHTML Basic"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["application/xhtml+xml", "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN", "foo", "XHTML1.1+MathML"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["application/xhtml+xml", "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN", "foo", "XHTML1.1+MathML+SVG"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["application/xhtml+xml", "-//W3C//DTD MathML 2.0//EN", "foo", "MathML"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<title>HTML entities for various XHTML Doctype</title>
|
||||||
|
<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents">
|
||||||
|
|
||||||
|
<script src="../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../resources/testharnessreport.js"></script>
|
||||||
|
<iframe id="test" src="support/xhtml-mathml-dtd-entity.htm"></iframe>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
onload = () => document.getElementById("test").contentWindow.run(
|
||||||
|
["application/xhtml+xml", "-//WAPFORUM//DTD XHTML Mobile 1.0//EN", "foo", "XHTML Mobile"]);
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<?xml-stylesheet type="text/css" href="support/simple-style.css?pipe=trickle(d2)"?>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<script><![CDATA[
|
||||||
|
window.observedZIndex = getComputedStyle(document.documentElement).zIndex;
|
||||||
|
]]></script>
|
||||||
|
<title>xml-stylesheet blocks script execution and rendering</title>
|
||||||
|
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1986042" />
|
||||||
|
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io" />
|
||||||
|
<link rel="author" title="Mozilla" href="https://mozilla.org" />
|
||||||
|
<script src="../../../resources/testharness.js"/>
|
||||||
|
<script src="../../../resources/testharnessreport.js"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script><![CDATA[
|
||||||
|
test(function() {
|
||||||
|
assert_equals(window.observedZIndex, "3", "XML processing instruction should've blocked script execution and rendering");
|
||||||
|
});
|
||||||
|
]]></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -362,18 +362,6 @@ static auto parse(StringView contents)
|
||||||
contents,
|
contents,
|
||||||
{
|
{
|
||||||
.preserve_comments = true,
|
.preserve_comments = true,
|
||||||
.resolve_external_resource = [&](XML::SystemID const& system_id, Optional<XML::PublicID> const&) -> ErrorOr<Variant<ByteString, Vector<XML::MarkupDeclaration>>> {
|
|
||||||
auto base = URL::create_with_file_scheme(s_path);
|
|
||||||
auto url = URL::Parser::basic_parse(system_id.system_literal, base);
|
|
||||||
if (!url.has_value())
|
|
||||||
return Error::from_string_literal("Invalid URL");
|
|
||||||
|
|
||||||
if (url->scheme() != "file")
|
|
||||||
return Error::from_string_literal("NYI: Nonlocal entity");
|
|
||||||
|
|
||||||
auto file = TRY(Core::File::open(URL::percent_decode(url->serialize_path()), Core::File::OpenMode::Read));
|
|
||||||
return ByteString::copy(TRY(file->read_until_eof()));
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue