diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index 78280299aa0..85997cdb3c2 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -308,6 +308,7 @@ mod bindings { "mozilla::SERVO_PREF_.*", "kNameSpaceID_.*", "kGenericFont_.*", + "kPresContext_.*", ]; let whitelist = [ "RawGecko.*", diff --git a/components/style/font_metrics.rs b/components/style/font_metrics.rs index 43f6e570e13..5210ded345e 100644 --- a/components/style/font_metrics.rs +++ b/components/style/font_metrics.rs @@ -46,8 +46,16 @@ impl FontMetricsProvider for ServoMetricsProvider { fn create_from(_: &SharedStyleContext) -> Self { ServoMetricsProvider } + + fn get_size(&self, _font_name: &Atom, _font_family: u8) -> Au { + unreachable!("Dummy provider should never be used to compute font size") + } } +// Servo's font metrics provider will probably not live in this crate, so this will +// have to be replaced with something else (perhaps a trait method on TElement) +// when we get there + #[cfg(feature = "gecko")] /// Construct a font metrics provider for the current product pub fn get_metrics_provider_for_product() -> ::gecko::wrapper::GeckoFontMetricsProvider { @@ -61,7 +69,7 @@ pub fn get_metrics_provider_for_product() -> ServoMetricsProvider { } /// A trait used to represent something capable of providing us font metrics. -pub trait FontMetricsProvider: Send + fmt::Debug { +pub trait FontMetricsProvider: fmt::Debug { /// Obtain the metrics for given font family. /// /// TODO: We could make this take the full list, I guess, and save a few @@ -72,9 +80,7 @@ pub trait FontMetricsProvider: Send + fmt::Debug { } /// Get default size of a given language and generic family - fn get_size(&self, _font_name: &Atom, _font_family: u8) -> Au { - unimplemented!() - } + fn get_size(&self, font_name: &Atom, font_family: u8) -> Au; /// Construct from a shared style context fn create_from(context: &SharedStyleContext) -> Self where Self: Sized; diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 37f4c00cd08..e0b1b4af0f0 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -14,6 +14,7 @@ //! style system it's kind of pointless in the Stylo case, and only Servo forces //! the separation between the style system implementation and everything else. +use app_units::Au; use atomic_refcell::AtomicRefCell; use context::{SharedStyleContext, UpdateAnimationsTasks}; use data::ElementData; @@ -21,6 +22,7 @@ use dom::{self, AnimationRules, DescendantsBit, LayoutIterator, NodeInfo, TEleme use dom::{OpaqueNode, PresentationalHintsSynthetizer}; use element_state::ElementState; use error_reporting::StdoutErrorReporter; +use font_metrics::FontMetricsProvider; use gecko::global_style_data::GLOBAL_STYLE_DATA; use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement}; use gecko::snapshot_helpers; @@ -432,8 +434,11 @@ fn get_animation_rule(element: &GeckoElement, pub struct GeckoFontMetricsProvider { /// Cache of base font sizes for each language /// - /// Should have at most 31 elements (the number of language groups). Usually - /// will have 1. + /// Usually will have 1 element. + /// + // This may be slow on pages using more languages, might be worth optimizing + // by caching lang->group mapping separately and/or using a hashmap on larger + // loads. pub font_size_cache: RefCell>, } @@ -446,10 +451,38 @@ impl GeckoFontMetricsProvider { } } -impl ::font_metrics::FontMetricsProvider for GeckoFontMetricsProvider { - fn create_from(_: &SharedStyleContext) -> Self { +impl FontMetricsProvider for GeckoFontMetricsProvider { + fn create_from(_: &SharedStyleContext) -> GeckoFontMetricsProvider { GeckoFontMetricsProvider::new() } + + fn get_size(&self, font_name: &Atom, font_family: u8) -> Au { + use gecko_bindings::bindings::Gecko_GetBaseSize; + let mut cache = self.font_size_cache.borrow_mut(); + if let Some(sizes) = cache.iter().find(|el| el.0 == *font_name) { + return sizes.1.size_for_generic(font_family); + } + let sizes = unsafe { + Gecko_GetBaseSize(font_name.as_ptr()) + }; + cache.push((font_name.clone(), sizes)); + sizes.size_for_generic(font_family) + } +} + +impl structs::FontSizePrefs { + fn size_for_generic(&self, font_family: u8) -> Au { + Au(match font_family { + structs::kPresContext_DefaultVariableFont_ID => self.mDefaultVariableSize, + structs::kPresContext_DefaultFixedFont_ID => self.mDefaultFixedSize, + structs::kGenericFont_serif => self.mDefaultSerifSize, + structs::kGenericFont_sans_serif => self.mDefaultSansSerifSize, + structs::kGenericFont_monospace => self.mDefaultMonospaceSize, + structs::kGenericFont_cursive => self.mDefaultCursiveSize, + structs::kGenericFont_fantasy => self.mDefaultFantasySize, + x => unreachable!("Unknown generic ID {}", x), + }) + } } impl<'le> TElement for GeckoElement<'le> { diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index ffec9f8c804..ba6f97defcf 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -1063,9 +1063,7 @@ extern "C" { aSource: *const nsStyleFont); } extern "C" { - pub fn Gecko_GetBaseSize(lang: *mut nsIAtom, - pres_context: RawGeckoPresContextBorrowed) - -> FontSizePrefs; + pub fn Gecko_GetBaseSize(lang: *mut nsIAtom) -> FontSizePrefs; } extern "C" { pub fn Gecko_GetMediaFeatures() -> *const nsMediaFeature; diff --git a/components/style/gecko_bindings/structs_debug.rs b/components/style/gecko_bindings/structs_debug.rs index 92a983b4ecd..1c65c51d414 100644 --- a/components/style/gecko_bindings/structs_debug.rs +++ b/components/style/gecko_bindings/structs_debug.rs @@ -19547,6 +19547,8 @@ pub mod root { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct gfxMissingFontRecorder([u8; 0]); + pub const kPresContext_DefaultVariableFont_ID: u8 = 0; + pub const kPresContext_DefaultFixedFont_ID: u8 = 1; #[repr(C)] #[derive(Debug)] pub struct nsRootPresContext { diff --git a/components/style/gecko_bindings/structs_release.rs b/components/style/gecko_bindings/structs_release.rs index f7fc2d3072b..e75474a2b43 100644 --- a/components/style/gecko_bindings/structs_release.rs +++ b/components/style/gecko_bindings/structs_release.rs @@ -18981,6 +18981,8 @@ pub mod root { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct gfxMissingFontRecorder([u8; 0]); + pub const kPresContext_DefaultVariableFont_ID: u8 = 0; + pub const kPresContext_DefaultFixedFont_ID: u8 = 1; #[repr(C)] #[derive(Debug)] pub struct nsRootPresContext { diff --git a/components/style/gecko_string_cache/mod.rs b/components/style/gecko_string_cache/mod.rs index b10fd58174a..ca2c37ec213 100644 --- a/components/style/gecko_string_cache/mod.rs +++ b/components/style/gecko_string_cache/mod.rs @@ -186,10 +186,11 @@ impl fmt::Display for WeakAtom { impl Atom { /// Execute a callback with the atom represented by `ptr`. - pub unsafe fn with(ptr: *mut nsIAtom, callback: &mut F) where F: FnMut(&Atom) { + pub unsafe fn with(ptr: *mut nsIAtom, callback: &mut F) -> R where F: FnMut(&Atom) -> R { let atom = Atom(WeakAtom::new(ptr)); - callback(&atom); + let ret = callback(&atom); mem::forget(atom); + ret } /// Creates an atom from an static atom pointer without checking in release diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 81b10bdc48b..64c83d418c5 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -562,17 +562,10 @@ ${helpers.single_keyword("font-variant-caps", // XXXManishearth handle quirks mode - let base_sizes = unsafe { - Gecko_GetBaseSize(cx.style().get_font().gecko().mLanguage.raw()) - }; - let base_size = match cx.style().get_font().gecko().mGenericID { - structs::kGenericFont_serif => base_sizes.mDefaultSerifSize, - structs::kGenericFont_sans_serif => base_sizes.mDefaultSansSerifSize, - structs::kGenericFont_monospace => base_sizes.mDefaultMonospaceSize, - structs::kGenericFont_cursive => base_sizes.mDefaultCursiveSize, - structs::kGenericFont_fantasy => base_sizes.mDefaultFantasySize, - x => unreachable!("Unknown generic ID {}", x), - }; + let ref gecko_font = cx.style().get_font().gecko(); + let base_size = unsafe { Atom::with(gecko_font.mLanguage.raw(), &mut |atom| { + cx.font_metrics_provider.get_size(atom, gecko_font.mGenericID).0 + }) }; let base_size_px = au_to_int_px(base_size as f32); let html_size = *self as usize;