Bug 1473180 part 1 - Introduce a concept of logical group. r?emilio draft
authorXidorn Quan <me@upsuper.org>
Fri, 13 Jul 2018 11:17:50 +1000
changeset 819499 8831c486a9db5137251ba15c19be5d1e7673774a
parent 819498 daf71c58020a17da2a5f646e0309192cb947ac01
child 819500 0c8cbf0f371c2598d67f92d36972534cf77c5e43
push id116568
push userxquan@mozilla.com
push dateWed, 18 Jul 2018 00:24:45 +0000
reviewersemilio
bugs1473180
milestone63.0a1
Bug 1473180 part 1 - Introduce a concept of logical group. r?emilio MozReview-Commit-ID: GXlf8JNML4N
servo/components/style/properties/data.py
servo/components/style/properties/longhands/border.mako.rs
servo/components/style/properties/longhands/margin.mako.rs
servo/components/style/properties/longhands/padding.mako.rs
servo/components/style/properties/longhands/position.mako.rs
servo/components/style/properties/properties.mako.rs
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -161,17 +161,17 @@ def parse_property_aliases(alias_list):
 
 
 class Longhand(object):
     def __init__(self, style_struct, name, spec=None, animation_value_type=None, keyword=None,
                  predefined_type=None, servo_pref=None, gecko_pref=None,
                  enabled_in="content", need_index=False,
                  gecko_ffi_name=None,
                  allowed_in_keyframe_block=True, cast_type='u8',
-                 logical=False, alias=None, extra_prefixes=None, boxed=False,
+                 logical=False, logical_group=None, alias=None, extra_prefixes=None, boxed=False,
                  flags=None, allowed_in_page_rule=False, allow_quirks=False, ignored_when_colors_disabled=False,
                  vector=False, servo_restyle_damage="repaint"):
         self.name = name
         if not spec:
             raise TypeError("Spec should be specified for %s" % name)
         self.spec = spec
         self.keyword = keyword
         self.predefined_type = predefined_type
@@ -188,16 +188,19 @@ class Longhand(object):
         #  * "content" implies the property is accessible unconditionally,
         #    modulo a pref, set via servo_pref / gecko_pref.
         assert enabled_in in ["", "ua", "chrome", "content"]
         self.enabled_in = enabled_in
         self.need_index = need_index
         self.gecko_ffi_name = gecko_ffi_name or "m" + self.camel_case
         self.cast_type = cast_type
         self.logical = arg_to_bool(logical)
+        self.logical_group = logical_group
+        if self.logical:
+            assert logical_group, "Property " + name + " must have a logical group"
         self.alias = parse_property_aliases(alias)
         self.extra_prefixes = parse_property_aliases(extra_prefixes)
         self.boxed = arg_to_bool(boxed)
         self.flags = flags.split() if flags else []
         self.allowed_in_page_rule = arg_to_bool(allowed_in_page_rule)
         self.allow_quirks = allow_quirks
         self.ignored_when_colors_disabled = ignored_when_colors_disabled
         self.is_vector = vector
