--- 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