Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom properties, take 2 #7555

Merged
merged 10 commits into from Sep 17, 2015
Prev

Initial support for custom properties in CSSStyleDeclaration

  • Loading branch information
SimonSapin committed Sep 17, 2015
commit feaf6f4c3fbee9cafb3fdf9981c3ab639a56195b
@@ -979,7 +979,7 @@ impl LayoutTask {
// FIXME: implement used value computation for line-height
property => {
rw_data.resolved_style_response =
style.computed_value_to_string(property.as_slice());
style.computed_value_to_string(property.as_slice()).ok();
}
};
}
@@ -650,15 +650,15 @@ impl Element {
if let &mut Some(ref mut declarations) = &mut *inline_declarations {
let index = declarations.normal
.iter()
.position(|decl| decl.name() == property);
.position(|decl| decl.matches(property));
if let Some(index) = index {
Arc::make_mut(&mut declarations.normal).remove(index);
return;
}

let index = declarations.important
.iter()
.position(|decl| decl.name() == property);
.position(|decl| decl.matches(property));
if let Some(index) = index {
Arc::make_mut(&mut declarations.important).remove(index);
return;
@@ -715,7 +715,8 @@ impl Element {
let to = Arc::make_mut(to);
let mut new_from = Vec::new();
for declaration in from.drain(..) {
if properties.contains(&declaration.name()) {
let name = declaration.name();
if properties.iter().any(|p| name == **p) {
to.push(declaration)
} else {
new_from.push(declaration)
@@ -2,10 +2,11 @@
* 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, TokenSerializationType};
use cssparser::{Parser, Token, SourcePosition, Delimiter, TokenSerializationType, ToCss};
use properties::DeclaredValue;
use std::ascii::AsciiExt;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::sync::Arc;
use string_cache::Atom;
use util::mem::HeapSizeOf;
@@ -14,9 +15,9 @@ use util::mem::HeapSizeOf;
pub type Name = Atom;

// https://drafts.csswg.org/css-variables/#typedef-custom-property-name
pub fn parse_name(s: &str) -> Result<Name, ()> {
pub fn parse_name(s: &str) -> Result<&str, ()> {
if s.starts_with("--") {
Ok(Atom::from_slice(&s[2..]))
Ok(&s[2..])
} else {
Err(())
}
@@ -47,6 +48,18 @@ pub struct ComputedValue {
last_token_type: TokenSerializationType,
}

impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
dest.write_str(&self.css)
}
}

impl ToCss for ComputedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
dest.write_str(&self.css)
}
}

pub type ComputedValuesMap = HashMap<Name, ComputedValue>;

impl ComputedValue {
@@ -157,7 +170,7 @@ fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>, references: &mut Optio
try!(parse_declaration_value(input, references));
}
if let Some(ref mut refs) = *references {
refs.insert(name);
refs.insert(Atom::from_slice(name));
}
Ok(())
}
@@ -381,7 +394,7 @@ fn substitute_block<F>(input: &mut Parser,
try!(input.parse_nested_block(|input| {
// parse_var_function() ensures neither .unwrap() will fail.
let name = input.expect_ident().unwrap();
let name = parse_name(&name).unwrap();
let name = Atom::from_slice(parse_name(&name).unwrap());

if let Ok(last) = substitute_one(&name, partial_computed_value) {
last_token_type = last;
@@ -5,7 +5,6 @@
// This file is a Mako template: http://www.makotemplates.org/

use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::collections::HashSet;
use std::default::Default;
use std::fmt;
@@ -23,6 +22,7 @@ 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};
@@ -5815,17 +5815,17 @@ pub enum DeclaredValue<T> {
// depending on whether the property is inherited.
}

impl<T: ToCss> DeclaredValue<T> {
pub fn specified_value(&self) -> String {
impl<T: ToCss> ToCss for DeclaredValue<T> {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
DeclaredValue::Value(ref inner) => inner.to_css_string(),
DeclaredValue::Value(ref inner) => inner.to_css(dest),
DeclaredValue::WithVariables { ref css, from_shorthand: Shorthand::None, .. } => {
css.clone()
dest.write_str(css)
}
// https://drafts.csswg.org/css-variables/#variables-in-shorthands
DeclaredValue::WithVariables { .. } => String::new(),
DeclaredValue::Initial => "initial".to_owned(),
DeclaredValue::Inherit => "inherit".to_owned(),
DeclaredValue::WithVariables { .. } => Ok(()),
DeclaredValue::Initial => dest.write_str("initial"),
DeclaredValue::Inherit => dest.write_str("inherit"),
}
}
}
@@ -5847,15 +5847,52 @@ pub enum PropertyDeclarationParseResult {
ValidOrIgnoredDeclaration,
}

#[derive(Eq, PartialEq, Clone)]
pub enum PropertyDeclarationName {
Longhand(&'static str),
Custom(::custom_properties::Name),
Internal
}

impl PartialEq<str> for PropertyDeclarationName {
fn eq(&self, other: &str) -> bool {
match *self {
PropertyDeclarationName::Longhand(n) => n == other,
PropertyDeclarationName::Custom(ref n) => {
::custom_properties::parse_name(other) == Ok(&**n)
}
PropertyDeclarationName::Internal => false,
}
}
}

impl fmt::Display for PropertyDeclarationName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PropertyDeclarationName::Longhand(n) => f.write_str(n),
PropertyDeclarationName::Custom(ref n) => {
try!(f.write_str("--"));
f.write_str(n)
}
PropertyDeclarationName::Internal => Ok(()),
}
}
}

impl PropertyDeclaration {
pub fn name(&self) -> &'static str {
pub fn name(&self) -> PropertyDeclarationName {
match *self {
% for property in LONGHANDS:
% if property.derived_from is None:
PropertyDeclaration::${property.camel_case}(..) => "${property.name}",
PropertyDeclaration::${property.camel_case}(..) => {
PropertyDeclarationName::Longhand("${property.name}")
}
% endif
% endfor
_ => "",
PropertyDeclaration::Custom(ref name, _) => {
PropertyDeclarationName::Custom(name.clone())
}
_ => PropertyDeclarationName::Internal,
}
}

@@ -5864,10 +5901,11 @@ impl PropertyDeclaration {
% for property in LONGHANDS:
% if property.derived_from is None:
PropertyDeclaration::${property.camel_case}(ref value) =>
value.specified_value(),
value.to_css_string(),
% endif
% endfor
ref decl => panic!("unsupported property declaration: {:?}", decl.name()),
PropertyDeclaration::Custom(_, ref value) => value.to_css_string(),
ref decl => panic!("unsupported property declaration: {}", decl.name()),
}
}

@@ -5880,6 +5918,9 @@ impl PropertyDeclaration {
}
% endif
% endfor
PropertyDeclaration::Custom(ref declaration_name, _) => {
::custom_properties::parse_name(name) == Ok(&**declaration_name)
}
_ => false,
}
}
@@ -5896,7 +5937,7 @@ impl PropertyDeclaration {
Err(()) => return PropertyDeclarationParseResult::InvalidValue,
}
};
result_list.push(PropertyDeclaration::Custom(name, value));
result_list.push(PropertyDeclaration::Custom(Atom::from_slice(name), value));
return PropertyDeclarationParseResult::ValidOrIgnoredDeclaration;
}
match_ignore_ascii_case! { name,
@@ -6154,14 +6195,19 @@ impl ComputedValues {
}
% endfor

pub fn computed_value_to_string(&self, name: &str) -> Option<String> {
pub fn computed_value_to_string(&self, name: &str) -> Result<String, ()> {
match name {
% for style_struct in STYLE_STRUCTS:
% for longhand in style_struct.longhands:
"${longhand.name}" => Some(self.${style_struct.ident}.${longhand.ident}.to_css_string()),
"${longhand.name}" => Ok(self.${style_struct.ident}.${longhand.ident}.to_css_string()),
% endfor
% endfor
_ => None
_ => {
let name = try!(::custom_properties::parse_name(name));
let map = try!(self.custom_properties.as_ref().ok_or(()));
let value = try!(map.get(&Atom::from_slice(name)).ok_or(()));
Ok(value.to_css_string())
}
}
}
}
@@ -6777,7 +6823,7 @@ pub fn is_supported_property(property: &str) -> bool {
"${property.name}" => true,
% endfor
"${LONGHANDS[-1].name}" => true
_ => false
_ => property.starts_with("--")
}
}

@@ -287,6 +287,18 @@
"url": "/_mozilla/css/test_variable_legal_values.html"
}
],
"css/test_variable_serialization_computed.html": [
{
"path": "css/test_variable_serialization_computed.html",
"url": "/_mozilla/css/test_variable_serialization_computed.html"
}
],
"css/test_variable_serialization_specified.html": [
{
"path": "css/test_variable_serialization_specified.html",
"url": "/_mozilla/css/test_variable_serialization_specified.html"
}
],
"mozilla/DOMParser.html": [
{
"path": "mozilla/DOMParser.html",
@@ -0,0 +1,56 @@
[test_variable_serialization_computed.html]
type: testharness
[subtest #20 with `--a: var(--b)var(--c); --b:orange; --c:red;`]
expected: FAIL

[subtest #21 with `--a: var(--b)var(--c,red); --b:orange;`]
expected: FAIL

[subtest #22 with `--a: var(--b,orange)var(--c); --c:red;`]
expected: FAIL

[subtest #23 with `counter-reset: var(--a)red; --a:orange;`]
expected: FAIL

[subtest #24 with `--a: var(--b)var(--c); --c:[c\]; --b:('ab`]
expected: FAIL

[subtest #25 with `--a: '`]
expected: FAIL

[subtest #26 with `--a: '\\`]
expected: FAIL

[subtest #27 with `--a: \\`]
expected: FAIL

[subtest #28 with `--a: "`]
expected: FAIL

[subtest #29 with `--a: "\\`]
expected: FAIL

[subtest #30 with `--a: /* abc `]
expected: FAIL

[subtest #31 with `--a: /* abc *`]
expected: FAIL

[subtest #32 with `--a: url(http://example.org/`]
expected: FAIL

[subtest #33 with `--a: url(http://example.org/\\`]
expected: FAIL

[subtest #34 with `--a: url('http://example.org/`]
expected: FAIL

[subtest #35 with `--a: url('http://example.org/\\`]
expected: FAIL

[subtest #36 with `--a: url("http://example.org/`]
expected: FAIL

[subtest #37 with `--a: url("http://example.org/\\`]
expected: FAIL

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.