mirror of
https://github.com/servo/servo.git
synced 2025-08-08 15:05:35 +01:00
Bug 1364412: Convert pseudo-elements to an enum. r=hiro,xidorn
This commit is contained in:
parent
0bc185f1c2
commit
5820e3ecac
17 changed files with 2260 additions and 1505 deletions
248
components/style/gecko/regen_atoms.py
Executable file
248
components/style/gecko/regen_atoms.py
Executable file
|
@ -0,0 +1,248 @@
|
|||
#!/usr/bin/env 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 re
|
||||
import os
|
||||
import sys
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
GECKO_DIR = os.path.dirname(__file__.replace('\\', '/'))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(GECKO_DIR), "properties"))
|
||||
|
||||
import build
|
||||
|
||||
PRELUDE = """
|
||||
/* 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/. */
|
||||
|
||||
/* Autogenerated file created by components/style/binding_tools/regen_atoms.py, DO NOT EDIT DIRECTLY */
|
||||
"""[1:]
|
||||
|
||||
|
||||
def gnu_symbolify(source, ident):
|
||||
return "_ZN{}{}{}{}E".format(len(source.CLASS), source.CLASS, len(ident), ident)
|
||||
|
||||
|
||||
def msvc64_symbolify(source, ident):
|
||||
return "?{}@{}@@2PEAV{}@@EA".format(ident, source.CLASS, source.TYPE)
|
||||
|
||||
|
||||
def msvc32_symbolify(source, ident):
|
||||
# Prepend "\x01" to avoid LLVM prefixing the mangled name with "_".
|
||||
# See https://github.com/rust-lang/rust/issues/36097
|
||||
return "\\x01?{}@{}@@2PAV{}@@A".format(ident, source.CLASS, source.TYPE)
|
||||
|
||||
|
||||
class GkAtomSource:
|
||||
PATTERN = re.compile('^GK_ATOM\((.+),\s*"(.*)"\)')
|
||||
FILE = "include/nsGkAtomList.h"
|
||||
CLASS = "nsGkAtoms"
|
||||
TYPE = "nsIAtom"
|
||||
|
||||
|
||||
class CSSPseudoElementsAtomSource:
|
||||
PATTERN = re.compile('^CSS_PSEUDO_ELEMENT\((.+),\s*"(.*)",')
|
||||
FILE = "include/nsCSSPseudoElementList.h"
|
||||
CLASS = "nsCSSPseudoElements"
|
||||
# NB: nsICSSPseudoElement is effectively the same as a nsIAtom, but we need
|
||||
# this for MSVC name mangling.
|
||||
TYPE = "nsICSSPseudoElement"
|
||||
|
||||
|
||||
class CSSAnonBoxesAtomSource:
|
||||
PATTERN = re.compile('^(?:CSS_ANON_BOX|CSS_NON_INHERITING_ANON_BOX)\((.+),\s*"(.*)"(\,|\))')
|
||||
FILE = "include/nsCSSAnonBoxList.h"
|
||||
CLASS = "nsCSSAnonBoxes"
|
||||
TYPE = "nsICSSAnonBoxPseudo"
|
||||
|
||||
|
||||
SOURCES = [
|
||||
GkAtomSource,
|
||||
CSSPseudoElementsAtomSource,
|
||||
CSSAnonBoxesAtomSource,
|
||||
]
|
||||
|
||||
|
||||
def map_atom(ident):
|
||||
if ident in {"box", "loop", "match", "mod", "ref",
|
||||
"self", "type", "use", "where", "in"}:
|
||||
return ident + "_"
|
||||
return ident
|
||||
|
||||
|
||||
class Atom:
|
||||
def __init__(self, source, ident, value):
|
||||
self.ident = "{}_{}".format(source.CLASS, ident)
|
||||
self.original_ident = ident
|
||||
self.value = value
|
||||
self.source = source
|
||||
|
||||
def cpp_class(self):
|
||||
return self.source.CLASS
|
||||
|
||||
def gnu_symbol(self):
|
||||
return gnu_symbolify(self.source, self.original_ident)
|
||||
|
||||
def msvc32_symbol(self):
|
||||
return msvc32_symbolify(self.source, self.original_ident)
|
||||
|
||||
def msvc64_symbol(self):
|
||||
return msvc64_symbolify(self.source, self.original_ident)
|
||||
|
||||
def type(self):
|
||||
return self.source.TYPE
|
||||
|
||||
def capitalized(self):
|
||||
return self.original_ident[0].upper() + self.original_ident[1:]
|
||||
|
||||
def is_anon_box(self):
|
||||
return self.type() == "nsICSSAnonBoxPseudo"
|
||||
|
||||
|
||||
def collect_atoms(objdir):
|
||||
atoms = []
|
||||
for source in SOURCES:
|
||||
path = os.path.abspath(os.path.join(objdir, source.FILE))
|
||||
print("cargo:rerun-if-changed={}".format(path))
|
||||
with open(path) as f:
|
||||
for line in f.readlines():
|
||||
result = re.match(source.PATTERN, line)
|
||||
if result:
|
||||
atoms.append(Atom(source, result.group(1), result.group(2)))
|
||||
return atoms
|
||||
|
||||
|
||||
class FileAvoidWrite(BytesIO):
|
||||
"""File-like object that buffers output and only writes if content changed."""
|
||||
def __init__(self, filename):
|
||||
BytesIO.__init__(self)
|
||||
self.name = filename
|
||||
|
||||
def write(self, buf):
|
||||
if isinstance(buf, unicode):
|
||||
buf = buf.encode('utf-8')
|
||||
BytesIO.write(self, buf)
|
||||
|
||||
def close(self):
|
||||
buf = self.getvalue()
|
||||
BytesIO.close(self)
|
||||
try:
|
||||
with open(self.name, 'rb') as f:
|
||||
old_content = f.read()
|
||||
if old_content == buf:
|
||||
print("{} is not changed, skip".format(self.name))
|
||||
return
|
||||
except IOError:
|
||||
pass
|
||||
with open(self.name, 'wb') as f:
|
||||
f.write(buf)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
if not self.closed:
|
||||
self.close()
|
||||
|
||||
|
||||
IMPORTS = ("\nuse gecko_bindings::structs::nsIAtom;"
|
||||
"\nuse string_cache::Atom;\n\n")
|
||||
|
||||
ATOM_TEMPLATE = (" #[link_name = \"{link_name}\"]\n"
|
||||
" pub static {name}: *mut {type};")
|
||||
|
||||
UNSAFE_STATIC = ("#[inline(always)]\n"
|
||||
"pub unsafe fn atom_from_static(ptr: *mut nsIAtom) -> Atom {\n"
|
||||
" Atom::from_static(ptr)\n"
|
||||
"}\n\n")
|
||||
|
||||
CFG_IF = '''
|
||||
cfg_if! {{
|
||||
if #[cfg(not(target_env = "msvc"))] {{
|
||||
extern {{
|
||||
{gnu}
|
||||
}}
|
||||
}} else if #[cfg(target_pointer_width = "64")] {{
|
||||
extern {{
|
||||
{msvc64}
|
||||
}}
|
||||
}} else {{
|
||||
extern {{
|
||||
{msvc32}
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
'''
|
||||
|
||||
RULE_TEMPLATE = ('("{atom}") =>\n '
|
||||
'{{ '
|
||||
# FIXME(bholley): Uncomment this when rust 1.14 is released.
|
||||
# See the comment in components/style/lib.rs.
|
||||
# ' #[allow(unsafe_code)] #[allow(unused_unsafe)] '
|
||||
'unsafe {{ $crate::string_cache::atom_macro::atom_from_static'
|
||||
'($crate::string_cache::atom_macro::{name} as *mut _) }}'
|
||||
' }};')
|
||||
|
||||
MACRO = '''
|
||||
#[macro_export]
|
||||
macro_rules! atom {{
|
||||
{}
|
||||
}}
|
||||
'''
|
||||
|
||||
|
||||
def write_atom_macro(atoms, file_name):
|
||||
def get_symbols(func):
|
||||
return '\n'.join([ATOM_TEMPLATE.format(name=atom.ident,
|
||||
link_name=func(atom),
|
||||
type=atom.type()) for atom in atoms])
|
||||
|
||||
with FileAvoidWrite(file_name) as f:
|
||||
f.write(PRELUDE)
|
||||
f.write(IMPORTS)
|
||||
|
||||
for source in SOURCES:
|
||||
if source.TYPE != "nsIAtom":
|
||||
f.write("pub enum {} {{}}\n\n".format(source.TYPE))
|
||||
|
||||
f.write(UNSAFE_STATIC)
|
||||
|
||||
gnu_symbols = get_symbols(Atom.gnu_symbol)
|
||||
msvc32_symbols = get_symbols(Atom.msvc32_symbol)
|
||||
msvc64_symbols = get_symbols(Atom.msvc64_symbol)
|
||||
f.write(CFG_IF.format(gnu=gnu_symbols, msvc32=msvc32_symbols, msvc64=msvc64_symbols))
|
||||
|
||||
macro_rules = [RULE_TEMPLATE.format(atom=atom.value, name=atom.ident) for atom in atoms]
|
||||
f.write(MACRO.format('\n'.join(macro_rules)))
|
||||
|
||||
|
||||
def write_pseudo_elements(atoms, target_filename):
|
||||
pseudos = []
|
||||
for atom in atoms:
|
||||
if atom.type() == "nsICSSPseudoElement" or atom.type() == "nsICSSAnonBoxPseudo":
|
||||
pseudos.append(atom)
|
||||
|
||||
pseudo_definition_template = os.path.join(GECKO_DIR, "pseudo_element_definition.mako.rs")
|
||||
print("cargo:rerun-if-changed={}".format(pseudo_definition_template))
|
||||
contents = build.render(pseudo_definition_template, PSEUDOS=pseudos)
|
||||
|
||||
with FileAvoidWrite(target_filename) as f:
|
||||
f.write(contents)
|
||||
|
||||
|
||||
def generate_atoms(dist, out):
|
||||
atoms = collect_atoms(dist)
|
||||
write_atom_macro(atoms, os.path.join(out, "atom_macro.rs"))
|
||||
write_pseudo_elements(atoms, os.path.join(out, "pseudo_element_definition.rs"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 3:
|
||||
print("Usage: {} dist out".format(sys.argv[0]))
|
||||
exit(2)
|
||||
generate_atoms(sys.argv[1], sys.argv[2])
|
Loading…
Add table
Add a link
Reference in a new issue