Add parsing a stylesheet form an iterator, a style attr form a string.

This commit is contained in:
Simon Sapin 2013-10-17 22:44:55 +01:00
parent a4c2e9dcf1
commit 6ddc2c37d1
4 changed files with 87 additions and 67 deletions

View file

@ -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<I: Iterator<Node>>(input: I) -> PropertyDeclarationBlock {
let mut important = ~[]; let mut important = ~[];
let mut normal = ~[]; let mut normal = ~[];
for item in ErrorLoggerIterator(parse_declaration_list(input.move_iter())) { for item in ErrorLoggerIterator(parse_declaration_list(input)) {
match item { match item {
Decl_AtRule(rule) => log_css_error( Decl_AtRule(rule) => log_css_error(
rule.location, fmt!("Unsupported at-rule in declaration list: @%s", rule.name)), rule.location, fmt!("Unsupported at-rule in declaration list: @%s", rule.name)),

View file

@ -6,7 +6,7 @@ use std::ascii::StrAsciiExt;
use extra::sort::tim_sort; use extra::sort::tim_sort;
use selectors::*; use selectors::*;
use stylesheets::parse_stylesheet; use stylesheets::Stylesheet;
use media_queries::{Device, Screen}; use media_queries::{Device, Screen};
use properties::{PropertyDeclaration, PropertyDeclarationBlock}; use properties::{PropertyDeclaration, PropertyDeclarationBlock};
use servo_util::tree::{TreeNodeRefAsElement, TreeNode, ElementLike}; use servo_util::tree::{TreeNodeRefAsElement, TreeNode, ElementLike};
@ -36,8 +36,7 @@ impl Stylist {
} }
} }
pub fn add_stylesheet(&mut self, css_source: &str, origin: StylesheetOrigin) { pub fn add_stylesheet(&mut self, stylesheet: Stylesheet, origin: StylesheetOrigin) {
let stylesheet = parse_stylesheet(css_source);
let rules = match origin { let rules = match origin {
UserAgentOrigin => &mut self.ua_rules, UserAgentOrigin => &mut self.ua_rules,
AuthorOrigin => &mut self.author_rules, AuthorOrigin => &mut self.author_rules,

View file

@ -18,10 +18,10 @@ extern mod servo_util (name = "util");
// The "real" public API // The "real" public API
pub use stylesheets::Stylesheet;
pub use selector_matching::{Stylist, StylesheetOrigin}; pub use selector_matching::{Stylist, StylesheetOrigin};
pub use properties::{cascade, computed_values}; pub use properties::{cascade, ComputedValues, computed_values};
pub use properties::{PropertyDeclarationBlock, pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
parse_property_declaration_list}; // Style attributes
// Things that need to be public to make the compiler happy // Things that need to be public to make the compiler happy
pub mod stylesheets; pub mod stylesheets;

View file

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::str;
use std::iterator::Iterator; use std::iterator::Iterator;
use std::ascii::StrAsciiExt; use std::ascii::StrAsciiExt;
use cssparser::*; use cssparser::*;
@ -31,65 +32,80 @@ pub struct StyleRule {
} }
pub fn parse_stylesheet(css: &str) -> Stylesheet { impl Stylesheet {
static STATE_CHARSET: uint = 1; pub fn from_iter<I: Iterator<~[u8]>>(input: I) -> Stylesheet {
static STATE_IMPORTS: uint = 2; let mut string = ~"";
static STATE_NAMESPACES: uint = 3; let mut input = input;
static STATE_BODY: uint = 4; // TODO: incremental tokinization/parsing
let mut state: uint = STATE_CHARSET; for chunk in input {
// Assume UTF-8. This fails on invalid UTF-8
let mut rules = ~[]; // TODO: support character encodings (use rust-encodings in rust-cssparser)
let mut namespaces = NamespaceMap::new(); string.push_str(str::from_utf8_owned(chunk))
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)
},
}
},
} }
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) { match selectors::parse_selector_list(prelude, namespaces) {
Some(selectors) => parent_rules.push(CSSStyleRule(StyleRule{ Some(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
selectors: selectors, 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."), None => log_css_error(location, "Unsupported CSS selector."),
} }
@ -125,7 +141,7 @@ impl Stylesheet {
struct StyleRuleIterator<'self> { struct StyleRuleIterator<'self> {
device: &'self media_queries::Device, device: &'self media_queries::Device,
// FIXME: I couldnt 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)], stack: ~[(&'self [CSSRule], uint)],
} }