/* 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 byteorder::{BigEndian, WriteBytesExt}; use computed_values::{font_stretch, font_style, font_weight}; use counter_style::{self, CounterBound}; use cssparser::UnicodeRange; use font_face::{FontFaceRuleData, Source, FontDisplay, FontWeight}; use gecko_bindings::bindings; use gecko_bindings::structs::{self, nsCSSFontFaceRule, nsCSSValue}; use gecko_bindings::structs::{nsCSSCounterDesc, nsCSSCounterStyleRule}; use gecko_bindings::sugar::ns_css_value::ToNsCssValue; use gecko_bindings::sugar::refptr::{RefPtr, UniqueRefPtr}; use nsstring::nsString; use properties::longhands::font_language_override; use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard}; use std::fmt::{self, Write}; use std::str; use str::CssStringWriter; use values::computed::font::FamilyName; use values::generics::font::FontTag; use values::specified::font::{SpecifiedFontVariationSettings, SpecifiedFontFeatureSettings}; /// A @font-face rule pub type FontFaceRule = RefPtr; impl ToNsCssValue for FamilyName { fn convert(self, nscssvalue: &mut nsCSSValue) { nscssvalue.set_string_from_atom(&self.name) } } impl ToNsCssValue for font_weight::T { fn convert(self, nscssvalue: &mut nsCSSValue) { nscssvalue.set_integer(self.0 as i32) } } impl ToNsCssValue for FontWeight { fn convert(self, nscssvalue: &mut nsCSSValue) { match self { FontWeight::Normal => nscssvalue.set_enum(structs::NS_STYLE_FONT_WEIGHT_NORMAL as i32), FontWeight::Bold => nscssvalue.set_enum(structs::NS_STYLE_FONT_WEIGHT_BOLD as i32), FontWeight::Weight(weight) => nscssvalue.set_integer(weight.0 as i32), } } } 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 ToNsCssValue for SpecifiedFontFeatureSettings { fn convert(self, nscssvalue: &mut nsCSSValue) { if self.0.is_empty() { nscssvalue.set_normal(); return; } nscssvalue.set_pair_list(self.0.into_iter().map(|entry| { let mut index = nsCSSValue::null(); index.set_integer(entry.value.value()); (entry.tag.into(), index) })) } } impl ToNsCssValue for SpecifiedFontVariationSettings { fn convert(self, nscssvalue: &mut nsCSSValue) { if self.0.is_empty() { nscssvalue.set_normal(); return; } nscssvalue.set_pair_list(self.0.into_iter().map(|entry| { let mut value = nsCSSValue::null(); value.set_number(entry.value.into()); (entry.tag.into(), value) })) } } impl ToNsCssValue for 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!(), } } } macro_rules! map_enum { ( $( $prop:ident { $($servo:ident => $gecko:ident,)+ } )+ ) => { $( impl ToNsCssValue for $prop::T { fn convert(self, nscssvalue: &mut nsCSSValue) { nscssvalue.set_enum(match self { $( $prop::T::$servo => structs::$gecko as i32, )+ }) } } )+ } } map_enum! { font_style { Normal => NS_FONT_STYLE_NORMAL, Italic => NS_FONT_STYLE_ITALIC, Oblique => NS_FONT_STYLE_OBLIQUE, } font_stretch { Normal => NS_FONT_STRETCH_NORMAL, UltraCondensed => NS_FONT_STRETCH_ULTRA_CONDENSED, ExtraCondensed => NS_FONT_STRETCH_EXTRA_CONDENSED, Condensed => NS_FONT_STRETCH_CONDENSED, SemiCondensed => NS_FONT_STRETCH_SEMI_CONDENSED, SemiExpanded => NS_FONT_STRETCH_SEMI_EXPANDED, Expanded => NS_FONT_STRETCH_EXPANDED, ExtraExpanded => NS_FONT_STRETCH_EXTRA_EXPANDED, UltraExpanded => NS_FONT_STRETCH_ULTRA_EXPANDED, } } impl ToNsCssValue for Vec { fn convert(self, nscssvalue: &mut nsCSSValue) { let src_len = self.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 = nscssvalue.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 self.into_iter() { match src { Source::Url(url) => { next!().set_url(&url.url); for hint in url.format_hints.iter() { next!().set_font_format(&hint); } } Source::Local(family) => { next!().set_local_font(&family.name); } } } debug_assert!(target_srcs.next().is_none(), "Should have filled all slots"); } } impl ToNsCssValue for 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 ToNsCssValue for 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 FontFaceRule { /// Ask Gecko to deep clone the nsCSSFontFaceRule, and then construct /// a FontFaceRule object from it. pub fn deep_clone_from_gecko(&self) -> FontFaceRule { let result = unsafe { UniqueRefPtr::from_addrefed( bindings::Gecko_CSSFontFaceRule_Clone(self.get())) }; result.get() } } impl From for FontFaceRule { fn from(data: FontFaceRuleData) -> FontFaceRule { let mut result = unsafe { UniqueRefPtr::from_addrefed(bindings::Gecko_CSSFontFaceRule_Create( data.source_location.line as u32, data.source_location.column as u32 )) }; data.set_descriptors(&mut result.mDecl.mDescriptors); result.get() } } impl ToCssWithGuard for FontFaceRule { fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result { let mut css_text = nsString::new(); unsafe { bindings::Gecko_CSSFontFaceRule_GetCssText(self.get(), &mut *css_text); } write!(dest, "{}", css_text) } } /// A @counter-style rule pub type CounterStyleRule = RefPtr; impl CounterStyleRule { /// Ask Gecko to deep clone the nsCSSCounterStyleRule, and then construct /// a CounterStyleRule object from it. pub fn deep_clone_from_gecko(&self) -> CounterStyleRule { let result = unsafe { UniqueRefPtr::from_addrefed( bindings::Gecko_CSSCounterStyle_Clone(self.get())) }; result.get() } } impl From for CounterStyleRule { fn from(data: counter_style::CounterStyleRuleData) -> CounterStyleRule { let mut result = unsafe { UniqueRefPtr::from_addrefed( bindings::Gecko_CSSCounterStyle_Create(data.name().0.as_ptr())) }; data.set_descriptors(&mut result.mValues); result.get() } } impl ToCssWithGuard for CounterStyleRule { fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result { let mut css_text = nsString::new(); unsafe { bindings::Gecko_CSSCounterStyle_GetCssText(self.get(), &mut *css_text); } write!(dest, "{}", css_text) } } /// The type of nsCSSCounterStyleRule::mValues pub type CounterStyleDescriptors = [nsCSSValue; nsCSSCounterDesc::eCSSCounterDesc_COUNT as usize]; impl ToNsCssValue for counter_style::System { fn convert(self, nscssvalue: &mut nsCSSValue) { use counter_style::System::*; match self { Cyclic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC as i32), Numeric => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC as i32), Alphabetic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as i32), Symbolic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as i32), Additive => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ADDITIVE as i32), Fixed { first_symbol_value } => { let mut a = nsCSSValue::null(); let mut b = nsCSSValue::null(); a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_FIXED as i32); b.set_integer(first_symbol_value.map_or(1, |v| v.value())); nscssvalue.set_pair(&a, &b); } Extends(other) => { let mut a = nsCSSValue::null(); let mut b = nsCSSValue::null(); a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_EXTENDS as i32); b.set_atom_ident(other.0); nscssvalue.set_pair(&a, &b); } } } } impl ToNsCssValue for counter_style::Negative { fn convert(self, nscssvalue: &mut nsCSSValue) { if let Some(second) = self.1 { let mut a = nsCSSValue::null(); let mut b = nsCSSValue::null(); a.set_from(self.0); b.set_from(second); nscssvalue.set_pair(&a, &b); } else { nscssvalue.set_from(self.0) } } } impl ToNsCssValue for counter_style::Symbol { fn convert(self, nscssvalue: &mut nsCSSValue) { match self { counter_style::Symbol::String(s) => nscssvalue.set_string(&s), counter_style::Symbol::Ident(s) => nscssvalue.set_ident_from_atom(&s.0), } } } impl ToNsCssValue for counter_style::Ranges { fn convert(self, nscssvalue: &mut nsCSSValue) { if self.0.is_empty() { nscssvalue.set_auto(); } else { nscssvalue.set_pair_list(self.0.into_iter().map(|range| { fn set_bound(bound: CounterBound, nscssvalue: &mut nsCSSValue) { if let CounterBound::Integer(finite) = bound { nscssvalue.set_integer(finite.value()) } else { nscssvalue.set_enum(structs::NS_STYLE_COUNTER_RANGE_INFINITE as i32) } } let mut start = nsCSSValue::null(); let mut end = nsCSSValue::null(); set_bound(range.start, &mut start); set_bound(range.end, &mut end); (start, end) })); } } } impl ToNsCssValue for counter_style::Pad { fn convert(self, nscssvalue: &mut nsCSSValue) { let mut min_length = nsCSSValue::null(); let mut pad_with = nsCSSValue::null(); min_length.set_integer(self.0.value()); pad_with.set_from(self.1); nscssvalue.set_pair(&min_length, &pad_with); } } impl ToNsCssValue for counter_style::Fallback { fn convert(self, nscssvalue: &mut nsCSSValue) { nscssvalue.set_atom_ident(self.0 .0) } } impl ToNsCssValue for counter_style::Symbols { fn convert(self, nscssvalue: &mut nsCSSValue) { nscssvalue.set_list(self.0.into_iter().map(|item| { let mut value = nsCSSValue::null(); value.set_from(item); value })); } } impl ToNsCssValue for counter_style::AdditiveSymbols { fn convert(self, nscssvalue: &mut nsCSSValue) { nscssvalue.set_pair_list(self.0.into_iter().map(|tuple| { let mut weight = nsCSSValue::null(); let mut symbol = nsCSSValue::null(); weight.set_integer(tuple.weight.value()); symbol.set_from(tuple.symbol); (weight, symbol) })); } } impl ToNsCssValue for counter_style::SpeakAs { fn convert(self, nscssvalue: &mut nsCSSValue) { use counter_style::SpeakAs::*; match self { Auto => nscssvalue.set_auto(), Bullets => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_BULLETS as i32), Numbers => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_NUMBERS as i32), Words => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_WORDS as i32), Other(other) => nscssvalue.set_atom_ident(other.0), } } }