From 10f2d3c38e77ab5dcccc223643cf0d0e479e15ee Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Sat, 15 Apr 2017 20:10:02 +1000 Subject: [PATCH 1/4] style: Add support for property value aliases. For keyword-typed properties with aliases but no extra_specified values, the storage of the specified and computed values could be the same, since value aliases are resolved at parse time. But to prevent computed_value::T::parse from recognizing these aliases, we keep the specified and computed value types distinct. --- components/style/properties/data.py | 31 ++++++++++++++ components/style/properties/helpers.mako.rs | 45 ++++++++++++++++++--- components/style_traits/values.rs | 40 ++++++++++++++---- 3 files changed, 103 insertions(+), 13 deletions(-) diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 83e91e020b4..f12a7ffd3b3 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -33,10 +33,20 @@ def to_camel_case(ident): return re.sub("(^|_|-)([a-z])", lambda m: m.group(2).upper(), ident.strip("_").strip("-")) +def parse_aliases(value): + aliases = {} + for pair in value.split(): + [a, v] = pair.split("=") + aliases[a] = v + return aliases + + class Keyword(object): def __init__(self, name, values, gecko_constant_prefix=None, gecko_enum_prefix=None, custom_consts=None, extra_gecko_values=None, extra_servo_values=None, + aliases=None, + extra_gecko_aliases=None, extra_servo_aliases=None, gecko_strip_moz_prefix=True, gecko_inexhaustive=None): self.name = name @@ -48,6 +58,9 @@ class Keyword(object): self.gecko_enum_prefix = gecko_enum_prefix self.extra_gecko_values = (extra_gecko_values or "").split() self.extra_servo_values = (extra_servo_values or "").split() + self.aliases = parse_aliases(aliases or "") + self.extra_gecko_aliases = parse_aliases(extra_gecko_aliases or "") + self.extra_servo_aliases = parse_aliases(extra_servo_aliases or "") self.consts_map = {} if custom_consts is None else custom_consts self.gecko_strip_moz_prefix = gecko_strip_moz_prefix self.gecko_inexhaustive = gecko_inexhaustive or (gecko_enum_prefix is None) @@ -58,6 +71,16 @@ class Keyword(object): def servo_values(self): return self.values + self.extra_servo_values + def gecko_aliases(self): + aliases = self.aliases.copy() + aliases.update(self.extra_gecko_aliases) + return aliases + + def servo_aliases(self): + aliases = self.aliases.copy() + aliases.update(self.extra_servo_aliases) + return aliases + def values_for(self, product): if product == "gecko": return self.gecko_values() @@ -66,6 +89,14 @@ class Keyword(object): else: raise Exception("Bad product: " + product) + def aliases_for(self, product): + if product == "gecko": + return self.gecko_aliases() + elif product == "servo": + return self.servo_aliases() + else: + raise Exception("Bad product: " + product) + def gecko_constant(self, value): moz_stripped = value.replace("-moz-", '') if self.gecko_strip_moz_prefix else value.replace("-moz-", 'moz-') mapped = self.consts_map.get(value) diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 4b6f20e9d7b..49a751bd59f 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -395,9 +395,33 @@ <%def name="single_keyword(name, values, vector=False, **kwargs)"> <%call expr="single_keyword_computed(name, values, vector, **kwargs)"> - use values::computed::ComputedValueAsSpecified; + % if not "extra_specified" in kwargs and ("aliases" in kwargs or (("extra_%s_aliases" % product) in kwargs)): + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, _context: &Context) -> computed_value::T { + match *self { + % for value in data.longhands_by_name[name].keyword.values_for(product): + SpecifiedValue::${to_rust_ident(value)} => computed_value::T::${to_rust_ident(value)}, + % endfor + } + } + #[inline] + fn from_computed_value(computed: &computed_value::T) -> Self { + match *computed { + % for value in data.longhands_by_name[name].keyword.values_for(product): + computed_value::T::${to_rust_ident(value)} => SpecifiedValue::${to_rust_ident(value)}, + % endfor + } + } + } + % else: + use values::computed::ComputedValueAsSpecified; + impl ComputedValueAsSpecified for SpecifiedValue {} + % endif + use values::HasViewportPercentage; - impl ComputedValueAsSpecified for SpecifiedValue {} no_viewport_percentage!(SpecifiedValue); @@ -444,17 +468,25 @@ keyword_kwargs = {a: kwargs.pop(a, None) for a in [ 'gecko_constant_prefix', 'gecko_enum_prefix', 'extra_gecko_values', 'extra_servo_values', + 'aliases', 'extra_gecko_aliases', 'extra_servo_aliases', 'custom_consts', 'gecko_inexhaustive', ]} %> <%def name="inner_body(keyword, extra_specified=None, needs_conversion=False)"> - % if extra_specified: + % if extra_specified or keyword.aliases_for(product): use style_traits::ToCss; define_css_keyword_enum! { SpecifiedValue: - % for value in keyword.values_for(product) + extra_specified.split(): - "${value}" => ${to_rust_ident(value)}, - % endfor + values { + % for value in keyword.values_for(product) + (extra_specified or "").split(): + "${value}" => ${to_rust_ident(value)}, + % endfor + } + aliases { + % for alias, value in keyword.aliases_for(product).iteritems(): + "${alias}" => ${to_rust_ident(value)}, + % endfor + } } % else: pub use self::computed_value::T as SpecifiedValue; @@ -493,6 +525,7 @@ conversion_values = keyword.values_for(product) if extra_specified: conversion_values += extra_specified.split() + conversion_values += keyword.aliases_for(product).keys() %> ${gecko_keyword_conversion(keyword, values=conversion_values)} % endif diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs index 05dab8440f6..663a39fb6ac 100644 --- a/components/style_traits/values.rs +++ b/components/style_traits/values.rs @@ -82,20 +82,43 @@ impl_to_css_for_predefined_type!(::cssparser::UnicodeRange); #[macro_export] macro_rules! define_css_keyword_enum { + ($name: ident: values { $( $css: expr => $variant: ident),+, } + aliases { $( $alias: expr => $alias_variant: ident ),+, }) => { + __define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ] + [ $( $alias => $alias_variant ),+ ]); + }; + ($name: ident: values { $( $css: expr => $variant: ident),+, } + aliases { $( $alias: expr => $alias_variant: ident ),* }) => { + __define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ] + [ $( $alias => $alias_variant ),* ]); + }; + ($name: ident: values { $( $css: expr => $variant: ident),+ } + aliases { $( $alias: expr => $alias_variant: ident ),+, }) => { + __define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ] + [ $( $alias => $alias_variant ),+ ]); + }; + ($name: ident: values { $( $css: expr => $variant: ident),+ } + aliases { $( $alias: expr => $alias_variant: ident ),* }) => { + __define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ] + [ $( $alias => $alias_variant ),* ]); + }; ($name: ident: $( $css: expr => $variant: ident ),+,) => { - __define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]); + __define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ] []); }; ($name: ident: $( $css: expr => $variant: ident ),+) => { - __define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]); + __define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ] []); }; } #[cfg(feature = "servo")] #[macro_export] macro_rules! __define_css_keyword_enum__add_optional_traits { - ($name: ident [ $( $css: expr => $variant: ident ),+ ]) => { + ($name: ident [ $( $css: expr => $variant: ident ),+ ] + [ $( $alias: expr => $alias_variant: ident),* ]) => { __define_css_keyword_enum__actual! { - $name [ Deserialize, Serialize, HeapSizeOf ] [ $( $css => $variant ),+ ] + $name [ Deserialize, Serialize, HeapSizeOf ] + [ $( $css => $variant ),+ ] + [ $( $alias => $alias_variant ),* ] } }; } @@ -103,16 +126,18 @@ macro_rules! __define_css_keyword_enum__add_optional_traits { #[cfg(not(feature = "servo"))] #[macro_export] macro_rules! __define_css_keyword_enum__add_optional_traits { - ($name: ident [ $( $css: expr => $variant: ident ),+ ]) => { + ($name: ident [ $( $css: expr => $variant: ident ),+ ] [ $( $alias: expr => $alias_variant: ident),* ]) => { __define_css_keyword_enum__actual! { - $name [] [ $( $css => $variant ),+ ] + $name [] [ $( $css => $variant ),+ ] [ $( $alias => $alias_variant ),* ] } }; } #[macro_export] macro_rules! __define_css_keyword_enum__actual { - ($name: ident [ $( $derived_trait: ident),* ] [ $( $css: expr => $variant: ident ),+ ]) => { + ($name: ident [ $( $derived_trait: ident),* ] + [ $( $css: expr => $variant: ident ),+ ] + [ $( $alias: expr => $alias_variant: ident ),* ]) => { #[allow(non_camel_case_types, missing_docs)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq $(, $derived_trait )* )] pub enum $name { @@ -130,6 +155,7 @@ macro_rules! __define_css_keyword_enum__actual { pub fn from_ident(ident: &str) -> Result<$name, ()> { match_ignore_ascii_case! { ident, $( $css => Ok($name::$variant), )+ + $( $alias => Ok($name::$alias_variant), )* _ => Err(()) } } From b73916a135d264664aa7591c81f58702300a428e Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Sat, 15 Apr 2017 20:10:24 +1000 Subject: [PATCH 2/4] style: Add Gecko-only support for writing-mode:sideways-{lr,rl}. Fixes #15213. --- components/style/logical_geometry.rs | 13 ++++++-- .../properties/longhand/inherited_box.mako.rs | 1 + .../style/properties/properties.mako.rs | 33 ++++++++++++++----- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/components/style/logical_geometry.rs b/components/style/logical_geometry.rs index 4a79d2d2af3..e9748128f55 100644 --- a/components/style/logical_geometry.rs +++ b/components/style/logical_geometry.rs @@ -29,8 +29,12 @@ bitflags!( const FLAG_RTL = 1 << 0, const FLAG_VERTICAL = 1 << 1, const FLAG_VERTICAL_LR = 1 << 2, - const FLAG_SIDEWAYS = 1 << 3, - const FLAG_UPRIGHT = 1 << 4, + /// For vertical writing modes only. When set, line-over/line-under + /// sides are inverted from block-start/block-end. This flag is + /// set when sideways-lr is used. + const FLAG_LINE_INVERTED = 1 << 3, + const FLAG_SIDEWAYS = 1 << 4, + const FLAG_UPRIGHT = 1 << 5, } ); @@ -50,7 +54,7 @@ impl WritingMode { #[inline] pub fn is_inline_tb(&self) -> bool { // https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical - !self.intersects(FLAG_RTL) + self.intersects(FLAG_RTL) == self.intersects(FLAG_LINE_INVERTED) } #[inline] @@ -145,6 +149,9 @@ impl fmt::Display for WritingMode { if self.intersects(FLAG_SIDEWAYS) { try!(write!(formatter, " Sideways")); } + if self.intersects(FLAG_LINE_INVERTED) { + try!(write!(formatter, " Inverted")); + } } else { try!(write!(formatter, "H")); } diff --git a/components/style/properties/longhand/inherited_box.mako.rs b/components/style/properties/longhand/inherited_box.mako.rs index d8c286301d5..0ca4e231746 100644 --- a/components/style/properties/longhand/inherited_box.mako.rs +++ b/components/style/properties/longhand/inherited_box.mako.rs @@ -18,6 +18,7 @@ ${helpers.single_keyword("visibility", // https://drafts.csswg.org/css-writing-modes-3 ${helpers.single_keyword("writing-mode", "horizontal-tb vertical-rl vertical-lr", + extra_gecko_values="sideways-rl sideways-lr", experimental=True, need_clone=True, animation_type="none", diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 9f5e6816fee..d3d4d807659 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -1936,16 +1936,33 @@ pub fn get_writing_mode(inheritedbox_style: &style_structs::InheritedBox) -> Wri flags.insert(logical_geometry::FLAG_VERTICAL); flags.insert(logical_geometry::FLAG_VERTICAL_LR); }, - } - % if product == "gecko": - match inheritedbox_style.clone_text_orientation() { - computed_values::text_orientation::T::mixed => {}, - computed_values::text_orientation::T::upright => { - flags.insert(logical_geometry::FLAG_UPRIGHT); - }, - computed_values::text_orientation::T::sideways => { + % if product == "gecko": + computed_values::writing_mode::T::sideways_rl => { + flags.insert(logical_geometry::FLAG_VERTICAL); flags.insert(logical_geometry::FLAG_SIDEWAYS); }, + computed_values::writing_mode::T::sideways_lr => { + flags.insert(logical_geometry::FLAG_VERTICAL); + flags.insert(logical_geometry::FLAG_VERTICAL_LR); + flags.insert(logical_geometry::FLAG_LINE_INVERTED); + flags.insert(logical_geometry::FLAG_SIDEWAYS); + }, + % endif + } + % if product == "gecko": + // If FLAG_SIDEWAYS is already set, this means writing-mode is either + // sideways-rl or sideways-lr, and for both of these values, + // text-orientation has no effect. + if !flags.intersects(logical_geometry::FLAG_SIDEWAYS) { + match inheritedbox_style.clone_text_orientation() { + computed_values::text_orientation::T::mixed => {}, + computed_values::text_orientation::T::upright => { + flags.insert(logical_geometry::FLAG_UPRIGHT); + }, + computed_values::text_orientation::T::sideways => { + flags.insert(logical_geometry::FLAG_SIDEWAYS); + }, + } } % endif flags From 35c88367cb8db00d26216f6dfb8475415e25c009 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Sun, 16 Apr 2017 22:06:32 +1000 Subject: [PATCH 3/4] style: Add Gecko-only support for the deprecated SVG 1.1 writing-mode aliases. --- components/style/properties/longhand/inherited_box.mako.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/style/properties/longhand/inherited_box.mako.rs b/components/style/properties/longhand/inherited_box.mako.rs index 0ca4e231746..e6836972f52 100644 --- a/components/style/properties/longhand/inherited_box.mako.rs +++ b/components/style/properties/longhand/inherited_box.mako.rs @@ -19,6 +19,9 @@ ${helpers.single_keyword("visibility", ${helpers.single_keyword("writing-mode", "horizontal-tb vertical-rl vertical-lr", extra_gecko_values="sideways-rl sideways-lr", + extra_gecko_aliases="lr=horizontal-tb lr-tb=horizontal-tb \ + rl=horizontal-tb rl-tb=horizontal-tb \ + tb=vertical-rl tb-rl=vertical-rl", experimental=True, need_clone=True, animation_type="none", From 221aa876504a890c6afed50adb676324efc5fd95 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Sun, 16 Apr 2017 18:26:27 +1000 Subject: [PATCH 4/4] style: Make text-orientation:sideways-right an alias. Gecko does not preserve this specified value; it converts it to sideways at parse time. --- .../properties/longhand/inherited_box.mako.rs | 43 +++---------------- 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/components/style/properties/longhand/inherited_box.mako.rs b/components/style/properties/longhand/inherited_box.mako.rs index e6836972f52..f919a95d406 100644 --- a/components/style/properties/longhand/inherited_box.mako.rs +++ b/components/style/properties/longhand/inherited_box.mako.rs @@ -31,42 +31,13 @@ ${helpers.single_keyword("direction", "ltr rtl", need_clone=True, animation_type spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction", needs_conversion=True)} -<%helpers:single_keyword_computed - name="text-orientation" - values="mixed upright sideways" - extra_specified="sideways-right" - products="gecko" - need_clone="True" - animation_type="none" - spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation" -> - use values::HasViewportPercentage; - no_viewport_percentage!(SpecifiedValue); - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, _: &Context) -> computed_value::T { - match *self { - % for value in "mixed upright sideways".split(): - SpecifiedValue::${value} => computed_value::T::${value}, - % endfor - // https://drafts.csswg.org/css-writing-modes-3/#valdef-text-orientation-sideways-right - SpecifiedValue::sideways_right => computed_value::T::sideways, - } - } - - #[inline] - fn from_computed_value(computed: &computed_value::T) -> SpecifiedValue { - match *computed { - % for value in "mixed upright sideways".split(): - computed_value::T::${value} => SpecifiedValue::${value}, - % endfor - } - } - } - +${helpers.single_keyword("text-orientation", + "mixed upright sideways", + extra_gecko_aliases="sideways-right=sideways", + products="gecko", + need_clone=True, + animation_type="none", + spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation")} // CSS Color Module Level 4 // https://drafts.csswg.org/css-color/