mirror of
https://github.com/servo/servo.git
synced 2025-07-23 23:33:43 +01:00
style: Add @keyframe rule parsing.
This commit is contained in:
parent
7b2080c5b7
commit
c1fd7432e9
5 changed files with 197 additions and 15 deletions
91
components/style/keyframes.rs
Normal file
91
components/style/keyframes.rs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use cssparser::{Parser, Delimiter};
|
||||||
|
use parser::ParserContext;
|
||||||
|
use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
|
||||||
|
|
||||||
|
/// Parses a keyframes list, like:
|
||||||
|
/// 0%, 50% {
|
||||||
|
/// width: 50%;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// 40%, 60%, 100% {
|
||||||
|
/// width: 100%;
|
||||||
|
/// }
|
||||||
|
pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Result<Vec<Keyframe>, ()> {
|
||||||
|
let mut keyframes = vec![];
|
||||||
|
while !input.is_exhausted() {
|
||||||
|
keyframes.push(try!(Keyframe::parse(context, input)));
|
||||||
|
}
|
||||||
|
Ok(keyframes)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A number from 1 to 100, indicating the percentage of the animation where
|
||||||
|
/// this keyframe should run.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, HeapSizeOf)]
|
||||||
|
pub struct KeyframePercentage(f32);
|
||||||
|
|
||||||
|
impl KeyframePercentage {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(value: f32) -> KeyframePercentage {
|
||||||
|
debug_assert!(value >= 0. && value <= 1.);
|
||||||
|
KeyframePercentage(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &mut Parser) -> Result<KeyframePercentage, ()> {
|
||||||
|
let percentage = if input.try(|input| input.expect_ident_matching("from")).is_ok() {
|
||||||
|
KeyframePercentage::new(0.)
|
||||||
|
} else if input.try(|input| input.expect_ident_matching("to")).is_ok() {
|
||||||
|
KeyframePercentage::new(1.)
|
||||||
|
} else {
|
||||||
|
KeyframePercentage::new(try!(input.expect_percentage()))
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(percentage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A keyframes selector is a list of percentages or from/to symbols, which are
|
||||||
|
/// converted at parse time to percentages.
|
||||||
|
#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
|
||||||
|
pub struct KeyframeSelector(Vec<KeyframePercentage>);
|
||||||
|
impl KeyframeSelector {
|
||||||
|
#[inline]
|
||||||
|
pub fn percentages(&self) -> &[KeyframePercentage] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A dummy public function so we can write a unit test for this.
|
||||||
|
pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelector {
|
||||||
|
KeyframeSelector(percentages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A keyframe.
|
||||||
|
#[derive(Debug, Clone, PartialEq, HeapSizeOf)]
|
||||||
|
pub struct Keyframe {
|
||||||
|
pub selector: KeyframeSelector,
|
||||||
|
pub declarations: PropertyDeclarationBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Keyframe {
|
||||||
|
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Keyframe, ()> {
|
||||||
|
let percentages = try!(input.parse_until_before(Delimiter::CurlyBracketBlock, |input| {
|
||||||
|
input.parse_comma_separated(|input| KeyframePercentage::parse(input))
|
||||||
|
}));
|
||||||
|
let selector = KeyframeSelector(percentages);
|
||||||
|
|
||||||
|
try!(input.expect_curly_bracket_block());
|
||||||
|
|
||||||
|
let declarations = input.parse_nested_block(|input| {
|
||||||
|
Ok(parse_property_declaration_list(context, input))
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
|
Ok(Keyframe {
|
||||||
|
selector: selector,
|
||||||
|
declarations: declarations,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,6 +76,7 @@ pub mod dom;
|
||||||
pub mod element_state;
|
pub mod element_state;
|
||||||
pub mod error_reporting;
|
pub mod error_reporting;
|
||||||
pub mod font_face;
|
pub mod font_face;
|
||||||
|
pub mod keyframes;
|
||||||
pub mod logical_geometry;
|
pub mod logical_geometry;
|
||||||
pub mod matching;
|
pub mod matching;
|
||||||
pub mod media_queries;
|
pub mod media_queries;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use dom::PresentationalHintsSynthetizer;
|
use dom::PresentationalHintsSynthetizer;
|
||||||
use element_state::*;
|
use element_state::*;
|
||||||
use error_reporting::StdoutErrorReporter;
|
use error_reporting::StdoutErrorReporter;
|
||||||
|
use keyframes::Keyframe;
|
||||||
use media_queries::{Device, MediaType};
|
use media_queries::{Device, MediaType};
|
||||||
use parser::ParserContextExtraData;
|
use parser::ParserContextExtraData;
|
||||||
use properties::{self, PropertyDeclaration, PropertyDeclarationBlock};
|
use properties::{self, PropertyDeclaration, PropertyDeclarationBlock};
|
||||||
|
@ -23,7 +24,7 @@ use std::hash::BuildHasherDefault;
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use style_traits::viewport::ViewportConstraints;
|
use style_traits::viewport::ViewportConstraints;
|
||||||
use stylesheets::{CSSRuleIteratorExt, Origin, Stylesheet};
|
use stylesheets::{CSSRule, CSSRuleIteratorExt, Origin, Stylesheet};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::opts;
|
use util::opts;
|
||||||
use util::resource_files::read_resource_file;
|
use util::resource_files::read_resource_file;
|
||||||
|
@ -126,6 +127,11 @@ pub struct Stylist<Impl: SelectorImplExt> {
|
||||||
PerPseudoElementSelectorMap<Impl>,
|
PerPseudoElementSelectorMap<Impl>,
|
||||||
BuildHasherDefault<::fnv::FnvHasher>>,
|
BuildHasherDefault<::fnv::FnvHasher>>,
|
||||||
|
|
||||||
|
/// A map with all the animations indexed by name.
|
||||||
|
animations: HashMap<String,
|
||||||
|
Vec<Keyframe>,
|
||||||
|
BuildHasherDefault<::fnv::FnvHasher>>,
|
||||||
|
|
||||||
/// Applicable declarations for a given non-eagerly cascaded pseudo-element.
|
/// Applicable declarations for a given non-eagerly cascaded pseudo-element.
|
||||||
/// These are eagerly computed once, and then used to resolve the new
|
/// These are eagerly computed once, and then used to resolve the new
|
||||||
/// computed values on the fly on layout.
|
/// computed values on the fly on layout.
|
||||||
|
@ -150,6 +156,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
|
||||||
|
|
||||||
element_map: PerPseudoElementSelectorMap::new(),
|
element_map: PerPseudoElementSelectorMap::new(),
|
||||||
pseudos_map: HashMap::with_hasher(Default::default()),
|
pseudos_map: HashMap::with_hasher(Default::default()),
|
||||||
|
animations: HashMap::with_hasher(Default::default()),
|
||||||
precomputed_pseudo_element_decls: HashMap::with_hasher(Default::default()),
|
precomputed_pseudo_element_decls: HashMap::with_hasher(Default::default()),
|
||||||
rules_source_order: 0,
|
rules_source_order: 0,
|
||||||
state_deps: DependencySet::new(),
|
state_deps: DependencySet::new(),
|
||||||
|
@ -173,6 +180,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
|
||||||
|
|
||||||
self.element_map = PerPseudoElementSelectorMap::new();
|
self.element_map = PerPseudoElementSelectorMap::new();
|
||||||
self.pseudos_map = HashMap::with_hasher(Default::default());
|
self.pseudos_map = HashMap::with_hasher(Default::default());
|
||||||
|
self.animations = HashMap::with_hasher(Default::default());
|
||||||
Impl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
Impl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
||||||
self.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new());
|
self.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new());
|
||||||
});
|
});
|
||||||
|
@ -233,16 +241,28 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
|
|
||||||
for style_rule in stylesheet.effective_rules(&self.device).style() {
|
for rule in stylesheet.effective_rules(&self.device) {
|
||||||
|
match *rule {
|
||||||
|
CSSRule::Style(ref style_rule) => {
|
||||||
append!(style_rule, normal);
|
append!(style_rule, normal);
|
||||||
append!(style_rule, important);
|
append!(style_rule, important);
|
||||||
rules_source_order += 1;
|
rules_source_order += 1;
|
||||||
for selector in &style_rule.selectors {
|
for selector in &style_rule.selectors {
|
||||||
self.state_deps.note_selector(selector.compound_selectors.clone());
|
self.state_deps.note_selector(selector.compound_selectors.clone());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.rules_source_order = rules_source_order;
|
self.rules_source_order = rules_source_order;
|
||||||
|
}
|
||||||
|
CSSRule::Keyframes(ref keyframes_rule) => {
|
||||||
|
// TODO: This *might* be optimised converting the
|
||||||
|
// Vec<Keyframe> into something like Arc<[Keyframe]>.
|
||||||
|
self.animations.insert(keyframes_rule.name.clone(),
|
||||||
|
keyframes_rule.keyframes.clone());
|
||||||
|
}
|
||||||
|
// We don't care about any other rule.
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Impl::each_precomputed_pseudo_element(|pseudo| {
|
Impl::each_precomputed_pseudo_element(|pseudo| {
|
||||||
// TODO: Consider not doing this and just getting the rules on the
|
// TODO: Consider not doing this and just getting the rules on the
|
||||||
|
|
|
@ -9,6 +9,7 @@ use cssparser::{AtRuleType, RuleListParser};
|
||||||
use encoding::EncodingRef;
|
use encoding::EncodingRef;
|
||||||
use error_reporting::ParseErrorReporter;
|
use error_reporting::ParseErrorReporter;
|
||||||
use font_face::{FontFaceRule, parse_font_face_block};
|
use font_face::{FontFaceRule, parse_font_face_block};
|
||||||
|
use keyframes::{Keyframe, parse_keyframe_list};
|
||||||
use media_queries::{Device, MediaQueryList, parse_media_query_list};
|
use media_queries::{Device, MediaQueryList, parse_media_query_list};
|
||||||
use parser::{ParserContext, ParserContextExtraData, log_css_error};
|
use parser::{ParserContext, ParserContextExtraData, log_css_error};
|
||||||
use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
|
use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
|
||||||
|
@ -62,6 +63,14 @@ pub enum CSSRule<Impl: SelectorImpl> {
|
||||||
Media(MediaRule<Impl>),
|
Media(MediaRule<Impl>),
|
||||||
FontFace(FontFaceRule),
|
FontFace(FontFaceRule),
|
||||||
Viewport(ViewportRule),
|
Viewport(ViewportRule),
|
||||||
|
Keyframes(KeyframesRule),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, HeapSizeOf, PartialEq)]
|
||||||
|
pub struct KeyframesRule {
|
||||||
|
pub name: String,
|
||||||
|
pub keyframes: Vec<Keyframe>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
@ -71,6 +80,7 @@ pub struct MediaRule<Impl: SelectorImpl> {
|
||||||
pub rules: Vec<CSSRule<Impl>>,
|
pub rules: Vec<CSSRule<Impl>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<Impl: SelectorImpl> MediaRule<Impl> {
|
impl<Impl: SelectorImpl> MediaRule<Impl> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn evaluate(&self, device: &Device) -> bool {
|
pub fn evaluate(&self, device: &Device) -> bool {
|
||||||
|
@ -127,7 +137,7 @@ impl<Impl: SelectorImpl> Stylesheet<Impl> {
|
||||||
let mut input = Parser::new(css);
|
let mut input = Parser::new(css);
|
||||||
input.look_for_viewport_percentages();
|
input.look_for_viewport_percentages();
|
||||||
|
|
||||||
let mut rules = Vec::new();
|
let mut rules = vec![];
|
||||||
{
|
{
|
||||||
let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser);
|
let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser);
|
||||||
while let Some(result) = iter.next() {
|
while let Some(result) = iter.next() {
|
||||||
|
@ -142,6 +152,7 @@ impl<Impl: SelectorImpl> Stylesheet<Impl> {
|
||||||
Some(namespace.clone());
|
Some(namespace.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rules.push(rule);
|
rules.push(rule);
|
||||||
}
|
}
|
||||||
Err(range) => {
|
Err(range) => {
|
||||||
|
@ -153,6 +164,7 @@ impl<Impl: SelectorImpl> Stylesheet<Impl> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stylesheet {
|
Stylesheet {
|
||||||
origin: origin,
|
origin: origin,
|
||||||
rules: rules,
|
rules: rules,
|
||||||
|
@ -253,7 +265,7 @@ pub mod rule_filter {
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use super::super::font_face::FontFaceRule;
|
use super::super::font_face::FontFaceRule;
|
||||||
use super::super::viewport::ViewportRule;
|
use super::super::viewport::ViewportRule;
|
||||||
use super::{CSSRule, MediaRule, StyleRule};
|
use super::{CSSRule, KeyframesRule, MediaRule, StyleRule};
|
||||||
|
|
||||||
macro_rules! rule_filter {
|
macro_rules! rule_filter {
|
||||||
($variant:ident -> $value:ty) => {
|
($variant:ident -> $value:ty) => {
|
||||||
|
@ -266,6 +278,8 @@ pub mod rule_filter {
|
||||||
|
|
||||||
impl<'a, I, Impl: SelectorImpl + 'a> $variant<'a, I>
|
impl<'a, I, Impl: SelectorImpl + 'a> $variant<'a, I>
|
||||||
where I: Iterator<Item=&'a CSSRule<Impl>> {
|
where I: Iterator<Item=&'a CSSRule<Impl>> {
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn new(iter: I) -> $variant<'a, I> {
|
pub fn new(iter: I) -> $variant<'a, I> {
|
||||||
$variant {
|
$variant {
|
||||||
iter: iter,
|
iter: iter,
|
||||||
|
@ -300,6 +314,7 @@ pub mod rule_filter {
|
||||||
rule_filter!(Style -> StyleRule<Impl>);
|
rule_filter!(Style -> StyleRule<Impl>);
|
||||||
rule_filter!(FontFace -> FontFaceRule);
|
rule_filter!(FontFace -> FontFaceRule);
|
||||||
rule_filter!(Viewport -> ViewportRule);
|
rule_filter!(Viewport -> ViewportRule);
|
||||||
|
rule_filter!(Keyframes -> KeyframesRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extension methods for `CSSRule` iterators.
|
/// Extension methods for `CSSRule` iterators.
|
||||||
|
@ -315,6 +330,9 @@ pub trait CSSRuleIteratorExt<'a, Impl: SelectorImpl + 'a>: Iterator<Item=&'a CSS
|
||||||
|
|
||||||
/// Yield only @viewport rules.
|
/// Yield only @viewport rules.
|
||||||
fn viewport(self) -> rule_filter::Viewport<'a, Self>;
|
fn viewport(self) -> rule_filter::Viewport<'a, Self>;
|
||||||
|
|
||||||
|
/// Yield only @keyframes rules.
|
||||||
|
fn keyframes(self) -> rule_filter::Keyframes<'a, Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I, Impl: SelectorImpl + 'a> CSSRuleIteratorExt<'a, Impl> for I where I: Iterator<Item=&'a CSSRule<Impl>> {
|
impl<'a, I, Impl: SelectorImpl + 'a> CSSRuleIteratorExt<'a, Impl> for I where I: Iterator<Item=&'a CSSRule<Impl>> {
|
||||||
|
@ -337,6 +355,11 @@ impl<'a, I, Impl: SelectorImpl + 'a> CSSRuleIteratorExt<'a, Impl> for I where I:
|
||||||
fn viewport(self) -> rule_filter::Viewport<'a, I> {
|
fn viewport(self) -> rule_filter::Viewport<'a, I> {
|
||||||
rule_filter::Viewport::new(self)
|
rule_filter::Viewport::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn keyframes(self) -> rule_filter::Keyframes<'a, I> {
|
||||||
|
rule_filter::Keyframes::new(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_nested_rules<Impl: SelectorImpl>(context: &ParserContext, input: &mut Parser) -> Vec<CSSRule<Impl>> {
|
fn parse_nested_rules<Impl: SelectorImpl>(context: &ParserContext, input: &mut Parser) -> Vec<CSSRule<Impl>> {
|
||||||
|
@ -376,9 +399,14 @@ enum State {
|
||||||
|
|
||||||
|
|
||||||
enum AtRulePrelude {
|
enum AtRulePrelude {
|
||||||
|
/// A @font-face rule prelude.
|
||||||
FontFace,
|
FontFace,
|
||||||
|
/// A @media rule prelude, with its media queries.
|
||||||
Media(MediaQueryList),
|
Media(MediaQueryList),
|
||||||
|
/// A @viewport rule prelude.
|
||||||
Viewport,
|
Viewport,
|
||||||
|
/// A @keyframes rule, with its animation name.
|
||||||
|
Keyframes(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -478,6 +506,10 @@ impl<'a, 'b, Impl: SelectorImpl> AtRuleParser for NestedRuleParser<'a, 'b, Impl>
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"keyframes" => {
|
||||||
|
let name = try!(input.expect_ident());
|
||||||
|
Ok(AtRuleType::WithBlock(AtRulePrelude::Keyframes(name.into_owned())))
|
||||||
|
},
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -496,10 +528,15 @@ impl<'a, 'b, Impl: SelectorImpl> AtRuleParser for NestedRuleParser<'a, 'b, Impl>
|
||||||
AtRulePrelude::Viewport => {
|
AtRulePrelude::Viewport => {
|
||||||
ViewportRule::parse(input, self.context).map(CSSRule::Viewport)
|
ViewportRule::parse(input, self.context).map(CSSRule::Viewport)
|
||||||
}
|
}
|
||||||
|
AtRulePrelude::Keyframes(name) => {
|
||||||
|
Ok(CSSRule::Keyframes(KeyframesRule {
|
||||||
|
name: name,
|
||||||
|
keyframes: try!(parse_keyframe_list(&self.context, input)),
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<'a, 'b, Impl: SelectorImpl> QualifiedRuleParser for NestedRuleParser<'a, 'b, Impl> {
|
impl<'a, 'b, Impl: SelectorImpl> QualifiedRuleParser for NestedRuleParser<'a, 'b, Impl> {
|
||||||
type Prelude = Vec<Selector<Impl>>;
|
type Prelude = Vec<Selector<Impl>>;
|
||||||
|
|
|
@ -9,11 +9,13 @@ use std::borrow::ToOwned;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use string_cache::{Atom, Namespace};
|
use string_cache::{Atom, Namespace};
|
||||||
|
use style::error_reporting::ParseErrorReporter;
|
||||||
|
use style::keyframes::{Keyframe, KeyframeSelector, KeyframePercentage};
|
||||||
use style::parser::ParserContextExtraData;
|
use style::parser::ParserContextExtraData;
|
||||||
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, DeclaredValue, longhands};
|
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, DeclaredValue, longhands};
|
||||||
use style::stylesheets::{CSSRule, StyleRule, Origin};
|
|
||||||
use style::error_reporting::ParseErrorReporter;
|
|
||||||
use style::servo::Stylesheet;
|
use style::servo::Stylesheet;
|
||||||
|
use style::stylesheets::{CSSRule, StyleRule, KeyframesRule, Origin};
|
||||||
|
use style::values::specified::{LengthOrPercentageOrAuto, Percentage};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -24,7 +26,10 @@ fn test_parse_stylesheet() {
|
||||||
input[type=hidden i] { display: none !important; }
|
input[type=hidden i] { display: none !important; }
|
||||||
html , body /**/ { display: block; }
|
html , body /**/ { display: block; }
|
||||||
#d1 > .ok { background: blue; }
|
#d1 > .ok { background: blue; }
|
||||||
";
|
@keyframes foo {
|
||||||
|
from { width: 0% }
|
||||||
|
to { width: 100%}
|
||||||
|
}";
|
||||||
let url = Url::parse("about::test").unwrap();
|
let url = Url::parse("about::test").unwrap();
|
||||||
let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent,
|
let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent,
|
||||||
Box::new(CSSErrorReporterTest),
|
Box::new(CSSErrorReporterTest),
|
||||||
|
@ -145,6 +150,34 @@ fn test_parse_stylesheet() {
|
||||||
important: Arc::new(vec![]),
|
important: Arc::new(vec![]),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
CSSRule::Keyframes(KeyframesRule {
|
||||||
|
name: "foo".into(),
|
||||||
|
keyframes: vec![
|
||||||
|
Keyframe {
|
||||||
|
selector: KeyframeSelector::new_for_unit_testing(
|
||||||
|
vec![KeyframePercentage::new(0.)]),
|
||||||
|
declarations: PropertyDeclarationBlock {
|
||||||
|
normal: Arc::new(vec![
|
||||||
|
PropertyDeclaration::Width(DeclaredValue::Value(
|
||||||
|
LengthOrPercentageOrAuto::Percentage(Percentage(0.)))),
|
||||||
|
]),
|
||||||
|
important: Arc::new(vec![]),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Keyframe {
|
||||||
|
selector: KeyframeSelector::new_for_unit_testing(
|
||||||
|
vec![KeyframePercentage::new(1.)]),
|
||||||
|
declarations: PropertyDeclarationBlock {
|
||||||
|
normal: Arc::new(vec![
|
||||||
|
PropertyDeclaration::Width(DeclaredValue::Value(
|
||||||
|
LengthOrPercentageOrAuto::Percentage(Percentage(1.)))),
|
||||||
|
]),
|
||||||
|
important: Arc::new(vec![]),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue