Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion moli-benchmark/wpt-cross-current/failed-cases.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2730,7 +2730,6 @@ dom/ranges/tentative/OpaqueRange-range-updates.html
dom/ranges/tentative/OpaqueRange-supported-elements.html
dom/ranges/tentative/OpaqueRange-unsupported-elements.html
dom/ranges/tentative/OpaqueRange-validation.html
domparsing/DOMParser-parseFromString-html.html
domparsing/DOMParser-parseFromString-url-base-pushstate.html
domparsing/DOMParser-parseFromString-url-base.html
domparsing/DOMParser-parseFromString-url-moretests.html
Expand Down
1 change: 1 addition & 0 deletions moli-benchmark/wpt-cross-current/passed-cases.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3608,6 +3608,7 @@ dom/traversal/TreeWalker.html
dom/window-extends-event-target.html
dom/xpath-result-single-node-value-nullable.html
domparsing/DOMParser-parseFromString-encoding.html
domparsing/DOMParser-parseFromString-html.html
domparsing/DOMParser-parseFromString-stylesheets.html
domparsing/createContextualFragment.html
domparsing/domparser-spurious-attributes.html
Expand Down
19 changes: 19 additions & 0 deletions moli-dom/src/native/host/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,25 @@ impl DomHost {
true
}

pub fn set_document_quirks_mode_for_handle(
&mut self,
document_handle: DomHandle,
quirks_mode: selectors::matching::QuirksMode,
) -> bool {
let Some(document) = self
.node_mut(document_handle)
.and_then(|node| node.data_mut().as_document_mut())
else {
return false;
};
if document.quirks_mode() == quirks_mode {
return false;
}
document.set_quirks_mode(quirks_mode);
self.record_mutation(MutationScope::QueryState);
true
}

pub fn set_document_default_language_for_handle(
&mut self,
document_handle: DomHandle,
Expand Down
24 changes: 12 additions & 12 deletions moli-parser/src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ use super::{
ParserYield,
},
live_target::{ParserRuntimeDomSinks, ParserStreamHtmlTreeSinkTarget},
session::{HtmlParserSession, HtmlParserSessionResult, new_html_tree_sink_session},
session::{
HtmlParserSession, HtmlParserSessionResult, HtmlTreeSinkSession, new_html_tree_sink_session,
},
};

pub(super) struct HtmlTreeSinkStream {
Expand Down Expand Up @@ -424,11 +426,7 @@ pub(crate) fn prepare_parser_script_handoff_for_static_document(
}

impl HtmlTreeSinkStream {
pub(super) fn from_target_with_scripting(
target: ParserStreamHtmlTreeSinkTarget,
scripting_enabled: bool,
) -> Self {
let session = new_html_tree_sink_session(target, scripting_enabled);
fn from_session(session: HtmlTreeSinkSession) -> Self {
Self {
parser: session.parser,
script_input: session.script_input,
Expand All @@ -437,6 +435,13 @@ impl HtmlTreeSinkStream {
}
}

pub(super) fn from_target_with_scripting(
target: ParserStreamHtmlTreeSinkTarget,
scripting_enabled: bool,
) -> Self {
Self::from_session(new_html_tree_sink_session(target, scripting_enabled))
}

#[cfg(any(test, feature = "test-support"))]
pub(super) fn from_fragment_target(
target: ParserStreamHtmlTreeSinkTarget,
Expand All @@ -452,12 +457,7 @@ impl HtmlTreeSinkStream {
context_local_name,
scripting_enabled,
);
Self {
parser: session.parser,
script_input: session.script_input,
parser_script_positions: HashMap::new(),
next_parser_script_position: 0,
}
Self::from_session(session)
}

fn parser_script_position(&mut self, node_id: NativeNodeId) -> usize {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,19 @@ pub(crate) fn build_detached_document_object_from_dom_host_with_content_type<'s>
character_set: Option<&str>,
) -> Option<v8::Local<'s, v8::Object>> {
let url = detached_document_url(&parsed);
let quirks_mode = parsed.dom().document()?.quirks_mode();
let compat_mode = if quirks_mode == selectors::matching::QuirksMode::Quirks {
"BackCompat"
} else {
"CSS1Compat"
};
let document = new_detached_document_shell(scope, kind, url)?;
if let Some(state) = detached_state_object(scope, document) {
let _ = state.set(
scope,
v8str(scope, "compatMode").into(),
v8_string(scope, compat_mode)?.into(),
);
if let Some(content_type) = content_type {
let _ = state.set(
scope,
Expand All @@ -212,6 +223,13 @@ pub(crate) fn build_detached_document_object_from_dom_host_with_content_type<'s>
);
}
}
if let Some(document_handle) = detached_native_handle(scope, document)
&& let Some(runtime_ptr) = context_host_ptr_from_global_bridge(scope)
{
let _ = unsafe { &mut *runtime_ptr }
.dom_host_mut()
.set_document_quirks_mode_for_handle(document_handle, quirks_mode);
}
import_detached_document_children_from_host(scope, document, &parsed)?;
Some(document)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,14 @@ pub(in crate::native_bridge) fn bridge_detached_document_character_set_callback<

pub(in crate::native_bridge) fn bridge_detached_document_compat_mode_callback<'a>(
scope: &mut v8::PinScope<'a, '_>,
_args: v8::FunctionCallbackArguments<'a>,
args: v8::FunctionCallbackArguments<'a>,
mut rv: v8::ReturnValue<'_, v8::Value>,
) {
set_string_return_value(scope, &mut rv, "CSS1Compat");
let compat_mode = v8::Local::<v8::Object>::try_from(args.get(0))
.ok()
.map(|document| detached_document_state_string(scope, document, "compatMode", "CSS1Compat"))
.unwrap_or_else(|| "CSS1Compat".to_owned());
set_string_return_value(scope, &mut rv, &compat_mode);
}

pub(in crate::native_bridge) fn bridge_detached_document_referrer_callback<'a>(
Expand Down
38 changes: 38 additions & 0 deletions moli-renderer-v8/src/script_vm/tests/dom_elements/detached.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,44 @@ fn adopted_xml_cdata_uses_html_fragment_serialization() {
);
}

#[test]
fn domparser_html_preserves_quirks_mode_and_parses_with_scripting_disabled() {
let mut vm = new_storage_test_vm("https://domparser-html-mode.test/");

let result = vm
.eval(
r#"
(() => {
const parser = new DOMParser();
const quirks = parser.parseFromString(
"<html><head></head><body></body></html>",
"text/html"
);
const standards = parser.parseFromString(
"<!doctype html><html><head></head><body></body></html>",
"text/html"
);
const noscript = parser.parseFromString(
"<body><noscript><p id='first'></p><p id='second'></p></noscript></body>",
"text/html"
);
return JSON.stringify({
quirks: quirks.compatMode,
standards: standards.compatMode,
noscriptChildren: Array.from(noscript.querySelector("noscript").children)
.map(element => element.id)
});
})()
"#,
)
.expect("DOMParser HTML parse mode probe should evaluate");

assert_eq!(
result,
r#"{"quirks":"BackCompat","standards":"CSS1Compat","noscriptChildren":["first","second"]}"#
);
}

#[test]
fn detached_query_brand_checks_accept_standard_prototype_methods() {
let mut vm = new_storage_test_vm("https://detached-query-brand-check.test/");
Expand Down
Loading