aboutsummaryrefslogtreecommitdiffstats
path: root/components/style
diff options
context:
space:
mode:
authorSimon Sapin <simon.sapin@exyr.org>2015-09-09 20:47:49 +0200
committerSimon Sapin <simon.sapin@exyr.org>2015-09-17 14:48:19 +0200
commit81dd1ab363461898bc42d579468fd7edeea9586b (patch)
treed3445f3916d8f71b6a302f6c2312ab36fa92a4ca /components/style
parentb8fd51e9403ca941acdc09e55851b377c0359fee (diff)
downloadservo-81dd1ab363461898bc42d579468fd7edeea9586b.tar.gz
servo-81dd1ab363461898bc42d579468fd7edeea9586b.zip
Record first and last token type of custom property values.
Diffstat (limited to 'components/style')
-rw-r--r--components/style/Cargo.toml2
-rw-r--r--components/style/custom_properties.rs145
-rw-r--r--components/style/properties.mako.rs11
3 files changed, 98 insertions, 60 deletions
diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml
index ce0553f95f9..c9a5427e47d 100644
--- a/components/style/Cargo.toml
+++ b/components/style/Cargo.toml
@@ -23,7 +23,7 @@ git = "https://github.com/servo/rust-selectors"
features = ["unstable"]
[dependencies.cssparser]
-version = "0.3.8"
+version = "0.3.9"
features = [ "serde-serialization" ]
[dependencies.url]
diff --git a/components/style/custom_properties.rs b/components/style/custom_properties.rs
index c593feb1a6c..6a08249e70e 100644
--- a/components/style/custom_properties.rs
+++ b/components/style/custom_properties.rs
@@ -2,12 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use cssparser::{Parser, Token, SourcePosition, Delimiter};
+use cssparser::{Parser, Token, SourcePosition, Delimiter, TokenSerializationType};
use properties::DeclaredValue;
use std::ascii::AsciiExt;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use string_cache::Atom;
+use util::mem::HeapSizeOf;
// Does not include the `--` prefix
pub type Name = Atom;
@@ -22,38 +23,51 @@ pub fn parse_name(s: &str) -> Result<Name, ()> {
}
#[derive(Clone, PartialEq)]
-pub struct Value {
- /// In CSS syntax
- value: String,
+pub struct SpecifiedValue {
+ css: String,
+
+ first_token: TokenSerializationType,
+ last_token: TokenSerializationType,
/// Custom property names in var() functions.
references: HashSet<Name>,
}
-pub struct BorrowedValue<'a> {
- value: &'a str,
+pub struct BorrowedSpecifiedValue<'a> {
+ css: &'a str,
+ first_token: TokenSerializationType,
+ last_token: TokenSerializationType,
references: Option<&'a HashSet<Name>>,
}
-pub fn parse(input: &mut Parser) -> Result<Value, ()> {
+#[derive(Clone, HeapSizeOf)]
+pub struct ComputedValue {
+ css: String,
+ first_token: TokenSerializationType,
+ last_token: TokenSerializationType,
+}
+
+pub type ComputedValuesMap = HashMap<Name, ComputedValue>;
+
+pub fn parse(input: &mut Parser) -> Result<SpecifiedValue, ()> {
let start = input.position();
let mut references = Some(HashSet::new());
- try!(parse_declaration_value(input, &mut references));
- Ok(Value {
- value: input.slice_from(start).to_owned(),
+ let (first_token, last_token) = try!(parse_declaration_value(input, &mut references));
+ Ok(SpecifiedValue {
+ css: input.slice_from(start).to_owned(),
+ first_token: first_token,
+ last_token: last_token,
references: references.unwrap(),
})
}
/// https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value
pub fn parse_declaration_value(input: &mut Parser, references: &mut Option<HashSet<Name>>)
- -> Result<(), ()> {
+ -> Result<(TokenSerializationType, TokenSerializationType), ()> {
input.parse_until_before(Delimiter::Bang | Delimiter::Semicolon, |input| {
// Need at least one token
let start_position = input.position();
- if input.next_including_whitespace().is_err() {
- return Err(())
- }
+ try!(input.next_including_whitespace());
input.reset(start_position);
parse_declaration_value_block(input, references)
@@ -63,8 +77,16 @@ pub fn parse_declaration_value(input: &mut Parser, references: &mut Option<HashS
/// Like parse_declaration_value,
/// but accept `!` and `;` since they are only invalid at the top level
fn parse_declaration_value_block(input: &mut Parser, references: &mut Option<HashSet<Name>>)
- -> Result<(), ()> {
- while let Ok(token) = input.next() {
+ -> Result<(TokenSerializationType, TokenSerializationType), ()> {
+ let mut first_token_type = TokenSerializationType::nothing();
+ let mut last_token_type = TokenSerializationType::nothing();
+ while let Ok(token) = input.next_including_whitespace_and_comments() {
+ first_token_type.set_if_nothing(token.serialization_type());
+ // This may be OpenParen when it should be Other (for the closing paren)
+ // but that doesn’t make a difference since OpenParen is only special
+ // when it comes *after* an identifier (it would turn into a function)
+ // but a "last" token will only be concantenated *before* another unrelated token.
+ last_token_type = token.serialization_type();
match token {
Token::BadUrl |
Token::BadString |
@@ -92,7 +114,7 @@ fn parse_declaration_value_block(input: &mut Parser, references: &mut Option<Has
_ => {}
}
}
- Ok(())
+ Ok((first_token_type, last_token_type))
}
// If the var function is valid, return Ok((custom_property_name, fallback))
@@ -111,30 +133,37 @@ fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>, references: &mut Optio
/// Add one custom property declaration to a map,
/// unless another with the same name was already there.
-pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Name, BorrowedValue<'a>>>,
- inherited: &'a Option<Arc<HashMap<Name, String>>>,
+pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Name, BorrowedSpecifiedValue<'a>>>,
+ inherited: &'a Option<Arc<HashMap<Name, ComputedValue>>>,
seen: &mut HashSet<&'a Name>,
name: &'a Name,
- value: &'a DeclaredValue<Value>) {
+ specified_value: &'a DeclaredValue<SpecifiedValue>) {
let was_not_already_present = seen.insert(name);
if was_not_already_present {
let map = match *custom_properties {
Some(ref mut map) => map,
None => {
*custom_properties = Some(match *inherited {
- Some(ref inherited) => inherited.iter().map(|(key, value)| {
- (key, BorrowedValue { value: &value, references: None })
+ Some(ref inherited) => inherited.iter().map(|(key, inherited_value)| {
+ (key, BorrowedSpecifiedValue {
+ css: &inherited_value.css,
+ first_token: inherited_value.first_token,
+ last_token: inherited_value.last_token,
+ references: None
+ })
}).collect(),
None => HashMap::new(),
});
custom_properties.as_mut().unwrap()
}
};
- match *value {
- DeclaredValue::Value(ref value) => {
- map.insert(name, BorrowedValue {
- value: &value.value,
- references: Some(&value.references),
+ match *specified_value {
+ DeclaredValue::Value(ref specified_value) => {
+ map.insert(name, BorrowedSpecifiedValue {
+ css: &specified_value.css,
+ first_token: specified_value.first_token,
+ last_token: specified_value.last_token,
+ references: Some(&specified_value.references),
});
},
DeclaredValue::WithVariables { .. } => unreachable!(),
@@ -146,9 +175,9 @@ pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Name, BorrowedValu
}
}
-pub fn finish_cascade(custom_properties: Option<HashMap<&Name, BorrowedValue>>,
- inherited: &Option<Arc<HashMap<Name, String>>>)
- -> Option<Arc<HashMap<Name, String>>> {
+pub fn finish_cascade(custom_properties: Option<HashMap<&Name, BorrowedSpecifiedValue>>,
+ inherited: &Option<Arc<HashMap<Name, ComputedValue>>>)
+ -> Option<Arc<HashMap<Name, ComputedValue>>> {
if let Some(mut map) = custom_properties {
remove_cycles(&mut map);
Some(Arc::new(substitute_all(map, inherited)))
@@ -159,7 +188,7 @@ pub fn finish_cascade(custom_properties: Option<HashMap<&Name, BorrowedValue>>,
/// https://drafts.csswg.org/css-variables/#cycles
/// The initial value of a custom property is represented by this property not being in the map.
-fn remove_cycles(map: &mut HashMap<&Name, BorrowedValue>) {
+fn remove_cycles(map: &mut HashMap<&Name, BorrowedSpecifiedValue>) {
let mut to_remove = HashSet::new();
{
let mut visited = HashSet::new();
@@ -167,7 +196,7 @@ fn remove_cycles(map: &mut HashMap<&Name, BorrowedValue>) {
for name in map.keys() {
walk(map, name, &mut stack, &mut visited, &mut to_remove);
- fn walk<'a>(map: &HashMap<&'a Name, BorrowedValue<'a>>,
+ fn walk<'a>(map: &HashMap<&'a Name, BorrowedSpecifiedValue<'a>>,
name: &'a Name,
stack: &mut Vec<&'a Name>,
visited: &mut HashSet<&'a Name>,
@@ -201,9 +230,9 @@ fn remove_cycles(map: &mut HashMap<&Name, BorrowedValue>) {
}
/// Replace `var()` functions for all custom properties.
-fn substitute_all(custom_properties: HashMap<&Name, BorrowedValue>,
- inherited: &Option<Arc<HashMap<Name, String>>>)
- -> HashMap<Name, String> {
+fn substitute_all(custom_properties: HashMap<&Name, BorrowedSpecifiedValue>,
+ inherited: &Option<Arc<HashMap<Name, ComputedValue>>>)
+ -> HashMap<Name, ComputedValue> {
let mut substituted_map = HashMap::new();
let mut invalid = HashSet::new();
for (&name, value) in &custom_properties {
@@ -219,16 +248,16 @@ fn substitute_all(custom_properties: HashMap<&Name, BorrowedValue>,
/// Also recursively record results for other custom properties referenced by `var()` functions.
/// Return `Err(())` for invalid at computed time.
fn substitute_one(name: &Name,
- value: &BorrowedValue,
- custom_properties: &HashMap<&Name, BorrowedValue>,
- inherited: &Option<Arc<HashMap<Name, String>>>,
+ specified_value: &BorrowedSpecifiedValue,
+ custom_properties: &HashMap<&Name, BorrowedSpecifiedValue>,
+ inherited: &Option<Arc<HashMap<Name, ComputedValue>>>,
substituted: Option<&mut String>,
- substituted_map: &mut HashMap<Name, String>,
+ substituted_map: &mut HashMap<Name, ComputedValue>,
invalid: &mut HashSet<Name>)
-> Result<(), ()> {
- if let Some(value) = substituted_map.get(name) {
+ if let Some(computed_value) = substituted_map.get(name) {
if let Some(substituted) = substituted {
- substituted.push_str(value)
+ substituted.push_str(&computed_value.css)
}
return Ok(())
}
@@ -236,36 +265,46 @@ fn substitute_one(name: &Name,
if invalid.contains(name) {
return Err(());
}
- let value = if value.references.map(|set| set.is_empty()) == Some(false) {
+ let computed_value = if specified_value.references.map(|set| set.is_empty()) == Some(false) {
let mut substituted = String::new();
- let mut input = Parser::new(&value.value);
+ let mut input = Parser::new(&specified_value.css);
let mut start = input.position();
if substitute_block(&mut input, &mut start, &mut substituted, &mut |name, substituted| {
- if let Some(value) = custom_properties.get(name) {
- substitute_one(name, value, custom_properties, inherited,
+ if let Some(other_specified_value) = custom_properties.get(name) {
+ substitute_one(name, other_specified_value, custom_properties, inherited,
Some(substituted), substituted_map, invalid)
} else {
Err(())
}
}).is_ok() {
substituted.push_str(input.slice_from(start));
- substituted
+ ComputedValue {
+ css: substituted,
+ // FIXME: what if these are `var(` or the corresponding `)`?
+ first_token: specified_value.first_token,
+ last_token: specified_value.last_token,
+ }
} else {
// Invalid at computed-value time. Use the inherited value.
- if let Some(value) = inherited.as_ref().and_then(|i| i.get(name)) {
- value.clone()
+ if let Some(inherited_value) = inherited.as_ref().and_then(|i| i.get(name)) {
+ inherited_value.clone()
} else {
invalid.insert(name.clone());
return Err(())
}
}
} else {
- value.value.to_owned()
+ // The specified value contains no var() reference
+ ComputedValue {
+ css: specified_value.css.to_owned(),
+ first_token: specified_value.first_token,
+ last_token: specified_value.last_token,
+ }
};
if let Some(substituted) = substituted {
- substituted.push_str(&value)
+ substituted.push_str(&computed_value.css)
}
- substituted_map.insert(name.clone(), value);
+ substituted_map.insert(name.clone(), computed_value);
Ok(())
}
@@ -334,7 +373,7 @@ fn substitute_block<F>(input: &mut Parser,
/// Replace `var()` functions for a non-custom property.
/// Return `Err(())` for invalid at computed time.
-pub fn substitute(input: &str, custom_properties: &Option<Arc<HashMap<Name, String>>>)
+pub fn substitute(input: &str, custom_properties: &Option<Arc<HashMap<Name, ComputedValue>>>)
-> Result<String, ()> {
let empty_map;
let custom_properties = if let &Some(ref arc) = custom_properties {
@@ -348,7 +387,7 @@ pub fn substitute(input: &str, custom_properties: &Option<Arc<HashMap<Name, Stri
let mut start = input.position();
try!(substitute_block(&mut input, &mut start, &mut substituted, &mut |name, substituted| {
if let Some(value) = custom_properties.get(name) {
- substituted.push_str(value);
+ substituted.push_str(&value.css);
Ok(())
} else {
Err(())
diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs
index 27250d379d8..5940353d78f 100644
--- a/components/style/properties.mako.rs
+++ b/components/style/properties.mako.rs
@@ -6,7 +6,7 @@
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
-use std::collections::{HashSet, HashMap};
+use std::collections::HashSet;
use std::default::Default;
use std::fmt;
use std::fmt::Debug;
@@ -23,7 +23,6 @@ use util::logical_geometry::{LogicalMargin, PhysicalSide, WritingMode};
use euclid::SideOffsets2D;
use euclid::size::Size2D;
use fnv::FnvHasher;
-use string_cache::Atom;
use computed_values;
use parser::{ParserContext, log_css_error};
@@ -5604,7 +5603,7 @@ mod property_bit_field {
% if property.derived_from is None:
fn substitute_variables_${property.ident}<F, R>(
value: &DeclaredValue<longhands::${property.ident}::SpecifiedValue>,
- custom_properties: &Option<Arc<HashMap<Atom, String>>>,
+ custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>,
f: F)
-> R
where F: FnOnce(&DeclaredValue<longhands::${property.ident}::SpecifiedValue>) -> R
@@ -5827,7 +5826,7 @@ pub enum PropertyDeclaration {
% for property in LONGHANDS:
${property.camel_case}(DeclaredValue<longhands::${property.ident}::SpecifiedValue>),
% endfor
- Custom(::custom_properties::Name, DeclaredValue<::custom_properties::Value>),
+ Custom(::custom_properties::Name, DeclaredValue<::custom_properties::SpecifiedValue>),
}
@@ -5988,7 +5987,7 @@ pub struct ComputedValues {
% for style_struct in STYLE_STRUCTS:
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
% endfor
- custom_properties: Option<Arc<HashMap<::custom_properties::Name, String>>>,
+ custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
shareable: bool,
pub writing_mode: WritingMode,
pub root_font_size: Au,
@@ -6222,7 +6221,7 @@ fn cascade_with_cached_declarations(
shareable: bool,
parent_style: &ComputedValues,
cached_style: &ComputedValues,
- custom_properties: Option<Arc<HashMap<Atom, String>>>,
+ custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
context: &computed::Context)
-> ComputedValues {
% for style_struct in STYLE_STRUCTS: