From f6d30397e6be2a3eaf7aa232f5d52ba806d85b33 Mon Sep 17 00:00:00 2001 From: ldm0 Date: Thu, 3 Sep 2026 18:20:56 +0800 Subject: [PATCH] fix(dom): initialize empty browsing contexts correctly --- .../child_documents/initial_empty.rs | 9 ++-- .../context_host/child_frames/lookup.rs | 11 ++++- .../tests/dom_elements/dom_surface.rs | 44 ++++++++++++++++++- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/moli-renderer-v8/src/native_bridge/context_host/child_documents/initial_empty.rs b/moli-renderer-v8/src/native_bridge/context_host/child_documents/initial_empty.rs index 1a87b86096..f9d86db8c4 100644 --- a/moli-renderer-v8/src/native_bridge/context_host/child_documents/initial_empty.rs +++ b/moli-renderer-v8/src/native_bridge/context_host/child_documents/initial_empty.rs @@ -181,9 +181,11 @@ impl JsContextHost { } fn populate_initial_empty_child_html_document(&mut self, document_handle: DomHandle) { - let doctype = - self.dom_host_mut() - .create_document_type_for_document(document_handle, "html", "", ""); + self.dom_host_mut() + .set_html_quirks_mode_for_parser_document( + document_handle, + html5ever::tree_builder::QuirksMode::Quirks, + ); let html = self .dom_host_mut() .create_parser_element_without_attributes_for_document( @@ -208,7 +210,6 @@ impl JsContextHost { "http://www.w3.org/1999/xhtml".to_owned(), None, ); - assert!(self.dom_host_mut().append_child(document_handle, doctype)); assert!(self.dom_host_mut().append_child(document_handle, html)); assert!(self.dom_host_mut().append_child(html, head)); assert!(self.dom_host_mut().append_child(html, body)); diff --git a/moli-renderer-v8/src/native_bridge/context_host/child_frames/lookup.rs b/moli-renderer-v8/src/native_bridge/context_host/child_frames/lookup.rs index 279ef02aa7..192158f588 100644 --- a/moli-renderer-v8/src/native_bridge/context_host/child_frames/lookup.rs +++ b/moli-renderer-v8/src/native_bridge/context_host/child_frames/lookup.rs @@ -384,10 +384,17 @@ impl JsContextHost { &self, document_handle: DomHandle, ) -> Option<&str> { - self.child_browsing_context_host_for_document_handle(document_handle) - .and_then(|child_handle| self.child_browsing_contexts.get(&child_handle)) + let child_handle = self.child_browsing_context_host_for_document_handle(document_handle)?; + if let Some(character_set) = self + .child_browsing_contexts + .get(&child_handle) .and_then(|entry| entry.cached_snapshot_ref()) .map(|snapshot| snapshot.character_set.as_str()) + { + return Some(character_set); + } + self.child_current_document_is_initial_empty(child_handle) + .then_some("UTF-8") } pub(crate) fn child_browsing_context_referrer_for_document_handle( diff --git a/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs b/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs index ec1f79972c..32691af1e0 100644 --- a/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs +++ b/moli-renderer-v8/src/script_vm/tests/dom_elements/dom_surface.rs @@ -632,7 +632,7 @@ fn transformed_constrained_iframe_routes_hover_click_and_wheel_in_child_coordina const frame = document.getElementById('input-frame'); const child = frame.contentDocument; return JSON.stringify({ - hovered: child.getElementById('hover-target').matches(':hover'), + hovered: child.getElementById('hover-target').matches('#hover-target:hover'), wheelTop: child.getElementById('wheel-target').scrollTop, rootTop: document.scrollingElement.scrollTop, events: frame.contentWindow.__inputEvents @@ -927,7 +927,7 @@ fn focusing_visible_child_target_does_not_scroll_partially_hidden_transformed_if parentScroll: window.scrollY, parentActive: document.activeElement === frame, childActive: child.activeElement === child.getElementById('focus-target'), - hovered: child.getElementById('focus-target').matches(':hover'), + hovered: child.getElementById('focus-target').matches('#focus-target:hover'), events: frame.contentWindow.__focusEvents }); })() @@ -11509,6 +11509,46 @@ fn no_src_iframe_initial_about_blank_load_is_synchronous_at_connection() { ); } +#[test] +fn no_src_iframe_initial_about_blank_has_a_quirks_empty_document() { + let mut vm = new_storage_test_vm("https://iframe-initial-document.test/page.html"); + vm.document_runtime + .set_document_character_set("windows-1252"); + + let result = vm + .eval( + r#" +(() => { + const frame = document.createElement("iframe"); + (document.body || document.documentElement || document).appendChild(frame); + const doc = frame.contentDocument; + return JSON.stringify({ + compatMode: doc.compatMode, + contentType: doc.contentType, + readyState: doc.readyState, + documentURI: doc.documentURI, + url: doc.URL, + doctypeIsNull: doc.doctype === null, + characterSet: doc.characterSet, + documentChildCount: doc.childNodes.length, + documentElement: doc.documentElement.tagName, + documentElementChildCount: doc.documentElement.childNodes.length, + head: doc.documentElement.firstChild.tagName, + headChildCount: doc.head.childNodes.length, + body: doc.documentElement.lastChild.tagName, + bodyChildCount: doc.body.childNodes.length + }); +})() +"#, + ) + .expect("initial about:blank document shape should evaluate"); + + assert_eq!( + result, + r#"{"compatMode":"BackCompat","contentType":"text/html","readyState":"complete","documentURI":"about:blank","url":"about:blank","doctypeIsNull":true,"characterSet":"UTF-8","documentChildCount":1,"documentElement":"HTML","documentElementChildCount":2,"head":"HEAD","headChildCount":0,"body":"BODY","bodyChildCount":0}"# + ); +} + #[tokio::test] async fn top_history_back_routes_to_child_joint_history_entry() { let loader = ResourceRequestClient::new(&moli_fetch::FetchConfig::default()).expect("loader");