Auto merge of #20751 - emilio:gecko-sync, r=emilio

style: Sync changes from mozilla-central.

See each commit for details.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20751)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-05-05 12:54:15 -04:00 committed by GitHub
commit 719e4e37e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 245 additions and 326 deletions

View file

@ -39,14 +39,14 @@ where
let mut new_running_animations = vec![]; let mut new_running_animations = vec![];
while let Ok(animation) = new_animations_receiver.try_recv() { while let Ok(animation) = new_animations_receiver.try_recv() {
let mut should_push = true; let mut should_push = true;
if let Animation::Keyframes(ref node, ref name, ref state) = animation { if let Animation::Keyframes(ref node, _, ref name, ref state) = animation {
// If the animation was already present in the list for the // If the animation was already present in the list for the
// node, just update its state, else push the new animation to // node, just update its state, else push the new animation to
// run. // run.
if let Some(ref mut animations) = running_animations.get_mut(node) { if let Some(ref mut animations) = running_animations.get_mut(node) {
// TODO: This being linear is probably not optimal. // TODO: This being linear is probably not optimal.
for anim in animations.iter_mut() { for anim in animations.iter_mut() {
if let Animation::Keyframes(_, ref anim_name, ref mut anim_state) = *anim { if let Animation::Keyframes(_, _, ref anim_name, ref mut anim_state) = *anim {
if *name == *anim_name { if *name == *anim_name {
debug!("update_animation_state: Found other animation {}", name); debug!("update_animation_state: Found other animation {}", name);
anim_state.update_from_other(&state, timer); anim_state.update_from_other(&state, timer);
@ -83,7 +83,7 @@ where
Animation::Transition(_, started_at, ref frame, _expired) => { Animation::Transition(_, started_at, ref frame, _expired) => {
now < started_at + frame.duration now < started_at + frame.duration
} }
Animation::Keyframes(_, _, ref mut state) => { Animation::Keyframes(_, _, _, ref mut state) => {
// This animation is still running, or we need to keep // This animation is still running, or we need to keep
// iterating. // iterating.
now < state.started_at + state.duration || state.tick() now < state.started_at + state.duration || state.tick()

View file

@ -272,27 +272,27 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> {
} }
self.traversal.list_item.truncate_to_level(self.level); self.traversal.list_item.truncate_to_level(self.level);
for &(ref counter_name, value) in &*fragment.style().get_counters().counter_reset { for pair in &*fragment.style().get_counters().counter_reset {
let counter_name = &*counter_name.0; let counter_name = &*pair.name.0;
if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) { if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) {
counter.reset(self.level, value); counter.reset(self.level, pair.value);
continue continue
} }
let mut counter = Counter::new(); let mut counter = Counter::new();
counter.reset(self.level, value); counter.reset(self.level, pair.value);
self.traversal.counters.insert(counter_name.to_owned(), counter); self.traversal.counters.insert(counter_name.to_owned(), counter);
} }
for &(ref counter_name, value) in &*fragment.style().get_counters().counter_increment { for pair in &*fragment.style().get_counters().counter_increment {
let counter_name = &*counter_name.0; let counter_name = &*pair.name.0;
if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) { if let Some(ref mut counter) = self.traversal.counters.get_mut(counter_name) {
counter.increment(self.level, value); counter.increment(self.level, pair.value);
continue continue
} }
let mut counter = Counter::new(); let mut counter = Counter::new();
counter.increment(self.level, value); counter.increment(self.level, pair.value);
self.traversal.counters.insert(counter_name.to_owned(), counter); self.traversal.counters.insert(counter_name.to_owned(), counter);
} }

View file

@ -335,7 +335,7 @@ fn create_and_insert_some_stuff() {
let false_positives = (1001_usize..2000).filter(|i| bf.might_contain(i)).count(); let false_positives = (1001_usize..2000).filter(|i| bf.might_contain(i)).count();
assert!(false_positives < 150, "{} is not < 150", false_positives); // 15%. assert!(false_positives < 160, "{} is not < 160", false_positives); // 16%.
for i in 0_usize..100 { for i in 0_usize..100 {
bf.remove(&i); bf.remove(&i);

View file

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! CSS transitions and animations. //! CSS transitions and animations.
#![deny(missing_docs)]
use Atom; use Atom;
use bezier::Bezier; use bezier::Bezier;
@ -16,8 +15,9 @@ use properties::longhands::animation_direction::computed_value::single_value::T
use properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState; use properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
use rule_tree::CascadeLevel; use rule_tree::CascadeLevel;
use servo_arc::Arc; use servo_arc::Arc;
use std::fmt;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use stylesheets::keyframes_rule::{KeyframesStep, KeyframesStepValue}; use stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
use timer::Timer; use timer::Timer;
use values::computed::Time; use values::computed::Time;
use values::computed::transform::TimingFunction; use values::computed::transform::TimingFunction;
@ -52,7 +52,7 @@ pub enum KeyframesRunningState {
/// duration, the current and maximum iteration count, and the state (either /// duration, the current and maximum iteration count, and the state (either
/// playing or paused). /// playing or paused).
// TODO: unify the use of f32/f64 in this file. // TODO: unify the use of f32/f64 in this file.
#[derive(Clone, Debug)] #[derive(Clone)]
pub struct KeyframesAnimationState { pub struct KeyframesAnimationState {
/// The time this animation started at. /// The time this animation started at.
pub started_at: f64, pub started_at: f64,
@ -183,6 +183,22 @@ impl KeyframesAnimationState {
} }
} }
impl fmt::Debug for KeyframesAnimationState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("KeyframesAnimationState")
.field("started_at", &self.started_at)
.field("duration", &self.duration)
.field("delay", &self.delay)
.field("iteration_state", &self.iteration_state)
.field("running_state", &self.running_state)
.field("direction", &self.direction)
.field("current_direction", &self.current_direction)
.field("expired", &self.expired)
.field("cascade_style", &())
.finish()
}
}
/// State relating to an animation. /// State relating to an animation.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Animation { pub enum Animation {
@ -194,7 +210,9 @@ pub enum Animation {
Transition(OpaqueNode, f64, AnimationFrame, bool), Transition(OpaqueNode, f64, AnimationFrame, bool),
/// A keyframes animation is identified by a name, and can have a /// A keyframes animation is identified by a name, and can have a
/// node-dependent state (i.e. iteration count, etc.). /// node-dependent state (i.e. iteration count, etc.).
Keyframes(OpaqueNode, Atom, KeyframesAnimationState), ///
/// TODO(emilio): The animation object could be refcounted.
Keyframes(OpaqueNode, KeyframesAnimation, Atom, KeyframesAnimationState),
} }
impl Animation { impl Animation {
@ -204,7 +222,7 @@ impl Animation {
debug_assert!(!self.is_expired()); debug_assert!(!self.is_expired());
match *self { match *self {
Animation::Transition(_, _, _, ref mut expired) => *expired = true, Animation::Transition(_, _, _, ref mut expired) => *expired = true,
Animation::Keyframes(_, _, ref mut state) => state.expired = true, Animation::Keyframes(_, _, _, ref mut state) => state.expired = true,
} }
} }
@ -213,7 +231,7 @@ impl Animation {
pub fn is_expired(&self) -> bool { pub fn is_expired(&self) -> bool {
match *self { match *self {
Animation::Transition(_, _, _, expired) => expired, Animation::Transition(_, _, _, expired) => expired,
Animation::Keyframes(_, _, ref state) => state.expired, Animation::Keyframes(_, _, _, ref state) => state.expired,
} }
} }
@ -222,7 +240,7 @@ impl Animation {
pub fn node(&self) -> &OpaqueNode { pub fn node(&self) -> &OpaqueNode {
match *self { match *self {
Animation::Transition(ref node, _, _, _) => node, Animation::Transition(ref node, _, _, _) => node,
Animation::Keyframes(ref node, _, _) => node, Animation::Keyframes(ref node, _, _, _) => node,
} }
} }
@ -231,7 +249,7 @@ impl Animation {
pub fn is_paused(&self) -> bool { pub fn is_paused(&self) -> bool {
match *self { match *self {
Animation::Transition(..) => false, Animation::Transition(..) => false,
Animation::Keyframes(_, _, ref state) => state.is_paused(), Animation::Keyframes(_, _, _, ref state) => state.is_paused(),
} }
} }
@ -390,7 +408,6 @@ impl PropertyAnimation {
/// Inserts transitions into the queue of running animations as applicable for /// Inserts transitions into the queue of running animations as applicable for
/// the given style difference. This is called from the layout worker threads. /// the given style difference. This is called from the layout worker threads.
/// Returns true if any animations were kicked off and false otherwise. /// Returns true if any animations were kicked off and false otherwise.
#[cfg(feature = "servo")]
pub fn start_transitions_if_applicable( pub fn start_transitions_if_applicable(
new_animations_sender: &Sender<Animation>, new_animations_sender: &Sender<Animation>,
opaque_node: OpaqueNode, opaque_node: OpaqueNode,
@ -500,12 +517,16 @@ where
/// Triggers animations for a given node looking at the animation property /// Triggers animations for a given node looking at the animation property
/// values. /// values.
pub fn maybe_start_animations( pub fn maybe_start_animations<E>(
element: E,
context: &SharedStyleContext, context: &SharedStyleContext,
new_animations_sender: &Sender<Animation>, new_animations_sender: &Sender<Animation>,
node: OpaqueNode, node: OpaqueNode,
new_style: &Arc<ComputedValues>, new_style: &Arc<ComputedValues>,
) -> bool { ) -> bool
where
E: TElement,
{
let mut had_animations = false; let mut had_animations = false;
let box_style = new_style.get_box(); let box_style = new_style.get_box();
@ -522,7 +543,7 @@ pub fn maybe_start_animations(
continue; continue;
} }
if let Some(ref anim) = context.stylist.get_animation(name) { if let Some(anim) = context.stylist.get_animation(name, element) {
debug!("maybe_start_animations: animation {} found", name); debug!("maybe_start_animations: animation {} found", name);
// If this animation doesn't have any keyframe, we can just continue // If this animation doesn't have any keyframe, we can just continue
@ -561,6 +582,7 @@ pub fn maybe_start_animations(
new_animations_sender new_animations_sender
.send(Animation::Keyframes( .send(Animation::Keyframes(
node, node,
anim.clone(),
name.clone(), name.clone(),
KeyframesAnimationState { KeyframesAnimationState {
started_at: animation_start, started_at: animation_start,
@ -605,6 +627,7 @@ pub fn update_style_for_animation_frame(
true true
} }
/// Updates a single animation and associated style based on the current time. /// Updates a single animation and associated style based on the current time.
pub fn update_style_for_animation<E>( pub fn update_style_for_animation<E>(
context: &SharedStyleContext, context: &SharedStyleContext,
@ -628,7 +651,7 @@ pub fn update_style_for_animation<E>(
*style = new_style *style = new_style
} }
}, },
Animation::Keyframes(_, ref name, ref state) => { Animation::Keyframes(_, ref animation, ref name, ref state) => {
debug!( debug!(
"update_style_for_animation: animation found: \"{}\", {:?}", "update_style_for_animation: animation found: \"{}\", {:?}",
name, state name, state
@ -641,14 +664,6 @@ pub fn update_style_for_animation<E>(
KeyframesRunningState::Paused(progress) => started_at + duration * progress, KeyframesRunningState::Paused(progress) => started_at + duration * progress,
}; };
let animation = match context.stylist.get_animation(name) {
None => {
warn!("update_style_for_animation: Animation {:?} not found", name);
return;
},
Some(animation) => animation,
};
debug_assert!(!animation.steps.is_empty()); debug_assert!(!animation.steps.is_empty());
let maybe_index = style let maybe_index = style

View file

@ -8,8 +8,8 @@ use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use context::QuirksMode; use context::QuirksMode;
use dom::TElement; use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet}; use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{self, RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet}; use gecko_bindings::structs::{self, RawGeckoPresContextOwned, ServoStyleSetSizes, StyleSheet as DomStyleSheet};
use gecko_bindings::structs::{ServoStyleSheetInner, StyleSheetInfo, nsIDocument}; use gecko_bindings::structs::{StyleSheetInfo, nsIDocument};
use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI}; use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::media_queries::{MediaListKey, ToMediaListKey}; use invalidation::media_queries::{MediaListKey, ToMediaListKey};
use malloc_size_of::MallocSizeOfOps; use malloc_size_of::MallocSizeOfOps;
@ -23,7 +23,7 @@ use stylist::Stylist;
/// Little wrapper to a Gecko style sheet. /// Little wrapper to a Gecko style sheet.
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct GeckoStyleSheet(*const ServoStyleSheet); pub struct GeckoStyleSheet(*const DomStyleSheet);
impl ToMediaListKey for ::gecko::data::GeckoStyleSheet { impl ToMediaListKey for ::gecko::data::GeckoStyleSheet {
fn to_media_list_key(&self) -> MediaListKey { fn to_media_list_key(&self) -> MediaListKey {
@ -33,30 +33,30 @@ impl ToMediaListKey for ::gecko::data::GeckoStyleSheet {
} }
impl GeckoStyleSheet { impl GeckoStyleSheet {
/// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer. /// Create a `GeckoStyleSheet` from a raw `DomStyleSheet` pointer.
#[inline] #[inline]
pub unsafe fn new(s: *const ServoStyleSheet) -> Self { pub unsafe fn new(s: *const DomStyleSheet) -> Self {
debug_assert!(!s.is_null()); debug_assert!(!s.is_null());
bindings::Gecko_StyleSheet_AddRef(s); bindings::Gecko_StyleSheet_AddRef(s);
Self::from_addrefed(s) Self::from_addrefed(s)
} }
/// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer that /// Create a `GeckoStyleSheet` from a raw `DomStyleSheet` pointer that
/// already holds a strong reference. /// already holds a strong reference.
#[inline] #[inline]
pub unsafe fn from_addrefed(s: *const ServoStyleSheet) -> Self { pub unsafe fn from_addrefed(s: *const DomStyleSheet) -> Self {
debug_assert!(!s.is_null()); debug_assert!(!s.is_null());
GeckoStyleSheet(s) GeckoStyleSheet(s)
} }
/// Get the raw `ServoStyleSheet` that we're wrapping. /// Get the raw `StyleSheet` that we're wrapping.
pub fn raw(&self) -> &ServoStyleSheet { pub fn raw(&self) -> &DomStyleSheet {
unsafe { &*self.0 } unsafe { &*self.0 }
} }
fn inner(&self) -> &ServoStyleSheetInner { fn inner(&self) -> &StyleSheetInfo {
unsafe { unsafe {
&*(self.raw()._base.mInner as *const StyleSheetInfo as *const ServoStyleSheetInner) &*(self.raw().mInner as *const StyleSheetInfo)
} }
} }
@ -98,7 +98,7 @@ impl StylesheetInDocument for GeckoStyleSheet {
use std::mem; use std::mem;
unsafe { unsafe {
let dom_media_list = self.raw()._base.mMedia.mRawPtr as *const DomMediaList; let dom_media_list = self.raw().mMedia.mRawPtr as *const DomMediaList;
if dom_media_list.is_null() { if dom_media_list.is_null() {
return None; return None;
} }

View file

@ -13,7 +13,7 @@ use euclid::TypedScale;
use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor}; use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
use gecko_bindings::bindings; use gecko_bindings::bindings;
use gecko_bindings::structs; use gecko_bindings::structs;
use gecko_bindings::structs::{nsCSSKeyword, nsCSSProps_KTableEntry, nsCSSUnit, nsCSSValue}; use gecko_bindings::structs::{nsCSSKTableEntry, nsCSSKeyword, nsCSSUnit, nsCSSValue};
use gecko_bindings::structs::{nsMediaFeature, nsMediaFeature_RangeType}; use gecko_bindings::structs::{nsMediaFeature, nsMediaFeature_RangeType};
use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext}; use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext};
use gecko_bindings::structs::RawGeckoPresContextOwned; use gecko_bindings::structs::RawGeckoPresContextOwned;
@ -479,7 +479,7 @@ where
} }
unsafe fn find_in_table<F>( unsafe fn find_in_table<F>(
mut current_entry: *const nsCSSProps_KTableEntry, mut current_entry: *const nsCSSKTableEntry,
mut f: F, mut f: F,
) -> Option<(nsCSSKeyword, i16)> ) -> Option<(nsCSSKeyword, i16)>
where where
@ -544,7 +544,7 @@ fn parse_feature_value<'i, 't>(
bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32) bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32)
}; };
let first_table_entry: *const nsCSSProps_KTableEntry = let first_table_entry: *const nsCSSKTableEntry =
unsafe { *feature.mData.mKeywordTable.as_ref() }; unsafe { *feature.mData.mKeywordTable.as_ref() };
let value = match unsafe { find_in_table(first_table_entry, |kw, _| kw == keyword) } { let value = match unsafe { find_in_table(first_table_entry, |kw, _| kw == keyword) } {

View file

@ -103,7 +103,6 @@ extern crate void;
#[macro_use] #[macro_use]
mod macros; mod macros;
#[cfg(feature = "servo")]
pub mod animation; pub mod animation;
pub mod applicable_declarations; pub mod applicable_declarations;
#[allow(missing_docs)] // TODO. #[allow(missing_docs)] // TODO.

View file

@ -425,6 +425,7 @@ trait PrivateMatchMethods: TElement {
let this_opaque = self.as_node().opaque(); let this_opaque = self.as_node().opaque();
// Trigger any present animations if necessary. // Trigger any present animations if necessary.
animation::maybe_start_animations( animation::maybe_start_animations(
*self,
&shared_context, &shared_context,
new_animations_sender, new_animations_sender,
this_opaque, this_opaque,

View file

@ -5697,9 +5697,9 @@ clip-path
) { ) {
unsafe { unsafe {
bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut self.gecko, v.len() as u32); bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut self.gecko, v.len() as u32);
for (i, &(ref name, value)) in v.iter().enumerate() { for (i, ref pair) in v.iter().enumerate() {
self.gecko.m${counter_property}s[i].mCounter.assign(name.0.as_slice()); self.gecko.m${counter_property}s[i].mCounter.assign(pair.name.0.as_slice());
self.gecko.m${counter_property}s[i].mValue = value; self.gecko.m${counter_property}s[i].mValue = pair.value;
} }
} }
} }
@ -5717,12 +5717,16 @@ clip-path
pub fn clone_counter_${counter_property.lower()}( pub fn clone_counter_${counter_property.lower()}(
&self &self
) -> longhands::counter_${counter_property.lower()}::computed_value::T { ) -> longhands::counter_${counter_property.lower()}::computed_value::T {
use values::generics::counters::CounterPair;
use values::CustomIdent; use values::CustomIdent;
use gecko_string_cache::Atom; use gecko_string_cache::Atom;
longhands::counter_${counter_property.lower()}::computed_value::T::new( longhands::counter_${counter_property.lower()}::computed_value::T::new(
self.gecko.m${counter_property}s.iter().map(|ref gecko_counter| { self.gecko.m${counter_property}s.iter().map(|ref gecko_counter| {
(CustomIdent(Atom::from(gecko_counter.mCounter.to_string())), gecko_counter.mValue) CounterPair {
name: CustomIdent(Atom::from(gecko_counter.mCounter.to_string())),
value: gecko_counter.mValue,
}
}).collect() }).collect()
) )
} }

View file

@ -196,7 +196,6 @@ pub fn nscsspropertyid_is_transitionable(property: nsCSSPropertyID) -> bool {
/// An animated property interpolation between two computed values for that /// An animated property interpolation between two computed values for that
/// property. /// property.
#[cfg(feature = "servo")]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub enum AnimatedProperty { pub enum AnimatedProperty {
@ -213,7 +212,6 @@ pub enum AnimatedProperty {
% endfor % endfor
} }
#[cfg(feature = "servo")]
impl AnimatedProperty { impl AnimatedProperty {
/// Get the name of this property. /// Get the name of this property.
pub fn name(&self) -> &'static str { pub fn name(&self) -> &'static str {
@ -255,9 +253,12 @@ impl AnimatedProperty {
/// Update `style` with the proper computed style corresponding to this /// Update `style` with the proper computed style corresponding to this
/// animation at `progress`. /// animation at `progress`.
#[cfg_attr(feature = "gecko", allow(unused))]
pub fn update(&self, style: &mut ComputedValues, progress: f64) { pub fn update(&self, style: &mut ComputedValues, progress: f64) {
match *self { #[cfg(feature = "servo")]
% for prop in data.longhands: {
match *self {
% for prop in data.longhands:
% if prop.animatable: % if prop.animatable:
AnimatedProperty::${prop.camel_case}(ref from, ref to) => { AnimatedProperty::${prop.camel_case}(ref from, ref to) => {
// https://drafts.csswg.org/web-animations/#discrete-animation-type // https://drafts.csswg.org/web-animations/#discrete-animation-type
@ -276,7 +277,8 @@ impl AnimatedProperty {
style.mutate_${prop.style_struct.name_lower}().set_${prop.ident}(value); style.mutate_${prop.style_struct.name_lower}().set_${prop.ident}(value);
} }
% endif % endif
% endfor % endfor
}
} }
} }
@ -1291,16 +1293,8 @@ impl Animate for ComputedTransformOperation {
&TransformOperation::Perspective(ref fd), &TransformOperation::Perspective(ref fd),
&TransformOperation::Perspective(ref td), &TransformOperation::Perspective(ref td),
) => { ) => {
let mut fd_matrix = Matrix3D::identity(); Ok(TransformOperation::Perspective(
let mut td_matrix = Matrix3D::identity(); fd.animate(td, procedure)?
if fd.px() > 0. {
fd_matrix.m34 = -1. / fd.px();
}
if td.px() > 0. {
td_matrix.m34 = -1. / td.px();
}
Ok(TransformOperation::Matrix3D(
fd_matrix.animate(&td_matrix, procedure)?,
)) ))
}, },
_ if self.is_translate() && other.is_translate() => { _ if self.is_translate() && other.is_translate() => {
@ -2640,16 +2634,7 @@ impl ComputeSquaredDistance for ComputedTransformOperation {
&TransformOperation::Perspective(ref fd), &TransformOperation::Perspective(ref fd),
&TransformOperation::Perspective(ref td), &TransformOperation::Perspective(ref td),
) => { ) => {
let mut fd_matrix = Matrix3D::identity(); fd.compute_squared_distance(td)
let mut td_matrix = Matrix3D::identity();
if fd.px() > 0. {
fd_matrix.m34 = -1. / fd.px();
}
if td.px() > 0. {
td_matrix.m34 = -1. / td.px();
}
fd_matrix.compute_squared_distance(&td_matrix)
} }
( (
&TransformOperation::Perspective(ref p), &TransformOperation::Perspective(ref p),
@ -2658,6 +2643,8 @@ impl ComputeSquaredDistance for ComputedTransformOperation {
&TransformOperation::Matrix3D(ref m), &TransformOperation::Matrix3D(ref m),
&TransformOperation::Perspective(ref p), &TransformOperation::Perspective(ref p),
) => { ) => {
// FIXME(emilio): Is this right? Why interpolating this with
// Perspective but not with anything else?
let mut p_matrix = Matrix3D::identity(); let mut p_matrix = Matrix3D::identity();
if p.px() > 0. { if p.px() > 0. {
p_matrix.m34 = -1. / p.px(); p_matrix.m34 = -1. / p.px();

View file

@ -56,12 +56,6 @@ use style_adjuster::StyleAdjuster;
pub use self::declaration_block::*; pub use self::declaration_block::*;
#[cfg(feature = "gecko")]
#[macro_export]
macro_rules! property_name {
($s: tt) => { atom!($s) }
}
<%! <%!
from data import Method, Keyword, to_rust_ident, to_camel_case, SYSTEM_FONT_LONGHANDS from data import Method, Keyword, to_rust_ident, to_camel_case, SYSTEM_FONT_LONGHANDS
import os.path import os.path

View file

@ -237,7 +237,7 @@ pub trait ToCssWithGuard {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub struct DeepCloneParams { pub struct DeepCloneParams {
/// The new sheet we're cloning rules into. /// The new sheet we're cloning rules into.
pub reference_sheet: *const ::gecko_bindings::structs::ServoStyleSheet, pub reference_sheet: *const ::gecko_bindings::structs::StyleSheet,
} }
/// Parameters needed for deep clones. /// Parameters needed for deep clones.

View file

@ -259,7 +259,7 @@ impl DeepCloneWithLock for Keyframe {
/// declarations to apply. /// declarations to apply.
/// ///
/// TODO: Find a better name for this? /// TODO: Find a better name for this?
#[derive(Debug, MallocSizeOf)] #[derive(Clone, Debug, MallocSizeOf)]
pub enum KeyframesStepValue { pub enum KeyframesStepValue {
/// A step formed by a declaration block specified by the CSS. /// A step formed by a declaration block specified by the CSS.
Declarations { Declarations {
@ -275,7 +275,7 @@ pub enum KeyframesStepValue {
} }
/// A single step from a keyframe animation. /// A single step from a keyframe animation.
#[derive(Debug, MallocSizeOf)] #[derive(Clone, Debug, MallocSizeOf)]
pub struct KeyframesStep { pub struct KeyframesStep {
/// The percentage of the animation duration when this step starts. /// The percentage of the animation duration when this step starts.
pub start_percentage: KeyframePercentage, pub start_percentage: KeyframePercentage,
@ -352,7 +352,7 @@ impl KeyframesStep {
/// of keyframes, in order. /// of keyframes, in order.
/// ///
/// It only takes into account animable properties. /// It only takes into account animable properties.
#[derive(Debug, MallocSizeOf)] #[derive(Clone, Debug, MallocSizeOf)]
pub struct KeyframesAnimation { pub struct KeyframesAnimation {
/// The difference steps of the animation. /// The difference steps of the animation.
pub steps: Vec<KeyframesStep>, pub steps: Vec<KeyframesStep>,

View file

@ -1421,14 +1421,53 @@ impl Stylist {
} }
/// Returns the registered `@keyframes` animation for the specified name. /// Returns the registered `@keyframes` animation for the specified name.
///
/// FIXME(emilio): This needs to account for the element rules.
#[inline] #[inline]
pub fn get_animation(&self, name: &Atom) -> Option<&KeyframesAnimation> { pub fn get_animation<'a, E>(
self.cascade_data &'a self,
.iter_origins() name: &Atom,
.filter_map(|(d, _)| d.animations.get(name)) element: E,
.next() ) -> Option<&'a KeyframesAnimation>
where
E: TElement + 'a,
{
macro_rules! try_find_in {
($data:expr) => {
if let Some(animation) = $data.animations.get(name) {
return Some(animation);
}
}
}
// NOTE(emilio): We implement basically what Blink does for this case,
// which is [1] as of this writing.
//
// See [2] for the spec discussion about what to do about this. WebKit's
// behavior makes a bit more sense off-hand, but it's way more complex
// to implement, and it makes value computation having to thread around
// the cascade level, which is not great. Also, it breaks if you inherit
// animation-name from an element in a different tree.
//
// See [3] for the bug to implement whatever gets resolved, and related
// bugs for a bit more context.
//
// [1]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/
// core/css/resolver/style_resolver.cc?l=1267&rcl=90f9f8680ebb4a87d177f3b0833372ae4e0c88d8
// [2]: https://github.com/w3c/csswg-drafts/issues/1995
// [3]: https://bugzil.la/1458189
if let Some(shadow) = element.shadow_root() {
try_find_in!(shadow.style_data());
}
if let Some(shadow) = element.containing_shadow() {
try_find_in!(shadow.style_data());
} else {
try_find_in!(self.cascade_data.author);
}
try_find_in!(self.cascade_data.user);
try_find_in!(self.cascade_data.user_agent.cascade_data);
None
} }
/// Computes the match results of a given element against the set of /// Computes the match results of a given element against the set of
@ -1517,27 +1556,25 @@ impl Stylist {
E: TElement, E: TElement,
{ {
use font_metrics::get_metrics_provider_for_product; use font_metrics::get_metrics_provider_for_product;
use std::iter;
// FIXME(emilio): Why do we even need the rule node? We should probably let block = declarations.read_with(guards.author);
// just avoid allocating it and calling `apply_declarations` directly, let iter_declarations = || {
// maybe... block.declaration_importance_iter().map(|(declaration, importance)| {
let rule_node = self.rule_tree.insert_ordered_rules(iter::once(( debug_assert!(!importance.important());
StyleSource::from_declarations(declarations), (declaration, CascadeLevel::StyleAttributeNormal)
CascadeLevel::StyleAttributeNormal, })
))); };
// This currently ignores visited styles. It appears to be used for
// font styles in <canvas> via Servo_StyleSet_ResolveForDeclarations.
// It is unclear if visited styles are meaningful for this case.
let metrics = get_metrics_provider_for_product(); let metrics = get_metrics_provider_for_product();
// FIXME(emilio): the pseudo bit looks quite dubious! // We don't bother inserting these declarations in the rule tree, since
properties::cascade::<E>( // it'd be quite useless and slow.
properties::apply_declarations::<E, _, _>(
&self.device, &self.device,
/* pseudo = */ None, /* pseudo = */ None,
&rule_node, self.rule_tree.root(),
guards, guards,
iter_declarations,
Some(parent_style), Some(parent_style),
Some(parent_style), Some(parent_style),
Some(parent_style), Some(parent_style),

View file

@ -251,11 +251,11 @@ impl ToAnimatedZero for TransformOperation {
generic::TransformOperation::Rotate(_) => { generic::TransformOperation::Rotate(_) => {
Ok(generic::TransformOperation::Rotate(Angle::zero())) Ok(generic::TransformOperation::Rotate(Angle::zero()))
}, },
generic::TransformOperation::Perspective(..) | generic::TransformOperation::Perspective(ref l) => {
Ok(generic::TransformOperation::Perspective(l.to_animated_zero()?))
},
generic::TransformOperation::AccumulateMatrix { .. } | generic::TransformOperation::AccumulateMatrix { .. } |
generic::TransformOperation::InterpolateMatrix { .. } => { generic::TransformOperation::InterpolateMatrix { .. } => {
// Perspective: We convert a perspective function into an equivalent
// ComputedMatrix, and then decompose/interpolate/recompose these matrices.
// AccumulateMatrix/InterpolateMatrix: We do interpolation on // AccumulateMatrix/InterpolateMatrix: We do interpolation on
// AccumulateMatrix/InterpolateMatrix by reading it as a ComputedMatrix // AccumulateMatrix/InterpolateMatrix by reading it as a ComputedMatrix
// (with layout information), and then do matrix interpolation. // (with layout information), and then do matrix interpolation.

View file

@ -23,12 +23,13 @@ pub enum BorderImageSideWidth<LengthOrPercentage, Number> {
/// A generic value for the `border-image-slice` property. /// A generic value for the `border-image-slice` property.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)] ToComputedValue, ToCss)]
pub struct BorderImageSlice<NumberOrPercentage> { pub struct BorderImageSlice<NumberOrPercentage> {
/// The offsets. /// The offsets.
#[css(field_bound)]
pub offsets: Rect<NumberOrPercentage>, pub offsets: Rect<NumberOrPercentage>,
/// Whether to fill the middle part. /// Whether to fill the middle part.
#[value_info(represents_keyword)] #[css(represents_keyword)]
pub fill: bool, pub fill: bool,
} }
@ -86,22 +87,6 @@ where
} }
} }
impl<N> ToCss for BorderImageSlice<N>
where
N: PartialEq + ToCss,
{
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.offsets.to_css(dest)?;
if self.fill {
dest.write_str(" fill")?;
}
Ok(())
}
}
impl<L> BorderRadius<L> { impl<L> BorderRadius<L> {
/// Returns a new `BorderRadius<L>`. /// Returns a new `BorderRadius<L>`.
#[inline] #[inline]

View file

@ -4,12 +4,19 @@
//! Generic types for counters-related CSS values. //! Generic types for counters-related CSS values.
use std::fmt;
use std::fmt::Write;
use std::ops::Deref; use std::ops::Deref;
use style_traits::{CssWriter, ToCss};
use values::CustomIdent; use values::CustomIdent;
/// A name / value pair for counters.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct CounterPair<Integer> {
/// The name of the counter.
pub name: CustomIdent,
/// The value of the counter / increment / etc.
pub value: Integer,
}
/// A generic value for the `counter-increment` property. /// A generic value for the `counter-increment` property.
#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, #[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)] ToComputedValue, ToCss)]
@ -18,13 +25,13 @@ pub struct CounterIncrement<I>(Counters<I>);
impl<I> CounterIncrement<I> { impl<I> CounterIncrement<I> {
/// Returns a new value for `counter-increment`. /// Returns a new value for `counter-increment`.
#[inline] #[inline]
pub fn new(counters: Vec<(CustomIdent, I)>) -> Self { pub fn new(counters: Vec<CounterPair<I>>) -> Self {
CounterIncrement(Counters(counters.into_boxed_slice())) CounterIncrement(Counters(counters.into_boxed_slice()))
} }
} }
impl<I> Deref for CounterIncrement<I> { impl<I> Deref for CounterIncrement<I> {
type Target = [(CustomIdent, I)]; type Target = [CounterPair<I>];
#[inline] #[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -40,13 +47,13 @@ pub struct CounterReset<I>(Counters<I>);
impl<I> CounterReset<I> { impl<I> CounterReset<I> {
/// Returns a new value for `counter-reset`. /// Returns a new value for `counter-reset`.
#[inline] #[inline]
pub fn new(counters: Vec<(CustomIdent, I)>) -> Self { pub fn new(counters: Vec<CounterPair<I>>) -> Self {
CounterReset(Counters(counters.into_boxed_slice())) CounterReset(Counters(counters.into_boxed_slice()))
} }
} }
impl<I> Deref for CounterReset<I> { impl<I> Deref for CounterReset<I> {
type Target = [(CustomIdent, I)]; type Target = [CounterPair<I>];
#[inline] #[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -58,8 +65,8 @@ impl<I> Deref for CounterReset<I> {
/// ///
/// Keyword `none` is represented by an empty vector. /// Keyword `none` is represented by an empty vector.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)] ToComputedValue, ToCss)]
pub struct Counters<I>(#[css(if_empty = "none")] Box<[(CustomIdent, I)]>); pub struct Counters<I>(#[css(iterable, if_empty = "none")] Box<[CounterPair<I>]>);
impl<I> Default for Counters<I> { impl<I> Default for Counters<I> {
#[inline] #[inline]
@ -67,30 +74,3 @@ impl<I> Default for Counters<I> {
Counters(vec![].into_boxed_slice()) Counters(vec![].into_boxed_slice())
} }
} }
impl<I> ToCss for Counters<I>
where
I: ToCss,
{
#[inline]
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: fmt::Write,
{
if self.0.is_empty() {
return dest.write_str("none");
}
let mut first = true;
for &(ref name, ref value) in &*self.0 {
if !first {
dest.write_str(" ")?;
}
first = false;
name.to_css(dest)?;
dest.write_str(" ")?;
value.to_css(dest)?;
}
Ok(())
}
}

View file

@ -4,14 +4,12 @@
//! Generic types for CSS values related to effects. //! Generic types for CSS values related to effects.
use std::fmt::{self, Write};
use style_traits::values::{CssWriter, SequenceWriter, ToCss};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
/// A generic value for a single `box-shadow`. /// A generic value for a single `box-shadow`.
#[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, #[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToAnimatedValue, ToAnimatedZero)] ToAnimatedValue, ToAnimatedZero, ToCss)]
pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> { pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
/// The base shadow. /// The base shadow.
pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>, pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>,
@ -19,7 +17,7 @@ pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
pub spread: ShapeLength, pub spread: ShapeLength,
/// Whether this is an inset box shadow. /// Whether this is an inset box shadow.
#[animation(constant)] #[animation(constant)]
#[value_info(represents_keyword)] #[css(represents_keyword)]
pub inset: bool, pub inset: bool,
} }
@ -80,27 +78,3 @@ pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
/// Blur radius. /// Blur radius.
pub blur: ShapeLength, pub blur: ShapeLength,
} }
impl<Color, SizeLength, BlurShapeLength, ShapeLength> ToCss
for BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength>
where
Color: ToCss,
SizeLength: ToCss,
BlurShapeLength: ToCss,
ShapeLength: ToCss,
{
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
{
let mut writer = SequenceWriter::new(&mut *dest, " ");
writer.item(&self.base)?;
writer.item(&self.spread)?;
}
if self.inset {
dest.write_str(" inset")?;
}
Ok(())
}
}

View file

@ -13,6 +13,7 @@ use values::CustomIdent;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use values::generics::CounterStyleOrNone; use values::generics::CounterStyleOrNone;
use values::generics::counters::CounterIncrement as GenericCounterIncrement; use values::generics::counters::CounterIncrement as GenericCounterIncrement;
use values::generics::counters::CounterPair;
use values::generics::counters::CounterReset as GenericCounterReset; use values::generics::counters::CounterReset as GenericCounterReset;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use values::specified::Attr; use values::specified::Attr;
@ -48,7 +49,7 @@ fn parse_counters<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
default_value: i32, default_value: i32,
) -> Result<Vec<(CustomIdent, Integer)>, ParseError<'i>> { ) -> Result<Vec<CounterPair<Integer>>, ParseError<'i>> {
if input if input
.try(|input| input.expect_ident_matching("none")) .try(|input| input.expect_ident_matching("none"))
.is_ok() .is_ok()
@ -59,16 +60,16 @@ fn parse_counters<'i, 't>(
let mut counters = Vec::new(); let mut counters = Vec::new();
loop { loop {
let location = input.current_source_location(); let location = input.current_source_location();
let counter_name = match input.next() { let name = match input.next() {
Ok(&Token::Ident(ref ident)) => CustomIdent::from_ident(location, ident, &["none"])?, Ok(&Token::Ident(ref ident)) => CustomIdent::from_ident(location, ident, &["none"])?,
Ok(t) => return Err(location.new_unexpected_token_error(t.clone())), Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
Err(_) => break, Err(_) => break,
}; };
let counter_delta = input let value = input
.try(|input| Integer::parse(context, input)) .try(|input| Integer::parse(context, input))
.unwrap_or(Integer::new(default_value)); .unwrap_or(Integer::new(default_value));
counters.push((counter_name, counter_delta)) counters.push(CounterPair { name, value });
} }
if !counters.is_empty() { if !counters.is_empty() {

View file

@ -1947,11 +1947,11 @@ pub struct FontSynthesis {
/// If a `font-weight` is requested that the font family does not contain, /// If a `font-weight` is requested that the font family does not contain,
/// the user agent may synthesize the requested weight from the weights /// the user agent may synthesize the requested weight from the weights
/// that do exist in the font family. /// that do exist in the font family.
#[value_info(represents_keyword)] #[css(represents_keyword)]
pub weight: bool, pub weight: bool,
/// If a font-style is requested that the font family does not contain, /// If a font-style is requested that the font family does not contain,
/// the user agent may synthesize the requested style from the normal face in the font family. /// the user agent may synthesize the requested style from the normal face in the font family.
#[value_info(represents_keyword)] #[css(represents_keyword)]
pub style: bool, pub style: bool,
} }

View file

@ -424,14 +424,14 @@ pub enum AutoFlow {
} }
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)] ToComputedValue, ToCss)]
/// Controls how the auto-placement algorithm works /// Controls how the auto-placement algorithm works
/// specifying exactly how auto-placed items get flowed into the grid /// specifying exactly how auto-placed items get flowed into the grid
pub struct GridAutoFlow { pub struct GridAutoFlow {
/// Specifiy how auto-placement algorithm fills each `row` or `column` in turn /// Specifiy how auto-placement algorithm fills each `row` or `column` in turn
pub autoflow: AutoFlow, pub autoflow: AutoFlow,
/// Specify use `dense` packing algorithm or not /// Specify use `dense` packing algorithm or not
#[value_info(represents_keyword)] #[css(represents_keyword)]
pub dense: bool, pub dense: bool,
} }
@ -446,20 +446,6 @@ impl GridAutoFlow {
} }
} }
impl ToCss for GridAutoFlow {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.autoflow.to_css(dest)?;
if self.dense {
dest.write_str(" dense")?;
}
Ok(())
}
}
impl Parse for GridAutoFlow { impl Parse for GridAutoFlow {
/// [ row | column ] || dense /// [ row | column ] || dense
fn parse<'i, 't>( fn parse<'i, 't>(

View file

@ -140,13 +140,13 @@ fn derive_struct_fields<'a>(
values.push(value.to_string()); values.push(value.to_string());
} }
} }
if info_attrs.represents_keyword { let css_attrs = cg::parse_field_attrs::<CssFieldAttrs>(field);
if css_attrs.represents_keyword {
let ident = field.ident.as_ref() let ident = field.ident.as_ref()
.expect("only named field should use represents_keyword"); .expect("only named field should use represents_keyword");
values.push(cg::to_css_identifier(ident.as_ref())); values.push(cg::to_css_identifier(ident.as_ref()));
return None; return None;
} }
let css_attrs = cg::parse_field_attrs::<CssFieldAttrs>(field);
if let Some(if_empty) = css_attrs.if_empty { if let Some(if_empty) = css_attrs.if_empty {
values.push(if_empty); values.push(if_empty);
} }
@ -176,6 +176,5 @@ struct ValueInfoVariantAttrs {
#[darling(attributes(value_info), default)] #[darling(attributes(value_info), default)]
#[derive(Default, FromField)] #[derive(Default, FromField)]
struct ValueInfoFieldAttrs { struct ValueInfoFieldAttrs {
represents_keyword: bool,
other_values: Option<String>, other_values: Option<String>,
} }

View file

@ -175,7 +175,7 @@ fn derive_single_field_expr(
{ {
let mut iter = #field.iter().peekable(); let mut iter = #field.iter().peekable();
if iter.peek().is_none() { if iter.peek().is_none() {
writer.item(&::style_traits::values::Verbatim(#if_empty))?; writer.raw_item(#if_empty)?;
} else { } else {
for item in iter { for item in iter {
writer.item(&item)?; writer.item(&item)?;
@ -189,6 +189,15 @@ fn derive_single_field_expr(
writer.item(&item)?; writer.item(&item)?;
} }
} }
} else if attrs.represents_keyword {
let ident =
field.ast().ident.as_ref().expect("Unnamed field with represents_keyword?");
let ident = cg::to_css_identifier(ident.as_ref());
quote! {
if *#field {
writer.raw_item(#ident)?;
}
}
} else { } else {
if attrs.field_bound { if attrs.field_bound {
let ty = &field.ast().ty; let ty = &field.ast().ty;
@ -236,5 +245,6 @@ pub struct CssFieldAttrs {
pub field_bound: bool, pub field_bound: bool,
pub iterable: bool, pub iterable: bool,
pub skip: bool, pub skip: bool,
pub represents_keyword: bool,
pub skip_if: Option<Path>, pub skip_if: Option<Path>,
} }

View file

@ -56,8 +56,6 @@ pub type KeywordsCollectFn<'a> = &'a mut FnMut(&[&'static str]);
/// * `#[value_info(starts_with_keyword)]` can be used on variants to /// * `#[value_info(starts_with_keyword)]` can be used on variants to
/// add the name of a non-unit variant (serialized like `ToCss`) into /// add the name of a non-unit variant (serialized like `ToCss`) into
/// `collect_completion_keywords`. /// `collect_completion_keywords`.
/// * `#[value_info(represents_keyword)]` can be used on fields into
/// `collect_completion_keywords`.
pub trait SpecifiedValueInfo { pub trait SpecifiedValueInfo {
/// Supported CssTypes by the given value type. /// Supported CssTypes by the given value type.
/// ///

View file

@ -37,6 +37,9 @@ use std::fmt::{self, Write};
/// * if `#[css(skip_if = "function")]` is found on a field, the `ToCss` call /// * if `#[css(skip_if = "function")]` is found on a field, the `ToCss` call
/// for that field is skipped if `function` returns true. This function is /// for that field is skipped if `function` returns true. This function is
/// provided the field as an argument; /// provided the field as an argument;
/// * `#[css(represents_keyword)]` can be used on bool fields in order to
/// serialize the field name if the field is true, or nothing otherwise. It
/// also collects those keywords for `SpecifiedValueInfo`.
/// * finally, one can put `#[css(derive_debug)]` on the whole type, to /// * finally, one can put `#[css(derive_debug)]` on the whole type, to
/// implement `Debug` by a single call to `ToCss::to_css`. /// implement `Debug` by a single call to `ToCss::to_css`.
pub trait ToCss { pub trait ToCss {
@ -232,21 +235,6 @@ where
} }
} }
/// A wrapper type that implements `ToCss` by printing its inner field.
pub struct Verbatim<'a, T>(pub &'a T)
where
T: ?Sized + 'a;
impl<'a, T> ToCss for Verbatim<'a, T>
where
T: AsRef<str> + ?Sized + 'a,
{
#[inline]
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write {
dest.write_str(self.0.as_ref())
}
}
/// Type used as the associated type in the `OneOrMoreSeparated` trait on a /// Type used as the associated type in the `OneOrMoreSeparated` trait on a
/// type to indicate that a serialized list of elements of this type is /// type to indicate that a serialized list of elements of this type is
/// separated by commas. /// separated by commas.

View file

@ -14,7 +14,7 @@ use std::ptr;
use style::error_reporting::{ParseErrorReporter, ContextualParseError}; use style::error_reporting::{ParseErrorReporter, ContextualParseError};
use style::gecko_bindings::bindings::{Gecko_CreateCSSErrorReporter, Gecko_DestroyCSSErrorReporter}; use style::gecko_bindings::bindings::{Gecko_CreateCSSErrorReporter, Gecko_DestroyCSSErrorReporter};
use style::gecko_bindings::bindings::Gecko_ReportUnexpectedCSSError; use style::gecko_bindings::bindings::Gecko_ReportUnexpectedCSSError;
use style::gecko_bindings::structs::{Loader, ServoStyleSheet, nsIURI}; use style::gecko_bindings::structs::{Loader, StyleSheet as DomStyleSheet, nsIURI};
use style::gecko_bindings::structs::ErrorReporter as GeckoErrorReporter; use style::gecko_bindings::structs::ErrorReporter as GeckoErrorReporter;
use style::gecko_bindings::structs::URLExtraData as RawUrlExtraData; use style::gecko_bindings::structs::URLExtraData as RawUrlExtraData;
use style::stylesheets::UrlExtraData; use style::stylesheets::UrlExtraData;
@ -27,9 +27,11 @@ pub struct ErrorReporter(*mut GeckoErrorReporter);
impl ErrorReporter { impl ErrorReporter {
/// Create a new instance of the Gecko error reporter. /// Create a new instance of the Gecko error reporter.
pub fn new(sheet: *mut ServoStyleSheet, pub fn new(
loader: *mut Loader, sheet: *mut DomStyleSheet,
extra_data: *mut RawUrlExtraData) -> ErrorReporter { loader: *mut Loader,
extra_data: *mut RawUrlExtraData,
) -> Self {
unsafe { unsafe {
let url = extra_data.as_ref() let url = extra_data.as_ref()
.map(|d| d.mBaseURI.raw::<nsIURI>()) .map(|d| d.mBaseURI.raw::<nsIURI>())

View file

@ -73,7 +73,6 @@ use style::gecko_bindings::bindings::RawGeckoCSSPropertyIDListBorrowed;
use style::gecko_bindings::bindings::RawGeckoComputedKeyframeValuesListBorrowedMut; use style::gecko_bindings::bindings::RawGeckoComputedKeyframeValuesListBorrowedMut;
use style::gecko_bindings::bindings::RawGeckoComputedTimingBorrowed; use style::gecko_bindings::bindings::RawGeckoComputedTimingBorrowed;
use style::gecko_bindings::bindings::RawGeckoFontFaceRuleListBorrowedMut; use style::gecko_bindings::bindings::RawGeckoFontFaceRuleListBorrowedMut;
use style::gecko_bindings::bindings::RawGeckoServoAnimationValueListBorrowed;
use style::gecko_bindings::bindings::RawGeckoServoAnimationValueListBorrowedMut; use style::gecko_bindings::bindings::RawGeckoServoAnimationValueListBorrowedMut;
use style::gecko_bindings::bindings::RawGeckoServoStyleRuleListBorrowedMut; use style::gecko_bindings::bindings::RawGeckoServoStyleRuleListBorrowedMut;
use style::gecko_bindings::bindings::RawServoAnimationValueBorrowed; use style::gecko_bindings::bindings::RawServoAnimationValueBorrowed;
@ -92,8 +91,8 @@ use style::gecko_bindings::structs;
use style::gecko_bindings::structs::{CallerType, CSSPseudoElementType, CompositeOperation}; use style::gecko_bindings::structs::{CallerType, CSSPseudoElementType, CompositeOperation};
use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets}; use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets};
use style::gecko_bindings::structs::{RawServoStyleRule, ComputedStyleStrong, RustString}; use style::gecko_bindings::structs::{RawServoStyleRule, ComputedStyleStrong, RustString};
use style::gecko_bindings::structs::{ServoStyleSheet, SheetLoadData, SheetLoadDataHolder};
use style::gecko_bindings::structs::{SheetParsingMode, nsAtom, nsCSSPropertyID}; use style::gecko_bindings::structs::{SheetParsingMode, nsAtom, nsCSSPropertyID};
use style::gecko_bindings::structs::{StyleSheet as DomStyleSheet, SheetLoadData, SheetLoadDataHolder};
use style::gecko_bindings::structs::{nsCSSFontDesc, nsCSSCounterDesc}; use style::gecko_bindings::structs::{nsCSSFontDesc, nsCSSCounterDesc};
use style::gecko_bindings::structs::{nsRestyleHint, nsChangeHint, PropertyValuePair}; use style::gecko_bindings::structs::{nsRestyleHint, nsChangeHint, PropertyValuePair};
use style::gecko_bindings::structs::AtomArray; use style::gecko_bindings::structs::AtomArray;
@ -129,7 +128,7 @@ use style::invalidation::element::restyle_hints;
use style::media_queries::{MediaList, parse_media_query_list}; use style::media_queries::{MediaList, parse_media_query_list};
use style::parser::{Parse, ParserContext, self}; use style::parser::{Parse, ParserContext, self};
use style::properties::{ComputedValues, DeclarationSource, Importance}; use style::properties::{ComputedValues, DeclarationSource, Importance};
use style::properties::{LonghandId, LonghandIdSet, PropertyDeclaration, PropertyDeclarationBlock, PropertyId}; use style::properties::{LonghandId, LonghandIdSet, PropertyDeclarationBlock, PropertyId};
use style::properties::{PropertyDeclarationId, ShorthandId}; use style::properties::{PropertyDeclarationId, ShorthandId};
use style::properties::{SourcePropertyDeclaration, StyleBuilder}; use style::properties::{SourcePropertyDeclaration, StyleBuilder};
use style::properties::{parse_one_declaration_into, parse_style_attribute}; use style::properties::{parse_one_declaration_into, parse_style_attribute};
@ -708,31 +707,6 @@ pub extern "C" fn Servo_AnimationValue_Serialize(
debug_assert!(rv.is_ok()); debug_assert!(rv.is_ok());
} }
#[no_mangle]
pub unsafe extern "C" fn Servo_Shorthand_AnimationValues_Serialize(
shorthand_property: nsCSSPropertyID,
values: RawGeckoServoAnimationValueListBorrowed,
buffer: *mut nsAString,
) {
let property_id = get_property_id_from_nscsspropertyid!(shorthand_property, ());
let shorthand = match property_id.as_shorthand() {
Ok(shorthand) => shorthand,
_ => return,
};
// Convert RawServoAnimationValue(s) into a vector of PropertyDeclaration
// so that we can use reference of the PropertyDeclaration without worrying
// about its lifetime. (longhands_to_css() expects &PropertyDeclaration
// iterator.)
let declarations: Vec<PropertyDeclaration> =
values.iter().map(|v| AnimationValue::as_arc(&&*v.mRawPtr).uncompute()).collect();
let _ = shorthand.longhands_to_css(
declarations.iter(),
&mut CssWriter::new(&mut *buffer),
);
}
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_AnimationValue_GetOpacity( pub extern "C" fn Servo_AnimationValue_GetOpacity(
value: RawServoAnimationValueBorrowed, value: RawServoAnimationValueBorrowed,
@ -1194,7 +1168,7 @@ fn mode_to_origin(mode: SheetParsingMode) -> Origin {
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes( pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(
loader: *mut Loader, loader: *mut Loader,
stylesheet: *mut ServoStyleSheet, stylesheet: *mut DomStyleSheet,
load_data: *mut SheetLoadData, load_data: *mut SheetLoadData,
bytes: *const nsACString, bytes: *const nsACString,
mode: SheetParsingMode, mode: SheetParsingMode,
@ -1263,7 +1237,7 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSet_AppendStyleSheet( pub extern "C" fn Servo_StyleSet_AppendStyleSheet(
raw_data: RawServoStyleSetBorrowed, raw_data: RawServoStyleSetBorrowed,
sheet: *const ServoStyleSheet, sheet: *const DomStyleSheet,
) { ) {
let global_style_data = &*GLOBAL_STYLE_DATA; let global_style_data = &*GLOBAL_STYLE_DATA;
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
@ -1288,7 +1262,7 @@ pub extern "C" fn Servo_AuthorStyles_Drop(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet( pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet(
styles: RawServoAuthorStylesBorrowedMut, styles: RawServoAuthorStylesBorrowedMut,
sheet: *const ServoStyleSheet, sheet: *const DomStyleSheet,
) { ) {
let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles); let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
@ -1301,8 +1275,8 @@ pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore( pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore(
styles: RawServoAuthorStylesBorrowedMut, styles: RawServoAuthorStylesBorrowedMut,
sheet: *const ServoStyleSheet, sheet: *const DomStyleSheet,
before_sheet: *const ServoStyleSheet, before_sheet: *const DomStyleSheet,
) { ) {
let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles); let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
@ -1319,7 +1293,7 @@ pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn Servo_AuthorStyles_RemoveStyleSheet( pub unsafe extern "C" fn Servo_AuthorStyles_RemoveStyleSheet(
styles: RawServoAuthorStylesBorrowedMut, styles: RawServoAuthorStylesBorrowedMut,
sheet: *const ServoStyleSheet, sheet: *const DomStyleSheet,
) { ) {
let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles); let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
@ -1454,7 +1428,7 @@ pub unsafe extern "C" fn Servo_StyleSet_MediumFeaturesChanged(
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSet_PrependStyleSheet( pub extern "C" fn Servo_StyleSet_PrependStyleSheet(
raw_data: RawServoStyleSetBorrowed, raw_data: RawServoStyleSetBorrowed,
sheet: *const ServoStyleSheet, sheet: *const DomStyleSheet,
) { ) {
let global_style_data = &*GLOBAL_STYLE_DATA; let global_style_data = &*GLOBAL_STYLE_DATA;
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
@ -1467,8 +1441,8 @@ pub extern "C" fn Servo_StyleSet_PrependStyleSheet(
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore( pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(
raw_data: RawServoStyleSetBorrowed, raw_data: RawServoStyleSetBorrowed,
sheet: *const ServoStyleSheet, sheet: *const DomStyleSheet,
before_sheet: *const ServoStyleSheet before_sheet: *const DomStyleSheet
) { ) {
let global_style_data = &*GLOBAL_STYLE_DATA; let global_style_data = &*GLOBAL_STYLE_DATA;
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
@ -1485,7 +1459,7 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSet_RemoveStyleSheet( pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(
raw_data: RawServoStyleSetBorrowed, raw_data: RawServoStyleSetBorrowed,
sheet: *const ServoStyleSheet sheet: *const DomStyleSheet
) { ) {
let global_style_data = &*GLOBAL_STYLE_DATA; let global_style_data = &*GLOBAL_STYLE_DATA;
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
@ -1560,7 +1534,7 @@ pub extern "C" fn Servo_StyleSheet_GetRules(
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSheet_Clone( pub extern "C" fn Servo_StyleSheet_Clone(
raw_sheet: RawServoStyleSheetContentsBorrowed, raw_sheet: RawServoStyleSheetContentsBorrowed,
reference_sheet: *const ServoStyleSheet, reference_sheet: *const DomStyleSheet,
) -> RawServoStyleSheetContentsStrong { ) -> RawServoStyleSheetContentsStrong {
use style::shared_lock::{DeepCloneParams, DeepCloneWithLock}; use style::shared_lock::{DeepCloneParams, DeepCloneWithLock};
let global_style_data = &*GLOBAL_STYLE_DATA; let global_style_data = &*GLOBAL_STYLE_DATA;
@ -1681,7 +1655,7 @@ pub extern "C" fn Servo_CssRules_InsertRule(
index: u32, index: u32,
nested: bool, nested: bool,
loader: *mut Loader, loader: *mut Loader,
gecko_stylesheet: *mut ServoStyleSheet, gecko_stylesheet: *mut DomStyleSheet,
rule_type: *mut u16, rule_type: *mut u16,
) -> nsresult { ) -> nsresult {
let loader = if loader.is_null() { let loader = if loader.is_null() {
@ -2136,16 +2110,16 @@ pub extern "C" fn Servo_ImportRule_GetHref(rule: RawServoImportRuleBorrowed, res
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_ImportRule_GetSheet( pub extern "C" fn Servo_ImportRule_GetSheet(
rule: RawServoImportRuleBorrowed, rule: RawServoImportRuleBorrowed,
) -> *const ServoStyleSheet { ) -> *const DomStyleSheet {
read_locked_arc(rule, |rule: &ImportRule| { read_locked_arc(rule, |rule: &ImportRule| {
rule.stylesheet.as_sheet().unwrap().raw() as *const ServoStyleSheet rule.stylesheet.as_sheet().unwrap().raw() as *const DomStyleSheet
}) })
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_ImportRule_SetSheet( pub extern "C" fn Servo_ImportRule_SetSheet(
rule: RawServoImportRuleBorrowed, rule: RawServoImportRuleBorrowed,
sheet: *mut ServoStyleSheet, sheet: *mut DomStyleSheet,
) { ) {
write_locked_arc(rule, |rule: &mut ImportRule| { write_locked_arc(rule, |rule: &mut ImportRule| {
let sheet = unsafe { GeckoStyleSheet::new(sheet) }; let sheet = unsafe { GeckoStyleSheet::new(sheet) };
@ -3609,6 +3583,20 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
) )
} }
#[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue(
declarations: RawServoDeclarationBlockBorrowed,
animation_value: RawServoAnimationValueBorrowed,
) -> bool {
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(
AnimationValue::as_arc(&animation_value).uncompute(),
Importance::Normal,
DeclarationSource::CssOm,
)
})
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById( pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
declarations: RawServoDeclarationBlockBorrowed, declarations: RawServoDeclarationBlockBorrowed,
@ -4506,7 +4494,6 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(
raw_data: RawServoStyleSetBorrowed, raw_data: RawServoStyleSetBorrowed,
computed_keyframes: RawGeckoComputedKeyframeValuesListBorrowedMut computed_keyframes: RawGeckoComputedKeyframeValuesListBorrowedMut
) { ) {
use std::mem;
use style::properties::LonghandIdSet; use style::properties::LonghandIdSet;
let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
@ -4567,10 +4554,6 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(
// This is safe since we immediately write to the uninitialized values. // This is safe since we immediately write to the uninitialized values.
unsafe { animation_values.set_len((property_index + 1) as u32) }; unsafe { animation_values.set_len((property_index + 1) as u32) };
animation_values[property_index].mProperty = property.to_nscsspropertyid(); animation_values[property_index].mProperty = property.to_nscsspropertyid();
// We only make sure we have enough space for this variable,
// but didn't construct a default value for StyleAnimationValue,
// so we should zero it to avoid getting undefined behaviors.
animation_values[property_index].mValue.mGecko = unsafe { mem::zeroed() };
match value { match value {
Some(v) => { Some(v) => {
animation_values[property_index].mValue.mServo.set_arc_leaky(Arc::new(v)); animation_values[property_index].mValue.mServo.set_arc_leaky(Arc::new(v));
@ -4768,17 +4751,18 @@ fn fill_in_missing_keyframe_values(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName( pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
raw_data: RawServoStyleSetBorrowed, raw_data: RawServoStyleSetBorrowed,
element: RawGeckoElementBorrowed,
name: *mut nsAtom, name: *mut nsAtom,
inherited_timing_function: nsTimingFunctionBorrowed, inherited_timing_function: nsTimingFunctionBorrowed,
keyframes: RawGeckoKeyframeListBorrowedMut, keyframes: RawGeckoKeyframeListBorrowedMut,
) -> bool { ) -> bool {
debug_assert!(keyframes.len() == 0, debug_assert!(keyframes.len() == 0, "keyframes should be initially empty");
"keyframes should be initially empty");
let element = GeckoElement(element);
let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let name = Atom::from_raw(name); let name = Atom::from_raw(name);
let animation = match data.stylist.get_animation(&name) { let animation = match data.stylist.get_animation(&name, element) {
Some(animation) => animation, Some(animation) => animation,
None => return false, None => return false,
}; };

View file

@ -12,7 +12,7 @@ use style::gecko::global_style_data::GLOBAL_STYLE_DATA;
use style::gecko_bindings::bindings; use style::gecko_bindings::bindings;
use style::gecko_bindings::bindings::Gecko_LoadStyleSheet; use style::gecko_bindings::bindings::Gecko_LoadStyleSheet;
use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets}; use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets};
use style::gecko_bindings::structs::{ServoStyleSheet, SheetLoadData, SheetLoadDataHolder}; use style::gecko_bindings::structs::{StyleSheet as DomStyleSheet, SheetLoadData, SheetLoadDataHolder};
use style::gecko_bindings::structs::URLExtraData; use style::gecko_bindings::structs::URLExtraData;
use style::gecko_bindings::sugar::ownership::FFIArcHelpers; use style::gecko_bindings::sugar::ownership::FFIArcHelpers;
use style::gecko_bindings::sugar::refptr::RefPtr; use style::gecko_bindings::sugar::refptr::RefPtr;
@ -24,13 +24,15 @@ use style::stylesheets::StylesheetContents;
use style::stylesheets::import_rule::ImportSheet; use style::stylesheets::import_rule::ImportSheet;
use style::values::CssUrl; use style::values::CssUrl;
pub struct StylesheetLoader(*mut Loader, *mut ServoStyleSheet, *mut SheetLoadData, *mut LoaderReusableStyleSheets); pub struct StylesheetLoader(*mut Loader, *mut DomStyleSheet, *mut SheetLoadData, *mut LoaderReusableStyleSheets);
impl StylesheetLoader { impl StylesheetLoader {
pub fn new(loader: *mut Loader, pub fn new(
parent: *mut ServoStyleSheet, loader: *mut Loader,
parent_load_data: *mut SheetLoadData, parent: *mut DomStyleSheet,
reusable_sheets: *mut LoaderReusableStyleSheets) -> Self { parent_load_data: *mut SheetLoadData,
reusable_sheets: *mut LoaderReusableStyleSheets,
) -> Self {
StylesheetLoader(loader, parent, parent_load_data, reusable_sheets) StylesheetLoader(loader, parent, parent_load_data, reusable_sheets)
} }
} }

View file

@ -7,7 +7,7 @@ use style::computed_values::display::T as Display;
use style::properties::{PropertyDeclaration, Importance}; use style::properties::{PropertyDeclaration, Importance};
use style::properties::declaration_block::PropertyDeclarationBlock; use style::properties::declaration_block::PropertyDeclarationBlock;
use style::properties::parse_property_declaration_list; use style::properties::parse_property_declaration_list;
use style::values::{CustomIdent, RGBA}; use style::values::RGBA;
use style::values::specified::{BorderStyle, BorderSideWidth, Color}; use style::values::specified::{BorderStyle, BorderSideWidth, Color};
use style::values::specified::{Length, LengthOrPercentage, LengthOrPercentageOrAuto}; use style::values::specified::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
use style::values::specified::NoCalcLength; use style::values::specified::NoCalcLength;
@ -890,31 +890,4 @@ mod shorthand_serialization {
assert_eq!(shadow.to_css_string(), shadow_css); assert_eq!(shadow.to_css_string(), shadow_css);
} }
} }
mod counter_increment {
pub use super::*;
pub use style::properties::longhands::counter_increment::SpecifiedValue as CounterIncrement;
use style::values::specified::Integer;
#[test]
fn counter_increment_with_properties_should_serialize_correctly() {
let mut properties = Vec::new();
properties.push((CustomIdent("counter1".into()), Integer::new(1)));
properties.push((CustomIdent("counter2".into()), Integer::new(-4)));
let counter_increment = CounterIncrement::new(properties);
let counter_increment_css = "counter1 1 counter2 -4";
assert_eq!(counter_increment.to_css_string(), counter_increment_css);
}
#[test]
fn counter_increment_without_properties_should_serialize_correctly() {
let counter_increment = CounterIncrement::new(Vec::new());
let counter_increment_css = "none";
assert_eq!(counter_increment.to_css_string(), counter_increment_css);
}
}
} }