diff --git a/moli-renderer-v8/src/runtime/page_vm/tests/rendering_update/realtime_resize_observer.rs b/moli-renderer-v8/src/runtime/page_vm/tests/rendering_update/realtime_resize_observer.rs index 6fdf6bdb6e..9c3ea48ec6 100644 --- a/moli-renderer-v8/src/runtime/page_vm/tests/rendering_update/realtime_resize_observer.rs +++ b/moli-renderer-v8/src/runtime/page_vm/tests/rendering_update/realtime_resize_observer.rs @@ -67,3 +67,84 @@ fn realtime_ro_initial_delivery_follows_raf_and_becomes_idle_without_capture() { ); }); } + +#[test] +fn realtime_frames_admit_cssom_fonts_after_observer_callbacks_without_capture() { + assert_frame_cssom_font_admission(true); +} + +#[test] +fn realtime_frame_cssom_fonts_preserve_the_disabled_resource_policy() { + assert_frame_cssom_font_admission(false); +} + +fn assert_frame_cssom_font_admission(fonts_enabled: bool) { + run_page_vm_large_stack_async_test("realtime-cssom-font-admission", move || async move { + use base64::Engine; + + let loader = crate::network::ResourceRequestClient::new(&FetchConfig::default()).unwrap(); + loader.set_optional_resource_fetch_mask(if fonts_enabled { + crate::protocol_types::OptionalResourceFetchMask::FONT + } else { + crate::protocol_types::OptionalResourceFetchMask::NONE + }); + let mut page = realtime_page(&loader); + let font = base64::engine::general_purpose::STANDARD.encode(include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../moli-layout/tests/fixtures/moli-ahem.woff2" + ))); + let markup = "iiii"; + page.vm_mut().eval(&format!(r#" + document.head.innerHTML=''; + document.body.innerHTML="iiii"; + const child=frame.contentDocument; + child.open();child.write({markup});child.close(); + window.samples=[[],[]];window.observers=[]; + [document,child].forEach((doc,index)=>{{ + const ro=new doc.defaultView.ResizeObserver(entries=>{{ + samples[index].push(entries[0].contentRect.width); + if(samples[index].length===1){{ + doc.styleSheets[0].cssRules[0].style.src='url(data:font/woff2;base64,{font})'; + }} + }}); + observers.push(ro);ro.observe(doc.getElementById('target')); + }}); + "#,markup=serde_json::to_string(markup).unwrap())).unwrap(); + // Advance bounded native frame opportunities, without screenshots, + // geometry queries or a manual font-reconciliation helper. + for _ in 0..4 { + if page + .next_rendering_opportunity_deadline_for_test() + .is_none() + { + break; + } + run_opportunity(&mut page, &loader).await.unwrap(); + } + let samples: Vec> = + serde_json::from_str(&page.vm_mut().eval("JSON.stringify(samples)").unwrap()).unwrap(); + for sample in &samples { + assert_eq!( + sample.len(), + if fonts_enabled { 2 } else { 1 }, + "font policy {fonts_enabled}: {samples:?}" + ); + assert_ne!(sample[0], 48.0); + if fonts_enabled { + assert_eq!(sample[1], 48.0); + } + } + assert!( + page.next_rendering_opportunity_deadline_for_test() + .is_none() + ); + assert_eq!( + page.vm() + .layout_pass_observability_for_test() + .3 + .unwrap() + .paint_operation_count, + 0 + ); + }); +} diff --git a/moli-renderer-v8/src/script_vm/rendering_update/realtime.rs b/moli-renderer-v8/src/script_vm/rendering_update/realtime.rs index 4a047b10e9..7968dd0948 100644 --- a/moli-renderer-v8/src/script_vm/rendering_update/realtime.rs +++ b/moli-renderer-v8/src/script_vm/rendering_update/realtime.rs @@ -127,6 +127,16 @@ impl ScriptVm { if unsafe { &*host_ptr }.realtime_rendering_opportunity_is_current(id, root) { crate::observer_runtime::sample_realtime_intersections(scope, host_ptr)?; } + if unsafe { &*host_ptr }.realtime_rendering_opportunity_is_current(id, root) { + // Layout has published the actual child viewports, and rAF/RO may + // have changed CSS font sources. Admit those resources through the + // existing owner-checked loader after sampling this frame. A ready + // font invalidates geometry and requests its own next opportunity; + // synchronous getters never start resource or callback work. + crate::document_runtime::DocumentRuntime::reconcile_document_web_fonts_in_current_scope( + scope, host_ptr, + ); + } Ok(invoked) } }