mirror of
https://github.com/servo/servo.git
synced 2025-06-21 23:59:00 +01:00
Port to the new cssparser.
https://github.com/servo/rust-cssparser/pull/68
This commit is contained in:
parent
ad328fda65
commit
d034a6c6bc
20 changed files with 2018 additions and 2388 deletions
|
@ -46,8 +46,8 @@ use servo_util::opts;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::num::FloatMath;
|
use std::num::FloatMath;
|
||||||
use style::computed::{AngleOrCorner, LengthOrPercentage, HorizontalDirection, VerticalDirection};
|
use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection};
|
||||||
use style::computed::{Image, LinearGradient};
|
use style::computed::{Image, LinearGradient, LengthOrPercentage};
|
||||||
use style::computed_values::filter::Filter;
|
use style::computed_values::filter::Filter;
|
||||||
use style::computed_values::{background_attachment, background_repeat, border_style, overflow};
|
use style::computed_values::{background_attachment, background_repeat, border_style, overflow};
|
||||||
use style::computed_values::{position, visibility};
|
use style::computed_values::{position, visibility};
|
||||||
|
@ -222,13 +222,13 @@ fn build_border_radius(abs_bounds: &Rect<Au>, border_style: &Border) -> BorderRa
|
||||||
// radii will be relative to the width.
|
// radii will be relative to the width.
|
||||||
|
|
||||||
BorderRadii {
|
BorderRadii {
|
||||||
top_left: model::specified(border_style.border_top_left_radius.radius,
|
top_left: model::specified(border_style.border_top_left_radius,
|
||||||
abs_bounds.size.width),
|
abs_bounds.size.width),
|
||||||
top_right: model::specified(border_style.border_top_right_radius.radius,
|
top_right: model::specified(border_style.border_top_right_radius,
|
||||||
abs_bounds.size.width),
|
abs_bounds.size.width),
|
||||||
bottom_right: model::specified(border_style.border_bottom_right_radius.radius,
|
bottom_right: model::specified(border_style.border_bottom_right_radius,
|
||||||
abs_bounds.size.width),
|
abs_bounds.size.width),
|
||||||
bottom_left: model::specified(border_style.border_bottom_left_radius.radius,
|
bottom_left: model::specified(border_style.border_bottom_left_radius,
|
||||||
abs_bounds.size.width),
|
abs_bounds.size.width),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,8 @@ use dom::node::{window_from_node};
|
||||||
use dom::nodelist::NodeList;
|
use dom::nodelist::NodeList;
|
||||||
use dom::virtualmethods::{VirtualMethods, vtable_for};
|
use dom::virtualmethods::{VirtualMethods, vtable_for};
|
||||||
use devtools_traits::AttrInfo;
|
use devtools_traits::AttrInfo;
|
||||||
use style::{mod, StylesheetOrigin, SimpleColorAttribute, UnsignedIntegerAttribute};
|
use style::{mod, SimpleColorAttribute, UnsignedIntegerAttribute};
|
||||||
use style::{IntegerAttribute, LengthAttribute, ParserContext, matches};
|
use style::{IntegerAttribute, LengthAttribute, matches};
|
||||||
use servo_util::namespace;
|
use servo_util::namespace;
|
||||||
use servo_util::str::{DOMString, LengthOrPercentageOrAuto};
|
use servo_util::str::{DOMString, LengthOrPercentageOrAuto};
|
||||||
|
|
||||||
|
@ -1112,10 +1112,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
|
||||||
|
|
||||||
// http://dom.spec.whatwg.org/#dom-element-matches
|
// http://dom.spec.whatwg.org/#dom-element-matches
|
||||||
fn Matches(self, selectors: DOMString) -> Fallible<bool> {
|
fn Matches(self, selectors: DOMString) -> Fallible<bool> {
|
||||||
let parser_context = ParserContext {
|
match style::parse_author_origin_selector_list_from_str(selectors.as_slice()) {
|
||||||
origin: StylesheetOrigin::Author,
|
|
||||||
};
|
|
||||||
match style::parse_selector_list_from_str(&parser_context, selectors.as_slice()) {
|
|
||||||
Err(()) => Err(Syntax),
|
Err(()) => Err(Syntax),
|
||||||
Ok(ref selectors) => {
|
Ok(ref selectors) => {
|
||||||
let root: JSRef<Node> = NodeCast::from_ref(self);
|
let root: JSRef<Node> = NodeCast::from_ref(self);
|
||||||
|
@ -1126,10 +1123,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#dom-element-closest
|
// https://dom.spec.whatwg.org/#dom-element-closest
|
||||||
fn Closest(self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> {
|
fn Closest(self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> {
|
||||||
let parser_context = ParserContext {
|
match style::parse_author_origin_selector_list_from_str(selectors.as_slice()) {
|
||||||
origin: StylesheetOrigin::Author,
|
|
||||||
};
|
|
||||||
match style::parse_selector_list_from_str(&parser_context, selectors.as_slice()) {
|
|
||||||
Err(()) => Err(Syntax),
|
Err(()) => Err(Syntax),
|
||||||
Ok(ref selectors) => {
|
Ok(ref selectors) => {
|
||||||
let root: JSRef<Node> = NodeCast::from_ref(self);
|
let root: JSRef<Node> = NodeCast::from_ref(self);
|
||||||
|
|
|
@ -48,7 +48,7 @@ use devtools_traits::NodeInfo;
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::str::{DOMString, null_str_as_empty};
|
use servo_util::str::{DOMString, null_str_as_empty};
|
||||||
use style::{matches, StylesheetOrigin, ParserContext, SelectorList};
|
use style::{matches, SelectorList};
|
||||||
|
|
||||||
use js::jsapi::{JSContext, JSObject, JSTracer, JSRuntime};
|
use js::jsapi::{JSContext, JSObject, JSTracer, JSRuntime};
|
||||||
use js::jsfriendapi;
|
use js::jsfriendapi;
|
||||||
|
@ -742,10 +742,7 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
|
||||||
// http://dom.spec.whatwg.org/#dom-parentnode-queryselector
|
// http://dom.spec.whatwg.org/#dom-parentnode-queryselector
|
||||||
fn query_selector(self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> {
|
fn query_selector(self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
let parser_context = ParserContext {
|
match style::parse_author_origin_selector_list_from_str(selectors.as_slice()) {
|
||||||
origin: StylesheetOrigin::Author,
|
|
||||||
};
|
|
||||||
match style::parse_selector_list_from_str(&parser_context, selectors.as_slice()) {
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
Err(()) => return Err(Syntax),
|
Err(()) => return Err(Syntax),
|
||||||
// Step 3.
|
// Step 3.
|
||||||
|
@ -767,10 +764,7 @@ impl<'a> NodeHelpers<'a> for JSRef<'a, Node> {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
let nodes;
|
let nodes;
|
||||||
let root = self.ancestors().last().unwrap_or(self.clone());
|
let root = self.ancestors().last().unwrap_or(self.clone());
|
||||||
let parser_context = ParserContext {
|
match style::parse_author_origin_selector_list_from_str(selectors.as_slice()) {
|
||||||
origin: StylesheetOrigin::Author,
|
|
||||||
};
|
|
||||||
match style::parse_selector_list_from_str(&parser_context, selectors.as_slice()) {
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
Err(()) => return Err(Syntax),
|
Err(()) => return Err(Syntax),
|
||||||
// Step 3.
|
// Step 3.
|
||||||
|
|
9
components/servo/Cargo.lock
generated
9
components/servo/Cargo.lock
generated
|
@ -123,9 +123,10 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "git+https://github.com/servo/rust-cssparser#110bf3052d016bf6eda0689fb21cf971e2c23dc8"
|
source = "git+https://github.com/servo/rust-cssparser#8d1b3e220e795f7baaa940919059d5f4ef4ec28c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"matches 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"text_writer 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"text_writer 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -488,6 +489,11 @@ dependencies = [
|
||||||
"pnacl-build-helper 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pnacl-build-helper 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matches"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mime"
|
name = "mime"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -678,6 +684,7 @@ dependencies = [
|
||||||
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||||
"lazy_static 0.1.0 (git+https://github.com/Kimundi/lazy-static.rs)",
|
"lazy_static 0.1.0 (git+https://github.com/Kimundi/lazy-static.rs)",
|
||||||
|
"matches 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"plugins 0.0.1",
|
"plugins 0.0.1",
|
||||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache)",
|
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||||
|
|
|
@ -36,3 +36,4 @@ git = "https://github.com/servo/string-cache"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
text_writer = "0.1.1"
|
text_writer = "0.1.1"
|
||||||
encoding = "0.2"
|
encoding = "0.2"
|
||||||
|
matches = "0.1"
|
||||||
|
|
|
@ -1,32 +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::ast::{SyntaxError, SourceLocation};
|
|
||||||
|
|
||||||
|
|
||||||
pub struct ErrorLoggerIterator<I>(pub I);
|
|
||||||
|
|
||||||
impl<T, I: Iterator<Result<T, SyntaxError>>> Iterator<T> for ErrorLoggerIterator<I> {
|
|
||||||
fn next(&mut self) -> Option<T> {
|
|
||||||
let ErrorLoggerIterator(ref mut this) = *self;
|
|
||||||
loop {
|
|
||||||
match this.next() {
|
|
||||||
Some(Ok(v)) => return Some(v),
|
|
||||||
Some(Err(error)) => log_css_error(error.location,
|
|
||||||
format!("{}", error.reason).as_slice()),
|
|
||||||
None => return None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Defaults to a no-op.
|
|
||||||
/// Set a `RUST_LOG=style::errors` environment variable
|
|
||||||
/// to log CSS parse errors to stderr.
|
|
||||||
pub fn log_css_error(location: SourceLocation, message: &str) {
|
|
||||||
// TODO eventually this will got into a "web console" or something.
|
|
||||||
info!("{}:{} {}", location.line, location.column, message)
|
|
||||||
}
|
|
|
@ -2,24 +2,23 @@
|
||||||
* 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 cssparser::ast::*;
|
use cssparser::{Token, Parser, DeclarationListParser, AtRuleParser, DeclarationParser};
|
||||||
use cssparser::ast::ComponentValue::*;
|
|
||||||
use cssparser::parse_declaration_list;
|
|
||||||
use errors::{ErrorLoggerIterator, log_css_error};
|
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use parsing_utils::{BufferedIter, ParserIter, parse_slice_comma_separated};
|
|
||||||
use properties::longhands::font_family::parse_one_family;
|
|
||||||
use properties::computed_values::font_family::FontFamily::FamilyName;
|
|
||||||
use stylesheets::CSSRule;
|
use stylesheets::CSSRule;
|
||||||
|
use properties::longhands::font_family::parse_one_family;
|
||||||
|
use properties::computed_values::font_family::FontFamily;
|
||||||
use media_queries::Device;
|
use media_queries::Device;
|
||||||
use url::{Url, UrlParser};
|
use url::{Url, UrlParser};
|
||||||
|
use parser::ParserContext;
|
||||||
|
|
||||||
|
|
||||||
pub fn iter_font_face_rules_inner(rules: &[CSSRule], device: &Device,
|
pub fn iter_font_face_rules_inner(rules: &[CSSRule], device: &Device,
|
||||||
callback: |family: &str, source: &Source|) {
|
callback: |family: &str, source: &Source|) {
|
||||||
for rule in rules.iter() {
|
for rule in rules.iter() {
|
||||||
match *rule {
|
match *rule {
|
||||||
CSSRule::Style(_) => {},
|
CSSRule::Style(..) |
|
||||||
|
CSSRule::Charset(..) |
|
||||||
|
CSSRule::Namespace(..) => {},
|
||||||
CSSRule::Media(ref rule) => if rule.media_queries.evaluate(device) {
|
CSSRule::Media(ref rule) => if rule.media_queries.evaluate(device) {
|
||||||
iter_font_face_rules_inner(rule.rules.as_slice(), device, |f, s| callback(f, s))
|
iter_font_face_rules_inner(rule.rules.as_slice(), device, |f, s| callback(f, s))
|
||||||
},
|
},
|
||||||
|
@ -32,102 +31,94 @@ pub fn iter_font_face_rules_inner(rules: &[CSSRule], device: &Device,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone, Show, PartialEq, Eq)]
|
||||||
pub enum Source {
|
pub enum Source {
|
||||||
Url(UrlSource),
|
Url(UrlSource),
|
||||||
Local(String),
|
Local(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone, Show, PartialEq, Eq)]
|
||||||
pub struct UrlSource {
|
pub struct UrlSource {
|
||||||
pub url: Url,
|
pub url: Url,
|
||||||
pub format_hints: Vec<String>,
|
pub format_hints: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(Show, PartialEq, Eq)]
|
||||||
pub struct FontFaceRule {
|
pub struct FontFaceRule {
|
||||||
pub family: String,
|
pub family: String,
|
||||||
pub sources: Vec<Source>,
|
pub sources: Vec<Source>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_font_face_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, base_url: &Url) {
|
|
||||||
if rule.prelude.as_slice().skip_whitespace().next().is_some() {
|
|
||||||
log_css_error(rule.location, "@font-face prelude contains unexpected characters");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let block = match rule.block {
|
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser)
|
||||||
Some(block) => block,
|
-> Result<FontFaceRule, ()> {
|
||||||
None => {
|
let parser = FontFaceRuleParser {
|
||||||
log_css_error(rule.location, "Invalid @font-face rule");
|
context: context,
|
||||||
return
|
family: None,
|
||||||
}
|
src: None,
|
||||||
};
|
};
|
||||||
|
match DeclarationListParser::new(input, parser).run() {
|
||||||
let mut maybe_family = None;
|
FontFaceRuleParser { family: Some(family), src: Some(src), .. } => {
|
||||||
let mut maybe_sources = None;
|
Ok(FontFaceRule {
|
||||||
|
family: family,
|
||||||
for item in ErrorLoggerIterator(parse_declaration_list(block.into_iter())) {
|
sources: src,
|
||||||
match item {
|
})
|
||||||
DeclarationListItem::AtRule(rule) => log_css_error(
|
|
||||||
rule.location, format!("Unsupported at-rule in declaration list: @{}", rule.name).as_slice()),
|
|
||||||
DeclarationListItem::Declaration(Declaration{ location, name, value, important }) => {
|
|
||||||
if important {
|
|
||||||
log_css_error(location, "!important is not allowed on @font-face descriptors");
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
let name_lower = name.as_slice().to_ascii_lower();
|
|
||||||
match name_lower.as_slice() {
|
|
||||||
"font-family" => {
|
|
||||||
let iter = &mut BufferedIter::new(value.as_slice().skip_whitespace());
|
|
||||||
match parse_one_family(iter) {
|
|
||||||
Ok(FamilyName(name)) => {
|
|
||||||
maybe_family = Some(name);
|
|
||||||
},
|
|
||||||
// This also includes generic family names:
|
|
||||||
_ => log_css_error(location, "Invalid font-family in @font-face"),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"src" => {
|
|
||||||
match parse_slice_comma_separated(
|
|
||||||
value.as_slice(), |iter| parse_one_src(iter, base_url)) {
|
|
||||||
Ok(sources) => maybe_sources = Some(sources),
|
|
||||||
Err(()) => log_css_error(location, "Invalid src in @font-face"),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
log_css_error(location, format!("Unsupported declaration {}", name).as_slice());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
_ => Err(())
|
||||||
|
|
||||||
match (maybe_family, maybe_sources) {
|
|
||||||
(Some(family), Some(sources)) => parent_rules.push(CSSRule::FontFace(FontFaceRule {
|
|
||||||
family: family,
|
|
||||||
sources: sources,
|
|
||||||
})),
|
|
||||||
(None, _) => log_css_error(rule.location, "@font-face without a font-family descriptor"),
|
|
||||||
_ => log_css_error(rule.location, "@font-face without an src descriptor"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn parse_one_src(iter: ParserIter, base_url: &Url) -> Result<Source, ()> {
|
struct FontFaceRuleParser<'a, 'b: 'a> {
|
||||||
let url = match iter.next() {
|
context: &'a ParserContext<'b>,
|
||||||
|
family: Option<String>,
|
||||||
|
src: Option<Vec<Source>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Default methods reject all at rules.
|
||||||
|
impl<'a, 'b> AtRuleParser<(), ()> for FontFaceRuleParser<'a, 'b> {}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, 'b> DeclarationParser<()> for FontFaceRuleParser<'a, 'b> {
|
||||||
|
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
|
||||||
|
match_ignore_ascii_case! { name:
|
||||||
|
"font-family" => {
|
||||||
|
self.family = Some(try!(parse_one_non_generic_family_name(input)));
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
"src" => {
|
||||||
|
self.src = Some(try!(input.parse_comma_separated(|input| {
|
||||||
|
parse_one_src(self.context, input)
|
||||||
|
})));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_one_non_generic_family_name(input: &mut Parser) -> Result<String, ()> {
|
||||||
|
match parse_one_family(input) {
|
||||||
|
Ok(FontFamily::FamilyName(name)) => Ok(name),
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn parse_one_src(context: &ParserContext, input: &mut Parser) -> Result<Source, ()> {
|
||||||
|
let url = match input.next() {
|
||||||
// Parsing url()
|
// Parsing url()
|
||||||
Some(&URL(ref url)) => {
|
Ok(Token::Url(url)) => {
|
||||||
UrlParser::new().base_url(base_url).parse(url.as_slice()).unwrap_or_else(
|
UrlParser::new().base_url(context.base_url).parse(url.as_slice()).unwrap_or_else(
|
||||||
|_error| Url::parse("about:invalid").unwrap())
|
|_error| Url::parse("about:invalid").unwrap())
|
||||||
},
|
},
|
||||||
// Parsing local() with early return()
|
// Parsing local() with early return
|
||||||
Some(&Function(ref name, ref arguments)) => {
|
Ok(Token::Function(name)) => {
|
||||||
if name.as_slice().eq_ignore_ascii_case("local") {
|
if name.eq_ignore_ascii_case("local") {
|
||||||
let iter = &mut BufferedIter::new(arguments.as_slice().skip_whitespace());
|
return Ok(Source::Local(try!(input.parse_nested_block(|input| {
|
||||||
match parse_one_family(iter) {
|
parse_one_non_generic_family_name(input)
|
||||||
Ok(FamilyName(name)) => return Ok(Source::Local(name)),
|
}))))
|
||||||
_ => return Err(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return Err(())
|
return Err(())
|
||||||
},
|
},
|
||||||
|
@ -135,18 +126,14 @@ fn parse_one_src(iter: ParserIter, base_url: &Url) -> Result<Source, ()> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parsing optional format()
|
// Parsing optional format()
|
||||||
let format_hints = match iter.next() {
|
let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
|
||||||
Some(&Function(ref name, ref arguments)) => {
|
try!(input.parse_nested_block(|input| {
|
||||||
if !name.as_slice().eq_ignore_ascii_case("format") {
|
input.parse_comma_separated(|input| {
|
||||||
return Err(())
|
Ok((try!(input.expect_string())).into_owned())
|
||||||
}
|
})
|
||||||
try!(parse_slice_comma_separated(arguments.as_slice(), parse_one_format))
|
}))
|
||||||
}
|
} else {
|
||||||
Some(component_value) => {
|
vec![]
|
||||||
iter.push_back(component_value);
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
None => vec![],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Source::Url(UrlSource {
|
Ok(Source::Url(UrlSource {
|
||||||
|
@ -154,17 +141,3 @@ fn parse_one_src(iter: ParserIter, base_url: &Url) -> Result<Source, ()> {
|
||||||
format_hints: format_hints,
|
format_hints: format_hints,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn parse_one_format(iter: ParserIter) -> Result<String, ()> {
|
|
||||||
match iter.next() {
|
|
||||||
Some(&QuotedString(ref value)) => {
|
|
||||||
if iter.next().is_none() {
|
|
||||||
Ok(value.clone())
|
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
//! `<input size>`, and so forth.
|
//! `<input size>`, and so forth.
|
||||||
|
|
||||||
use node::{TElement, TElementAttributes, TNode};
|
use node::{TElement, TElementAttributes, TNode};
|
||||||
use properties::common_types::specified::CSSColor;
|
use values::specified::CSSColor;
|
||||||
|
use values::{CSSFloat, specified};
|
||||||
use properties::DeclaredValue::SpecifiedValue;
|
use properties::DeclaredValue::SpecifiedValue;
|
||||||
use properties::PropertyDeclaration::*;
|
use properties::PropertyDeclaration;
|
||||||
use properties::{CSSFloat, specified};
|
|
||||||
use selector_matching::{DeclarationBlock, Stylist};
|
use selector_matching::{DeclarationBlock, Stylist};
|
||||||
|
|
||||||
use cssparser::Color;
|
use cssparser::Color;
|
||||||
|
@ -110,13 +110,13 @@ impl PresentationalHintSynthesis for Stylist {
|
||||||
LengthOrPercentageOrAuto::Percentage(percentage) => {
|
LengthOrPercentageOrAuto::Percentage(percentage) => {
|
||||||
let width_value = specified::LengthOrPercentageOrAuto::Percentage(percentage);
|
let width_value = specified::LengthOrPercentageOrAuto::Percentage(percentage);
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
WidthDeclaration(SpecifiedValue(width_value))));
|
PropertyDeclaration::Width(SpecifiedValue(width_value))));
|
||||||
*shareable = false
|
*shareable = false
|
||||||
}
|
}
|
||||||
LengthOrPercentageOrAuto::Length(length) => {
|
LengthOrPercentageOrAuto::Length(length) => {
|
||||||
let width_value = specified::LengthOrPercentageOrAuto::Length(specified::Length::Au(length));
|
let width_value = specified::LengthOrPercentageOrAuto::Length(specified::Length::Au(length));
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
WidthDeclaration(SpecifiedValue(width_value))));
|
PropertyDeclaration::Width(SpecifiedValue(width_value))));
|
||||||
*shareable = false
|
*shareable = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,8 +160,8 @@ impl PresentationalHintSynthesis for Stylist {
|
||||||
_ => specified::Length::Au(Au::from_px(value as int)),
|
_ => specified::Length::Au(Au::from_px(value as int)),
|
||||||
};
|
};
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
WidthDeclaration(SpecifiedValue(specified::LengthOrPercentageOrAuto::Length(
|
PropertyDeclaration::Width(SpecifiedValue(
|
||||||
value)))));
|
specified::LengthOrPercentageOrAuto::Length(value)))));
|
||||||
*shareable = false
|
*shareable = false
|
||||||
}
|
}
|
||||||
Some(_) | None => {}
|
Some(_) | None => {}
|
||||||
|
@ -177,8 +177,8 @@ impl PresentationalHintSynthesis for Stylist {
|
||||||
// https://html.spec.whatwg.org/multipage/rendering.html#textarea-effective-width
|
// https://html.spec.whatwg.org/multipage/rendering.html#textarea-effective-width
|
||||||
let value = specified::Length::ServoCharacterWidth(value);
|
let value = specified::Length::ServoCharacterWidth(value);
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
WidthDeclaration(SpecifiedValue(specified::LengthOrPercentageOrAuto::Length(
|
PropertyDeclaration::Width(SpecifiedValue(
|
||||||
value)))));
|
specified::LengthOrPercentageOrAuto::Length(value)))));
|
||||||
*shareable = false
|
*shareable = false
|
||||||
}
|
}
|
||||||
Some(_) | None => {}
|
Some(_) | None => {}
|
||||||
|
@ -190,8 +190,8 @@ impl PresentationalHintSynthesis for Stylist {
|
||||||
// https://html.spec.whatwg.org/multipage/rendering.html#textarea-effective-height
|
// https://html.spec.whatwg.org/multipage/rendering.html#textarea-effective-height
|
||||||
let value = specified::Length::Em(value as CSSFloat);
|
let value = specified::Length::Em(value as CSSFloat);
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
HeightDeclaration(SpecifiedValue(specified::LengthOrPercentageOrAuto::Length(
|
PropertyDeclaration::Height(SpecifiedValue(
|
||||||
value)))));
|
specified::LengthOrPercentageOrAuto::Length(value)))));
|
||||||
*shareable = false
|
*shareable = false
|
||||||
}
|
}
|
||||||
Some(_) | None => {}
|
Some(_) | None => {}
|
||||||
|
@ -216,7 +216,8 @@ impl PresentationalHintSynthesis for Stylist {
|
||||||
None => {}
|
None => {}
|
||||||
Some(color) => {
|
Some(color) => {
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
BackgroundColorDeclaration(SpecifiedValue(CSSColor { parsed: Color::RGBA(color), authored: None }))));
|
PropertyDeclaration::BackgroundColor(SpecifiedValue(
|
||||||
|
CSSColor { parsed: Color::RGBA(color), authored: None }))));
|
||||||
*shareable = false
|
*shareable = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,13 +237,13 @@ impl PresentationalHintSynthesis for Stylist {
|
||||||
Some(length) => {
|
Some(length) => {
|
||||||
let width_value = specified::Length::Au(Au::from_px(length as int));
|
let width_value = specified::Length::Au(Au::from_px(length as int));
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
BorderTopWidthDeclaration(SpecifiedValue(width_value))));
|
PropertyDeclaration::BorderTopWidth(SpecifiedValue(width_value))));
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
BorderLeftWidthDeclaration(SpecifiedValue(width_value))));
|
PropertyDeclaration::BorderLeftWidth(SpecifiedValue(width_value))));
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
BorderBottomWidthDeclaration(SpecifiedValue(width_value))));
|
PropertyDeclaration::BorderBottomWidth(SpecifiedValue(width_value))));
|
||||||
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
|
||||||
BorderRightWidthDeclaration(SpecifiedValue(width_value))));
|
PropertyDeclaration::BorderRightWidth(SpecifiedValue(width_value))));
|
||||||
*shareable = false
|
*shareable = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,12 @@ extern crate serialize;
|
||||||
extern crate text_writer;
|
extern crate text_writer;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
|
|
||||||
|
#[phase(plugin, link)]
|
||||||
extern crate cssparser;
|
extern crate cssparser;
|
||||||
|
|
||||||
|
#[phase(plugin)]
|
||||||
|
extern crate matches;
|
||||||
|
|
||||||
extern crate encoding;
|
extern crate encoding;
|
||||||
extern crate string_cache;
|
extern crate string_cache;
|
||||||
|
|
||||||
|
@ -34,39 +39,41 @@ extern crate lazy_static;
|
||||||
extern crate "util" as servo_util;
|
extern crate "util" as servo_util;
|
||||||
|
|
||||||
|
|
||||||
// Public API
|
|
||||||
pub use media_queries::{Device, MediaType};
|
pub use media_queries::{Device, MediaType};
|
||||||
pub use stylesheets::{Stylesheet, iter_font_face_rules};
|
pub use stylesheets::{Stylesheet, iter_font_face_rules};
|
||||||
pub use selector_matching::{Stylist, StylesheetOrigin};
|
pub use selector_matching::{Stylist};
|
||||||
pub use selector_matching::{DeclarationBlock, CommonStyleAffectingAttributes};
|
pub use selector_matching::{DeclarationBlock, CommonStyleAffectingAttributes};
|
||||||
pub use selector_matching::{CommonStyleAffectingAttributeInfo, CommonStyleAffectingAttributeMode};
|
pub use selector_matching::{CommonStyleAffectingAttributeInfo, CommonStyleAffectingAttributeMode};
|
||||||
pub use selector_matching::{matches, matches_simple_selector, common_style_affecting_attributes};
|
pub use selector_matching::{matches, matches_simple_selector, common_style_affecting_attributes};
|
||||||
pub use selector_matching::{rare_style_affecting_attributes};
|
pub use selector_matching::{rare_style_affecting_attributes};
|
||||||
pub use selector_matching::{RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE, SELECTOR_WHITESPACE};
|
pub use selector_matching::{RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE, SELECTOR_WHITESPACE};
|
||||||
pub use properties::{cascade, cascade_anonymous, computed, longhands_from_shorthand};
|
pub use properties::{cascade, cascade_anonymous, longhands_from_shorthand};
|
||||||
pub use properties::{is_supported_property, make_inline};
|
pub use properties::{is_supported_property, make_inline};
|
||||||
pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs};
|
pub use properties::{PropertyDeclaration};
|
||||||
|
pub use properties::{computed_values, ComputedValues, style_structs};
|
||||||
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
|
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
|
||||||
pub use properties::{CSSFloat, DeclaredValue, PropertyDeclarationParseResult};
|
pub use properties::{DeclaredValue, PropertyDeclarationParseResult};
|
||||||
pub use properties::{Angle, AngleOrCorner};
|
pub use values::CSSFloat;
|
||||||
pub use properties::{HorizontalDirection, VerticalDirection};
|
pub use values::specified::{Angle, AngleOrCorner, HorizontalDirection, VerticalDirection};
|
||||||
|
pub use values::computed;
|
||||||
pub use node::{TElement, TElementAttributes, TNode};
|
pub use node::{TElement, TElementAttributes, TNode};
|
||||||
pub use selectors::{PseudoElement, ParserContext, SelectorList};
|
pub use selectors::{PseudoElement, SelectorList};
|
||||||
pub use selectors::{AttrSelector, NamespaceConstraint};
|
pub use selectors::{AttrSelector, NamespaceConstraint};
|
||||||
pub use selectors::{SimpleSelector, parse_selector_list_from_str};
|
pub use selectors::{SimpleSelector, parse_author_origin_selector_list_from_str};
|
||||||
pub use cssparser::{Color, RGBA};
|
pub use cssparser::{Color, RGBA};
|
||||||
pub use legacy::{IntegerAttribute, LengthAttribute};
|
pub use legacy::{IntegerAttribute, LengthAttribute};
|
||||||
pub use legacy::{SimpleColorAttribute, UnsignedIntegerAttribute};
|
pub use legacy::{SimpleColorAttribute, UnsignedIntegerAttribute};
|
||||||
pub use font_face::Source;
|
pub use font_face::Source;
|
||||||
|
pub use stylesheets::Origin as StylesheetOrigin;
|
||||||
|
|
||||||
mod stylesheets;
|
pub mod stylesheets;
|
||||||
mod errors;
|
pub mod parser;
|
||||||
mod selectors;
|
pub mod selectors;
|
||||||
mod selector_matching;
|
pub mod selector_matching;
|
||||||
mod properties;
|
pub mod values;
|
||||||
mod namespaces;
|
pub mod properties;
|
||||||
mod node;
|
pub mod namespaces;
|
||||||
mod media_queries;
|
pub mod node;
|
||||||
mod parsing_utils;
|
pub mod media_queries;
|
||||||
mod font_face;
|
pub mod font_face;
|
||||||
mod legacy;
|
pub mod legacy;
|
||||||
|
|
|
@ -3,31 +3,20 @@
|
||||||
* 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::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use cssparser::parse_rule_list;
|
use cssparser::{Token, Parser, Delimiter};
|
||||||
use cssparser::ast::*;
|
|
||||||
use cssparser::ast::ComponentValue::*;
|
|
||||||
|
|
||||||
use errors::{ErrorLoggerIterator, log_css_error};
|
|
||||||
use geom::size::TypedSize2D;
|
use geom::size::TypedSize2D;
|
||||||
use selectors::ParserContext;
|
|
||||||
use stylesheets::{CSSRule, parse_style_rule, parse_nested_at_rule};
|
|
||||||
use namespaces::NamespaceMap;
|
|
||||||
use parsing_utils::{BufferedIter, ParserIter};
|
|
||||||
use properties::common_types::*;
|
|
||||||
use properties::longhands;
|
use properties::longhands;
|
||||||
use servo_util::geometry::ViewportPx;
|
use servo_util::geometry::{Au, ViewportPx};
|
||||||
use url::Url;
|
use values::{computed, specified};
|
||||||
|
|
||||||
pub struct MediaRule {
|
|
||||||
pub media_queries: MediaQueryList,
|
|
||||||
pub rules: Vec<CSSRule>,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#[deriving(Show, PartialEq)]
|
||||||
pub struct MediaQueryList {
|
pub struct MediaQueryList {
|
||||||
media_queries: Vec<MediaQuery>
|
media_queries: Vec<MediaQuery>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq, Eq, Copy)]
|
#[deriving(PartialEq, Eq, Copy, Show)]
|
||||||
pub enum Range<T> {
|
pub enum Range<T> {
|
||||||
Min(T),
|
Min(T),
|
||||||
Max(T),
|
Max(T),
|
||||||
|
@ -44,17 +33,18 @@ impl<T: Ord> Range<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq, Eq, Copy)]
|
#[deriving(PartialEq, Eq, Copy, Show)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Width(Range<Au>),
|
Width(Range<Au>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq, Eq, Copy)]
|
#[deriving(PartialEq, Eq, Copy, Show)]
|
||||||
pub enum Qualifier {
|
pub enum Qualifier {
|
||||||
Only,
|
Only,
|
||||||
Not,
|
Not,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(Show, PartialEq)]
|
||||||
pub struct MediaQuery {
|
pub struct MediaQuery {
|
||||||
qualifier: Option<Qualifier>,
|
qualifier: Option<Qualifier>,
|
||||||
media_type: MediaQueryType,
|
media_type: MediaQueryType,
|
||||||
|
@ -72,19 +62,21 @@ impl MediaQuery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq, Eq, Copy)]
|
#[deriving(PartialEq, Eq, Copy, Show)]
|
||||||
pub enum MediaQueryType {
|
pub enum MediaQueryType {
|
||||||
All, // Always true
|
All, // Always true
|
||||||
MediaType(MediaType),
|
MediaType(MediaType),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq, Eq, Copy)]
|
#[deriving(PartialEq, Eq, Copy, Show)]
|
||||||
pub enum MediaType {
|
pub enum MediaType {
|
||||||
Screen,
|
Screen,
|
||||||
Print,
|
Print,
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(missing_copy_implementations)]
|
||||||
|
#[deriving(Show)]
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
pub media_type: MediaType,
|
pub media_type: MediaType,
|
||||||
pub viewport_size: TypedSize2D<ViewportPx, f32>,
|
pub viewport_size: TypedSize2D<ViewportPx, f32>,
|
||||||
|
@ -99,42 +91,9 @@ impl Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_media_rule(context: &ParserContext,
|
|
||||||
rule: AtRule,
|
|
||||||
parent_rules: &mut Vec<CSSRule>,
|
|
||||||
namespaces: &NamespaceMap,
|
|
||||||
base_url: &Url) {
|
|
||||||
let media_queries = parse_media_query_list(rule.prelude.as_slice());
|
|
||||||
let block = match rule.block {
|
|
||||||
Some(block) => block,
|
|
||||||
None => {
|
|
||||||
log_css_error(rule.location, "Invalid @media rule");
|
|
||||||
return
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut rules = vec!();
|
|
||||||
for rule in ErrorLoggerIterator(parse_rule_list(block.into_iter())) {
|
|
||||||
match rule {
|
|
||||||
Rule::QualifiedRule(rule) => {
|
|
||||||
parse_style_rule(context, rule, &mut rules, namespaces, base_url)
|
|
||||||
}
|
|
||||||
Rule::AtRule(rule) => parse_nested_at_rule(
|
|
||||||
context,
|
|
||||||
rule.name.as_slice().to_ascii_lower().as_slice(),
|
|
||||||
rule,
|
|
||||||
&mut rules,
|
|
||||||
namespaces,
|
|
||||||
base_url),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parent_rules.push(CSSRule::Media(MediaRule {
|
|
||||||
media_queries: media_queries,
|
|
||||||
rules: rules,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_value_as_length(value: &ComponentValue) -> Result<Au, ()> {
|
fn parse_non_negative_length(input: &mut Parser) -> Result<Au, ()> {
|
||||||
let length = try!(specified::Length::parse_non_negative(value));
|
let length = try!(specified::Length::parse_non_negative(input));
|
||||||
|
|
||||||
// http://dev.w3.org/csswg/mediaqueries3/ - Section 6
|
// http://dev.w3.org/csswg/mediaqueries3/ - Section 6
|
||||||
// em units are relative to the initial font-size.
|
// em units are relative to the initial font-size.
|
||||||
|
@ -142,154 +101,87 @@ fn parse_value_as_length(value: &ComponentValue) -> Result<Au, ()> {
|
||||||
Ok(computed::compute_Au_with_font_size(length, initial_font_size, initial_font_size))
|
Ok(computed::compute_Au_with_font_size(length, initial_font_size, initial_font_size))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_media_query_expression(iter: ParserIter) -> Result<Expression, ()> {
|
|
||||||
// Expect a parenthesis block with the condition
|
|
||||||
match iter.next() {
|
|
||||||
Some(&ParenthesisBlock(ref block)) => {
|
|
||||||
let iter = &mut BufferedIter::new(block.as_slice().skip_whitespace());
|
|
||||||
|
|
||||||
// Parse the variable (e.g. min-width)
|
impl Expression {
|
||||||
let variable = match iter.next() {
|
fn parse(input: &mut Parser) -> Result<Expression, ()> {
|
||||||
Some(&Ident(ref value)) => value,
|
try!(input.expect_parenthesis_block());
|
||||||
_ => return Err(())
|
input.parse_nested_block(|input| {
|
||||||
};
|
let name = try!(input.expect_ident());
|
||||||
|
try!(input.expect_colon());
|
||||||
// Ensure a colon follows
|
// TODO: Handle other media features
|
||||||
match iter.next() {
|
match_ignore_ascii_case! { name:
|
||||||
Some(&Colon) => {},
|
|
||||||
_ => return Err(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the value
|
|
||||||
let value = try!(iter.next_as_result());
|
|
||||||
|
|
||||||
// TODO: Handle other media query types
|
|
||||||
let expression = match variable.as_slice().to_ascii_lower().as_slice() {
|
|
||||||
"min-width" => {
|
"min-width" => {
|
||||||
let au = try!(parse_value_as_length(value));
|
Ok(Expression::Width(Range::Min(try!(parse_non_negative_length(input)))))
|
||||||
Expression::Width(Range::Min(au))
|
},
|
||||||
}
|
|
||||||
"max-width" => {
|
"max-width" => {
|
||||||
let au = try!(parse_value_as_length(value));
|
Ok(Expression::Width(Range::Max(try!(parse_non_negative_length(input)))))
|
||||||
Expression::Width(Range::Max(au))
|
|
||||||
}
|
}
|
||||||
_ => return Err(())
|
_ => Err(())
|
||||||
};
|
|
||||||
|
|
||||||
if iter.is_eof() {
|
|
||||||
Ok(expression)
|
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
_ => Err(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_media_query(iter: ParserIter) -> Result<MediaQuery, ()> {
|
impl MediaQuery {
|
||||||
let mut expressions = vec!();
|
fn parse(input: &mut Parser) -> Result<MediaQuery, ()> {
|
||||||
|
let mut expressions = vec![];
|
||||||
|
|
||||||
// Check for optional 'only' or 'not'
|
let qualifier = if input.try(|input| input.expect_ident_matching("only")).is_ok() {
|
||||||
let qualifier = match iter.next() {
|
Some(Qualifier::Only)
|
||||||
Some(&Ident(ref value)) if value.as_slice().to_ascii_lower().as_slice() == "only" => Some(Qualifier::Only),
|
} else if input.try(|input| input.expect_ident_matching("not")).is_ok() {
|
||||||
Some(&Ident(ref value)) if value.as_slice().to_ascii_lower().as_slice() == "not" => Some(Qualifier::Not),
|
Some(Qualifier::Not)
|
||||||
Some(component_value) => {
|
} else {
|
||||||
iter.push_back(component_value);
|
|
||||||
None
|
None
|
||||||
}
|
};
|
||||||
None => return Err(()), // Empty queries are invalid
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check for media type
|
let media_type;
|
||||||
let media_type = match iter.next() {
|
if let Ok(ident) = input.try(|input| input.expect_ident()) {
|
||||||
Some(&Ident(ref value)) => {
|
media_type = match_ignore_ascii_case! { ident:
|
||||||
match value.as_slice().to_ascii_lower().as_slice() {
|
|
||||||
"screen" => MediaQueryType::MediaType(MediaType::Screen),
|
"screen" => MediaQueryType::MediaType(MediaType::Screen),
|
||||||
"print" => MediaQueryType::MediaType(MediaType::Print),
|
"print" => MediaQueryType::MediaType(MediaType::Print),
|
||||||
"all" => MediaQueryType::All,
|
"all" => MediaQueryType::All
|
||||||
_ => MediaQueryType::MediaType(MediaType::Unknown), // Unknown media types never match
|
_ => MediaQueryType::MediaType(MediaType::Unknown)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
Some(component_value) => {
|
|
||||||
// Media type is only optional if qualifier is not specified.
|
// Media type is only optional if qualifier is not specified.
|
||||||
if qualifier.is_some() {
|
if qualifier.is_some() {
|
||||||
return Err(());
|
return Err(())
|
||||||
}
|
}
|
||||||
iter.push_back(component_value);
|
media_type = MediaQueryType::All;
|
||||||
|
// Without a media type, require at least one expression
|
||||||
// If no qualifier and media type present, an expression should exist here
|
expressions.push(try!(Expression::parse(input)));
|
||||||
let expression = try!(parse_media_query_expression(iter));
|
|
||||||
expressions.push(expression);
|
|
||||||
|
|
||||||
MediaQueryType::All
|
|
||||||
}
|
}
|
||||||
None => return Err(()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse any subsequent expressions
|
// Parse any subsequent expressions
|
||||||
loop {
|
loop {
|
||||||
// Each expression should begin with and
|
if input.try(|input| input.expect_ident_matching("and")).is_err() {
|
||||||
match iter.next() {
|
return Ok(MediaQuery::new(qualifier, media_type, expressions))
|
||||||
Some(&Ident(ref value)) => {
|
|
||||||
match value.as_slice().to_ascii_lower().as_slice() {
|
|
||||||
"and" => {
|
|
||||||
let expression = try!(parse_media_query_expression(iter));
|
|
||||||
expressions.push(expression);
|
|
||||||
}
|
|
||||||
_ => return Err(()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some(component_value) => {
|
expressions.push(try!(Expression::parse(input)))
|
||||||
iter.push_back(component_value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
None => break,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(MediaQuery::new(qualifier, media_type, expressions))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_media_query_list(input: &[ComponentValue]) -> MediaQueryList {
|
pub fn parse_media_query_list(input: &mut Parser) -> MediaQueryList {
|
||||||
let iter = &mut BufferedIter::new(input.skip_whitespace());
|
let queries = if input.is_exhausted() {
|
||||||
let mut media_queries = vec!();
|
vec![MediaQuery::new(None, MediaQueryType::All, vec!())]
|
||||||
|
|
||||||
if iter.is_eof() {
|
|
||||||
media_queries.push(MediaQuery::new(None, MediaQueryType::All, vec!()));
|
|
||||||
} else {
|
} else {
|
||||||
|
let mut media_queries = vec![];
|
||||||
loop {
|
loop {
|
||||||
// Attempt to parse a media query.
|
media_queries.push(
|
||||||
let media_query_result = parse_media_query(iter);
|
input.parse_until_before(Delimiter::Comma, MediaQuery::parse)
|
||||||
|
.unwrap_or(MediaQuery::new(Some(Qualifier::Not),
|
||||||
// Skip until next query or end
|
MediaQueryType::All,
|
||||||
let mut trailing_tokens = false;
|
vec!())));
|
||||||
let mut more_queries = false;
|
match input.next() {
|
||||||
loop {
|
Ok(Token::Comma) => continue,
|
||||||
match iter.next() {
|
Ok(_) => unreachable!(),
|
||||||
Some(&Comma) => {
|
Err(()) => break,
|
||||||
more_queries = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Some(_) => trailing_tokens = true,
|
|
||||||
None => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the media query if it was valid and no trailing tokens were found.
|
|
||||||
// Otherwise, create a 'not all' media query, that will never match.
|
|
||||||
let media_query = match (media_query_result, trailing_tokens) {
|
|
||||||
(Ok(media_query), false) => media_query,
|
|
||||||
_ => MediaQuery::new(Some(Qualifier::Not), MediaQueryType::All, vec!()),
|
|
||||||
};
|
|
||||||
media_queries.push(media_query);
|
|
||||||
|
|
||||||
if !more_queries {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
media_queries
|
||||||
|
};
|
||||||
MediaQueryList { media_queries: media_queries }
|
MediaQueryList { media_queries: queries }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MediaQueryList {
|
impl MediaQueryList {
|
||||||
|
@ -323,17 +215,16 @@ impl MediaQueryList {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use geom::size::TypedSize2D;
|
use geom::size::TypedSize2D;
|
||||||
use properties::common_types::*;
|
use servo_util::geometry::Au;
|
||||||
use stylesheets::{iter_stylesheet_media_rules, iter_stylesheet_style_rules, Stylesheet};
|
use stylesheets::{iter_stylesheet_media_rules, iter_stylesheet_style_rules, Stylesheet};
|
||||||
use selector_matching::StylesheetOrigin;
|
use stylesheets::Origin;
|
||||||
use super::*;
|
use super::*;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
|
|
||||||
fn test_media_rule(css: &str, callback: |&MediaQueryList, &str|) {
|
fn test_media_rule(css: &str, callback: |&MediaQueryList, &str|) {
|
||||||
let url = Url::parse("http://localhost").unwrap();
|
let url = Url::parse("http://localhost").unwrap();
|
||||||
let stylesheet = Stylesheet::from_str(css, url,
|
let stylesheet = Stylesheet::from_str(css, url, Origin::Author);
|
||||||
StylesheetOrigin::Author);
|
|
||||||
let mut rule_count: int = 0;
|
let mut rule_count: int = 0;
|
||||||
iter_stylesheet_media_rules(&stylesheet, |rule| {
|
iter_stylesheet_media_rules(&stylesheet, |rule| {
|
||||||
rule_count += 1;
|
rule_count += 1;
|
||||||
|
@ -344,7 +235,7 @@ mod tests {
|
||||||
|
|
||||||
fn media_query_test(device: &Device, css: &str, expected_rule_count: int) {
|
fn media_query_test(device: &Device, css: &str, expected_rule_count: int) {
|
||||||
let url = Url::parse("http://localhost").unwrap();
|
let url = Url::parse("http://localhost").unwrap();
|
||||||
let ss = Stylesheet::from_str(css, url, StylesheetOrigin::Author);
|
let ss = Stylesheet::from_str(css, url, Origin::Author);
|
||||||
let mut rule_count: int = 0;
|
let mut rule_count: int = 0;
|
||||||
iter_stylesheet_style_rules(&ss, device, |_| rule_count += 1);
|
iter_stylesheet_style_rules(&ss, device, |_| rule_count += 1);
|
||||||
assert!(rule_count == expected_rule_count, css.to_owned());
|
assert!(rule_count == expected_rule_count, css.to_owned());
|
||||||
|
@ -629,11 +520,15 @@ mod tests {
|
||||||
});
|
});
|
||||||
|
|
||||||
test_media_rule("@media , {}", |list, css| {
|
test_media_rule("@media , {}", |list, css| {
|
||||||
assert!(list.media_queries.len() == 1, css.to_owned());
|
assert!(list.media_queries.len() == 2, css.to_owned());
|
||||||
let q = &list.media_queries[0];
|
let q = &list.media_queries[0];
|
||||||
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||||
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||||
assert!(q.expressions.len() == 0, css.to_owned());
|
assert!(q.expressions.len() == 0, css.to_owned());
|
||||||
|
let q = &list.media_queries[1];
|
||||||
|
assert!(q.qualifier == Some(Qualifier::Not), css.to_owned());
|
||||||
|
assert!(q.media_type == MediaQueryType::All, css.to_owned());
|
||||||
|
assert!(q.expressions.len() == 0, css.to_owned());
|
||||||
});
|
});
|
||||||
|
|
||||||
test_media_rule("@media screen 4px, print {}", |list, css| {
|
test_media_rule("@media screen 4px, print {}", |list, css| {
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
* 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 cssparser::ast::*;
|
use cssparser::Parser;
|
||||||
use cssparser::ast::ComponentValue::*;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use servo_util::namespace;
|
use string_cache::{Atom, Namespace};
|
||||||
use errors::log_css_error;
|
use parser::ParserContext;
|
||||||
use string_cache::Namespace;
|
|
||||||
|
|
||||||
|
|
||||||
|
#[deriving(Clone)]
|
||||||
pub struct NamespaceMap {
|
pub struct NamespaceMap {
|
||||||
pub default: Option<Namespace>,
|
pub default: Option<Namespace>,
|
||||||
pub prefix_map: HashMap<String, Namespace>,
|
pub prefix_map: HashMap<String, Namespace>,
|
||||||
|
@ -22,45 +22,28 @@ impl NamespaceMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn parse_namespace_rule(rule: AtRule, namespaces: &mut NamespaceMap) {
|
pub fn parse_namespace_rule(context: &mut ParserContext, input: &mut Parser)
|
||||||
let location = rule.location;
|
-> Result<(Option<String>, Namespace), ()> {
|
||||||
macro_rules! syntax_error(
|
let prefix = input.try(|input| input.expect_ident()).ok().map(|p| p.into_owned());
|
||||||
() => {{
|
let url = try!(input.expect_url_or_string());
|
||||||
log_css_error(location, "Invalid @namespace rule");
|
try!(input.expect_exhausted());
|
||||||
return
|
|
||||||
}};
|
let namespace = Namespace(Atom::from_slice(url.as_slice()));
|
||||||
);
|
let is_duplicate = match prefix {
|
||||||
if rule.block.is_some() { syntax_error!() }
|
Some(ref prefix) => {
|
||||||
let mut prefix: Option<String> = None;
|
context.namespaces.prefix_map.insert(prefix.clone(), namespace.clone()).is_some()
|
||||||
let mut ns: Option<Namespace> = None;
|
|
||||||
let mut iter = rule.prelude.move_skip_whitespace();
|
|
||||||
for component_value in iter {
|
|
||||||
match component_value {
|
|
||||||
Ident(value) => {
|
|
||||||
if prefix.is_some() { syntax_error!() }
|
|
||||||
prefix = Some(value);
|
|
||||||
},
|
|
||||||
URL(value) | QuotedString(value) => {
|
|
||||||
if ns.is_some() { syntax_error!() }
|
|
||||||
ns = Some(namespace::from_domstring(Some(value)));
|
|
||||||
break
|
|
||||||
},
|
|
||||||
_ => syntax_error!(),
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
if iter.next().is_some() { syntax_error!() }
|
let has_default = context.namespaces.default.is_some();
|
||||||
match (prefix, ns) {
|
if !has_default {
|
||||||
(Some(prefix), Some(ns)) => {
|
context.namespaces.default = Some(namespace.clone());
|
||||||
if namespaces.prefix_map.insert(prefix, ns).is_some() {
|
|
||||||
log_css_error(location, "Duplicate @namespace rule");
|
|
||||||
}
|
}
|
||||||
},
|
has_default
|
||||||
(None, Some(ns)) => {
|
}
|
||||||
if namespaces.default.is_some() {
|
};
|
||||||
log_css_error(location, "Duplicate @namespace rule");
|
if is_duplicate {
|
||||||
}
|
Err(()) // "Duplicate @namespace rule"
|
||||||
namespaces.default = Some(ns);
|
} else {
|
||||||
},
|
Ok((prefix, namespace))
|
||||||
_ => syntax_error!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
42
components/style/parser.rs
Normal file
42
components/style/parser.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* 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, SourcePosition};
|
||||||
|
use url::{Url, UrlParser};
|
||||||
|
use log;
|
||||||
|
|
||||||
|
use stylesheets::Origin;
|
||||||
|
use namespaces::NamespaceMap;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct ParserContext<'a> {
|
||||||
|
pub stylesheet_origin: Origin,
|
||||||
|
pub base_url: &'a Url,
|
||||||
|
pub namespaces: NamespaceMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a> ParserContext<'a> {
|
||||||
|
pub fn in_user_agent_stylesheet(&self) -> bool {
|
||||||
|
self.stylesheet_origin == Origin::UserAgent
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_url(&self, input: &str) -> Url {
|
||||||
|
UrlParser::new().base_url(self.base_url).parse(input)
|
||||||
|
.unwrap_or_else(|_| Url::parse("about:invalid").unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Defaults to a no-op.
|
||||||
|
/// Set a `RUST_LOG=style::errors` environment variable
|
||||||
|
/// to log CSS parse errors to stderr.
|
||||||
|
pub fn log_css_error(input: &mut Parser, position: SourcePosition, message: &str) {
|
||||||
|
if log_enabled!(log::INFO) {
|
||||||
|
let location = input.source_location(position);
|
||||||
|
// TODO eventually this will got into a "web console" or something.
|
||||||
|
info!("{}:{} {}", location.line, location.column, message)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,101 +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 std::ascii::AsciiExt;
|
|
||||||
use cssparser::ast::{SkipWhitespaceIterable, SkipWhitespaceIterator};
|
|
||||||
use cssparser::ast::ComponentValue::{mod, Ident, Comma};
|
|
||||||
|
|
||||||
|
|
||||||
pub fn one_component_value<'a>(input: &'a [ComponentValue]) -> Result<&'a ComponentValue, ()> {
|
|
||||||
let mut iter = input.skip_whitespace();
|
|
||||||
match iter.next() {
|
|
||||||
Some(value) => if iter.next().is_none() { Ok(value) } else { Err(()) },
|
|
||||||
None => Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn get_ident_lower(component_value: &ComponentValue) -> Result<String, ()> {
|
|
||||||
match component_value {
|
|
||||||
&Ident(ref value) => Ok(value.as_slice().to_ascii_lower()),
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct BufferedIter<E, I> {
|
|
||||||
iter: I,
|
|
||||||
buffer: Option<E>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, I: Iterator<E>> BufferedIter<E, I> {
|
|
||||||
pub fn new(iter: I) -> BufferedIter<E, I> {
|
|
||||||
BufferedIter {
|
|
||||||
iter: iter,
|
|
||||||
buffer: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn push_back(&mut self, value: E) {
|
|
||||||
assert!(self.buffer.is_none());
|
|
||||||
self.buffer = Some(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_eof(&mut self) -> bool {
|
|
||||||
match self.next() {
|
|
||||||
Some(value) => {
|
|
||||||
self.push_back(value);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
None => true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn next_as_result(&mut self) -> Result<E, ()> {
|
|
||||||
match self.next() {
|
|
||||||
Some(value) => Ok(value),
|
|
||||||
None => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E, I: Iterator<E>> Iterator<E> for BufferedIter<E, I> {
|
|
||||||
#[inline]
|
|
||||||
fn next(&mut self) -> Option<E> {
|
|
||||||
if self.buffer.is_some() {
|
|
||||||
self.buffer.take()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
self.iter.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type ParserIter<'a, 'b> = &'a mut BufferedIter<&'b ComponentValue, SkipWhitespaceIterator<'b>>;
|
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn parse_slice_comma_separated<T>(input: &[ComponentValue],
|
|
||||||
parse_one: |ParserIter| -> Result<T, ()>)
|
|
||||||
-> Result<Vec<T>, ()> {
|
|
||||||
parse_comma_separated(&mut BufferedIter::new(input.skip_whitespace()), parse_one)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn parse_comma_separated<T>(iter: ParserIter,
|
|
||||||
parse_one: |ParserIter| -> Result<T, ()>)
|
|
||||||
-> Result<Vec<T>, ()> {
|
|
||||||
let mut values = vec![try!(parse_one(iter))];
|
|
||||||
loop {
|
|
||||||
match iter.next() {
|
|
||||||
Some(&Comma) => values.push(try!(parse_one(iter))),
|
|
||||||
Some(_) => return Err(()),
|
|
||||||
None => return Ok(values),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -22,14 +22,8 @@ use properties::{PropertyDeclaration, PropertyDeclarationBlock};
|
||||||
use selectors::{CaseSensitivity, Combinator, CompoundSelector, LocalName};
|
use selectors::{CaseSensitivity, Combinator, CompoundSelector, LocalName};
|
||||||
use selectors::{PseudoElement, SelectorList, SimpleSelector};
|
use selectors::{PseudoElement, SelectorList, SimpleSelector};
|
||||||
use selectors::{get_selector_list_selectors};
|
use selectors::{get_selector_list_selectors};
|
||||||
use stylesheets::{Stylesheet, iter_stylesheet_media_rules, iter_stylesheet_style_rules};
|
use stylesheets::{Stylesheet, iter_stylesheet_media_rules, iter_stylesheet_style_rules, Origin};
|
||||||
|
|
||||||
#[deriving(Clone, PartialEq, Eq, Copy)]
|
|
||||||
pub enum StylesheetOrigin {
|
|
||||||
UserAgent,
|
|
||||||
Author,
|
|
||||||
User,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The definition of whitespace per CSS Selectors Level 3 § 4.
|
/// The definition of whitespace per CSS Selectors Level 3 § 4.
|
||||||
pub static SELECTOR_WHITESPACE: &'static [char] = &[' ', '\t', '\n', '\r', '\x0C'];
|
pub static SELECTOR_WHITESPACE: &'static [char] = &[' ', '\t', '\n', '\r', '\x0C'];
|
||||||
|
@ -303,7 +297,7 @@ impl Stylist {
|
||||||
Url::parse(format!("chrome:///{}", filename).as_slice()).unwrap(),
|
Url::parse(format!("chrome:///{}", filename).as_slice()).unwrap(),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
StylesheetOrigin::UserAgent);
|
Origin::UserAgent);
|
||||||
stylist.add_stylesheet(ua_stylesheet);
|
stylist.add_stylesheet(ua_stylesheet);
|
||||||
}
|
}
|
||||||
stylist
|
stylist
|
||||||
|
@ -318,17 +312,17 @@ impl Stylist {
|
||||||
|
|
||||||
for stylesheet in self.stylesheets.iter() {
|
for stylesheet in self.stylesheets.iter() {
|
||||||
let (mut element_map, mut before_map, mut after_map) = match stylesheet.origin {
|
let (mut element_map, mut before_map, mut after_map) = match stylesheet.origin {
|
||||||
StylesheetOrigin::UserAgent => (
|
Origin::UserAgent => (
|
||||||
&mut self.element_map.user_agent,
|
&mut self.element_map.user_agent,
|
||||||
&mut self.before_map.user_agent,
|
&mut self.before_map.user_agent,
|
||||||
&mut self.after_map.user_agent,
|
&mut self.after_map.user_agent,
|
||||||
),
|
),
|
||||||
StylesheetOrigin::Author => (
|
Origin::Author => (
|
||||||
&mut self.element_map.author,
|
&mut self.element_map.author,
|
||||||
&mut self.before_map.author,
|
&mut self.before_map.author,
|
||||||
&mut self.after_map.author,
|
&mut self.after_map.author,
|
||||||
),
|
),
|
||||||
StylesheetOrigin::User => (
|
Origin::User => (
|
||||||
&mut self.element_map.user,
|
&mut self.element_map.user,
|
||||||
&mut self.before_map.user,
|
&mut self.before_map.user,
|
||||||
&mut self.after_map.user,
|
&mut self.after_map.user,
|
||||||
|
@ -395,7 +389,7 @@ impl Stylist {
|
||||||
Url::parse("chrome:///quirks-mode.css").unwrap(),
|
Url::parse("chrome:///quirks-mode.css").unwrap(),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
StylesheetOrigin::UserAgent))
|
Origin::UserAgent))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_stylesheet(&mut self, stylesheet: Stylesheet) {
|
pub fn add_stylesheet(&mut self, stylesheet: Stylesheet) {
|
||||||
|
@ -529,7 +523,7 @@ struct Rule {
|
||||||
|
|
||||||
/// A property declaration together with its precedence among rules of equal specificity so that
|
/// A property declaration together with its precedence among rules of equal specificity so that
|
||||||
/// we can sort them.
|
/// we can sort them.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone, Show)]
|
||||||
pub struct DeclarationBlock {
|
pub struct DeclarationBlock {
|
||||||
pub declarations: Arc<Vec<PropertyDeclaration>>,
|
pub declarations: Arc<Vec<PropertyDeclaration>>,
|
||||||
source_order: uint,
|
source_order: uint,
|
||||||
|
@ -1171,21 +1165,24 @@ mod tests {
|
||||||
use super::{DeclarationBlock, Rule, SelectorMap};
|
use super::{DeclarationBlock, Rule, SelectorMap};
|
||||||
use selectors::LocalName;
|
use selectors::LocalName;
|
||||||
use string_cache::Atom;
|
use string_cache::Atom;
|
||||||
|
use cssparser::Parser;
|
||||||
|
use parser::ParserContext;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
/// 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 namespaces::NamespaceMap;
|
||||||
use selectors::{ParserContext, parse_selector_list};
|
use selectors::parse_selector_list;
|
||||||
use selector_matching::StylesheetOrigin;
|
use stylesheets::Origin;
|
||||||
use cssparser::tokenize;
|
|
||||||
|
|
||||||
let namespaces = NamespaceMap::new();
|
|
||||||
css_selectors.iter().enumerate().map(|(i, selectors)| {
|
css_selectors.iter().enumerate().map(|(i, selectors)| {
|
||||||
let context = ParserContext {
|
let context = ParserContext {
|
||||||
origin: StylesheetOrigin::Author,
|
stylesheet_origin: Origin::Author,
|
||||||
|
namespaces: NamespaceMap::new(),
|
||||||
|
base_url: &Url::parse("about:blank").unwrap(),
|
||||||
};
|
};
|
||||||
parse_selector_list(&context, tokenize(*selectors).map(|(c, _)| c), &namespaces)
|
parse_selector_list(&context, &mut Parser::new(*selectors))
|
||||||
.unwrap().into_iter().map(|s| {
|
.unwrap().into_iter().map(|s| {
|
||||||
Rule {
|
Rule {
|
||||||
selector: s.compound_selectors.clone(),
|
selector: s.compound_selectors.clone(),
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,55 +8,75 @@ use url::Url;
|
||||||
|
|
||||||
use encoding::EncodingRef;
|
use encoding::EncodingRef;
|
||||||
|
|
||||||
use cssparser::{decode_stylesheet_bytes, tokenize, parse_stylesheet_rules, ToCss};
|
use cssparser::{Parser, decode_stylesheet_bytes,
|
||||||
use cssparser::ast::*;
|
QualifiedRuleParser, AtRuleParser, RuleListParser, AtRuleType};
|
||||||
use selectors::{mod, ParserContext};
|
use string_cache::Namespace;
|
||||||
use properties;
|
use selectors::{Selector, parse_selector_list};
|
||||||
use errors::{ErrorLoggerIterator, log_css_error};
|
use parser::ParserContext;
|
||||||
|
use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
|
||||||
use namespaces::{NamespaceMap, parse_namespace_rule};
|
use namespaces::{NamespaceMap, parse_namespace_rule};
|
||||||
use media_queries::{mod, Device, MediaRule};
|
use media_queries::{mod, Device, MediaQueryList, parse_media_query_list};
|
||||||
use font_face::{FontFaceRule, Source, parse_font_face_rule, iter_font_face_rules_inner};
|
use font_face::{FontFaceRule, Source, parse_font_face_block, iter_font_face_rules_inner};
|
||||||
use selector_matching::StylesheetOrigin;
|
|
||||||
|
|
||||||
|
|
||||||
|
#[deriving(Clone, PartialEq, Eq, Copy, Show)]
|
||||||
|
pub enum Origin {
|
||||||
|
UserAgent,
|
||||||
|
Author,
|
||||||
|
User,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[deriving(Show, PartialEq)]
|
||||||
pub struct Stylesheet {
|
pub struct Stylesheet {
|
||||||
/// List of rules in the order they were found (important for
|
/// List of rules in the order they were found (important for
|
||||||
/// cascading order)
|
/// cascading order)
|
||||||
rules: Vec<CSSRule>,
|
rules: Vec<CSSRule>,
|
||||||
pub origin: StylesheetOrigin,
|
pub origin: Origin,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[deriving(Show, PartialEq)]
|
||||||
pub enum CSSRule {
|
pub enum CSSRule {
|
||||||
|
Charset(String),
|
||||||
|
Namespace(Option<String>, Namespace),
|
||||||
Style(StyleRule),
|
Style(StyleRule),
|
||||||
Media(MediaRule),
|
Media(MediaRule),
|
||||||
FontFace(FontFaceRule),
|
FontFace(FontFaceRule),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(Show, PartialEq)]
|
||||||
|
pub struct MediaRule {
|
||||||
|
pub media_queries: MediaQueryList,
|
||||||
|
pub rules: Vec<CSSRule>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[deriving(Show, PartialEq)]
|
||||||
pub struct StyleRule {
|
pub struct StyleRule {
|
||||||
pub selectors: Vec<selectors::Selector>,
|
pub selectors: Vec<Selector>,
|
||||||
pub declarations: properties::PropertyDeclarationBlock,
|
pub declarations: PropertyDeclarationBlock,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Stylesheet {
|
impl Stylesheet {
|
||||||
pub fn from_bytes_iter<I: Iterator<Vec<u8>>>(
|
pub fn from_bytes_iter<I: Iterator<Vec<u8>>>(
|
||||||
mut input: I, base_url: Url, protocol_encoding_label: Option<&str>,
|
mut input: I, base_url: Url, protocol_encoding_label: Option<&str>,
|
||||||
environment_encoding: Option<EncodingRef>, origin: StylesheetOrigin) -> Stylesheet {
|
environment_encoding: Option<EncodingRef>, origin: Origin) -> Stylesheet {
|
||||||
let mut bytes = vec!();
|
let mut bytes = vec!();
|
||||||
// TODO: incremental decoding and tokenization/parsing
|
// TODO: incremental decoding and tokenization/parsing
|
||||||
for chunk in input {
|
for chunk in input {
|
||||||
bytes.push_all(chunk.as_slice())
|
bytes.push_all(chunk.as_slice())
|
||||||
}
|
}
|
||||||
Stylesheet::from_bytes(bytes.as_slice(), base_url, protocol_encoding_label, environment_encoding, origin)
|
Stylesheet::from_bytes(bytes.as_slice(), base_url, protocol_encoding_label,
|
||||||
|
environment_encoding, origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_bytes(bytes: &[u8],
|
pub fn from_bytes(bytes: &[u8],
|
||||||
base_url: Url,
|
base_url: Url,
|
||||||
protocol_encoding_label: Option<&str>,
|
protocol_encoding_label: Option<&str>,
|
||||||
environment_encoding: Option<EncodingRef>,
|
environment_encoding: Option<EncodingRef>,
|
||||||
origin: StylesheetOrigin)
|
origin: Origin)
|
||||||
-> Stylesheet {
|
-> Stylesheet {
|
||||||
// TODO: bytes.as_slice could be bytes.container_as_bytes()
|
// TODO: bytes.as_slice could be bytes.container_as_bytes()
|
||||||
let (string, _) = decode_stylesheet_bytes(
|
let (string, _) = decode_stylesheet_bytes(
|
||||||
|
@ -64,121 +84,139 @@ impl Stylesheet {
|
||||||
Stylesheet::from_str(string.as_slice(), base_url, origin)
|
Stylesheet::from_str(string.as_slice(), base_url, origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_str(css: &str, base_url: Url, origin: StylesheetOrigin) -> Stylesheet {
|
pub fn from_str<'i>(css: &'i str, base_url: Url, origin: Origin) -> Stylesheet {
|
||||||
static STATE_CHARSET: uint = 1;
|
let mut context = ParserContext {
|
||||||
static STATE_IMPORTS: uint = 2;
|
stylesheet_origin: origin,
|
||||||
static STATE_NAMESPACES: uint = 3;
|
base_url: &base_url,
|
||||||
static STATE_BODY: uint = 4;
|
namespaces: NamespaceMap::new()
|
||||||
|
|
||||||
let parser_context = ParserContext {
|
|
||||||
origin: origin,
|
|
||||||
};
|
};
|
||||||
|
let rule_parser = MainRuleParser {
|
||||||
let mut state: uint = STATE_CHARSET;
|
context: &mut context,
|
||||||
|
state: State::Start,
|
||||||
let mut rules = vec!();
|
};
|
||||||
let mut namespaces = NamespaceMap::new();
|
let rules = RuleListParser::new_for_stylesheet(&mut Parser::new(css), rule_parser)
|
||||||
|
.filter_map(|result| result.ok())
|
||||||
for rule in ErrorLoggerIterator(parse_stylesheet_rules(tokenize(css))) {
|
.collect();
|
||||||
let next_state; // Unitialized to force each branch to set it.
|
|
||||||
match rule {
|
|
||||||
Rule::QualifiedRule(rule) => {
|
|
||||||
next_state = STATE_BODY;
|
|
||||||
parse_style_rule(&parser_context, rule, &mut rules, &namespaces, &base_url)
|
|
||||||
},
|
|
||||||
Rule::AtRule(rule) => {
|
|
||||||
let lower_name = rule.name.as_slice().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(&parser_context,
|
|
||||||
lower_name.as_slice(),
|
|
||||||
rule,
|
|
||||||
&mut rules,
|
|
||||||
&namespaces,
|
|
||||||
&base_url)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
state = next_state;
|
|
||||||
}
|
|
||||||
Stylesheet {
|
Stylesheet {
|
||||||
rules: rules,
|
|
||||||
origin: origin,
|
origin: origin,
|
||||||
|
rules: rules,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// lower_name is passed explicitly to avoid computing it twice.
|
|
||||||
pub fn parse_nested_at_rule(context: &ParserContext,
|
fn parse_nested_rules(context: &mut ParserContext, input: &mut Parser) -> Vec<CSSRule> {
|
||||||
lower_name: &str,
|
let parser = MainRuleParser {
|
||||||
rule: AtRule,
|
context: context,
|
||||||
parent_rules: &mut Vec<CSSRule>,
|
state: State::Body,
|
||||||
namespaces: &NamespaceMap,
|
};
|
||||||
base_url: &Url) {
|
RuleListParser::new_for_nested_rule(input, parser)
|
||||||
match lower_name {
|
.filter_map(|result| result.ok())
|
||||||
"media" => {
|
.collect()
|
||||||
media_queries::parse_media_rule(context, rule, parent_rules, namespaces, base_url)
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct MainRuleParser<'a, 'b: 'a> {
|
||||||
|
context: &'a mut ParserContext<'b>,
|
||||||
|
state: State,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[deriving(Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
enum State {
|
||||||
|
Start = 1,
|
||||||
|
Imports = 2,
|
||||||
|
Namespaces = 3,
|
||||||
|
Body = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum AtRulePrelude {
|
||||||
|
FontFace,
|
||||||
|
Media(MediaQueryList),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, 'b> AtRuleParser<AtRulePrelude, CSSRule> for MainRuleParser<'a, 'b> {
|
||||||
|
fn parse_prelude(&mut self, name: &str, input: &mut Parser)
|
||||||
|
-> Result<AtRuleType<AtRulePrelude, CSSRule>, ()> {
|
||||||
|
match_ignore_ascii_case! { name:
|
||||||
|
"charset" => {
|
||||||
|
if self.state <= State::Start {
|
||||||
|
// Valid @charset rules are just ignored
|
||||||
|
self.state = State::Imports;
|
||||||
|
let charset = try!(input.expect_string()).into_owned();
|
||||||
|
return Ok(AtRuleType::WithoutBlock(CSSRule::Charset(charset)))
|
||||||
|
} else {
|
||||||
|
return Err(()) // "@charset must be the first rule"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"import" => {
|
||||||
|
if self.state <= State::Imports {
|
||||||
|
self.state = State::Imports;
|
||||||
|
// TODO: support @import
|
||||||
|
return Err(()) // "@import is not supported yet"
|
||||||
|
} else {
|
||||||
|
return Err(()) // "@import must be before any rule but @charset"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"namespace" => {
|
||||||
|
if self.state <= State::Namespaces {
|
||||||
|
self.state = State::Namespaces;
|
||||||
|
let (prefix, namespace) = try!(parse_namespace_rule(self.context, input));
|
||||||
|
return Ok(AtRuleType::WithoutBlock(CSSRule::Namespace(prefix, namespace)))
|
||||||
|
} else {
|
||||||
|
return Err(()) // "@namespace must be before any rule but @charset and @import"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state = State::Body;
|
||||||
|
|
||||||
|
match_ignore_ascii_case! { name:
|
||||||
|
"media" => {
|
||||||
|
let media_queries = parse_media_query_list(input);
|
||||||
|
Ok(AtRuleType::WithBlock(AtRulePrelude::Media(media_queries)))
|
||||||
|
},
|
||||||
|
"font-face" => {
|
||||||
|
Ok(AtRuleType::WithBlock(AtRulePrelude::FontFace))
|
||||||
|
}
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CSSRule, ()> {
|
||||||
|
match prelude {
|
||||||
|
AtRulePrelude::FontFace => {
|
||||||
|
parse_font_face_block(self.context, input).map(CSSRule::FontFace)
|
||||||
|
}
|
||||||
|
AtRulePrelude::Media(media_queries) => {
|
||||||
|
Ok(CSSRule::Media(MediaRule {
|
||||||
|
media_queries: media_queries,
|
||||||
|
rules: parse_nested_rules(self.context, input),
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"font-face" => parse_font_face_rule(rule, parent_rules, base_url),
|
|
||||||
_ => log_css_error(rule.location,
|
|
||||||
format!("Unsupported at-rule: @{}", lower_name).as_slice())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_style_rule(context: &ParserContext,
|
|
||||||
rule: QualifiedRule,
|
impl<'a, 'b> QualifiedRuleParser<Vec<Selector>, CSSRule> for MainRuleParser<'a, 'b> {
|
||||||
parent_rules: &mut Vec<CSSRule>,
|
fn parse_prelude(&mut self, input: &mut Parser) -> Result<Vec<Selector>, ()> {
|
||||||
namespaces: &NamespaceMap,
|
self.state = State::Body;
|
||||||
base_url: &Url) {
|
parse_selector_list(self.context, input)
|
||||||
let QualifiedRule {
|
}
|
||||||
location,
|
|
||||||
prelude,
|
fn parse_block(&mut self, prelude: Vec<Selector>, input: &mut Parser) -> Result<CSSRule, ()> {
|
||||||
block
|
Ok(CSSRule::Style(StyleRule {
|
||||||
} = rule;
|
selectors: prelude,
|
||||||
// FIXME: avoid doing this for valid selectors
|
declarations: parse_property_declaration_list(self.context, input)
|
||||||
let serialized = prelude.to_css_string();
|
}))
|
||||||
match selectors::parse_selector_list(context, prelude.into_iter(), namespaces) {
|
|
||||||
Ok(selectors) => parent_rules.push(CSSRule::Style(StyleRule{
|
|
||||||
selectors: selectors,
|
|
||||||
declarations: properties::parse_property_declaration_list(block.into_iter(), base_url)
|
|
||||||
})),
|
|
||||||
Err(()) => log_css_error(location, format!(
|
|
||||||
"Invalid/unsupported selector: {}", serialized).as_slice()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
|
pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
|
||||||
callback: |&StyleRule|) {
|
callback: |&StyleRule|) {
|
||||||
for rule in rules.iter() {
|
for rule in rules.iter() {
|
||||||
|
@ -187,7 +225,9 @@ pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
|
||||||
CSSRule::Media(ref rule) => if rule.media_queries.evaluate(device) {
|
CSSRule::Media(ref rule) => if rule.media_queries.evaluate(device) {
|
||||||
iter_style_rules(rule.rules.as_slice(), device, |s| callback(s))
|
iter_style_rules(rule.rules.as_slice(), device, |s| callback(s))
|
||||||
},
|
},
|
||||||
CSSRule::FontFace(_) => {},
|
CSSRule::FontFace(..) |
|
||||||
|
CSSRule::Charset(..) |
|
||||||
|
CSSRule::Namespace(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,7 +236,10 @@ pub fn iter_stylesheet_media_rules(stylesheet: &Stylesheet, callback: |&MediaRul
|
||||||
for rule in stylesheet.rules.iter() {
|
for rule in stylesheet.rules.iter() {
|
||||||
match *rule {
|
match *rule {
|
||||||
CSSRule::Media(ref rule) => callback(rule),
|
CSSRule::Media(ref rule) => callback(rule),
|
||||||
_ => {}
|
CSSRule::Style(..) |
|
||||||
|
CSSRule::FontFace(..) |
|
||||||
|
CSSRule::Charset(..) |
|
||||||
|
CSSRule::Namespace(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,3 +256,134 @@ pub fn iter_font_face_rules(stylesheet: &Stylesheet, device: &Device,
|
||||||
callback: |family: &str, source: &Source|) {
|
callback: |family: &str, source: &Source|) {
|
||||||
iter_font_face_rules_inner(stylesheet.rules.as_slice(), device, callback)
|
iter_font_face_rules_inner(stylesheet.rules.as_slice(), device, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_stylesheet() {
|
||||||
|
use std::sync::Arc;
|
||||||
|
use cssparser;
|
||||||
|
use selectors::*;
|
||||||
|
use string_cache::Atom;
|
||||||
|
use properties::{PropertyDeclaration, DeclaredValue, longhands};
|
||||||
|
|
||||||
|
let css = r"
|
||||||
|
@namespace url(http://www.w3.org/1999/xhtml);
|
||||||
|
/* FIXME: only if scripting is enabled */
|
||||||
|
input[type=hidden i] { display: none !important; }
|
||||||
|
html , body /**/ { display: block; }
|
||||||
|
#d1 > .ok { background: blue; }
|
||||||
|
";
|
||||||
|
let url = Url::parse("about::test").unwrap();
|
||||||
|
let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent);
|
||||||
|
assert_eq!(stylesheet, Stylesheet {
|
||||||
|
origin: Origin::UserAgent,
|
||||||
|
rules: vec![
|
||||||
|
CSSRule::Namespace(None, ns!(HTML)),
|
||||||
|
CSSRule::Style(StyleRule {
|
||||||
|
selectors: vec![
|
||||||
|
Selector {
|
||||||
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
|
simple_selectors: vec![
|
||||||
|
SimpleSelector::Namespace(ns!(HTML)),
|
||||||
|
SimpleSelector::LocalName(LocalName {
|
||||||
|
name: atom!(input),
|
||||||
|
lower_name: atom!(input),
|
||||||
|
}),
|
||||||
|
SimpleSelector::AttrEqual(AttrSelector {
|
||||||
|
name: atom!(type),
|
||||||
|
lower_name: atom!(type),
|
||||||
|
namespace: NamespaceConstraint::Specific(ns!("")),
|
||||||
|
}, "hidden".into_string(), CaseSensitivity::CaseInsensitive)
|
||||||
|
],
|
||||||
|
next: None,
|
||||||
|
}),
|
||||||
|
pseudo_element: None,
|
||||||
|
specificity: (0 << 20) + (1 << 10) + (1 << 0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
declarations: PropertyDeclarationBlock {
|
||||||
|
normal: Arc::new(vec![]),
|
||||||
|
important: Arc::new(vec![
|
||||||
|
PropertyDeclaration::Display(DeclaredValue::SpecifiedValue(
|
||||||
|
longhands::display::SpecifiedValue::none)),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
CSSRule::Style(StyleRule {
|
||||||
|
selectors: vec![
|
||||||
|
Selector {
|
||||||
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
|
simple_selectors: vec![
|
||||||
|
SimpleSelector::Namespace(ns!(HTML)),
|
||||||
|
SimpleSelector::LocalName(LocalName {
|
||||||
|
name: atom!(html),
|
||||||
|
lower_name: atom!(html),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
next: None,
|
||||||
|
}),
|
||||||
|
pseudo_element: None,
|
||||||
|
specificity: (0 << 20) + (0 << 10) + (1 << 0),
|
||||||
|
},
|
||||||
|
Selector {
|
||||||
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
|
simple_selectors: vec![
|
||||||
|
SimpleSelector::Namespace(ns!(HTML)),
|
||||||
|
SimpleSelector::LocalName(LocalName {
|
||||||
|
name: atom!(body),
|
||||||
|
lower_name: atom!(body),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
next: None,
|
||||||
|
}),
|
||||||
|
pseudo_element: None,
|
||||||
|
specificity: (0 << 20) + (0 << 10) + (1 << 0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
declarations: PropertyDeclarationBlock {
|
||||||
|
normal: Arc::new(vec![
|
||||||
|
PropertyDeclaration::Display(DeclaredValue::SpecifiedValue(
|
||||||
|
longhands::display::SpecifiedValue::block)),
|
||||||
|
]),
|
||||||
|
important: Arc::new(vec![]),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
CSSRule::Style(StyleRule {
|
||||||
|
selectors: vec![
|
||||||
|
Selector {
|
||||||
|
compound_selectors: Arc::new(CompoundSelector {
|
||||||
|
simple_selectors: vec![
|
||||||
|
SimpleSelector::Class(Atom::from_slice("ok")),
|
||||||
|
],
|
||||||
|
next: Some((box CompoundSelector {
|
||||||
|
simple_selectors: vec![
|
||||||
|
SimpleSelector::ID(Atom::from_slice("d1")),
|
||||||
|
],
|
||||||
|
next: None,
|
||||||
|
}, Combinator::Child)),
|
||||||
|
}),
|
||||||
|
pseudo_element: None,
|
||||||
|
specificity: (1 << 20) + (1 << 10) + (0 << 0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
declarations: PropertyDeclarationBlock {
|
||||||
|
normal: Arc::new(vec![
|
||||||
|
PropertyDeclaration::BackgroundImage(DeclaredValue::Initial),
|
||||||
|
PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial),
|
||||||
|
PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial),
|
||||||
|
PropertyDeclaration::BackgroundPosition(DeclaredValue::Initial),
|
||||||
|
PropertyDeclaration::BackgroundColor(DeclaredValue::SpecifiedValue(
|
||||||
|
longhands::background_color::SpecifiedValue {
|
||||||
|
authored: Some("blue".into_string()),
|
||||||
|
parsed: cssparser::Color::RGBA(cssparser::RGBA {
|
||||||
|
red: 0., green: 0., blue: 1., alpha: 1.
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
]),
|
||||||
|
important: Arc::new(vec![]),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -5,10 +5,6 @@
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
#![macro_escape]
|
#![macro_escape]
|
||||||
|
|
||||||
use url::{Url, UrlParser};
|
|
||||||
|
|
||||||
pub use servo_util::geometry::Au;
|
|
||||||
|
|
||||||
|
|
||||||
macro_rules! define_css_keyword_enum {
|
macro_rules! define_css_keyword_enum {
|
||||||
($name: ident: $( $css: expr => $variant: ident ),+,) => {
|
($name: ident: $( $css: expr => $variant: ident ),+,) => {
|
||||||
|
@ -22,14 +18,9 @@ macro_rules! define_css_keyword_enum {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $name {
|
impl $name {
|
||||||
pub fn parse(component_value: &::cssparser::ast::ComponentValue) -> Result<$name, ()> {
|
pub fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> {
|
||||||
match component_value {
|
match_ignore_ascii_case! { try!(input.expect_ident()):
|
||||||
&::cssparser::ast::ComponentValue::Ident(ref value) => {
|
$( $css => Ok($name::$variant) ),+
|
||||||
match_ignore_ascii_case! { value:
|
|
||||||
$( $css => Ok($name::$variant) ),+
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,12 +54,12 @@ pub mod specified {
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Formatter, Show};
|
use std::fmt::{Formatter, Show};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use cssparser::{mod, ToCss, CssStringWriter};
|
use cssparser::{mod, Token, Parser, ToCss, CssStringWriter};
|
||||||
use cssparser::ast::*;
|
use parser::ParserContext;
|
||||||
use cssparser::ast::ComponentValue::*;
|
|
||||||
use text_writer::{mod, TextWriter};
|
use text_writer::{mod, TextWriter};
|
||||||
use parsing_utils::{mod, BufferedIter, ParserIter};
|
use servo_util::geometry::Au;
|
||||||
use super::{Au, CSSFloat};
|
use super::CSSFloat;
|
||||||
|
use super::computed;
|
||||||
|
|
||||||
#[deriving(Clone, PartialEq)]
|
#[deriving(Clone, PartialEq)]
|
||||||
pub struct CSSColor {
|
pub struct CSSColor {
|
||||||
|
@ -76,17 +67,16 @@ pub mod specified {
|
||||||
pub authored: Option<String>,
|
pub authored: Option<String>,
|
||||||
}
|
}
|
||||||
impl CSSColor {
|
impl CSSColor {
|
||||||
pub fn parse(component_value: &ComponentValue) -> Result<CSSColor, ()> {
|
pub fn parse(input: &mut Parser) -> Result<CSSColor, ()> {
|
||||||
let parsed = cssparser::Color::parse(component_value);
|
let start_position = input.position();
|
||||||
parsed.map(|parsed| {
|
let authored = match input.next() {
|
||||||
let authored = match component_value {
|
Ok(Token::Ident(s)) => Some(s.into_owned()),
|
||||||
&Ident(ref s) => Some(s.clone()),
|
_ => None,
|
||||||
_ => None,
|
};
|
||||||
};
|
input.reset(start_position);
|
||||||
CSSColor {
|
Ok(CSSColor {
|
||||||
parsed: parsed,
|
parsed: try!(cssparser::Color::parse(input)),
|
||||||
authored: authored,
|
authored: authored,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +94,7 @@ pub mod specified {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone, PartialEq)]
|
||||||
pub struct CSSRGBA {
|
pub struct CSSRGBA {
|
||||||
pub parsed: cssparser::RGBA,
|
pub parsed: cssparser::RGBA,
|
||||||
pub authored: Option<String>,
|
pub authored: Option<String>,
|
||||||
|
@ -150,13 +140,6 @@ pub mod specified {
|
||||||
/// This cannot be specified by the user directly and is only generated by
|
/// This cannot be specified by the user directly and is only generated by
|
||||||
/// `Stylist::synthesize_rules_for_legacy_attributes()`.
|
/// `Stylist::synthesize_rules_for_legacy_attributes()`.
|
||||||
ServoCharacterWidth(i32),
|
ServoCharacterWidth(i32),
|
||||||
|
|
||||||
// XXX uncomment when supported:
|
|
||||||
// Ch(CSSFloat),
|
|
||||||
// Vw(CSSFloat),
|
|
||||||
// Vh(CSSFloat),
|
|
||||||
// Vmin(CSSFloat),
|
|
||||||
// Vmax(CSSFloat),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Show for Length {
|
impl fmt::Show for Length {
|
||||||
|
@ -184,23 +167,24 @@ pub mod specified {
|
||||||
const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
|
const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
|
||||||
impl Length {
|
impl Length {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Result<Length, ()> {
|
fn parse_internal(input: &mut Parser, negative_ok: bool) -> Result<Length, ()> {
|
||||||
match input {
|
match try!(input.next()) {
|
||||||
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
|
Token::Dimension(ref value, ref unit) if negative_ok || value.value >= 0. => {
|
||||||
=> Length::parse_dimension(value.value, unit.as_slice()),
|
Length::parse_dimension(value.value, unit.as_slice())
|
||||||
&Number(ref value) if value.value == 0. => Ok(Length::Au(Au(0))),
|
}
|
||||||
|
Token::Number(ref value) if value.value == 0. => Ok(Length::Au(Au(0))),
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn parse(input: &ComponentValue) -> Result<Length, ()> {
|
pub fn parse(input: &mut Parser) -> Result<Length, ()> {
|
||||||
Length::parse_internal(input, /* negative_ok = */ true)
|
Length::parse_internal(input, /* negative_ok = */ true)
|
||||||
}
|
}
|
||||||
pub fn parse_non_negative(input: &ComponentValue) -> Result<Length, ()> {
|
pub fn parse_non_negative(input: &mut Parser) -> Result<Length, ()> {
|
||||||
Length::parse_internal(input, /* negative_ok = */ false)
|
Length::parse_internal(input, /* negative_ok = */ false)
|
||||||
}
|
}
|
||||||
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
|
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
|
||||||
match unit.to_ascii_lower().as_slice() {
|
match_ignore_ascii_case! { unit:
|
||||||
"px" => Ok(Length::from_px(value)),
|
"px" => Ok(Length::from_px(value)),
|
||||||
"in" => Ok(Length::Au(Au((value * AU_PER_IN) as i32))),
|
"in" => Ok(Length::Au(Au((value * AU_PER_IN) as i32))),
|
||||||
"cm" => Ok(Length::Au(Au((value * AU_PER_CM) as i32))),
|
"cm" => Ok(Length::Au(Au((value * AU_PER_CM) as i32))),
|
||||||
|
@ -209,7 +193,7 @@ pub mod specified {
|
||||||
"pc" => Ok(Length::Au(Au((value * AU_PER_PC) as i32))),
|
"pc" => Ok(Length::Au(Au((value * AU_PER_PC) as i32))),
|
||||||
"em" => Ok(Length::Em(value)),
|
"em" => Ok(Length::Em(value)),
|
||||||
"ex" => Ok(Length::Ex(value)),
|
"ex" => Ok(Length::Ex(value)),
|
||||||
"rem" => Ok(Length::Rem(value)),
|
"rem" => Ok(Length::Rem(value))
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,6 +203,7 @@ pub mod specified {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[deriving(Clone, PartialEq, Copy)]
|
#[deriving(Clone, PartialEq, Copy)]
|
||||||
pub enum LengthOrPercentage {
|
pub enum LengthOrPercentage {
|
||||||
Length(Length),
|
Length(Length),
|
||||||
|
@ -239,26 +224,29 @@ pub mod specified {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl LengthOrPercentage {
|
impl LengthOrPercentage {
|
||||||
fn parse_internal(input: &ComponentValue, negative_ok: bool)
|
fn parse_internal(input: &mut Parser, negative_ok: bool)
|
||||||
-> Result<LengthOrPercentage, ()> {
|
-> Result<LengthOrPercentage, ()> {
|
||||||
match input {
|
match try!(input.next()) {
|
||||||
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0. =>
|
Token::Dimension(ref value, ref unit) if negative_ok || value.value >= 0. => {
|
||||||
Length::parse_dimension(value.value, unit.as_slice())
|
Length::parse_dimension(value.value, unit.as_slice())
|
||||||
.map(LengthOrPercentage::Length),
|
.map(LengthOrPercentage::Length)
|
||||||
&Percentage(ref value) if negative_ok || value.value >= 0. =>
|
}
|
||||||
Ok(LengthOrPercentage::Percentage(value.value / 100.)),
|
Token::Percentage(ref value) if negative_ok || value.unit_value >= 0. => {
|
||||||
&Number(ref value) if value.value == 0. =>
|
Ok(LengthOrPercentage::Percentage(value.unit_value))
|
||||||
Ok(LengthOrPercentage::Length(Length::Au(Au(0)))),
|
}
|
||||||
|
Token::Number(ref value) if value.value == 0. => {
|
||||||
|
Ok(LengthOrPercentage::Length(Length::Au(Au(0))))
|
||||||
|
}
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn parse(input: &ComponentValue) -> Result<LengthOrPercentage, ()> {
|
pub fn parse(input: &mut Parser) -> Result<LengthOrPercentage, ()> {
|
||||||
LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
|
LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn parse_non_negative(input: &ComponentValue) -> Result<LengthOrPercentage, ()> {
|
pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentage, ()> {
|
||||||
LengthOrPercentage::parse_internal(input, /* negative_ok = */ false)
|
LengthOrPercentage::parse_internal(input, /* negative_ok = */ false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,26 +273,31 @@ pub mod specified {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl LengthOrPercentageOrAuto {
|
impl LengthOrPercentageOrAuto {
|
||||||
fn parse_internal(input: &ComponentValue, negative_ok: bool)
|
fn parse_internal(input: &mut Parser, negative_ok: bool)
|
||||||
-> Result<LengthOrPercentageOrAuto, ()> {
|
-> Result<LengthOrPercentageOrAuto, ()> {
|
||||||
match input {
|
match try!(input.next()) {
|
||||||
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0. =>
|
Token::Dimension(ref value, ref unit) if negative_ok || value.value >= 0. => {
|
||||||
Length::parse_dimension(value.value, unit.as_slice()).map(LengthOrPercentageOrAuto::Length),
|
Length::parse_dimension(value.value, unit.as_slice())
|
||||||
&Percentage(ref value) if negative_ok || value.value >= 0. =>
|
.map(LengthOrPercentageOrAuto::Length)
|
||||||
Ok(LengthOrPercentageOrAuto::Percentage(value.value / 100.)),
|
}
|
||||||
&Number(ref value) if value.value == 0. =>
|
Token::Percentage(ref value) if negative_ok || value.unit_value >= 0. => {
|
||||||
Ok(LengthOrPercentageOrAuto::Length(Length::Au(Au(0)))),
|
Ok(LengthOrPercentageOrAuto::Percentage(value.unit_value))
|
||||||
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("auto") =>
|
}
|
||||||
Ok(LengthOrPercentageOrAuto::Auto),
|
Token::Number(ref value) if value.value == 0. => {
|
||||||
|
Ok(LengthOrPercentageOrAuto::Length(Length::Au(Au(0))))
|
||||||
|
}
|
||||||
|
Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => {
|
||||||
|
Ok(LengthOrPercentageOrAuto::Auto)
|
||||||
|
}
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn parse(input: &ComponentValue) -> Result<LengthOrPercentageOrAuto, ()> {
|
pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> {
|
||||||
LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ true)
|
LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ true)
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn parse_non_negative(input: &ComponentValue) -> Result<LengthOrPercentageOrAuto, ()> {
|
pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> {
|
||||||
LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ false)
|
LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -331,25 +324,32 @@ pub mod specified {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl LengthOrPercentageOrNone {
|
impl LengthOrPercentageOrNone {
|
||||||
fn parse_internal(input: &ComponentValue, negative_ok: bool)
|
fn parse_internal(input: &mut Parser, negative_ok: bool)
|
||||||
-> Result<LengthOrPercentageOrNone, ()> {
|
-> Result<LengthOrPercentageOrNone, ()> {
|
||||||
match input {
|
match try!(input.next()) {
|
||||||
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
|
Token::Dimension(ref value, ref unit) if negative_ok || value.value >= 0. => {
|
||||||
=> Length::parse_dimension(value.value, unit.as_slice()).map(LengthOrPercentageOrNone::Length),
|
Length::parse_dimension(value.value, unit.as_slice())
|
||||||
&Percentage(ref value) if negative_ok || value.value >= 0.
|
.map(LengthOrPercentageOrNone::Length)
|
||||||
=> Ok(LengthOrPercentageOrNone::Percentage(value.value / 100.)),
|
}
|
||||||
&Number(ref value) if value.value == 0. => Ok(LengthOrPercentageOrNone::Length(Length::Au(Au(0)))),
|
Token::Percentage(ref value) if negative_ok || value.unit_value >= 0. => {
|
||||||
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("none") => Ok(LengthOrPercentageOrNone::None),
|
Ok(LengthOrPercentageOrNone::Percentage(value.unit_value))
|
||||||
|
}
|
||||||
|
Token::Number(ref value) if value.value == 0. => {
|
||||||
|
Ok(LengthOrPercentageOrNone::Length(Length::Au(Au(0))))
|
||||||
|
}
|
||||||
|
Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => {
|
||||||
|
Ok(LengthOrPercentageOrNone::None)
|
||||||
|
}
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn parse(input: &ComponentValue) -> Result<LengthOrPercentageOrNone, ()> {
|
pub fn parse(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> {
|
||||||
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ true)
|
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ true)
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn parse_non_negative(input: &ComponentValue) -> Result<LengthOrPercentageOrNone, ()> {
|
pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> {
|
||||||
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ false)
|
LengthOrPercentageOrNone::parse_internal(input, /* negative_ok = */ false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,19 +366,27 @@ pub mod specified {
|
||||||
Bottom,
|
Bottom,
|
||||||
}
|
}
|
||||||
impl PositionComponent {
|
impl PositionComponent {
|
||||||
pub fn parse(input: &ComponentValue) -> Result<PositionComponent, ()> {
|
pub fn parse(input: &mut Parser) -> Result<PositionComponent, ()> {
|
||||||
match input {
|
match try!(input.next()) {
|
||||||
&Dimension(ref value, ref unit) =>
|
Token::Dimension(ref value, ref unit) => {
|
||||||
Length::parse_dimension(value.value, unit.as_slice()).map(PositionComponent::Length),
|
Length::parse_dimension(value.value, unit.as_slice())
|
||||||
&Percentage(ref value) => Ok(PositionComponent::Percentage(value.value / 100.)),
|
.map(PositionComponent::Length)
|
||||||
&Number(ref value) if value.value == 0. => Ok(PositionComponent::Length(Length::Au(Au(0)))),
|
}
|
||||||
&Ident(ref value) => {
|
Token::Percentage(ref value) => {
|
||||||
if value.as_slice().eq_ignore_ascii_case("center") { Ok(PositionComponent::Center) }
|
Ok(PositionComponent::Percentage(value.unit_value))
|
||||||
else if value.as_slice().eq_ignore_ascii_case("left") { Ok(PositionComponent::Left) }
|
}
|
||||||
else if value.as_slice().eq_ignore_ascii_case("right") { Ok(PositionComponent::Right) }
|
Token::Number(ref value) if value.value == 0. => {
|
||||||
else if value.as_slice().eq_ignore_ascii_case("top") { Ok(PositionComponent::Top) }
|
Ok(PositionComponent::Length(Length::Au(Au(0))))
|
||||||
else if value.as_slice().eq_ignore_ascii_case("bottom") { Ok(PositionComponent::Bottom) }
|
}
|
||||||
else { Err(()) }
|
Token::Ident(value) => {
|
||||||
|
match_ignore_ascii_case! { value:
|
||||||
|
"center" => Ok(PositionComponent::Center),
|
||||||
|
"left" => Ok(PositionComponent::Left),
|
||||||
|
"right" => Ok(PositionComponent::Right),
|
||||||
|
"top" => Ok(PositionComponent::Top),
|
||||||
|
"bottom" => Ok(PositionComponent::Bottom)
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
|
@ -389,8 +397,10 @@ pub mod specified {
|
||||||
PositionComponent::Length(x) => LengthOrPercentage::Length(x),
|
PositionComponent::Length(x) => LengthOrPercentage::Length(x),
|
||||||
PositionComponent::Percentage(x) => LengthOrPercentage::Percentage(x),
|
PositionComponent::Percentage(x) => LengthOrPercentage::Percentage(x),
|
||||||
PositionComponent::Center => LengthOrPercentage::Percentage(0.5),
|
PositionComponent::Center => LengthOrPercentage::Percentage(0.5),
|
||||||
PositionComponent::Left | PositionComponent::Top => LengthOrPercentage::Percentage(0.0),
|
PositionComponent::Left |
|
||||||
PositionComponent::Right | PositionComponent::Bottom => LengthOrPercentage::Percentage(1.0),
|
PositionComponent::Top => LengthOrPercentage::Percentage(0.0),
|
||||||
|
PositionComponent::Right |
|
||||||
|
PositionComponent::Bottom => LengthOrPercentage::Percentage(1.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -416,30 +426,24 @@ pub mod specified {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEG_TO_RAD: CSSFloat = PI / 180.0;
|
const RAD_PER_DEG: CSSFloat = PI / 180.0;
|
||||||
static GRAD_TO_RAD: CSSFloat = PI / 200.0;
|
const RAD_PER_GRAD: CSSFloat = PI / 200.0;
|
||||||
|
const RAD_PER_TURN: CSSFloat = PI * 2.0;
|
||||||
|
|
||||||
impl Angle {
|
impl Angle {
|
||||||
/// Parses an angle according to CSS-VALUES § 6.1.
|
/// Parses an angle according to CSS-VALUES § 6.1.
|
||||||
fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle,()> {
|
pub fn parse(input: &mut Parser) -> Result<Angle, ()> {
|
||||||
if unit.eq_ignore_ascii_case("deg") {
|
match try!(input.next()) {
|
||||||
Ok(Angle(value * DEG_TO_RAD))
|
Token::Dimension(value, unit) => {
|
||||||
} else if unit.eq_ignore_ascii_case("grad") {
|
match_ignore_ascii_case! { unit:
|
||||||
Ok(Angle(value * GRAD_TO_RAD))
|
"deg" => Ok(Angle(value.value * RAD_PER_DEG)),
|
||||||
} else if unit.eq_ignore_ascii_case("rad") {
|
"grad" => Ok(Angle(value.value * RAD_PER_GRAD)),
|
||||||
Ok(Angle(value))
|
"turn" => Ok(Angle(value.value * RAD_PER_TURN)),
|
||||||
} else if unit.eq_ignore_ascii_case("turn") {
|
"rad" => Ok(Angle(value.value))
|
||||||
Ok(Angle(value * 2.0 * PI))
|
_ => Err(())
|
||||||
} else {
|
}
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Parses an angle from a token according to CSS-VALUES § 6.1.
|
|
||||||
pub fn parse(value: &ComponentValue) -> Result<Angle,()> {
|
|
||||||
match *value {
|
|
||||||
Dimension(ref value, ref unit) => {
|
|
||||||
Angle::parse_dimension(value.value, unit.as_slice())
|
|
||||||
}
|
}
|
||||||
|
Token::Number(ref value) if value.value == 0. => Ok(Angle(0.)),
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,33 +475,30 @@ pub mod specified {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Image {
|
impl Image {
|
||||||
pub fn from_component_value(component_value: &ComponentValue, base_url: &Url)
|
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> {
|
||||||
-> Result<Image,()> {
|
match try!(input.next()) {
|
||||||
match component_value {
|
Token::Url(url) => {
|
||||||
&URL(ref url) => {
|
Ok(Image::Url(context.parse_url(url.as_slice())))
|
||||||
let image_url = super::parse_url(url.as_slice(), base_url);
|
}
|
||||||
Ok(Image::Url(image_url))
|
Token::Function(name) => {
|
||||||
},
|
match_ignore_ascii_case! { name:
|
||||||
&Function(ref name, ref args) => {
|
"linear-gradient" => {
|
||||||
if name.as_slice().eq_ignore_ascii_case("linear-gradient") {
|
Ok(Image::LinearGradient(try!(
|
||||||
Ok(Image::LinearGradient(try!(
|
input.parse_nested_block(LinearGradient::parse_function))))
|
||||||
super::specified::LinearGradient::parse_function(
|
}
|
||||||
args.as_slice()))))
|
_ => Err(())
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Err(()),
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_computed_value(self, context: &super::computed::Context)
|
pub fn to_computed_value(self, context: &computed::Context) -> computed::Image {
|
||||||
-> super::computed::Image {
|
|
||||||
match self {
|
match self {
|
||||||
Image::Url(url) => super::computed::Image::Url(url),
|
Image::Url(url) => computed::Image::Url(url),
|
||||||
Image::LinearGradient(linear_gradient) => {
|
Image::LinearGradient(linear_gradient) => {
|
||||||
super::computed::Image::LinearGradient(
|
computed::Image::LinearGradient(
|
||||||
super::computed::LinearGradient::compute(linear_gradient, context))
|
computed::LinearGradient::compute(linear_gradient, context))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -585,154 +586,105 @@ pub mod specified {
|
||||||
define_css_keyword_enum!(HorizontalDirection: "left" => Left, "right" => Right)
|
define_css_keyword_enum!(HorizontalDirection: "left" => Left, "right" => Right)
|
||||||
define_css_keyword_enum!(VerticalDirection: "top" => Top, "bottom" => Bottom)
|
define_css_keyword_enum!(VerticalDirection: "top" => Top, "bottom" => Bottom)
|
||||||
|
|
||||||
fn parse_color_stop(source: ParserIter) -> Result<ColorStop,()> {
|
fn parse_one_color_stop(input: &mut Parser) -> Result<ColorStop, ()> {
|
||||||
let color = match source.next() {
|
|
||||||
Some(color) => try!(CSSColor::parse(color)),
|
|
||||||
None => return Err(()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let position = match source.next() {
|
|
||||||
None => None,
|
|
||||||
Some(value) => {
|
|
||||||
match *value {
|
|
||||||
Comma => {
|
|
||||||
source.push_back(value);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
ref position => Some(try!(LengthOrPercentage::parse(position))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(ColorStop {
|
Ok(ColorStop {
|
||||||
color: color,
|
color: try!(CSSColor::parse(input)),
|
||||||
position: position,
|
position: input.try(LengthOrPercentage::parse).ok(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LinearGradient {
|
impl LinearGradient {
|
||||||
/// Parses a linear gradient from the given arguments.
|
/// Parses a linear gradient from the given arguments.
|
||||||
pub fn parse_function(args: &[ComponentValue]) -> Result<LinearGradient,()> {
|
pub fn parse_function(input: &mut Parser) -> Result<LinearGradient, ()> {
|
||||||
let mut source = BufferedIter::new(args.skip_whitespace());
|
let angle_or_corner = if input.try(|input| input.expect_ident_matching("to")).is_ok() {
|
||||||
|
let (horizontal, vertical) =
|
||||||
// Parse the angle.
|
if let Ok(value) = input.try(HorizontalDirection::parse) {
|
||||||
let (angle_or_corner, need_to_parse_comma) = match source.next() {
|
(Some(value), input.try(VerticalDirection::parse).ok())
|
||||||
None => return Err(()),
|
} else {
|
||||||
Some(token) => {
|
let value = try!(VerticalDirection::parse(input));
|
||||||
match *token {
|
(input.try(HorizontalDirection::parse).ok(), Some(value))
|
||||||
Dimension(ref value, ref unit) => {
|
};
|
||||||
match Angle::parse_dimension(value.value, unit.as_slice()) {
|
try!(input.expect_comma());
|
||||||
Ok(angle) => {
|
match (horizontal, vertical) {
|
||||||
(AngleOrCorner::Angle(angle), true)
|
(None, Some(VerticalDirection::Top)) => {
|
||||||
}
|
AngleOrCorner::Angle(Angle(0.0))
|
||||||
Err(()) => {
|
},
|
||||||
source.push_back(token);
|
(Some(HorizontalDirection::Right), None) => {
|
||||||
(AngleOrCorner::Angle(Angle(PI)), false)
|
AngleOrCorner::Angle(Angle(PI * 0.5))
|
||||||
}
|
},
|
||||||
}
|
(None, Some(VerticalDirection::Bottom)) => {
|
||||||
}
|
AngleOrCorner::Angle(Angle(PI))
|
||||||
Ident(ref ident) if ident.as_slice().eq_ignore_ascii_case("to") => {
|
},
|
||||||
let (mut horizontal, mut vertical) = (None, None);
|
(Some(HorizontalDirection::Left), None) => {
|
||||||
loop {
|
AngleOrCorner::Angle(Angle(PI * 1.5))
|
||||||
match source.next() {
|
},
|
||||||
None => break,
|
(Some(horizontal), Some(vertical)) => {
|
||||||
Some(token) => {
|
AngleOrCorner::Corner(horizontal, vertical)
|
||||||
match *token {
|
|
||||||
Ident(ref ident) => {
|
|
||||||
let ident = ident.as_slice();
|
|
||||||
if ident.eq_ignore_ascii_case("top") &&
|
|
||||||
vertical.is_none() {
|
|
||||||
vertical = Some(VerticalDirection::Top)
|
|
||||||
} else if ident.eq_ignore_ascii_case("bottom") &&
|
|
||||||
vertical.is_none() {
|
|
||||||
vertical = Some(VerticalDirection::Bottom)
|
|
||||||
} else if ident.eq_ignore_ascii_case("left") &&
|
|
||||||
horizontal.is_none() {
|
|
||||||
horizontal = Some(HorizontalDirection::Left)
|
|
||||||
} else if ident.eq_ignore_ascii_case("right") &&
|
|
||||||
horizontal.is_none() {
|
|
||||||
horizontal = Some(HorizontalDirection::Right)
|
|
||||||
} else {
|
|
||||||
return Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Comma => {
|
|
||||||
source.push_back(token);
|
|
||||||
break
|
|
||||||
}
|
|
||||||
_ => return Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(match (horizontal, vertical) {
|
|
||||||
(None, Some(VerticalDirection::Top)) => {
|
|
||||||
AngleOrCorner::Angle(Angle(0.0))
|
|
||||||
},
|
|
||||||
(Some(HorizontalDirection::Right), None) => {
|
|
||||||
AngleOrCorner::Angle(Angle(PI * 0.5))
|
|
||||||
},
|
|
||||||
(None, Some(VerticalDirection::Bottom)) => {
|
|
||||||
AngleOrCorner::Angle(Angle(PI))
|
|
||||||
},
|
|
||||||
(Some(HorizontalDirection::Left), None) => {
|
|
||||||
AngleOrCorner::Angle(Angle(PI * 1.5))
|
|
||||||
},
|
|
||||||
(Some(horizontal), Some(vertical)) => {
|
|
||||||
AngleOrCorner::Corner(horizontal, vertical)
|
|
||||||
}
|
|
||||||
(None, None) => return Err(()),
|
|
||||||
}, true)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
source.push_back(token);
|
|
||||||
(AngleOrCorner::Angle(Angle(PI)), false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
(None, None) => unreachable!(),
|
||||||
}
|
}
|
||||||
};
|
} else if let Ok(angle) = input.try(Angle::parse) {
|
||||||
|
try!(input.expect_comma());
|
||||||
// Parse the color stops.
|
AngleOrCorner::Angle(angle)
|
||||||
let stops = if need_to_parse_comma {
|
|
||||||
match source.next() {
|
|
||||||
Some(&Comma) => {
|
|
||||||
try!(parsing_utils::parse_comma_separated(&mut source, parse_color_stop))
|
|
||||||
}
|
|
||||||
None => Vec::new(),
|
|
||||||
Some(_) => return Err(()),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
try!(parsing_utils::parse_comma_separated(&mut source, parse_color_stop))
|
AngleOrCorner::Angle(Angle(PI))
|
||||||
};
|
};
|
||||||
|
// Parse the color stops.
|
||||||
|
let stops = try!(input.parse_comma_separated(parse_one_color_stop));
|
||||||
if stops.len() < 2 {
|
if stops.len() < 2 {
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(LinearGradient {
|
Ok(LinearGradient {
|
||||||
angle_or_corner: angle_or_corner,
|
angle_or_corner: angle_or_corner,
|
||||||
stops: stops,
|
stops: stops,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn parse_border_width(input: &mut Parser) -> Result<Length, ()> {
|
||||||
|
input.try(Length::parse_non_negative).or_else(|()| {
|
||||||
|
match_ignore_ascii_case! { try!(input.expect_ident()):
|
||||||
|
"thin" => Ok(Length::from_px(1.)),
|
||||||
|
"medium" => Ok(Length::from_px(3.)),
|
||||||
|
"thick" => Ok(Length::from_px(5.))
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
define_css_keyword_enum! { BorderStyle:
|
||||||
|
"none" => none,
|
||||||
|
"solid" => solid,
|
||||||
|
"double" => double,
|
||||||
|
"dotted" => dotted,
|
||||||
|
"dashed" => dashed,
|
||||||
|
"hidden" => hidden,
|
||||||
|
"groove" => groove,
|
||||||
|
"ridge" => ridge,
|
||||||
|
"inset" => inset,
|
||||||
|
"outset" => outset,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub mod computed {
|
pub mod computed {
|
||||||
pub use super::specified::{Angle, AngleOrCorner, HorizontalDirection};
|
pub use super::specified::BorderStyle;
|
||||||
pub use super::specified::{VerticalDirection};
|
use super::specified::{AngleOrCorner};
|
||||||
|
use super::{specified, CSSFloat};
|
||||||
pub use cssparser::Color as CSSColor;
|
pub use cssparser::Color as CSSColor;
|
||||||
use super::*;
|
use properties::longhands;
|
||||||
use super::super::longhands;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
use servo_util::geometry::Au;
|
||||||
|
|
||||||
#[allow(missing_copy_implementations)] // It’s kinda big
|
#[allow(missing_copy_implementations)] // It’s kinda big
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub inherited_font_weight: longhands::font_weight::computed_value::T,
|
pub inherited_font_weight: longhands::font_weight::computed_value::T,
|
||||||
pub inherited_font_size: longhands::font_size::computed_value::T,
|
pub inherited_font_size: longhands::font_size::computed_value::T,
|
||||||
pub inherited_text_decorations_in_effect: longhands::_servo_text_decorations_in_effect::T,
|
pub inherited_text_decorations_in_effect:
|
||||||
pub inherited_height: longhands::height::T,
|
longhands::_servo_text_decorations_in_effect::computed_value::T,
|
||||||
|
pub inherited_height: longhands::height::computed_value::T,
|
||||||
pub color: longhands::color::computed_value::T,
|
pub color: longhands::color::computed_value::T,
|
||||||
pub text_decoration: longhands::text_decoration::computed_value::T,
|
pub text_decoration: longhands::text_decoration::computed_value::T,
|
||||||
pub font_size: longhands::font_size::computed_value::T,
|
pub font_size: longhands::font_size::computed_value::T,
|
||||||
|
@ -750,10 +702,16 @@ pub mod computed {
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn compute_CSSColor(value: specified::CSSColor, _context: &computed::Context) -> CSSColor {
|
pub fn compute_CSSColor(value: specified::CSSColor, _context: &Context) -> CSSColor {
|
||||||
value.parsed
|
value.parsed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[inline]
|
||||||
|
pub fn compute_BorderStyle(value: BorderStyle, _context: &Context) -> BorderStyle {
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn compute_Au(value: specified::Length, context: &Context) -> Au {
|
pub fn compute_Au(value: specified::Length, context: &Context) -> Au {
|
||||||
|
@ -951,8 +909,3 @@ pub mod computed {
|
||||||
|
|
||||||
pub type Length = Au;
|
pub type Length = Au;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_url(input: &str, base_url: &Url) -> Url {
|
|
||||||
UrlParser::new().base_url(base_url).parse(input)
|
|
||||||
.unwrap_or_else(|_| Url::parse("about:invalid").unwrap())
|
|
||||||
}
|
|
45
ports/cef/Cargo.lock
generated
45
ports/cef/Cargo.lock
generated
|
@ -131,9 +131,10 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "git+https://github.com/servo/rust-cssparser#110bf3052d016bf6eda0689fb21cf971e2c23dc8"
|
source = "git+https://github.com/servo/rust-cssparser#8d1b3e220e795f7baaa940919059d5f4ef4ec28c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"matches 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"text_writer 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"text_writer 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -310,35 +311,6 @@ dependencies = [
|
||||||
"gl_generator 0.0.1 (git+https://github.com/bjz/gl-rs.git)",
|
"gl_generator 0.0.1 (git+https://github.com/bjz/gl-rs.git)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "glfw"
|
|
||||||
version = "0.0.1"
|
|
||||||
source = "git+https://github.com/servo/glfw-rs?ref=servo#b186cb444e349a36b992445dc5cb2c99d38f2a42"
|
|
||||||
dependencies = [
|
|
||||||
"glfw-sys 3.0.4 (git+https://github.com/servo/glfw?ref=cargo-3.0.4)",
|
|
||||||
"semver 0.1.4 (git+https://github.com/rust-lang/semver)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "glfw-sys"
|
|
||||||
version = "3.0.4"
|
|
||||||
source = "git+https://github.com/servo/glfw?ref=cargo-3.0.4#765dace7e4125b87c764f5ac0e7a80eae5c550b2"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "glfw_app"
|
|
||||||
version = "0.0.1"
|
|
||||||
dependencies = [
|
|
||||||
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
|
|
||||||
"compositing 0.0.1",
|
|
||||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
|
||||||
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
|
|
||||||
"glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo)",
|
|
||||||
"layers 0.1.0 (git+https://github.com/servo/rust-layers)",
|
|
||||||
"msg 0.0.1",
|
|
||||||
"time 0.1.0 (git+https://github.com/rust-lang/time)",
|
|
||||||
"util 0.0.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glutin"
|
name = "glutin"
|
||||||
version = "0.0.2"
|
version = "0.0.2"
|
||||||
|
@ -496,6 +468,11 @@ dependencies = [
|
||||||
"pnacl-build-helper 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pnacl-build-helper 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matches"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mime"
|
name = "mime"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -639,18 +616,13 @@ dependencies = [
|
||||||
"util 0.0.1",
|
"util 0.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "semver"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "git+https://github.com/rust-lang/semver#58dc6b1999d345ca925a2f12a6a84676e823e179"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo"
|
name = "servo"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compositing 0.0.1",
|
"compositing 0.0.1",
|
||||||
"gfx 0.0.1",
|
"gfx 0.0.1",
|
||||||
"glfw_app 0.0.1",
|
"glutin_app 0.0.1",
|
||||||
"layout 0.0.1",
|
"layout 0.0.1",
|
||||||
"msg 0.0.1",
|
"msg 0.0.1",
|
||||||
"net 0.0.1",
|
"net 0.0.1",
|
||||||
|
@ -702,6 +674,7 @@ dependencies = [
|
||||||
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||||
"lazy_static 0.1.0 (git+https://github.com/Kimundi/lazy-static.rs)",
|
"lazy_static 0.1.0 (git+https://github.com/Kimundi/lazy-static.rs)",
|
||||||
|
"matches 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"plugins 0.0.1",
|
"plugins 0.0.1",
|
||||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache)",
|
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||||
|
|
9
ports/gonk/Cargo.lock
generated
9
ports/gonk/Cargo.lock
generated
|
@ -102,9 +102,10 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "git+https://github.com/servo/rust-cssparser#110bf3052d016bf6eda0689fb21cf971e2c23dc8"
|
source = "git+https://github.com/servo/rust-cssparser#8d1b3e220e795f7baaa940919059d5f4ef4ec28c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"matches 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"text_writer 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"text_writer 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -410,6 +411,11 @@ dependencies = [
|
||||||
"pnacl-build-helper 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pnacl-build-helper 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matches"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mime"
|
name = "mime"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -610,6 +616,7 @@ dependencies = [
|
||||||
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||||
"lazy_static 0.1.0 (git+https://github.com/Kimundi/lazy-static.rs)",
|
"lazy_static 0.1.0 (git+https://github.com/Kimundi/lazy-static.rs)",
|
||||||
|
"matches 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"plugins 0.0.1",
|
"plugins 0.0.1",
|
||||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
"string_cache 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache)",
|
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache)",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue