fix(dom): initialize empty browsing contexts correctly

This commit is contained in:
ldm0
2026-09-13 16:57:18 +08:00
parent 823c43f958
commit f6d30397e6
3 changed files with 56 additions and 8 deletions
@@ -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));
@@ -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(
@@ -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");