diff --git a/components/style/gecko/mod.rs b/components/style/gecko/mod.rs index 1e950fe2ad1..92582823527 100644 --- a/components/style/gecko/mod.rs +++ b/components/style/gecko/mod.rs @@ -13,6 +13,7 @@ pub mod data; pub mod global_style_data; pub mod media_queries; pub mod restyle_damage; +pub mod rules; pub mod selector_parser; pub mod snapshot; pub mod snapshot_helpers; diff --git a/components/style/gecko/rules.rs b/components/style/gecko/rules.rs new file mode 100644 index 00000000000..f725a65a524 --- /dev/null +++ b/components/style/gecko/rules.rs @@ -0,0 +1,121 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Bindings for CSS Rule objects + +use font_face::{FontFaceData, Source}; +use gecko_bindings::bindings; +use gecko_bindings::structs::{self, CSSFontFaceDescriptors, nsCSSFontFaceRule}; +use gecko_bindings::sugar::refptr::{RefPtr, UniqueRefPtr}; +use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard}; +use std::fmt; + +/// A @font-face rule +pub type FontFaceRule = RefPtr; + +fn set_font_face_descriptors(descriptors: &mut CSSFontFaceDescriptors, + data: FontFaceData) { + // font-family + descriptors.mFamily.set_string_from_atom(&data.family.0); + + macro_rules! map_enum { + ($target:ident = ($data:ident: $prop:ident) { + $($servo:ident => $gecko:ident,)+ + }) => {{ + use computed_values::$prop::T; + descriptors.$target.set_enum(match data.$data { + $( T::$servo => structs::$gecko as i32, )+ + }) + }} + } + + // font-style + map_enum!(mStyle = (style: font_style) { + normal => NS_FONT_STYLE_NORMAL, + italic => NS_FONT_STYLE_ITALIC, + oblique => NS_FONT_STYLE_OBLIQUE, + }); + + // font-weight + descriptors.mWeight.set_integer(data.weight as i32); + + // font-stretch + map_enum!(mStretch = (stretch: font_stretch) { + normal => NS_FONT_STRETCH_NORMAL, + ultra_condensed => NS_FONT_STRETCH_ULTRA_CONDENSED, + extra_condensed => NS_FONT_STRETCH_EXTRA_CONDENSED, + condensed => NS_FONT_STRETCH_CONDENSED, + semi_condensed => NS_FONT_STRETCH_SEMI_CONDENSED, + semi_expanded => NS_FONT_STRETCH_SEMI_EXPANDED, + expanded => NS_FONT_STRETCH_EXPANDED, + extra_expanded => NS_FONT_STRETCH_EXTRA_EXPANDED, + ultra_expanded => NS_FONT_STRETCH_ULTRA_EXPANDED, + }); + + // src + let src_len = data.sources.iter().fold(0, |acc, src| { + acc + match *src { + // Each format hint takes one position in the array of mSrc. + Source::Url(ref url) => url.format_hints.len() + 1, + Source::Local(_) => 1, + } + }); + let mut target_srcs = + descriptors.mSrc.set_array(src_len as i32).as_mut_slice().iter_mut(); + macro_rules! next { () => { + target_srcs.next().expect("Length of target_srcs should be enough") + } } + for src in data.sources.iter() { + match *src { + Source::Url(ref url) => { + next!().set_url(&url.url); + for hint in url.format_hints.iter() { + next!().set_font_format(&hint); + } + } + Source::Local(ref name) => { + next!().set_local_font(&name.0); + } + } + } + debug_assert!(target_srcs.next().is_none(), "Should have filled all slots"); + + // unicode-range + let target_ranges = descriptors.mUnicodeRange + .set_array((data.unicode_range.len() * 2) as i32) + .as_mut_slice().chunks_mut(2); + for (range, target) in data.unicode_range.iter().zip(target_ranges) { + target[0].set_integer(range.start as i32); + target[1].set_integer(range.end as i32); + } + + // The following three descriptors are not implemented yet. + // font-feature-settings + descriptors.mFontFeatureSettings.set_normal(); + // font-language-override + descriptors.mFontLanguageOverride.set_normal(); + // font-display + descriptors.mDisplay.set_enum(structs::NS_FONT_DISPLAY_AUTO as i32); +} + +impl From for FontFaceRule { + fn from(data: FontFaceData) -> FontFaceRule { + let mut result = unsafe { + UniqueRefPtr::from_addrefed(bindings::Gecko_CSSFontFaceRule_Create()) + }; + set_font_face_descriptors(&mut result.mDecl.mDescriptors, data); + result.get() + } +} + +impl ToCssWithGuard for FontFaceRule { + fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { + ns_auto_string!(css_text); + unsafe { + bindings::Gecko_CSSFontFaceRule_GetCssText(self.get(), &mut *css_text); + } + write!(dest, "{}", css_text) + } +} diff --git a/components/style/lib.rs b/components/style/lib.rs index 059e26c03ec..1708226f2dc 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -57,7 +57,9 @@ extern crate log; #[allow(unused_extern_crates)] #[macro_use] extern crate matches; -#[cfg(feature = "gecko")] extern crate nsstring_vendor as nsstring; +#[cfg(feature = "gecko")] +#[macro_use] +extern crate nsstring_vendor as nsstring; #[cfg(feature = "gecko")] extern crate num_cpus; extern crate num_integer; extern crate num_traits; diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index c40f81a2ef1..ba1ffb5d698 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -11,7 +11,11 @@ use cssparser::{AtRuleParser, Parser, QualifiedRuleParser}; use cssparser::{AtRuleType, RuleListParser, SourcePosition, Token, parse_one_rule}; use cssparser::ToCss as ParserToCss; use error_reporting::ParseErrorReporter; -use font_face::{FontFaceData, parse_font_face_block}; +#[cfg(feature = "servo")] +use font_face::FontFaceData; +use font_face::parse_font_face_block; +#[cfg(feature = "gecko")] +pub use gecko::rules::FontFaceRule; use keyframes::{Keyframe, parse_keyframe_list}; use media_queries::{Device, MediaList, parse_media_query_list}; use parking_lot::RwLock; @@ -552,6 +556,7 @@ impl ToCssWithGuard for StyleRule { } /// A @font-face rule +#[cfg(feature = "servo")] pub type FontFaceRule = FontFaceData; impl Stylesheet {