Update rustc to revision 3dcd2157403163789aaf21a9ab3c4d30a7c6494d.

This commit is contained in:
Ms2ger 2014-12-17 10:42:52 +01:00 committed by Josh Matthews
parent b8900782b0
commit 466faac2a5
223 changed files with 4414 additions and 4105 deletions

View file

@ -8,8 +8,8 @@ use errors::{ErrorLoggerIterator, log_css_error};
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::FamilyName;
use stylesheets::{CSSRule, CSSFontFaceRule, CSSStyleRule, CSSMediaRule};
use properties::computed_values::font_family::FontFamily::FamilyName;
use stylesheets::CSSRule;
use media_queries::Device;
use url::{Url, UrlParser};
@ -18,11 +18,11 @@ pub fn iter_font_face_rules_inner(rules: &[CSSRule], device: &Device,
callback: |family: &str, source: &Source|) {
for rule in rules.iter() {
match *rule {
CSSStyleRule(_) => {},
CSSMediaRule(ref rule) => if rule.media_queries.evaluate(device) {
CSSRule::Style(_) => {},
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))
},
CSSFontFaceRule(ref rule) => {
CSSRule::FontFace(ref rule) => {
for source in rule.sources.iter() {
callback(rule.family.as_slice(), source)
}
@ -33,8 +33,8 @@ pub fn iter_font_face_rules_inner(rules: &[CSSRule], device: &Device,
#[deriving(Clone)]
pub enum Source {
UrlSource_(UrlSource),
LocalSource(String),
Url(UrlSource),
Local(String),
}
#[deriving(Clone)]
@ -67,9 +67,9 @@ pub fn parse_font_face_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, base_
for item in ErrorLoggerIterator(parse_declaration_list(block.into_iter())) {
match item {
DeclAtRule(rule) => log_css_error(
DeclarationListItem::AtRule(rule) => log_css_error(
rule.location, format!("Unsupported at-rule in declaration list: @{:s}", rule.name).as_slice()),
Declaration_(Declaration{ location, name, value, important }) => {
DeclarationListItem::Declaration(Declaration{ location, name, value, important }) => {
if important {
log_css_error(location, "!important is not allowed on @font-face descriptors");
continue
@ -102,7 +102,7 @@ pub fn parse_font_face_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, base_
}
match (maybe_family, maybe_sources) {
(Some(family), Some(sources)) => parent_rules.push(CSSFontFaceRule(FontFaceRule {
(Some(family), Some(sources)) => parent_rules.push(CSSRule::FontFace(FontFaceRule {
family: family,
sources: sources,
})),
@ -124,7 +124,7 @@ fn parse_one_src(iter: ParserIter, base_url: &Url) -> Result<Source, ()> {
if name.as_slice().eq_ignore_ascii_case("local") {
let iter = &mut BufferedIter::new(arguments.as_slice().skip_whitespace());
match parse_one_family(iter) {
Ok(FamilyName(name)) => return Ok(LocalSource(name)),
Ok(FamilyName(name)) => return Ok(Source::Local(name)),
_ => return Err(())
}
}
@ -148,7 +148,7 @@ fn parse_one_src(iter: ParserIter, base_url: &Url) -> Result<Source, ()> {
None => vec![],
};
Ok(UrlSource_(UrlSource {
Ok(Source::Url(UrlSource {
url: url,
format_hints: format_hints,
}))

View file

@ -5,29 +5,32 @@
//! Legacy presentational attributes defined in the HTML5 specification: `<td width>`,
//! `<input size>`, and so forth.
use self::UnsignedIntegerAttribute::*;
use self::SimpleColorAttribute::*;
use node::{TElement, TElementAttributes, TNode};
use properties::{BackgroundColorDeclaration, BorderBottomWidthDeclaration, CSSFloat};
use properties::{BorderLeftWidthDeclaration, BorderRightWidthDeclaration, HeightDeclaration};
use properties::{BorderTopWidthDeclaration, SpecifiedValue, WidthDeclaration, specified};
use properties::DeclaredValue::SpecifiedValue;
use properties::PropertyDeclaration::*;
use properties::{CSSFloat, specified};
use selector_matching::{DeclarationBlock, Stylist};
use cssparser::RGBAColor;
use cssparser::Color;
use servo_util::geometry::Au;
use servo_util::smallvec::VecLike;
use servo_util::str::{AutoLpa, LengthLpa, PercentageLpa};
use servo_util::str::LengthOrPercentageOrAuto;
/// Legacy presentational attributes that take a length as defined in HTML5 § 2.4.4.4.
pub enum LengthAttribute {
/// `<td width>`
WidthLengthAttribute,
Width,
}
/// Legacy presentational attributes that take an integer as defined in HTML5 § 2.4.4.2.
pub enum IntegerAttribute {
/// `<input size>`
SizeIntegerAttribute,
ColsIntegerAttribute,
RowsIntegerAttribute,
Size,
Cols,
Rows,
}
/// Legacy presentational attributes that take a nonnegative integer as defined in HTML5 § 2.4.4.2.
@ -100,16 +103,16 @@ impl PresentationalHintSynthesis for Stylist {
let element = node.as_element();
match element.get_local_name() {
name if *name == atom!("td") => {
match element.get_length_attribute(WidthLengthAttribute) {
AutoLpa => {}
PercentageLpa(percentage) => {
let width_value = specified::LPA_Percentage(percentage);
match element.get_length_attribute(LengthAttribute::Width) {
LengthOrPercentageOrAuto::Auto => {}
LengthOrPercentageOrAuto::Percentage(percentage) => {
let width_value = specified::LengthOrPercentageOrAuto::Percentage(percentage);
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
WidthDeclaration(SpecifiedValue(width_value))));
*shareable = false
}
LengthLpa(length) => {
let width_value = specified::LPA_Length(specified::Au_(length));
LengthOrPercentageOrAuto::Length(length) => {
let width_value = specified::LengthOrPercentageOrAuto::Length(specified::Length::Au(length));
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
WidthDeclaration(SpecifiedValue(width_value))));
*shareable = false
@ -142,7 +145,7 @@ impl PresentationalHintSynthesis for Stylist {
shareable);
}
name if *name == atom!("input") => {
match element.get_integer_attribute(SizeIntegerAttribute) {
match element.get_integer_attribute(IntegerAttribute::Size) {
Some(value) if value != 0 => {
// Per HTML 4.01 § 17.4, this value is in characters if `type` is `text` or
// `password` and in pixels otherwise.
@ -150,12 +153,12 @@ impl PresentationalHintSynthesis for Stylist {
// FIXME(pcwalton): More use of atoms, please!
let value = match element.get_attr(&ns!(""), &atom!("type")) {
Some("text") | Some("password") => {
specified::ServoCharacterWidth(value)
specified::Length::ServoCharacterWidth(value)
}
_ => specified::Au_(Au::from_px(value as int)),
_ => specified::Length::Au(Au::from_px(value as int)),
};
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
WidthDeclaration(SpecifiedValue(specified::LPA_Length(
WidthDeclaration(SpecifiedValue(specified::LengthOrPercentageOrAuto::Length(
value)))));
*shareable = false
}
@ -163,29 +166,29 @@ impl PresentationalHintSynthesis for Stylist {
}
}
name if *name == atom!("textarea") => {
match element.get_integer_attribute(ColsIntegerAttribute) {
match element.get_integer_attribute(IntegerAttribute::Cols) {
Some(value) if value != 0 => {
// TODO(mttr) ServoCharacterWidth uses the size math for <input type="text">, but
// the math for <textarea> is a little different since we need to take
// scrollbar size into consideration (but we don't have a scrollbar yet!)
//
// https://html.spec.whatwg.org/multipage/rendering.html#textarea-effective-width
let value = specified::ServoCharacterWidth(value);
let value = specified::Length::ServoCharacterWidth(value);
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
WidthDeclaration(SpecifiedValue(specified::LPA_Length(
WidthDeclaration(SpecifiedValue(specified::LengthOrPercentageOrAuto::Length(
value)))));
*shareable = false
}
Some(_) | None => {}
}
match element.get_integer_attribute(RowsIntegerAttribute) {
match element.get_integer_attribute(IntegerAttribute::Rows) {
Some(value) if value != 0 => {
// TODO(mttr) This should take scrollbar size into consideration.
//
// https://html.spec.whatwg.org/multipage/rendering.html#textarea-effective-height
let value = specified::Em(value as CSSFloat);
let value = specified::Length::Em(value as CSSFloat);
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
HeightDeclaration(SpecifiedValue(specified::LPA_Length(
HeightDeclaration(SpecifiedValue(specified::LengthOrPercentageOrAuto::Length(
value)))));
*shareable = false
}
@ -211,7 +214,7 @@ impl PresentationalHintSynthesis for Stylist {
None => {}
Some(color) => {
matching_rules_list.vec_push(DeclarationBlock::from_declaration(
BackgroundColorDeclaration(SpecifiedValue(RGBAColor(color)))));
BackgroundColorDeclaration(SpecifiedValue(Color::RGBA(color)))));
*shareable = false
}
}
@ -229,7 +232,7 @@ impl PresentationalHintSynthesis for Stylist {
match element.get_unsigned_integer_attribute(BorderUnsignedIntegerAttribute) {
None => {}
Some(length) => {
let width_value = specified::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(
BorderTopWidthDeclaration(SpecifiedValue(width_value))));
matching_rules_list.vec_push(DeclarationBlock::from_declaration(

View file

@ -34,12 +34,11 @@ extern crate "util" as servo_util;
// Public API
pub use media_queries::{Device, Screen};
pub use media_queries::{Device, MediaType};
pub use stylesheets::{Stylesheet, iter_font_face_rules};
pub use selector_matching::{Stylist, StylesheetOrigin, UserAgentOrigin, AuthorOrigin, UserOrigin};
pub use selector_matching::{Stylist, StylesheetOrigin};
pub use selector_matching::{DeclarationBlock, CommonStyleAffectingAttributes};
pub use selector_matching::{CommonStyleAffectingAttributeInfo, CommonStyleAffectingAttributeMode};
pub use selector_matching::{AttrIsPresentMode, AttrIsEqualMode};
pub use selector_matching::{matches, matches_simple_selector, common_style_affecting_attributes};
pub use selector_matching::{rare_style_affecting_attributes};
pub use selector_matching::{RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE, SELECTOR_WHITESPACE};
@ -47,18 +46,16 @@ pub use properties::{cascade, cascade_anonymous, computed};
pub use properties::{PropertyDeclaration, ComputedValues, computed_values, style_structs};
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
pub use properties::{CSSFloat, DeclaredValue, PropertyDeclarationParseResult};
pub use properties::{Angle, AngleOrCorner, AngleAoc, CornerAoc};
pub use properties::{Left, Right, Bottom, Top};
pub use properties::{Angle, AngleOrCorner};
pub use properties::{HorizontalDirection, VerticalDirection};
pub use node::{TElement, TElementAttributes, TNode};
pub use selectors::{PseudoElement, Before, After, ParserContext, SelectorList};
pub use selectors::{AttrSelector, NamespaceConstraint, SpecificNamespace, AnyNamespace};
pub use selectors::{SimpleSelector, LocalNameSelector, parse_selector_list_from_str};
pub use selectors::{PseudoElement, ParserContext, SelectorList};
pub use selectors::{AttrSelector, NamespaceConstraint};
pub use selectors::{SimpleSelector, parse_selector_list_from_str};
pub use cssparser::{Color, RGBA};
pub use legacy::{BgColorSimpleColorAttribute, BorderUnsignedIntegerAttribute};
pub use legacy::{ColSpanUnsignedIntegerAttribute, IntegerAttribute, LengthAttribute};
pub use legacy::{SimpleColorAttribute, SizeIntegerAttribute, UnsignedIntegerAttribute};
pub use legacy::{WidthLengthAttribute, ColsIntegerAttribute, RowsIntegerAttribute};
pub use font_face::{Source, LocalSource, UrlSource_};
pub use legacy::{IntegerAttribute, LengthAttribute};
pub use legacy::{SimpleColorAttribute, UnsignedIntegerAttribute};
pub use font_face::Source;
mod stylesheets;
mod errors;

View file

@ -9,13 +9,12 @@ use cssparser::ast::*;
use errors::{ErrorLoggerIterator, log_css_error};
use geom::size::TypedSize2D;
use selectors::ParserContext;
use stylesheets::{CSSRule, CSSMediaRule};
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 servo_util::geometry::ViewportPx;
use stylesheets;
use url::Url;
pub struct MediaRule {
@ -36,9 +35,9 @@ pub enum Range<T> {
impl<T: Ord> Range<T> {
fn evaluate(&self, value: T) -> bool {
match *self {
Min(ref width) => { value >= *width },
Max(ref width) => { value <= *width },
//Eq(ref width) => { value == *width },
Range::Min(ref width) => { value >= *width },
Range::Max(ref width) => { value <= *width },
//Range::Eq(ref width) => { value == *width },
}
}
}
@ -73,7 +72,7 @@ impl MediaQuery {
#[deriving(PartialEq)]
pub enum MediaQueryType {
All, // Always true
MediaType_(MediaType),
MediaType(MediaType),
}
#[deriving(PartialEq)]
@ -113,20 +112,19 @@ pub fn parse_media_rule(context: &ParserContext,
let mut rules = vec!();
for rule in ErrorLoggerIterator(parse_rule_list(block.into_iter())) {
match rule {
QualifiedRule_(rule) => {
stylesheets::parse_style_rule(context, rule, &mut rules, namespaces, base_url)
}
AtRule_(rule) => {
stylesheets::parse_nested_at_rule(context,
rule.name.as_slice().to_ascii_lower().as_slice(),
rule,
&mut rules,
namespaces,
base_url)
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(CSSMediaRule(MediaRule {
parent_rules.push(CSSRule::Media(MediaRule {
media_queries: media_queries,
rules: rules,
}))
@ -166,11 +164,11 @@ fn parse_media_query_expression(iter: ParserIter) -> Result<Expression, ()> {
let expression = match variable.as_slice().to_ascii_lower().as_slice() {
"min-width" => {
let au = try!(parse_value_as_length(value));
Width(Min(au))
Expression::Width(Range::Min(au))
}
"max-width" => {
let au = try!(parse_value_as_length(value));
Width(Max(au))
Expression::Width(Range::Max(au))
}
_ => return Err(())
};
@ -190,8 +188,8 @@ fn parse_media_query(iter: ParserIter) -> Result<MediaQuery, ()> {
// Check for optional 'only' or 'not'
let qualifier = match iter.next() {
Some(&Ident(ref value)) if value.as_slice().to_ascii_lower().as_slice() == "only" => Some(Only),
Some(&Ident(ref value)) if value.as_slice().to_ascii_lower().as_slice() == "not" => Some(Not),
Some(&Ident(ref value)) if value.as_slice().to_ascii_lower().as_slice() == "only" => Some(Qualifier::Only),
Some(&Ident(ref value)) if value.as_slice().to_ascii_lower().as_slice() == "not" => Some(Qualifier::Not),
Some(component_value) => {
iter.push_back(component_value);
None
@ -203,10 +201,10 @@ fn parse_media_query(iter: ParserIter) -> Result<MediaQuery, ()> {
let media_type = match iter.next() {
Some(&Ident(ref value)) => {
match value.as_slice().to_ascii_lower().as_slice() {
"screen" => MediaType_(Screen),
"print" => MediaType_(Print),
"all" => All,
_ => MediaType_(Unknown), // Unknown media types never match
"screen" => MediaQueryType::MediaType(MediaType::Screen),
"print" => MediaQueryType::MediaType(MediaType::Print),
"all" => MediaQueryType::All,
_ => MediaQueryType::MediaType(MediaType::Unknown), // Unknown media types never match
}
}
Some(component_value) => {
@ -220,7 +218,7 @@ fn parse_media_query(iter: ParserIter) -> Result<MediaQuery, ()> {
let expression = try!(parse_media_query_expression(iter));
expressions.push(expression);
All
MediaQueryType::All
}
None => return Err(()),
};
@ -254,7 +252,7 @@ pub fn parse_media_query_list(input: &[ComponentValue]) -> MediaQueryList {
let mut media_queries = vec!();
if iter.is_eof() {
media_queries.push(MediaQuery::new(None, All, vec!()));
media_queries.push(MediaQuery::new(None, MediaQueryType::All, vec!()));
} else {
loop {
// Attempt to parse a media query.
@ -278,7 +276,7 @@ pub fn parse_media_query_list(input: &[ComponentValue]) -> MediaQueryList {
// 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(Not), All, vec!()),
_ => MediaQuery::new(Some(Qualifier::Not), MediaQueryType::All, vec!()),
};
media_queries.push(media_query);
@ -297,22 +295,22 @@ impl MediaQueryList {
self.media_queries.iter().any(|mq| {
// Check if media matches. Unknown media never matches.
let media_match = match mq.media_type {
MediaType_(Unknown) => false,
MediaType_(media_type) => media_type == device.media_type,
All => true,
MediaQueryType::MediaType(MediaType::Unknown) => false,
MediaQueryType::MediaType(media_type) => media_type == device.media_type,
MediaQueryType::All => true,
};
// Check if all conditions match (AND condition)
let query_match = media_match && mq.expressions.iter().all(|expression| {
match expression {
&Width(value) => value.evaluate(
&Expression::Width(value) => value.evaluate(
Au::from_frac_px(device.viewport_size.to_untyped().width as f64)),
}
});
// Apply the logical NOT qualifier to the result
match mq.qualifier {
Some(Not) => !query_match,
Some(Qualifier::Not) => !query_match,
_ => query_match,
}
})
@ -324,13 +322,14 @@ mod tests {
use geom::size::TypedSize2D;
use properties::common_types::*;
use stylesheets::{iter_stylesheet_media_rules, iter_stylesheet_style_rules, Stylesheet};
use selector_matching::AuthorOrigin;
use selector_matching::StylesheetOrigin;
use super::*;
use url::Url;
fn test_media_rule(css: &str, callback: |&MediaQueryList, &str|) {
let url = Url::parse("http://localhost").unwrap();
let stylesheet = Stylesheet::from_str(css, url, AuthorOrigin);
let stylesheet = Stylesheet::from_str(css, url,
StylesheetOrigin::Author);
let mut rule_count: int = 0;
iter_stylesheet_media_rules(&stylesheet, |rule| {
rule_count += 1;
@ -341,7 +340,7 @@ mod tests {
fn media_query_test(device: &Device, css: &str, expected_rule_count: int) {
let url = Url::parse("http://localhost").unwrap();
let ss = Stylesheet::from_str(css, url, AuthorOrigin);
let ss = Stylesheet::from_str(css, url, StylesheetOrigin::Author);
let mut rule_count: int = 0;
iter_stylesheet_style_rules(&ss, device, |_| rule_count += 1);
assert!(rule_count == expected_rule_count, css.to_string());
@ -353,7 +352,7 @@ mod tests {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == None, css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
}
@ -364,23 +363,23 @@ mod tests {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == None, css.to_string());
assert!(q.media_type == MediaType_(Screen), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media only screen { }", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Only), css.to_string());
assert!(q.media_type == MediaType_(Screen), css.to_string());
assert!(q.qualifier == Some(Qualifier::Only), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media not screen { }", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Not), css.to_string());
assert!(q.media_type == MediaType_(Screen), css.to_string());
assert!(q.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
}
@ -391,23 +390,23 @@ mod tests {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == None, css.to_string());
assert!(q.media_type == MediaType_(Print), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media only print { }", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Only), css.to_string());
assert!(q.media_type == MediaType_(Print), css.to_string());
assert!(q.qualifier == Some(Qualifier::Only), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media not print { }", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Not), css.to_string());
assert!(q.media_type == MediaType_(Print), css.to_string());
assert!(q.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
}
@ -418,23 +417,23 @@ mod tests {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == None, css.to_string());
assert!(q.media_type == MediaType_(Unknown), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media only glass { }", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Only), css.to_string());
assert!(q.media_type == MediaType_(Unknown), css.to_string());
assert!(q.qualifier == Some(Qualifier::Only), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media not wood { }", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Not), css.to_string());
assert!(q.media_type == MediaType_(Unknown), css.to_string());
assert!(q.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
}
@ -445,23 +444,23 @@ mod tests {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == None, css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media only all { }", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Only), css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.qualifier == Some(Qualifier::Only), css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media not all { }", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Not), css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
}
@ -472,12 +471,12 @@ mod tests {
assert!(list.media_queries.len() == 2, css.to_string());
let q0 = &list.media_queries[0];
assert!(q0.qualifier == None, css.to_string());
assert!(q0.media_type == MediaType_(Screen), css.to_string());
assert!(q0.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_string());
assert!(q0.expressions.len() == 0, css.to_string());
let q1 = &list.media_queries[1];
assert!(q1.qualifier == None, css.to_string());
assert!(q1.media_type == MediaType_(Print), css.to_string());
assert!(q1.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_string());
assert!(q1.expressions.len() == 0, css.to_string());
});
}
@ -488,10 +487,10 @@ mod tests {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == None, css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 1, css.to_string());
match q.expressions[0] {
Width(Min(w)) => assert!(w == Au::from_px(100)),
Expression::Width(Range::Min(w)) => assert!(w == Au::from_px(100)),
_ => panic!("wrong expression type"),
}
});
@ -500,10 +499,10 @@ mod tests {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == None, css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 1, css.to_string());
match q.expressions[0] {
Width(Max(w)) => assert!(w == Au::from_px(43)),
Expression::Width(Range::Max(w)) => assert!(w == Au::from_px(43)),
_ => panic!("wrong expression type"),
}
});
@ -515,10 +514,10 @@ mod tests {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == None, css.to_string());
assert!(q.media_type == MediaType_(Screen), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_string());
assert!(q.expressions.len() == 1, css.to_string());
match q.expressions[0] {
Width(Min(w)) => assert!(w == Au::from_px(100)),
Expression::Width(Range::Min(w)) => assert!(w == Au::from_px(100)),
_ => panic!("wrong expression type"),
}
});
@ -527,10 +526,10 @@ mod tests {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == None, css.to_string());
assert!(q.media_type == MediaType_(Print), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_string());
assert!(q.expressions.len() == 1, css.to_string());
match q.expressions[0] {
Width(Max(w)) => assert!(w == Au::from_px(43)),
Expression::Width(Range::Max(w)) => assert!(w == Au::from_px(43)),
_ => panic!("wrong expression type"),
}
});
@ -539,10 +538,10 @@ mod tests {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == None, css.to_string());
assert!(q.media_type == MediaType_(Unknown), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_string());
assert!(q.expressions.len() == 1, css.to_string());
match q.expressions[0] {
Width(Max(w)) => assert!(w == Au::from_px(52)),
Expression::Width(Range::Max(w)) => assert!(w == Au::from_px(52)),
_ => panic!("wrong expression type"),
}
});
@ -554,14 +553,14 @@ mod tests {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == None, css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 2, css.to_string());
match q.expressions[0] {
Width(Min(w)) => assert!(w == Au::from_px(100)),
Expression::Width(Range::Min(w)) => assert!(w == Au::from_px(100)),
_ => panic!("wrong expression type"),
}
match q.expressions[1] {
Width(Max(w)) => assert!(w == Au::from_px(200)),
Expression::Width(Range::Max(w)) => assert!(w == Au::from_px(200)),
_ => panic!("wrong expression type"),
}
});
@ -569,15 +568,15 @@ mod tests {
test_media_rule("@media not screen and (min-width: 100px) and (max-width: 200px) { }", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Not), css.to_string());
assert!(q.media_type == MediaType_(Screen), css.to_string());
assert!(q.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_string());
assert!(q.expressions.len() == 2, css.to_string());
match q.expressions[0] {
Width(Min(w)) => assert!(w == Au::from_px(100)),
Expression::Width(Range::Min(w)) => assert!(w == Au::from_px(100)),
_ => panic!("wrong expression type"),
}
match q.expressions[1] {
Width(Max(w)) => assert!(w == Au::from_px(200)),
Expression::Width(Range::Max(w)) => assert!(w == Au::from_px(200)),
_ => panic!("wrong expression type"),
}
});
@ -588,60 +587,60 @@ mod tests {
test_media_rule("@media (min-width: 100blah) and (max-width: 200px) { }", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Not), css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media screen and (height: 200px) { }", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Not), css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media (min-width: 30em foo bar) {}", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Not), css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media not {}", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Not), css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media not (min-width: 300px) {}", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Not), css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media , {}", |list, css| {
assert!(list.media_queries.len() == 1, css.to_string());
let q = &list.media_queries[0];
assert!(q.qualifier == Some(Not), css.to_string());
assert!(q.media_type == All, css.to_string());
assert!(q.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q.media_type == MediaQueryType::All, css.to_string());
assert!(q.expressions.len() == 0, css.to_string());
});
test_media_rule("@media screen 4px, print {}", |list, css| {
assert!(list.media_queries.len() == 2, css.to_string());
let q0 = &list.media_queries[0];
assert!(q0.qualifier == Some(Not), css.to_string());
assert!(q0.media_type == All, css.to_string());
assert!(q0.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q0.media_type == MediaQueryType::All, css.to_string());
assert!(q0.expressions.len() == 0, css.to_string());
let q1 = &list.media_queries[1];
assert!(q1.qualifier == None, css.to_string());
assert!(q1.media_type == MediaType_(Print), css.to_string());
assert!(q1.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_string());
assert!(q1.expressions.len() == 0, css.to_string());
});
@ -649,11 +648,11 @@ mod tests {
assert!(list.media_queries.len() == 2, css.to_string());
let q0 = &list.media_queries[0];
assert!(q0.qualifier == None, css.to_string());
assert!(q0.media_type == MediaType_(Screen), css.to_string());
assert!(q0.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_string());
assert!(q0.expressions.len() == 0, css.to_string());
let q1 = &list.media_queries[1];
assert!(q1.qualifier == Some(Not), css.to_string());
assert!(q1.media_type == All, css.to_string());
assert!(q1.qualifier == Some(Qualifier::Not), css.to_string());
assert!(q1.media_type == MediaQueryType::All, css.to_string());
assert!(q1.expressions.len() == 0, css.to_string());
});
}
@ -661,7 +660,7 @@ mod tests {
#[test]
fn test_matching_simple() {
let device = Device {
media_type: Screen,
media_type: MediaType::Screen,
viewport_size: TypedSize2D(200.0, 100.0),
};
@ -680,7 +679,7 @@ mod tests {
#[test]
fn test_matching_width() {
let device = Device {
media_type: Screen,
media_type: MediaType::Screen,
viewport_size: TypedSize2D(200.0, 100.0),
};
@ -718,7 +717,7 @@ mod tests {
#[test]
fn test_matching_invalid() {
let device = Device {
media_type: Screen,
media_type: MediaType::Screen,
viewport_size: TypedSize2D(200.0, 100.0),
};

View file

@ -22,7 +22,7 @@ pub mod specified {
#[deriving(Clone, Show)]
pub enum Length {
Au_(Au), // application units
Au(Au), // application units
Em(CSSFloat),
Ex(CSSFloat),
Rem(CSSFloat),
@ -52,7 +52,7 @@ pub mod specified {
match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
=> Length::parse_dimension(value.value, unit.as_slice()),
&Number(ref value) if value.value == 0. => Ok(Au_(Au(0))),
&Number(ref value) if value.value == 0. => Ok(Length::Au(Au(0))),
_ => Err(())
}
}
@ -66,38 +66,40 @@ pub mod specified {
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
match unit.to_ascii_lower().as_slice() {
"px" => Ok(Length::from_px(value)),
"in" => Ok(Au_(Au((value * AU_PER_IN) as i32))),
"cm" => Ok(Au_(Au((value * AU_PER_CM) as i32))),
"mm" => Ok(Au_(Au((value * AU_PER_MM) as i32))),
"pt" => Ok(Au_(Au((value * AU_PER_PT) as i32))),
"pc" => Ok(Au_(Au((value * AU_PER_PC) as i32))),
"em" => Ok(Em(value)),
"ex" => Ok(Ex(value)),
"rem" => Ok(Rem(value)),
"in" => Ok(Length::Au(Au((value * AU_PER_IN) as i32))),
"cm" => Ok(Length::Au(Au((value * AU_PER_CM) as i32))),
"mm" => Ok(Length::Au(Au((value * AU_PER_MM) as i32))),
"pt" => Ok(Length::Au(Au((value * AU_PER_PT) as i32))),
"pc" => Ok(Length::Au(Au((value * AU_PER_PC) as i32))),
"em" => Ok(Length::Em(value)),
"ex" => Ok(Length::Ex(value)),
"rem" => Ok(Length::Rem(value)),
_ => Err(())
}
}
#[inline]
pub fn from_px(px_value: CSSFloat) -> Length {
Au_(Au((px_value * AU_PER_PX) as i32))
Length::Au(Au((px_value * AU_PER_PX) as i32))
}
}
#[deriving(Clone, Show)]
pub enum LengthOrPercentage {
LP_Length(Length),
LP_Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
Length(Length),
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
}
impl LengthOrPercentage {
fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentage, ()> {
match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
=> Length::parse_dimension(value.value, unit.as_slice()).map(LP_Length),
&ast::Percentage(ref value) if negative_ok || value.value >= 0.
=> Ok(LP_Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. => Ok(LP_Length(Au_(Au(0)))),
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0. =>
Length::parse_dimension(value.value, unit.as_slice())
.map(LengthOrPercentage::Length),
&ast::Percentage(ref value) if negative_ok || value.value >= 0. =>
Ok(LengthOrPercentage::Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. =>
Ok(LengthOrPercentage::Length(Length::Au(Au(0)))),
_ => Err(())
}
}
@ -114,20 +116,22 @@ pub mod specified {
#[deriving(Clone)]
pub enum LengthOrPercentageOrAuto {
LPA_Length(Length),
LPA_Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
LPA_Auto,
Length(Length),
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
Auto,
}
impl LengthOrPercentageOrAuto {
fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentageOrAuto, ()> {
match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
=> Length::parse_dimension(value.value, unit.as_slice()).map(LPA_Length),
&ast::Percentage(ref value) if negative_ok || value.value >= 0.
=> Ok(LPA_Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. => Ok(LPA_Length(Au_(Au(0)))),
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("auto") => Ok(LPA_Auto),
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0. =>
Length::parse_dimension(value.value, unit.as_slice()).map(LengthOrPercentageOrAuto::Length),
&ast::Percentage(ref value) if negative_ok || value.value >= 0. =>
Ok(LengthOrPercentageOrAuto::Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. =>
Ok(LengthOrPercentageOrAuto::Length(Length::Au(Au(0)))),
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("auto") =>
Ok(LengthOrPercentageOrAuto::Auto),
_ => Err(())
}
}
@ -143,20 +147,20 @@ pub mod specified {
#[deriving(Clone)]
pub enum LengthOrPercentageOrNone {
LPN_Length(Length),
LPN_Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
LPN_None,
Length(Length),
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
None,
}
impl LengthOrPercentageOrNone {
fn parse_internal(input: &ComponentValue, negative_ok: bool)
-> Result<LengthOrPercentageOrNone, ()> {
match input {
&Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
=> Length::parse_dimension(value.value, unit.as_slice()).map(LPN_Length),
=> Length::parse_dimension(value.value, unit.as_slice()).map(LengthOrPercentageOrNone::Length),
&ast::Percentage(ref value) if negative_ok || value.value >= 0.
=> Ok(LPN_Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. => Ok(LPN_Length(Au_(Au(0)))),
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("none") => Ok(LPN_None),
=> Ok(LengthOrPercentageOrNone::Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. => Ok(LengthOrPercentageOrNone::Length(Length::Au(Au(0)))),
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("none") => Ok(LengthOrPercentageOrNone::None),
_ => Err(())
}
}
@ -174,27 +178,27 @@ pub mod specified {
// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position
#[deriving(Clone)]
pub enum PositionComponent {
Pos_Length(Length),
Pos_Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
Pos_Center,
Pos_Left,
Pos_Right,
Pos_Top,
Pos_Bottom,
Length(Length),
Percentage(CSSFloat), // [0 .. 100%] maps to [0.0 .. 1.0]
Center,
Left,
Right,
Top,
Bottom,
}
impl PositionComponent {
pub fn parse(input: &ComponentValue) -> Result<PositionComponent, ()> {
match input {
&Dimension(ref value, ref unit) =>
Length::parse_dimension(value.value, unit.as_slice()).map(Pos_Length),
&ast::Percentage(ref value) => Ok(Pos_Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. => Ok(Pos_Length(Au_(Au(0)))),
Length::parse_dimension(value.value, unit.as_slice()).map(PositionComponent::Length),
&ast::Percentage(ref value) => Ok(PositionComponent::Percentage(value.value / 100.)),
&Number(ref value) if value.value == 0. => Ok(PositionComponent::Length(Length::Au(Au(0)))),
&Ident(ref value) => {
if value.as_slice().eq_ignore_ascii_case("center") { Ok(Pos_Center) }
else if value.as_slice().eq_ignore_ascii_case("left") { Ok(Pos_Left) }
else if value.as_slice().eq_ignore_ascii_case("right") { Ok(Pos_Right) }
else if value.as_slice().eq_ignore_ascii_case("top") { Ok(Pos_Top) }
else if value.as_slice().eq_ignore_ascii_case("bottom") { Ok(Pos_Bottom) }
if value.as_slice().eq_ignore_ascii_case("center") { Ok(PositionComponent::Center) }
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) }
else if value.as_slice().eq_ignore_ascii_case("top") { Ok(PositionComponent::Top) }
else if value.as_slice().eq_ignore_ascii_case("bottom") { Ok(PositionComponent::Bottom) }
else { Err(()) }
}
_ => Err(())
@ -203,11 +207,11 @@ pub mod specified {
#[inline]
pub fn to_length_or_percentage(self) -> LengthOrPercentage {
match self {
Pos_Length(x) => LP_Length(x),
Pos_Percentage(x) => LP_Percentage(x),
Pos_Center => LP_Percentage(0.5),
Pos_Left | Pos_Top => LP_Percentage(0.0),
Pos_Right | Pos_Bottom => LP_Percentage(1.0),
PositionComponent::Length(x) => LengthOrPercentage::Length(x),
PositionComponent::Percentage(x) => LengthOrPercentage::Percentage(x),
PositionComponent::Center => LengthOrPercentage::Percentage(0.5),
PositionComponent::Left | PositionComponent::Top => LengthOrPercentage::Percentage(0.0),
PositionComponent::Right | PositionComponent::Bottom => LengthOrPercentage::Percentage(1.0),
}
}
}
@ -245,8 +249,8 @@ pub mod specified {
/// Specified values for an image according to CSS-IMAGES.
#[deriving(Clone)]
pub enum Image {
UrlImage(Url),
LinearGradientImage(LinearGradient),
Url(Url),
LinearGradient(LinearGradient),
}
impl Image {
@ -255,11 +259,11 @@ pub mod specified {
match component_value {
&ast::URL(ref url) => {
let image_url = super::parse_url(url.as_slice(), base_url);
Ok(UrlImage(image_url))
Ok(Image::Url(image_url))
},
&ast::Function(ref name, ref args) => {
if name.as_slice().eq_ignore_ascii_case("linear-gradient") {
Ok(LinearGradientImage(try!(
Ok(Image::LinearGradient(try!(
super::specified::LinearGradient::parse_function(
args.as_slice()))))
} else {
@ -273,9 +277,9 @@ pub mod specified {
pub fn to_computed_value(self, context: &super::computed::Context)
-> super::computed::Image {
match self {
UrlImage(url) => super::computed::UrlImage(url),
LinearGradientImage(linear_gradient) => {
super::computed::LinearGradientImage(
Image::Url(url) => super::computed::Image::Url(url),
Image::LinearGradient(linear_gradient) => {
super::computed::Image::LinearGradient(
super::computed::LinearGradient::compute(linear_gradient, context))
}
}
@ -295,8 +299,8 @@ pub mod specified {
/// Specified values for an angle or a corner in a linear gradient.
#[deriving(Clone, PartialEq)]
pub enum AngleOrCorner {
AngleAoc(Angle),
CornerAoc(HorizontalDirection, VerticalDirection),
Angle(Angle),
Corner(HorizontalDirection, VerticalDirection),
}
/// Specified values for one color stop in a linear gradient.
@ -360,11 +364,11 @@ pub mod specified {
Dimension(ref value, ref unit) => {
match Angle::parse_dimension(value.value, unit.as_slice()) {
Ok(angle) => {
(AngleAoc(angle), true)
(AngleOrCorner::Angle(angle), true)
}
Err(()) => {
source.push_back(token);
(AngleAoc(Angle(PI)), false)
(AngleOrCorner::Angle(Angle(PI)), false)
}
}
}
@ -379,16 +383,16 @@ pub mod specified {
let ident = ident.as_slice();
if ident.eq_ignore_ascii_case("top") &&
vertical.is_none() {
vertical = Some(Top)
vertical = Some(VerticalDirection::Top)
} else if ident.eq_ignore_ascii_case("bottom") &&
vertical.is_none() {
vertical = Some(Bottom)
vertical = Some(VerticalDirection::Bottom)
} else if ident.eq_ignore_ascii_case("left") &&
horizontal.is_none() {
horizontal = Some(Left)
horizontal = Some(HorizontalDirection::Left)
} else if ident.eq_ignore_ascii_case("right") &&
horizontal.is_none() {
horizontal = Some(Right)
horizontal = Some(HorizontalDirection::Right)
} else {
return Err(())
}
@ -404,19 +408,27 @@ pub mod specified {
}
(match (horizontal, vertical) {
(None, Some(Top)) => AngleAoc(Angle(0.0)),
(Some(Right), None) => AngleAoc(Angle(PI * 0.5)),
(None, Some(Bottom)) => AngleAoc(Angle(PI)),
(Some(Left), None) => AngleAoc(Angle(PI * 1.5)),
(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)) => {
CornerAoc(horizontal, vertical)
AngleOrCorner::Corner(horizontal, vertical)
}
(None, None) => return Err(()),
}, true)
}
_ => {
source.push_back(token);
(AngleAoc(Angle(PI)), false)
(AngleOrCorner::Angle(Angle(PI)), false)
}
}
}
@ -448,7 +460,7 @@ pub mod specified {
}
pub mod computed {
pub use super::specified::{Angle, AngleAoc, AngleOrCorner, CornerAoc, HorizontalDirection};
pub use super::specified::{Angle, AngleOrCorner, HorizontalDirection};
pub use super::specified::{VerticalDirection};
pub use cssparser::Color as CSSColor;
pub use super::super::longhands::computed_as_specified as compute_CSSColor;
@ -487,14 +499,14 @@ pub mod computed {
#[inline]
pub fn compute_Au_with_font_size(value: specified::Length, reference_font_size: Au, root_font_size: Au) -> Au {
match value {
specified::Au_(value) => value,
specified::Em(value) => reference_font_size.scale_by(value),
specified::Ex(value) => {
specified::Length::Au(value) => value,
specified::Length::Em(value) => reference_font_size.scale_by(value),
specified::Length::Ex(value) => {
let x_height = 0.5; // TODO: find that from the font
reference_font_size.scale_by(value * x_height)
},
specified::Rem(value) => root_font_size.scale_by(value),
specified::ServoCharacterWidth(value) => {
specified::Length::Rem(value) => root_font_size.scale_by(value),
specified::Length::ServoCharacterWidth(value) => {
// This applies the *converting a character width to pixels* algorithm as specified
// in HTML5 § 14.5.4.
//
@ -508,56 +520,64 @@ pub mod computed {
#[deriving(PartialEq, Clone, Show)]
pub enum LengthOrPercentage {
LP_Length(Au),
LP_Percentage(CSSFloat),
Length(Au),
Percentage(CSSFloat),
}
#[allow(non_snake_case)]
pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context)
-> LengthOrPercentage {
match value {
specified::LP_Length(value) => LP_Length(compute_Au(value, context)),
specified::LP_Percentage(value) => LP_Percentage(value),
specified::LengthOrPercentage::Length(value) =>
LengthOrPercentage::Length(compute_Au(value, context)),
specified::LengthOrPercentage::Percentage(value) =>
LengthOrPercentage::Percentage(value),
}
}
#[deriving(PartialEq, Clone, Show)]
pub enum LengthOrPercentageOrAuto {
LPA_Length(Au),
LPA_Percentage(CSSFloat),
LPA_Auto,
Length(Au),
Percentage(CSSFloat),
Auto,
}
#[allow(non_snake_case)]
pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto,
context: &Context) -> LengthOrPercentageOrAuto {
match value {
specified::LPA_Length(value) => LPA_Length(compute_Au(value, context)),
specified::LPA_Percentage(value) => LPA_Percentage(value),
specified::LPA_Auto => LPA_Auto,
specified::LengthOrPercentageOrAuto::Length(value) =>
LengthOrPercentageOrAuto::Length(compute_Au(value, context)),
specified::LengthOrPercentageOrAuto::Percentage(value) =>
LengthOrPercentageOrAuto::Percentage(value),
specified::LengthOrPercentageOrAuto::Auto =>
LengthOrPercentageOrAuto::Auto,
}
}
#[deriving(PartialEq, Clone, Show)]
pub enum LengthOrPercentageOrNone {
LPN_Length(Au),
LPN_Percentage(CSSFloat),
LPN_None,
Length(Au),
Percentage(CSSFloat),
None,
}
#[allow(non_snake_case)]
pub fn compute_LengthOrPercentageOrNone(value: specified::LengthOrPercentageOrNone,
context: &Context) -> LengthOrPercentageOrNone {
match value {
specified::LPN_Length(value) => LPN_Length(compute_Au(value, context)),
specified::LPN_Percentage(value) => LPN_Percentage(value),
specified::LPN_None => LPN_None,
specified::LengthOrPercentageOrNone::Length(value) =>
LengthOrPercentageOrNone::Length(compute_Au(value, context)),
specified::LengthOrPercentageOrNone::Percentage(value) =>
LengthOrPercentageOrNone::Percentage(value),
specified::LengthOrPercentageOrNone::None =>
LengthOrPercentageOrNone::None,
}
}
/// Computed values for an image according to CSS-IMAGES.
#[deriving(Clone, PartialEq)]
pub enum Image {
UrlImage(Url),
LinearGradientImage(LinearGradient),
Url(Url),
LinearGradient(LinearGradient),
}
/// Computed values for a CSS linear gradient.

View file

@ -13,8 +13,8 @@ pub use url::Url;
pub use cssparser::*;
pub use cssparser::ast::*;
pub use geom::SideOffsets2D;
pub use self::common_types::specified::{Angle, AngleAoc, AngleOrCorner, Bottom, CornerAoc};
pub use self::common_types::specified::{Left, Right, Top};
pub use self::common_types::specified::{Angle, AngleOrCorner};
pub use self::common_types::specified::{HorizontalDirection, VerticalDirection};
use errors::{ErrorLoggerIterator, log_css_error};
pub use parsing_utils::*;
@ -121,9 +121,9 @@ pub mod longhands {
pub fn parse_declared(input: &[ComponentValue], base_url: &Url)
-> Result<DeclaredValue<SpecifiedValue>, ()> {
match CSSWideKeyword::parse(input) {
Ok(InheritKeyword) => Ok(Inherit),
Ok(InitialKeyword) => Ok(Initial),
Ok(UnsetKeyword) => Ok(${
Ok(CSSWideKeyword::InheritKeyword) => Ok(DeclaredValue::Inherit),
Ok(CSSWideKeyword::InitialKeyword) => Ok(DeclaredValue::Initial),
Ok(CSSWideKeyword::UnsetKeyword) => Ok(DeclaredValue::${
"Inherit" if THIS_STYLE_STRUCT.inherited else "Initial"}),
Err(()) => parse_specified(input, base_url),
}
@ -139,7 +139,7 @@ pub mod longhands {
% if derived_from is None:
pub fn parse_specified(_input: &[ComponentValue], _base_url: &Url)
-> Result<DeclaredValue<SpecifiedValue>, ()> {
parse(_input, _base_url).map(super::SpecifiedValue)
parse(_input, _base_url).map(super::DeclaredValue::SpecifiedValue)
}
% endif
</%self:raw_longhand>
@ -169,14 +169,14 @@ pub mod longhands {
}
pub type SpecifiedValue = computed_value::T;
#[inline] pub fn get_initial_value() -> computed_value::T {
${to_rust_ident(values.split()[0])}
T::${to_rust_ident(values.split()[0])}
}
pub fn from_component_value(v: &ComponentValue, _base_url: &Url)
-> Result<SpecifiedValue, ()> {
get_ident_lower(v).and_then(|keyword| {
match keyword.as_slice() {
% for value in values.split():
"${value}" => Ok(${to_rust_ident(value)}),
"${value}" => Ok(T::${to_rust_ident(value)}),
% endfor
_ => Err(()),
}
@ -216,21 +216,21 @@ pub mod longhands {
% for side in ["top", "right", "bottom", "left"]:
${predefined_type("margin-" + side, "LengthOrPercentageOrAuto",
"computed::LPA_Length(Au(0))")}
"computed::LengthOrPercentageOrAuto::Length(Au(0))")}
% endfor
${new_style_struct("Padding", is_inherited=False)}
% for side in ["top", "right", "bottom", "left"]:
${predefined_type("padding-" + side, "LengthOrPercentage",
"computed::LP_Length(Au(0))",
"computed::LengthOrPercentage::Length(Au(0))",
"parse_non_negative")}
% endfor
${new_style_struct("Border", is_inherited=False)}
% for side in ["top", "right", "bottom", "left"]:
${predefined_type("border-%s-color" % side, "CSSColor", "CurrentColor")}
${predefined_type("border-%s-color" % side, "CSSColor", "super::super::computed::CSSColor::CurrentColor")}
% endfor
${single_keyword("border-top-style", values="none solid double dotted dashed hidden groove ridge inset outset")}
@ -302,7 +302,7 @@ pub mod longhands {
#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T {
radius: computed::LP_Length(Au(0)),
radius: computed::LengthOrPercentage::Length(Au(0)),
}
}
#[inline]
@ -358,7 +358,7 @@ pub mod longhands {
${new_style_struct("Outline", is_inherited=False)}
// TODO(pcwalton): `invert`
${predefined_type("outline-color", "CSSColor", "CurrentColor")}
${predefined_type("outline-color", "CSSColor", "super::super::computed::CSSColor::CurrentColor")}
<%self:single_component_value name="outline-style">
pub use super::border_top_style::{get_initial_value, to_computed_value};
@ -391,7 +391,7 @@ pub mod longhands {
% for side in ["top", "right", "bottom", "left"]:
${predefined_type(side, "LengthOrPercentageOrAuto",
"computed::LPA_Auto")}
"computed::LengthOrPercentageOrAuto::Auto")}
% endfor
// CSS 2.1, Section 9 - Visual formatting model
@ -413,12 +413,13 @@ pub mod longhands {
// }
if context.positioned || context.floated || context.is_root_element {
match value {
inline_table => table,
inline | inline_block
| table_row_group | table_column | table_column_group
| table_header_group | table_footer_group | table_row
| table_cell | table_caption
=> block,
T::inline_table => T::table,
T::inline | T::inline_block |
T::table_row_group | T::table_column |
T::table_column_group | T::table_header_group |
T::table_footer_group | T::table_row | T::table_cell |
T::table_caption
=> T::block,
_ => value,
}
} else {
@ -463,23 +464,23 @@ pub mod longhands {
impl T {
pub fn number_or_zero(self) -> i32 {
match self {
Auto => 0,
Number(value) => value,
T::Auto => 0,
T::Number(value) => value,
}
}
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T {
Auto
T::Auto
}
fn from_component_value(input: &ComponentValue, _: &Url) -> Result<SpecifiedValue,()> {
match *input {
Ident(ref keyword) if keyword.as_slice().eq_ignore_ascii_case("auto") => Ok(Auto),
Ident(ref keyword) if keyword.as_slice().eq_ignore_ascii_case("auto") => Ok(T::Auto),
ast::Number(ast::NumericValue {
int_value: Some(value),
..
}) => Ok(Number(value as i32)),
}) => Ok(T::Number(value as i32)),
_ => Err(())
}
}
@ -494,7 +495,7 @@ pub mod longhands {
${switch_to_style_struct("Box")}
${predefined_type("width", "LengthOrPercentageOrAuto",
"computed::LPA_Auto",
"computed::LengthOrPercentageOrAuto::Auto",
"parse_non_negative")}
<%self:single_component_value name="height">
pub type SpecifiedValue = specified::LengthOrPercentageOrAuto;
@ -502,7 +503,7 @@ pub mod longhands {
pub type T = super::super::computed::LengthOrPercentageOrAuto;
}
#[inline]
pub fn get_initial_value() -> computed_value::T { computed::LPA_Auto }
pub fn get_initial_value() -> computed_value::T { computed::LengthOrPercentageOrAuto::Auto }
#[inline]
pub fn from_component_value(v: &ComponentValue, _base_url: &Url)
-> Result<SpecifiedValue, ()> {
@ -511,9 +512,9 @@ pub mod longhands {
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
-> computed_value::T {
match (value, context.inherited_height) {
(specified::LPA_Percentage(_), computed::LPA_Auto)
(specified::LengthOrPercentageOrAuto::Percentage(_), computed::LengthOrPercentageOrAuto::Auto)
if !context.is_root_element && !context.positioned => {
computed::LPA_Auto
computed::LengthOrPercentageOrAuto::Auto
},
_ => computed::compute_LengthOrPercentageOrAuto(value, context)
}
@ -521,17 +522,17 @@ pub mod longhands {
</%self:single_component_value>
${predefined_type("min-width", "LengthOrPercentage",
"computed::LP_Length(Au(0))",
"computed::LengthOrPercentage::Length(Au(0))",
"parse_non_negative")}
${predefined_type("max-width", "LengthOrPercentageOrNone",
"computed::LPN_None",
"computed::LengthOrPercentageOrNone::None",
"parse_non_negative")}
${predefined_type("min-height", "LengthOrPercentage",
"computed::LP_Length(Au(0))",
"computed::LengthOrPercentage::Length(Au(0))",
"parse_non_negative")}
${predefined_type("max-height", "LengthOrPercentageOrNone",
"computed::LPN_None",
"computed::LengthOrPercentageOrNone::None",
"parse_non_negative")}
${switch_to_style_struct("InheritedBox")}
@ -539,24 +540,24 @@ pub mod longhands {
<%self:single_component_value name="line-height">
#[deriving(Clone)]
pub enum SpecifiedValue {
SpecifiedNormal,
SpecifiedLength(specified::Length),
SpecifiedNumber(CSSFloat),
Normal,
Length(specified::Length),
Number(CSSFloat),
// percentage are the same as em.
}
/// normal | <number> | <length> | <percentage>
pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
-> Result<SpecifiedValue, ()> {
match input {
&ast::Number(ref value) if value.value >= 0.
=> Ok(SpecifiedNumber(value.value)),
&ast::Percentage(ref value) if value.value >= 0.
=> Ok(SpecifiedLength(specified::Em(value.value / 100.))),
&Dimension(ref value, ref unit) if value.value >= 0.
=> specified::Length::parse_dimension(value.value, unit.as_slice())
.map(SpecifiedLength),
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("normal")
=> Ok(SpecifiedNormal),
&ast::Number(ref value) if value.value >= 0. =>
Ok(SpecifiedValue::Number(value.value)),
&ast::Percentage(ref value) if value.value >= 0. =>
Ok(SpecifiedValue::Length(specified::Length::Em(value.value / 100.))),
&Dimension(ref value, ref unit) if value.value >= 0. =>
specified::Length::parse_dimension(value.value, unit.as_slice())
.map(SpecifiedValue::Length),
&Ident(ref value) if value.as_slice().eq_ignore_ascii_case("normal") =>
Ok(SpecifiedValue::Normal),
_ => Err(()),
}
}
@ -570,14 +571,14 @@ pub mod longhands {
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T { Normal }
pub fn get_initial_value() -> computed_value::T { T::Normal }
#[inline]
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
-> computed_value::T {
match value {
SpecifiedNormal => Normal,
SpecifiedLength(value) => Length(computed::compute_Au(value, context)),
SpecifiedNumber(value) => Number(value),
SpecifiedValue::Normal => T::Normal,
SpecifiedValue::Length(value) => T::Length(computed::compute_Au(value, context)),
SpecifiedValue::Number(value) => T::Number(value),
}
}
</%self:single_component_value>
@ -591,9 +592,9 @@ pub mod longhands {
#[deriving(Clone)]
pub enum SpecifiedValue {
% for keyword in vertical_align_keywords:
Specified_${to_rust_ident(keyword)},
${to_rust_ident(keyword)},
% endfor
SpecifiedLengthOrPercentage(specified::LengthOrPercentage),
LengthOrPercentage(specified::LengthOrPercentage),
}
/// baseline | sub | super | top | text-top | middle | bottom | text-bottom
/// | <percentage> | <length>
@ -603,13 +604,13 @@ pub mod longhands {
&Ident(ref value) => {
match value.as_slice().to_ascii_lower().as_slice() {
% for keyword in vertical_align_keywords:
"${keyword}" => Ok(Specified_${to_rust_ident(keyword)}),
"${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}),
% endfor
_ => Err(()),
}
},
_ => specified::LengthOrPercentage::parse_non_negative(input)
.map(SpecifiedLengthOrPercentage)
.map(SpecifiedValue::LengthOrPercentage)
}
}
pub mod computed_value {
@ -625,18 +626,18 @@ pub mod longhands {
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T { baseline }
pub fn get_initial_value() -> computed_value::T { T::baseline }
#[inline]
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
-> computed_value::T {
match value {
% for keyword in vertical_align_keywords:
Specified_${to_rust_ident(keyword)} => ${to_rust_ident(keyword)},
SpecifiedValue::${to_rust_ident(keyword)} => computed_value::T::${to_rust_ident(keyword)},
% endfor
SpecifiedLengthOrPercentage(value)
SpecifiedValue::LengthOrPercentage(value)
=> match computed::compute_LengthOrPercentage(value, context) {
computed::LP_Length(value) => Length(value),
computed::LP_Percentage(value) => Percentage(value)
computed::LengthOrPercentage::Length(value) => T::Length(value),
computed::LengthOrPercentage::Percentage(value) => T::Percentage(value)
}
}
}
@ -672,7 +673,7 @@ pub mod longhands {
}
}
pub type SpecifiedValue = computed_value::T;
#[inline] pub fn get_initial_value() -> computed_value::T { normal }
#[inline] pub fn get_initial_value() -> computed_value::T { T::normal }
// normal | none | [ <string> ]+
// TODO: <uri>, <counter>, attr(<identifier>), open-quote, close-quote, no-open-quote, no-close-quote
@ -680,8 +681,8 @@ pub mod longhands {
match one_component_value(input) {
Ok(&Ident(ref keyword)) => {
match keyword.as_slice().to_ascii_lower().as_slice() {
"normal" => return Ok(normal),
"none" => return Ok(none),
"normal" => return Ok(T::normal),
"none" => return Ok(T::none),
_ => ()
}
},
@ -691,11 +692,11 @@ pub mod longhands {
for component_value in input.skip_whitespace() {
match component_value {
&QuotedString(ref value)
=> content.push(StringContent(value.clone())),
=> content.push(ContentItem::StringContent(value.clone())),
_ => return Err(()) // invalid/unsupported value
}
}
Ok(Content(content))
Ok(T::Content(content))
}
</%self:longhand>
@ -743,7 +744,7 @@ pub mod longhands {
${new_style_struct("Background", is_inherited=False)}
${predefined_type("background-color", "CSSColor",
"RGBAColor(RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */")}
"Color::RGBA(RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */")}
<%self:single_component_value name="background-image">
use super::common_types::specified as common_specified;
@ -804,13 +805,13 @@ pub mod longhands {
-> Result<SpecifiedValue,()> {
let (horiz, vert) = match (category(first), category(second)) {
// Don't allow two vertical keywords or two horizontal keywords.
(HorizontalKeyword, HorizontalKeyword) |
(VerticalKeyword, VerticalKeyword) => return Err(()),
(PositionCategory::HorizontalKeyword, PositionCategory::HorizontalKeyword) |
(PositionCategory::VerticalKeyword, PositionCategory::VerticalKeyword) => return Err(()),
// Swap if both are keywords and vertical precedes horizontal.
(VerticalKeyword, HorizontalKeyword) |
(VerticalKeyword, OtherKeyword) |
(OtherKeyword, HorizontalKeyword) => (second, first),
(PositionCategory::VerticalKeyword, PositionCategory::HorizontalKeyword) |
(PositionCategory::VerticalKeyword, PositionCategory::OtherKeyword) |
(PositionCategory::OtherKeyword, PositionCategory::HorizontalKeyword) => (second, first),
// By default, horizontal is first.
_ => (first, second),
@ -831,11 +832,17 @@ pub mod longhands {
}
fn category(p: specified::PositionComponent) -> PositionCategory {
match p {
specified::Pos_Left | specified::Pos_Right => HorizontalKeyword,
specified::Pos_Top | specified::Pos_Bottom => VerticalKeyword,
specified::Pos_Center => OtherKeyword,
specified::Pos_Length(_) |
specified::Pos_Percentage(_) => LengthOrPercentage,
specified::PositionComponent::Left |
specified::PositionComponent::Right =>
PositionCategory::HorizontalKeyword,
specified::PositionComponent::Top |
specified::PositionComponent::Bottom =>
PositionCategory::VerticalKeyword,
specified::PositionComponent::Center =>
PositionCategory::OtherKeyword,
specified::PositionComponent::Length(_) |
specified::PositionComponent::Percentage(_) =>
PositionCategory::LengthOrPercentage,
}
}
@ -851,15 +858,15 @@ pub mod longhands {
#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T {
horizontal: computed::LP_Percentage(0.0),
vertical: computed::LP_Percentage(0.0),
horizontal: computed::LengthOrPercentage::Percentage(0.0),
vertical: computed::LengthOrPercentage::Percentage(0.0),
}
}
pub fn parse_one(first: &ComponentValue) -> Result<SpecifiedValue, ()> {
let first = try!(specified::PositionComponent::parse(first));
// If only one value is provided, use `center` for the second.
SpecifiedValue::new(first, specified::Pos_Center)
SpecifiedValue::new(first, specified::PositionComponent::Center)
}
pub fn parse_two(first: &ComponentValue, second: &ComponentValue)
@ -906,8 +913,8 @@ pub mod longhands {
pub fn parse_specified(input: &[ComponentValue], _base_url: &Url)
-> Result<DeclaredValue<SpecifiedValue>, ()> {
match one_component_value(input).and_then(Color::parse) {
Ok(RGBAColor(rgba)) => Ok(SpecifiedValue(rgba)),
Ok(CurrentColor) => Ok(Inherit),
Ok(Color::RGBA(rgba)) => Ok(DeclaredValue::SpecifiedValue(rgba)),
Ok(Color::CurrentColor) => Ok(DeclaredValue::Inherit),
Err(()) => Err(()),
}
}
@ -933,7 +940,7 @@ pub mod longhands {
impl FontFamily {
pub fn name(&self) -> &str {
match *self {
FamilyName(ref name) => name.as_slice(),
FontFamily::FamilyName(ref name) => name.as_slice(),
}
}
}
@ -943,7 +950,7 @@ pub mod longhands {
#[inline]
pub fn get_initial_value() -> computed_value::T {
vec![FamilyName("serif".to_string())]
vec![FontFamily::FamilyName("serif".to_string())]
}
/// <familiy-name>#
/// <familiy-name> = <string> | [ <ident>+ ]
@ -954,7 +961,7 @@ pub mod longhands {
pub fn parse_one_family<'a>(iter: ParserIter) -> Result<FontFamily, ()> {
// TODO: avoid copying strings?
let mut idents = match iter.next() {
Some(&QuotedString(ref value)) => return Ok(FamilyName(value.clone())),
Some(&QuotedString(ref value)) => return Ok(FontFamily::FamilyName(value.clone())),
Some(&Ident(ref value)) => {
// match value.as_slice().to_ascii_lower().as_slice() {
// "serif" => return Ok(Serif),
@ -982,7 +989,7 @@ pub mod longhands {
None => break,
}
}
Ok(FamilyName(idents.connect(" ")))
Ok(FontFamily::FamilyName(idents.connect(" ")))
}
</%self:longhand>
@ -1005,23 +1012,23 @@ pub mod longhands {
match input {
&Ident(ref value) => {
match value.as_slice().to_ascii_lower().as_slice() {
"bold" => Ok(SpecifiedWeight700),
"normal" => Ok(SpecifiedWeight400),
"bolder" => Ok(Bolder),
"lighter" => Ok(Lighter),
"bold" => Ok(SpecifiedValue::SpecifiedWeight700),
"normal" => Ok(SpecifiedValue::SpecifiedWeight400),
"bolder" => Ok(SpecifiedValue::Bolder),
"lighter" => Ok(SpecifiedValue::Lighter),
_ => Err(()),
}
},
&Number(ref value) => match value.int_value {
Some(100) => Ok(SpecifiedWeight100),
Some(200) => Ok(SpecifiedWeight200),
Some(300) => Ok(SpecifiedWeight300),
Some(400) => Ok(SpecifiedWeight400),
Some(500) => Ok(SpecifiedWeight500),
Some(600) => Ok(SpecifiedWeight600),
Some(700) => Ok(SpecifiedWeight700),
Some(800) => Ok(SpecifiedWeight800),
Some(900) => Ok(SpecifiedWeight900),
Some(100) => Ok(SpecifiedValue::SpecifiedWeight100),
Some(200) => Ok(SpecifiedValue::SpecifiedWeight200),
Some(300) => Ok(SpecifiedValue::SpecifiedWeight300),
Some(400) => Ok(SpecifiedValue::SpecifiedWeight400),
Some(500) => Ok(SpecifiedValue::SpecifiedWeight500),
Some(600) => Ok(SpecifiedValue::SpecifiedWeight600),
Some(700) => Ok(SpecifiedValue::SpecifiedWeight700),
Some(800) => Ok(SpecifiedValue::SpecifiedWeight800),
Some(900) => Ok(SpecifiedValue::SpecifiedWeight900),
_ => Err(()),
},
_ => Err(())
@ -1037,42 +1044,45 @@ pub mod longhands {
impl T {
pub fn is_bold(self) -> bool {
match self {
Weight900 | Weight800 | Weight700 | Weight600 => true,
T::Weight900 | T::Weight800 |
T::Weight700 | T::Weight600 => true,
_ => false
}
}
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T { Weight400 } // normal
pub fn get_initial_value() -> computed_value::T {
computed_value::T::Weight400 // normal
}
#[inline]
pub fn to_computed_value(value: SpecifiedValue, context: &computed::Context)
-> computed_value::T {
match value {
% for weight in range(100, 901, 100):
SpecifiedWeight${weight} => Weight${weight},
SpecifiedValue::SpecifiedWeight${weight} => computed_value::T::Weight${weight},
% endfor
Bolder => match context.inherited_font_weight {
Weight100 => Weight400,
Weight200 => Weight400,
Weight300 => Weight400,
Weight400 => Weight700,
Weight500 => Weight700,
Weight600 => Weight900,
Weight700 => Weight900,
Weight800 => Weight900,
Weight900 => Weight900,
SpecifiedValue::Bolder => match context.inherited_font_weight {
computed_value::T::Weight100 => computed_value::T::Weight400,
computed_value::T::Weight200 => computed_value::T::Weight400,
computed_value::T::Weight300 => computed_value::T::Weight400,
computed_value::T::Weight400 => computed_value::T::Weight700,
computed_value::T::Weight500 => computed_value::T::Weight700,
computed_value::T::Weight600 => computed_value::T::Weight900,
computed_value::T::Weight700 => computed_value::T::Weight900,
computed_value::T::Weight800 => computed_value::T::Weight900,
computed_value::T::Weight900 => computed_value::T::Weight900,
},
Lighter => match context.inherited_font_weight {
Weight100 => Weight100,
Weight200 => Weight100,
Weight300 => Weight100,
Weight400 => Weight100,
Weight500 => Weight100,
Weight600 => Weight400,
Weight700 => Weight400,
Weight800 => Weight700,
Weight900 => Weight700,
SpecifiedValue::Lighter => match context.inherited_font_weight {
computed_value::T::Weight100 => computed_value::T::Weight100,
computed_value::T::Weight200 => computed_value::T::Weight100,
computed_value::T::Weight300 => computed_value::T::Weight100,
computed_value::T::Weight400 => computed_value::T::Weight100,
computed_value::T::Weight500 => computed_value::T::Weight100,
computed_value::T::Weight600 => computed_value::T::Weight400,
computed_value::T::Weight700 => computed_value::T::Weight400,
computed_value::T::Weight800 => computed_value::T::Weight700,
computed_value::T::Weight900 => computed_value::T::Weight700,
},
}
}
@ -1098,22 +1108,22 @@ pub mod longhands {
pub fn from_component_value(input: &ComponentValue, _base_url: &Url)
-> Result<SpecifiedValue, ()> {
match specified::LengthOrPercentage::parse_non_negative(input) {
Ok(specified::LP_Length(value)) => return Ok(value),
Ok(specified::LP_Percentage(value)) => return Ok(specified::Em(value)),
Ok(specified::LengthOrPercentage::Length(value)) => return Ok(value),
Ok(specified::LengthOrPercentage::Percentage(value)) => return Ok(specified::Length::Em(value)),
Err(()) => (),
}
match try!(get_ident_lower(input)).as_slice() {
"xx-small" => Ok(specified::Au_(Au::from_px(MEDIUM_PX) * 3 / 5)),
"x-small" => Ok(specified::Au_(Au::from_px(MEDIUM_PX) * 3 / 4)),
"small" => Ok(specified::Au_(Au::from_px(MEDIUM_PX) * 8 / 9)),
"medium" => Ok(specified::Au_(Au::from_px(MEDIUM_PX))),
"large" => Ok(specified::Au_(Au::from_px(MEDIUM_PX) * 6 / 5)),
"x-large" => Ok(specified::Au_(Au::from_px(MEDIUM_PX) * 3 / 2)),
"xx-large" => Ok(specified::Au_(Au::from_px(MEDIUM_PX) * 2)),
"xx-small" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 3 / 5)),
"x-small" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 3 / 4)),
"small" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 8 / 9)),
"medium" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX))),
"large" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 6 / 5)),
"x-large" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 3 / 2)),
"xx-large" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 2)),
// https://github.com/servo/servo/issues/3423#issuecomment-56321664
"smaller" => Ok(specified::Em(0.85)),
"larger" => Ok(specified::Em(1.2)),
"smaller" => Ok(specified::Length::Em(0.85)),
"larger" => Ok(specified::Length::Em(1.2)),
_ => return Err(())
}
@ -1173,7 +1183,7 @@ pub mod longhands {
}
</%self:single_component_value>
${predefined_type("text-indent", "LengthOrPercentage", "computed::LP_Length(Au(0))")}
${predefined_type("text-indent", "LengthOrPercentage", "computed::LengthOrPercentage::Length(Au(0))")}
// Also known as "word-wrap" (which is more popular because of IE), but this is the preferred
// name per CSS-TEXT 6.2.
@ -1269,7 +1279,7 @@ pub mod longhands {
// Start with no declarations if this is a block; otherwise, start with the
// declarations in effect and add in the text decorations that this inline specifies.
let mut result = match context.display {
display::computed_value::inline => context.inherited_text_decorations_in_effect,
display::computed_value::T::inline => context.inherited_text_decorations_in_effect,
_ => {
SpecifiedValue {
underline: None,
@ -1422,14 +1432,14 @@ pub mod longhands {
offset_y: computed::compute_Au(value.offset_y, context),
blur_radius: computed::compute_Au(value.blur_radius, context),
spread_radius: computed::compute_Au(value.spread_radius, context),
color: value.color.unwrap_or(cssparser::CurrentColor),
color: value.color.unwrap_or(cssparser::Color::CurrentColor),
inset: value.inset,
}
}).collect()
}
fn parse_one_box_shadow(iter: ParserIter) -> Result<SpecifiedBoxShadow,()> {
let mut lengths = [specified::Au_(Au(0)), ..4];
let mut lengths = [specified::Length::Au(Au(0)), ..4];
let mut lengths_parsed = false;
let mut color = None;
let mut inset = false;
@ -1766,7 +1776,7 @@ pub mod shorthands {
fn parse_one_set_of_border_radii<'a,I>(mut input: Peekable< &'a ComponentValue,I >)
-> Result<[specified::LengthOrPercentage, ..4],()>
where I: Iterator< &'a ComponentValue > {
let (mut count, mut values) = (0u, [specified::LP_Length(specified::Au_(Au(0))), ..4]);
let (mut count, mut values) = (0u, [specified::LengthOrPercentage::Length(specified::Length::Au(Au(0))), ..4]);
while count < 4 {
let token = match input.peek() {
None => break,
@ -2004,14 +2014,14 @@ pub mod shorthands {
Ok(Longhands {
list_style_position: position,
list_style_image: Some(None),
list_style_type: Some(list_style_type::none),
list_style_type: Some(list_style_type::T::none),
})
}
(true, 1, None, Some(image)) => {
Ok(Longhands {
list_style_position: position,
list_style_image: Some(image),
list_style_type: Some(list_style_type::none),
list_style_type: Some(list_style_type::T::none),
})
}
(true, 1, Some(list_style_type), None) => {
@ -2025,7 +2035,7 @@ pub mod shorthands {
Ok(Longhands {
list_style_position: position,
list_style_image: Some(None),
list_style_type: Some(list_style_type::none),
list_style_type: Some(list_style_type::T::none),
})
}
(true, 0, list_style_type, image) => {
@ -2105,9 +2115,9 @@ pub fn parse_property_declaration_list<I: Iterator<Node>>(input: I, base_url: &U
ErrorLoggerIterator(parse_declaration_list(input)).collect();
for item in items.into_iter().rev() {
match item {
DeclAtRule(rule) => log_css_error(
DeclarationListItem::AtRule(rule) => log_css_error(
rule.location, format!("Unsupported at-rule in declaration list: @{:s}", rule.name).as_slice()),
Declaration_(Declaration{ location: l, name: n, value: v, important: i}) => {
DeclarationListItem::Declaration(Declaration{ location: l, name: n, value: v, important: i}) => {
// TODO: only keep the last valid declaration for a given name.
let (list, seen) = if i {
(&mut important_declarations, &mut important_seen)
@ -2115,15 +2125,15 @@ pub fn parse_property_declaration_list<I: Iterator<Node>>(input: I, base_url: &U
(&mut normal_declarations, &mut normal_seen)
};
match PropertyDeclaration::parse(n.as_slice(), v.as_slice(), list, base_url, seen) {
UnknownProperty => log_css_error(l, format!(
PropertyDeclarationParseResult::UnknownProperty => log_css_error(l, format!(
"Unsupported property: {}:{}", n, v.iter().to_css()).as_slice()),
ExperimentalProperty => log_css_error(l, format!(
PropertyDeclarationParseResult::ExperimentalProperty => log_css_error(l, format!(
"Experimental property, use `servo --enable_experimental` \
or `servo -e` to enable: {}:{}",
n, v.iter().to_css()).as_slice()),
InvalidValue => log_css_error(l, format!(
PropertyDeclarationParseResult::InvalidValue => log_css_error(l, format!(
"Invalid value: {}:{}", n, v.iter().to_css()).as_slice()),
ValidOrIgnoredDeclaration => (),
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => (),
}
}
}
@ -2145,9 +2155,9 @@ impl CSSWideKeyword {
pub fn parse(input: &[ComponentValue]) -> Result<CSSWideKeyword, ()> {
one_component_value(input).and_then(get_ident_lower).and_then(|keyword| {
match keyword.as_slice() {
"initial" => Ok(InitialKeyword),
"inherit" => Ok(InheritKeyword),
"unset" => Ok(UnsetKeyword),
"initial" => Ok(CSSWideKeyword::InitialKeyword),
"inherit" => Ok(CSSWideKeyword::InheritKeyword),
"unset" => Ok(CSSWideKeyword::UnsetKeyword),
_ => Err(())
}
})
@ -2192,84 +2202,86 @@ impl PropertyDeclaration {
"${property.name}" => {
% if property.experimental:
if !::servo_util::opts::experimental_enabled() {
return ExperimentalProperty
return PropertyDeclarationParseResult::ExperimentalProperty
}
% endif
if seen.get_${property.ident}() {
return ValidOrIgnoredDeclaration
return PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
}
match longhands::${property.ident}::parse_declared(value, base_url) {
Ok(value) => {
seen.set_${property.ident}();
result_list.push(${property.camel_case}Declaration(value));
ValidOrIgnoredDeclaration
result_list.push(PropertyDeclaration::${property.camel_case}Declaration(value));
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
},
Err(()) => InvalidValue,
Err(()) => PropertyDeclarationParseResult::InvalidValue,
}
},
% else:
"${property.name}" => UnknownProperty,
"${property.name}" => PropertyDeclarationParseResult::UnknownProperty,
% endif
% endfor
% for shorthand in SHORTHANDS:
"${shorthand.name}" => {
if ${" && ".join("seen.get_%s()" % sub_property.ident
for sub_property in shorthand.sub_properties)} {
return ValidOrIgnoredDeclaration
return PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
}
match CSSWideKeyword::parse(value) {
Ok(InheritKeyword) => {
Ok(CSSWideKeyword::InheritKeyword) => {
% for sub_property in shorthand.sub_properties:
if !seen.get_${sub_property.ident}() {
seen.set_${sub_property.ident}();
result_list.push(
${sub_property.camel_case}Declaration(Inherit));
PropertyDeclaration::${sub_property.camel_case}Declaration(
DeclaredValue::Inherit));
}
% endfor
ValidOrIgnoredDeclaration
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
},
Ok(InitialKeyword) => {
Ok(CSSWideKeyword::InitialKeyword) => {
% for sub_property in shorthand.sub_properties:
if !seen.get_${sub_property.ident}() {
seen.set_${sub_property.ident}();
result_list.push(
${sub_property.camel_case}Declaration(Initial));
PropertyDeclaration::${sub_property.camel_case}Declaration(
DeclaredValue::Initial));
}
% endfor
ValidOrIgnoredDeclaration
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
},
Ok(UnsetKeyword) => {
Ok(CSSWideKeyword::UnsetKeyword) => {
% for sub_property in shorthand.sub_properties:
if !seen.get_${sub_property.ident}() {
seen.set_${sub_property.ident}();
result_list.push(${sub_property.camel_case}Declaration(
${"Inherit" if sub_property.style_struct.inherited else "Initial"}
result_list.push(PropertyDeclaration::${sub_property.camel_case}Declaration(
DeclaredValue::${"Inherit" if sub_property.style_struct.inherited else "Initial"}
));
}
% endfor
ValidOrIgnoredDeclaration
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
},
Err(()) => match shorthands::${shorthand.ident}::parse(value, base_url) {
Ok(result) => {
% for sub_property in shorthand.sub_properties:
if !seen.get_${sub_property.ident}() {
seen.set_${sub_property.ident}();
result_list.push(${sub_property.camel_case}Declaration(
result_list.push(PropertyDeclaration::${sub_property.camel_case}Declaration(
match result.${sub_property.ident} {
Some(value) => SpecifiedValue(value),
None => Initial,
Some(value) => DeclaredValue::SpecifiedValue(value),
None => DeclaredValue::Initial,
}
));
}
% endfor
ValidOrIgnoredDeclaration
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
},
Err(()) => InvalidValue,
Err(()) => PropertyDeclarationParseResult::InvalidValue,
}
}
},
% endfor
_ => UnknownProperty,
_ => PropertyDeclarationParseResult::UnknownProperty,
}
}
}
@ -2308,8 +2320,8 @@ impl ComputedValues {
#[inline]
pub fn resolve_color(&self, color: computed::CSSColor) -> RGBA {
match color {
RGBAColor(rgba) => rgba,
CurrentColor => self.get_color().color,
Color::RGBA(rgba) => rgba,
Color::CurrentColor => self.get_color().color,
}
}
@ -2414,27 +2426,27 @@ fn get_writing_mode(inheritedbox_style: &style_structs::InheritedBox) -> Writing
use servo_util::logical_geometry;
let mut flags = WritingMode::empty();
match inheritedbox_style.direction {
computed_values::direction::ltr => {},
computed_values::direction::rtl => {
computed_values::direction::T::ltr => {},
computed_values::direction::T::rtl => {
flags.insert(logical_geometry::FLAG_RTL);
},
}
match inheritedbox_style.writing_mode {
computed_values::writing_mode::horizontal_tb => {},
computed_values::writing_mode::vertical_rl => {
computed_values::writing_mode::T::horizontal_tb => {},
computed_values::writing_mode::T::vertical_rl => {
flags.insert(logical_geometry::FLAG_VERTICAL);
},
computed_values::writing_mode::vertical_lr => {
computed_values::writing_mode::T::vertical_lr => {
flags.insert(logical_geometry::FLAG_VERTICAL);
flags.insert(logical_geometry::FLAG_VERTICAL_LR);
},
}
match inheritedbox_style.text_orientation {
computed_values::text_orientation::sideways_right => {},
computed_values::text_orientation::sideways_left => {
computed_values::text_orientation::T::sideways_right => {},
computed_values::text_orientation::T::sideways_left => {
flags.insert(logical_geometry::FLAG_VERTICAL_LR);
},
computed_values::text_orientation::sideways => {
computed_values::text_orientation::T::sideways => {
if flags.intersects(logical_geometry::FLAG_VERTICAL_LR) {
flags.insert(logical_geometry::FLAG_SIDEWAYS_LEFT);
}
@ -2492,21 +2504,21 @@ fn cascade_with_cached_declarations(applicable_declarations: &[DeclarationBlock]
% for style_struct in STYLE_STRUCTS:
% for property in style_struct.longhands:
% if property.derived_from is None:
${property.camel_case}Declaration(ref ${'_' if not style_struct.inherited else ''}declared_value) => {
PropertyDeclaration::${property.camel_case}Declaration(ref ${'_' if not style_struct.inherited else ''}declared_value) => {
% if style_struct.inherited:
if seen.get_${property.ident}() {
continue
}
seen.set_${property.ident}();
let computed_value = match *declared_value {
SpecifiedValue(ref specified_value)
DeclaredValue::SpecifiedValue(ref specified_value)
=> longhands::${property.ident}::to_computed_value(
(*specified_value).clone(),
context
),
Initial
DeclaredValue::Initial
=> longhands::${property.ident}::get_initial_value(),
Inherit => {
DeclaredValue::Inherit => {
// This is a bit slow, but this is rare so it shouldn't
// matter.
//
@ -2538,7 +2550,7 @@ fn cascade_with_cached_declarations(applicable_declarations: &[DeclarationBlock]
% endif
}
% else:
${property.camel_case}Declaration(_) => {
PropertyDeclaration::${property.camel_case}Declaration(_) => {
// Do not allow stylesheets to set derived properties.
}
% endif
@ -2613,9 +2625,9 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock],
macro_rules! get_specified(
($style_struct_getter: ident, $property: ident, $declared_value: expr) => {
match *$declared_value {
SpecifiedValue(specified_value) => specified_value,
Initial => longhands::$property::get_initial_value(),
Inherit => inherited_style.$style_struct_getter().$property.clone(),
DeclaredValue::SpecifiedValue(specified_value) => specified_value,
DeclaredValue::Initial => longhands::$property::get_initial_value(),
DeclaredValue::Inherit => inherited_style.$style_struct_getter().$property.clone(),
}
};
)
@ -2626,39 +2638,39 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock],
// Declarations are stored in reverse source order, we want them in forward order here.
for declaration in sub_list.declarations.iter().rev() {
match *declaration {
FontSizeDeclaration(ref value) => {
PropertyDeclaration::FontSizeDeclaration(ref value) => {
context.font_size = match *value {
SpecifiedValue(specified_value) => computed::compute_Au_with_font_size(
DeclaredValue::SpecifiedValue(specified_value) => computed::compute_Au_with_font_size(
specified_value, context.inherited_font_size, context.root_font_size),
Initial => longhands::font_size::get_initial_value(),
Inherit => context.inherited_font_size,
DeclaredValue::Initial => longhands::font_size::get_initial_value(),
DeclaredValue::Inherit => context.inherited_font_size,
}
}
ColorDeclaration(ref value) => {
PropertyDeclaration::ColorDeclaration(ref value) => {
context.color = get_specified!(get_color, color, value);
}
DisplayDeclaration(ref value) => {
PropertyDeclaration::DisplayDeclaration(ref value) => {
context.display = get_specified!(get_box, display, value);
}
PositionDeclaration(ref value) => {
PropertyDeclaration::PositionDeclaration(ref value) => {
context.positioned = match get_specified!(get_box, position, value) {
longhands::position::absolute | longhands::position::fixed => true,
longhands::position::T::absolute | longhands::position::T::fixed => true,
_ => false,
}
}
FloatDeclaration(ref value) => {
PropertyDeclaration::FloatDeclaration(ref value) => {
context.floated = get_specified!(get_box, float, value)
!= longhands::float::none;
!= longhands::float::T::none;
}
TextDecorationDeclaration(ref value) => {
PropertyDeclaration::TextDecorationDeclaration(ref value) => {
context.text_decoration = get_specified!(get_text, text_decoration, value);
}
% for side in ["top", "right", "bottom", "left"]:
Border${side.capitalize()}StyleDeclaration(ref value) => {
PropertyDeclaration::Border${side.capitalize()}StyleDeclaration(ref value) => {
context.border_${side}_present =
match get_specified!(get_border, border_${side}_style, value) {
longhands::border_top_style::none |
longhands::border_top_style::hidden => false,
longhands::border_top_style::T::none |
longhands::border_top_style::T::hidden => false,
_ => true,
};
}
@ -2700,20 +2712,20 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock],
% for style_struct in STYLE_STRUCTS:
% for property in style_struct.longhands:
% if property.derived_from is None:
${property.camel_case}Declaration(ref declared_value) => {
PropertyDeclaration::${property.camel_case}Declaration(ref declared_value) => {
if seen.get_${property.ident}() {
continue
}
seen.set_${property.ident}();
let computed_value = match *declared_value {
SpecifiedValue(ref specified_value)
DeclaredValue::SpecifiedValue(ref specified_value)
=> longhands::${property.ident}::to_computed_value(
(*specified_value).clone(),
&context
),
Initial
DeclaredValue::Initial
=> longhands::${property.ident}::get_initial_value(),
Inherit => {
DeclaredValue::Inherit => {
// This is a bit slow, but this is rare so it shouldn't
// matter.
//
@ -2740,7 +2752,7 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock],
% endif
}
% else:
${property.camel_case}Declaration(_) => {
PropertyDeclaration::${property.camel_case}Declaration(_) => {
// Do not allow stylesheets to set derived properties.
}
% endif
@ -2824,7 +2836,7 @@ pub mod computed_values {
pub use cssparser::RGBA;
pub use super::common_types::computed::{
LengthOrPercentage, LP_Length, LP_Percentage,
LengthOrPercentageOrAuto, LPA_Length, LPA_Percentage, LPA_Auto,
LengthOrPercentageOrNone, LPN_Length, LPN_Percentage, LPN_None};
LengthOrPercentage,
LengthOrPercentageOrAuto,
LengthOrPercentageOrNone};
}

View file

@ -20,26 +20,16 @@ use legacy::PresentationalHintSynthesis;
use media_queries::Device;
use node::{TElement, TElementAttributes, TNode};
use properties::{PropertyDeclaration, PropertyDeclarationBlock};
use selectors::{After, AnyLink, AttrDashMatch, AttrEqual};
use selectors::{AttrExists, AttrIncludes, AttrPrefixMatch};
use selectors::{AttrSubstringMatch, AttrSuffixMatch, Before, CaseInsensitive, CaseSensitive};
use selectors::{Checked, Child, ClassSelector, Indeterminate};
use selectors::{CompoundSelector, Descendant, Disabled, Enabled, FirstChild, FirstOfType};
use selectors::{Hover, IDSelector, LastChild, LastOfType};
use selectors::{LaterSibling, LocalName, LocalNameSelector};
use selectors::{NamespaceSelector, Link, Negation};
use selectors::{NextSibling, NthChild};
use selectors::{NthLastChild, NthLastOfType};
use selectors::{NthOfType, OnlyChild, OnlyOfType, PseudoElement, Root};
use selectors::{SelectorList, ServoNonzeroBorder, SimpleSelector, Visited};
use selectors::{CaseSensitivity, Combinator, CompoundSelector, LocalName};
use selectors::{PseudoElement, SelectorList, SimpleSelector};
use selectors::{get_selector_list_selectors};
use stylesheets::{Stylesheet, iter_stylesheet_media_rules, iter_stylesheet_style_rules};
#[deriving(Clone, PartialEq)]
pub enum StylesheetOrigin {
UserAgentOrigin,
AuthorOrigin,
UserOrigin,
UserAgent,
Author,
User,
}
/// The definition of whitespace per CSS Selectors Level 3 § 4.
@ -232,7 +222,7 @@ impl SelectorMap {
match *ss {
// TODO(pradeep): Implement case-sensitivity based on the document type and quirks
// mode.
IDSelector(ref id) => return Some(id.clone()),
SimpleSelector::IDSelector(ref id) => return Some(id.clone()),
_ => {}
}
}
@ -246,7 +236,7 @@ impl SelectorMap {
match *ss {
// TODO(pradeep): Implement case-sensitivity based on the document type and quirks
// mode.
ClassSelector(ref class) => return Some(class.clone()),
SimpleSelector::ClassSelector(ref class) => return Some(class.clone()),
_ => {}
}
}
@ -258,7 +248,7 @@ impl SelectorMap {
let simple_selector_sequence = &rule.selector.simple_selectors;
for ss in simple_selector_sequence.iter() {
match *ss {
LocalNameSelector(ref name) => {
SimpleSelector::LocalNameSelector(ref name) => {
return Some(name.clone())
}
_ => {}
@ -314,7 +304,7 @@ impl Stylist {
Url::parse(format!("chrome:///{}", filename).as_slice()).unwrap(),
None,
None,
UserAgentOrigin);
StylesheetOrigin::UserAgent);
stylist.add_stylesheet(ua_stylesheet);
}
stylist
@ -329,17 +319,17 @@ impl Stylist {
for stylesheet in self.stylesheets.iter() {
let (mut element_map, mut before_map, mut after_map) = match stylesheet.origin {
UserAgentOrigin => (
StylesheetOrigin::UserAgent => (
&mut self.element_map.user_agent,
&mut self.before_map.user_agent,
&mut self.after_map.user_agent,
),
AuthorOrigin => (
StylesheetOrigin::Author => (
&mut self.element_map.author,
&mut self.before_map.author,
&mut self.after_map.author,
),
UserOrigin => (
StylesheetOrigin::User => (
&mut self.element_map.user,
&mut self.before_map.user,
&mut self.after_map.user,
@ -355,8 +345,8 @@ impl Stylist {
for selector in $style_rule.selectors.iter() {
let map = match selector.pseudo_element {
None => &mut element_map,
Some(Before) => &mut before_map,
Some(After) => &mut after_map,
Some(PseudoElement::Before) => &mut before_map,
Some(PseudoElement::After) => &mut after_map,
};
map.$priority.insert(Rule {
selector: selector.compound_selectors.clone(),
@ -406,7 +396,7 @@ impl Stylist {
Url::parse("chrome:///quirks-mode.css").unwrap(),
None,
None,
UserAgentOrigin))
StylesheetOrigin::UserAgent))
}
pub fn add_stylesheet(&mut self, stylesheet: Stylesheet) {
@ -438,8 +428,8 @@ impl Stylist {
let map = match pseudo_element {
None => &self.element_map,
Some(Before) => &self.before_map,
Some(After) => &self.after_map,
Some(PseudoElement::Before) => &self.before_map,
Some(PseudoElement::After) => &self.after_map,
};
let mut shareable = true;
@ -588,7 +578,7 @@ fn matches_compound_selector<'a,E,N>(selector: &CompoundSelector,
-> bool
where E: TElement<'a>, N: TNode<'a,E> {
match matches_compound_selector_internal(selector, element, parent_bf, shareable) {
Matched => true,
SelectorMatchingResult::Matched => true,
_ => false
}
}
@ -653,7 +643,7 @@ fn can_fast_reject<'a,E,N>(mut selector: &CompoundSelector,
where E: TElement<'a>, N: TNode<'a,E> {
if !selector.simple_selectors.iter().all(|simple_selector| {
matches_simple_selector(simple_selector, element, shareable) }) {
return Some(NotMatchedAndRestartFromClosestLaterSibling);
return Some(SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling);
}
let bf: &BloomFilter = match *parent_bf {
@ -666,7 +656,7 @@ fn can_fast_reject<'a,E,N>(mut selector: &CompoundSelector,
loop {
match selector.next {
None => break,
Some((ref cs, Descendant)) => selector = &**cs,
Some((ref cs, Combinator::Descendant)) => selector = &**cs,
Some((ref cs, _)) => {
selector = &**cs;
continue;
@ -675,25 +665,25 @@ fn can_fast_reject<'a,E,N>(mut selector: &CompoundSelector,
for ss in selector.simple_selectors.iter() {
match *ss {
LocalNameSelector(LocalName { ref name, ref lower_name }) => {
SimpleSelector::LocalNameSelector(LocalName { ref name, ref lower_name }) => {
if !bf.might_contain(name)
&& !bf.might_contain(lower_name) {
return Some(NotMatchedGlobally);
return Some(SelectorMatchingResult::NotMatchedGlobally);
}
},
NamespaceSelector(ref namespace) => {
SimpleSelector::NamespaceSelector(ref namespace) => {
if !bf.might_contain(namespace) {
return Some(NotMatchedGlobally);
return Some(SelectorMatchingResult::NotMatchedGlobally);
}
},
IDSelector(ref id) => {
SimpleSelector::IDSelector(ref id) => {
if !bf.might_contain(id) {
return Some(NotMatchedGlobally);
return Some(SelectorMatchingResult::NotMatchedGlobally);
}
},
ClassSelector(ref class) => {
SimpleSelector::ClassSelector(ref class) => {
if !bf.might_contain(class) {
return Some(NotMatchedGlobally);
return Some(SelectorMatchingResult::NotMatchedGlobally);
}
},
_ => {},
@ -718,13 +708,13 @@ fn matches_compound_selector_internal<'a,E,N>(selector: &CompoundSelector,
};
match selector.next {
None => Matched,
None => SelectorMatchingResult::Matched,
Some((ref next_selector, combinator)) => {
let (siblings, candidate_not_found) = match combinator {
Child => (false, NotMatchedGlobally),
Descendant => (false, NotMatchedGlobally),
NextSibling => (true, NotMatchedAndRestartFromClosestDescendant),
LaterSibling => (true, NotMatchedAndRestartFromClosestDescendant),
Combinator::Child => (false, SelectorMatchingResult::NotMatchedGlobally),
Combinator::Descendant => (false, SelectorMatchingResult::NotMatchedGlobally),
Combinator::NextSibling => (true, SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant),
Combinator::LaterSibling => (true, SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant),
};
let mut node = (*element).clone();
loop {
@ -744,25 +734,25 @@ fn matches_compound_selector_internal<'a,E,N>(selector: &CompoundSelector,
shareable);
match (result, combinator) {
// Return the status immediately.
(Matched, _) => return result,
(NotMatchedGlobally, _) => return result,
(SelectorMatchingResult::Matched, _) => return result,
(SelectorMatchingResult::NotMatchedGlobally, _) => return result,
// Upgrade the failure status to
// NotMatchedAndRestartFromClosestDescendant.
(_, Child) => return NotMatchedAndRestartFromClosestDescendant,
(_, Combinator::Child) => return SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant,
// Return the status directly.
(_, NextSibling) => return result,
(_, Combinator::NextSibling) => return result,
// If the failure status is NotMatchedAndRestartFromClosestDescendant
// and combinator is LaterSibling, give up this LaterSibling matching
// and combinator is Combinator::LaterSibling, give up this Combinator::LaterSibling matching
// and restart from the closest descendant combinator.
(NotMatchedAndRestartFromClosestDescendant, LaterSibling) => return result,
(SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant, Combinator::LaterSibling) => return result,
// The Descendant combinator and the status is
// The Combinator::Descendant combinator and the status is
// NotMatchedAndRestartFromClosestLaterSibling or
// NotMatchedAndRestartFromClosestDescendant,
// or the LaterSibling combinator and the status is
// or the Combinator::LaterSibling combinator and the status is
// NotMatchedAndRestartFromClosestDescendant
// can continue to matching on the next candidate element.
_ => {},
@ -789,8 +779,8 @@ pub struct CommonStyleAffectingAttributeInfo {
}
pub enum CommonStyleAffectingAttributeMode {
AttrIsPresentMode(CommonStyleAffectingAttributes),
AttrIsEqualMode(&'static str, CommonStyleAffectingAttributes),
IsPresent(CommonStyleAffectingAttributes),
IsEqual(&'static str, CommonStyleAffectingAttributes),
}
// NB: This must match the order in `layout::css::matching::CommonStyleAffectingAttributes`.
@ -799,23 +789,23 @@ pub fn common_style_affecting_attributes() -> [CommonStyleAffectingAttributeInfo
[
CommonStyleAffectingAttributeInfo {
atom: atom!("hidden"),
mode: AttrIsPresentMode(HIDDEN_ATTRIBUTE),
mode: CommonStyleAffectingAttributeMode::IsPresent(HIDDEN_ATTRIBUTE),
},
CommonStyleAffectingAttributeInfo {
atom: atom!("nowrap"),
mode: AttrIsPresentMode(NO_WRAP_ATTRIBUTE),
mode: CommonStyleAffectingAttributeMode::IsPresent(NO_WRAP_ATTRIBUTE),
},
CommonStyleAffectingAttributeInfo {
atom: atom!("align"),
mode: AttrIsEqualMode("left", ALIGN_LEFT_ATTRIBUTE),
mode: CommonStyleAffectingAttributeMode::IsEqual("left", ALIGN_LEFT_ATTRIBUTE),
},
CommonStyleAffectingAttributeInfo {
atom: atom!("align"),
mode: AttrIsEqualMode("center", ALIGN_CENTER_ATTRIBUTE),
mode: CommonStyleAffectingAttributeMode::IsEqual("center", ALIGN_CENTER_ATTRIBUTE),
},
CommonStyleAffectingAttributeInfo {
atom: atom!("align"),
mode: AttrIsEqualMode("right", ALIGN_RIGHT_ATTRIBUTE),
mode: CommonStyleAffectingAttributeMode::IsEqual("right", ALIGN_RIGHT_ATTRIBUTE),
}
]
}
@ -840,48 +830,48 @@ pub fn matches_simple_selector<'a,E,N>(selector: &SimpleSelector,
-> bool
where E: TElement<'a>, N: TNode<'a,E> {
match *selector {
LocalNameSelector(LocalName { ref name, ref lower_name }) => {
SimpleSelector::LocalNameSelector(LocalName { ref name, ref lower_name }) => {
let name = if element.is_html_element_in_html_document() { lower_name } else { name };
let element = element.as_element();
element.get_local_name() == name
}
NamespaceSelector(ref namespace) => {
SimpleSelector::NamespaceSelector(ref namespace) => {
let element = element.as_element();
element.get_namespace() == namespace
}
// TODO: case-sensitivity depends on the document type and quirks mode
IDSelector(ref id) => {
SimpleSelector::IDSelector(ref id) => {
*shareable = false;
let element = element.as_element();
element.get_id().map_or(false, |attr| {
attr == *id
})
}
ClassSelector(ref class) => {
SimpleSelector::ClassSelector(ref class) => {
let element = element.as_element();
element.has_class(class)
}
AttrExists(ref attr) => {
SimpleSelector::AttrExists(ref attr) => {
// NB(pcwalton): If you update this, remember to update the corresponding list in
// `can_share_style_with()` as well.
if common_style_affecting_attributes().iter().all(|common_attr_info| {
!(common_attr_info.atom == attr.name && match common_attr_info.mode {
AttrIsPresentMode(_) => true,
AttrIsEqualMode(..) => false,
CommonStyleAffectingAttributeMode::IsPresent(_) => true,
CommonStyleAffectingAttributeMode::IsEqual(..) => false,
})
}) {
*shareable = false;
}
element.match_attr(attr, |_| true)
}
AttrEqual(ref attr, ref value, case_sensitivity) => {
SimpleSelector::AttrEqual(ref attr, ref value, case_sensitivity) => {
if value.as_slice() != "DIR" &&
common_style_affecting_attributes().iter().all(|common_attr_info| {
!(common_attr_info.atom == attr.name && match common_attr_info.mode {
AttrIsEqualMode(target_value, _) => target_value == value.as_slice(),
AttrIsPresentMode(_) => false,
CommonStyleAffectingAttributeMode::IsEqual(target_value, _) => target_value == value.as_slice(),
CommonStyleAffectingAttributeMode::IsPresent(_) => false,
})
}) {
// FIXME(pcwalton): Remove once we start actually supporting RTL text. This is in
@ -890,56 +880,56 @@ pub fn matches_simple_selector<'a,E,N>(selector: &SimpleSelector,
}
element.match_attr(attr, |attr_value| {
match case_sensitivity {
CaseSensitive => attr_value == value.as_slice(),
CaseInsensitive => attr_value.eq_ignore_ascii_case(value.as_slice()),
CaseSensitivity::CaseSensitive => attr_value == value.as_slice(),
CaseSensitivity::CaseInsensitive => attr_value.eq_ignore_ascii_case(value.as_slice()),
}
})
}
AttrIncludes(ref attr, ref value) => {
SimpleSelector::AttrIncludes(ref attr, ref value) => {
*shareable = false;
element.match_attr(attr, |attr_value| {
attr_value.split(SELECTOR_WHITESPACE).any(|v| v == value.as_slice())
})
}
AttrDashMatch(ref attr, ref value, ref dashing_value) => {
SimpleSelector::AttrDashMatch(ref attr, ref value, ref dashing_value) => {
*shareable = false;
element.match_attr(attr, |attr_value| {
attr_value == value.as_slice() ||
attr_value.starts_with(dashing_value.as_slice())
})
}
AttrPrefixMatch(ref attr, ref value) => {
SimpleSelector::AttrPrefixMatch(ref attr, ref value) => {
*shareable = false;
element.match_attr(attr, |attr_value| {
attr_value.starts_with(value.as_slice())
})
}
AttrSubstringMatch(ref attr, ref value) => {
SimpleSelector::AttrSubstringMatch(ref attr, ref value) => {
*shareable = false;
element.match_attr(attr, |attr_value| {
attr_value.contains(value.as_slice())
})
}
AttrSuffixMatch(ref attr, ref value) => {
SimpleSelector::AttrSuffixMatch(ref attr, ref value) => {
*shareable = false;
element.match_attr(attr, |attr_value| {
attr_value.ends_with(value.as_slice())
})
}
AnyLink => {
SimpleSelector::AnyLink => {
*shareable = false;
let element = element.as_element();
element.get_link().is_some()
}
Link => {
SimpleSelector::Link => {
let elem = element.as_element();
match elem.get_link() {
Some(url) => !url_is_visited(url),
None => false,
}
}
Visited => {
SimpleSelector::Visited => {
// NB(pcwalton): When we actually start supporting visited links, remember to update
// `can_share_style_with`.
let elem = element.as_element();
@ -949,91 +939,91 @@ pub fn matches_simple_selector<'a,E,N>(selector: &SimpleSelector,
}
}
Hover => {
SimpleSelector::Hover => {
*shareable = false;
let elem = element.as_element();
elem.get_hover_state()
},
// http://www.whatwg.org/html/#selector-disabled
Disabled => {
SimpleSelector::Disabled => {
*shareable = false;
let elem = element.as_element();
elem.get_disabled_state()
},
// http://www.whatwg.org/html/#selector-enabled
Enabled => {
SimpleSelector::Enabled => {
*shareable = false;
let elem = element.as_element();
elem.get_enabled_state()
},
// https://html.spec.whatwg.org/multipage/scripting.html#selector-checked
Checked => {
SimpleSelector::Checked => {
*shareable = false;
let elem = element.as_element();
elem.get_checked_state()
}
// https://html.spec.whatwg.org/multipage/scripting.html#selector-indeterminate
Indeterminate => {
SimpleSelector::Indeterminate => {
*shareable = false;
let elem = element.as_element();
elem.get_indeterminate_state()
}
FirstChild => {
SimpleSelector::FirstChild => {
*shareable = false;
matches_first_child(element)
}
LastChild => {
SimpleSelector::LastChild => {
*shareable = false;
matches_last_child(element)
}
OnlyChild => {
SimpleSelector::OnlyChild => {
*shareable = false;
matches_first_child(element) && matches_last_child(element)
}
Root => {
SimpleSelector::Root => {
*shareable = false;
matches_root(element)
}
NthChild(a, b) => {
SimpleSelector::NthChild(a, b) => {
*shareable = false;
matches_generic_nth_child(element, a, b, false, false)
}
NthLastChild(a, b) => {
SimpleSelector::NthLastChild(a, b) => {
*shareable = false;
matches_generic_nth_child(element, a, b, false, true)
}
NthOfType(a, b) => {
SimpleSelector::NthOfType(a, b) => {
*shareable = false;
matches_generic_nth_child(element, a, b, true, false)
}
NthLastOfType(a, b) => {
SimpleSelector::NthLastOfType(a, b) => {
*shareable = false;
matches_generic_nth_child(element, a, b, true, true)
}
FirstOfType => {
SimpleSelector::FirstOfType => {
*shareable = false;
matches_generic_nth_child(element, 0, 1, true, false)
}
LastOfType => {
SimpleSelector::LastOfType => {
*shareable = false;
matches_generic_nth_child(element, 0, 1, true, true)
}
OnlyOfType => {
SimpleSelector::OnlyOfType => {
*shareable = false;
matches_generic_nth_child(element, 0, 1, true, false) &&
matches_generic_nth_child(element, 0, 1, true, true)
}
ServoNonzeroBorder => {
SimpleSelector::ServoNonzeroBorder => {
*shareable = false;
let elem = element.as_element();
elem.has_nonzero_border()
}
Negation(ref negated) => {
SimpleSelector::Negation(ref negated) => {
*shareable = false;
!negated.iter().all(|s| matches_simple_selector(s, element, shareable))
},
@ -1186,13 +1176,13 @@ mod tests {
fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> {
use namespaces::NamespaceMap;
use selectors::{ParserContext, parse_selector_list};
use selector_matching::AuthorOrigin;
use selector_matching::StylesheetOrigin;
use cssparser::tokenize;
let namespaces = NamespaceMap::new();
css_selectors.iter().enumerate().map(|(i, selectors)| {
let context = ParserContext {
origin: AuthorOrigin,
origin: StylesheetOrigin::Author,
};
parse_selector_list(&context, tokenize(*selectors).map(|(c, _)| c), &namespaces)
.unwrap().into_iter().map(|s| {

View file

@ -9,7 +9,7 @@ use sync::Arc;
use cssparser::ast::*;
use cssparser::{tokenize, parse_nth};
use selector_matching::{StylesheetOrigin, UserAgentOrigin};
use selector_matching::StylesheetOrigin;
use string_cache::{Atom, Namespace};
use namespaces::NamespaceMap;
@ -114,8 +114,8 @@ pub struct AttrSelector {
#[deriving(Eq, PartialEq, Clone, Hash)]
pub enum NamespaceConstraint {
AnyNamespace,
SpecificNamespace(Namespace),
Any,
Specific(Namespace),
}
@ -162,21 +162,37 @@ fn compute_specificity(mut selector: &CompoundSelector,
specificity: &mut Specificity) {
for simple_selector in simple_selectors.iter() {
match simple_selector {
&LocalNameSelector(..) => specificity.element_selectors += 1,
&IDSelector(..) => specificity.id_selectors += 1,
&ClassSelector(..)
| &AttrExists(..) | &AttrEqual(..) | &AttrIncludes(..) | &AttrDashMatch(..)
| &AttrPrefixMatch(..) | &AttrSubstringMatch(..) | &AttrSuffixMatch(..)
| &AnyLink | &Link | &Visited | &Hover | &Disabled | &Enabled
| &FirstChild | &LastChild | &OnlyChild | &Root | &Checked | &Indeterminate
// | &Empty | &Lang(*)
| &NthChild(..) | &NthLastChild(..)
| &NthOfType(..) | &NthLastOfType(..)
| &FirstOfType | &LastOfType | &OnlyOfType | &ServoNonzeroBorder
=> specificity.class_like_selectors += 1,
&NamespaceSelector(..) => (),
&Negation(ref negated)
=> simple_selectors_specificity(negated.as_slice(), specificity),
&SimpleSelector::LocalNameSelector(..) =>
specificity.element_selectors += 1,
&SimpleSelector::IDSelector(..) =>
specificity.id_selectors += 1,
&SimpleSelector::ClassSelector(..) |
&SimpleSelector::AttrExists(..) |
&SimpleSelector::AttrEqual(..) |
&SimpleSelector::AttrIncludes(..) |
&SimpleSelector::AttrDashMatch(..) |
&SimpleSelector::AttrPrefixMatch(..) |
&SimpleSelector::AttrSubstringMatch(..) |
&SimpleSelector::AttrSuffixMatch(..) |
&SimpleSelector::AnyLink | &SimpleSelector::Link |
&SimpleSelector::Visited | &SimpleSelector::Hover |
&SimpleSelector::Disabled | &SimpleSelector::Enabled |
&SimpleSelector::FirstChild | &SimpleSelector::LastChild |
&SimpleSelector::OnlyChild | &SimpleSelector::Root |
&SimpleSelector::Checked |
&SimpleSelector::Indeterminate |
// &SimpleSelector::Empty | &SimpleSelector::Lang(*) |
&SimpleSelector::NthChild(..) |
&SimpleSelector::NthLastChild(..) |
&SimpleSelector::NthOfType(..) |
&SimpleSelector::NthLastOfType(..) |
&SimpleSelector::FirstOfType | &SimpleSelector::LastOfType |
&SimpleSelector::OnlyOfType |
&SimpleSelector::ServoNonzeroBorder =>
specificity.class_like_selectors += 1,
&SimpleSelector::NamespaceSelector(..) => (),
&SimpleSelector::Negation(ref negated) =>
simple_selectors_specificity(negated.as_slice(), specificity),
}
}
}
@ -201,12 +217,14 @@ fn parse_type_selector<I: Iterator<ComponentValue>>(
Some((namespace, local_name)) => {
let mut simple_selectors = vec!();
match namespace {
SpecificNamespace(ns) => simple_selectors.push(NamespaceSelector(ns)),
AnyNamespace => (),
NamespaceConstraint::Specific(ns) => {
simple_selectors.push(SimpleSelector::NamespaceSelector(ns))
},
NamespaceConstraint::Any => (),
}
match local_name {
Some(name) => {
simple_selectors.push(LocalNameSelector(LocalName {
simple_selectors.push(SimpleSelector::LocalNameSelector(LocalName {
name: Atom::from_slice(name.as_slice()),
lower_name: Atom::from_slice(name.into_ascii_lower().as_slice())
}))
@ -220,8 +238,8 @@ fn parse_type_selector<I: Iterator<ComponentValue>>(
enum SimpleSelectorParseResult {
SimpleSelectorResult(SimpleSelector),
PseudoElementResult(PseudoElement),
SimpleSelector(SimpleSelector),
PseudoElement(PseudoElement),
}
@ -233,8 +251,8 @@ fn parse_qualified_name<I: Iterator<ComponentValue>>(
-> Result<Option<(NamespaceConstraint, Option<String>)>, ()> {
let default_namespace = |local_name| {
let namespace = match namespaces.default {
Some(ref ns) => SpecificNamespace(ns.clone()),
None => AnyNamespace,
Some(ref ns) => NamespaceConstraint::Specific(ns.clone()),
None => NamespaceConstraint::Any,
};
Ok(Some((namespace, local_name)))
};
@ -264,24 +282,24 @@ fn parse_qualified_name<I: Iterator<ComponentValue>>(
None => return Err(()), // Undeclared namespace prefix
Some(ref ns) => (*ns).clone(),
};
explicit_namespace(iter, SpecificNamespace(namespace))
explicit_namespace(iter, NamespaceConstraint::Specific(namespace))
},
_ if in_attr_selector => Ok(Some(
(SpecificNamespace(ns!("")), Some(value)))),
(NamespaceConstraint::Specific(ns!("")), Some(value)))),
_ => default_namespace(Some(value)),
}
},
Some(&Delim('*')) => {
iter.next(); // Consume '*'
match iter.peek() {
Some(&Delim('|')) => explicit_namespace(iter, AnyNamespace),
Some(&Delim('|')) => explicit_namespace(iter, NamespaceConstraint::Any),
_ => {
if !in_attr_selector { default_namespace(None) }
else { Err(()) }
},
}
},
Some(&Delim('|')) => explicit_namespace(iter, SpecificNamespace(ns!(""))),
Some(&Delim('|')) => explicit_namespace(iter, NamespaceConstraint::Specific(ns!(""))),
_ => Ok(None),
}
}
@ -302,20 +320,37 @@ fn parse_attribute_selector(content: Vec<ComponentValue>, namespaces: &Namespace
skip_whitespace(iter);
// TODO: deal with empty value or value containing whitespace (see spec)
let result = match iter.next() {
None => AttrExists(attr), // [foo]
Some(Delim('=')) => AttrEqual(
attr, try!(parse_attribute_value(iter)),
try!(parse_attribute_flags(iter))), // [foo=bar]
Some(IncludeMatch) => AttrIncludes(attr, try!(parse_attribute_value(iter))), // [foo~=bar]
// [foo]
None => SimpleSelector::AttrExists(attr),
// [foo=bar]
Some(Delim('=')) =>
SimpleSelector::AttrEqual(attr, try!(parse_attribute_value(iter)),
try!(parse_attribute_flags(iter))),
// [foo~=bar]
Some(IncludeMatch) =>
SimpleSelector::AttrIncludes(attr, try!(parse_attribute_value(iter))),
// [foo|=bar]
Some(DashMatch) => {
let value = try!(parse_attribute_value(iter));
let dashing_value = format!("{}-", value);
AttrDashMatch(attr, value, dashing_value) // [foo|=bar]
SimpleSelector::AttrDashMatch(attr, value, dashing_value)
},
Some(PrefixMatch) => AttrPrefixMatch(attr, try!(parse_attribute_value(iter))), // [foo^=bar]
// [foo^=bar]
Some(PrefixMatch) =>
SimpleSelector::AttrPrefixMatch(attr, try!(parse_attribute_value(iter))),
// [foo*=bar]
Some(SubstringMatch) => AttrSubstringMatch(attr, try!(parse_attribute_value(iter))),
Some(SuffixMatch) => AttrSuffixMatch(attr, try!(parse_attribute_value(iter))), // [foo$=bar]
Some(SubstringMatch) =>
SimpleSelector::AttrSubstringMatch(attr, try!(parse_attribute_value(iter))),
// [foo$=bar]
Some(SuffixMatch) =>
SimpleSelector::AttrSuffixMatch(attr, try!(parse_attribute_value(iter))),
_ => return Err(())
};
skip_whitespace(iter);
@ -336,9 +371,9 @@ fn parse_attribute_flags<I: Iterator<ComponentValue>>(iter: &mut Iter<I>)
-> Result<CaseSensitivity, ()> {
skip_whitespace(iter);
match iter.next() {
None => Ok(CaseSensitive),
None => Ok(CaseSensitivity::CaseSensitive),
Some(Ident(ref value)) if value.as_slice().eq_ignore_ascii_case("i")
=> Ok(CaseInsensitive),
=> Ok(CaseSensitivity::CaseInsensitive),
_ => Err(())
}
}
@ -388,11 +423,11 @@ fn parse_selector<I>(context: &ParserContext, iter: &mut Iter<I>, namespaces: &N
let combinator = match iter.peek() {
None => break, // EOF
Some(&Comma) => break,
Some(&Delim('>')) => { iter.next(); Child },
Some(&Delim('+')) => { iter.next(); NextSibling },
Some(&Delim('~')) => { iter.next(); LaterSibling },
Some(&Delim('>')) => { iter.next(); Combinator::Child },
Some(&Delim('+')) => { iter.next(); Combinator::NextSibling },
Some(&Delim('~')) => { iter.next(); Combinator::LaterSibling },
Some(_) => {
if any_whitespace { Descendant }
if any_whitespace { Combinator::Descendant }
else { return Err(()) }
}
};
@ -417,14 +452,14 @@ fn parse_negation(context: &ParserContext,
-> Result<SimpleSelector,()> {
let iter = &mut arguments.into_iter().peekable();
match try!(parse_type_selector(iter, namespaces)) {
Some(type_selector) => Ok(Negation(type_selector)),
Some(type_selector) => Ok(SimpleSelector::Negation(type_selector)),
None => {
match try!(parse_one_simple_selector(context,
iter,
namespaces,
/* inside_negation = */ true)) {
Some(SimpleSelectorResult(simple_selector)) => {
Ok(Negation(vec![simple_selector]))
Some(SimpleSelectorParseResult::SimpleSelector(simple_selector)) => {
Ok(SimpleSelector::Negation(vec![simple_selector]))
}
_ => Err(())
}
@ -455,8 +490,8 @@ fn parse_simple_selectors<I>(context: &ParserContext,
namespaces,
/* inside_negation = */ false)) {
None => break,
Some(SimpleSelectorResult(s)) => { simple_selectors.push(s); empty = false },
Some(PseudoElementResult(p)) => { pseudo_element = Some(p); empty = false; break },
Some(SimpleSelectorParseResult::SimpleSelector(s)) => { simple_selectors.push(s); empty = false },
Some(SimpleSelectorParseResult::PseudoElement(p)) => { pseudo_element = Some(p); empty = false; break },
}
}
if empty {
@ -475,10 +510,10 @@ fn parse_functional_pseudo_class(context: &ParserContext,
-> Result<SimpleSelector,()> {
match name.as_slice().to_ascii_lower().as_slice() {
// "lang" => parse_lang(arguments),
"nth-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthChild(a, b)),
"nth-last-child" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastChild(a, b)),
"nth-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthOfType(a, b)),
"nth-last-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| NthLastOfType(a, b)),
"nth-child" => parse_nth(arguments.as_slice()).map(|(a, b)| SimpleSelector::NthChild(a, b)),
"nth-last-child" => parse_nth(arguments.as_slice()).map(|(a, b)| SimpleSelector::NthLastChild(a, b)),
"nth-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| SimpleSelector::NthOfType(a, b)),
"nth-last-of-type" => parse_nth(arguments.as_slice()).map(|(a, b)| SimpleSelector::NthLastOfType(a, b)),
"not" => {
if inside_negation {
Err(())
@ -503,21 +538,21 @@ fn parse_one_simple_selector<I>(context: &ParserContext,
where I: Iterator<ComponentValue> {
match iter.peek() {
Some(&IDHash(_)) => match iter.next() {
Some(IDHash(id)) => Ok(Some(SimpleSelectorResult(
IDSelector(Atom::from_slice(id.as_slice()))))),
Some(IDHash(id)) => Ok(Some(SimpleSelectorParseResult::SimpleSelector(
SimpleSelector::IDSelector(Atom::from_slice(id.as_slice()))))),
_ => panic!("Implementation error, this should not happen."),
},
Some(&Delim('.')) => {
iter.next();
match iter.next() {
Some(Ident(class)) => Ok(Some(SimpleSelectorResult(
ClassSelector(Atom::from_slice(class.as_slice()))))),
Some(Ident(class)) => Ok(Some(SimpleSelectorParseResult::SimpleSelector(
SimpleSelector::ClassSelector(Atom::from_slice(class.as_slice()))))),
_ => Err(()),
}
}
Some(&SquareBracketBlock(_)) => match iter.next() {
Some(SquareBracketBlock(content))
=> Ok(Some(SimpleSelectorResult(try!(parse_attribute_selector(content, namespaces))))),
=> Ok(Some(SimpleSelectorParseResult::SimpleSelector(try!(parse_attribute_selector(content, namespaces))))),
_ => panic!("Implementation error, this should not happen."),
},
Some(&Colon) => {
@ -528,18 +563,18 @@ fn parse_one_simple_selector<I>(context: &ParserContext,
match name.as_slice().to_ascii_lower().as_slice() {
// Supported CSS 2.1 pseudo-elements only.
// ** Do not add to this list! **
"before" => Ok(Some(PseudoElementResult(Before))),
"after" => Ok(Some(PseudoElementResult(After))),
// "first-line" => PseudoElementResult(FirstLine),
// "first-letter" => PseudoElementResult(FirstLetter),
"before" => Ok(Some(SimpleSelectorParseResult::PseudoElement(PseudoElement::Before))),
"after" => Ok(Some(SimpleSelectorParseResult::PseudoElement(PseudoElement::After))),
// "first-line" => SimpleSelectorParseResult::PseudoElement(FirstLine),
// "first-letter" => SimpleSelectorParseResult::PseudoElement(FirstLetter),
_ => Err(())
}
},
Ok(result) => Ok(Some(SimpleSelectorResult(result))),
Ok(result) => Ok(Some(SimpleSelectorParseResult::SimpleSelector(result))),
},
Some(Function(name, arguments))
=> {
Ok(Some(SimpleSelectorResult(try!(parse_functional_pseudo_class(
Ok(Some(SimpleSelectorParseResult::SimpleSelector(try!(parse_functional_pseudo_class(
context,
name,
arguments,
@ -549,7 +584,7 @@ fn parse_one_simple_selector<I>(context: &ParserContext,
Some(Colon) => {
match iter.next() {
Some(Ident(name))
=> Ok(Some(PseudoElementResult(try!(parse_pseudo_element(name))))),
=> Ok(Some(SimpleSelectorParseResult::PseudoElement(try!(parse_pseudo_element(name))))),
_ => Err(()),
}
}
@ -562,23 +597,23 @@ fn parse_one_simple_selector<I>(context: &ParserContext,
fn parse_simple_pseudo_class(context: &ParserContext, name: &str) -> Result<SimpleSelector,()> {
match name.to_ascii_lower().as_slice() {
"any-link" => Ok(AnyLink),
"link" => Ok(Link),
"visited" => Ok(Visited),
"hover" => Ok(Hover),
"disabled" => Ok(Disabled),
"enabled" => Ok(Enabled),
"checked" => Ok(Checked),
"indeterminate" => Ok(Indeterminate),
"first-child" => Ok(FirstChild),
"last-child" => Ok(LastChild),
"only-child" => Ok(OnlyChild),
"root" => Ok(Root),
"first-of-type" => Ok(FirstOfType),
"last-of-type" => Ok(LastOfType),
"only-of-type" => Ok(OnlyOfType),
"-servo-nonzero-border" if context.origin == UserAgentOrigin => Ok(ServoNonzeroBorder),
// "empty" => Ok(Empty),
"any-link" => Ok(SimpleSelector::AnyLink),
"link" => Ok(SimpleSelector::Link),
"visited" => Ok(SimpleSelector::Visited),
"hover" => Ok(SimpleSelector::Hover),
"disabled" => Ok(SimpleSelector::Disabled),
"enabled" => Ok(SimpleSelector::Enabled),
"checked" => Ok(SimpleSelector::Checked),
"indeterminate" => Ok(SimpleSelector::Indeterminate),
"first-child" => Ok(SimpleSelector::FirstChild),
"last-child" => Ok(SimpleSelector::LastChild),
"only-child" => Ok(SimpleSelector::OnlyChild),
"root" => Ok(SimpleSelector::Root),
"first-of-type" => Ok(SimpleSelector::FirstOfType),
"last-of-type" => Ok(SimpleSelector::LastOfType),
"only-of-type" => Ok(SimpleSelector::OnlyOfType),
"-servo-nonzero-border" if context.origin == StylesheetOrigin::UserAgent => Ok(SimpleSelector::ServoNonzeroBorder),
// "empty" => Ok(Empty),
_ => Err(())
}
}
@ -586,8 +621,8 @@ fn parse_simple_pseudo_class(context: &ParserContext, name: &str) -> Result<Simp
fn parse_pseudo_element(name: String) -> Result<PseudoElement, ()> {
match name.as_slice().to_ascii_lower().as_slice() {
// All supported pseudo-elements
"before" => Ok(Before),
"after" => Ok(After),
"before" => Ok(PseudoElement::Before),
"after" => Ok(PseudoElement::After),
// "first-line" => Some(FirstLine),
// "first-letter" => Some(FirstLetter),
_ => Err(())
@ -634,9 +669,11 @@ mod tests {
use sync::Arc;
use cssparser;
use namespaces::NamespaceMap;
use selector_matching::AuthorOrigin;
use selector_matching::StylesheetOrigin;
use string_cache::Atom;
use super::*;
use super::SimpleSelector::*;
use super::PseudoElement::*;
fn parse(input: &str) -> Result<Vec<Selector>, ()> {
parse_ns(input, &NamespaceMap::new())
@ -644,7 +681,7 @@ mod tests {
fn parse_ns(input: &str, namespaces: &NamespaceMap) -> Result<Vec<Selector>, ()> {
let context = ParserContext {
origin: AuthorOrigin,
origin: StylesheetOrigin::Author,
};
parse_selector_list(&context, cssparser::tokenize(input).map(|(v, _)| v), namespaces)
}
@ -658,7 +695,7 @@ mod tests {
assert!(parse("") == Err(()))
assert!(parse("EeÉ") == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(LocalNameSelector(LocalName {
simple_selectors: vec!(SimpleSelector::LocalNameSelector(LocalName {
name: Atom::from_slice("EeÉ"),
lower_name: Atom::from_slice("eeÉ") })),
next: None,
@ -668,7 +705,7 @@ mod tests {
})))
assert!(parse(".foo") == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(ClassSelector(Atom::from_slice("foo"))),
simple_selectors: vec!(SimpleSelector::ClassSelector(Atom::from_slice("foo"))),
next: None,
}),
pseudo_element: None,
@ -676,7 +713,7 @@ mod tests {
})))
assert!(parse("#bar") == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(IDSelector(Atom::from_slice("bar"))),
simple_selectors: vec!(SimpleSelector::IDSelector(Atom::from_slice("bar"))),
next: None,
}),
pseudo_element: None,
@ -684,11 +721,11 @@ mod tests {
})))
assert!(parse("e.foo#bar") == Ok(vec!(Selector {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(LocalNameSelector(LocalName {
simple_selectors: vec!(SimpleSelector::LocalNameSelector(LocalName {
name: Atom::from_slice("e"),
lower_name: Atom::from_slice("e") }),
ClassSelector(Atom::from_slice("foo")),
IDSelector(Atom::from_slice("bar"))),
SimpleSelector::ClassSelector(Atom::from_slice("foo")),
SimpleSelector::IDSelector(Atom::from_slice("bar"))),
next: None,
}),
pseudo_element: None,
@ -698,12 +735,12 @@ mod tests {
compound_selectors: Arc::new(CompoundSelector {
simple_selectors: vec!(IDSelector(Atom::from_slice("bar"))),
next: Some((box CompoundSelector {
simple_selectors: vec!(LocalNameSelector(LocalName {
simple_selectors: vec!(SimpleSelector::LocalNameSelector(LocalName {
name: Atom::from_slice("e"),
lower_name: Atom::from_slice("e") }),
ClassSelector(Atom::from_slice("foo"))),
SimpleSelector::ClassSelector(Atom::from_slice("foo"))),
next: None,
}, Descendant)),
}, Combinator::Descendant)),
}),
pseudo_element: None,
specificity: specificity(1, 1, 1),
@ -716,7 +753,7 @@ mod tests {
simple_selectors: vec!(AttrExists(AttrSelector {
name: Atom::from_slice("Foo"),
lower_name: Atom::from_slice("foo"),
namespace: SpecificNamespace(ns!("")),
namespace: NamespaceConstraint::Specific(ns!("")),
})),
next: None,
}),
@ -731,7 +768,7 @@ mod tests {
simple_selectors: vec!(AttrExists(AttrSelector {
name: Atom::from_slice("Foo"),
lower_name: Atom::from_slice("foo"),
namespace: SpecificNamespace(ns!("")),
namespace: NamespaceConstraint::Specific(ns!("")),
})),
next: None,
}),
@ -769,7 +806,7 @@ mod tests {
name: atom!("div"),
lower_name: atom!("div") })),
next: None,
}, Descendant)),
}, Combinator::Descendant)),
}),
pseudo_element: Some(After),
specificity: specificity(0, 0, 2),

View file

@ -28,9 +28,9 @@ pub struct Stylesheet {
pub enum CSSRule {
CSSStyleRule(StyleRule),
CSSMediaRule(MediaRule),
CSSFontFaceRule(FontFaceRule),
Style(StyleRule),
Media(MediaRule),
FontFace(FontFaceRule),
}
@ -82,11 +82,11 @@ impl Stylesheet {
for rule in ErrorLoggerIterator(parse_stylesheet_rules(tokenize(css))) {
let next_state; // Unitialized to force each branch to set it.
match rule {
QualifiedRule_(rule) => {
Rule::QualifiedRule(rule) => {
next_state = STATE_BODY;
parse_style_rule(&parser_context, rule, &mut rules, &namespaces, &base_url)
},
AtRule_(rule) => {
Rule::AtRule(rule) => {
let lower_name = rule.name.as_slice().to_ascii_lower();
match lower_name.as_slice() {
"charset" => {
@ -170,7 +170,7 @@ pub fn parse_style_rule(context: &ParserContext,
// FIXME: avoid doing this for valid selectors
let serialized = prelude.iter().to_css();
match selectors::parse_selector_list(context, prelude.into_iter(), namespaces) {
Ok(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
Ok(selectors) => parent_rules.push(CSSRule::Style(StyleRule{
selectors: selectors,
declarations: properties::parse_property_declaration_list(block.into_iter(), base_url)
})),
@ -183,11 +183,11 @@ pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
callback: |&StyleRule|) {
for rule in rules.iter() {
match *rule {
CSSStyleRule(ref rule) => callback(rule),
CSSMediaRule(ref rule) => if rule.media_queries.evaluate(device) {
CSSRule::Style(ref rule) => callback(rule),
CSSRule::Media(ref rule) => if rule.media_queries.evaluate(device) {
iter_style_rules(rule.rules.as_slice(), device, |s| callback(s))
},
CSSFontFaceRule(_) => {},
CSSRule::FontFace(_) => {},
}
}
}
@ -195,7 +195,7 @@ pub fn iter_style_rules<'a>(rules: &[CSSRule], device: &media_queries::Device,
pub fn iter_stylesheet_media_rules(stylesheet: &Stylesheet, callback: |&MediaRule|) {
for rule in stylesheet.rules.iter() {
match *rule {
CSSMediaRule(ref rule) => callback(rule),
CSSRule::Media(ref rule) => callback(rule),
_ => {}
}
}