mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
Bug 1454591 part 1 - Generate more structured data in ServoCSSPropList.py. r=heycam
This patch changes ServoCSSPropList.py to use classes for properties. This allows extending the data in the file without needing to update all users of this file. Sorting in GenerateCSSPropsGenerated.py is removed because the data file has the right order already. MozReview-Commit-ID: D74bItCfpPH --HG-- extra : rebase_source : e0138c255f77515f491496fcb8680686362f4e9e
This commit is contained in:
parent
3b95cfc89e
commit
7db648bdec
@ -10,6 +10,7 @@ This information is used to generate the properties-db.js file.
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import runpy
|
||||||
import sys
|
import sys
|
||||||
import string
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -53,15 +54,12 @@ class MachCommands(MachCommandBase):
|
|||||||
# The data takes the following form:
|
# The data takes the following form:
|
||||||
# [ (name, prop, id, flags, pref, proptype), ... ]
|
# [ (name, prop, id, flags, pref, proptype), ... ]
|
||||||
dataPath = resolve_path(self.topobjdir, 'layout/style/ServoCSSPropList.py')
|
dataPath = resolve_path(self.topobjdir, 'layout/style/ServoCSSPropList.py')
|
||||||
with open(dataPath, "r") as f:
|
data = runpy.run_path(dataPath)['data']
|
||||||
data = eval(f.read())
|
|
||||||
|
|
||||||
# Map this list
|
# Map this list
|
||||||
# (name, prop, id, flags, pref, proptype) => (name, pref)
|
|
||||||
preferences = [
|
preferences = [
|
||||||
(name, pref)
|
(p.name, p.pref) for p in data
|
||||||
for name, prop, id, flags, pref, proptype in data
|
if 'CSSPropFlags::Internal' not in p.flags and p.pref]
|
||||||
if 'CSSPropFlags::Internal' not in flags and pref]
|
|
||||||
|
|
||||||
return preferences
|
return preferences
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import sys
|
import sys
|
||||||
import string
|
import string
|
||||||
import argparse
|
import argparse
|
||||||
|
import runpy
|
||||||
|
|
||||||
# Generates a line of WebIDL with the given spelling of the property name
|
# Generates a line of WebIDL with the given spelling of the property name
|
||||||
# (whether camelCase, _underscorePrefixed, etc.) and the given array of
|
# (whether camelCase, _underscorePrefixed, etc.) and the given array of
|
||||||
@ -13,18 +14,19 @@ def generateLine(propName, extendedAttrs):
|
|||||||
return " [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
|
return " [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
|
||||||
propName)
|
propName)
|
||||||
def generate(output, idlFilename, dataFile):
|
def generate(output, idlFilename, dataFile):
|
||||||
with open(dataFile, "r") as f:
|
propList = runpy.run_path(dataFile)["data"]
|
||||||
propList = eval(f.read())
|
|
||||||
props = ""
|
props = ""
|
||||||
for name, prop, id, flags, pref, proptype in propList:
|
for p in propList:
|
||||||
if "CSSPropFlags::Internal" in flags:
|
if "CSSPropFlags::Internal" in p.flags:
|
||||||
continue
|
continue
|
||||||
# Unfortunately, even some of the getters here are fallible
|
# Unfortunately, even some of the getters here are fallible
|
||||||
# (e.g. on nsComputedDOMStyle).
|
# (e.g. on nsComputedDOMStyle).
|
||||||
extendedAttrs = ["CEReactions", "Throws", "TreatNullAs=EmptyString",
|
extendedAttrs = ["CEReactions", "Throws", "TreatNullAs=EmptyString",
|
||||||
"SetterNeedsSubjectPrincipal=NonSystem"]
|
"SetterNeedsSubjectPrincipal=NonSystem"]
|
||||||
if pref is not "":
|
if p.pref is not "":
|
||||||
extendedAttrs.append('Pref="%s"' % pref)
|
extendedAttrs.append('Pref="%s"' % p.pref)
|
||||||
|
|
||||||
|
prop = p.method
|
||||||
|
|
||||||
# webkit properties get a camelcase "webkitFoo" accessor
|
# webkit properties get a camelcase "webkitFoo" accessor
|
||||||
# as well as a capitalized "WebkitFoo" alias (added here).
|
# as well as a capitalized "WebkitFoo" alias (added here).
|
||||||
@ -52,8 +54,8 @@ def generate(output, idlFilename, dataFile):
|
|||||||
# cover (3) and all of (1) except "float". If we now add an alias
|
# 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
|
# for all the cases where "name" doesn't match "prop", that will cover
|
||||||
# "float" and (2).
|
# "float" and (2).
|
||||||
if prop != name:
|
if prop != p.name:
|
||||||
extendedAttrs.append('BindingAlias="%s"' % name)
|
extendedAttrs.append('BindingAlias="%s"' % p.name)
|
||||||
|
|
||||||
props += generateLine(prop, extendedAttrs)
|
props += generateLine(prop, extendedAttrs)
|
||||||
|
|
||||||
|
@ -2,30 +2,30 @@
|
|||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
import runpy
|
||||||
import string
|
import string
|
||||||
|
|
||||||
def generate(output, template, dataFile):
|
def generate(output, template, dataFile):
|
||||||
with open(template, "r") as f:
|
with open(template, "r") as f:
|
||||||
template = string.Template(f.read())
|
template = string.Template(f.read())
|
||||||
with open(dataFile, "r") as f:
|
data = runpy.run_path(dataFile)["data"]
|
||||||
data = eval(f.read())
|
|
||||||
|
|
||||||
longhand_count = 0
|
longhand_count = 0
|
||||||
shorthand_count = 0
|
shorthand_count = 0
|
||||||
alias_count = 0
|
alias_count = 0
|
||||||
property_ids = []
|
property_ids = []
|
||||||
for name, method, id, flags, pref, prototype in data:
|
for prop in data:
|
||||||
if prototype != "alias":
|
if prop.type() != "alias":
|
||||||
if prototype == "longhand":
|
if prop.type() == "longhand":
|
||||||
assert shorthand_count == 0
|
assert shorthand_count == 0
|
||||||
longhand_count += 1
|
longhand_count += 1
|
||||||
else:
|
else:
|
||||||
assert alias_count == 0
|
assert alias_count == 0
|
||||||
shorthand_count += 1
|
shorthand_count += 1
|
||||||
property_ids.append("eCSSProperty_{}".format(id))
|
property_ids.append("eCSSProperty_{}".format(prop.id))
|
||||||
else:
|
else:
|
||||||
alias_count += 1
|
alias_count += 1
|
||||||
property_ids.append("eCSSPropertyAlias_{}".format(id[0]))
|
property_ids.append("eCSSPropertyAlias_{}".format(prop.alias_id))
|
||||||
|
|
||||||
output.write("/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */\n\n")
|
output.write("/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */\n\n")
|
||||||
output.write(template.substitute({
|
output.write(template.substitute({
|
||||||
|
@ -2,75 +2,66 @@
|
|||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
# 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/.
|
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
import runpy
|
||||||
import sys
|
import sys
|
||||||
import string
|
import string
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
def get_properties(dataFile):
|
class PropertyWrapper(object):
|
||||||
with open(dataFile, "r") as f:
|
__slots__ = ["index", "prop", "idlname"]
|
||||||
properties = eval(f.read())
|
|
||||||
properties = [{"name":p[0], "prop":p[1], "id":p[2],
|
|
||||||
"flags":p[3], "pref":p[4], "proptype":p[5]}
|
|
||||||
for (i, p) in enumerate(properties)]
|
|
||||||
|
|
||||||
# Sort the list so that longhand properties are intermingled first,
|
def __init__(self, index, prop):
|
||||||
# shorthand properties follow, then aliases appear last.
|
self.index = index
|
||||||
# This matches the order of the nsCSSPropertyID enum.
|
self.prop = prop
|
||||||
|
if "CSSPropFlags::Internal" in prop.flags:
|
||||||
def property_compare(x, y):
|
self.idlname = None
|
||||||
property_order = {"longhand": 0, "shorthand": 1, "alias": 2}
|
|
||||||
return property_order[x["proptype"]] - property_order[y["proptype"]]
|
|
||||||
|
|
||||||
properties = sorted(properties, cmp=property_compare)
|
|
||||||
|
|
||||||
for i, p in enumerate(properties):
|
|
||||||
p["index"] = i
|
|
||||||
|
|
||||||
# Record each property's IDL name.
|
|
||||||
for p in properties:
|
|
||||||
if "CSSPropFlags::Internal" in p["flags"]:
|
|
||||||
p["idlname"] = None
|
|
||||||
else:
|
else:
|
||||||
idl_name = p["prop"]
|
idl_name = prop.method
|
||||||
if not idl_name.startswith("Moz"):
|
if not idl_name.startswith("Moz"):
|
||||||
idl_name = idl_name[0].lower() + idl_name[1:]
|
idl_name = idl_name[0].lower() + idl_name[1:]
|
||||||
p["idlname"] = idl_name
|
self.idlname = idl_name
|
||||||
|
|
||||||
return properties
|
def __getattr__(self, name):
|
||||||
|
return getattr(self.prop, name)
|
||||||
|
|
||||||
|
|
||||||
|
def get_properties(dataFile):
|
||||||
|
properties = runpy.run_path(dataFile)["data"]
|
||||||
|
return [PropertyWrapper(i, p) for i, p in enumerate(properties)]
|
||||||
|
|
||||||
def generate_idl_names(properties):
|
def generate_idl_names(properties):
|
||||||
names = []
|
names = []
|
||||||
for p in properties:
|
for p in properties:
|
||||||
if p["proptype"] is "alias":
|
if p.type() == "alias":
|
||||||
continue
|
continue
|
||||||
if p["idlname"] is None:
|
if p.idlname is None:
|
||||||
names.append(" nullptr, // %s" % p["name"])
|
names.append(" nullptr, // %s" % p.name)
|
||||||
else:
|
else:
|
||||||
names.append(' "%s",' % p["idlname"])
|
names.append(' "%s",' % p.idlname)
|
||||||
return "\n".join(names)
|
return "\n".join(names)
|
||||||
|
|
||||||
def generate_assertions(properties):
|
def generate_assertions(properties):
|
||||||
def enum(p):
|
def enum(p):
|
||||||
if p["proptype"] is "alias":
|
if p.type() == "alias":
|
||||||
return "eCSSPropertyAlias_%s" % p["id"][0]
|
return "eCSSPropertyAlias_%s" % p.alias_id
|
||||||
else:
|
else:
|
||||||
return "eCSSProperty_%s" % p["id"]
|
return "eCSSProperty_%s" % p.id
|
||||||
msg = ('static_assert(%s == %d, "GenerateCSSPropsGenerated.py did not list '
|
msg = ('static_assert(%s == %d, "GenerateCSSPropsGenerated.py did not list '
|
||||||
'properties in nsCSSPropertyID order");')
|
'properties in nsCSSPropertyID order");')
|
||||||
return "\n".join(map(lambda p: msg % (enum(p), p["index"]), properties))
|
return "\n".join(map(lambda p: msg % (enum(p), p.index), properties))
|
||||||
|
|
||||||
def generate_idl_name_positions(properties):
|
def generate_idl_name_positions(properties):
|
||||||
# Skip aliases.
|
# Skip aliases.
|
||||||
ps = filter(lambda p: p["proptype"] is not "alias", properties)
|
ps = filter(lambda p: p.type() != "alias", properties)
|
||||||
|
|
||||||
# Sort alphabetically by IDL name.
|
# Sort alphabetically by IDL name.
|
||||||
ps = sorted(ps, key=lambda p: p["idlname"])
|
ps = sorted(ps, key=lambda p: p.idlname)
|
||||||
|
|
||||||
# Annotate entries with the sorted position.
|
# Annotate entries with the sorted position.
|
||||||
ps = [(p, position) for position, p in enumerate(ps)]
|
ps = [(p, position) for position, p in enumerate(ps)]
|
||||||
|
|
||||||
# Sort back to nsCSSPropertyID order.
|
# Sort back to nsCSSPropertyID order.
|
||||||
ps = sorted(ps, key=lambda (p, position): p["index"])
|
ps = sorted(ps, key=lambda (p, position): p.index)
|
||||||
|
|
||||||
return ",\n".join(map(lambda (p, position): " %d" % position, ps))
|
return ",\n".join(map(lambda (p, position): " %d" % position, ps))
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import buildconfig
|
import buildconfig
|
||||||
import mozpack.path as mozpath
|
import mozpack.path as mozpath
|
||||||
import os
|
import os
|
||||||
|
import runpy
|
||||||
import subprocess
|
import subprocess
|
||||||
import string
|
import string
|
||||||
import sys
|
import sys
|
||||||
@ -32,8 +33,7 @@ def generate_data(output, template):
|
|||||||
|
|
||||||
|
|
||||||
def generate_header(output, data):
|
def generate_header(output, data):
|
||||||
with open(data, "r") as f:
|
data = runpy.run_path(data)["data"]
|
||||||
data = eval(f.read())
|
|
||||||
|
|
||||||
output.write("""/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */
|
output.write("""/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */
|
||||||
|
|
||||||
@ -68,28 +68,29 @@ def generate_header(output, data):
|
|||||||
"shorthand": "CSS_PROP_SHORTHAND",
|
"shorthand": "CSS_PROP_SHORTHAND",
|
||||||
"alias": "CSS_PROP_ALIAS",
|
"alias": "CSS_PROP_ALIAS",
|
||||||
}
|
}
|
||||||
for name, method, id, flags, pref, proptype in data:
|
for prop in data:
|
||||||
is_internal = "CSSPropFlags::Internal" in flags
|
is_internal = "CSSPropFlags::Internal" in prop.flags
|
||||||
pref = '"' + pref + '"'
|
pref = '"' + prop.pref + '"'
|
||||||
if proptype == "alias":
|
if prop.type() == "alias":
|
||||||
params = [name, id[0], id[1], method, pref]
|
params = [prop.name, prop.alias_id, prop.prop_id, prop.method, pref]
|
||||||
else:
|
else:
|
||||||
|
method = prop.method
|
||||||
if method == "CssFloat":
|
if method == "CssFloat":
|
||||||
method = "CSS_PROP_PUBLIC_OR_PRIVATE(CssFloat, Float)"
|
method = "CSS_PROP_PUBLIC_OR_PRIVATE(CssFloat, Float)"
|
||||||
elif method.startswith("Moz"):
|
elif method.startswith("Moz"):
|
||||||
method = "CSS_PROP_DOMPROP_PREFIXED({})".format(method[3:])
|
method = "CSS_PROP_DOMPROP_PREFIXED({})".format(method[3:])
|
||||||
if flags:
|
if prop.flags:
|
||||||
flags = " | ".join(flags)
|
flags = " | ".join(prop.flags)
|
||||||
else:
|
else:
|
||||||
flags = "CSSPropFlags(0)"
|
flags = "CSSPropFlags(0)"
|
||||||
params = [name, id, method, flags, pref]
|
params = [prop.name, prop.id, method, flags, pref]
|
||||||
|
|
||||||
is_component_of_all = not is_internal and name not in ["direction", "unicode-bidi"]
|
is_component_of_all = not is_internal and prop.name not in ["direction", "unicode-bidi"]
|
||||||
if not is_component_of_all:
|
if not is_component_of_all:
|
||||||
output.write("#ifndef CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND\n")
|
output.write("#ifndef CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND\n")
|
||||||
if is_internal:
|
if is_internal:
|
||||||
output.write("#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL\n")
|
output.write("#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL\n")
|
||||||
output.write("{}({})\n".format(MACRO_NAMES[proptype], ", ".join(params)))
|
output.write("{}({})\n".format(MACRO_NAMES[prop.type()], ", ".join(params)))
|
||||||
if is_internal:
|
if is_internal:
|
||||||
output.write("#endif\n")
|
output.write("#endif\n")
|
||||||
if not is_component_of_all:
|
if not is_component_of_all:
|
||||||
|
@ -2,6 +2,43 @@
|
|||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
def _assign_slots(obj, args):
|
||||||
|
for i, attr in enumerate(obj.__slots__):
|
||||||
|
setattr(obj, attr, args[i])
|
||||||
|
|
||||||
|
|
||||||
|
class Longhand(object):
|
||||||
|
__slots__ = ["name", "method", "id", "flags", "pref"]
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
_assign_slots(self, args)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def type():
|
||||||
|
return "longhand"
|
||||||
|
|
||||||
|
|
||||||
|
class Shorthand(object):
|
||||||
|
__slots__ = ["name", "method", "id", "flags", "pref"]
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
_assign_slots(self, args)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def type():
|
||||||
|
return "shorthand"
|
||||||
|
|
||||||
|
|
||||||
|
class Alias(object):
|
||||||
|
__slots__ = ["name", "method", "alias_id", "prop_id", "flags", "pref"]
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
_assign_slots(self, args)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def type():
|
||||||
|
return "alias"
|
||||||
|
|
||||||
<%!
|
<%!
|
||||||
# nsCSSPropertyID of longhands and shorthands is ordered alphabetically
|
# nsCSSPropertyID of longhands and shorthands is ordered alphabetically
|
||||||
# with vendor prefixes removed. Note that aliases use their alias name
|
# with vendor prefixes removed. Note that aliases use their alias name
|
||||||
@ -27,6 +64,13 @@ def is_internal(prop):
|
|||||||
]
|
]
|
||||||
return prop.name in OTHER_INTERNALS
|
return prop.name in OTHER_INTERNALS
|
||||||
|
|
||||||
|
def method(prop):
|
||||||
|
if prop.name == "float":
|
||||||
|
return "CssFloat"
|
||||||
|
if prop.name.startswith("-x-"):
|
||||||
|
return prop.camel_case[1:]
|
||||||
|
return prop.camel_case
|
||||||
|
|
||||||
def flags(prop):
|
def flags(prop):
|
||||||
result = []
|
result = []
|
||||||
if prop.explicitly_enabled_in_chrome():
|
if prop.explicitly_enabled_in_chrome():
|
||||||
@ -49,43 +93,16 @@ def pref(prop):
|
|||||||
return '""'
|
return '""'
|
||||||
%>
|
%>
|
||||||
|
|
||||||
[
|
data = [
|
||||||
% for prop in sorted(data.longhands, key=order_key):
|
% for prop in sorted(data.longhands, key=order_key):
|
||||||
(
|
Longhand("${prop.name}", "${method(prop)}", "${prop.ident}", [${flags(prop)}], ${pref(prop)}),
|
||||||
"${prop.name}",
|
|
||||||
% if prop.name == "float":
|
|
||||||
"CssFloat",
|
|
||||||
% elif prop.name.startswith("-x-"):
|
|
||||||
"${prop.camel_case[1:]}",
|
|
||||||
% else:
|
|
||||||
"${prop.camel_case}",
|
|
||||||
% endif
|
|
||||||
"${prop.ident}",
|
|
||||||
[${flags(prop)}],
|
|
||||||
${pref(prop)},
|
|
||||||
"longhand",
|
|
||||||
),
|
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
% for prop in sorted(data.shorthands, key=order_key):
|
% for prop in sorted(data.shorthands, key=order_key):
|
||||||
(
|
Shorthand("${prop.name}", "${prop.camel_case}", "${prop.ident}", [${flags(prop)}], ${pref(prop)}),
|
||||||
"${prop.name}",
|
|
||||||
"${prop.camel_case}",
|
|
||||||
"${prop.ident}",
|
|
||||||
[${flags(prop)}],
|
|
||||||
${pref(prop)},
|
|
||||||
"shorthand",
|
|
||||||
),
|
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
% for prop in sorted(data.all_aliases(), key=lambda x: x.name):
|
% for prop in sorted(data.all_aliases(), key=lambda x: x.name):
|
||||||
(
|
Alias("${prop.name}", "${prop.camel_case}", "${prop.ident}", "${prop.original.ident}", [], ${pref(prop)}),
|
||||||
"${prop.name}",
|
|
||||||
"${prop.camel_case}",
|
|
||||||
("${prop.ident}", "${prop.original.ident}"),
|
|
||||||
[],
|
|
||||||
${pref(prop)},
|
|
||||||
"alias",
|
|
||||||
),
|
|
||||||
% endfor
|
% endfor
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user