From 449fe2338e9ce4af5a68ec82ee7b8e54a11bfdcb Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 27 Jan 2023 17:32:54 +0000 Subject: [PATCH] style: Create a pref to list icon font families that should be used even when use_document_fonts=0, overriding the browser's font prefs Some widely-used icon fonts use ligature rules to replace icon names such as "volume_up" or "down_arrow" with icon glyphs. If the site is designed to use such a font, but the user disables document fonts and we use our default Latin font instead, the underlying text will be rendered instead of the intended icon. To enable such fonts to continue to work, we provide a list of known ligature-icon fonts and allow them to be used even when the document-fonts setting is disabled. Differential Revision: https://phabricator.services.mozilla.com/D167923 --- components/style/values/computed/font.rs | 57 +++++++++++++++++++----- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index de6957c5952..f25501e0264 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -444,6 +444,13 @@ pub struct FamilyName { pub syntax: FontFamilyNameSyntax, } +impl FamilyName { + fn is_known_icon_font_family(&self) -> bool { + use crate::gecko_bindings::bindings; + unsafe { bindings::Gecko_IsKnownIconFontFamily(self.name.as_ptr()) } + } +} + impl ToCss for FamilyName { fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where @@ -706,26 +713,56 @@ impl FontFamilyList { } /// If there's a generic font family on the list which is suitable for user - /// font prioritization, then move it to the front of the list. Otherwise, - /// prepend the default generic. + /// font prioritization, then move it ahead of the other families in the list, + /// except for any families known to be ligature-based icon fonts, where using a + /// generic instead of the site's specified font may cause substantial breakage. + /// If no suitable generic is found in the list, insert the default generic ahead + /// of all the listed families except for known ligature-based icon fonts. #[cfg(feature = "gecko")] pub(crate) fn prioritize_first_generic_or_prepend(&mut self, generic: GenericFontFamily) { - let index_of_first_generic = self.iter().position(|f| match *f { - SingleFontFamily::Generic(f) => f.valid_for_user_font_prioritization(), - _ => false, - }); + let mut index_of_first_generic = None; + let mut target_index = None; - if let Some(0) = index_of_first_generic { - return; // Already first + for (i, f) in self.iter().enumerate() { + match &*f { + SingleFontFamily::Generic(f) => { + if index_of_first_generic.is_none() && f.valid_for_user_font_prioritization() { + // If we haven't found a target position, there's nothing to do; + // this entry is already ahead of everything except any whitelisted + // icon fonts. + if target_index.is_none() { + return; + } + index_of_first_generic = Some(i); + break; + } + // A non-prioritized generic (e.g. cursive, fantasy) becomes the target + // position for prioritization, just like arbitrary named families. + if target_index.is_none() { + target_index = Some(i); + } + }, + SingleFontFamily::FamilyName(fam) => { + // Target position for the first generic is in front of the first + // non-whitelisted icon font family we find. + if target_index.is_none() && !fam.is_known_icon_font_family() { + target_index = Some(i); + } + }, + } } let mut new_list = self.list.iter().cloned().collect::>(); - let element_to_prepend = match index_of_first_generic { + let first_generic = match index_of_first_generic { Some(i) => new_list.remove(i), None => SingleFontFamily::Generic(generic), }; - new_list.insert(0, element_to_prepend); + if let Some(i) = target_index { + new_list.insert(i, first_generic); + } else { + new_list.push(first_generic); + } self.list = crate::ArcSlice::from_iter(new_list.into_iter()); }