mirror of
https://github.com/servo/servo.git
synced 2025-06-25 09:34:32 +01:00
Support var() in shorthands.
This commit is contained in:
parent
6cd098da30
commit
4abe7cdf97
4 changed files with 111 additions and 51 deletions
|
@ -5,6 +5,7 @@
|
||||||
#![feature(arc_unique)]
|
#![feature(arc_unique)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(concat_idents)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(custom_attribute)]
|
#![feature(custom_attribute)]
|
||||||
#![feature(custom_derive)]
|
#![feature(custom_derive)]
|
||||||
|
|
|
@ -115,6 +115,7 @@ pub mod longhands {
|
||||||
derived_from=derived_from,
|
derived_from=derived_from,
|
||||||
custom_cascade=custom_cascade,
|
custom_cascade=custom_cascade,
|
||||||
experimental=experimental)
|
experimental=experimental)
|
||||||
|
property.style_struct = THIS_STYLE_STRUCT
|
||||||
THIS_STYLE_STRUCT.longhands.append(property)
|
THIS_STYLE_STRUCT.longhands.append(property)
|
||||||
LONGHANDS.append(property)
|
LONGHANDS.append(property)
|
||||||
LONGHANDS_BY_NAME[name] = property
|
LONGHANDS_BY_NAME[name] = property
|
||||||
|
@ -128,7 +129,7 @@ pub mod longhands {
|
||||||
% if derived_from is None:
|
% if derived_from is None:
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use parser::ParserContext;
|
use parser::ParserContext;
|
||||||
use properties::{CSSWideKeyword, DeclaredValue};
|
use properties::{CSSWideKeyword, DeclaredValue, Shorthand};
|
||||||
% endif
|
% endif
|
||||||
use properties::longhands;
|
use properties::longhands;
|
||||||
use properties::property_bit_field::PropertyBitField;
|
use properties::property_bit_field::PropertyBitField;
|
||||||
|
@ -157,7 +158,7 @@ pub mod longhands {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
seen.set_${property.ident}();
|
seen.set_${property.ident}();
|
||||||
let computed_value = substitute_variables(
|
let computed_value = ::properties::substitute_variables_${property.ident}(
|
||||||
declared_value, &style.custom_properties, |value| match *value {
|
declared_value, &style.custom_properties, |value| match *value {
|
||||||
DeclaredValue::Value(ref specified_value) => {
|
DeclaredValue::Value(ref specified_value) => {
|
||||||
specified_value.to_computed_value(&context)
|
specified_value.to_computed_value(&context)
|
||||||
|
@ -193,29 +194,6 @@ pub mod longhands {
|
||||||
% endif
|
% endif
|
||||||
}
|
}
|
||||||
% if derived_from is None:
|
% if derived_from is None:
|
||||||
pub fn substitute_variables<F, R>(value: &DeclaredValue<SpecifiedValue>,
|
|
||||||
custom_properties: &Option<Arc<HashMap<Atom, String>>>,
|
|
||||||
f: F)
|
|
||||||
-> R
|
|
||||||
where F: FnOnce(&DeclaredValue<SpecifiedValue>) -> R {
|
|
||||||
if let DeclaredValue::WithVariables { ref css, ref base_url } = *value {
|
|
||||||
f(&
|
|
||||||
::custom_properties::substitute(css, custom_properties)
|
|
||||||
.and_then(|css| {
|
|
||||||
// As of this writing, only the base URL is used for property values:
|
|
||||||
let context = ParserContext::new(
|
|
||||||
::stylesheets::Origin::Author, base_url);
|
|
||||||
parse_specified(&context, &mut Parser::new(&css))
|
|
||||||
})
|
|
||||||
.unwrap_or(
|
|
||||||
// Invalid at computed-value time.
|
|
||||||
DeclaredValue::${"Inherit" if THIS_STYLE_STRUCT.inherited else "Initial"}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
f(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn parse_declared(context: &ParserContext, input: &mut Parser)
|
pub fn parse_declared(context: &ParserContext, input: &mut Parser)
|
||||||
-> Result<DeclaredValue<SpecifiedValue>, ()> {
|
-> Result<DeclaredValue<SpecifiedValue>, ()> {
|
||||||
match input.try(CSSWideKeyword::parse) {
|
match input.try(CSSWideKeyword::parse) {
|
||||||
|
@ -234,6 +212,7 @@ pub mod longhands {
|
||||||
return Ok(DeclaredValue::WithVariables {
|
return Ok(DeclaredValue::WithVariables {
|
||||||
css: input.slice_from(start).to_owned(),
|
css: input.slice_from(start).to_owned(),
|
||||||
base_url: context.base_url.clone(),
|
base_url: context.base_url.clone(),
|
||||||
|
from_shorthand: Shorthand::None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
specified
|
specified
|
||||||
|
@ -4881,7 +4860,7 @@ pub mod shorthands {
|
||||||
pub mod ${shorthand.ident} {
|
pub mod ${shorthand.ident} {
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use parser::ParserContext;
|
use parser::ParserContext;
|
||||||
use properties::longhands;
|
use properties::{longhands, PropertyDeclaration, DeclaredValue, Shorthand};
|
||||||
|
|
||||||
pub struct Longhands {
|
pub struct Longhands {
|
||||||
% for sub_property in shorthand.sub_properties:
|
% for sub_property in shorthand.sub_properties:
|
||||||
|
@ -4890,8 +4869,44 @@ pub mod shorthands {
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse(context: &ParserContext, input: &mut Parser,
|
||||||
|
declarations: &mut Vec<PropertyDeclaration>)
|
||||||
|
-> Result<(), ()> {
|
||||||
|
input.look_for_var_functions();
|
||||||
|
let start = input.position();
|
||||||
|
let value = parse_value(context, input);
|
||||||
|
let var = input.seen_var_functions();
|
||||||
|
if let Ok(value) = value {
|
||||||
|
% for sub_property in shorthand.sub_properties:
|
||||||
|
declarations.push(PropertyDeclaration::${sub_property.camel_case}(
|
||||||
|
match value.${sub_property.ident} {
|
||||||
|
Some(value) => DeclaredValue::Value(value),
|
||||||
|
None => DeclaredValue::Initial,
|
||||||
|
}
|
||||||
|
));
|
||||||
|
% endfor
|
||||||
|
Ok(())
|
||||||
|
} else if var {
|
||||||
|
input.reset(start);
|
||||||
|
try!(::custom_properties::parse_declaration_value(input, &mut None));
|
||||||
|
let css = input.slice_from(start);
|
||||||
|
% for sub_property in shorthand.sub_properties:
|
||||||
|
declarations.push(PropertyDeclaration::${sub_property.camel_case}(
|
||||||
|
DeclaredValue::WithVariables {
|
||||||
|
css: css.to_owned(),
|
||||||
|
base_url: context.base_url.clone(),
|
||||||
|
from_shorthand: Shorthand::${shorthand.camel_case},
|
||||||
|
}
|
||||||
|
));
|
||||||
|
% endfor
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
|
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
|
||||||
${caller.body()}
|
${caller.body()}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5582,6 +5597,54 @@ mod property_bit_field {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
% for property in LONGHANDS:
|
||||||
|
% 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>>>,
|
||||||
|
f: F)
|
||||||
|
-> R
|
||||||
|
where F: FnOnce(&DeclaredValue<longhands::${property.ident}::SpecifiedValue>) -> R
|
||||||
|
{
|
||||||
|
if let DeclaredValue::WithVariables {
|
||||||
|
ref css, ref base_url, from_shorthand
|
||||||
|
} = *value {
|
||||||
|
f(&
|
||||||
|
::custom_properties::substitute(css, custom_properties)
|
||||||
|
.and_then(|css| {
|
||||||
|
// As of this writing, only the base URL is used for property values:
|
||||||
|
let context = ParserContext::new(
|
||||||
|
::stylesheets::Origin::Author, base_url);
|
||||||
|
let mut input = Parser::new(&css);
|
||||||
|
match from_shorthand {
|
||||||
|
Shorthand::None => {
|
||||||
|
longhands::${property.ident}::parse_specified(&context, &mut input)
|
||||||
|
}
|
||||||
|
% for shorthand in SHORTHANDS:
|
||||||
|
% if property in shorthand.sub_properties:
|
||||||
|
Shorthand::${shorthand.camel_case} => {
|
||||||
|
shorthands::${shorthand.ident}::parse_value(&context, &mut input)
|
||||||
|
.map(|result| match result.${property.ident} {
|
||||||
|
Some(value) => DeclaredValue::Value(value),
|
||||||
|
None => DeclaredValue::Initial,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or(
|
||||||
|
// Invalid at computed-value time.
|
||||||
|
DeclaredValue::${"Inherit" if property.style_struct.inherited else "Initial"}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
f(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
|
||||||
/// Declarations are stored in reverse order.
|
/// Declarations are stored in reverse order.
|
||||||
/// Overridden declarations are skipped.
|
/// Overridden declarations are skipped.
|
||||||
|
@ -5720,11 +5783,19 @@ impl CSSWideKeyword {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||||
|
pub enum Shorthand {
|
||||||
|
None,
|
||||||
|
% for property in SHORTHANDS:
|
||||||
|
${property.camel_case},
|
||||||
|
% endfor
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum DeclaredValue<T> {
|
pub enum DeclaredValue<T> {
|
||||||
Value(T),
|
Value(T),
|
||||||
WithVariables { css: String, base_url: Url },
|
WithVariables { css: String, base_url: Url, from_shorthand: Shorthand },
|
||||||
Initial,
|
Initial,
|
||||||
Inherit,
|
Inherit,
|
||||||
// There is no Unset variant here.
|
// There is no Unset variant here.
|
||||||
|
@ -5736,7 +5807,11 @@ impl<T: ToCss> DeclaredValue<T> {
|
||||||
pub fn specified_value(&self) -> String {
|
pub fn specified_value(&self) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
DeclaredValue::Value(ref inner) => inner.to_css_string(),
|
DeclaredValue::Value(ref inner) => inner.to_css_string(),
|
||||||
DeclaredValue::WithVariables { ref css, .. } => css.clone(),
|
DeclaredValue::WithVariables { ref css, from_shorthand: Shorthand::None, .. } => {
|
||||||
|
css.clone()
|
||||||
|
}
|
||||||
|
// https://drafts.csswg.org/css-variables/#variables-in-shorthands
|
||||||
|
DeclaredValue::WithVariables { .. } => String::new(),
|
||||||
DeclaredValue::Initial => "initial".to_owned(),
|
DeclaredValue::Initial => "initial".to_owned(),
|
||||||
DeclaredValue::Inherit => "inherit".to_owned(),
|
DeclaredValue::Inherit => "inherit".to_owned(),
|
||||||
}
|
}
|
||||||
|
@ -5865,18 +5940,8 @@ impl PropertyDeclaration {
|
||||||
% endfor
|
% endfor
|
||||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
|
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
|
||||||
},
|
},
|
||||||
Err(()) => match shorthands::${shorthand.ident}::parse(context, input) {
|
Err(()) => match shorthands::${shorthand.ident}::parse(context, input, result_list) {
|
||||||
Ok(result) => {
|
Ok(()) => PropertyDeclarationParseResult::ValidOrIgnoredDeclaration,
|
||||||
% for sub_property in shorthand.sub_properties:
|
|
||||||
result_list.push(PropertyDeclaration::${sub_property.camel_case}(
|
|
||||||
match result.${sub_property.ident} {
|
|
||||||
Some(value) => DeclaredValue::Value(value),
|
|
||||||
None => DeclaredValue::Initial,
|
|
||||||
}
|
|
||||||
));
|
|
||||||
% endfor
|
|
||||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
|
|
||||||
},
|
|
||||||
Err(()) => PropertyDeclarationParseResult::InvalidValue,
|
Err(()) => PropertyDeclarationParseResult::InvalidValue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6182,7 +6247,7 @@ fn cascade_with_cached_declarations(
|
||||||
}
|
}
|
||||||
seen.set_${property.ident}();
|
seen.set_${property.ident}();
|
||||||
let computed_value =
|
let computed_value =
|
||||||
longhands::${property.ident}::substitute_variables(
|
substitute_variables_${property.ident}(
|
||||||
declared_value, &custom_properties, |value| match *value {
|
declared_value, &custom_properties, |value| match *value {
|
||||||
DeclaredValue::Value(ref specified_value)
|
DeclaredValue::Value(ref specified_value)
|
||||||
=> specified_value.to_computed_value(context),
|
=> specified_value.to_computed_value(context),
|
||||||
|
@ -6354,7 +6419,7 @@ pub fn cascade(viewport_size: Size2D<Au>,
|
||||||
// This assumes that the computed and specified values have the same Rust type.
|
// This assumes that the computed and specified values have the same Rust type.
|
||||||
macro_rules! get_specified(
|
macro_rules! get_specified(
|
||||||
($style_struct_getter: ident, $property: ident, $declared_value: expr) => {
|
($style_struct_getter: ident, $property: ident, $declared_value: expr) => {
|
||||||
longhands::$property::substitute_variables(
|
concat_idents!(substitute_variables_, $property)(
|
||||||
$declared_value, &custom_properties, |value| match *value {
|
$declared_value, &custom_properties, |value| match *value {
|
||||||
DeclaredValue::Value(specified_value) => specified_value,
|
DeclaredValue::Value(specified_value) => specified_value,
|
||||||
DeclaredValue::Initial => longhands::$property::get_initial_value(),
|
DeclaredValue::Initial => longhands::$property::get_initial_value(),
|
||||||
|
@ -6374,7 +6439,7 @@ pub fn cascade(viewport_size: Size2D<Au>,
|
||||||
for declaration in sub_list.declarations.iter().rev() {
|
for declaration in sub_list.declarations.iter().rev() {
|
||||||
match *declaration {
|
match *declaration {
|
||||||
PropertyDeclaration::FontSize(ref value) => {
|
PropertyDeclaration::FontSize(ref value) => {
|
||||||
context.font_size = longhands::font_size::substitute_variables(
|
context.font_size = substitute_variables_font_size(
|
||||||
value, &custom_properties, |value| match *value {
|
value, &custom_properties, |value| match *value {
|
||||||
DeclaredValue::Value(ref specified_value) => {
|
DeclaredValue::Value(ref specified_value) => {
|
||||||
match specified_value.0 {
|
match specified_value.0 {
|
||||||
|
@ -6395,7 +6460,7 @@ pub fn cascade(viewport_size: Size2D<Au>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
PropertyDeclaration::Color(ref value) => {
|
PropertyDeclaration::Color(ref value) => {
|
||||||
context.color = longhands::color::substitute_variables(
|
context.color = substitute_variables_color(
|
||||||
value, &custom_properties, |value| match *value {
|
value, &custom_properties, |value| match *value {
|
||||||
DeclaredValue::Value(ref specified_value) => {
|
DeclaredValue::Value(ref specified_value) => {
|
||||||
specified_value.parsed
|
specified_value.parsed
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-36.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[variable-reference-38.htm]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue