script: Move the FontContext to Window (#34845)

This will allow using layout's `FontContext` in `Window` letting script
manage font selection and download.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
This commit is contained in:
Martin Robinson 2025-01-07 05:44:31 +01:00 committed by GitHub
parent fe8a22b72c
commit 7142a96d36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 61 additions and 45 deletions

View file

@ -23,7 +23,6 @@ use euclid::{Point2D, Rect, Scale, Size2D};
use fnv::FnvHashMap; use fnv::FnvHashMap;
use fonts::{ use fonts::{
get_and_reset_text_shaping_performance_counter, FontContext, FontContextWebFontMethods, get_and_reset_text_shaping_performance_counter, FontContext, FontContextWebFontMethods,
SystemFontServiceProxy,
}; };
use fonts_traits::WebFontLoadFinishedCallback; use fonts_traits::WebFontLoadFinishedCallback;
use fxhash::{FxHashMap, FxHashSet}; use fxhash::{FxHashMap, FxHashSet};
@ -51,7 +50,6 @@ use log::{debug, error, trace};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use metrics::{PaintTimeMetrics, ProfilerMetadataFactory}; use metrics::{PaintTimeMetrics, ProfilerMetadataFactory};
use net_traits::image_cache::{ImageCache, UsePlaceholder}; use net_traits::image_cache::{ImageCache, UsePlaceholder};
use net_traits::ResourceThreads;
use parking_lot::RwLock; use parking_lot::RwLock;
use profile_traits::mem::{Report, ReportKind}; use profile_traits::mem::{Report, ReportKind};
use profile_traits::time::{ use profile_traits::time::{
@ -203,8 +201,7 @@ impl LayoutFactory for LayoutFactoryImpl {
config.is_iframe, config.is_iframe,
config.script_chan, config.script_chan,
config.image_cache, config.image_cache,
config.resource_threads, config.font_context,
config.system_font_service,
config.time_profiler_chan, config.time_profiler_chan,
config.compositor_api, config.compositor_api,
config.paint_time_metrics, config.paint_time_metrics,
@ -228,10 +225,6 @@ impl Layout for LayoutThread {
self.stylist.device() self.stylist.device()
} }
fn waiting_for_web_fonts_to_load(&self) -> bool {
self.font_context.web_fonts_still_loading() != 0
}
fn current_epoch(&self) -> Epoch { fn current_epoch(&self) -> Epoch {
self.epoch.get() self.epoch.get()
} }
@ -517,8 +510,7 @@ impl LayoutThread {
is_iframe: bool, is_iframe: bool,
script_chan: IpcSender<ConstellationControlMsg>, script_chan: IpcSender<ConstellationControlMsg>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
resource_threads: ResourceThreads, font_context: Arc<FontContext>,
system_font_service: Arc<SystemFontServiceProxy>,
time_profiler_chan: profile_time::ProfilerChan, time_profiler_chan: profile_time::ProfilerChan,
compositor_api: CrossProcessCompositorApi, compositor_api: CrossProcessCompositorApi,
paint_time_metrics: PaintTimeMetrics, paint_time_metrics: PaintTimeMetrics,
@ -535,11 +527,6 @@ impl LayoutThread {
keyword_info: KeywordInfo::medium(), keyword_info: KeywordInfo::medium(),
}; };
let font_context = Arc::new(FontContext::new(
system_font_service,
compositor_api.clone(),
resource_threads,
));
let device = Device::new( let device = Device::new(
MediaType::screen(), MediaType::screen(),
QuirksMode::NoQuirks, QuirksMode::NoQuirks,

View file

@ -22,7 +22,7 @@ use embedder_traits::resources::{self, Resource};
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D}; use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D};
use euclid::{Point2D, Scale, Size2D, Vector2D}; use euclid::{Point2D, Scale, Size2D, Vector2D};
use fnv::FnvHashMap; use fnv::FnvHashMap;
use fonts::{FontContext, FontContextWebFontMethods, SystemFontServiceProxy}; use fonts::{FontContext, FontContextWebFontMethods};
use fonts_traits::WebFontLoadFinishedCallback; use fonts_traits::WebFontLoadFinishedCallback;
use fxhash::FxHashMap; use fxhash::FxHashMap;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
@ -39,7 +39,6 @@ use log::{debug, error};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use metrics::{PaintTimeMetrics, ProfilerMetadataFactory}; use metrics::{PaintTimeMetrics, ProfilerMetadataFactory};
use net_traits::image_cache::{ImageCache, UsePlaceholder}; use net_traits::image_cache::{ImageCache, UsePlaceholder};
use net_traits::ResourceThreads;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use profile_traits::mem::{Report, ReportKind}; use profile_traits::mem::{Report, ReportKind};
use profile_traits::time::{ use profile_traits::time::{
@ -176,8 +175,7 @@ impl LayoutFactory for LayoutFactoryImpl {
config.is_iframe, config.is_iframe,
config.script_chan, config.script_chan,
config.image_cache, config.image_cache,
config.resource_threads, config.font_context,
config.system_font_service,
config.time_profiler_chan, config.time_profiler_chan,
config.compositor_api, config.compositor_api,
config.paint_time_metrics, config.paint_time_metrics,
@ -201,10 +199,6 @@ impl Layout for LayoutThread {
self.stylist.device() self.stylist.device()
} }
fn waiting_for_web_fonts_to_load(&self) -> bool {
self.font_context.web_fonts_still_loading() != 0
}
fn current_epoch(&self) -> Epoch { fn current_epoch(&self) -> Epoch {
self.epoch.get() self.epoch.get()
} }
@ -491,8 +485,7 @@ impl LayoutThread {
is_iframe: bool, is_iframe: bool,
script_chan: IpcSender<ConstellationControlMsg>, script_chan: IpcSender<ConstellationControlMsg>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
resource_threads: ResourceThreads, font_context: Arc<FontContext>,
system_font_service: Arc<SystemFontServiceProxy>,
time_profiler_chan: profile_time::ProfilerChan, time_profiler_chan: profile_time::ProfilerChan,
compositor_api: CrossProcessCompositorApi, compositor_api: CrossProcessCompositorApi,
paint_time_metrics: PaintTimeMetrics, paint_time_metrics: PaintTimeMetrics,
@ -511,11 +504,6 @@ impl LayoutThread {
// The device pixel ratio is incorrect (it does not have the hidpi value), // The device pixel ratio is incorrect (it does not have the hidpi value),
// but it will be set correctly when the initial reflow takes place. // but it will be set correctly when the initial reflow takes place.
let font_context = Arc::new(FontContext::new(
system_font_service,
compositor_api.clone(),
resource_threads,
));
let device = Device::new( let device = Device::new(
MediaType::screen(), MediaType::screen(),
QuirksMode::NoQuirks, QuirksMode::NoQuirks,

View file

@ -50,6 +50,7 @@ use std::cell::OnceCell;
use std::collections::BinaryHeap; use std::collections::BinaryHeap;
use std::hash::{BuildHasher, Hash}; use std::hash::{BuildHasher, Hash};
use std::ops::Range; use std::ops::Range;
use std::sync::Arc;
pub use style_malloc_size_of::MallocSizeOfOps; pub use style_malloc_size_of::MallocSizeOfOps;
use uuid::Uuid; use uuid::Uuid;
@ -523,6 +524,38 @@ impl<T: MallocSizeOf> MallocConditionalSizeOf for servo_arc::Arc<T> {
} }
} }
impl<T> MallocUnconditionalShallowSizeOf for Arc<T> {
fn unconditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
unsafe { ops.malloc_size_of(Arc::as_ptr(self)) }
}
}
impl<T: MallocSizeOf> MallocUnconditionalSizeOf for Arc<T> {
fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.unconditional_shallow_size_of(ops) + (**self).size_of(ops)
}
}
impl<T> MallocConditionalShallowSizeOf for Arc<T> {
fn conditional_shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
if ops.have_seen_ptr(Arc::as_ptr(self)) {
0
} else {
self.unconditional_shallow_size_of(ops)
}
}
}
impl<T: MallocSizeOf> MallocConditionalSizeOf for Arc<T> {
fn conditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
if ops.have_seen_ptr(Arc::as_ptr(self)) {
0
} else {
self.unconditional_size_of(ops)
}
}
}
/// If a mutex is stored directly as a member of a data type that is being measured, /// If a mutex is stored directly as a member of a data type that is being measured,
/// it is the unique owner of its contents and deserves to be measured. /// it is the unique owner of its contents and deserves to be measured.
/// ///

View file

@ -28,6 +28,7 @@ use dom_struct::dom_struct;
use embedder_traits::{EmbedderMsg, PromptDefinition, PromptOrigin, PromptResult}; use embedder_traits::{EmbedderMsg, PromptDefinition, PromptOrigin, PromptResult};
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect}; use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
use euclid::{Point2D, Rect, Scale, Size2D, Vector2D}; use euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
use fonts::FontContext;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use js::conversions::ToJSValConvertible; use js::conversions::ToJSValConvertible;
@ -207,6 +208,11 @@ pub struct Window {
#[no_trace] #[no_trace]
#[ignore_malloc_size_of = "TODO: Add MallocSizeOf support to layout"] #[ignore_malloc_size_of = "TODO: Add MallocSizeOf support to layout"]
layout: RefCell<Box<dyn Layout>>, layout: RefCell<Box<dyn Layout>>,
/// A [`FontContext`] which is used to store and match against fonts for this `Window` and to
/// trigger the download of web fonts.
#[no_trace]
#[conditional_malloc_size_of]
font_context: Arc<FontContext>,
navigator: MutNullableDom<Navigator>, navigator: MutNullableDom<Navigator>,
#[ignore_malloc_size_of = "Arc"] #[ignore_malloc_size_of = "Arc"]
#[no_trace] #[no_trace]
@ -1942,9 +1948,8 @@ impl Window {
/// should happen as part of the HTML event loop via *update the rendering*. Currerntly, the /// should happen as part of the HTML event loop via *update the rendering*. Currerntly, the
/// only exceptions are script queries and scroll requests. /// only exceptions are script queries and scroll requests.
pub(crate) fn reflow(&self, reflow_goal: ReflowGoal, can_gc: CanGc) -> bool { pub(crate) fn reflow(&self, reflow_goal: ReflowGoal, can_gc: CanGc) -> bool {
// Fetch the pending web fonts before layout, in case a font loads during // Count the pending web fonts before layout, in case a font loads during the layout.
// the layout. let waiting_for_web_fonts_to_load = self.font_context.web_fonts_still_loading() != 0;
let pending_web_fonts = self.layout.borrow().waiting_for_web_fonts_to_load();
self.Document().ensure_safe_to_run_script_or_layout(); self.Document().ensure_safe_to_run_script_or_layout();
@ -1988,7 +1993,7 @@ impl Window {
// Thus, we are queueing promise resolution here. This reflow should have been triggered by // Thus, we are queueing promise resolution here. This reflow should have been triggered by
// a "rendering opportunity" in `ScriptThread::handle_web_font_loaded, which should also // a "rendering opportunity" in `ScriptThread::handle_web_font_loaded, which should also
// make sure a microtask checkpoint happens, triggering the promise callback. // make sure a microtask checkpoint happens, triggering the promise callback.
if !pending_web_fonts && is_ready_state_complete { if !waiting_for_web_fonts_to_load && is_ready_state_complete {
font_face_set.fulfill_ready_promise_if_needed(); font_face_set.fulfill_ready_promise_if_needed();
} }
@ -2017,7 +2022,7 @@ impl Window {
is_ready_state_complete && is_ready_state_complete &&
!reftest_wait && !reftest_wait &&
!pending_images && !pending_images &&
!pending_web_fonts !waiting_for_web_fonts_to_load
{ {
debug!( debug!(
"{:?}: Sending DocumentState::Idle to Constellation", "{:?}: Sending DocumentState::Idle to Constellation",
@ -2674,6 +2679,7 @@ impl Window {
runtime: Rc<Runtime>, runtime: Rc<Runtime>,
script_chan: MainThreadScriptChan, script_chan: MainThreadScriptChan,
layout: Box<dyn Layout>, layout: Box<dyn Layout>,
font_context: Arc<FontContext>,
image_cache_chan: Sender<ImageCacheMsg>, image_cache_chan: Sender<ImageCacheMsg>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
resource_threads: ResourceThreads, resource_threads: ResourceThreads,
@ -2737,6 +2743,7 @@ impl Window {
), ),
script_chan, script_chan,
layout: RefCell::new(layout), layout: RefCell::new(layout),
font_context,
image_cache_chan, image_cache_chan,
image_cache, image_cache,
navigator: Default::default(), navigator: Default::default(),

View file

@ -47,7 +47,7 @@ use devtools_traits::{
}; };
use embedder_traits::EmbedderMsg; use embedder_traits::EmbedderMsg;
use euclid::default::{Point2D, Rect}; use euclid::default::{Point2D, Rect};
use fonts::SystemFontServiceProxy; use fonts::{FontContext, SystemFontServiceProxy};
use headers::{HeaderMapExt, LastModified, ReferrerPolicy as ReferrerPolicyHeader}; use headers::{HeaderMapExt, LastModified, ReferrerPolicy as ReferrerPolicyHeader};
use html5ever::{local_name, namespace_url, ns}; use html5ever::{local_name, namespace_url, ns};
use hyper_serde::Serde; use hyper_serde::Serde;
@ -3142,6 +3142,12 @@ impl ScriptThread {
incomplete.navigation_start, incomplete.navigation_start,
); );
let font_context = Arc::new(FontContext::new(
self.system_font_service.clone(),
self.compositor_api.clone(),
self.resource_threads.clone(),
));
let layout_config = LayoutConfig { let layout_config = LayoutConfig {
id: incomplete.pipeline_id, id: incomplete.pipeline_id,
url: final_url.clone(), url: final_url.clone(),
@ -3149,8 +3155,7 @@ impl ScriptThread {
constellation_chan: self.senders.layout_to_constellation_ipc_sender.clone(), constellation_chan: self.senders.layout_to_constellation_ipc_sender.clone(),
script_chan: self.senders.constellation_sender.clone(), script_chan: self.senders.constellation_sender.clone(),
image_cache: self.image_cache.clone(), image_cache: self.image_cache.clone(),
system_font_service: self.system_font_service.clone(), font_context: font_context.clone(),
resource_threads: self.resource_threads.clone(),
time_profiler_chan: self.senders.time_profiler_sender.clone(), time_profiler_chan: self.senders.time_profiler_sender.clone(),
compositor_api: self.compositor_api.clone(), compositor_api: self.compositor_api.clone(),
paint_time_metrics, paint_time_metrics,
@ -3162,6 +3167,7 @@ impl ScriptThread {
self.js_runtime.clone(), self.js_runtime.clone(),
self.senders.self_sender.clone(), self.senders.self_sender.clone(),
self.layout_factory.create(layout_config), self.layout_factory.create(layout_config),
font_context,
self.senders.image_cache_sender.clone(), self.senders.image_cache_sender.clone(),
self.image_cache.clone(), self.image_cache.clone(),
self.resource_threads.clone(), self.resource_threads.clone(),

View file

@ -24,13 +24,12 @@ use canvas_traits::canvas::{CanvasId, CanvasMsg};
use euclid::default::{Point2D, Rect}; use euclid::default::{Point2D, Rect};
use euclid::Size2D; use euclid::Size2D;
use fnv::FnvHashMap; use fnv::FnvHashMap;
use fonts::SystemFontServiceProxy; use fonts::{FontContext, SystemFontServiceProxy};
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use libc::c_void; use libc::c_void;
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
use metrics::PaintTimeMetrics; use metrics::PaintTimeMetrics;
use net_traits::image_cache::{ImageCache, PendingImageId}; use net_traits::image_cache::{ImageCache, PendingImageId};
use net_traits::ResourceThreads;
use profile_traits::mem::Report; use profile_traits::mem::Report;
use profile_traits::time; use profile_traits::time;
use script_traits::{ use script_traits::{
@ -188,8 +187,7 @@ pub struct LayoutConfig {
pub constellation_chan: IpcSender<LayoutMsg>, pub constellation_chan: IpcSender<LayoutMsg>,
pub script_chan: IpcSender<ConstellationControlMsg>, pub script_chan: IpcSender<ConstellationControlMsg>,
pub image_cache: Arc<dyn ImageCache>, pub image_cache: Arc<dyn ImageCache>,
pub resource_threads: ResourceThreads, pub font_context: Arc<FontContext>,
pub system_font_service: Arc<SystemFontServiceProxy>,
pub time_profiler_chan: time::ProfilerChan, pub time_profiler_chan: time::ProfilerChan,
pub compositor_api: CrossProcessCompositorApi, pub compositor_api: CrossProcessCompositorApi,
pub paint_time_metrics: PaintTimeMetrics, pub paint_time_metrics: PaintTimeMetrics,
@ -205,9 +203,6 @@ pub trait Layout {
/// resolve font metrics. /// resolve font metrics.
fn device(&self) -> &Device; fn device(&self) -> &Device;
/// Whether or not this layout is waiting for fonts from loaded stylesheets to finish loading.
fn waiting_for_web_fonts_to_load(&self) -> bool;
/// The currently laid out Epoch that this Layout has finished. /// The currently laid out Epoch that this Layout has finished.
fn current_epoch(&self) -> Epoch; fn current_epoch(&self) -> Epoch;