font_cache: Handle filtering @font-face rules in Servo (#31601)

Instead of letting Stylo filter `@font-face` rules, handle this
filtering in Servo. It doesn't make sense that Stylo knows about what
fonts Servo supports. This also cleans up a bit the way that this is
handled, giving an entire stylesheet of rules to the font cache to
process instead of letting each layout thread walk the rules. This
brings more of the font-related code into the FontCacheThread itself.

This is the first step toward adding WOFF2 support and fixing various
web font related bugs.
This commit is contained in:
Martin Robinson 2024-03-11 15:47:52 +01:00 committed by GitHub
parent b03411f567
commit 45344dca2b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 182 additions and 219 deletions

26
Cargo.lock generated
View file

@ -1208,7 +1208,7 @@ dependencies = [
[[package]]
name = "derive_common"
version = "0.0.1"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"darling",
"proc-macro2",
@ -3463,7 +3463,7 @@ dependencies = [
[[package]]
name = "malloc_size_of"
version = "0.0.1"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"accountable-refcell",
"app_units",
@ -5075,7 +5075,7 @@ dependencies = [
[[package]]
name = "selectors"
version = "0.24.0"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"bitflags 1.3.2",
"cssparser",
@ -5363,7 +5363,7 @@ dependencies = [
[[package]]
name = "servo_arc"
version = "0.2.0"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"nodrop",
"serde",
@ -5373,7 +5373,7 @@ dependencies = [
[[package]]
name = "servo_atoms"
version = "0.0.1"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"string_cache",
"string_cache_codegen",
@ -5579,7 +5579,7 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "size_of_test"
version = "0.0.1"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"static_assertions",
]
@ -5705,7 +5705,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "static_prefs"
version = "0.1.0"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
[[package]]
name = "str-buf"
@ -5748,7 +5748,7 @@ dependencies = [
[[package]]
name = "style"
version = "0.0.1"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"app_units",
"arrayvec",
@ -5806,7 +5806,7 @@ dependencies = [
[[package]]
name = "style_config"
version = "0.0.1"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"lazy_static",
]
@ -5814,7 +5814,7 @@ dependencies = [
[[package]]
name = "style_derive"
version = "0.0.1"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"darling",
"derive_common",
@ -5845,7 +5845,7 @@ dependencies = [
[[package]]
name = "style_traits"
version = "0.0.1"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"app_units",
"bitflags 1.3.2",
@ -6188,7 +6188,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "to_shmem"
version = "0.0.1"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"cssparser",
"servo_arc",
@ -6201,7 +6201,7 @@ dependencies = [
[[package]]
name = "to_shmem_derive"
version = "0.0.1"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6d01b5972aa3d00acbbe2a9cac98c59934b659e6"
source = "git+https://github.com/servo/stylo.git?branch=2023-07-23#6614be88ec2b773e397767eb0d0554dd1145e81e"
dependencies = [
"darling",
"derive_common",

View file

@ -17,8 +17,10 @@ use net_traits::{fetch_async, CoreResourceThread, FetchResponseMsg};
use serde::{Deserialize, Serialize};
use servo_atoms::Atom;
use servo_url::ServoUrl;
use style::font_face::{EffectiveSources, Source};
use style::values::computed::font::FamilyName;
use style::font_face::{FontFaceSourceFormat, FontFaceSourceFormatKeyword, Source};
use style::media_queries::Device;
use style::shared_lock::SharedRwLockReadGuard;
use style::stylesheets::{Stylesheet, StylesheetInDocument};
use webrender_api::{FontInstanceKey, FontKey};
use crate::font::{FontFamilyDescriptor, FontFamilyName, FontSearchScope};
@ -130,7 +132,7 @@ pub enum Command {
IpcSender<Reply>,
),
GetFontInstance(FontKey, Au, IpcSender<FontInstanceKey>),
AddWebFont(LowercaseString, EffectiveSources, IpcSender<()>),
AddWebFont(LowercaseString, Vec<Source>, IpcSender<()>),
AddDownloadedWebFont(LowercaseString, ServoUrl, Vec<u8>, IpcSender<()>),
Exit(IpcSender<()>),
Ping,
@ -248,10 +250,10 @@ impl FontCache {
fn handle_add_web_font(
&mut self,
family_name: LowercaseString,
mut sources: EffectiveSources,
mut sources: Vec<Source>,
sender: IpcSender<()>,
) {
let src = if let Some(src) = sources.next() {
let src = if let Some(src) = sources.pop() {
src
} else {
sender.send(()).unwrap();
@ -503,19 +505,58 @@ impl FontCacheThread {
FontCacheThread { chan }
}
pub fn add_web_font(
pub fn add_all_web_fonts_from_stylesheet(
&self,
family: FamilyName,
sources: EffectiveSources,
sender: IpcSender<()>,
) {
self.chan
.send(Command::AddWebFont(
LowercaseString::new(&family.name),
sources,
sender,
))
.unwrap();
stylesheet: &Stylesheet,
guard: &SharedRwLockReadGuard,
device: &Device,
font_cache_sender: &IpcSender<()>,
synchronous: bool,
) -> usize {
let (sender, receiver) = if synchronous {
let (sender, receiver) = ipc::channel().unwrap();
(Some(sender), Some(receiver))
} else {
(None, None)
};
let mut number_loading = 0;
stylesheet.effective_font_face_rules(&device, guard, |rule| {
let font_face = match rule.font_face() {
Some(font_face) => font_face,
None => return,
};
let sources: Vec<Source> = font_face
.sources()
.0
.iter()
.rev()
.filter(is_supported_web_font_source)
.cloned()
.collect();
if sources.is_empty() {
return;
}
let sender = sender.as_ref().unwrap_or(font_cache_sender).clone();
self.chan
.send(Command::AddWebFont(
LowercaseString::new(&font_face.family().name),
sources,
sender,
))
.unwrap();
// Either increment the count of loading web fonts, or wait for a synchronous load.
if let Some(ref receiver) = receiver {
receiver.recv().unwrap();
} else {
number_loading += 1;
}
});
number_loading
}
pub fn exit(&self) {
@ -624,3 +665,31 @@ impl fmt::Display for LowercaseString {
self.inner.fmt(f)
}
}
fn is_supported_web_font_source(source: &&Source) -> bool {
let url_source = match source {
Source::Url(ref url_source) => url_source,
Source::Local(_) => return true,
};
let format_hint = match url_source.format_hint {
Some(ref format_hint) => format_hint,
None => return true,
};
if matches!(
format_hint,
FontFaceSourceFormat::Keyword(
FontFaceSourceFormatKeyword::Truetype |
FontFaceSourceFormatKeyword::Opentype |
FontFaceSourceFormatKeyword::Woff
)
) {
return true;
}
if let FontFaceSourceFormat::String(string) = format_hint {
return string == "truetype" || string == "opentype" || string == "woff";
}
false
}

View file

@ -24,6 +24,7 @@ use style::values::computed::font::{
FamilyName, FontFamily, FontFamilyList, FontFamilyNameSyntax, FontSize, FontStretch, FontStyle,
FontWeight, SingleFontFamily,
};
use style::values::computed::FontLanguageOverride;
use webrender_api::{FontInstanceKey, FontKey, IdNamespace};
struct TestFontSource {
@ -100,6 +101,7 @@ fn style() -> FontStyleStruct {
font_size: FontSize::medium(),
font_stretch: FontStretch::hundred(),
hash: 0,
font_language_override: FontLanguageOverride::normal(),
};
style.compute_font_hash();
style

View file

@ -295,43 +295,6 @@ impl<'a, 'b: 'a> RwData<'a, 'b> {
}
}
fn add_font_face_rules(
stylesheet: &Stylesheet,
guard: &SharedRwLockReadGuard,
device: &Device,
font_cache_thread: &FontCacheThread,
font_cache_sender: &IpcSender<()>,
outstanding_web_fonts_counter: &Arc<AtomicUsize>,
load_webfonts_synchronously: bool,
) {
if load_webfonts_synchronously {
let (sender, receiver) = ipc::channel().unwrap();
stylesheet.effective_font_face_rules(&device, guard, |rule| {
if let Some(font_face) = rule.font_face() {
let effective_sources = font_face.effective_sources();
font_cache_thread.add_web_font(
font_face.family().clone(),
effective_sources,
sender.clone(),
);
receiver.recv().unwrap();
}
})
} else {
stylesheet.effective_font_face_rules(&device, guard, |rule| {
if let Some(font_face) = rule.font_face() {
let effective_sources = font_face.effective_sources();
outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst);
font_cache_thread.add_web_font(
font_face.family().clone(),
effective_sources,
(*font_cache_sender).clone(),
);
}
})
}
}
impl Layout for LayoutThread {
fn process(&mut self, msg: script_layout_interface::message::Msg) {
self.handle_request(Request::FromScript(msg));
@ -644,15 +607,16 @@ impl LayoutThread {
// Find all font-face rules and notify the font cache of them.
// GWTODO: Need to handle unloading web fonts.
if stylesheet.is_effective_for_device(self.stylist.device(), &guard) {
add_font_face_rules(
&*stylesheet,
&guard,
self.stylist.device(),
&self.font_cache_thread,
&self.font_cache_sender,
&self.outstanding_web_fonts,
self.debug.load_webfonts_synchronously,
);
let newly_loading_font_count =
self.font_cache_thread.add_all_web_fonts_from_stylesheet(
&*stylesheet,
&guard,
self.stylist.device(),
&self.font_cache_sender,
self.debug.load_webfonts_synchronously,
);
self.outstanding_web_fonts
.fetch_add(newly_loading_font_count, Ordering::SeqCst);
}
}

View file

@ -273,42 +273,6 @@ impl<'a, 'b: 'a> RwData<'a, 'b> {
}
}
fn add_font_face_rules(
stylesheet: &Stylesheet,
guard: &SharedRwLockReadGuard,
device: &Device,
font_cache_thread: &FontCacheThread,
font_cache_sender: &IpcSender<()>,
outstanding_web_fonts_counter: &Arc<AtomicUsize>,
load_webfonts_synchronously: bool,
) {
if load_webfonts_synchronously {
let (sender, receiver) = ipc::channel().unwrap();
stylesheet.effective_font_face_rules(&device, guard, |rule| {
if let Some(font_face) = rule.font_face() {
let effective_sources = font_face.effective_sources();
font_cache_thread.add_web_font(
font_face.family().clone(),
effective_sources,
sender.clone(),
);
receiver.recv().unwrap();
}
})
} else {
stylesheet.effective_font_face_rules(&device, guard, |rule| {
if let Some(font_face) = rule.font_face() {
let effective_sources = font_face.effective_sources();
outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst);
font_cache_thread.add_web_font(
font_face.family().clone(),
effective_sources,
(*font_cache_sender).clone(),
);
}
})
}
}
impl Layout for LayoutThread {
fn process(&mut self, msg: script_layout_interface::message::Msg) {
self.handle_request(Request::FromScript(msg));
@ -578,15 +542,16 @@ impl LayoutThread {
// Find all font-face rules and notify the font cache of them.
// GWTODO: Need to handle unloading web fonts.
if stylesheet.is_effective_for_device(self.stylist.device(), &guard) {
add_font_face_rules(
&*stylesheet,
&guard,
self.stylist.device(),
&self.font_cache_thread,
&self.font_cache_sender,
&self.outstanding_web_fonts,
self.debug.load_webfonts_synchronously,
);
let newly_loading_font_count =
self.font_cache_thread.add_all_web_fonts_from_stylesheet(
&*stylesheet,
&guard,
self.stylist.device(),
&self.font_cache_sender,
self.debug.load_webfonts_synchronously,
);
self.outstanding_web_fonts
.fetch_add(newly_loading_font_count, Ordering::SeqCst);
}
}

View file

@ -67,3 +67,39 @@
[Setting font-stretch to normal should not prevent the font shorthand from serializing in computed style]
expected: FAIL
[Setting font-language-override to initial should prevent the font shorthand from serializing in specified style]
expected: FAIL
[Setting font-language-override to initial should not prevent the font shorthand from serializing in computed style]
expected: FAIL
[Setting font-language-override to inherit should prevent the font shorthand from serializing in specified style]
expected: FAIL
[Setting font-language-override to inherit should not prevent the font shorthand from serializing in computed style]
expected: FAIL
[Setting font-language-override to unset should prevent the font shorthand from serializing in specified style]
expected: FAIL
[Setting font-language-override to unset should not prevent the font shorthand from serializing in computed style]
expected: FAIL
[Setting font-language-override to revert should prevent the font shorthand from serializing in specified style]
expected: FAIL
[Setting font-language-override to revert should not prevent the font shorthand from serializing in computed style]
expected: FAIL
[Setting font-language-override to revert-layer should prevent the font shorthand from serializing in specified style]
expected: FAIL
[Setting font-language-override to revert-layer should not prevent the font shorthand from serializing in computed style]
expected: FAIL
[Setting font-language-override to normal should not prevent the font shorthand from serializing in computed style]
expected: FAIL
[Setting font-language-override to "SRB" should prevent the font shorthand from serializing in specified style]
expected: FAIL

View file

@ -1,2 +1,3 @@
[font-shorthand-subproperties-reset.html]
expected: TIMEOUT
[Property font-language-override should be reset to its initial value.]
expected: FAIL

View file

@ -62,9 +62,6 @@
[Property font-variant-alternates has initial value normal]
expected: FAIL
[Property font-language-override inherits]
expected: FAIL
[Property font-optical-sizing has initial value auto]
expected: FAIL
@ -74,9 +71,6 @@
[Property font-variant-alternates inherits]
expected: FAIL
[Property font-language-override has initial value normal]
expected: FAIL
[Property font-synthesis has initial value weight style small-caps]
expected: FAIL

View file

@ -5,20 +5,5 @@
[Property font-language-override value 'normal' computes to 'normal']
expected: FAIL
[Property font-language-override value 'normal']
expected: FAIL
[Property font-language-override value '"ksw"']
expected: FAIL
[Property font-language-override value '"KSW"']
expected: FAIL
[Property font-language-override value '"ENG "']
expected: FAIL
[Property font-language-override value '"en "']
expected: FAIL
[Property font-language-override value '" en "']
expected: FAIL

View file

@ -1,27 +0,0 @@
[font-language-override-valid.html]
[e.style['font-language-override'\] = "\\"ksw\\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "normal" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"KSW\\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"APPH\\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"ENG \\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"tr\\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"en \\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\" en \\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"1 %\\"" should set the property value]
expected: FAIL

View file

@ -16,3 +16,24 @@
[Setting font-variant to none should prevent the font shorthand from serializing in computed style]
expected: FAIL
[Setting font-language-override to initial should prevent the font shorthand from serializing in specified style]
expected: FAIL
[Setting font-language-override to inherit should prevent the font shorthand from serializing in specified style]
expected: FAIL
[Setting font-language-override to unset should prevent the font shorthand from serializing in specified style]
expected: FAIL
[Setting font-language-override to revert should prevent the font shorthand from serializing in specified style]
expected: FAIL
[Setting font-language-override to revert-layer should prevent the font shorthand from serializing in specified style]
expected: FAIL
[Setting font-language-override to "SRB" should prevent the font shorthand from serializing in specified style]
expected: FAIL
[Setting font-language-override to "SRB" should prevent the font shorthand from serializing in computed style]
expected: FAIL

View file

@ -1,2 +1,3 @@
[font-shorthand-subproperties-reset.html]
expected: TIMEOUT
[Property font-language-override should be reset to its initial value.]
expected: FAIL

View file

@ -11,12 +11,6 @@
[Property font-kerning inherits]
expected: FAIL
[Property font-language-override has initial value normal]
expected: FAIL
[Property font-language-override inherits]
expected: FAIL
[Property font-optical-sizing has initial value auto]
expected: FAIL

View file

@ -1,15 +0,0 @@
[font-language-override-computed.html]
[Property font-language-override value 'normal']
expected: FAIL
[Property font-language-override value '"KSW"']
expected: FAIL
[Property font-language-override value '"ENG "']
expected: FAIL
[Property font-language-override value '"en "']
expected: FAIL
[Property font-language-override value '" en "']
expected: FAIL

View file

@ -1,27 +0,0 @@
[font-language-override-valid.html]
[e.style['font-language-override'\] = "normal" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"KSW\\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"APPH\\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"ENG \\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"ksw\\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"tr\\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"en \\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\" en \\"" should set the property value]
expected: FAIL
[e.style['font-language-override'\] = "\\"1 %\\"" should set the property value]
expected: FAIL