1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 from counted_unknown_properties
import COUNTED_UNKNOWN_PROPERTIES
8 PHYSICAL_SIDES
= ["top", "right", "bottom", "left"]
9 LOGICAL_SIDES
= ["block-start", "block-end", "inline-start", "inline-end"]
10 PHYSICAL_SIZES
= ["width", "height"]
11 LOGICAL_SIZES
= ["block-size", "inline-size"]
12 PHYSICAL_CORNERS
= ["top-left", "top-right", "bottom-right", "bottom-left"]
13 LOGICAL_CORNERS
= ["start-start", "start-end", "end-start", "end-end"]
14 PHYSICAL_AXES
= ["x", "y"]
15 LOGICAL_AXES
= ["inline", "block"]
17 # bool is True when logical
18 ALL_SIDES
= [(side
, False) for side
in PHYSICAL_SIDES
] + [
19 (side
, True) for side
in LOGICAL_SIDES
21 ALL_SIZES
= [(size
, False) for size
in PHYSICAL_SIZES
] + [
22 (size
, True) for size
in LOGICAL_SIZES
24 ALL_CORNERS
= [(corner
, False) for corner
in PHYSICAL_CORNERS
] + [
25 (corner
, True) for corner
in LOGICAL_CORNERS
27 ALL_AXES
= [(axis
, False) for axis
in PHYSICAL_AXES
] + [
28 (axis
, True) for axis
in LOGICAL_AXES
31 SYSTEM_FONT_LONGHANDS
= """font_family font_size font_style
32 font_stretch font_weight""".split()
34 # Bitfield values for all rule types which can have property declarations.
37 KEYFRAME_RULE
= 1 << 2
39 ALL_RULES
= STYLE_RULE | PAGE_RULE | KEYFRAME_RULE
40 DEFAULT_RULES
= STYLE_RULE | KEYFRAME_RULE
41 DEFAULT_RULES_AND_PAGE
= DEFAULT_RULES | PAGE_RULE
42 DEFAULT_RULES_EXCEPT_KEYFRAME
= STYLE_RULE
44 # Rule name to value dict
48 "Keyframe": KEYFRAME_RULE
,
52 def rule_values_from_arg(that
):
53 if isinstance(that
, int):
56 for rule
in that
.split():
57 mask |
= RULE_VALUES
[rule
]
61 def maybe_moz_logical_alias(engine
, side
, prop
):
62 if engine
== "gecko" and side
[1]:
63 axis
, dir = side
[0].split("-")
69 def to_rust_ident(name
):
70 name
= name
.replace("-", "_")
71 if name
in ["static", "super", "box", "move"]: # Rust keywords
76 def to_snake_case(ident
):
77 return re
.sub("([A-Z]+)", lambda m
: "_" + m
.group(1).lower(), ident
).strip("_")
80 def to_camel_case(ident
):
82 "(^|_|-)([a-z0-9])", lambda m
: m
.group(2).upper(), ident
.strip("_").strip("-")
86 def to_camel_case_lower(ident
):
87 camel
= to_camel_case(ident
)
88 return camel
[0].lower() + camel
[1:]
91 # https://drafts.csswg.org/cssom/#css-property-to-idl-attribute
92 def to_idl_name(ident
):
93 return re
.sub("-([a-z])", lambda m
: m
.group(1).upper(), ident
)
96 def parse_aliases(value
):
98 for pair
in value
.split():
99 [a
, v
] = pair
.split("=")
104 class Keyword(object):
109 gecko_constant_prefix
=None,
110 gecko_enum_prefix
=None,
112 extra_gecko_values
=None,
113 extra_servo_2013_values
=None,
114 extra_servo_2020_values
=None,
116 servo_2013_aliases
=None,
117 servo_2020_aliases
=None,
118 gecko_strip_moz_prefix
=None,
119 gecko_inexhaustive
=None,
122 self
.values
= values
.split()
123 if gecko_constant_prefix
and gecko_enum_prefix
:
125 "Only one of gecko_constant_prefix and gecko_enum_prefix "
128 self
.gecko_constant_prefix
= (
129 gecko_constant_prefix
or "NS_STYLE_" + self
.name
.upper().replace("-", "_")
131 self
.gecko_enum_prefix
= gecko_enum_prefix
132 self
.extra_gecko_values
= (extra_gecko_values
or "").split()
133 self
.extra_servo_2013_values
= (extra_servo_2013_values
or "").split()
134 self
.extra_servo_2020_values
= (extra_servo_2020_values
or "").split()
135 self
.gecko_aliases
= parse_aliases(gecko_aliases
or "")
136 self
.servo_2013_aliases
= parse_aliases(servo_2013_aliases
or "")
137 self
.servo_2020_aliases
= parse_aliases(servo_2020_aliases
or "")
138 self
.consts_map
= {} if custom_consts
is None else custom_consts
139 self
.gecko_strip_moz_prefix
= (
140 True if gecko_strip_moz_prefix
is None else gecko_strip_moz_prefix
142 self
.gecko_inexhaustive
= gecko_inexhaustive
or (gecko_enum_prefix
is None)
144 def values_for(self
, engine
):
145 if engine
== "gecko":
146 return self
.values
+ self
.extra_gecko_values
147 elif engine
== "servo-2013":
148 return self
.values
+ self
.extra_servo_2013_values
149 elif engine
== "servo-2020":
150 return self
.values
+ self
.extra_servo_2020_values
152 raise Exception("Bad engine: " + engine
)
154 def aliases_for(self
, engine
):
155 if engine
== "gecko":
156 return self
.gecko_aliases
157 elif engine
== "servo-2013":
158 return self
.servo_2013_aliases
159 elif engine
== "servo-2020":
160 return self
.servo_2020_aliases
162 raise Exception("Bad engine: " + engine
)
164 def gecko_constant(self
, value
):
166 value
.replace("-moz-", "")
167 if self
.gecko_strip_moz_prefix
168 else value
.replace("-moz-", "moz-")
170 mapped
= self
.consts_map
.get(value
)
171 if self
.gecko_enum_prefix
:
172 parts
= moz_stripped
.replace("-", "_").split("_")
173 parts
= mapped
if mapped
else [p
.title() for p
in parts
]
174 return self
.gecko_enum_prefix
+ "::" + "".join(parts
)
176 suffix
= mapped
if mapped
else moz_stripped
.replace("-", "_")
177 return self
.gecko_constant_prefix
+ "_" + suffix
.upper()
179 def needs_cast(self
):
180 return self
.gecko_enum_prefix
is None
182 def maybe_cast(self
, type_str
):
183 return "as " + type_str
if self
.needs_cast() else ""
185 def casted_constant_name(self
, value
, cast_type
):
186 if cast_type
is None:
187 raise TypeError("We should specify the cast_type.")
189 if self
.gecko_enum_prefix
is None:
190 return cast_type
.upper() + "_" + self
.gecko_constant(value
)
195 + self
.gecko_constant(value
).upper().replace("::", "_")
199 def arg_to_bool(arg
):
200 if isinstance(arg
, bool):
202 assert arg
in ["True", "False"], "Unexpected value for boolean arguement: " + repr(
208 def parse_property_aliases(alias_list
):
211 for alias
in alias_list
.split():
212 (name
, _
, pref
) = alias
.partition(":")
213 result
.append((name
, pref
))
217 def to_phys(name
, logical
, physical
):
218 return name
.replace(logical
, physical
).replace("inset-", "")
221 class Property(object):
237 raise TypeError("Spec should be specified for " + name
)
239 self
.ident
= to_rust_ident(name
)
240 self
.camel_case
= to_camel_case(self
.ident
)
241 self
.servo_2013_pref
= servo_2013_pref
242 self
.servo_2020_pref
= servo_2020_pref
243 self
.gecko_pref
= gecko_pref
244 self
.rule_types_allowed
= rule_values_from_arg(rule_types_allowed
)
245 # For enabled_in, the setup is as follows:
246 # It needs to be one of the four values: ["", "ua", "chrome", "content"]
247 # * "chrome" implies "ua", and implies that they're explicitly
249 # * "" implies the property will never be parsed.
250 # * "content" implies the property is accessible unconditionally,
251 # modulo a pref, set via servo_pref / gecko_pref.
252 assert enabled_in
in ("", "ua", "chrome", "content")
253 self
.enabled_in
= enabled_in
254 self
.aliases
= parse_property_aliases(aliases
)
255 self
.extra_prefixes
= parse_property_aliases(extra_prefixes
)
256 self
.flags
= flags
.split() if flags
else []
258 def rule_types_allowed_names(self
):
259 for name
in RULE_VALUES
:
260 if self
.rule_types_allowed
& RULE_VALUES
[name
] != 0:
263 def experimental(self
, engine
):
264 if engine
== "gecko":
265 return bool(self
.gecko_pref
)
266 elif engine
== "servo-2013":
267 return bool(self
.servo_2013_pref
)
268 elif engine
== "servo-2020":
269 return bool(self
.servo_2020_pref
)
271 raise Exception("Bad engine: " + engine
)
273 def explicitly_enabled_in_ua_sheets(self
):
274 return self
.enabled_in
in ("ua", "chrome")
276 def explicitly_enabled_in_chrome(self
):
277 return self
.enabled_in
== "chrome"
279 def enabled_in_content(self
):
280 return self
.enabled_in
== "content"
282 def nscsspropertyid(self
):
283 return "nsCSSPropertyID::eCSSProperty_" + self
.ident
286 class Longhand(Property
):
292 animation_value_type
=None,
294 predefined_type
=None,
295 servo_2013_pref
=None,
296 servo_2020_pref
=None,
298 enabled_in
="content",
301 has_effect_on_gecko_scrollbars
=None,
302 rule_types_allowed
=DEFAULT_RULES
,
311 ignored_when_colors_disabled
=False,
312 simple_vector_bindings
=False,
314 servo_restyle_damage
="repaint",
321 servo_2013_pref
=servo_2013_pref
,
322 servo_2020_pref
=servo_2020_pref
,
323 gecko_pref
=gecko_pref
,
324 enabled_in
=enabled_in
,
325 rule_types_allowed
=rule_types_allowed
,
327 extra_prefixes
=extra_prefixes
,
331 self
.affects
= affects
332 self
.flags
+= self
.affects_flags()
334 self
.keyword
= keyword
335 self
.predefined_type
= predefined_type
336 self
.style_struct
= style_struct
337 self
.has_effect_on_gecko_scrollbars
= has_effect_on_gecko_scrollbars
339 has_effect_on_gecko_scrollbars
in [None, False, True]
340 and not style_struct
.inherited
341 or (gecko_pref
is None and enabled_in
!= "")
342 == (has_effect_on_gecko_scrollbars
is None)
346 + ": has_effect_on_gecko_scrollbars must be "
347 + "specified, and must have a value of True or False, iff a "
348 + "property is inherited and is behind a Gecko pref or internal"
350 self
.need_index
= need_index
351 self
.gecko_ffi_name
= gecko_ffi_name
or "m" + self
.camel_case
352 self
.cast_type
= cast_type
353 self
.logical
= arg_to_bool(logical
)
354 self
.logical_group
= logical_group
356 assert logical_group
, "Property " + name
+ " must have a logical group"
358 self
.boxed
= arg_to_bool(boxed
)
359 self
.allow_quirks
= allow_quirks
360 self
.ignored_when_colors_disabled
= ignored_when_colors_disabled
361 self
.is_vector
= vector
362 self
.simple_vector_bindings
= simple_vector_bindings
364 # This is done like this since just a plain bool argument seemed like
366 if animation_value_type
is None:
368 "animation_value_type should be specified for (" + name
+ ")"
370 self
.animation_value_type
= animation_value_type
372 self
.animatable
= animation_value_type
!= "none"
373 self
.transitionable
= (
374 animation_value_type
!= "none" and animation_value_type
!= "discrete"
376 self
.is_animatable_with_computed_value
= (
377 animation_value_type
== "ComputedValue"
378 or animation_value_type
== "discrete"
381 # See compute_damage for the various values this can take
382 self
.servo_restyle_damage
= servo_restyle_damage
384 def affects_flags(self
):
385 # Layout is the stronger hint. This property animation affects layout
386 # or frame construction. `display` or `width` are examples that should
388 if self
.affects
== "layout":
389 return ["AFFECTS_LAYOUT"]
390 # This property doesn't affect layout, but affects overflow.
391 # `transform` and co. are examples of this.
392 if self
.affects
== "overflow":
393 return ["AFFECTS_OVERFLOW"]
394 # This property affects the rendered output but doesn't affect layout.
395 # `opacity`, `color`, or `z-index` are examples of this.
396 if self
.affects
== "paint":
397 return ["AFFECTS_PAINT"]
398 # This property doesn't affect rendering in any way.
399 # `user-select` is an example of this.
400 assert self
.affects
== "", (
403 + ': affects must be specified and be one of ["layout", "overflow", "paint", ""], see Longhand.affects_flags for documentation'
411 # For a given logical property return all the physical property names
412 # corresponding to it.
413 def all_physical_mapped_properties(self
, data
):
418 s
for s
in LOGICAL_SIDES
+ LOGICAL_SIZES
+ LOGICAL_CORNERS
if s
in self
.name
419 ] + [s
for s
in LOGICAL_AXES
if self
.name
.endswith(s
)]
420 assert len(candidates
) == 1
421 logical_side
= candidates
[0]
425 if logical_side
in LOGICAL_SIDES
427 if logical_side
in LOGICAL_SIZES
429 if logical_side
in LOGICAL_AXES
433 data
.longhands_by_name
[to_phys(self
.name
, logical_side
, physical_side
)]
434 for physical_side
in physical
437 def may_be_disabled_in(self
, shorthand
, engine
):
438 if engine
== "gecko":
439 return self
.gecko_pref
and self
.gecko_pref
!= shorthand
.gecko_pref
440 elif engine
== "servo-2013":
443 and self
.servo_2013_pref
!= shorthand
.servo_2013_pref
445 elif engine
== "servo-2020":
448 and self
.servo_2020_pref
!= shorthand
.servo_2020_pref
451 raise Exception("Bad engine: " + engine
)
454 if self
.predefined_type
and not self
.is_vector
:
455 return "crate::values::specified::{}".format(self
.predefined_type
)
456 return "longhands::{}::SpecifiedValue".format(self
.ident
)
458 def specified_type(self
):
459 if self
.predefined_type
and not self
.is_vector
:
460 ty
= "crate::values::specified::{}".format(self
.predefined_type
)
462 ty
= "longhands::{}::SpecifiedValue".format(self
.ident
)
464 ty
= "Box<{}>".format(ty
)
467 def specified_is_copy(self
):
468 if self
.is_vector
or self
.boxed
:
470 if self
.predefined_type
:
471 return self
.predefined_type
in {
483 "table::CaptionSide",
492 "FontLanguageOverride",
497 "FontVariantEastAsian",
498 "FontVariantLigatures",
499 "FontVariantNumeric",
501 "GreaterThanOrEqualToOneNumber",
514 "text::MozControlCharacterVisibility",
517 "MozScriptSizeMultiplier",
519 "TextDecorationSkipInk",
528 "OverscrollBehavior",
541 "ScrollSnapStrictness",
545 "TextDecorationLine",
546 "TextEmphasisPosition",
549 "TextUnderlinePosition",
559 if self
.name
== "overflow-y":
561 return bool(self
.keyword
)
563 def animated_type(self
):
564 assert self
.animatable
565 computed
= "<{} as ToComputedValue>::ComputedValue".format(self
.base_type())
566 if self
.is_animatable_with_computed_value
:
568 return "<{} as ToAnimatedValue>::AnimatedValue".format(computed
)
571 class Shorthand(Property
):
577 servo_2013_pref
=None,
578 servo_2020_pref
=None,
580 enabled_in
="content",
581 rule_types_allowed
=DEFAULT_RULES
,
590 servo_2013_pref
=servo_2013_pref
,
591 servo_2020_pref
=servo_2020_pref
,
592 gecko_pref
=gecko_pref
,
593 enabled_in
=enabled_in
,
594 rule_types_allowed
=rule_types_allowed
,
596 extra_prefixes
=extra_prefixes
,
599 self
.sub_properties
= sub_properties
601 def get_animatable(self
):
602 for sub
in self
.sub_properties
:
607 def get_transitionable(self
):
608 transitionable
= False
609 for sub
in self
.sub_properties
:
610 if sub
.transitionable
:
611 transitionable
= True
613 return transitionable
615 animatable
= property(get_animatable
)
616 transitionable
= property(get_transitionable
)
624 def __init__(self
, name
, original
, gecko_pref
):
626 self
.ident
= to_rust_ident(name
)
627 self
.camel_case
= to_camel_case(self
.ident
)
628 self
.original
= original
629 self
.enabled_in
= original
.enabled_in
630 self
.animatable
= original
.animatable
631 self
.servo_2013_pref
= original
.servo_2013_pref
632 self
.servo_2020_pref
= original
.servo_2020_pref
633 self
.gecko_pref
= gecko_pref
634 self
.transitionable
= original
.transitionable
635 self
.rule_types_allowed
= original
.rule_types_allowed
636 self
.flags
= original
.flags
642 def rule_types_allowed_names(self
):
643 for name
in RULE_VALUES
:
644 if self
.rule_types_allowed
& RULE_VALUES
[name
] != 0:
647 def experimental(self
, engine
):
648 if engine
== "gecko":
649 return bool(self
.gecko_pref
)
650 elif engine
== "servo-2013":
651 return bool(self
.servo_2013_pref
)
652 elif engine
== "servo-2020":
653 return bool(self
.servo_2020_pref
)
655 raise Exception("Bad engine: " + engine
)
657 def explicitly_enabled_in_ua_sheets(self
):
658 return self
.enabled_in
in ["ua", "chrome"]
660 def explicitly_enabled_in_chrome(self
):
661 return self
.enabled_in
== "chrome"
663 def enabled_in_content(self
):
664 return self
.enabled_in
== "content"
666 def nscsspropertyid(self
):
667 return "nsCSSPropertyID::eCSSPropertyAlias_%s" % self
.ident
670 class Method(object):
671 def __init__(self
, name
, return_type
=None, arg_types
=None, is_mut
=False):
673 self
.return_type
= return_type
674 self
.arg_types
= arg_types
or []
678 args
= ["_: " + x
for x
in self
.arg_types
]
679 args
= ["&mut self" if self
.is_mut
else "&self"] + args
680 return ", ".join(args
)
683 sig
= "fn %s(%s)" % (self
.name
, self
.arg_list())
685 sig
= sig
+ " -> " + self
.return_type
689 return self
.signature() + ";"
692 return self
.signature() + "{ unimplemented!() }"
695 class StyleStruct(object):
696 def __init__(self
, name
, inherited
, gecko_name
=None, additional_methods
=None):
697 self
.gecko_struct_name
= "Gecko" + name
699 self
.name_lower
= to_snake_case(name
)
700 self
.ident
= to_rust_ident(self
.name_lower
)
702 self
.inherited
= inherited
703 self
.gecko_name
= gecko_name
or name
704 self
.gecko_ffi_name
= "nsStyle" + self
.gecko_name
705 self
.additional_methods
= additional_methods
or []
706 self
.document_dependent
= self
.gecko_name
in ["Font", "Visibility", "Text"]
709 class PropertiesData(object):
710 def __init__(self
, engine
):
712 self
.style_structs
= []
713 self
.current_style_struct
= None
715 self
.longhands_by_name
= {}
716 self
.longhands_by_logical_group
= {}
717 self
.longhand_aliases
= []
719 self
.shorthands_by_name
= {}
720 self
.shorthand_aliases
= []
721 self
.counted_unknown_properties
= [
722 CountedUnknownProperty(p
) for p
in COUNTED_UNKNOWN_PROPERTIES
725 def new_style_struct(self
, *args
, **kwargs
):
726 style_struct
= StyleStruct(*args
, **kwargs
)
727 self
.style_structs
.append(style_struct
)
728 self
.current_style_struct
= style_struct
730 def active_style_structs(self
):
731 return [s
for s
in self
.style_structs
if s
.additional_methods
or s
.longhands
]
733 def add_prefixed_aliases(self
, property):
734 # FIXME Servo's DOM architecture doesn't support vendor-prefixed properties.
735 # See servo/servo#14941.
736 if self
.engine
== "gecko":
737 for prefix
, pref
in property.extra_prefixes
:
738 property.aliases
.append(("-%s-%s" % (prefix
, property.name
), pref
))
740 def declare_longhand(self
, name
, engines
=None, **kwargs
):
741 engines
= engines
.split()
742 if self
.engine
not in engines
:
745 longhand
= Longhand(self
.current_style_struct
, name
, **kwargs
)
746 self
.add_prefixed_aliases(longhand
)
747 longhand
.aliases
= [Alias(xp
[0], longhand
, xp
[1]) for xp
in longhand
.aliases
]
748 self
.longhand_aliases
+= longhand
.aliases
749 self
.current_style_struct
.longhands
.append(longhand
)
750 self
.longhands
.append(longhand
)
751 self
.longhands_by_name
[name
] = longhand
752 if longhand
.logical_group
:
753 self
.longhands_by_logical_group
.setdefault(
754 longhand
.logical_group
, []
759 def declare_shorthand(self
, name
, sub_properties
, engines
, *args
, **kwargs
):
760 engines
= engines
.split()
761 if self
.engine
not in engines
:
764 sub_properties
= [self
.longhands_by_name
[s
] for s
in sub_properties
]
765 shorthand
= Shorthand(name
, sub_properties
, *args
, **kwargs
)
766 self
.add_prefixed_aliases(shorthand
)
767 shorthand
.aliases
= [Alias(xp
[0], shorthand
, xp
[1]) for xp
in shorthand
.aliases
]
768 self
.shorthand_aliases
+= shorthand
.aliases
769 self
.shorthands
.append(shorthand
)
770 self
.shorthands_by_name
[name
] = shorthand
773 def shorthands_except_all(self
):
774 return [s
for s
in self
.shorthands
if s
.name
!= "all"]
776 def all_aliases(self
):
777 return self
.longhand_aliases
+ self
.shorthand_aliases
780 def _add_logical_props(data
, props
):
783 if prop
not in data
.longhands_by_name
:
784 assert data
.engine
in ["servo-2013", "servo-2020"]
786 prop
= data
.longhands_by_name
[prop
]
787 if prop
.logical_group
:
788 groups
.add(prop
.logical_group
)
790 for prop
in data
.longhands_by_logical_group
[group
]:
794 # These are probably Gecko bugs and should be supported per spec.
795 def _remove_common_first_line_and_first_letter_properties(props
, engine
):
796 if engine
== "gecko":
797 props
.remove("tab-size")
798 props
.remove("hyphens")
799 props
.remove("line-break")
800 props
.remove("text-align-last")
801 props
.remove("text-emphasis-position")
802 props
.remove("text-emphasis-style")
803 props
.remove("text-emphasis-color")
805 props
.remove("overflow-wrap")
806 props
.remove("text-align")
807 props
.remove("text-justify")
808 props
.remove("white-space")
809 props
.remove("word-break")
810 props
.remove("text-indent")
813 class PropertyRestrictions
:
815 def logical_group(data
, group
):
816 return [p
.name
for p
in data
.longhands_by_logical_group
[group
]]
819 def shorthand(data
, shorthand
):
820 if shorthand
not in data
.shorthands_by_name
:
822 return [p
.name
for p
in data
.shorthands_by_name
[shorthand
].sub_properties
]
825 def spec(data
, spec_path
):
826 return [p
.name
for p
in data
.longhands
if spec_path
in p
.spec
]
828 # https://drafts.csswg.org/css-pseudo/#first-letter-styling
830 def first_letter(data
):
837 # Kinda like css-fonts?
838 "-moz-osx-font-smoothing",
839 # Kinda like css-text?
840 "-webkit-text-stroke-width",
841 "-webkit-text-fill-color",
842 "-webkit-text-stroke-color",
844 # Will become shorthand of vertical-align (Bug 1830771)
847 # Kinda like css-backgrounds?
848 "background-blend-mode",
850 + PropertyRestrictions
.shorthand(data
, "padding")
851 + PropertyRestrictions
.shorthand(data
, "margin")
852 + PropertyRestrictions
.spec(data
, "css-fonts")
853 + PropertyRestrictions
.spec(data
, "css-backgrounds")
854 + PropertyRestrictions
.spec(data
, "css-text")
855 + PropertyRestrictions
.spec(data
, "css-shapes")
856 + PropertyRestrictions
.spec(data
, "css-text-decor")
859 _add_logical_props(data
, props
)
861 _remove_common_first_line_and_first_letter_properties(props
, data
.engine
)
864 # https://drafts.csswg.org/css-pseudo/#first-line-styling
866 def first_line(data
):
872 # Kinda like css-fonts?
873 "-moz-osx-font-smoothing",
874 # Kinda like css-text?
875 "-webkit-text-stroke-width",
876 "-webkit-text-fill-color",
877 "-webkit-text-stroke-color",
879 # Will become shorthand of vertical-align (Bug 1830771)
882 # Kinda like css-backgrounds?
883 "background-blend-mode",
885 + PropertyRestrictions
.spec(data
, "css-fonts")
886 + PropertyRestrictions
.spec(data
, "css-backgrounds")
887 + PropertyRestrictions
.spec(data
, "css-text")
888 + PropertyRestrictions
.spec(data
, "css-text-decor")
891 # These are probably Gecko bugs and should be supported per spec.
892 for prop
in PropertyRestrictions
.shorthand(data
, "border"):
894 for prop
in PropertyRestrictions
.shorthand(data
, "border-radius"):
896 props
.remove("box-shadow")
898 _remove_common_first_line_and_first_letter_properties(props
, data
.engine
)
901 # https://drafts.csswg.org/css-pseudo/#placeholder
903 # The spec says that placeholder and first-line have the same restrictions,
904 # but that's not true in Gecko and we also allow a handful other properties
907 def placeholder(data
):
908 props
= PropertyRestrictions
.first_line(data
)
910 props
.add("white-space")
911 props
.add("text-overflow")
912 props
.add("text-align")
913 props
.add("text-justify")
916 # https://drafts.csswg.org/css-pseudo/#marker-pseudo
923 "text-combine-upright",
929 "-moz-osx-font-smoothing",
931 + PropertyRestrictions
.spec(data
, "css-fonts")
932 + PropertyRestrictions
.spec(data
, "css-animations")
933 + PropertyRestrictions
.spec(data
, "css-transitions")
936 # https://www.w3.org/TR/webvtt1/#the-cue-pseudo-element
946 "text-combine-upright",
948 # XXX Should these really apply to cue?
949 "-moz-osx-font-smoothing",
950 # FIXME(emilio): background-blend-mode should be part of the
951 # background shorthand, and get reset, per
952 # https://drafts.fxtf.org/compositing/#background-blend-mode
953 "background-blend-mode",
955 + PropertyRestrictions
.shorthand(data
, "text-decoration")
956 + PropertyRestrictions
.shorthand(data
, "background")
957 + PropertyRestrictions
.shorthand(data
, "outline")
958 + PropertyRestrictions
.shorthand(data
, "font")
959 + PropertyRestrictions
.shorthand(data
, "font-synthesis")
963 class CountedUnknownProperty
:
964 def __init__(self
, name
):
966 self
.ident
= to_rust_ident(name
)
967 self
.camel_case
= to_camel_case(self
.ident
)