diff --git a/moli-dom/src/native/host/document.rs b/moli-dom/src/native/host/document.rs index 8456f9b278..6b20b7330d 100644 --- a/moli-dom/src/native/host/document.rs +++ b/moli-dom/src/native/host/document.rs @@ -1227,6 +1227,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, diff --git a/moli-renderer-v8/src/native_bridge/document/detached_objects/builders/documents.rs b/moli-renderer-v8/src/native_bridge/document/detached_objects/builders/documents.rs index 918c7053d2..1930be84ea 100644 --- a/moli-renderer-v8/src/native_bridge/document/detached_objects/builders/documents.rs +++ b/moli-renderer-v8/src/native_bridge/document/detached_objects/builders/documents.rs @@ -200,16 +200,34 @@ pub(crate) fn build_detached_document_object_from_dom_host_with_content_type<'s> character_set: Option<&str>, ) -> Option> { 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 content_type = content_type.unwrap_or(parsed.dom().document()?.content_type()); let document = new_detached_document_shell(scope, kind, content_type, url)?; - if let Some(state) = detached_state_object(scope, document) - && let Some(character_set) = character_set - { + if let Some(state) = detached_state_object(scope, document) { let _ = state.set( scope, - v8str(scope, "characterSet").into(), - v8_string(scope, character_set)?.into(), + v8str(scope, "compatMode").into(), + v8_string(scope, compat_mode)?.into(), ); + if let Some(character_set) = character_set { + let _ = state.set( + scope, + v8str(scope, "characterSet").into(), + v8_string(scope, character_set)?.into(), + ); + } + } + 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) diff --git a/moli-renderer-v8/src/native_bridge/document/detached_surface/document_state.rs b/moli-renderer-v8/src/native_bridge/document/detached_surface/document_state.rs index 7b02b5d1b9..b1df185e36 100644 --- a/moli-renderer-v8/src/native_bridge/document/detached_surface/document_state.rs +++ b/moli-renderer-v8/src/native_bridge/document/detached_surface/document_state.rs @@ -267,10 +267,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::::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>( diff --git a/moli-renderer-v8/src/script_vm/tests/dom_elements/detached/detached_document_and_element_surfaces.rs b/moli-renderer-v8/src/script_vm/tests/dom_elements/detached/detached_document_and_element_surfaces.rs index 14e95859a7..a92c2a7a8e 100644 --- a/moli-renderer-v8/src/script_vm/tests/dom_elements/detached/detached_document_and_element_surfaces.rs +++ b/moli-renderer-v8/src/script_vm/tests/dom_elements/detached/detached_document_and_element_surfaces.rs @@ -1706,3 +1706,41 @@ fn text_legacy_dom_string_reflectors_use_owner_prototypes() { assert_eq!(result, "ok"); } + +#[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( + "", + "text/html" + ); + const standards = parser.parseFromString( + "", + "text/html" + ); + const noscript = parser.parseFromString( + "", + "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"]}"# + ); +}