--- a/servo/components/style/properties/longhands/border.mako.rs
+++ b/servo/components/style/properties/longhands/border.mako.rs
@@ -22,41 +22,44 @@
     %>
     ${helpers.predefined_type(
         "border-%s-color" % side_name, "Color",
         "computed_value::T::currentcolor()",
         alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-color"),
         spec=maybe_logical_spec(side, "color"),
         animation_value_type="AnimatedColor",
         logical=is_logical,
+        logical_group="border-color",
         allow_quirks=not is_logical,
         flags="APPLIES_TO_FIRST_LETTER",
         ignored_when_colors_disabled=True,
     )}
 
     ${helpers.predefined_type(
         "border-%s-style" % side_name, "BorderStyle",
         "specified::BorderStyle::None",
         alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-style"),
         spec=maybe_logical_spec(side, "style"),
         flags="APPLIES_TO_FIRST_LETTER",
         animation_value_type="discrete" if not is_logical else "none",
         logical=is_logical,
+        logical_group="border-style",
         needs_context=False,
     )}
 
     ${helpers.predefined_type(
         "border-%s-width" % side_name,
         "BorderSideWidth",
         "::values::computed::NonNegativeLength::new(3.)",
         computed_type="::values::computed::NonNegativeLength",
         alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"),
         spec=maybe_logical_spec(side, "width"),
         animation_value_type="NonNegativeLength",
         logical=is_logical,
+        logical_group="border-width",
         flags="APPLIES_TO_FIRST_LETTER GETCS_NEEDS_LAYOUT_FLUSH",
         allow_quirks=not is_logical,
         servo_restyle_damage="reflow rebuild_and_reflow_inline"
     )}
 % endfor
 
 ${helpers.gecko_keyword_conversion(Keyword('border-style',
                                    "none solid double dotted dashed hidden groove ridge inset outset"),
--- a/servo/components/style/properties/longhands/margin.mako.rs
+++ b/servo/components/style/properties/longhands/margin.mako.rs
@@ -15,14 +15,15 @@
     ${helpers.predefined_type(
         "margin-%s" % side[0],
         "LengthOrPercentageOrAuto",
         "computed::LengthOrPercentageOrAuto::Length(computed::Length::new(0.))",
         alias=maybe_moz_logical_alias(product, side, "-moz-margin-%s"),
         allow_quirks=not side[1],
         animation_value_type="ComputedValue",
         logical=side[1],
+        logical_group="margin",
         spec=spec,
         flags="APPLIES_TO_FIRST_LETTER GETCS_NEEDS_LAYOUT_FLUSH",
         allowed_in_page_rule=True,
         servo_restyle_damage="reflow"
     )}
 % endfor
--- a/servo/components/style/properties/longhands/padding.mako.rs
+++ b/servo/components/style/properties/longhands/padding.mako.rs
@@ -16,14 +16,15 @@
     %>
     ${helpers.predefined_type(
         "padding-%s" % side[0],
         "NonNegativeLengthOrPercentage",
         "computed::NonNegativeLengthOrPercentage::zero()",
         alias=maybe_moz_logical_alias(product, side, "-moz-padding-%s"),
         animation_value_type="NonNegativeLengthOrPercentage",
         logical=side[1],
+        logical_group="padding",
         spec=spec,
         flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_PLACEHOLDER GETCS_NEEDS_LAYOUT_FLUSH",
         allow_quirks=not side[1],
         servo_restyle_damage="reflow rebuild_and_reflow_inline"
     )}
 % endfor
--- a/servo/components/style/properties/longhands/position.mako.rs
+++ b/servo/components/style/properties/longhands/position.mako.rs
@@ -13,30 +13,32 @@
     ${helpers.predefined_type(
         side,
         "LengthOrPercentageOrAuto",
         "computed::LengthOrPercentageOrAuto::Auto",
         spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side,
         flags="GETCS_NEEDS_LAYOUT_FLUSH",
         animation_value_type="ComputedValue",
         allow_quirks=True,
-        servo_restyle_damage="reflow_out_of_flow"
+        servo_restyle_damage="reflow_out_of_flow",
+        logical_group="inset",
     )}
 % endfor
 // inset-* logical properties, map to "top" / "left" / "bottom" / "right"
 % for side in LOGICAL_SIDES:
     ${helpers.predefined_type(
         "inset-%s" % side,
         "LengthOrPercentageOrAuto",
         "computed::LengthOrPercentageOrAuto::Auto",
         spec="https://drafts.csswg.org/css-logical-props/#propdef-inset-%s" % side,
         flags="GETCS_NEEDS_LAYOUT_FLUSH",
         alias="offset-%s:layout.css.offset-logical-properties.enabled" % side,
         animation_value_type="ComputedValue",
         logical=True,
+        logical_group="inset",
     )}
 % endfor
 
 #[cfg(feature = "gecko")]
 macro_rules! impl_align_conversions {
     ($name: path) => {
         impl From<u8> for $name {
             fn from(bits: u8) -> $name {
@@ -216,40 +218,43 @@ macro_rules! impl_align_conversions {
         %>
         // width, height, block-size, inline-size
         ${helpers.predefined_type(
             size,
             "MozLength",
             "computed::MozLength::auto()",
             parse_function,
             logical=logical,
+            logical_group="size",
             allow_quirks=not logical,
             spec=spec % size,
             animation_value_type="MozLength",
             flags="GETCS_NEEDS_LAYOUT_FLUSH",
             servo_restyle_damage="reflow"
         )}
         // min-width, min-height, min-block-size, min-inline-size,
         ${helpers.predefined_type(
             "min-%s" % size,
             "MozLength",
             "computed::MozLength::auto()",
             parse_function,
             logical=logical,
+            logical_group="min-size",
             allow_quirks=not logical,
             spec=spec % size,
             animation_value_type="MozLength",
             servo_restyle_damage = "reflow"
         )}
         ${helpers.predefined_type(
             "max-%s" % size,
             "MaxLength",
             "computed::MaxLength::none()",
             parse_function,
             logical=logical,
+            logical_group="max-size",
             allow_quirks=not logical,
             spec=spec % size,
             animation_value_type="MaxLength",
             servo_restyle_damage = "reflow"
         )}
     % else:
         // servo versions (no keyword support)
         ${helpers.predefined_type(size,
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -51,16 +51,17 @@ use values::serialize_atom_name;
 use rule_tree::{CascadeLevel, StrongRuleNode};
 use self::computed_value_flags::*;
 use str::{CssString, CssStringBorrow, CssStringWriter};
 use style_adjuster::StyleAdjuster;
 
 pub use self::declaration_block::*;
 
 <%!
+    from collections import defaultdict
     from data import Method, Keyword, to_rust_ident, to_camel_case, SYSTEM_FONT_LONGHANDS
     import os.path
 %>
 
 #[path="${repr(os.path.join(os.path.dirname(__file__), 'computed_value_flags.rs'))[1:-1]}"]
 pub mod computed_value_flags;
 #[path="${repr(os.path.join(os.path.dirname(__file__), 'declaration_block.rs'))[1:-1]}"]
 pub mod declaration_block;
@@ -836,16 +837,39 @@ bitflags! {
          * they can be checked in the C++ side via ServoCSSPropList.h. */
         /// This property can be animated on the compositor.
         const CAN_ANIMATE_ON_COMPOSITOR = 0;
         /// This shorthand property is accessible from getComputedStyle.
         const SHORTHAND_IN_GETCS = 0;
     }
 }
 
+<%
+    logical_groups = defaultdict(list)
+    for prop in data.longhands:
+        if prop.logical_group:
+            logical_groups[prop.logical_group].append(prop)
+
+    for group, props in logical_groups.iteritems():
+        logical_count = sum(1 for p in props if p.logical)
+        if logical_count * 2 != len(props):
+            raise RuntimeError("Logical group {} has ".format(group) +
+                               "unbalanced logical / physical properties")
+%>
+
+/// A group for properties which may override each other
+/// via logical resolution.
+#[derive(Clone, Copy, Eq, Hash, PartialEq)]
+pub enum LogicalGroup {
+    % for group in logical_groups.iterkeys():
+    /// ${group}
+    ${to_camel_case(group)},
+    % endfor
+}
+
 /// An identifier for a given longhand property.
 #[derive(Clone, Copy, Eq, Hash, MallocSizeOf, PartialEq)]
 #[repr(u16)]
 pub enum LonghandId {
     % for i, property in enumerate(data.longhands):
         /// ${property.name}
         ${property.camel_case} = ${i},
     % endfor
@@ -988,29 +1012,49 @@ impl LonghandId {
     /// the given writing mode.
     ///
     /// Otherwise, return unchanged.
     #[inline]
     pub fn to_physical(&self, wm: WritingMode) -> Self {
         match *self {
             % for property in data.longhands:
             % if property.logical:
+                <% logical_group = property.logical_group %>
                 LonghandId::${property.camel_case} => {
                     <%helpers:logical_setter_helper name="${property.name}">
                     <%def name="inner(physical_ident)">
+                        <%
+                            physical_name = physical_ident.replace("_", "-")
+                            physical_property = data.longhands_by_name[physical_name]
+                            assert logical_group == physical_property.logical_group
+                        %>
                         LonghandId::${to_camel_case(physical_ident)}
                     </%def>
                     </%helpers:logical_setter_helper>
                 }
             % endif
             % endfor
             _ => *self
         }
     }
 
+    /// Return the logical group of this longhand property.
+    pub fn logical_group(&self) -> Option<LogicalGroup> {
+        const LOGICAL_GROUPS: [Option<LogicalGroup>; ${len(data.longhands)}] = [
+            % for prop in data.longhands:
+            % if prop.logical_group:
+            Some(LogicalGroup::${to_camel_case(prop.logical_group)}),
+            % else:
+            None,
+            % endif
+            % endfor
+        ];
+        LOGICAL_GROUPS[*self as usize]
+    }
+
     /// Returns PropertyFlags for given longhand property.
     pub fn flags(&self) -> PropertyFlags {
         match *self {
             % for property in data.longhands:
                 LonghandId::${property.camel_case} =>
                     % for flag in property.flags:
                         PropertyFlags::${flag} |
                     % endfor