# 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
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",
]
])
)
# 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): ifnot 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 notin p.rule_types_allowed_names(): continue
pref = p.gecko_pref
propId = p.ident if p.type() == "alias": 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" elif 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: assertnot 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)
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)
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
*/
# 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. returnnot prop.gecko_pref andnot 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",
def serialized_by_servo(prop): if prop.type() == "alias": returnTrue# Doesn't matter, we resolve the alias early return prop.name notin LONGHANDS_NOT_SERIALIZED_WITH_SERVO
def exposed_on_getcs(prop): if"style"notin prop.rule_types_allowed_names(): returnFalse if is_internal(prop): returnFalse returnTrue
def cpp_flags(prop):
RUST_TO_CPP_FLAGS = { "CAN_ANIMATE_ON_COMPOSITOR": "CanAnimateOnCompositor", "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.longhands + raw_properties.shorthands) if p.type() != "alias"
]
# Generate kIDLNameTable
output.write( "const char* const nsCSSProps::""kIDLNameTable[eCSSProperty_COUNT] = {\n"
) for p in properties: if p.idlname isNone:
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] = {\n"
) for p, position in ps:
output.write(" {},\n".format(position))
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(eCSSProperty_{} == {}, "{}");\n'.format(p.ident, 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")
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
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))
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-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"notin prop.rule_types_allowed_names(): continue ifnot 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 */
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): ifnot exposed_on_getcs(p): returnFalse if serialized_by_servo(p): returnFalse if p.type() == "longhand"and p.logical: returnFalse returnTrue
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)
)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.