Add WebFontDocumentContext for CSS Fonts 4 font fetching

Signed-off-by: Uthman Yahaya Baba <uthmanyahayababa@gmail.com>
This commit is contained in:
Uthman Yahaya Baba 2025-05-16 04:09:55 +01:00
parent 3af0992ead
commit e9e360edef
8 changed files with 122 additions and 20 deletions

View file

@ -16,7 +16,11 @@ use fonts_traits::StylesheetWebFontLoadFinishedCallback;
use log::{debug, trace}; use log::{debug, trace};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
use net_traits::request::{Destination, Referrer, RequestBuilder}; use net_traits::policy_container::PolicyContainer;
use net_traits::request::{
CredentialsMode, Destination, InsecureRequestsPolicy, Referrer, RequestBuilder, RequestMode,
ServiceWorkersMode,
};
use net_traits::{CoreResourceThread, FetchResponseMsg, ResourceThreads, fetch_async}; use net_traits::{CoreResourceThread, FetchResponseMsg, ResourceThreads, fetch_async};
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use servo_arc::Arc as ServoArc; use servo_arc::Arc as ServoArc;
@ -83,6 +87,14 @@ pub struct FontContext {
have_removed_web_fonts: AtomicBool, have_removed_web_fonts: AtomicBool,
} }
#[derive(Clone, Debug)]
pub struct WebFontDocumentContext {
pub policy_container: PolicyContainer,
pub document_url: ServoUrl,
pub has_trustworthy_ancestor_origin: bool,
pub insecure_requests_policy: InsecureRequestsPolicy,
}
impl MallocSizeOf for FontContext { impl MallocSizeOf for FontContext {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
let font_cache_size = self let font_cache_size = self
@ -387,6 +399,7 @@ pub(crate) struct WebFontDownloadState {
local_fonts: HashMap<Atom, Option<FontTemplateRef>>, local_fonts: HashMap<Atom, Option<FontTemplateRef>>,
font_context: Arc<FontContext>, font_context: Arc<FontContext>,
initiator: WebFontLoadInitiator, initiator: WebFontLoadInitiator,
document_context: WebFontDocumentContext,
} }
impl WebFontDownloadState { impl WebFontDownloadState {
@ -397,6 +410,7 @@ impl WebFontDownloadState {
initiator: WebFontLoadInitiator, initiator: WebFontLoadInitiator,
sources: Vec<Source>, sources: Vec<Source>,
local_fonts: HashMap<Atom, Option<FontTemplateRef>>, local_fonts: HashMap<Atom, Option<FontTemplateRef>>,
document_context: WebFontDocumentContext,
) -> WebFontDownloadState { ) -> WebFontDownloadState {
match initiator { match initiator {
WebFontLoadInitiator::Stylesheet(ref stylesheet, _) => { WebFontLoadInitiator::Stylesheet(ref stylesheet, _) => {
@ -421,6 +435,7 @@ impl WebFontDownloadState {
local_fonts, local_fonts,
font_context, font_context,
initiator, initiator,
document_context,
} }
} }
@ -487,6 +502,7 @@ pub trait FontContextWebFontMethods {
guard: &SharedRwLockReadGuard, guard: &SharedRwLockReadGuard,
device: &Device, device: &Device,
finished_callback: StylesheetWebFontLoadFinishedCallback, finished_callback: StylesheetWebFontLoadFinishedCallback,
document_context: &WebFontDocumentContext,
) -> usize; ) -> usize;
fn load_web_font_for_script( fn load_web_font_for_script(
&self, &self,
@ -494,6 +510,7 @@ pub trait FontContextWebFontMethods {
source_list: SourceList, source_list: SourceList,
descriptors: CSSFontFaceDescriptors, descriptors: CSSFontFaceDescriptors,
finished_callback: ScriptWebFontLoadFinishedCallback, finished_callback: ScriptWebFontLoadFinishedCallback,
document_context: &WebFontDocumentContext,
); );
fn add_template_to_font_context( fn add_template_to_font_context(
&self, &self,
@ -513,6 +530,7 @@ impl FontContextWebFontMethods for Arc<FontContext> {
guard: &SharedRwLockReadGuard, guard: &SharedRwLockReadGuard,
device: &Device, device: &Device,
finished_callback: StylesheetWebFontLoadFinishedCallback, finished_callback: StylesheetWebFontLoadFinishedCallback,
document_context: &WebFontDocumentContext,
) -> usize { ) -> usize {
let mut number_loading = 0; let mut number_loading = 0;
for rule in stylesheet.effective_rules(device, guard) { for rule in stylesheet.effective_rules(device, guard) {
@ -535,6 +553,7 @@ impl FontContextWebFontMethods for Arc<FontContext> {
font_face.sources(), font_face.sources(),
css_font_face_descriptors, css_font_face_descriptors,
completion_handler, completion_handler,
document_context,
); );
} }
@ -643,9 +662,16 @@ impl FontContextWebFontMethods for Arc<FontContext> {
sources: SourceList, sources: SourceList,
descriptors: CSSFontFaceDescriptors, descriptors: CSSFontFaceDescriptors,
finished_callback: ScriptWebFontLoadFinishedCallback, finished_callback: ScriptWebFontLoadFinishedCallback,
document_context: &WebFontDocumentContext,
) { ) {
let completion_handler = WebFontLoadInitiator::Script(finished_callback); let completion_handler = WebFontLoadInitiator::Script(finished_callback);
self.start_loading_one_web_font(webview_id, &sources, descriptors, completion_handler); self.start_loading_one_web_font(
webview_id,
&sources,
descriptors,
completion_handler,
document_context,
);
} }
fn add_template_to_font_context( fn add_template_to_font_context(
@ -667,6 +693,7 @@ impl FontContext {
source_list: &SourceList, source_list: &SourceList,
css_font_face_descriptors: CSSFontFaceDescriptors, css_font_face_descriptors: CSSFontFaceDescriptors,
completion_handler: WebFontLoadInitiator, completion_handler: WebFontLoadInitiator,
document_context: &WebFontDocumentContext,
) { ) {
let sources: Vec<Source> = source_list let sources: Vec<Source> = source_list
.0 .0
@ -708,6 +735,7 @@ impl FontContext {
completion_handler, completion_handler,
sources, sources,
local_fonts, local_fonts,
document_context.clone(),
)); ));
} }
@ -792,10 +820,20 @@ impl RemoteWebFontDownloader {
None => return, None => return,
}; };
// FIXME: This shouldn't use NoReferrer, but the current documents url let document_context = &state.document_context;
let request =
RequestBuilder::new(state.webview_id, url.clone().into(), Referrer::NoReferrer) let request = RequestBuilder::new(
.destination(Destination::Font); state.webview_id,
url.clone().into(),
Referrer::ReferrerUrl(document_context.document_url.clone()),
)
.destination(Destination::Font)
.mode(RequestMode::CorsMode)
.credentials_mode(CredentialsMode::CredentialsSameOrigin)
.service_workers_mode(ServiceWorkersMode::All)
.policy_container(document_context.policy_container.clone())
.insecure_requests_policy(document_context.insecure_requests_policy)
.has_trustworthy_ancestor_origin(document_context.has_trustworthy_ancestor_origin);
let core_resource_thread_clone = state.core_resource_thread.clone(); let core_resource_thread_clone = state.core_resource_thread.clone();

View file

@ -19,7 +19,7 @@ use embedder_traits::{UntrustedNodeAddress, ViewportDetails};
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}; use fonts::{FontContext, FontContextWebFontMethods, WebFontDocumentContext};
use fonts_traits::StylesheetWebFontLoadFinishedCallback; use fonts_traits::StylesheetWebFontLoadFinishedCallback;
use fxhash::FxHashMap; use fxhash::FxHashMap;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
@ -194,11 +194,16 @@ impl Layout for LayoutThread {
self.epoch.get() self.epoch.get()
} }
fn load_web_fonts_from_stylesheet(&self, stylesheet: ServoArc<Stylesheet>) { fn load_web_fonts_from_stylesheet(
&self,
stylesheet: ServoArc<Stylesheet>,
document_context: &WebFontDocumentContext,
) {
let guard = stylesheet.shared_lock.read(); let guard = stylesheet.shared_lock.read();
self.load_all_web_fonts_from_stylesheet_with_guard( self.load_all_web_fonts_from_stylesheet_with_guard(
&DocumentStyleSheet(stylesheet.clone()), &DocumentStyleSheet(stylesheet.clone()),
&guard, &guard,
document_context,
); );
} }
@ -210,10 +215,11 @@ impl Layout for LayoutThread {
&mut self, &mut self,
stylesheet: ServoArc<Stylesheet>, stylesheet: ServoArc<Stylesheet>,
before_stylesheet: Option<ServoArc<Stylesheet>>, before_stylesheet: Option<ServoArc<Stylesheet>>,
document_context: &WebFontDocumentContext,
) { ) {
let guard = stylesheet.shared_lock.read(); let guard = stylesheet.shared_lock.read();
let stylesheet = DocumentStyleSheet(stylesheet.clone()); let stylesheet = DocumentStyleSheet(stylesheet.clone());
self.load_all_web_fonts_from_stylesheet_with_guard(&stylesheet, &guard); self.load_all_web_fonts_from_stylesheet_with_guard(&stylesheet, &guard, document_context);
match before_stylesheet { match before_stylesheet {
Some(insertion_point) => self.stylist.insert_stylesheet_before( Some(insertion_point) => self.stylist.insert_stylesheet_before(
@ -560,6 +566,7 @@ impl LayoutThread {
&self, &self,
stylesheet: &DocumentStyleSheet, stylesheet: &DocumentStyleSheet,
guard: &SharedRwLockReadGuard, guard: &SharedRwLockReadGuard,
document_context: &WebFontDocumentContext,
) { ) {
if !stylesheet.is_effective_for_device(self.stylist.device(), guard) { if !stylesheet.is_effective_for_device(self.stylist.device(), guard) {
return; return;
@ -579,6 +586,7 @@ impl LayoutThread {
guard, guard,
self.stylist.device(), self.stylist.device(),
Arc::new(web_font_finished_loading_callback) as StylesheetWebFontLoadFinishedCallback, Arc::new(web_font_finished_loading_callback) as StylesheetWebFontLoadFinishedCallback,
document_context,
); );
} }
@ -705,7 +713,11 @@ impl LayoutThread {
for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets { for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets {
self.stylist self.stylist
.append_stylesheet(stylesheet.clone(), guards.ua_or_user); .append_stylesheet(stylesheet.clone(), guards.ua_or_user);
self.load_all_web_fonts_from_stylesheet_with_guard(stylesheet, guards.ua_or_user); self.load_all_web_fonts_from_stylesheet_with_guard(
stylesheet,
guards.ua_or_user,
&reflow_request.document_context,
);
} }
if self.stylist.quirks_mode() != QuirksMode::NoQuirks { if self.stylist.quirks_mode() != QuirksMode::NoQuirks {
@ -716,6 +728,7 @@ impl LayoutThread {
self.load_all_web_fonts_from_stylesheet_with_guard( self.load_all_web_fonts_from_stylesheet_with_guard(
&ua_stylesheets.quirks_mode_stylesheet, &ua_stylesheets.quirks_mode_stylesheet,
guards.ua_or_user, guards.ua_or_user,
&reflow_request.document_context,
); );
} }
} }

View file

@ -35,6 +35,7 @@ use embedder_traits::{
}; };
use encoding_rs::{Encoding, UTF_8}; use encoding_rs::{Encoding, UTF_8};
use euclid::default::{Point2D, Rect, Size2D}; use euclid::default::{Point2D, Rect, Size2D};
use fonts::WebFontDocumentContext;
use html5ever::{LocalName, Namespace, QualName, local_name, ns}; use html5ever::{LocalName, Namespace, QualName, local_name, ns};
use hyper_serde::Serde; use hyper_serde::Serde;
use ipc_channel::ipc; use ipc_channel::ipc;
@ -4916,9 +4917,21 @@ impl Document {
.cloned(); .cloned();
if self.has_browsing_context() { if self.has_browsing_context() {
// Construct WebFontDocumentContext for font fetching
let document_context = WebFontDocumentContext {
policy_container: self.window.global().policy_container(),
document_url: self.window.global().api_base_url(),
has_trustworthy_ancestor_origin: self
.window
.global()
.has_trustworthy_ancestor_origin(),
insecure_requests_policy: self.window.global().insecure_requests_policy(),
};
self.window.layout_mut().add_stylesheet( self.window.layout_mut().add_stylesheet(
sheet.clone(), sheet.clone(),
insertion_point.as_ref().map(|s| s.sheet.clone()), insertion_point.as_ref().map(|s| s.sheet.clone()),
&document_context,
); );
} }
@ -4932,10 +4945,14 @@ impl Document {
} }
/// Given a stylesheet, load all web fonts from it in Layout. /// Given a stylesheet, load all web fonts from it in Layout.
pub(crate) fn load_web_fonts_from_stylesheet(&self, stylesheet: Arc<Stylesheet>) { pub(crate) fn load_web_fonts_from_stylesheet(
&self,
stylesheet: Arc<Stylesheet>,
document_context: &WebFontDocumentContext,
) {
self.window self.window
.layout() .layout()
.load_web_fonts_from_stylesheet(stylesheet); .load_web_fonts_from_stylesheet(stylesheet, document_context);
} }
/// Remove a stylesheet owned by `owner` from the list of document sheets. /// Remove a stylesheet owned by `owner` from the list of document sheets.

View file

@ -7,7 +7,10 @@ use std::rc::Rc;
use cssparser::{Parser, ParserInput}; use cssparser::{Parser, ParserInput};
use dom_struct::dom_struct; use dom_struct::dom_struct;
use fonts::{FontContext, FontContextWebFontMethods, FontTemplate, LowercaseFontFamilyName}; use fonts::{
FontContext, FontContextWebFontMethods, FontTemplate, LowercaseFontFamilyName,
WebFontDocumentContext,
};
use js::rust::HandleObject; use js::rust::HandleObject;
use style::error_reporting::ParseErrorReporter; use style::error_reporting::ParseErrorReporter;
use style::font_face::SourceList; use style::font_face::SourceList;
@ -540,6 +543,14 @@ impl FontFaceMethods<crate::DomTypeHolder> for FontFace {
) )
.expect("Parsing shouldn't fail as descriptors are valid by construction"); .expect("Parsing shouldn't fail as descriptors are valid by construction");
//Construct a WebFontDocumentContext object for the current document.
let document_context = WebFontDocumentContext {
policy_container: global.policy_container(),
document_url: global.api_base_url(),
has_trustworthy_ancestor_origin: global.has_trustworthy_ancestor_origin(),
insecure_requests_policy: global.insecure_requests_policy(),
};
// Step 4. Using the value of font faces [[Urls]] slot, attempt to load a font as defined // Step 4. Using the value of font faces [[Urls]] slot, attempt to load a font as defined
// in [CSS-FONTS-3], as if it was the value of a @font-face rules src descriptor. // in [CSS-FONTS-3], as if it was the value of a @font-face rules src descriptor.
// TODO: FontFaceSet is not supported on Workers yet. The `as_window` call below should be // TODO: FontFaceSet is not supported on Workers yet. The `as_window` call below should be
@ -549,6 +560,7 @@ impl FontFaceMethods<crate::DomTypeHolder> for FontFace {
sources, sources,
(&parsed_font_face_rule).into(), (&parsed_font_face_rule).into(),
finished_callback, finished_callback,
&document_context,
); );
// Step 3. Set font faces status attribute to "loading", return font faces // Step 3. Set font faces status attribute to "loading", return font faces

View file

@ -38,7 +38,7 @@ use embedder_traits::{
}; };
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 fonts::{FontContext, WebFontDocumentContext};
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use js::conversions::ToJSValConvertible; use js::conversions::ToJSValConvertible;
use js::glue::DumpJSStack; use js::glue::DumpJSStack;
@ -2170,6 +2170,13 @@ impl Window {
let highlighted_dom_node = document.highlighted_dom_node().map(|node| node.to_opaque()); let highlighted_dom_node = document.highlighted_dom_node().map(|node| node.to_opaque());
//Construct a new document context for the reflow.
let document_context = WebFontDocumentContext {
policy_container: self.global().policy_container(),
document_url: self.global().api_base_url(),
has_trustworthy_ancestor_origin: self.global().has_trustworthy_ancestor_origin(),
insecure_requests_policy: self.global().insecure_requests_policy(),
};
// Send new document and relevant styles to layout. // Send new document and relevant styles to layout.
let reflow = ReflowRequest { let reflow = ReflowRequest {
reflow_info: Reflow { reflow_info: Reflow {
@ -2190,6 +2197,7 @@ impl Window {
.take_image_animate_set(), .take_image_animate_set(),
theme: self.theme.get(), theme: self.theme.get(),
highlighted_dom_node, highlighted_dom_node,
document_context,
}; };
let Some(results) = self.layout.borrow_mut().reflow(reflow) else { let Some(results) = self.layout.borrow_mut().reflow(reflow) else {

View file

@ -8,6 +8,7 @@ use std::sync::atomic::AtomicBool;
use content_security_policy as csp; use content_security_policy as csp;
use cssparser::SourceLocation; use cssparser::SourceLocation;
use encoding_rs::UTF_8; use encoding_rs::UTF_8;
use fonts::WebFontDocumentContext;
use mime::{self, Mime}; use mime::{self, Mime};
use net_traits::request::{CorsSettings, Destination, RequestId}; use net_traits::request::{CorsSettings, Destination, RequestId};
use net_traits::{ use net_traits::{
@ -232,10 +233,19 @@ impl FetchResponseListener for StylesheetContext {
Some(&loader), Some(&loader),
win.css_error_reporter(), win.css_error_reporter(),
); );
//Construct a new WebFontDocumentContext for the stylesheet
let document_context = WebFontDocumentContext {
policy_container: win.global().policy_container(),
document_url: win.global().api_base_url(),
has_trustworthy_ancestor_origin: win
.global()
.has_trustworthy_ancestor_origin(),
insecure_requests_policy: win.global().insecure_requests_policy(),
};
// Layout knows about this stylesheet, because Stylo added it to the Stylist, // Layout knows about this stylesheet, because Stylo added it to the Stylist,
// but Layout doesn't know about any new web fonts that it contains. // but Layout doesn't know about any new web fonts that it contains.
document.load_web_fonts_from_stylesheet(stylesheet.clone()); document.load_web_fonts_from_stylesheet(stylesheet.clone(), &document_context);
}, },
} }

View file

@ -23,7 +23,7 @@ use constellation_traits::{LoadData, ScrollState};
use embedder_traits::{UntrustedNodeAddress, ViewportDetails}; use embedder_traits::{UntrustedNodeAddress, ViewportDetails};
use euclid::default::{Point2D, Rect}; use euclid::default::{Point2D, Rect};
use fnv::FnvHashMap; use fnv::FnvHashMap;
use fonts::{FontContext, SystemFontServiceProxy}; use fonts::{FontContext, SystemFontServiceProxy, WebFontDocumentContext};
use fxhash::FxHashMap; use fxhash::FxHashMap;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use libc::c_void; use libc::c_void;
@ -198,7 +198,11 @@ pub trait Layout {
/// Load all fonts from the given stylesheet, returning the number of fonts that /// Load all fonts from the given stylesheet, returning the number of fonts that
/// need to be loaded. /// need to be loaded.
fn load_web_fonts_from_stylesheet(&self, stylesheet: ServoArc<Stylesheet>); fn load_web_fonts_from_stylesheet(
&self,
stylesheet: ServoArc<Stylesheet>,
font_context: &WebFontDocumentContext,
);
/// Add a stylesheet to this Layout. This will add it to the Layout's `Stylist` as well as /// Add a stylesheet to this Layout. This will add it to the Layout's `Stylist` as well as
/// loading all web fonts defined in the stylesheet. The second stylesheet is the insertion /// loading all web fonts defined in the stylesheet. The second stylesheet is the insertion
@ -207,6 +211,7 @@ pub trait Layout {
&mut self, &mut self,
stylesheet: ServoArc<Stylesheet>, stylesheet: ServoArc<Stylesheet>,
before_stylsheet: Option<ServoArc<Stylesheet>>, before_stylsheet: Option<ServoArc<Stylesheet>>,
font_context: &WebFontDocumentContext,
); );
/// Inform the layout that its ScriptThread is about to exit. /// Inform the layout that its ScriptThread is about to exit.
@ -431,6 +436,8 @@ pub struct ReflowRequest {
pub theme: PrefersColorScheme, pub theme: PrefersColorScheme,
/// The node highlighted by the devtools, if any /// The node highlighted by the devtools, if any
pub highlighted_dom_node: Option<OpaqueNode>, pub highlighted_dom_node: Option<OpaqueNode>,
/// The current font context.
pub document_context: WebFontDocumentContext,
} }
/// A pending restyle. /// A pending restyle.

View file

@ -1,3 +0,0 @@
[internal-stylesheet.html]
[Font from internal stylesheet.]
expected: FAIL