diff options
-rw-r--r-- | components/style/animation.rs | 63 | ||||
-rw-r--r-- | components/style/properties/data.py | 10 | ||||
-rw-r--r-- | components/style/properties/helpers.mako.rs | 2 | ||||
-rw-r--r-- | components/style/properties/helpers/animated_properties.mako.rs | 9 | ||||
-rw-r--r-- | components/style/properties/longhand/box.mako.rs | 46 | ||||
-rw-r--r-- | components/style/properties/properties.mako.rs | 186 | ||||
-rw-r--r-- | components/style/values.rs | 5 | ||||
-rw-r--r-- | ports/geckolib/properties.mako.rs | 199 | ||||
-rw-r--r-- | ports/geckolib/values.rs | 158 |
9 files changed, 452 insertions, 226 deletions
diff --git a/components/style/animation.rs b/components/style/animation.rs index 29cd2bfa06d..eb9dc9fd32d 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -253,10 +253,10 @@ impl PropertyAnimation { new_style: &mut C) -> Vec<PropertyAnimation> { let mut result = vec![]; - let box_style = new_style.as_servo().get_box(); - let transition_property = box_style.transition_property.0[transition_index]; - let timing_function = *box_style.transition_timing_function.0.get_mod(transition_index); - let duration = *box_style.transition_duration.0.get_mod(transition_index); + let box_style = new_style.get_box(); + let transition_property = box_style.transition_property_at(transition_index); + let timing_function = box_style.transition_timing_function_mod(transition_index); + let duration = box_style.transition_duration_mod(transition_index); if transition_property != TransitionProperty::All { @@ -333,23 +333,6 @@ impl PropertyAnimation { } } -/// Accesses an element of an array, "wrapping around" using modular arithmetic. This is needed -/// to handle [repeatable lists][lists] of differing lengths. -/// -/// [lists]: https://drafts.csswg.org/css-transitions/#animtype-repeatable-list -pub trait GetMod { - type Item; - fn get_mod(&self, i: usize) -> &Self::Item; -} - -impl<T> GetMod for Vec<T> { - type Item = T; - #[inline] - fn get_mod(&self, i: usize) -> &T { - &(*self)[i % self.len()] - } -} - /// Inserts transitions into the queue of running animations as applicable for /// the given style difference. This is called from the layout worker threads. /// Returns true if any animations were kicked off and false otherwise. @@ -362,7 +345,7 @@ pub fn start_transitions_if_applicable<Impl: SelectorImplExt>(new_animations_sen new_style: &mut Arc<Impl::ComputedValues>) -> bool { let mut had_animations = false; - for i in 0..new_style.get_box().transition_count() { + for i in 0..new_style.get_box().transition_property_count() { // Create any property animations, if applicable. let property_animations = PropertyAnimation::from_transition(i, old_style, Arc::make_mut(new_style)); for property_animation in property_animations { @@ -372,13 +355,13 @@ pub fn start_transitions_if_applicable<Impl: SelectorImplExt>(new_animations_sen property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0); // Kick off the animation. + let box_style = new_style.get_box(); let now = time::precise_time_s(); - let box_style = new_style.as_servo().get_box(); let start_time = - now + (box_style.transition_delay.0.get_mod(i).seconds() as f64); + now + (box_style.transition_delay_mod(i).seconds() as f64); new_animations_sender .send(Animation::Transition(node, start_time, AnimationFrame { - duration: box_style.transition_duration.0.get_mod(i).seconds() as f64, + duration: box_style.transition_duration_mod(i).seconds() as f64, property_animation: property_animation, }, /* is_expired = */ false)).unwrap(); @@ -422,10 +405,10 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex { let mut had_animations = false; - let box_style = new_style.as_servo().get_box(); - for (i, name) in box_style.animation_name.0.iter().enumerate() { + let box_style = new_style.get_box(); + for (i, name) in box_style.animation_name_iter().enumerate() { debug!("maybe_start_animations: name={}", name); - let total_duration = box_style.animation_duration.0.get_mod(i).seconds(); + let total_duration = box_style.animation_duration_mod(i).seconds(); if total_duration == 0. { continue } @@ -441,16 +424,16 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex continue; } - let delay = box_style.animation_delay.0.get_mod(i).seconds(); + let delay = box_style.animation_delay_mod(i).seconds(); let now = time::precise_time_s(); let animation_start = now + delay as f64; - let duration = box_style.animation_duration.0.get_mod(i).seconds(); - let iteration_state = match *box_style.animation_iteration_count.0.get_mod(i) { + let duration = box_style.animation_duration_mod(i).seconds(); + let iteration_state = match box_style.animation_iteration_count_mod(i) { AnimationIterationCount::Infinite => KeyframesIterationState::Infinite, AnimationIterationCount::Number(n) => KeyframesIterationState::Finite(0, n), }; - let animation_direction = *box_style.animation_direction.0.get_mod(i); + let animation_direction = box_style.animation_direction_mod(i); let initial_direction = match animation_direction { AnimationDirection::normal | @@ -459,7 +442,7 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex AnimationDirection::alternate_reverse => AnimationDirection::reverse, }; - let running_state = match *box_style.animation_play_state.0.get_mod(i) { + let running_state = match box_style.animation_play_state_mod(i) { AnimationPlayState::paused => KeyframesRunningState::Paused(0.), AnimationPlayState::running => KeyframesRunningState::Running, }; @@ -550,9 +533,9 @@ where Impl: SelectorImplExt, debug_assert!(!animation.steps.is_empty()); - let maybe_index = style.as_servo() - .get_box().animation_name.0.iter() - .position(|animation_name| name == animation_name); + let maybe_index = style.get_box() + .animation_name_iter() + .position(|animation_name| *name == animation_name); let index = match maybe_index { Some(index) => index, @@ -562,7 +545,7 @@ where Impl: SelectorImplExt, } }; - let total_duration = style.as_servo().get_box().animation_duration.0.get_mod(index).seconds() as f64; + let total_duration = style.get_box().animation_duration_mod(index).seconds() as f64; if total_duration == 0. { debug!("update_style_for_animation: zero duration for animation {:?}", name); return; @@ -642,9 +625,9 @@ where Impl: SelectorImplExt, // NB: The spec says that the timing function can be overwritten // from the keyframe style. - let mut timing_function = *style.as_servo().get_box().animation_timing_function.0.get_mod(index); - if !from_style.as_servo().get_box().animation_timing_function.0.is_empty() { - timing_function = from_style.as_servo().get_box().animation_timing_function.0[0]; + let mut timing_function = style.get_box().animation_timing_function_mod(index); + if from_style.get_box().animation_timing_function_count() != 0 { + timing_function = from_style.get_box().animation_timing_function_at(0); } let target_style = compute_style_for_animation_step(context, diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 04da7ad225b..f7fd3eec1b7 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -47,7 +47,7 @@ class Keyword(object): class Longhand(object): def __init__(self, style_struct, name, animatable=None, derived_from=None, keyword=None, predefined_type=None, custom_cascade=False, experimental=False, internal=False, - need_clone=False, gecko_ffi_name=None): + need_clone=False, need_index=False, gecko_ffi_name=None): self.name = name self.keyword = keyword self.predefined_type = predefined_type @@ -57,7 +57,7 @@ class Longhand(object): self.experimental = ("layout.%s.enabled" % name) if experimental else None self.custom_cascade = custom_cascade self.internal = internal - self.need_clone = need_clone + self.need_index = need_index self.gecko_ffi_name = gecko_ffi_name or "m" + self.camel_case self.derived_from = (derived_from or "").split() @@ -71,6 +71,12 @@ class Longhand(object): assert animatable == "True" or animatable == "False" self.animatable = animatable == "True" + # NB: Animatable implies clone because a property animation requires a + # copy of the computed value. + # + # See components/style/helpers/animated_properties.mako.rs. + self.need_clone = need_clone or self.animatable + class Shorthand(object): def __init__(self, name, sub_properties, experimental=False, internal=False): diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index b704ef9784b..cd85567c856 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -225,6 +225,8 @@ } } + pub use self::${to_camel_case(name)} as SingleComputedValue; + define_css_keyword_enum! { ${to_camel_case(name)}: % for value in data.longhands_by_name[name].keyword.values_for(product): "${value}" => ${to_rust_ident(value)}, diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 552f5b303c3..52b2e181f6a 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -127,22 +127,17 @@ impl AnimatedProperty { } } - // NB: Transition properties need clone pub fn from_transition_property<C: ComputedValues>(transition_property: &TransitionProperty, old_style: &C, new_style: &C) -> AnimatedProperty { - // TODO: Generalise this for GeckoLib, adding clone_xxx to the - // appropiate longhands. - let old_style = old_style.as_servo(); - let new_style = new_style.as_servo(); match *transition_property { TransitionProperty::All => panic!("Can't use TransitionProperty::All here."), % for prop in data.longhands: % if prop.animatable: TransitionProperty::${prop.camel_case} => { AnimatedProperty::${prop.camel_case}( - old_style.get_${prop.style_struct.ident.strip("_")}().${prop.ident}.clone(), - new_style.get_${prop.style_struct.ident.strip("_")}().${prop.ident}.clone()) + old_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}(), + new_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}()) } % endif % endfor diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index f9f2a4be97c..9ec51e960cd 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -7,8 +7,7 @@ <% data.new_style_struct("Box", inherited=False, - gecko_name="Display", - additional_methods=[Method("transition_count", "usize")]) %> + gecko_name="Display") %> // TODO(SimonSapin): don't parse `inline-table`, since we don't support it <%helpers:longhand name="display" @@ -285,7 +284,9 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", </%helpers:longhand> // TODO(pcwalton): Multiple transitions. -<%helpers:longhand name="transition-duration" animatable="False"> +<%helpers:longhand name="transition-duration" + need_index="True" + animatable="False"> use values::computed::ComputedValueAsSpecified; use values::specified::Time; @@ -343,7 +344,9 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", // TODO(pcwalton): Lots more timing functions. // TODO(pcwalton): Multiple transitions. -<%helpers:longhand name="transition-timing-function" animatable="False"> +<%helpers:longhand name="transition-timing-function" + need_index="True" + animatable="False"> use self::computed_value::{StartEnd, TransitionTimingFunction}; use euclid::point::Point2D; @@ -541,7 +544,9 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", } </%helpers:longhand> -<%helpers:longhand name="transition-property" animatable="False"> +<%helpers:longhand name="transition-property" + need_index="True" + animatable="False"> pub use self::computed_value::SingleComputedValue as SingleSpecifiedValue; pub use self::computed_value::T as SpecifiedValue; @@ -592,14 +597,18 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", } </%helpers:longhand> -<%helpers:longhand name="transition-delay" animatable="False"> +<%helpers:longhand name="transition-delay" + need_index="True" + animatable="False"> pub use properties::longhands::transition_duration::{SingleSpecifiedValue, SpecifiedValue}; pub use properties::longhands::transition_duration::{computed_value}; pub use properties::longhands::transition_duration::{get_initial_single_value}; pub use properties::longhands::transition_duration::{get_initial_value, parse, parse_one}; </%helpers:longhand> -<%helpers:longhand name="animation-name" animatable="False"> +<%helpers:longhand name="animation-name" + need_index="True" + animatable="False"> use values::computed::ComputedValueAsSpecified; pub mod computed_value { @@ -607,6 +616,8 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", use std::fmt; use string_cache::Atom; + pub use string_cache::Atom as SingleComputedValue; + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] pub struct T(pub Vec<Atom>); @@ -645,25 +656,33 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", impl ComputedValueAsSpecified for SpecifiedValue {} </%helpers:longhand> -<%helpers:longhand name="animation-duration" animatable="False"> +<%helpers:longhand name="animation-duration" + need_index="True" + animatable="False"> pub use super::transition_duration::computed_value; pub use super::transition_duration::{parse, get_initial_value}; pub use super::transition_duration::SpecifiedValue; </%helpers:longhand> -<%helpers:longhand name="animation-timing-function" animatable="False"> +<%helpers:longhand name="animation-timing-function" + need_index="True" + animatable="False"> pub use super::transition_timing_function::computed_value; pub use super::transition_timing_function::{parse, get_initial_value}; pub use super::transition_timing_function::SpecifiedValue; </%helpers:longhand> -<%helpers:longhand name="animation-iteration-count" animatable="False"> +<%helpers:longhand name="animation-iteration-count" + need_index="True" + animatable="False"> use values::computed::ComputedValueAsSpecified; pub mod computed_value { use cssparser::ToCss; use std::fmt; + pub use self::AnimationIterationCount as SingleComputedValue; + #[derive(Debug, Clone, PartialEq, HeapSizeOf)] pub enum AnimationIterationCount { Number(u32), @@ -728,18 +747,23 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", ${helpers.keyword_list("animation-direction", "normal reverse alternate alternate-reverse", + need_index=True, animatable=False)} ${helpers.keyword_list("animation-play-state", "running paused", need_clone=True, + need_index=True, animatable=False)} ${helpers.keyword_list("animation-fill-mode", "none forwards backwards both", + need_index=True, animatable=False)} -<%helpers:longhand name="animation-delay" animatable="False"> +<%helpers:longhand name="animation-delay" + need_index="True" + animatable="False"> pub use super::transition_duration::computed_value; pub use super::transition_duration::{parse, get_initial_value}; pub use super::transition_duration::SpecifiedValue; diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index c42f973205c..1ba7dd932ea 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -1082,12 +1082,61 @@ pub mod style_struct_traits { #[allow(non_snake_case)] fn clone_${longhand.ident}(&self) -> longhands::${longhand.ident}::computed_value::T; % endif + % if longhand.need_index: + #[allow(non_snake_case)] + fn ${longhand.ident}_count(&self) -> usize; + + #[allow(non_snake_case)] + fn ${longhand.ident}_at(&self, index: usize) + -> longhands::${longhand.ident}::computed_value::SingleComputedValue; + + #[allow(non_snake_case)] + #[inline] + fn ${longhand.ident}_iter<'a>(&'a self) + -> ${longhand.camel_case}Iter<'a, Self> { + ${longhand.camel_case}Iter { + style_struct: self, + current: 0, + max: self.${longhand.ident}_count(), + } + } + + #[allow(non_snake_case)] + #[inline] + fn ${longhand.ident}_mod(&self, index: usize) + -> longhands::${longhand.ident}::computed_value::SingleComputedValue { + self.${longhand.ident}_at(index % self.${longhand.ident}_count()) + } + % endif % endfor % for additional in style_struct.additional_methods: #[allow(non_snake_case)] ${additional.declare()} % endfor } + + % for longhand in style_struct.longhands: + % if longhand.need_index: + pub struct ${longhand.camel_case}Iter<'a, S: ${style_struct.trait_name} + 'static> { + style_struct: &'a S, + current: usize, + max: usize, + } + + impl<'a, S: ${style_struct.trait_name} + 'static> Iterator for ${longhand.camel_case}Iter<'a, S> { + type Item = longhands::${longhand.ident}::computed_value::SingleComputedValue; + + fn next(&mut self) -> Option<Self::Item> { + self.current += 1; + if self.current <= self.max { + Some(self.style_struct.${longhand.ident}_at(self.current - 1)) + } else { + None + } + } + } + % endif + % endfor % endfor } @@ -1126,65 +1175,39 @@ pub mod style_structs { impl super::style_struct_traits::${style_struct.trait_name} for ${style_struct.servo_struct_name} { % for longhand in style_struct.longhands: + #[inline] fn set_${longhand.ident}(&mut self, v: longhands::${longhand.ident}::computed_value::T) { self.${longhand.ident} = v; } + #[inline] fn copy_${longhand.ident}_from(&mut self, other: &Self) { self.${longhand.ident} = other.${longhand.ident}.clone(); } + % if longhand.need_clone: + #[inline] + fn clone_${longhand.ident}(&self) -> longhands::${longhand.ident}::computed_value::T { + self.${longhand.ident}.clone() + } + % endif + + % if longhand.need_index: + fn ${longhand.ident}_count(&self) -> usize { + self.${longhand.ident}.0.len() + } + + fn ${longhand.ident}_at(&self, index: usize) + -> longhands::${longhand.ident}::computed_value::SingleComputedValue { + self.${longhand.ident}.0[index].clone() + } + % endif % endfor % if style_struct.trait_name == "Border": % for side in ["top", "right", "bottom", "left"]: - fn clone_border_${side}_style(&self) -> longhands::border_${side}_style::computed_value::T { - self.border_${side}_style.clone() - } - fn border_${side}_has_nonzero_width(&self) -> bool { - self.border_${side}_width != ::app_units::Au(0) - } + fn border_${side}_has_nonzero_width(&self) -> bool { + self.border_${side}_width != ::app_units::Au(0) + } % endfor - % elif style_struct.trait_name == "Box": - #[inline] - fn clone_display(&self) -> longhands::display::computed_value::T { - self.display.clone() - } - #[inline] - fn clone_position(&self) -> longhands::position::computed_value::T { - self.position.clone() - } - #[inline] - fn clone_float(&self) -> longhands::float::computed_value::T { - self.float.clone() - } - #[inline] - fn clone_overflow_x(&self) -> longhands::overflow_x::computed_value::T { - self.overflow_x.clone() - } - #[inline] - fn clone_overflow_y(&self) -> longhands::overflow_y::computed_value::T { - self.overflow_y.clone() - } - #[inline] - fn clone_animation_play_state(&self) -> longhands::animation_play_state::computed_value::T { - self.animation_play_state.clone() - } - #[inline] - fn transition_count(&self) -> usize { - self.transition_property.0.len() - } - % elif style_struct.trait_name == "Color": - #[inline] - fn clone_color(&self) -> longhands::color::computed_value::T { - self.color.clone() - } % elif style_struct.trait_name == "Font": - #[inline] - fn clone_font_size(&self) -> longhands::font_size::computed_value::T { - self.font_size.clone() - } - #[inline] - fn clone_font_weight(&self) -> longhands::font_weight::computed_value::T { - self.font_weight.clone() - } fn compute_font_hash(&mut self) { // Corresponds to the fields in `gfx::font_template::FontTemplateDescriptor`. let mut hasher: FnvHasher = Default::default(); @@ -1193,43 +1216,11 @@ pub mod style_structs { self.font_family.hash(&mut hasher); self.hash = hasher.finish() } - % elif style_struct.trait_name == "InheritedBox": - #[inline] - fn clone_direction(&self) -> longhands::direction::computed_value::T { - self.direction.clone() - } - #[inline] - fn clone_writing_mode(&self) -> longhands::writing_mode::computed_value::T { - self.writing_mode.clone() - } - #[inline] - fn clone_text_orientation(&self) -> longhands::text_orientation::computed_value::T { - self.text_orientation.clone() - } - % elif style_struct.trait_name == "InheritedText" and product == "servo": - #[inline] - fn clone__servo_text_decorations_in_effect(&self) -> - longhands::_servo_text_decorations_in_effect::computed_value::T { - self._servo_text_decorations_in_effect.clone() - } % elif style_struct.trait_name == "Outline": #[inline] - fn clone_outline_style(&self) -> longhands::outline_style::computed_value::T { - self.outline_style.clone() - } - #[inline] fn outline_has_nonzero_width(&self) -> bool { self.outline_width != ::app_units::Au(0) } - % elif style_struct.trait_name == "Position": - #[inline] - fn clone_align_items(&self) -> longhands::align_items::computed_value::T { - self.align_items.clone() - } - #[inline] - fn clone_align_self(&self) -> longhands::align_self::computed_value::T { - self.align_self.clone() - } % elif style_struct.trait_name == "Text": <% text_decoration_field = 'text_decoration' if product == 'servo' else 'text_decoration_line' %> #[inline] @@ -1255,13 +1246,6 @@ pub trait ComputedValues : Debug + Clone + Send + Sync + 'static { type Concrete${style_struct.trait_name}: style_struct_traits::${style_struct.trait_name}; % endfor - // Temporary bailout case for stuff we haven't made work with the trait - // yet - panics for non-Servo implementations. - // - // Used only for animations. Don't use it in other places. - fn as_servo<'a>(&'a self) -> &'a ServoComputedValues; - fn as_servo_mut<'a>(&'a mut self) -> &'a mut ServoComputedValues; - fn new(custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>, shareable: bool, writing_mode: WritingMode, @@ -1275,7 +1259,7 @@ pub trait ComputedValues : Debug + Clone + Send + Sync + 'static { fn initial_values() -> &'static Self; - fn do_cascade_property<F: FnOnce(&Vec<CascadePropertyFn<Self>>)>(f: F); + fn do_cascade_property<F: FnOnce(&[CascadePropertyFn<Self>])>(f: F); % for style_struct in data.active_style_structs(): fn clone_${style_struct.trait_name_lower}(&self) -> @@ -1310,9 +1294,6 @@ impl ComputedValues for ServoComputedValues { type Concrete${style_struct.trait_name} = style_structs::${style_struct.servo_struct_name}; % endfor - fn as_servo<'a>(&'a self) -> &'a ServoComputedValues { self } - fn as_servo_mut<'a>(&'a mut self) -> &'a mut ServoComputedValues { self } - fn new(custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>, shareable: bool, writing_mode: WritingMode, @@ -1346,8 +1327,9 @@ impl ComputedValues for ServoComputedValues { fn initial_values() -> &'static Self { &*INITIAL_SERVO_VALUES } - fn do_cascade_property<F: FnOnce(&Vec<CascadePropertyFn<Self>>)>(f: F) { - CASCADE_PROPERTY.with(|x| f(x)); + #[inline] + fn do_cascade_property<F: FnOnce(&[CascadePropertyFn<Self>])>(f: F) { + f(&CASCADE_PROPERTY) } % for style_struct in data.active_style_structs(): @@ -1747,19 +1729,11 @@ pub type CascadePropertyFn<C /*: ComputedValues */> = cacheable: &mut bool, error_reporter: &mut StdBox<ParseErrorReporter + Send>); -pub fn make_cascade_vec<C: ComputedValues>() -> Vec<CascadePropertyFn<C>> { - vec![ - % for property in data.longhands: - longhands::${property.ident}::cascade_property, - % endfor - ] -} - -// This is a thread-local rather than a lazy static to avoid atomic operations when cascading -// properties. -thread_local!(static CASCADE_PROPERTY: Vec<CascadePropertyFn<ServoComputedValues>> = { - make_cascade_vec::<ServoComputedValues>() -}); +static CASCADE_PROPERTY: [CascadePropertyFn<ServoComputedValues>; ${len(data.longhands)}] = [ + % for property in data.longhands: + longhands::${property.ident}::cascade_property, + % endfor +]; /// Performs the CSS cascade, computing new styles for an element from its parent style and /// optionally a cached related style. The arguments are: diff --git a/components/style/values.rs b/components/style/values.rs index 5dea6f3cb7a..007426be88f 100644 --- a/components/style/values.rs +++ b/components/style/values.rs @@ -1194,6 +1194,11 @@ pub mod specified { pub fn radians(self) -> f32 { self.0 } + + #[inline] + pub fn from_radians(r: f32) -> Self { + Angle(r) + } } const RAD_PER_DEG: CSSFloat = PI / 180.0; diff --git a/ports/geckolib/properties.mako.rs b/ports/geckolib/properties.mako.rs index 6493a399ea9..9c458602c7d 100644 --- a/ports/geckolib/properties.mako.rs +++ b/ports/geckolib/properties.mako.rs @@ -33,9 +33,8 @@ use style::custom_properties::ComputedValuesMap; use style::logical_geometry::WritingMode; use style::properties::{CascadePropertyFn, ServoComputedValues, ComputedValues}; use style::properties::longhands; -use style::properties::make_cascade_vec; use style::properties::style_struct_traits::*; -use values::{StyleCoordHelpers, ToGeckoStyleCoord, convert_nscolor_to_rgba}; +use values::{StyleCoordHelpers, GeckoStyleCoordConvertible, convert_nscolor_to_rgba}; use values::{convert_rgba_to_nscolor, debug_assert_unit_is_safe_to_copy}; use values::round_border_to_device_pixels; @@ -74,10 +73,6 @@ impl ComputedValues for GeckoComputedValues { type Concrete${style_struct.trait_name} = ${style_struct.gecko_struct_name}; % endfor - // These will go away, and we will never implement them. - fn as_servo<'a>(&'a self) -> &'a ServoComputedValues { unimplemented!() } - fn as_servo_mut<'a>(&'a mut self) -> &'a mut ServoComputedValues { unimplemented!() } - fn new(custom_properties: Option<Arc<ComputedValuesMap>>, shareable: bool, writing_mode: WritingMode, @@ -106,8 +101,9 @@ impl ComputedValues for GeckoComputedValues { fn initial_values() -> &'static Self { &*INITIAL_GECKO_VALUES } - fn do_cascade_property<F: FnOnce(&Vec<CascadePropertyFn<Self>>)>(f: F) { - CASCADE_PROPERTY.with(|x| f(x)); + #[inline] + fn do_cascade_property<F: FnOnce(&[CascadePropertyFn<Self>])>(f: F) { + f(&CASCADE_PROPERTY) } % for style_struct in data.style_structs: @@ -147,7 +143,13 @@ pub struct ${style_struct.gecko_struct_name} { } </%def> -<%def name="impl_simple_copy(ident, gecko_ffi_name)"> +<%def name="impl_simple_clone(ident, gecko_ffi_name)"> + fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { + self.gecko.${gecko_ffi_name} + } +</%def> + +<%def name="impl_simple_copy(ident, gecko_ffi_name, *kwargs)"> fn copy_${ident}_from(&mut self, other: &Self) { self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}; } @@ -247,12 +249,24 @@ def set_gecko_property(ffi_name, expr): <%def name="impl_color_copy(ident, gecko_ffi_name, color_flags_ffi_name=None)"> fn copy_${ident}_from(&mut self, other: &Self) { % if color_flags_ffi_name: - ${clear_color_flags(color_flags_ffi_name)} - if ${get_current_color_flag_from("other.gecko." + color_flags_ffi_name)} { - ${set_current_color_flag(color_flags_ffi_name)} - } + ${clear_color_flags(color_flags_ffi_name)} + if ${get_current_color_flag_from("other.gecko." + color_flags_ffi_name)} { + ${set_current_color_flag(color_flags_ffi_name)} + } % endif - self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}; + self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name} + } +</%def> + +<%def name="impl_color_clone(ident, gecko_ffi_name, color_flags_ffi_name=None)"> + fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { + use cssparser::Color; + % if color_flags_ffi_name: + if ${get_current_color_flag_from("self.gecko." + color_flags_ffi_name)} { + return Color::CurrentColor + } + % endif + Color::RGBA(convert_nscolor_to_rgba(${get_gecko_property(gecko_ffi_name)})) } </%def> @@ -264,14 +278,20 @@ def set_gecko_property(ffi_name, expr): % endif </%def> -<%def name="impl_simple(ident, gecko_ffi_name)"> +<%def name="impl_simple(ident, gecko_ffi_name, need_clone=False)"> <%call expr="impl_simple_setter(ident, gecko_ffi_name)"></%call> <%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call> +% if need_clone: + <%call expr="impl_simple_clone(ident, gecko_ffi_name)"></%call> +% endif </%def> -<%def name="impl_color(ident, gecko_ffi_name, color_flags_ffi_name=None)"> +<%def name="impl_color(ident, gecko_ffi_name, color_flags_ffi_name=None, need_clone=False)"> <%call expr="impl_color_setter(ident, gecko_ffi_name, color_flags_ffi_name)"></%call> <%call expr="impl_color_copy(ident, gecko_ffi_name, color_flags_ffi_name)"></%call> +% if need_clone: + <%call expr="impl_color_clone(ident, gecko_ffi_name, color_flags_ffi_name)"></%call> +% endif </%def> <%def name="impl_app_units(ident, gecko_ffi_name, need_clone, round_to_pixels=False)"> @@ -291,7 +311,7 @@ def set_gecko_property(ffi_name, expr): % endif </%def> -<%def name="impl_split_style_coord(ident, unit_ffi_name, union_ffi_name)"> +<%def name="impl_split_style_coord(ident, unit_ffi_name, union_ffi_name, need_clone=False)"> fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { v.to_gecko_style_coord(&mut self.gecko.${unit_ffi_name}, &mut self.gecko.${union_ffi_name}); @@ -301,13 +321,25 @@ def set_gecko_property(ffi_name, expr): self.gecko.${unit_ffi_name} = other.gecko.${unit_ffi_name}; self.gecko.${union_ffi_name} = other.gecko.${union_ffi_name}; } + % if need_clone: + fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { + use style::properties::longhands::${ident}::computed_value::T; + T::from_gecko_style_coord(&self.gecko.${unit_ffi_name}, + &self.gecko.${union_ffi_name}) + .expect("clone for ${ident} failed") + } + % endif </%def> -<%def name="impl_style_coord(ident, gecko_ffi_name)"> -<%call expr="impl_split_style_coord(ident, '%s.mUnit' % gecko_ffi_name, '%s.mValue' % gecko_ffi_name)"></%call> +<%def name="impl_style_coord(ident, gecko_ffi_name, need_clone=False)"> +${impl_split_style_coord(ident, + "%s.mUnit" % gecko_ffi_name, + "%s.mValue" % gecko_ffi_name, + need_clone=need_clone)} </%def> -<%def name="impl_corner_style_coord(ident, x_unit_ffi_name, x_union_ffi_name, y_unit_ffi_name, y_union_ffi_name)"> +<%def name="impl_corner_style_coord(ident, x_unit_ffi_name, x_union_ffi_name, \ + y_unit_ffi_name, y_union_ffi_name, need_clone=False)"> fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { v.0.width.to_gecko_style_coord(&mut self.gecko.${x_unit_ffi_name}, &mut self.gecko.${x_union_ffi_name}); @@ -322,6 +354,19 @@ def set_gecko_property(ffi_name, expr): self.gecko.${y_unit_ffi_name} = other.gecko.${y_unit_ffi_name}; self.gecko.${y_union_ffi_name} = other.gecko.${y_union_ffi_name}; } + % if need_clone: + fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { + use style::properties::longhands::${ident}::computed_value::T; + use euclid::Size2D; + let width = GeckoStyleCoordConvertible::from_gecko_style_coord(&self.gecko.${x_unit_ffi_name}, + &self.gecko.${x_union_ffi_name}) + .expect("Failed to clone ${ident}"); + let height = GeckoStyleCoordConvertible::from_gecko_style_coord(&self.gecko.${y_unit_ffi_name}, + &self.gecko.${y_union_ffi_name}) + .expect("Failed to clone ${ident}"); + T(Size2D::new(width, height)) + } + % endif </%def> <%def name="impl_style_struct(style_struct)"> @@ -424,7 +469,7 @@ impl ${style_struct.trait_name} for ${style_struct.gecko_struct_name} { impl_keyword(longhand.ident, longhand.gecko_ffi_name, longhand.keyword, longhand.need_clone) for longhand in predefined_longhands: impl_fn = predefined_types[longhand.predefined_type] - impl_fn(longhand.ident, longhand.gecko_ffi_name) + impl_fn(longhand.ident, longhand.gecko_ffi_name, need_clone=longhand.need_clone) %> /* @@ -446,6 +491,12 @@ impl ${style_struct.trait_name} for ${style_struct.gecko_struct_name} { unimplemented!() } % endif + % if longhand.need_index: + fn ${longhand.ident}_count(&self) -> usize { 0 } + fn ${longhand.ident}_at(&self, _index: usize) -> longhands::${longhand.ident}::computed_value::SingleComputedValue { + unimplemented!() + } + % endif % endfor <% additionals = [x for x in style_struct.additional_methods if skip_additionals != "*" and not x.name in skip_additionals.split()] %> @@ -515,9 +566,9 @@ fn static_assert() { need_clone=True) %> <% impl_color("border_%s_color" % side.ident, "mBorderColor[%s]" % side.index, - color_flags_ffi_name="mBorderStyle[%s]" % side.index) %> + color_flags_ffi_name="mBorderStyle[%s]" % side.index, need_clone=True) %> - <% impl_app_units("border_%s_width" % side.ident, "mComputedBorder.%s" % side.ident, need_clone=False, + <% impl_app_units("border_%s_width" % side.ident, "mComputedBorder.%s" % side.ident, need_clone=True, round_to_pixels=True) %> fn border_${side.ident}_has_nonzero_width(&self) -> bool { @@ -530,7 +581,8 @@ fn static_assert() { "mBorderRadius.mUnits[%s]" % corner.x_index, "mBorderRadius.mValues[%s]" % corner.x_index, "mBorderRadius.mUnits[%s]" % corner.y_index, - "mBorderRadius.mValues[%s]" % corner.y_index) %> + "mBorderRadius.mValues[%s]" % corner.y_index, + need_clone=True) %> % endfor </%self:impl_trait> @@ -541,7 +593,8 @@ fn static_assert() { % for side in SIDES: <% impl_split_style_coord("margin_%s" % side.ident, "mMargin.mUnits[%s]" % side.index, - "mMargin.mValues[%s]" % side.index) %> + "mMargin.mValues[%s]" % side.index, + need_clone=True) %> % endfor </%self:impl_trait> @@ -552,7 +605,8 @@ fn static_assert() { % for side in SIDES: <% impl_split_style_coord("padding_%s" % side.ident, "mPadding.mUnits[%s]" % side.index, - "mPadding.mValues[%s]" % side.index) %> + "mPadding.mValues[%s]" % side.index, + need_clone=True) %> % endfor </%self:impl_trait> @@ -563,7 +617,8 @@ fn static_assert() { % for side in SIDES: <% impl_split_style_coord("%s" % side.ident, "mOffset.mUnits[%s]" % side.index, - "mOffset.mValues[%s]" % side.index) %> + "mOffset.mValues[%s]" % side.index, + need_clone=True) %> % endfor fn set_z_index(&mut self, v: longhands::z_index::computed_value::T) { @@ -580,6 +635,17 @@ fn static_assert() { self.gecko.mZIndex.mValue = other.gecko.mZIndex.mValue; } + fn clone_z_index(&self) -> longhands::z_index::computed_value::T { + use style::properties::longhands::z_index::computed_value::T; + + if self.gecko.mZIndex.is_auto() { + return T::Auto; + } + + debug_assert!(self.gecko.mZIndex.is_int()); + T::Number(self.gecko.mZIndex.get_int()) + } + fn set_box_sizing(&mut self, v: longhands::box_sizing::computed_value::T) { use style::computed_values::box_sizing::T; use gecko_bindings::structs::StyleBoxSizing; @@ -602,9 +668,9 @@ fn static_assert() { <% impl_keyword("outline_style", "mOutlineStyle", border_style_keyword, need_clone=True) %> - <% impl_color("outline_color", "mOutlineColor", color_flags_ffi_name="mOutlineStyle") %> + <% impl_color("outline_color", "mOutlineColor", color_flags_ffi_name="mOutlineStyle", need_clone=True) %> - <% impl_app_units("outline_width", "mActualOutlineWidth", need_clone=False, + <% impl_app_units("outline_width", "mActualOutlineWidth", need_clone=True, round_to_pixels=True) %> % for corner in CORNERS: @@ -675,7 +741,7 @@ fn static_assert() { fn set_font_weight(&mut self, v: longhands::font_weight::computed_value::T) { self.gecko.mFont.weight = v as u16; } - <%call expr="impl_simple_copy('font_weight', 'mFont.weight')"></%call> + ${impl_simple_copy('font_weight', 'mFont.weight')} fn clone_font_weight(&self) -> longhands::font_weight::computed_value::T { debug_assert!(self.gecko.mFont.weight >= 100); @@ -697,7 +763,7 @@ fn static_assert() { "table-header-group table-footer-group table-row table-column-group " + "table-column table-cell table-caption list-item flex none " + "-moz-box -moz-inline-box") %> - <%call expr="impl_keyword('display', 'mDisplay', display_keyword, True)"></%call> + ${impl_keyword('display', 'mDisplay', display_keyword, True)} // overflow-y is implemented as a newtype of overflow-x, so we need special handling. // We could generalize this if we run into other newtype keywords. @@ -711,7 +777,7 @@ fn static_assert() { % endfor }; } - <%call expr="impl_simple_copy('overflow_y', 'mOverflowY')"></%call> + ${impl_simple_copy('overflow_y', 'mOverflowY')} fn clone_overflow_y(&self) -> longhands::overflow_y::computed_value::T { use style::properties::longhands::overflow_x::computed_value::T as BaseType; use style::properties::longhands::overflow_y::computed_value::T as NewType; @@ -737,6 +803,26 @@ fn static_assert() { } } + fn clone_vertical_align(&self) -> longhands::vertical_align::computed_value::T { + use style::properties::longhands::vertical_align::computed_value::T; + use style::values::computed::LengthOrPercentage; + + if self.gecko.mVerticalAlign.is_enum() { + match self.gecko.mVerticalAlign.get_enum() as u32 { + % for value in keyword.values_for('gecko'): + structs::${keyword.gecko_constant(value)} + => T::${to_rust_ident(value)}, + % endfor + _ => panic!("Unexpected enum variant for vertical-align"), + } + } else { + let v = LengthOrPercentage::from_gecko_style_coord(&self.gecko.mVerticalAlign.mUnit, + &self.gecko.mVerticalAlign.mValue) + .expect("Expected length or percentage for vertical-align"); + T::LengthOrPercentage(v) + } + } + <%call expr="impl_coord_copy('vertical_align', 'mVerticalAlign')"></%call> fn set__moz_binding(&mut self, v: longhands::_moz_binding::computed_value::T) { @@ -770,7 +856,7 @@ fn static_assert() { skip_longhands="${skip_background_longhands}" skip_additionals="*"> - <% impl_color("background_color", "mBackgroundColor") %> + <% impl_color("background_color", "mBackgroundColor", need_clone=True) %> fn copy_background_repeat_from(&mut self, other: &Self) { self.gecko.mImage.mRepeatCount = cmp::min(1, other.gecko.mImage.mRepeatCount); @@ -945,8 +1031,8 @@ fn static_assert() { <%self:impl_trait style_struct_name="List" skip_longhands="list-style-type" skip_additionals="*"> - <% impl_keyword_setter("list_style_type", "__LIST_STYLE_TYPE__", - data.longhands_by_name["list-style-type"].keyword) %> + ${impl_keyword_setter("list_style_type", "__LIST_STYLE_TYPE__", + data.longhands_by_name["list-style-type"].keyword)} fn copy_list_style_type_from(&mut self, other: &Self) { unsafe { Gecko_CopyListStyleTypeFrom(&mut self.gecko, &other.gecko); @@ -960,7 +1046,7 @@ fn static_assert() { <% text_align_keyword = Keyword("text-align", "start end left right center justify -moz-center -moz-left " + "-moz-right match-parent") %> - <%call expr="impl_keyword('text_align', 'mTextAlign', text_align_keyword, need_clone=False)"></%call> + ${impl_keyword('text_align', 'mTextAlign', text_align_keyword, need_clone=False)} fn set_line_height(&mut self, v: longhands::line_height::computed_value::T) { use style::properties::longhands::line_height::computed_value::T; @@ -974,6 +1060,22 @@ fn static_assert() { } } + fn clone_line_height(&self) -> longhands::line_height::computed_value::T { + use style::properties::longhands::line_height::computed_value::T; + if self.gecko.mLineHeight.is_normal() { + return T::Normal; + } + if self.gecko.mLineHeight.is_coord() { + return T::Length(self.gecko.mLineHeight.get_coord()); + } + if self.gecko.mLineHeight.is_factor() { + return T::Number(self.gecko.mLineHeight.get_factor()); + } + + debug_assert!(self.gecko.mLineHeight.get_enum() == structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT as i32); + T::MozBlockHeight + } + <%call expr="impl_coord_copy('line_height', 'mLineHeight')"></%call> </%self:impl_trait> @@ -982,8 +1084,8 @@ fn static_assert() { skip_longhands="text-decoration-color text-decoration-line" skip_additionals="*"> - <% impl_color("text_decoration_color", "mTextDecorationColor", - color_flags_ffi_name="mTextDecorationStyle") %> + ${impl_color("text_decoration_color", "mTextDecorationColor", + color_flags_ffi_name="mTextDecorationStyle", need_clone=True)} fn set_text_decoration_line(&mut self, v: longhands::text_decoration_line::computed_value::T) { let mut bits: u8 = 0; @@ -999,14 +1101,19 @@ fn static_assert() { self.gecko.mTextDecorationLine = bits; } - <%call expr="impl_simple_copy('text_decoration_line', 'mTextDecorationLine')"></%call> + ${impl_simple_copy('text_decoration_line', 'mTextDecorationLine')} + #[inline] fn has_underline(&self) -> bool { (self.gecko.mTextDecorationLine & (structs::NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE as u8)) != 0 } + + #[inline] fn has_overline(&self) -> bool { (self.gecko.mTextDecorationLine & (structs::NS_STYLE_TEXT_DECORATION_LINE_OVERLINE as u8)) != 0 } + + #[inline] fn has_line_through(&self) -> bool { (self.gecko.mTextDecorationLine & (structs::NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH as u8)) != 0 } @@ -1026,7 +1133,6 @@ fn static_assert() { <%self:impl_trait style_struct_name="Color" skip_longhands="*"> - fn set_color(&mut self, v: longhands::color::computed_value::T) { let result = convert_rgba_to_nscolor(&v); ${set_gecko_property("mColor", "result")} @@ -1042,7 +1148,6 @@ fn static_assert() { <%self:impl_trait style_struct_name="Pointing" skip_longhands="cursor"> - fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) { use style::properties::longhands::cursor::computed_value::T; use style_traits::cursor::Cursor; @@ -1090,7 +1195,6 @@ fn static_assert() { } ${impl_simple_copy('cursor', 'mCursor')} - </%self:impl_trait> <%self:impl_trait style_struct_name="Column" @@ -1104,7 +1208,6 @@ fn static_assert() { } ${impl_coord_copy('column_width', 'mColumnWidth')} - </%self:impl_trait> <%def name="define_ffi_struct_accessor(style_struct)"> @@ -1139,8 +1242,8 @@ lazy_static! { }; } -// This is a thread-local rather than a lazy static to avoid atomic operations when cascading -// properties. -thread_local!(static CASCADE_PROPERTY: Vec<CascadePropertyFn<GeckoComputedValues>> = { - make_cascade_vec::<GeckoComputedValues>() -}); +static CASCADE_PROPERTY: [CascadePropertyFn<GeckoComputedValues>; ${len(data.longhands)}] = [ + % for property in data.longhands: + longhands::${property.ident}::cascade_property, + % endfor +]; diff --git a/ports/geckolib/values.rs b/ports/geckolib/values.rs index 978453aa707..ee24be7565c 100644 --- a/ports/geckolib/values.rs +++ b/ports/geckolib/values.rs @@ -11,17 +11,37 @@ use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, Leng pub trait StyleCoordHelpers { fn copy_from(&mut self, other: &Self); - fn set<T: ToGeckoStyleCoord>(&mut self, val: T); + fn set<T: GeckoStyleCoordConvertible>(&mut self, val: T); + fn set_auto(&mut self); + fn is_auto(&self) -> bool; + fn set_normal(&mut self); + fn is_normal(&self) -> bool; + fn set_coord(&mut self, val: Au); + fn is_coord(&self) -> bool; + fn get_coord(&self) -> Au; + fn set_int(&mut self, val: i32); + fn is_int(&self) -> bool; + fn get_int(&self) -> i32; + fn set_enum(&mut self, val: i32); + fn is_enum(&self) -> bool; + fn get_enum(&self) -> i32; + fn set_percent(&mut self, val: f32); + fn is_percent(&self) -> bool; + fn get_percent(&self) -> f32; + fn set_factor(&mut self, val: f32); + fn is_factor(&self) -> bool; + fn get_factor(&self) -> f32; } impl StyleCoordHelpers for nsStyleCoord { + #[inline] fn copy_from(&mut self, other: &Self) { debug_assert_unit_is_safe_to_copy(self.mUnit); debug_assert_unit_is_safe_to_copy(other.mUnit); @@ -29,51 +49,113 @@ impl StyleCoordHelpers for nsStyleCoord { self.mValue = other.mValue; } - fn set<T: ToGeckoStyleCoord>(&mut self, val: T) { + #[inline] + fn set<T: GeckoStyleCoordConvertible>(&mut self, val: T) { val.to_gecko_style_coord(&mut self.mUnit, &mut self.mValue); } + #[inline] fn set_auto(&mut self) { self.mUnit = nsStyleUnit::eStyleUnit_Auto; unsafe { *self.mValue.mInt.as_mut() = 0; } } + #[inline] + fn is_auto(&self) -> bool { + self.mUnit == nsStyleUnit::eStyleUnit_Auto + } + #[inline] fn set_normal(&mut self) { self.mUnit = nsStyleUnit::eStyleUnit_Normal; unsafe { *self.mValue.mInt.as_mut() = 0; } } + #[inline] + fn is_normal(&self) -> bool { + self.mUnit == nsStyleUnit::eStyleUnit_Normal + } + #[inline] fn set_coord(&mut self, val: Au) { self.mUnit = nsStyleUnit::eStyleUnit_Coord; unsafe { *self.mValue.mInt.as_mut() = val.0; } } - - fn set_percent(&mut self, val: f32) { - self.mUnit = nsStyleUnit::eStyleUnit_Percent; - unsafe { *self.mValue.mFloat.as_mut() = val; } + #[inline] + fn is_coord(&self) -> bool { + self.mUnit == nsStyleUnit::eStyleUnit_Coord + } + #[inline] + fn get_coord(&self) -> Au { + debug_assert!(self.is_coord()); + Au(unsafe { *self.mValue.mInt.as_ref() }) } + #[inline] fn set_int(&mut self, val: i32) { self.mUnit = nsStyleUnit::eStyleUnit_Integer; unsafe { *self.mValue.mInt.as_mut() = val; } } + #[inline] + fn is_int(&self) -> bool { + self.mUnit == nsStyleUnit::eStyleUnit_Integer + } + #[inline] + fn get_int(&self) -> i32 { + debug_assert!(self.is_int()); + unsafe { *self.mValue.mInt.as_ref() } + } + #[inline] fn set_enum(&mut self, val: i32) { self.mUnit = nsStyleUnit::eStyleUnit_Enumerated; unsafe { *self.mValue.mInt.as_mut() = val; } } + #[inline] + fn is_enum(&self) -> bool { + self.mUnit == nsStyleUnit::eStyleUnit_Enumerated + } + #[inline] + fn get_enum(&self) -> i32 { + debug_assert!(self.is_enum()); + unsafe { *self.mValue.mInt.as_ref() } + } + + #[inline] + fn set_percent(&mut self, val: f32) { + self.mUnit = nsStyleUnit::eStyleUnit_Percent; + unsafe { *self.mValue.mFloat.as_mut() = val; } + } + #[inline] + fn is_percent(&self) -> bool { + self.mUnit == nsStyleUnit::eStyleUnit_Percent + } + #[inline] + fn get_percent(&self) -> f32 { + debug_assert!(self.is_percent()); + unsafe { *self.mValue.mFloat.as_ref() } + } + #[inline] fn set_factor(&mut self, val: f32) { self.mUnit = nsStyleUnit::eStyleUnit_Factor; unsafe { *self.mValue.mFloat.as_mut() = val; } } + #[inline] + fn is_factor(&self) -> bool { + self.mUnit == nsStyleUnit::eStyleUnit_Factor + } + #[inline] + fn get_factor(&self) -> f32 { + debug_assert!(self.is_factor()); + unsafe { *self.mValue.mFloat.as_ref() } + } } -pub trait ToGeckoStyleCoord { +pub trait GeckoStyleCoordConvertible : Sized { fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion); + fn from_gecko_style_coord(unit: &nsStyleUnit, union: &nsStyleUnion) -> Option<Self>; } -impl ToGeckoStyleCoord for LengthOrPercentage { +impl GeckoStyleCoordConvertible for LengthOrPercentage { fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion) { match *self { LengthOrPercentage::Length(au) => { @@ -87,9 +169,21 @@ impl ToGeckoStyleCoord for LengthOrPercentage { LengthOrPercentage::Calc(_) => unimplemented!(), }; } + + fn from_gecko_style_coord(unit: &nsStyleUnit, union: &nsStyleUnion) -> Option<Self> { + match *unit { + nsStyleUnit::eStyleUnit_Coord + => Some(LengthOrPercentage::Length(Au(unsafe { *union.mInt.as_ref() }))), + nsStyleUnit::eStyleUnit_Percent + => Some(LengthOrPercentage::Percentage(unsafe { *union.mFloat.as_ref() })), + nsStyleUnit::eStyleUnit_Calc + => unimplemented!(), + _ => None, + } + } } -impl ToGeckoStyleCoord for LengthOrPercentageOrAuto { +impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto { fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion) { match *self { LengthOrPercentageOrAuto::Length(au) => { @@ -107,9 +201,23 @@ impl ToGeckoStyleCoord for LengthOrPercentageOrAuto { LengthOrPercentageOrAuto::Calc(_) => unimplemented!(), }; } + + fn from_gecko_style_coord(unit: &nsStyleUnit, union: &nsStyleUnion) -> Option<Self> { + match *unit { + nsStyleUnit::eStyleUnit_Auto + => Some(LengthOrPercentageOrAuto::Auto), + nsStyleUnit::eStyleUnit_Coord + => Some(LengthOrPercentageOrAuto::Length(Au(unsafe { *union.mInt.as_ref() }))), + nsStyleUnit::eStyleUnit_Percent + => Some(LengthOrPercentageOrAuto::Percentage(unsafe { *union.mFloat.as_ref() })), + nsStyleUnit::eStyleUnit_Calc + => unimplemented!(), + _ => None, + } + } } -impl ToGeckoStyleCoord for LengthOrPercentageOrNone { +impl GeckoStyleCoordConvertible for LengthOrPercentageOrNone { fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion) { match *self { LengthOrPercentageOrNone::Length(au) => { @@ -127,9 +235,23 @@ impl ToGeckoStyleCoord for LengthOrPercentageOrNone { LengthOrPercentageOrNone::Calc(_) => unimplemented!(), }; } + + fn from_gecko_style_coord(unit: &nsStyleUnit, union: &nsStyleUnion) -> Option<Self> { + match *unit { + nsStyleUnit::eStyleUnit_None + => Some(LengthOrPercentageOrNone::None), + nsStyleUnit::eStyleUnit_Coord + => Some(LengthOrPercentageOrNone::Length(Au(unsafe { *union.mInt.as_ref() }))), + nsStyleUnit::eStyleUnit_Percent + => Some(LengthOrPercentageOrNone::Percentage(unsafe { *union.mFloat.as_ref() })), + nsStyleUnit::eStyleUnit_Calc + => unimplemented!(), + _ => None, + } + } } -impl<T: ToGeckoStyleCoord> ToGeckoStyleCoord for Option<T> { +impl<T: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for Option<T> { fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion) { if let Some(ref me) = *self { me.to_gecko_style_coord(unit, union); @@ -138,15 +260,27 @@ impl<T: ToGeckoStyleCoord> ToGeckoStyleCoord for Option<T> { unsafe { *union.mInt.as_mut() = 0; } } } + + fn from_gecko_style_coord(unit: &nsStyleUnit, union: &nsStyleUnion) -> Option<Self> { + Some(T::from_gecko_style_coord(unit, union)) + } } -impl ToGeckoStyleCoord for Angle { +impl GeckoStyleCoordConvertible for Angle { fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion) { *unit = nsStyleUnit::eStyleUnit_Radian; unsafe { *union.mFloat.as_mut() = self.radians() }; } + + fn from_gecko_style_coord(unit: &nsStyleUnit, union: &nsStyleUnion) -> Option<Self> { + if *unit == nsStyleUnit::eStyleUnit_Radian { + Some(Angle::from_radians(unsafe { *union.mFloat.as_ref() })) + } else { + None + } + } } pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 { |