mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Upgrade to rust-cssparser master.
* Use associated types * Avoid mutation to gather parsing results.
This commit is contained in:
parent
7359f99f20
commit
966af0030a
11 changed files with 183 additions and 165 deletions
2
components/servo/Cargo.lock
generated
2
components/servo/Cargo.lock
generated
|
@ -134,7 +134,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/servo/rust-cssparser#2a8c9f2c5f568495bae16f44b799be39b8efad39"
|
source = "git+https://github.com/servo/rust-cssparser#f4214c9a7bfafd6f40a62b0726aa0bde900ef0dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -52,13 +52,21 @@ pub struct FontFaceRule {
|
||||||
|
|
||||||
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser)
|
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser)
|
||||||
-> Result<FontFaceRule, ()> {
|
-> Result<FontFaceRule, ()> {
|
||||||
let parser = FontFaceRuleParser {
|
let mut family = None;
|
||||||
context: context,
|
let mut src = None;
|
||||||
family: None,
|
for declaration in DeclarationListParser::new(input, FontFaceRuleParser { context: context }) {
|
||||||
src: None,
|
match declaration {
|
||||||
};
|
Err(()) => {}
|
||||||
match DeclarationListParser::new(input, parser).run() {
|
Ok(FontFaceDescriptorDeclaration::Family(value)) => {
|
||||||
FontFaceRuleParser { family: Some(family), src: Some(src), .. } => {
|
family = Some(value);
|
||||||
|
}
|
||||||
|
Ok(FontFaceDescriptorDeclaration::Src(value)) => {
|
||||||
|
src = Some(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match (family, src) {
|
||||||
|
(Some(family), Some(src)) => {
|
||||||
Ok(FontFaceRule {
|
Ok(FontFaceRule {
|
||||||
family: family,
|
family: family,
|
||||||
sources: src,
|
sources: src,
|
||||||
|
@ -68,30 +76,36 @@ pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum FontFaceDescriptorDeclaration {
|
||||||
|
Family(String),
|
||||||
|
Src(Vec<Source>),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct FontFaceRuleParser<'a, 'b: 'a> {
|
struct FontFaceRuleParser<'a, 'b: 'a> {
|
||||||
context: &'a ParserContext<'b>,
|
context: &'a ParserContext<'b>,
|
||||||
family: Option<String>,
|
|
||||||
src: Option<Vec<Source>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Default methods reject all at rules.
|
/// Default methods reject all at rules.
|
||||||
impl<'a, 'b> AtRuleParser<(), ()> for FontFaceRuleParser<'a, 'b> {}
|
impl<'a, 'b> AtRuleParser for FontFaceRuleParser<'a, 'b> {
|
||||||
|
type Prelude = ();
|
||||||
|
type AtRule = FontFaceDescriptorDeclaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<'a, 'b> DeclarationParser<()> for FontFaceRuleParser<'a, 'b> {
|
impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> {
|
||||||
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
|
type Declaration = FontFaceDescriptorDeclaration;
|
||||||
|
|
||||||
|
fn parse_value(&self, name: &str, input: &mut Parser) -> Result<FontFaceDescriptorDeclaration, ()> {
|
||||||
match_ignore_ascii_case! { name,
|
match_ignore_ascii_case! { name,
|
||||||
"font-family" => {
|
"font-family" => {
|
||||||
self.family = Some(try!(parse_one_non_generic_family_name(input)));
|
Ok(FontFaceDescriptorDeclaration::Family(try!(parse_one_non_generic_family_name(input))))
|
||||||
Ok(())
|
|
||||||
},
|
},
|
||||||
"src" => {
|
"src" => {
|
||||||
self.src = Some(try!(input.parse_comma_separated(|input| {
|
Ok(FontFaceDescriptorDeclaration::Src(try!(input.parse_comma_separated(|input| {
|
||||||
parse_one_src(self.context, input)
|
parse_one_src(self.context, input)
|
||||||
})));
|
}))))
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,6 @@ pub mod selectors;
|
||||||
pub mod selector_matching;
|
pub mod selector_matching;
|
||||||
#[macro_use] pub mod values;
|
#[macro_use] pub mod values;
|
||||||
pub mod properties;
|
pub mod properties;
|
||||||
pub mod namespaces;
|
|
||||||
pub mod node;
|
pub mod node;
|
||||||
pub mod media_queries;
|
pub mod media_queries;
|
||||||
pub mod font_face;
|
pub mod font_face;
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
/* 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;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use string_cache::{Atom, Namespace};
|
|
||||||
use parser::ParserContext;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct NamespaceMap {
|
|
||||||
pub default: Option<Namespace>,
|
|
||||||
pub prefix_map: HashMap<String, Namespace>,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl NamespaceMap {
|
|
||||||
pub fn new() -> NamespaceMap {
|
|
||||||
NamespaceMap { default: None, prefix_map: HashMap::new() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_namespace_rule(context: &mut ParserContext, input: &mut Parser)
|
|
||||||
-> Result<(Option<String>, Namespace), ()> {
|
|
||||||
let prefix = input.try(|input| input.expect_ident()).ok().map(|p| p.into_owned());
|
|
||||||
let url = try!(input.expect_url_or_string());
|
|
||||||
try!(input.expect_exhausted());
|
|
||||||
|
|
||||||
let namespace = Namespace(Atom::from_slice(url.as_slice()));
|
|
||||||
let is_duplicate = match prefix {
|
|
||||||
Some(ref prefix) => {
|
|
||||||
context.namespaces.prefix_map.insert(prefix.clone(), namespace.clone()).is_some()
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let has_default = context.namespaces.default.is_some();
|
|
||||||
if !has_default {
|
|
||||||
context.namespaces.default = Some(namespace.clone());
|
|
||||||
}
|
|
||||||
has_default
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if is_duplicate {
|
|
||||||
Err(()) // "Duplicate @namespace rule"
|
|
||||||
} else {
|
|
||||||
Ok((prefix, namespace))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,12 +3,19 @@
|
||||||
* 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::collections::HashMap;
|
||||||
|
use string_cache::Namespace;
|
||||||
use cssparser::{Parser, SourcePosition};
|
use cssparser::{Parser, SourcePosition};
|
||||||
use url::{Url, UrlParser};
|
use url::{Url, UrlParser};
|
||||||
use log;
|
use log;
|
||||||
|
|
||||||
use stylesheets::Origin;
|
use stylesheets::Origin;
|
||||||
use namespaces::NamespaceMap;
|
|
||||||
|
|
||||||
|
pub struct NamespaceMap {
|
||||||
|
pub default: Option<Namespace>,
|
||||||
|
pub prefix_map: HashMap<String, Namespace>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct ParserContext<'a> {
|
pub struct ParserContext<'a> {
|
||||||
|
@ -17,6 +24,19 @@ pub struct ParserContext<'a> {
|
||||||
pub namespaces: NamespaceMap,
|
pub namespaces: NamespaceMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> ParserContext<'a> {
|
||||||
|
pub fn new(stylesheet_origin: Origin, base_url: &'a Url) -> ParserContext<'a> {
|
||||||
|
ParserContext {
|
||||||
|
stylesheet_origin: stylesheet_origin,
|
||||||
|
base_url: base_url,
|
||||||
|
namespaces: NamespaceMap {
|
||||||
|
default: None,
|
||||||
|
prefix_map: HashMap::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<'a> ParserContext<'a> {
|
impl<'a> ParserContext<'a> {
|
||||||
pub fn in_user_agent_stylesheet(&self) -> bool {
|
pub fn in_user_agent_stylesheet(&self) -> bool {
|
||||||
|
|
|
@ -21,7 +21,6 @@ use values::specified::BorderStyle;
|
||||||
use values::computed;
|
use values::computed;
|
||||||
use selector_matching::DeclarationBlock;
|
use selector_matching::DeclarationBlock;
|
||||||
use parser::ParserContext;
|
use parser::ParserContext;
|
||||||
use namespaces::NamespaceMap;
|
|
||||||
use stylesheets::Origin;
|
use stylesheets::Origin;
|
||||||
|
|
||||||
use self::property_bit_field::PropertyBitField;
|
use self::property_bit_field::PropertyBitField;
|
||||||
|
@ -2325,57 +2324,57 @@ pub struct PropertyDeclarationBlock {
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_style_attribute(input: &str, base_url: &Url) -> PropertyDeclarationBlock {
|
pub fn parse_style_attribute(input: &str, base_url: &Url) -> PropertyDeclarationBlock {
|
||||||
let context = ParserContext {
|
let context = ParserContext::new(Origin::Author, base_url);
|
||||||
stylesheet_origin: Origin::Author,
|
|
||||||
base_url: base_url,
|
|
||||||
namespaces: NamespaceMap::new(),
|
|
||||||
};
|
|
||||||
parse_property_declaration_list(&context, &mut Parser::new(input))
|
parse_property_declaration_list(&context, &mut Parser::new(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct PropertyDeclarationParser<'a, 'b: 'a> {
|
struct PropertyDeclarationParser<'a, 'b: 'a> {
|
||||||
context: &'a ParserContext<'b>,
|
context: &'a ParserContext<'b>,
|
||||||
important_declarations: Vec<PropertyDeclaration>,
|
|
||||||
normal_declarations: Vec<PropertyDeclaration>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Default methods reject all at rules.
|
/// Default methods reject all at rules.
|
||||||
impl<'a, 'b> AtRuleParser<(), ()> for PropertyDeclarationParser<'a, 'b> {}
|
impl<'a, 'b> AtRuleParser for PropertyDeclarationParser<'a, 'b> {
|
||||||
|
type Prelude = ();
|
||||||
|
type AtRule = (Vec<PropertyDeclaration>, bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<'a, 'b> DeclarationParser<()> for PropertyDeclarationParser<'a, 'b> {
|
impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
|
||||||
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
|
type Declaration = (Vec<PropertyDeclaration>, bool);
|
||||||
|
|
||||||
|
fn parse_value(&self, name: &str, input: &mut Parser) -> Result<(Vec<PropertyDeclaration>, bool), ()> {
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
let important = try!(input.parse_entirely(|input| {
|
match PropertyDeclaration::parse(name, self.context, input, &mut results) {
|
||||||
match PropertyDeclaration::parse(name, self.context, input, &mut results) {
|
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {}
|
||||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {}
|
_ => return Err(())
|
||||||
_ => return Err(())
|
|
||||||
}
|
|
||||||
Ok(input.try(parse_important).is_ok())
|
|
||||||
}));
|
|
||||||
if important {
|
|
||||||
self.important_declarations.push_all(results.as_slice());
|
|
||||||
} else {
|
|
||||||
self.normal_declarations.push_all(results.as_slice());
|
|
||||||
}
|
}
|
||||||
Ok(())
|
let important = input.try(parse_important).is_ok();
|
||||||
|
Ok((results, important))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Parser)
|
pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Parser)
|
||||||
-> PropertyDeclarationBlock {
|
-> PropertyDeclarationBlock {
|
||||||
|
let mut important_declarations = Vec::new();
|
||||||
|
let mut normal_declarations = Vec::new();
|
||||||
let parser = PropertyDeclarationParser {
|
let parser = PropertyDeclarationParser {
|
||||||
context: context,
|
context: context,
|
||||||
important_declarations: vec![],
|
|
||||||
normal_declarations: vec![],
|
|
||||||
};
|
};
|
||||||
let parser = DeclarationListParser::new(input, parser).run();
|
for declaration in DeclarationListParser::new(input, parser) {
|
||||||
|
if let Ok((results, important)) = declaration {
|
||||||
|
if important {
|
||||||
|
important_declarations.push_all(results.as_slice());
|
||||||
|
} else {
|
||||||
|
normal_declarations.push_all(results.as_slice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
PropertyDeclarationBlock {
|
PropertyDeclarationBlock {
|
||||||
important: Arc::new(deduplicate_property_declarations(parser.important_declarations)),
|
important: Arc::new(deduplicate_property_declarations(important_declarations)),
|
||||||
normal: Arc::new(deduplicate_property_declarations(parser.normal_declarations)),
|
normal: Arc::new(deduplicate_property_declarations(normal_declarations)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1166,16 +1166,12 @@ mod tests {
|
||||||
/// Helper method to get some Rules from selector strings.
|
/// Helper method to get some Rules from selector strings.
|
||||||
/// Each sublist of the result contains the Rules for one StyleRule.
|
/// Each sublist of the result contains the Rules for one StyleRule.
|
||||||
fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> {
|
fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> {
|
||||||
use namespaces::NamespaceMap;
|
|
||||||
use selectors::parse_selector_list;
|
use selectors::parse_selector_list;
|
||||||
use stylesheets::Origin;
|
use stylesheets::Origin;
|
||||||
|
|
||||||
css_selectors.iter().enumerate().map(|(i, selectors)| {
|
css_selectors.iter().enumerate().map(|(i, selectors)| {
|
||||||
let context = ParserContext {
|
let url = Url::parse("about:blank").unwrap();
|
||||||
stylesheet_origin: Origin::Author,
|
let context = ParserContext::new(Origin::Author, &url);
|
||||||
namespaces: NamespaceMap::new(),
|
|
||||||
base_url: &Url::parse("about:blank").unwrap(),
|
|
||||||
};
|
|
||||||
parse_selector_list(&context, &mut Parser::new(*selectors))
|
parse_selector_list(&context, &mut Parser::new(*selectors))
|
||||||
.unwrap().into_iter().map(|s| {
|
.unwrap().into_iter().map(|s| {
|
||||||
Rule {
|
Rule {
|
||||||
|
|
|
@ -12,7 +12,6 @@ use string_cache::{Atom, Namespace};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use parser::ParserContext;
|
use parser::ParserContext;
|
||||||
use namespaces::NamespaceMap;
|
|
||||||
use stylesheets::Origin;
|
use stylesheets::Origin;
|
||||||
|
|
||||||
|
|
||||||
|
@ -196,11 +195,8 @@ fn compute_specificity(mut selector: &CompoundSelector,
|
||||||
|
|
||||||
pub fn parse_author_origin_selector_list_from_str(input: &str)
|
pub fn parse_author_origin_selector_list_from_str(input: &str)
|
||||||
-> Result<SelectorList,()> {
|
-> Result<SelectorList,()> {
|
||||||
let context = ParserContext {
|
let url = Url::parse("about:blank").unwrap();
|
||||||
stylesheet_origin: Origin::Author,
|
let context = ParserContext::new(Origin::Author, &url);
|
||||||
namespaces: NamespaceMap::new(),
|
|
||||||
base_url: &Url::parse("about:blank").unwrap(),
|
|
||||||
};
|
|
||||||
parse_selector_list(&context, &mut Parser::new(input))
|
parse_selector_list(&context, &mut Parser::new(input))
|
||||||
.map(|s| SelectorList { selectors: s })
|
.map(|s| SelectorList { selectors: s })
|
||||||
}
|
}
|
||||||
|
@ -647,7 +643,6 @@ fn parse_pseudo_element(name: &str) -> Result<PseudoElement, ()> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use namespaces::NamespaceMap;
|
|
||||||
use stylesheets::Origin;
|
use stylesheets::Origin;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
use parser::ParserContext;
|
use parser::ParserContext;
|
||||||
|
@ -655,16 +650,11 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn parse(input: &str) -> Result<Vec<Selector>, ()> {
|
fn parse(input: &str) -> Result<Vec<Selector>, ()> {
|
||||||
parse_ns(input, NamespaceMap::new())
|
parse_ns(input, &ParserContext::new(Origin::Author, &Url::parse("about:blank").unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ns(input: &str, namespaces: NamespaceMap) -> Result<Vec<Selector>, ()> {
|
fn parse_ns(input: &str, context: &ParserContext) -> Result<Vec<Selector>, ()> {
|
||||||
let context = ParserContext {
|
parse_selector_list(context, &mut Parser::new(input))
|
||||||
stylesheet_origin: Origin::Author,
|
|
||||||
namespaces: namespaces,
|
|
||||||
base_url: &Url::parse("about:blank").unwrap(),
|
|
||||||
};
|
|
||||||
parse_selector_list(&context, &mut Parser::new(input))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn specificity(a: u32, b: u32, c: u32) -> u32 {
|
fn specificity(a: u32, b: u32, c: u32) -> u32 {
|
||||||
|
@ -728,8 +718,9 @@ mod tests {
|
||||||
})));
|
})));
|
||||||
// Default namespace does not apply to attribute selectors
|
// Default namespace does not apply to attribute selectors
|
||||||
// https://github.com/mozilla/servo/pull/1652
|
// https://github.com/mozilla/servo/pull/1652
|
||||||
let mut namespaces = NamespaceMap::new();
|
let url = Url::parse("about:blank").unwrap();
|
||||||
assert_eq!(parse_ns("[Foo]", namespaces.clone()), Ok(vec!(Selector {
|
let mut context = ParserContext::new(Origin::Author, &url);
|
||||||
|
assert_eq!(parse_ns("[Foo]", &context), Ok(vec!(Selector {
|
||||||
compound_selectors: Arc::new(CompoundSelector {
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
simple_selectors: vec!(SimpleSelector::AttrExists(AttrSelector {
|
simple_selectors: vec!(SimpleSelector::AttrExists(AttrSelector {
|
||||||
name: Atom::from_slice("Foo"),
|
name: Atom::from_slice("Foo"),
|
||||||
|
@ -743,8 +734,8 @@ mod tests {
|
||||||
})));
|
})));
|
||||||
// Default namespace does not apply to attribute selectors
|
// Default namespace does not apply to attribute selectors
|
||||||
// https://github.com/mozilla/servo/pull/1652
|
// https://github.com/mozilla/servo/pull/1652
|
||||||
namespaces.default = Some(ns!(MathML));
|
context.namespaces.default = Some(ns!(MathML));
|
||||||
assert_eq!(parse_ns("[Foo]", namespaces.clone()), Ok(vec!(Selector {
|
assert_eq!(parse_ns("[Foo]", &context), Ok(vec!(Selector {
|
||||||
compound_selectors: Arc::new(CompoundSelector {
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
simple_selectors: vec!(SimpleSelector::AttrExists(AttrSelector {
|
simple_selectors: vec!(SimpleSelector::AttrExists(AttrSelector {
|
||||||
name: Atom::from_slice("Foo"),
|
name: Atom::from_slice("Foo"),
|
||||||
|
@ -757,7 +748,7 @@ mod tests {
|
||||||
specificity: specificity(0, 1, 0),
|
specificity: specificity(0, 1, 0),
|
||||||
})));
|
})));
|
||||||
// Default namespace does apply to type selectors
|
// Default namespace does apply to type selectors
|
||||||
assert_eq!(parse_ns("e", namespaces), Ok(vec!(Selector {
|
assert_eq!(parse_ns("e", &context), Ok(vec!(Selector {
|
||||||
compound_selectors: Arc::new(CompoundSelector {
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
simple_selectors: vec!(
|
simple_selectors: vec!(
|
||||||
SimpleSelector::Namespace(ns!(MathML)),
|
SimpleSelector::Namespace(ns!(MathML)),
|
||||||
|
|
|
@ -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::cell::Cell;
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -10,11 +11,10 @@ use encoding::EncodingRef;
|
||||||
|
|
||||||
use cssparser::{Parser, decode_stylesheet_bytes,
|
use cssparser::{Parser, decode_stylesheet_bytes,
|
||||||
QualifiedRuleParser, AtRuleParser, RuleListParser, AtRuleType};
|
QualifiedRuleParser, AtRuleParser, RuleListParser, AtRuleType};
|
||||||
use string_cache::Namespace;
|
use string_cache::{Atom, Namespace};
|
||||||
use selectors::{Selector, parse_selector_list};
|
use selectors::{Selector, parse_selector_list};
|
||||||
use parser::ParserContext;
|
use parser::ParserContext;
|
||||||
use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
|
use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
|
||||||
use namespaces::{NamespaceMap, parse_namespace_rule};
|
|
||||||
use media_queries::{self, Device, MediaQueryList, parse_media_query_list};
|
use media_queries::{self, Device, MediaQueryList, parse_media_query_list};
|
||||||
use font_face::{FontFaceRule, Source, parse_font_face_block, iter_font_face_rules_inner};
|
use font_face::{FontFaceRule, Source, parse_font_face_block, iter_font_face_rules_inner};
|
||||||
|
|
||||||
|
@ -85,18 +85,26 @@ impl Stylesheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_str<'i>(css: &'i str, base_url: Url, origin: Origin) -> Stylesheet {
|
pub fn from_str<'i>(css: &'i str, base_url: Url, origin: Origin) -> Stylesheet {
|
||||||
let mut context = ParserContext {
|
let rule_parser = TopLevelRuleParser {
|
||||||
stylesheet_origin: origin,
|
context: ParserContext::new(origin, &base_url),
|
||||||
base_url: &base_url,
|
state: Cell::new(State::Start),
|
||||||
namespaces: NamespaceMap::new()
|
|
||||||
};
|
};
|
||||||
let rule_parser = MainRuleParser {
|
let mut input = Parser::new(css);
|
||||||
context: &mut context,
|
let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser);
|
||||||
state: State::Start,
|
let mut rules = Vec::new();
|
||||||
};
|
while let Some(result) = iter.next() {
|
||||||
let rules = RuleListParser::new_for_stylesheet(&mut Parser::new(css), rule_parser)
|
if let Ok(rule) = result {
|
||||||
.filter_map(|result| result.ok())
|
if let CSSRule::Namespace(ref prefix, ref namespace) = rule {
|
||||||
.collect();
|
if let Some(prefix) = prefix.as_ref() {
|
||||||
|
iter.parser.context.namespaces.prefix_map.insert(
|
||||||
|
prefix.clone(), namespace.clone());
|
||||||
|
} else {
|
||||||
|
iter.parser.context.namespaces.default = Some(namespace.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rules.push(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
Stylesheet {
|
Stylesheet {
|
||||||
origin: origin,
|
origin: origin,
|
||||||
rules: rules,
|
rules: rules,
|
||||||
|
@ -105,24 +113,19 @@ impl Stylesheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn parse_nested_rules(context: &mut ParserContext, input: &mut Parser) -> Vec<CSSRule> {
|
fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> Vec<CSSRule> {
|
||||||
let parser = MainRuleParser {
|
RuleListParser::new_for_nested_rule(input, NestedRuleParser { context: context })
|
||||||
context: context,
|
|
||||||
state: State::Body,
|
|
||||||
};
|
|
||||||
RuleListParser::new_for_nested_rule(input, parser)
|
|
||||||
.filter_map(|result| result.ok())
|
.filter_map(|result| result.ok())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct MainRuleParser<'a, 'b: 'a> {
|
struct TopLevelRuleParser<'a> {
|
||||||
context: &'a mut ParserContext<'b>,
|
context: ParserContext<'a>,
|
||||||
state: State,
|
state: Cell<State>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy)]
|
||||||
#[derive(Eq, PartialEq, Ord, PartialOrd)]
|
|
||||||
enum State {
|
enum State {
|
||||||
Start = 1,
|
Start = 1,
|
||||||
Imports = 2,
|
Imports = 2,
|
||||||
|
@ -137,14 +140,17 @@ enum AtRulePrelude {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> {
|
impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
|
||||||
fn parse_prelude(&mut self, name: &str, input: &mut Parser)
|
type Prelude = AtRulePrelude;
|
||||||
|
type AtRule = CSSRule;
|
||||||
|
|
||||||
|
fn parse_prelude(&self, name: &str, input: &mut Parser)
|
||||||
-> Result<AtRuleType<AtRulePrelude, CSSRule>, ()> {
|
-> Result<AtRuleType<AtRulePrelude, CSSRule>, ()> {
|
||||||
match_ignore_ascii_case! { name,
|
match_ignore_ascii_case! { name,
|
||||||
"charset" => {
|
"charset" => {
|
||||||
if self.state <= State::Start {
|
if self.state.get() <= State::Start {
|
||||||
// Valid @charset rules are just ignored
|
// Valid @charset rules are just ignored
|
||||||
self.state = State::Imports;
|
self.state.set(State::Imports);
|
||||||
let charset = try!(input.expect_string()).into_owned();
|
let charset = try!(input.expect_string()).into_owned();
|
||||||
return Ok(AtRuleType::WithoutBlock(CSSRule::Charset(charset)))
|
return Ok(AtRuleType::WithoutBlock(CSSRule::Charset(charset)))
|
||||||
} else {
|
} else {
|
||||||
|
@ -152,8 +158,8 @@ impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"import" => {
|
"import" => {
|
||||||
if self.state <= State::Imports {
|
if self.state.get() <= State::Imports {
|
||||||
self.state = State::Imports;
|
self.state.set(State::Imports);
|
||||||
// TODO: support @import
|
// TODO: support @import
|
||||||
return Err(()) // "@import is not supported yet"
|
return Err(()) // "@import is not supported yet"
|
||||||
} else {
|
} else {
|
||||||
|
@ -161,10 +167,12 @@ impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"namespace" => {
|
"namespace" => {
|
||||||
if self.state <= State::Namespaces {
|
if self.state.get() <= State::Namespaces {
|
||||||
self.state = State::Namespaces;
|
self.state.set(State::Namespaces);
|
||||||
let (prefix, namespace) = try!(parse_namespace_rule(self.context, input));
|
|
||||||
return Ok(AtRuleType::WithoutBlock(CSSRule::Namespace(prefix, namespace)))
|
let prefix = input.try(|input| input.expect_ident()).ok().map(|p| p.into_owned());
|
||||||
|
let url = Namespace(Atom::from_slice(try!(input.expect_url_or_string()).as_slice()));
|
||||||
|
return Ok(AtRuleType::WithoutBlock(CSSRule::Namespace(prefix, url)))
|
||||||
} else {
|
} else {
|
||||||
return Err(()) // "@namespace must be before any rule but @charset and @import"
|
return Err(()) // "@namespace must be before any rule but @charset and @import"
|
||||||
}
|
}
|
||||||
|
@ -172,8 +180,46 @@ impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state = State::Body;
|
self.state.set(State::Body);
|
||||||
|
AtRuleParser::parse_prelude(&NestedRuleParser { context: &self.context }, name, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CSSRule, ()> {
|
||||||
|
AtRuleParser::parse_block(&NestedRuleParser { context: &self.context }, prelude, input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> {
|
||||||
|
type Prelude = Vec<Selector>;
|
||||||
|
type QualifiedRule = CSSRule;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn parse_prelude(&self, input: &mut Parser) -> Result<Vec<Selector>, ()> {
|
||||||
|
self.state.set(State::Body);
|
||||||
|
QualifiedRuleParser::parse_prelude(&NestedRuleParser { context: &self.context }, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn parse_block(&self, prelude: Vec<Selector>, input: &mut Parser) -> Result<CSSRule, ()> {
|
||||||
|
QualifiedRuleParser::parse_block(&NestedRuleParser { context: &self.context },
|
||||||
|
prelude, input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct NestedRuleParser<'a, 'b: 'a> {
|
||||||
|
context: &'a ParserContext<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
|
||||||
|
type Prelude = AtRulePrelude;
|
||||||
|
type AtRule = CSSRule;
|
||||||
|
|
||||||
|
fn parse_prelude(&self, name: &str, input: &mut Parser)
|
||||||
|
-> Result<AtRuleType<AtRulePrelude, CSSRule>, ()> {
|
||||||
match_ignore_ascii_case! { name,
|
match_ignore_ascii_case! { name,
|
||||||
"media" => {
|
"media" => {
|
||||||
let media_queries = parse_media_query_list(input);
|
let media_queries = parse_media_query_list(input);
|
||||||
|
@ -186,7 +232,7 @@ impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CSSRule, ()> {
|
fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CSSRule, ()> {
|
||||||
match prelude {
|
match prelude {
|
||||||
AtRulePrelude::FontFace => {
|
AtRulePrelude::FontFace => {
|
||||||
parse_font_face_block(self.context, input).map(CSSRule::FontFace)
|
parse_font_face_block(self.context, input).map(CSSRule::FontFace)
|
||||||
|
@ -202,13 +248,15 @@ impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<'a, 'b> QualifiedRuleParser<Vec<Selector>, CSSRule> for MainRuleParser<'a, 'b> {
|
impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
|
||||||
fn parse_prelude(&mut self, input: &mut Parser) -> Result<Vec<Selector>, ()> {
|
type Prelude = Vec<Selector>;
|
||||||
self.state = State::Body;
|
type QualifiedRule = CSSRule;
|
||||||
|
|
||||||
|
fn parse_prelude(&self, input: &mut Parser) -> Result<Vec<Selector>, ()> {
|
||||||
parse_selector_list(self.context, input)
|
parse_selector_list(self.context, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block(&mut self, prelude: Vec<Selector>, input: &mut Parser) -> Result<CSSRule, ()> {
|
fn parse_block(&self, prelude: Vec<Selector>, input: &mut Parser) -> Result<CSSRule, ()> {
|
||||||
Ok(CSSRule::Style(StyleRule {
|
Ok(CSSRule::Style(StyleRule {
|
||||||
selectors: prelude,
|
selectors: prelude,
|
||||||
declarations: parse_property_declaration_list(self.context, input)
|
declarations: parse_property_declaration_list(self.context, input)
|
||||||
|
|
2
ports/cef/Cargo.lock
generated
2
ports/cef/Cargo.lock
generated
|
@ -132,7 +132,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/servo/rust-cssparser#2a8c9f2c5f568495bae16f44b799be39b8efad39"
|
source = "git+https://github.com/servo/rust-cssparser#f4214c9a7bfafd6f40a62b0726aa0bde900ef0dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
2
ports/gonk/Cargo.lock
generated
2
ports/gonk/Cargo.lock
generated
|
@ -103,7 +103,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/servo/rust-cssparser#2a8c9f2c5f568495bae16f44b799be39b8efad39"
|
source = "git+https://github.com/servo/rust-cssparser#f4214c9a7bfafd6f40a62b0726aa0bde900ef0dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue