From d8337541836dbed241afe890ae6cda66e6e21d2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 3 Oct 2018 23:50:21 +0200 Subject: [PATCH] style: Remove nsCSSValue usage from font code. Really sorry for the size of the patch. Differential Revision: https://phabricator.services.mozilla.com/D7753 --- components/style/cbindgen.toml | 25 ++- components/style/font_face.rs | 136 ++++++++++++--- components/style/gecko/rules.rs | 156 +----------------- .../gecko_bindings/sugar/ns_css_value.rs | 15 -- components/style/values/computed/font.rs | 1 + .../style/values/computed/percentage.rs | 1 + components/style/values/specified/font.rs | 55 +++--- 7 files changed, 170 insertions(+), 219 deletions(-) diff --git a/components/style/cbindgen.toml b/components/style/cbindgen.toml index 46162e43db5..8bcba69c057 100644 --- a/components/style/cbindgen.toml +++ b/components/style/cbindgen.toml @@ -6,7 +6,17 @@ autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated usi * 1. Get the latest cbindgen using `cargo install --force cbindgen` * a. Alternatively, you can clone `https://github.com/eqrion/cbindgen` and use a tagged release * 2. Run `rustup run nightly cbindgen toolkit/library/rust/ --lockfile Cargo.lock --crate style -o layout/style/ServoStyleConsts.h` - */""" + */ +class nsAtom; +namespace mozilla { + namespace css { + struct URLValue; + } + // Work-around weird cbindgen renaming. + typedef css::URLValue StyleURLValue; + typedef nsAtom StylensAtom; +} +""" include_guard = "mozilla_ServoStyleConsts_h" include_version = true braces = "SameLine" @@ -15,6 +25,10 @@ tab_width = 2 language = "C++" namespaces = ["mozilla"] +[parse] +parse_deps = true +include = ["cssparser"] + [struct] derive_eq = true @@ -25,9 +39,16 @@ derive_helper_methods = true prefix = "Style" include = [ "StyleAppearance", + "StyleComputedFontStretchRange", + "StyleComputedFontStyleDescriptor", + "StyleComputedFontWeightRange", "StyleDisplay", "StyleDisplayMode", "StyleFillRule", - "StylePathCommand" + "StyleFontDisplay", + "StyleFontFaceSourceListComponent", + "StyleFontLanguageOverride", + "StylePathCommand", + "StyleUnicodeRange", ] item_types = ["enums", "structs", "typedefs"] diff --git a/components/style/font_face.rs b/components/style/font_face.rs index fde25f08f6f..987ddb829b6 100644 --- a/components/style/font_face.rs +++ b/components/style/font_face.rs @@ -24,7 +24,7 @@ use style_traits::values::SequenceWriter; use values::computed::font::FamilyName; use values::generics::font::FontStyle as GenericFontStyle; use values::specified::Angle; -use values::specified::font::{AbsoluteFontWeight, FontStretch as SpecifiedFontStretch}; +use values::specified::font::{AbsoluteFontWeight, FontStretch}; #[cfg(feature = "gecko")] use values::specified::font::{SpecifiedFontFeatureSettings, SpecifiedFontVariationSettings}; use values::specified::font::SpecifiedFontStyle; @@ -45,6 +45,19 @@ impl OneOrMoreSeparated for Source { type S = Comma; } +/// A POD representation for Gecko. All pointers here are non-owned and as such +/// can't outlive the rule they came from, but we can't enforce that via C++. +/// +/// All the strings are of course utf8. +#[cfg(feature = "gecko")] +#[repr(u8)] +#[allow(missing_docs)] +pub enum FontFaceSourceListComponent { + Url(*const ::gecko_bindings::structs::mozilla::css::URLValue), + Local(*mut ::gecko_bindings::structs::nsAtom), + FormatHint { length: usize, utf8_bytes: *const u8 }, +} + /// A `UrlSource` represents a font-face source that has been specified with a /// `url()` function. /// @@ -84,6 +97,7 @@ impl ToCss for UrlSource { #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)] +#[repr(u8)] pub enum FontDisplay { Auto, Block, @@ -92,41 +106,83 @@ pub enum FontDisplay { Optional, } +macro_rules! impl_range { + ($range:ident, $component:ident) => { + impl Parse for $range { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let first = $component::parse(context, input)?; + let second = input + .try(|input| $component::parse(context, input)) + .unwrap_or_else(|_| first.clone()); + Ok($range(first, second)) + } + } + impl ToCss for $range { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: fmt::Write, + { + self.0.to_css(dest)?; + if self.0 != self.1 { + dest.write_str(" ")?; + self.1.to_css(dest)?; + } + Ok(()) + } + } + } +} + /// The font-weight descriptor: /// /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-weight -#[derive(Clone, Debug, PartialEq, ToCss)] -pub struct FontWeight(pub AbsoluteFontWeight, pub Option); +#[derive(Clone, Debug, PartialEq)] +pub struct FontWeightRange(pub AbsoluteFontWeight, pub AbsoluteFontWeight); +impl_range!(FontWeightRange, AbsoluteFontWeight); -impl Parse for FontWeight { - fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - let first = AbsoluteFontWeight::parse(context, input)?; - let second = input - .try(|input| AbsoluteFontWeight::parse(context, input)) - .ok(); - Ok(FontWeight(first, second)) +/// The computed representation of the above so Gecko can read them easily. +/// +/// This one is needed because cbindgen doesn't know how to generate +/// specified::Number. +#[repr(C)] +#[allow(missing_docs)] +pub struct ComputedFontWeightRange(f32, f32); + +impl FontWeightRange { + /// Returns a computed font-stretch range. + pub fn compute(&self) -> ComputedFontWeightRange { + ComputedFontWeightRange(self.0.compute().0, self.1.compute().0) } } /// The font-stretch descriptor: /// /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-stretch -#[derive(Clone, Debug, PartialEq, ToCss)] -pub struct FontStretch(pub SpecifiedFontStretch, pub Option); +#[derive(Clone, Debug, PartialEq,)] +pub struct FontStretchRange(pub FontStretch, pub FontStretch); +impl_range!(FontStretchRange, FontStretch); -impl Parse for FontStretch { - fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - let first = SpecifiedFontStretch::parse(context, input)?; - let second = input - .try(|input| SpecifiedFontStretch::parse(context, input)) - .ok(); - Ok(FontStretch(first, second)) +/// The computed representation of the above, so that +/// Gecko can read them easily. +#[repr(C)] +#[allow(missing_docs)] +pub struct ComputedFontStretchRange(f32, f32); + +impl FontStretchRange { + /// Returns a computed font-stretch range. + pub fn compute(&self) -> ComputedFontStretchRange { + fn compute_stretch(s: &FontStretch) -> f32 { + match *s { + FontStretch::Keyword(ref kw) => kw.compute().0, + FontStretch::Stretch(ref p) => p.get(), + FontStretch::System(..) => unreachable!(), + } + } + + ComputedFontStretchRange(compute_stretch(&self.0), compute_stretch(&self.1)) } } @@ -141,6 +197,16 @@ pub enum FontStyle { Oblique(Angle, Angle), } +/// The computed representation of the above, with angles in degrees, so that +/// Gecko can read them easily. +#[repr(u8)] +#[allow(missing_docs)] +pub enum ComputedFontStyleDescriptor { + Normal, + Italic, + Oblique(f32, f32), +} + impl Parse for FontStyle { fn parse<'i, 't>( context: &ParserContext, @@ -185,6 +251,22 @@ impl ToCss for FontStyle { } } +impl FontStyle { + /// Returns a computed font-style descriptor. + pub fn compute(&self) -> ComputedFontStyleDescriptor { + match *self { + FontStyle::Normal => ComputedFontStyleDescriptor::Normal, + FontStyle::Italic => ComputedFontStyleDescriptor::Italic, + FontStyle::Oblique(ref first, ref second) => { + ComputedFontStyleDescriptor::Oblique( + SpecifiedFontStyle::compute_angle_degrees(first), + SpecifiedFontStyle::compute_angle_degrees(second), + ) + } + } + } +} + /// Parse the block inside a `@font-face` rule. /// /// Note that the prelude parsing code lives in the `stylesheets` module. @@ -459,10 +541,10 @@ font_face_descriptors! { "font-style" style / mStyle: FontStyle, /// The weight of this font face. - "font-weight" weight / mWeight: FontWeight, + "font-weight" weight / mWeight: FontWeightRange, /// The stretch of this font face. - "font-stretch" stretch / mStretch: FontStretch, + "font-stretch" stretch / mStretch: FontStretchRange, /// The display of this font face. "font-display" display / mDisplay: FontDisplay, diff --git a/components/style/gecko/rules.rs b/components/style/gecko/rules.rs index 233b1757ef5..11970151fb8 100644 --- a/components/style/gecko/rules.rs +++ b/components/style/gecko/rules.rs @@ -4,139 +4,10 @@ //! Bindings for CSS Rule objects -use byteorder::{BigEndian, WriteBytesExt}; use counter_style::{self, CounterBound}; -use cssparser::UnicodeRange; -use font_face::{FontDisplay, FontWeight, FontStretch, FontStyle, Source}; +use font_face::Source; use gecko_bindings::structs::{self, nsCSSValue}; use gecko_bindings::sugar::ns_css_value::ToNsCssValue; -use properties::longhands::font_language_override; -use std::str; -use values::computed::font::FamilyName; -use values::generics::font::FontTag; -use values::specified::font::{AbsoluteFontWeight, FontStretch as SpecifiedFontStretch}; -use values::specified::font::{SpecifiedFontFeatureSettings, SpecifiedFontVariationSettings}; -use values::specified::font::SpecifiedFontStyle; - -impl<'a> ToNsCssValue for &'a FamilyName { - fn convert(self, nscssvalue: &mut nsCSSValue) { - nscssvalue.set_string_from_atom(&self.name) - } -} - -impl<'a> ToNsCssValue for &'a SpecifiedFontStretch { - fn convert(self, nscssvalue: &mut nsCSSValue) { - let number = match *self { - SpecifiedFontStretch::Stretch(ref p) => p.get(), - SpecifiedFontStretch::Keyword(ref kw) => kw.compute().0, - SpecifiedFontStretch::System(..) => unreachable!(), - }; - nscssvalue.set_font_stretch(number); - } -} - -impl<'a> ToNsCssValue for &'a AbsoluteFontWeight { - fn convert(self, nscssvalue: &mut nsCSSValue) { - nscssvalue.set_font_weight(self.compute().0) - } -} - -impl ToNsCssValue for FontTag { - fn convert(self, nscssvalue: &mut nsCSSValue) { - let mut raw = [0u8; 4]; - (&mut raw[..]).write_u32::(self.0).unwrap(); - nscssvalue.set_string(str::from_utf8(&raw).unwrap()); - } -} - -impl<'a> ToNsCssValue for &'a SpecifiedFontFeatureSettings { - fn convert(self, nscssvalue: &mut nsCSSValue) { - if self.0.is_empty() { - nscssvalue.set_normal(); - return; - } - - nscssvalue.set_pair_list(self.0.iter().map(|entry| { - let mut index = nsCSSValue::null(); - index.set_integer(entry.value.value()); - (entry.tag.into(), index) - })) - } -} - -impl<'a> ToNsCssValue for &'a SpecifiedFontVariationSettings { - fn convert(self, nscssvalue: &mut nsCSSValue) { - if self.0.is_empty() { - nscssvalue.set_normal(); - return; - } - - nscssvalue.set_pair_list(self.0.iter().map(|entry| { - let mut value = nsCSSValue::null(); - value.set_number(entry.value.into()); - (entry.tag.into(), value) - })) - } -} - -macro_rules! descriptor_range_conversion { - ($name:ident) => { - impl<'a> ToNsCssValue for &'a $name { - fn convert(self, nscssvalue: &mut nsCSSValue) { - let $name(ref first, ref second) = *self; - let second = match *second { - None => { - nscssvalue.set_from(first); - return; - }, - Some(ref second) => second, - }; - - let mut a = nsCSSValue::null(); - let mut b = nsCSSValue::null(); - - a.set_from(first); - b.set_from(second); - - nscssvalue.set_pair(&a, &b); - } - } - }; -} - -descriptor_range_conversion!(FontWeight); -descriptor_range_conversion!(FontStretch); - -impl<'a> ToNsCssValue for &'a FontStyle { - fn convert(self, nscssvalue: &mut nsCSSValue) { - match *self { - FontStyle::Normal => nscssvalue.set_normal(), - FontStyle::Italic => nscssvalue.set_enum(structs::NS_FONT_STYLE_ITALIC as i32), - FontStyle::Oblique(ref first, ref second) => { - let mut a = nsCSSValue::null(); - let mut b = nsCSSValue::null(); - - a.set_font_style(SpecifiedFontStyle::compute_angle(first).degrees()); - b.set_font_style(SpecifiedFontStyle::compute_angle(second).degrees()); - - nscssvalue.set_pair(&a, &b); - }, - } - } -} - -impl<'a> ToNsCssValue for &'a font_language_override::SpecifiedValue { - fn convert(self, nscssvalue: &mut nsCSSValue) { - match *self { - font_language_override::SpecifiedValue::Normal => nscssvalue.set_normal(), - font_language_override::SpecifiedValue::Override(ref lang) => { - nscssvalue.set_string(&*lang) - }, - // This path is unreachable because the descriptor is only specified by the user. - font_language_override::SpecifiedValue::System(_) => unreachable!(), - } - } -} impl<'a> ToNsCssValue for &'a Vec { fn convert(self, nscssvalue: &mut nsCSSValue) { @@ -175,31 +46,6 @@ impl<'a> ToNsCssValue for &'a Vec { } } -impl<'a> ToNsCssValue for &'a Vec { - fn convert(self, nscssvalue: &mut nsCSSValue) { - let target_ranges = nscssvalue - .set_array((self.len() * 2) as i32) - .as_mut_slice() - .chunks_mut(2); - for (range, target) in self.iter().zip(target_ranges) { - target[0].set_integer(range.start as i32); - target[1].set_integer(range.end as i32); - } - } -} - -impl<'a> ToNsCssValue for &'a FontDisplay { - fn convert(self, nscssvalue: &mut nsCSSValue) { - nscssvalue.set_enum(match *self { - FontDisplay::Auto => structs::NS_FONT_DISPLAY_AUTO, - FontDisplay::Block => structs::NS_FONT_DISPLAY_BLOCK, - FontDisplay::Swap => structs::NS_FONT_DISPLAY_SWAP, - FontDisplay::Fallback => structs::NS_FONT_DISPLAY_FALLBACK, - FontDisplay::Optional => structs::NS_FONT_DISPLAY_OPTIONAL, - } as i32) - } -} - impl<'a> ToNsCssValue for &'a counter_style::System { fn convert(self, nscssvalue: &mut nsCSSValue) { use counter_style::System::*; diff --git a/components/style/gecko_bindings/sugar/ns_css_value.rs b/components/style/gecko_bindings/sugar/ns_css_value.rs index 644166e3797..c026161bddc 100644 --- a/components/style/gecko_bindings/sugar/ns_css_value.rs +++ b/components/style/gecko_bindings/sugar/ns_css_value.rs @@ -177,21 +177,6 @@ impl nsCSSValue { self.set_string_from_atom_internal(s, nsCSSUnit::eCSSUnit_Local_Font); } - /// Set to a font stretch. - pub fn set_font_stretch(&mut self, s: f32) { - unsafe { bindings::Gecko_CSSValue_SetFontStretch(self, s) } - } - - /// Set to a font style - pub fn set_font_style(&mut self, s: f32) { - unsafe { bindings::Gecko_CSSValue_SetFontSlantStyle(self, s) } - } - - /// Set to a font weight - pub fn set_font_weight(&mut self, w: f32) { - unsafe { bindings::Gecko_CSSValue_SetFontWeight(self, w) } - } - fn set_int_internal(&mut self, value: i32, unit: nsCSSUnit) { unsafe { bindings::Gecko_CSSValue_SetInt(self, value, unit) } } diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs index 4cb8f7a7bdf..911193b0c0b 100644 --- a/components/style/values/computed/font.rs +++ b/components/style/values/computed/font.rs @@ -747,6 +747,7 @@ pub type FontVariationSettings = FontSettings>; /// it and store it as a 32-bit integer /// (see http://www.microsoft.com/typography/otspec/languagetags.htm). #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)] +#[repr(C)] pub struct FontLanguageOverride(pub u32); impl FontLanguageOverride { diff --git a/components/style/values/computed/percentage.rs b/components/style/values/computed/percentage.rs index 4e9ae6172a9..e7f038f4bef 100644 --- a/components/style/values/computed/percentage.rs +++ b/components/style/values/computed/percentage.rs @@ -27,6 +27,7 @@ use values::generics::NonNegative; ToAnimatedZero, ToComputedValue, )] +#[repr(C)] pub struct Percentage(pub CSSFloat); impl Percentage { diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs index 5613ae603d2..cdfe3228c8b 100644 --- a/components/style/values/specified/font.rs +++ b/components/style/values/specified/font.rs @@ -292,14 +292,16 @@ pub const FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES: f32 = 90.; pub const FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES: f32 = -90.; impl SpecifiedFontStyle { - /// Gets a clamped angle from a specified Angle. - pub fn compute_angle(angle: &Angle) -> ComputedAngle { - ComputedAngle::Deg( - angle - .degrees() - .max(FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES) - .min(FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES), - ) + /// Gets a clamped angle in degrees from a specified Angle. + pub fn compute_angle_degrees(angle: &Angle) -> f32 { + angle + .degrees() + .max(FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES) + .min(FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES) + } + + fn compute_angle(angle: &Angle) -> ComputedAngle { + ComputedAngle::Deg(Self::compute_angle_degrees(angle)) } /// Parse a suitable angle for font-style: oblique. @@ -380,6 +382,7 @@ impl Parse for FontStyle { /// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop #[allow(missing_docs)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] +#[repr(u8)] pub enum FontStretch { Stretch(Percentage), Keyword(FontStretchKeyword), @@ -2057,6 +2060,29 @@ impl FontLanguageOverride { FontLanguageOverride::Normal } + /// The ToComputedValue implementation for non-system-font + /// FontLanguageOverride, used for @font-face descriptors. + #[inline] + pub fn compute_non_system(&self) -> computed::FontLanguageOverride { + match *self { + FontLanguageOverride::Normal => computed::FontLanguageOverride(0), + FontLanguageOverride::Override(ref lang) => { + if lang.is_empty() || lang.len() > 4 { + return computed::FontLanguageOverride(0); + } + let mut bytes = [b' '; 4]; + for (byte, lang_byte) in bytes.iter_mut().zip(lang.as_bytes()) { + if !lang_byte.is_ascii() { + return computed::FontLanguageOverride(0); + } + *byte = *lang_byte; + } + computed::FontLanguageOverride(BigEndian::read_u32(&bytes)) + }, + FontLanguageOverride::System(..) => unreachable!(), + } + } + system_font_methods!(FontLanguageOverride, font_language_override); } @@ -2066,19 +2092,8 @@ impl ToComputedValue for FontLanguageOverride { #[inline] fn to_computed_value(&self, context: &Context) -> computed::FontLanguageOverride { match *self { - FontLanguageOverride::Normal => computed::FontLanguageOverride(0), - FontLanguageOverride::Override(ref lang) => { - if lang.is_empty() || lang.len() > 4 || !lang.is_ascii() { - return computed::FontLanguageOverride(0); - } - let mut computed_lang = lang.to_string(); - while computed_lang.len() < 4 { - computed_lang.push(' '); - } - let bytes = computed_lang.into_bytes(); - computed::FontLanguageOverride(BigEndian::read_u32(&bytes)) - }, FontLanguageOverride::System(_) => self.compute_system(context), + _ => self.compute_non_system(), } } #[inline]