- Adds `-moz-scrollbar-inset-block` and `-moz-scrollbar-inset-inline`, chrome-only
`<non-negative-length>{1,2}` longhands. Each names the scrollbar's axis it
applies to. The two values are the axis' logical start and end
and flip with the writing mode.
- ScrollContainerFrame::ScrollbarInsets() serves as the one place to extract the inset from for
both nsScrollbarFrame and GetBorderRadii
- Applies inset to nsScrollbarFrame::Reflow similar to stepper buttons
- ScrollContainerFrame::GetBorderRadii no longer squares a corner off when the
inset already holds the scrollbar clear of the curve.
- Forward the <browser> embedder's inset to a root scrollbar for the content viewport
- Add reftests for css-scrollbars
- This commit does NOT implement the css property anywhere
Differential Revision: https://phabricator.services.mozilla.com/D313900
697 lines
23 KiB
Python
697 lines
23 KiB
Python
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
import buildconfig
|
|
import mozpack.path as mozpath
|
|
import string
|
|
import sys
|
|
|
|
SERVO_PROPS = mozpath.join(buildconfig.topsrcdir, "servo", "components", "style", "properties")
|
|
sys.path.insert(0, SERVO_PROPS)
|
|
|
|
GENERATED_FILE_BOILERPLATE = """/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
"""
|
|
|
|
import data
|
|
|
|
|
|
def props_and_deps():
|
|
properties = data.PropertiesData(engine="gecko")
|
|
# Add all relevant files into the dependencies of the generated file.
|
|
return (
|
|
properties,
|
|
set([
|
|
mozpath.join(SERVO_PROPS, f) for f in [
|
|
"data.py", "counted_unknown_properties.py",
|
|
"longhands.toml", "shorthands.toml",
|
|
"font_face_descriptors.toml", "counter_style_descriptors.toml",
|
|
"property_descriptors.toml",
|
|
"view_transition_descriptors.toml",
|
|
]
|
|
])
|
|
)
|
|
|
|
|
|
def gen_css_prop_list_header(output):
|
|
properties, deps = props_and_deps()
|
|
|
|
output.write(GENERATED_FILE_BOILERPLATE)
|
|
output.write(
|
|
"""#ifndef CSS_PROP_LONGHAND
|
|
#define CSS_PROP_LONGHAND(name_, id_, method_, flags_, pref_) /* nothing */
|
|
#define DEFINED_CSS_PROP_LONGHAND
|
|
#endif
|
|
|
|
#ifndef CSS_PROP_SHORTHAND
|
|
#define CSS_PROP_SHORTHAND(name_, id_, method_, flags_, pref_) /* nothing */
|
|
#define DEFINED_CSS_PROP_SHORTHAND
|
|
#endif
|
|
|
|
#ifndef CSS_PROP_ALIAS
|
|
#define CSS_PROP_ALIAS(name_, aliasid_, id_, method_, flags_, pref_) /* nothing */
|
|
#define DEFINED_CSS_PROP_ALIAS
|
|
#endif
|
|
|
|
"""
|
|
)
|
|
|
|
MACRO_NAMES = {
|
|
"longhand": "CSS_PROP_LONGHAND",
|
|
"shorthand": "CSS_PROP_SHORTHAND",
|
|
"alias": "CSS_PROP_ALIAS",
|
|
}
|
|
for prop in properties.all_properties_and_aliases():
|
|
flags = " | ".join(
|
|
"CSSPropFlags::{}".format(flag)
|
|
for flag in cpp_flags(prop)
|
|
)
|
|
if not flags:
|
|
flags = "CSSPropFlags(0)"
|
|
pref = '"' + (prop.gecko_pref or "") + '"'
|
|
method = prop.idl_method
|
|
if prop.type() == "alias":
|
|
params = [prop.name, prop.ident, prop.original.ident, method, flags, pref]
|
|
else:
|
|
params = [prop.name, prop.ident, method, flags, pref]
|
|
output.write("{}({})\n".format(MACRO_NAMES[prop.type()], ", ".join(params)))
|
|
|
|
output.write(
|
|
"""
|
|
#ifdef DEFINED_CSS_PROP_ALIAS
|
|
#undef CSS_PROP_ALIAS
|
|
#undef DEFINED_CSS_PROP_ALIAS
|
|
#endif
|
|
|
|
#ifdef DEFINED_CSS_PROP_SHORTHAND
|
|
#undef CSS_PROP_SHORTHAND
|
|
#undef DEFINED_CSS_PROP_SHORTHAND
|
|
#endif
|
|
|
|
#ifdef DEFINED_CSS_PROP_LONGHAND
|
|
#undef CSS_PROP_LONGHAND
|
|
#undef DEFINED_CSS_PROP_LONGHAND
|
|
#endif
|
|
"""
|
|
)
|
|
|
|
return deps
|
|
|
|
|
|
# Generates a line of WebIDL with the given spelling of the property name
|
|
# (whether camelCase, _underscorePrefixed, etc.) and the given array of
|
|
# extended attributes.
|
|
def generateLine(propName, extendedAttrs):
|
|
return " [%s] attribute [LegacyNullToEmptyString] UTF8String %s;\n" % (
|
|
", ".join(extendedAttrs),
|
|
propName,
|
|
)
|
|
|
|
|
|
def idl_attribute(p):
|
|
prop = p.idl_method
|
|
# Generate a name with camelCase spelling of property-name (or capitalized,
|
|
# for Moz-prefixed properties):
|
|
if not prop.startswith("Moz"):
|
|
prop = prop[0].lower() + prop[1:]
|
|
return prop
|
|
|
|
|
|
def gen_webidl(output, ruleType, interfaceName, bindingTemplate, pref=None):
|
|
properties, deps = props_and_deps()
|
|
output.write(GENERATED_FILE_BOILERPLATE)
|
|
output.write("[Exposed=Window")
|
|
if pref:
|
|
output.write(', Pref="' + pref + '"')
|
|
output.write(
|
|
"""]
|
|
interface """
|
|
+ interfaceName
|
|
+ " : CSSStyleDeclaration {\n"
|
|
)
|
|
for p in properties.all_properties_and_aliases():
|
|
# Skip properties which aren't valid in style rules.
|
|
if ruleType not in p.rule_types_allowed_names():
|
|
continue
|
|
|
|
pref = p.gecko_pref
|
|
|
|
propId = p.ident
|
|
if p.idl_method == "MozAppearance":
|
|
# Hide MozAppearance from CSSStyleProperties to prevent outdated
|
|
# special casing against Gecko. (Bug 1977489)
|
|
pref = "layout.css.moz-appearance.webidl.enabled"
|
|
if p.type() == "alias":
|
|
if p.gecko_pref == p.original.gecko_pref:
|
|
# We already added this as a BindingAlias for the original prop.
|
|
continue
|
|
propId = p.original.ident
|
|
extendedAttrs = [
|
|
"BindingTemplate=(%s, NonCustomCSSPropertyId, eCSSProperty_%s)" % (bindingTemplate, propId),
|
|
"CEReactions",
|
|
"SetterThrows",
|
|
"SetterNeedsSubjectPrincipal=NonSystem",
|
|
]
|
|
|
|
if pref:
|
|
assert not is_internal(p)
|
|
# backdrop-filter is a special case where we want WebIDL to check a
|
|
# function instead of checking the pref directly.
|
|
if p.name == "backdrop-filter":
|
|
extendedAttrs.append('Func="nsCSSProps::IsBackdropFilterAvailable"')
|
|
else:
|
|
extendedAttrs.append('Pref="%s"' % pref)
|
|
elif p.explicitly_enabled_in_chrome():
|
|
extendedAttrs.append("ChromeOnly")
|
|
elif is_internal(p):
|
|
continue
|
|
|
|
def add_extra_accessors(p):
|
|
# webkit properties get a camelcase "webkitFoo" accessor
|
|
# as well as a capitalized "WebkitFoo" alias (added here).
|
|
if p.idl_method.startswith("Webkit"):
|
|
extendedAttrs.append('BindingAlias="%s"' % p.idl_method)
|
|
|
|
prop = idl_attribute(p)
|
|
|
|
# Per spec, what's actually supposed to happen here is that we're supposed
|
|
# to have properties for:
|
|
#
|
|
# 1) Each supported CSS property name, camelCased.
|
|
# 2) Each supported name that contains or starts with dashes,
|
|
# without any changes to the name.
|
|
# 3) cssFloat
|
|
#
|
|
# Note that "float" will cause a property called "float" to exist due to (1)
|
|
# in that list.
|
|
#
|
|
# In practice, cssFloat is the only case in which "name" doesn't contain
|
|
# "-" but also doesn't match "prop". So the generateLine() call will
|
|
# cover (3) and all of (1) except "float". If we now add an alias
|
|
# for all the cases where "name" doesn't match "prop", that will cover
|
|
# "float" and (2).
|
|
if prop != p.name:
|
|
extendedAttrs.append('BindingAlias="%s"' % p.name)
|
|
|
|
return prop
|
|
|
|
prop = add_extra_accessors(p)
|
|
|
|
if p.type() != "alias":
|
|
for a in p.aliases:
|
|
if p.gecko_pref == a.gecko_pref:
|
|
newProp = add_extra_accessors(a)
|
|
extendedAttrs.append('BindingAlias="%s"' % newProp)
|
|
|
|
output.write(generateLine(prop, extendedAttrs))
|
|
|
|
output.write("};")
|
|
return deps
|
|
|
|
|
|
def gen_style_properties_webidl(output):
|
|
return gen_webidl(output, "style", "CSSStyleProperties", "CSS2Property")
|
|
|
|
|
|
def gen_page_descriptors_webidl(output):
|
|
return gen_webidl(output, "page", "CSSPageDescriptors", "CSSPageDescriptor")
|
|
|
|
|
|
def gen_position_try_descriptors_webidl(output):
|
|
return gen_webidl(output, "position-try", "CSSPositionTryDescriptors",
|
|
"CSSPositionTryDescriptor")
|
|
|
|
|
|
def gen_font_face_descriptors_webidl(output):
|
|
properties, deps = props_and_deps()
|
|
output.write(GENERATED_FILE_BOILERPLATE)
|
|
output.write("""/*
|
|
* The origin of this IDL file is
|
|
* https://drafts.csswg.org/css-fonts-5/#cssfontfacedescriptors
|
|
*/
|
|
|
|
// https://drafts.csswg.org/css-fonts-5/#cssfontfacedescriptors
|
|
[Exposed=Window]
|
|
interface CSSFontFaceDescriptors : CSSStyleDeclaration {
|
|
"""
|
|
)
|
|
for d in properties.font_face_descriptors:
|
|
idl_name = data.to_idl_name(d.name)
|
|
extendedAttrs = [
|
|
"BindingTemplate=(CSSFontFaceDesc, FontFaceDescriptorId, %s)" % d.camel_case,
|
|
"SetterThrows",
|
|
]
|
|
if d.gecko_pref:
|
|
extendedAttrs.append('Pref="%s"' % d.gecko_pref)
|
|
if idl_name != d.name:
|
|
extendedAttrs.append('BindingAlias="%s"' % d.name)
|
|
for alias in d.aliases:
|
|
alias_idl_name = data.to_idl_name(alias)
|
|
if alias_idl_name != alias:
|
|
extendedAttrs.append('BindingAlias="%s"' % alias)
|
|
extendedAttrs.append('BindingAlias="%s"' % alias_idl_name)
|
|
output.write(generateLine(idl_name, extendedAttrs))
|
|
output.write("};\n")
|
|
return deps
|
|
|
|
|
|
def gen_counter_style_rule_webidl(output):
|
|
properties, deps = props_and_deps()
|
|
output.write(GENERATED_FILE_BOILERPLATE)
|
|
output.write("""/* The origin of this IDL file is
|
|
* https://drafts.csswg.org/css-counter-styles-3/#the-csscounterstylerule-interface
|
|
*/
|
|
|
|
// https://drafts.csswg.org/css-counter-styles-3/#the-csscounterstylerule-interface
|
|
[Exposed=Window]
|
|
interface CSSCounterStyleRule : CSSRule {
|
|
attribute DOMString name;
|
|
"""
|
|
)
|
|
for d in properties.counter_style_descriptors:
|
|
output.write(
|
|
" [BindingTemplate=(CSSCounterStyleDesc, CounterStyleDescriptorId, {})]"
|
|
" attribute UTF8String {};\n".format(d.camel_case, data.to_idl_name(d.name))
|
|
)
|
|
output.write("};\n")
|
|
return deps
|
|
|
|
|
|
class PropertyWrapper(object):
|
|
__slots__ = ["index", "prop", "idlname"]
|
|
|
|
def __init__(self, index, prop):
|
|
self.index = index
|
|
self.prop = prop
|
|
self.idlname = None if is_internal(prop) else idl_attribute(prop)
|
|
|
|
def __getattr__(self, name):
|
|
return getattr(self.prop, name)
|
|
|
|
|
|
# See bug 1454823 for situation of internal flag.
|
|
def is_internal(prop):
|
|
# A property which is not controlled by pref and not enabled in
|
|
# content by default is an internal property.
|
|
return not prop.gecko_pref and not prop.enabled_in_content()
|
|
|
|
|
|
# TODO(emilio): Get this to zero.
|
|
LONGHANDS_NOT_SERIALIZED_WITH_SERVO = set([
|
|
# These resolve auto to zero in a few cases, but not all.
|
|
"max-height",
|
|
"max-width",
|
|
"min-height",
|
|
"min-width",
|
|
|
|
# resistfingerprinting stuff.
|
|
"-moz-osx-font-smoothing",
|
|
|
|
# Layout dependent.
|
|
"width",
|
|
"height",
|
|
"grid-template-rows",
|
|
"grid-template-columns",
|
|
"perspective-origin",
|
|
"transform-origin",
|
|
"transform",
|
|
"-webkit-transform",
|
|
"top",
|
|
"right",
|
|
"bottom",
|
|
"left",
|
|
"margin-top",
|
|
"margin-right",
|
|
"margin-bottom",
|
|
"margin-left",
|
|
"padding-top",
|
|
"padding-right",
|
|
"padding-bottom",
|
|
"padding-left",
|
|
])
|
|
|
|
|
|
def serialized_by_servo(prop):
|
|
if prop.type() == "alias":
|
|
return True # Doesn't matter, we resolve the alias early
|
|
return prop.name not in LONGHANDS_NOT_SERIALIZED_WITH_SERVO
|
|
|
|
|
|
def exposed_on_getcs(prop):
|
|
if "style" not in prop.rule_types_allowed_names():
|
|
return False
|
|
if is_internal(prop):
|
|
return False
|
|
return True
|
|
|
|
|
|
def cpp_flags(prop):
|
|
RUST_TO_CPP_FLAGS = {
|
|
"CAN_ANIMATE_ON_COMPOSITOR": "CanAnimateOnCompositor",
|
|
"SCROLL_LINKED_EFFECTIVE": "ScrollLinkedEffective",
|
|
"AFFECTS_LAYOUT": "AffectsLayout",
|
|
"AFFECTS_PAINT": "AffectsPaint",
|
|
"AFFECTS_OVERFLOW": "AffectsOverflow",
|
|
}
|
|
result = []
|
|
if prop.explicitly_enabled_in_chrome():
|
|
result.append("EnabledInUASheetsAndChrome")
|
|
elif prop.explicitly_enabled_in_ua_sheets():
|
|
result.append("EnabledInUASheets")
|
|
if is_internal(prop):
|
|
result.append("Internal")
|
|
if prop.enabled_in == "":
|
|
result.append("Inaccessible")
|
|
for (k, v) in RUST_TO_CPP_FLAGS.items():
|
|
if k in prop.flags:
|
|
result.append(v)
|
|
if serialized_by_servo(prop):
|
|
result.append("SerializedByServo")
|
|
if prop.type() == "longhand" and prop.logical:
|
|
result.append("IsLogical")
|
|
return result
|
|
|
|
|
|
|
|
def gen_ns_css_props(output):
|
|
raw_properties, deps = props_and_deps()
|
|
output.write(
|
|
"""/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */
|
|
|
|
/* processed file that defines CSS property tables that can't be generated
|
|
with the pre-processor, designed to be #included in nsCSSProps.cpp */
|
|
|
|
"""
|
|
)
|
|
|
|
properties = [
|
|
PropertyWrapper(i, p)
|
|
for i, p in enumerate(raw_properties.all_properties_and_aliases())
|
|
]
|
|
|
|
# Generate kIDLNameTable
|
|
output.write(
|
|
"const char* const nsCSSProps::kIDLNameTable[eCSSProperty_COUNT_with_aliases] = {\n"
|
|
)
|
|
for p in properties:
|
|
if p.idlname is None:
|
|
output.write(" nullptr, // {}\n".format(p.name))
|
|
else:
|
|
output.write(' "{}",\n'.format(p.idlname))
|
|
output.write("};\n\n")
|
|
|
|
# Generate kIDLNameSortPositionTable
|
|
ps = sorted(properties, key=lambda p: p.idlname if p.idlname else "")
|
|
ps = [(p, position) for position, p in enumerate(ps)]
|
|
ps.sort(key=lambda item: item[0].index)
|
|
output.write(
|
|
"const int32_t nsCSSProps::kIDLNameSortPositionTable[eCSSProperty_COUNT_with_aliases] = {\n"
|
|
)
|
|
for p, position in ps:
|
|
output.write(" {},\n".format(position))
|
|
output.write("};\n\n")
|
|
|
|
# Generate preferences table
|
|
output.write(
|
|
"const nsCSSProps::PropertyPref nsCSSProps::kPropertyPrefTable[] = {\n"
|
|
)
|
|
for p in raw_properties.all_properties_and_aliases():
|
|
if not p.gecko_pref:
|
|
continue
|
|
if p.type() != "alias":
|
|
prop_id = "eCSSProperty_" + p.ident
|
|
else:
|
|
prop_id = "eCSSPropertyAlias_" + p.ident
|
|
output.write(' {{ {}, "{}" }},\n'.format(prop_id, p.gecko_pref))
|
|
output.write(" { eCSSProperty_UNKNOWN, nullptr },\n")
|
|
output.write("};\n\n")
|
|
|
|
# Generate shorthand subprop tables
|
|
names = []
|
|
for p in properties:
|
|
if p.type() != "shorthand":
|
|
continue
|
|
name = "g{}SubpropTable".format(p.idl_method)
|
|
names.append(name)
|
|
output.write(f"static const NonCustomCSSPropertyId {name}[] = {{\n")
|
|
for subprop in p.sub_properties:
|
|
output.write(f" eCSSProperty_{subprop.ident},\n")
|
|
output.write(" eCSSProperty_UNKNOWN\n")
|
|
output.write("};\n\n")
|
|
output.write("const NonCustomCSSPropertyId* const\n")
|
|
output.write(
|
|
"nsCSSProps::kSubpropertyTable["
|
|
"eCSSProperty_COUNT - eCSSProperty_COUNT_no_shorthands"
|
|
"] = {\n"
|
|
)
|
|
for name in names:
|
|
output.write(" {},\n".format(name))
|
|
output.write("};\n\n")
|
|
|
|
# Generate assertions
|
|
msg = (
|
|
"GenerateCSSPropsGenerated.py did not list properties "
|
|
"in NonCustomCSSPropertyId order"
|
|
)
|
|
for p in properties:
|
|
output.write(
|
|
'static_assert({} == {}, "{}");\n'.format(
|
|
p.noncustomcsspropertyid(), p.index, msg
|
|
)
|
|
)
|
|
|
|
output.write("\n")
|
|
|
|
# Generate font-face descriptor name table
|
|
output.write(
|
|
"const nsCSSProps::DescriptorTableEntry<FontFaceDescriptorId>\n"
|
|
"nsCSSProps::kFontFaceDescs[] = {\n"
|
|
)
|
|
for d in raw_properties.font_face_descriptors:
|
|
output.write(' {{ FontFaceDescriptorId::{}, "{}"_ns }},\n'.format(d.camel_case, d.name))
|
|
output.write("};\n\n")
|
|
|
|
# Generate counter-style descriptor name table
|
|
output.write(
|
|
"const nsCSSProps::DescriptorTableEntry<CounterStyleDescriptorId>\n"
|
|
"nsCSSProps::kCounterStyleDescs[] = {\n"
|
|
)
|
|
for d in raw_properties.counter_style_descriptors:
|
|
output.write(' {{ CounterStyleDescriptorId::{}, "{}"_ns }},\n'.format(d.camel_case, d.name))
|
|
output.write("};\n\n")
|
|
|
|
return deps
|
|
|
|
|
|
def gen_counted_unknown_properties(output, prop_file):
|
|
properties, deps = props_and_deps()
|
|
|
|
output.write("/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */\n\n")
|
|
|
|
for prop in properties.counted_unknown_properties:
|
|
output.write(
|
|
"COUNTED_UNKNOWN_PROPERTY({}, {})\n".format(prop.name, prop.ident)
|
|
)
|
|
return deps
|
|
|
|
|
|
def gen_compositor_animatable_properties(output):
|
|
properties, deps = props_and_deps()
|
|
output.write(
|
|
"""/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */
|
|
#ifndef COMPOSITOR_ANIMATABLE_PROPERTY_LIST
|
|
#define COMPOSITOR_ANIMATABLE_PROPERTY_LIST { \\
|
|
"""
|
|
)
|
|
|
|
count = 0
|
|
for p in properties.longhands:
|
|
if "CAN_ANIMATE_ON_COMPOSITOR" in p.flags:
|
|
output.write(" eCSSProperty_{}, \\\n".format(p.ident))
|
|
count += 1
|
|
|
|
output.write("}\n")
|
|
output.write("#endif /* COMPOSITOR_ANIMATABLE_PROPERTY_LIST */\n")
|
|
|
|
output.write("\n")
|
|
output.write("#ifndef COMPOSITOR_ANIMATABLE_PROPERTY_LIST_LENGTH\n")
|
|
output.write(
|
|
"#define COMPOSITOR_ANIMATABLE_PROPERTY_LIST_LENGTH {}\n".format(count)
|
|
)
|
|
output.write("#endif /* COMPOSITOR_ANIMATABLE_PROPERTY_LIST_LENGTH */\n")
|
|
return deps
|
|
|
|
|
|
def gen_non_custom_css_property_id(output, template):
|
|
properties, deps = props_and_deps()
|
|
with open(template, "r") as f:
|
|
template = string.Template(f.read())
|
|
|
|
property_ids = []
|
|
for prop in properties.longhands:
|
|
property_ids.append("eCSSProperty_{}".format(prop.ident))
|
|
for prop in properties.shorthands:
|
|
property_ids.append("eCSSProperty_{}".format(prop.ident))
|
|
for alias in properties.all_aliases():
|
|
property_ids.append("eCSSPropertyAlias_{}".format(alias.ident))
|
|
|
|
longhand_count = property_ids[len(properties.longhands)]
|
|
shorthand_count = property_ids[len(properties.longhands) + len(properties.shorthands)]
|
|
|
|
output.write("/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */\n\n")
|
|
output.write(
|
|
template.substitute(
|
|
{
|
|
"property_ids": "\n".join(" {},".format(p) for p in property_ids),
|
|
"longhand_first": property_ids[0],
|
|
"longhand_count": longhand_count,
|
|
"shorthand_count": shorthand_count,
|
|
"font_face_descriptors": "\n".join(" {},".format(d.camel_case) for d in properties.font_face_descriptors),
|
|
"font_face_descriptor_count": len(properties.font_face_descriptors),
|
|
"counter_style_descriptors": "\n".join(" {},".format(d.camel_case) for d in properties.counter_style_descriptors),
|
|
"counter_style_descriptor_count": len(properties.counter_style_descriptors),
|
|
}
|
|
)
|
|
)
|
|
return deps
|
|
|
|
|
|
# This builds the list of CSS properties that we expect in the
|
|
# property-database file for testing.
|
|
def gen_css_properties_js(output):
|
|
# Don't print the properties that aren't accepted by the parser
|
|
# TODO(emilio): Pretty sure we can automate this more.
|
|
inaccessible_properties = set([
|
|
"-x-cols",
|
|
"-x-lang",
|
|
"-x-span",
|
|
"-x-text-scale",
|
|
"-moz-default-appearance",
|
|
"-moz-theme",
|
|
"-moz-inert",
|
|
"-moz-script-level", # parsed by UA sheets only
|
|
"-moz-math-variant",
|
|
"-moz-math-display", # parsed by UA sheets only
|
|
"-moz-top-layer", # parsed by UA sheets only
|
|
"-moz-min-font-size-ratio", # parsed by UA sheets only
|
|
"-moz-box-collapse", # chrome-only internal properties
|
|
"-moz-line-scroll-amount", # chrome-only internal properties
|
|
"-moz-image-decoding", # chrome-only internal properties
|
|
"-moz-scrollbar-inset-block", # chrome-only internal properties
|
|
"-moz-scrollbar-inset-inline", # chrome-only internal properties
|
|
"-moz-subtree-hidden-only-visually", # chrome-only internal properties
|
|
"-moz-user-focus", # chrome-only internal properties
|
|
"-moz-window-input-region-margin", # chrome-only internal properties
|
|
"-moz-window-dragging", # chrome-only internal properties
|
|
"-moz-window-opacity", # chrome-only internal properties
|
|
"-moz-window-transform", # chrome-only internal properties
|
|
"-moz-window-shadow", # chrome-only internal properties
|
|
])
|
|
|
|
properties, deps = props_and_deps()
|
|
|
|
def print_array(name, props):
|
|
first = True
|
|
output.write(f"var {name} = [\n");
|
|
for prop in props:
|
|
if prop.name in inaccessible_properties:
|
|
continue
|
|
if "style" not in prop.rule_types_allowed_names():
|
|
continue
|
|
if not first:
|
|
output.write(",\n")
|
|
first = False
|
|
output.write(f"\t{{ name: \"{prop.name}\", prop: \"{idl_attribute(prop)}\"")
|
|
if prop.gecko_pref:
|
|
output.write(f", pref: \"{prop.gecko_pref}\"")
|
|
output.write(" }")
|
|
output.write("\n];\n")
|
|
|
|
output.write("/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */\n\n")
|
|
print_array("gLonghandProperties", properties.longhands)
|
|
print_array("gShorthandProperties", properties.shorthands)
|
|
return deps
|
|
|
|
|
|
COMPUTED_STYLE_INC = """/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */
|
|
|
|
/* processed file that defines entries for nsComputedDOMStyle, designed
|
|
to be #included in nsComputedDOMStyle.cpp */
|
|
|
|
static constexpr size_t kEntryIndices[eCSSProperty_COUNT] = {{
|
|
{indices}
|
|
}};
|
|
|
|
{asserts}
|
|
|
|
static constexpr Entry kEntries[eCSSProperty_COUNT] = {{
|
|
{entries}
|
|
}};
|
|
"""
|
|
|
|
|
|
def gen_computed_style(output):
|
|
properties, deps = props_and_deps()
|
|
|
|
def order_key(p):
|
|
# Put prefixed properties after normal properties.
|
|
# The spec is unclear about this, and Blink doesn't have any sensible
|
|
# order at all, so it probably doesn't matter a lot. But originally
|
|
# Gecko put then later so we do so as well. See w3c/csswg-drafts#2827.
|
|
order = p.name.startswith("-")
|
|
return (order, p.name)
|
|
|
|
def has_cpp_getter(p):
|
|
if not exposed_on_getcs(p):
|
|
return False
|
|
if serialized_by_servo(p):
|
|
return False
|
|
if p.type() == "longhand" and p.logical:
|
|
return False
|
|
return True
|
|
|
|
def getter_entry(p):
|
|
if has_cpp_getter(p):
|
|
return "DoGet" + p.idl_method
|
|
# Put a dummy getter here instead of nullptr because MSVC seems
|
|
# to have bug which ruins the table when we put nullptr for
|
|
# pointer-to-member-function. See bug 1471426.
|
|
return "DummyGetter"
|
|
|
|
entries = []
|
|
indices = []
|
|
asserts = []
|
|
index_map = {}
|
|
non_aliases = properties.longhands + properties.shorthands
|
|
for i, p in enumerate(sorted(non_aliases, key=order_key)):
|
|
can_be_exposed = "true" if exposed_on_getcs(p) else "false"
|
|
entries.append(
|
|
"{{ eCSSProperty_{}, {}, &nsComputedDOMStyle::{}}}".format(
|
|
p.ident, can_be_exposed, getter_entry(p)
|
|
)
|
|
)
|
|
index_map[p.ident] = i
|
|
i += 1
|
|
|
|
for i, p in enumerate(non_aliases):
|
|
indices.append(str(index_map[p.ident]))
|
|
asserts.append(
|
|
'static_assert(size_t(eCSSProperty_{}) == {}, "");'.format(p.ident, i)
|
|
)
|
|
|
|
assert len(indices) == len(entries)
|
|
|
|
output.write(
|
|
COMPUTED_STYLE_INC.format(
|
|
indices=", ".join(indices),
|
|
entries=",\n ".join(entries),
|
|
asserts="\n".join(asserts),
|
|
)
|
|
)
|
|
return deps
|