From 6ddc2c37d15e9d641b2ae96d4189ec7820f48c29 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 17 Oct 2013 22:44:55 +0100 Subject: [PATCH] Add parsing a stylesheet form an iterator, a style attr form a string. --- src/components/style/properties.rs.mako | 9 +- src/components/style/selector_matching.rs | 5 +- src/components/style/style.rc | 6 +- src/components/style/stylesheets.rs | 134 ++++++++++++---------- 4 files changed, 87 insertions(+), 67 deletions(-) diff --git a/src/components/style/properties.rs.mako b/src/components/style/properties.rs.mako index 4d7973f7f65..0cc9b33da1b 100644 --- a/src/components/style/properties.rs.mako +++ b/src/components/style/properties.rs.mako @@ -815,10 +815,15 @@ pub struct PropertyDeclarationBlock { } -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>(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)), diff --git a/src/components/style/selector_matching.rs b/src/components/style/selector_matching.rs index f40cfe5c8e6..10de6d6117f 100644 --- a/src/components/style/selector_matching.rs +++ b/src/components/style/selector_matching.rs @@ -6,7 +6,7 @@ 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 +36,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, diff --git a/src/components/style/style.rc b/src/components/style/style.rc index 553b550bd2b..c926e41649d 100644 --- a/src/components/style/style.rc +++ b/src/components/style/style.rc @@ -18,10 +18,10 @@ extern mod servo_util (name = "util"); // The "real" public API +pub use stylesheets::Stylesheet; pub use selector_matching::{Stylist, StylesheetOrigin}; -pub use properties::{cascade, computed_values}; -pub use properties::{PropertyDeclarationBlock, - parse_property_declaration_list}; // Style attributes +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..c6a210f5ff4 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::*; @@ -31,65 +32,80 @@ pub struct StyleRule { } -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 { - 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) - }, - } - }, +impl Stylesheet { + pub fn from_iter>(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)) } - state = next_state; + 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; + }, + "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; + } + 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)], }