diff options
author | bors-servo <release+servo@mozilla.com> | 2013-10-18 14:25:34 -0700 |
---|---|---|
committer | bors-servo <release+servo@mozilla.com> | 2013-10-18 14:25:34 -0700 |
commit | 8f7f70cb5c26c6787e322fdff729b3e5054398bd (patch) | |
tree | f88dbc964ebb91fc027bb84c5121cc58c8a41472 | |
parent | 284ad5ee8eb43274036b05ae400fccb823313d15 (diff) | |
parent | ec711dac78750a8417c181cba0285f0753e82ff8 (diff) | |
download | servo-8f7f70cb5c26c6787e322fdff729b3e5054398bd.tar.gz servo-8f7f70cb5c26c6787e322fdff729b3e5054398bd.zip |
auto merge of #1087 : SimonSapin/servo/newnewcss, r=kmcallister
This is still not the big switch yet, but preparatory changes contained to the 'style' crate.
The current status of the actual port can be seen here: https://github.com/SimonSapin/servo/compare/newnewcss...break-all-the-things (moving as I push and rebase stuff.)
-rw-r--r-- | src/components/style/common_types.rs | 52 | ||||
-rw-r--r-- | src/components/style/properties.rs.mako | 177 | ||||
-rw-r--r-- | src/components/style/selector_matching.rs | 17 | ||||
-rw-r--r-- | src/components/style/selectors.rs | 13 | ||||
-rw-r--r-- | src/components/style/style.rc | 9 | ||||
-rw-r--r-- | src/components/style/stylesheets.rs | 134 | ||||
-rw-r--r-- | src/components/style/tests/mod.rs | 4 |
7 files changed, 244 insertions, 162 deletions
diff --git a/src/components/style/common_types.rs b/src/components/style/common_types.rs index 48cbafa51ed..96341e5d286 100644 --- a/src/components/style/common_types.rs +++ b/src/components/style/common_types.rs @@ -4,34 +4,34 @@ pub use servo_util::geometry::Au; -pub type Float = f64; +pub type CSSFloat = f64; pub mod specified { use std::ascii::StrAsciiExt; use cssparser::*; - use super::{Au, Float}; + use super::{Au, CSSFloat}; pub use CSSColor = cssparser::Color; #[deriving(Clone)] pub enum Length { Au_(Au), // application units - Em(Float), - Ex(Float), + Em(CSSFloat), + Ex(CSSFloat), // XXX uncomment when supported: -// Ch(Float), -// Rem(Float), -// Vw(Float), -// Vh(Float), -// Vmin(Float), -// Vmax(Float), +// Ch(CSSFloat), +// Rem(CSSFloat), +// Vw(CSSFloat), +// Vh(CSSFloat), +// Vmin(CSSFloat), +// Vmax(CSSFloat), } - static AU_PER_PX: Float = 60.; - static AU_PER_IN: Float = AU_PER_PX * 96.; - static AU_PER_CM: Float = AU_PER_IN / 2.54; - static AU_PER_MM: Float = AU_PER_IN / 25.4; - static AU_PER_PT: Float = AU_PER_IN / 72.; - static AU_PER_PC: Float = AU_PER_PT * 12.; + static AU_PER_PX: CSSFloat = 60.; + static AU_PER_IN: CSSFloat = AU_PER_PX * 96.; + static AU_PER_CM: CSSFloat = AU_PER_IN / 2.54; + static AU_PER_MM: CSSFloat = AU_PER_IN / 25.4; + static AU_PER_PT: CSSFloat = AU_PER_IN / 72.; + static AU_PER_PC: CSSFloat = AU_PER_PT * 12.; impl Length { #[inline] fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Option<Length> { @@ -48,7 +48,7 @@ pub mod specified { pub fn parse_non_negative(input: &ComponentValue) -> Option<Length> { Length::parse_internal(input, /* negative_ok = */ false) } - pub fn parse_dimension(value: Float, unit: &str) -> Option<Length> { + pub fn parse_dimension(value: CSSFloat, unit: &str) -> Option<Length> { match unit.to_ascii_lower().as_slice() { "px" => Some(Length::from_px(value)), "in" => Some(Au_(Au((value * AU_PER_IN) as i32))), @@ -62,7 +62,7 @@ pub mod specified { } } #[inline] - pub fn from_px(px_value: Float) -> Length { + pub fn from_px(px_value: CSSFloat) -> Length { Au_(Au((px_value * AU_PER_PX) as i32)) } } @@ -70,7 +70,7 @@ pub mod specified { #[deriving(Clone)] pub enum LengthOrPercentage { LP_Length(Length), - LP_Percentage(Float), // [0 .. 100%] maps to [0.0 .. 1.0] + LP_Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] } impl LengthOrPercentage { fn parse_internal(input: &ComponentValue, negative_ok: bool) @@ -97,7 +97,7 @@ pub mod specified { #[deriving(Clone)] pub enum LengthOrPercentageOrAuto { LPA_Length(Length), - LPA_Percentage(Float), // [0 .. 100%] maps to [0.0 .. 1.0] + LPA_Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0] LPA_Auto, } impl LengthOrPercentageOrAuto { @@ -135,7 +135,7 @@ pub mod computed { pub struct Context { current_color: cssparser::RGBA, font_size: Au, - font_weight: longhands::font_weight::ComputedValue, + font_weight: longhands::font_weight::computed_value::T, position: longhands::position::SpecifiedValue, float: longhands::float::SpecifiedValue, is_root_element: bool, @@ -147,7 +147,7 @@ pub mod computed { } #[inline] - fn mul(a: Au, b: Float) -> Au { Au(((*a as Float) * b) as i32) } + fn mul(a: Au, b: CSSFloat) -> Au { Au(((*a as CSSFloat) * b) as i32) } pub fn compute_Au(value: specified::Length, context: &Context) -> Au { match value { @@ -160,10 +160,10 @@ pub mod computed { } } - #[deriving(Clone)] + #[deriving(Eq, Clone)] pub enum LengthOrPercentage { LP_Length(Au), - LP_Percentage(Float), + LP_Percentage(CSSFloat), } pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context) -> LengthOrPercentage { @@ -173,10 +173,10 @@ pub mod computed { } } - #[deriving(Clone)] + #[deriving(Eq, Clone)] pub enum LengthOrPercentageOrAuto { LPA_Length(Au), - LPA_Percentage(Float), + LPA_Percentage(CSSFloat), LPA_Auto, } pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto, diff --git a/src/components/style/properties.rs.mako b/src/components/style/properties.rs.mako index b8ea608b212..7e5425f78ed 100644 --- a/src/components/style/properties.rs.mako +++ b/src/components/style/properties.rs.mako @@ -5,7 +5,6 @@ // This file is a Mako template: http://www.makotemplates.org/ use std::ascii::StrAsciiExt; -use std::at_vec; pub use std::iterator; pub use cssparser::*; pub use errors::{ErrorLoggerIterator, log_css_error}; @@ -68,6 +67,7 @@ pub mod longhands { % if not no_super: use super::*; % endif + pub use self::computed_value::*; ${caller.body()} pub fn parse_declared(input: &[ComponentValue]) -> Option<DeclaredValue<SpecifiedValue>> { @@ -104,14 +104,16 @@ pub mod longhands { <%self:single_component_value name="${name}" inherited="${inherited}"> // The computed value is the same as the specified value. pub use to_computed_value = super::computed_as_specified; - #[deriving(Clone)] - pub enum SpecifiedValue { - % for value in values.split(): - ${to_rust_ident(value)}, - % endfor + pub mod computed_value { + #[deriving(Eq, Clone)] + pub enum T { + % for value in values.split(): + ${to_rust_ident(value)}, + % endfor + } } - pub type ComputedValue = SpecifiedValue; - #[inline] pub fn get_initial_value() -> ComputedValue { + pub type SpecifiedValue = computed_value::T; + #[inline] pub fn get_initial_value() -> computed_value::T { ${to_rust_ident(values.split()[0])} } pub fn from_component_value(v: &ComponentValue) -> Option<SpecifiedValue> { @@ -131,8 +133,10 @@ pub mod longhands { <%self:single_component_value name="${name}" inherited="${inherited}"> pub use to_computed_value = super::super::common_types::computed::compute_${type}; pub type SpecifiedValue = specified::${type}; - pub type ComputedValue = computed::${type}; - #[inline] pub fn get_initial_value() -> ComputedValue { ${initial_value} } + pub mod computed_value { + pub type T = super::super::computed::${type}; + } + #[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} } #[inline] pub fn from_component_value(v: &ComponentValue) -> Option<SpecifiedValue> { specified::${type}::${parse_method}(v) } @@ -163,13 +167,15 @@ pub mod longhands { ${predefined_type("border-%s-color" % side, "CSSColor", "CurrentColor")} % endfor - // dotted dashed double groove ridge insed outset - ${single_keyword("border-top-style", "none solid hidden")} + // double groove ridge insed outset + ${single_keyword("border-top-style", "none solid dotted dashed hidden")} % for side in ["right", "bottom", "left"]: <%self:longhand name="border-${side}-style", no_super="True"> pub use super::border_top_style::*; pub type SpecifiedValue = super::border_top_style::SpecifiedValue; - pub type ComputedValue = super::border_top_style::ComputedValue; + pub mod computed_value { + pub type T = super::super::border_top_style::computed_value::T; + } </%self:longhand> % endfor @@ -187,15 +193,18 @@ pub mod longhands { % for side in ["top", "right", "bottom", "left"]: <%self:longhand name="border-${side}-width"> pub type SpecifiedValue = specified::Length; - pub type ComputedValue = Au; - #[inline] pub fn get_initial_value() -> ComputedValue { + pub mod computed_value { + use super::super::Au; + pub type T = Au; + } + #[inline] pub fn get_initial_value() -> computed_value::T { Au::from_px(3) // medium } pub fn parse(input: &[ComponentValue]) -> Option<SpecifiedValue> { one_component_value(input).chain(parse_border_width) } pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context) - -> ComputedValue { + -> computed_value::T { if context.has_border_${side} { computed::compute_Au(value, context) } else { Au(0) } } @@ -231,7 +240,7 @@ pub mod longhands { pub enum SpecifiedValue { SpecifiedNormal, SpecifiedLength(specified::Length), - SpecifiedNumber(Float), + SpecifiedNumber(CSSFloat), // percentage are the same as em. } /// normal | <number> | <length> | <percentage> @@ -249,15 +258,18 @@ pub mod longhands { _ => None, } } - #[deriving(Clone)] - pub enum ComputedValue { - Normal, - Length(Au), - Number(Float), + pub mod computed_value { + use super::super::{Au, CSSFloat}; + #[deriving(Eq, Clone)] + pub enum T { + Normal, + Length(Au), + Number(CSSFloat), + } } - #[inline] pub fn get_initial_value() -> ComputedValue { Normal } + #[inline] pub fn get_initial_value() -> computed_value::T { Normal } pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context) - -> ComputedValue { + -> computed_value::T { match value { SpecifiedNormal => Normal, SpecifiedLength(value) => Length(computed::compute_Au(value, context)), @@ -290,17 +302,20 @@ pub mod longhands { .map_move(SpecifiedLengthOrPercentage) } } - #[deriving(Clone)] - pub enum ComputedValue { - % for keyword in vertical_align_keywords: - ${to_rust_ident(keyword)}, - % endfor - Length(Au), - Percentage(Float), + pub mod computed_value { + use super::super::{Au, CSSFloat}; + #[deriving(Eq, Clone)] + pub enum T { + % for keyword in vertical_align_keywords: + ${to_rust_ident(keyword)}, + % endfor + Length(Au), + Percentage(CSSFloat), + } } - #[inline] pub fn get_initial_value() -> ComputedValue { baseline } + #[inline] pub fn get_initial_value() -> computed_value::T { baseline } pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context) - -> ComputedValue { + -> computed_value::T { match value { % for keyword in vertical_align_keywords: Specified_${to_rust_ident(keyword)} => ${to_rust_ident(keyword)}, @@ -334,8 +349,10 @@ pub mod longhands { <%self:raw_longhand name="color" inherited="True"> pub use to_computed_value = super::computed_as_specified; pub type SpecifiedValue = RGBA; - pub type ComputedValue = SpecifiedValue; - #[inline] pub fn get_initial_value() -> ComputedValue { + pub mod computed_value { + pub type T = super::SpecifiedValue; + } + #[inline] pub fn get_initial_value() -> computed_value::T { RGBA { red: 0., green: 0., blue: 0., alpha: 1. } /* black */ } pub fn parse_specified(input: &[ComponentValue]) -> Option<DeclaredValue<SpecifiedValue>> { @@ -353,7 +370,7 @@ pub mod longhands { <%self:longhand name="font-family" inherited="True"> pub use to_computed_value = super::computed_as_specified; - #[deriving(Clone)] + #[deriving(Eq, Clone)] enum FontFamily { FamilyName(~str), // Generic @@ -364,8 +381,10 @@ pub mod longhands { // Monospace, } pub type SpecifiedValue = ~[FontFamily]; - pub type ComputedValue = SpecifiedValue; - #[inline] pub fn get_initial_value() -> ComputedValue { ~[FamilyName(~"serif")] } + pub mod computed_value { + pub type T = super::SpecifiedValue; + } + #[inline] pub fn get_initial_value() -> computed_value::T { ~[FamilyName(~"serif")] } /// <familiy-name># /// <familiy-name> = <string> | [ <ident>+ ] /// TODO: <generic-familiy> @@ -462,15 +481,17 @@ pub mod longhands { _ => None } } - #[deriving(Clone)] - pub enum ComputedValue { - % for weight in range(100, 901, 100): - Weight${weight}, - % endfor + pub mod computed_value { + #[deriving(Eq, Clone)] + pub enum T { + % for weight in range(100, 901, 100): + Weight${weight}, + % endfor + } } - #[inline] pub fn get_initial_value() -> ComputedValue { Weight400 } // normal + #[inline] pub fn get_initial_value() -> computed_value::T { Weight400 } // normal pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context) - -> ComputedValue { + -> computed_value::T { match value { % for weight in range(100, 901, 100): SpecifiedWeight${weight} => Weight${weight}, @@ -504,8 +525,11 @@ pub mod longhands { <%self:single_component_value name="font-size" inherited="True"> pub use to_computed_value = super::super::common_types::computed::compute_Au; pub type SpecifiedValue = specified::Length; // Percentages are the same as em. - pub type ComputedValue = Au; - #[inline] pub fn get_initial_value() -> ComputedValue { + pub mod computed_value { + use super::super::Au; + pub type T = Au; + } + #[inline] pub fn get_initial_value() -> computed_value::T { Au::from_px(16) // medium } /// <length> | <percentage> @@ -529,7 +553,7 @@ pub mod longhands { <%self:longhand name="text-decoration"> pub use to_computed_value = super::computed_as_specified; - #[deriving(Clone)] + #[deriving(Eq, Clone)] pub struct SpecifiedValue { underline: bool, overline: bool, @@ -537,8 +561,10 @@ pub mod longhands { // 'blink' is accepted in the parser but ignored. // Just not blinking the text is a conforming implementation per CSS 2.1. } - pub type ComputedValue = SpecifiedValue; - #[inline] pub fn get_initial_value() -> ComputedValue { + pub mod computed_value { + pub type T = super::SpecifiedValue; + } + #[inline] pub fn get_initial_value() -> computed_value::T { SpecifiedValue { underline: false, overline: false, line_through: false } // none } /// none | [ underline || overline || line-through || blink ] @@ -783,15 +809,20 @@ pub mod shorthands { pub struct PropertyDeclarationBlock { - important: @[PropertyDeclaration], - normal: @[PropertyDeclaration], + important: ~[PropertyDeclaration], + normal: ~[PropertyDeclaration], } -pub fn parse_property_declaration_list(input: ~[Node]) -> PropertyDeclarationBlock { +pub fn parse_style_attribute(input: &str) -> PropertyDeclarationBlock { + parse_property_declaration_list(tokenize(input)) +} + + +pub fn parse_property_declaration_list<I: Iterator<Node>>(input: I) -> PropertyDeclarationBlock { let mut important = ~[]; let mut normal = ~[]; - for item in ErrorLoggerIterator(parse_declaration_list(input.move_iter())) { + for item in ErrorLoggerIterator(parse_declaration_list(input)) { match item { Decl_AtRule(rule) => log_css_error( rule.location, fmt!("Unsupported at-rule in declaration list: @%s", rule.name)), @@ -805,9 +836,8 @@ pub fn parse_property_declaration_list(input: ~[Node]) -> PropertyDeclarationBlo } } PropertyDeclarationBlock { - // TODO avoid copying? - important: at_vec::to_managed_move(important), - normal: at_vec::to_managed_move(normal), + important: important, + normal: normal, } } @@ -840,6 +870,7 @@ pub enum DeclaredValue<T> { CSSWideKeyword(CSSWideKeyword), } +#[deriving(Clone)] pub enum PropertyDeclaration { % for property in LONGHANDS: ${property.ident}_declaration(DeclaredValue<longhands::${property.ident}::SpecifiedValue>), @@ -900,20 +931,38 @@ impl PropertyDeclaration { pub mod style_structs { use super::longhands; % for name, longhands in LONGHANDS_PER_STYLE_STRUCT: + #[deriving(Eq, Clone)] pub struct ${name} { % for longhand in longhands: - ${longhand.ident}: longhands::${longhand.ident}::ComputedValue, + ${longhand.ident}: longhands::${longhand.ident}::computed_value::T, % endfor } % endfor } +#[deriving(Eq, Clone)] pub struct ComputedValues { % for name, longhands in LONGHANDS_PER_STYLE_STRUCT: ${name}: style_structs::${name}, % endfor } +impl ComputedValues { + /// Resolves the currentColor keyword. + /// Any color value form computed values (except for the 'color' property itself) + /// should go through this method. + /// + /// Usage example: + /// let top_color = style.resolve_color(style.Border.border_top_color); + #[inline] + pub fn resolve_color(&self, color: computed::CSSColor) -> RGBA { + match color { + RGBA(rgba) => rgba, + CurrentColor => self.Color.color, + } + } +} + #[inline] fn get_initial_values() -> ComputedValues { ComputedValues { @@ -929,7 +978,7 @@ fn get_initial_values() -> ComputedValues { // Most specific/important declarations last -pub fn cascade(applicable_declarations: &[@[PropertyDeclaration]], +pub fn cascade(applicable_declarations: &[~[PropertyDeclaration]], parent_style: Option< &ComputedValues>) -> ComputedValues { let initial_keep_alive; @@ -1017,3 +1066,13 @@ pub fn cascade(applicable_declarations: &[@[PropertyDeclaration]], % endfor } } + + +// Only re-export the types for computed values. +pub mod computed_values { + % for property in LONGHANDS: + pub use ${property.ident} = super::longhands::${property.ident}::computed_value; + % endfor + // Don't use a side-specific name needlessly: + pub use border_style = super::longhands::border_top_style::computed_value; +} diff --git a/src/components/style/selector_matching.rs b/src/components/style/selector_matching.rs index f40cfe5c8e6..490d15c68ac 100644 --- a/src/components/style/selector_matching.rs +++ b/src/components/style/selector_matching.rs @@ -2,11 +2,12 @@ * 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 std::at_vec; use std::ascii::StrAsciiExt; use extra::sort::tim_sort; use selectors::*; -use stylesheets::parse_stylesheet; +use stylesheets::Stylesheet; use media_queries::{Device, Screen}; use properties::{PropertyDeclaration, PropertyDeclarationBlock}; use servo_util::tree::{TreeNodeRefAsElement, TreeNode, ElementLike}; @@ -36,8 +37,7 @@ impl Stylist { } } - pub fn add_stylesheet(&mut self, css_source: &str, origin: StylesheetOrigin) { - let stylesheet = parse_stylesheet(css_source); + pub fn add_stylesheet(&mut self, stylesheet: Stylesheet, origin: StylesheetOrigin) { let rules = match origin { UserAgentOrigin => &mut self.ua_rules, AuthorOrigin => &mut self.author_rules, @@ -51,9 +51,10 @@ impl Stylist { if style_rule.declarations.$priority.len() > 0 { $flag = true; for selector in style_rule.selectors.iter() { + // TODO: avoid copying? rules.$priority.push(Rule { - selector: *selector, - declarations: style_rule.declarations.$priority, + selector: @(*selector).clone(), + declarations:at_vec::to_managed(style_rule.declarations.$priority), }) } } @@ -100,10 +101,12 @@ impl Stylist { // Style attributes have author origin but higher specificity than style rules. append!(self.author_rules.normal); - style_attribute.map(|sa| applicable_declarations.push(sa.normal)); + // TODO: avoid copying? + style_attribute.map(|sa| applicable_declarations.push(at_vec::to_managed(sa.normal))); append!(self.author_rules.important); - style_attribute.map(|sa| applicable_declarations.push(sa.important)); + // TODO: avoid copying? + style_attribute.map(|sa| applicable_declarations.push(at_vec::to_managed(sa.important))); append!(self.user_rules.important); append!(self.ua_rules.important); diff --git a/src/components/style/selectors.rs b/src/components/style/selectors.rs index e5d5666c40c..4a2ed8caed3 100644 --- a/src/components/style/selectors.rs +++ b/src/components/style/selectors.rs @@ -8,6 +8,7 @@ use cssparser::*; use namespaces::NamespaceMap; +#[deriving(Clone)] pub struct Selector { compound_selectors: CompoundSelector, pseudo_element: Option<PseudoElement>, @@ -17,7 +18,7 @@ pub struct Selector { pub static STYLE_ATTRIBUTE_SPECIFICITY: u32 = 1 << 31; -#[deriving(Eq)] +#[deriving(Eq, Clone)] pub enum PseudoElement { Before, After, @@ -26,11 +27,13 @@ pub enum PseudoElement { } +#[deriving(Clone)] pub struct CompoundSelector { simple_selectors: ~[SimpleSelector], next: Option<(~CompoundSelector, Combinator)>, // c.next is left of c } +#[deriving(Eq, Clone)] pub enum Combinator { Child, // > Descendant, // space @@ -38,6 +41,7 @@ pub enum Combinator { LaterSibling, // ~ } +#[deriving(Clone)] pub enum SimpleSelector { IDSelector(~str), ClassSelector(~str), @@ -62,6 +66,7 @@ pub enum SimpleSelector { // ... } +#[deriving(Clone)] pub struct AttrSelector { name: ~str, namespace: Option<~str>, @@ -73,7 +78,7 @@ type Iter = iterator::Peekable<ComponentValue, vec::MoveIterator<ComponentValue> // None means invalid selector pub fn parse_selector_list(input: ~[ComponentValue], namespaces: &NamespaceMap) - -> Option<~[@Selector]> { + -> Option<~[Selector]> { let iter = &mut input.move_iter().peekable(); let first = match parse_selector(iter, namespaces) { None => return None, @@ -99,7 +104,7 @@ pub fn parse_selector_list(input: ~[ComponentValue], namespaces: &NamespaceMap) // None means invalid selector fn parse_selector(iter: &mut Iter, namespaces: &NamespaceMap) - -> Option<@Selector> { + -> Option<Selector> { let (first, pseudo_element) = match parse_simple_selectors(iter, namespaces) { None => return None, Some(result) => result @@ -130,7 +135,7 @@ fn parse_selector(iter: &mut Iter, namespaces: &NamespaceMap) } } } - Some(@Selector { + Some(Selector { specificity: compute_specificity(&compound, &pseudo_element), compound_selectors: compound, pseudo_element: pseudo_element, diff --git a/src/components/style/style.rc b/src/components/style/style.rc index 3527f3e9fea..c926e41649d 100644 --- a/src/components/style/style.rc +++ b/src/components/style/style.rc @@ -18,11 +18,10 @@ extern mod servo_util (name = "util"); // The "real" public API -pub use self::selector_matching::{Stylist, StylesheetOrigin}; -pub use self::properties::cascade; -pub use self::properties::{PropertyDeclarationBlock, - parse_property_declaration_list}; // Style attributes - +pub use stylesheets::Stylesheet; +pub use selector_matching::{Stylist, StylesheetOrigin}; +pub use properties::{cascade, ComputedValues, computed_values}; +pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes // Things that need to be public to make the compiler happy pub mod stylesheets; diff --git a/src/components/style/stylesheets.rs b/src/components/style/stylesheets.rs index c0c1394456c..e3c8d5a6ad8 100644 --- a/src/components/style/stylesheets.rs +++ b/src/components/style/stylesheets.rs @@ -2,6 +2,7 @@ * 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 std::str; use std::iterator::Iterator; use std::ascii::StrAsciiExt; use cssparser::*; @@ -26,70 +27,85 @@ pub enum CSSRule { pub struct StyleRule { - selectors: ~[@selectors::Selector], + selectors: ~[selectors::Selector], declarations: properties::PropertyDeclarationBlock, } -pub fn parse_stylesheet(css: &str) -> Stylesheet { - static STATE_CHARSET: uint = 1; - static STATE_IMPORTS: uint = 2; - static STATE_NAMESPACES: uint = 3; - static STATE_BODY: uint = 4; - let mut state: uint = STATE_CHARSET; - - let mut rules = ~[]; - let mut namespaces = NamespaceMap::new(); - - for rule in ErrorLoggerIterator(parse_stylesheet_rules(tokenize(css))) { - let next_state; // Unitialized to force each branch to set it. - match rule { - QualifiedRule(rule) => { - next_state = STATE_BODY; - parse_style_rule(rule, &mut rules, &namespaces) - }, - AtRule(rule) => { - let lower_name = rule.name.to_ascii_lower(); - match lower_name.as_slice() { - "charset" => { - if state > STATE_CHARSET { - log_css_error(rule.location, "@charset must be the first rule") - } - // Valid @charset rules are just ignored - next_state = STATE_IMPORTS; - }, - "import" => { - if state > STATE_IMPORTS { - next_state = state; - log_css_error(rule.location, - "@import must be before any rule but @charset") - } else { +impl Stylesheet { + pub fn from_iter<I: Iterator<~[u8]>>(input: I) -> Stylesheet { + let mut string = ~""; + let mut input = input; + // TODO: incremental tokinization/parsing + for chunk in input { + // Assume UTF-8. This fails on invalid UTF-8 + // TODO: support character encodings (use rust-encodings in rust-cssparser) + string.push_str(str::from_utf8_owned(chunk)) + } + Stylesheet::from_str(string) + } + + pub fn from_str(css: &str) -> Stylesheet { + static STATE_CHARSET: uint = 1; + static STATE_IMPORTS: uint = 2; + static STATE_NAMESPACES: uint = 3; + static STATE_BODY: uint = 4; + let mut state: uint = STATE_CHARSET; + + let mut rules = ~[]; + let mut namespaces = NamespaceMap::new(); + + for rule in ErrorLoggerIterator(parse_stylesheet_rules(tokenize(css))) { + let next_state; // Unitialized to force each branch to set it. + match rule { + QualifiedRule(rule) => { + next_state = STATE_BODY; + parse_style_rule(rule, &mut rules, &namespaces) + }, + AtRule(rule) => { + let lower_name = rule.name.to_ascii_lower(); + match lower_name.as_slice() { + "charset" => { + if state > STATE_CHARSET { + log_css_error(rule.location, "@charset must be the first rule") + } + // Valid @charset rules are just ignored next_state = STATE_IMPORTS; - log_css_error(rule.location, "@import is not supported yet") // TODO - } - }, - "namespace" => { - if state > STATE_NAMESPACES { - next_state = state; - log_css_error( - rule.location, - "@namespace must be before any rule but @charset and @import" - ) - } else { - next_state = STATE_NAMESPACES; - parse_namespace_rule(rule, &mut namespaces) - } - }, - _ => { - next_state = STATE_BODY; - parse_nested_at_rule(lower_name, rule, &mut rules, &namespaces) - }, - } - }, + }, + "import" => { + if state > STATE_IMPORTS { + next_state = state; + log_css_error(rule.location, + "@import must be before any rule but @charset") + } else { + next_state = STATE_IMPORTS; + // TODO: support @import + log_css_error(rule.location, "@import is not supported yet") + } + }, + "namespace" => { + if state > STATE_NAMESPACES { + next_state = state; + log_css_error( + rule.location, + "@namespace must be before any rule but @charset and @import" + ) + } else { + next_state = STATE_NAMESPACES; + parse_namespace_rule(rule, &mut namespaces) + } + }, + _ => { + next_state = STATE_BODY; + parse_nested_at_rule(lower_name, rule, &mut rules, &namespaces) + }, + } + }, + } + state = next_state; } - state = next_state; + Stylesheet{ rules: rules, namespaces: namespaces } } - Stylesheet{ rules: rules, namespaces: namespaces } } @@ -99,7 +115,7 @@ pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut ~[CSSRule], match selectors::parse_selector_list(prelude, namespaces) { Some(selectors) => parent_rules.push(CSSStyleRule(StyleRule{ selectors: selectors, - declarations: properties::parse_property_declaration_list(block) + declarations: properties::parse_property_declaration_list(block.move_iter()) })), None => log_css_error(location, "Unsupported CSS selector."), } @@ -125,7 +141,7 @@ impl Stylesheet { struct StyleRuleIterator<'self> { device: &'self media_queries::Device, - // FIXME: I couldn’t get this to borrow-check with a stack of VecIterator + // FIXME: I couldn't get this to borrow-check with a stack of VecIterator stack: ~[(&'self [CSSRule], uint)], } diff --git a/src/components/style/tests/mod.rs b/src/components/style/tests/mod.rs index 8c2771a9a0a..e9a67a302c1 100644 --- a/src/components/style/tests/mod.rs +++ b/src/components/style/tests/mod.rs @@ -2,11 +2,11 @@ * 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 super::stylesheets::parse_stylesheet; +use super::stylesheets::Stylesheet; #[test] fn test_bootstrap() { // Test that parsing bootstrap does not trigger an assertion or otherwise fail. - let stylesheet = parse_stylesheet(include_str!("bootstrap-v3.0.0.css")); + let stylesheet = Stylesheet::from_str(include_str!("bootstrap-v3.0.0.css")); assert!(stylesheet.rules.len() > 100); // This depends on whet selectors are supported. } |