mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Move gecko_bindings and gecko_string_cache into the style crate
This commit is contained in:
parent
0dd005eacc
commit
c6787458d9
33 changed files with 2629 additions and 2688 deletions
|
@ -12,8 +12,8 @@ name = "style"
|
|||
path = "lib.rs"
|
||||
|
||||
[features]
|
||||
gecko = ["gecko_bindings", "gecko_string_cache"]
|
||||
servo = ["serde", "serde/unstable", "serde_macros", "heapsize", "heapsize_plugin",
|
||||
gecko = []
|
||||
servo = ["serde/unstable", "serde_macros", "heapsize_plugin",
|
||||
"style_traits/servo", "app_units/plugins",
|
||||
"cssparser/heap_size", "cssparser/serde-serialization",
|
||||
"selectors/heap_size", "selectors/unstable", "string_cache",
|
||||
|
@ -23,14 +23,13 @@ testing = []
|
|||
[dependencies]
|
||||
app_units = "0.3"
|
||||
bitflags = "0.7"
|
||||
cfg-if = "0.1.0"
|
||||
cssparser = "0.7"
|
||||
deque = "0.3.1"
|
||||
encoding = "0.2"
|
||||
euclid = "0.10.1"
|
||||
fnv = "1.0"
|
||||
gecko_bindings = {path = "../../ports/geckolib/gecko_bindings", optional = true}
|
||||
gecko_string_cache = {path = "../../ports/geckolib/string_cache", optional = true}
|
||||
heapsize = {version = "0.3.0", optional = true}
|
||||
heapsize = "0.3.0"
|
||||
heapsize_plugin = {version = "0.1.2", optional = true}
|
||||
lazy_static = "0.2"
|
||||
log = "0.3.5"
|
||||
|
@ -42,7 +41,7 @@ quickersort = "2.0.0"
|
|||
rand = "0.3"
|
||||
rustc-serialize = "0.3"
|
||||
selectors = "0.13"
|
||||
serde = {version = "0.8", optional = true}
|
||||
serde = "0.8"
|
||||
serde_macros = {version = "0.8", optional = true}
|
||||
smallvec = "0.1"
|
||||
string_cache = {version = "0.2.26", features = ["heap_size"], optional = true}
|
||||
|
|
2
components/style/binding_tools/.gitignore
vendored
Normal file
2
components/style/binding_tools/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
llvm/
|
||||
rust-bindgen/
|
26
components/style/binding_tools/README.md
Normal file
26
components/style/binding_tools/README.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
# GeckoLib tools
|
||||
|
||||
This directory contains mostly simple tools for working with
|
||||
[stylo](https://public.etherpad-mozilla.org/p/stylo).
|
||||
|
||||
Some scripts require [multirust](https://github.com/brson/multirust) in order to
|
||||
work.
|
||||
|
||||
You can see a description of them below.
|
||||
|
||||
## `setup_bindgen.sh`
|
||||
|
||||
This uses downloads a custom version of bindgen, up to date to generate the
|
||||
bindings, and uses the required `llvm38` to build it.
|
||||
|
||||
It will also rebuild it if it's already downloaded.
|
||||
|
||||
## `regen_bindings.sh`
|
||||
|
||||
This will regenerate the bindings for the `ServoBindings.h` file in your gecko
|
||||
build (which are in `ports/geckolib/bindings.rs`).
|
||||
|
||||
## `regen_style_structs.sh`
|
||||
|
||||
This will generate the bindings for Gecko's style structs. Current bindings are
|
||||
actually in `ports/geckolib/structs.rs`.
|
668
components/style/binding_tools/regen.py
Executable file
668
components/style/binding_tools/regen.py
Executable file
|
@ -0,0 +1,668 @@
|
|||
#!/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/.
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import platform
|
||||
import copy
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
import regen_atoms
|
||||
|
||||
DESCRIPTION = 'Regenerate the rust version of the structs or the bindings file.'
|
||||
TOOLS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
COMMON_BUILD_KEY = "__common__"
|
||||
|
||||
COMPILATION_TARGETS = {
|
||||
# Flags common for all the targets.
|
||||
COMMON_BUILD_KEY: {
|
||||
"flags": [
|
||||
"--no-unstable-rust", "--no-type-renaming",
|
||||
],
|
||||
"clang_flags": [
|
||||
"-x", "c++", "-std=c++14",
|
||||
"-DTRACING=1", "-DIMPL_LIBXUL", "-DMOZ_STYLO_BINDINGS=1",
|
||||
"-DMOZILLA_INTERNAL_API", "-DRUST_BINDGEN", "-DMOZ_STYLO"
|
||||
],
|
||||
"search_dirs": [
|
||||
"{}/dist/include",
|
||||
"{}/dist/include/nspr",
|
||||
"{}/../nsprpub/pr/include"
|
||||
],
|
||||
"includes": [
|
||||
"{}/mozilla-config.h",
|
||||
],
|
||||
},
|
||||
# Generation of style structs.
|
||||
"structs": {
|
||||
"target_dir": "../gecko_bindings",
|
||||
"test": True,
|
||||
"flags": [
|
||||
"--ignore-functions",
|
||||
"--ignore-methods",
|
||||
],
|
||||
"includes": [
|
||||
"{}/dist/include/nsThemeConstants.h",
|
||||
"{}/dist/include/mozilla/dom/AnimationEffectReadOnlyBinding.h",
|
||||
"{}/dist/include/mozilla/ServoElementSnapshot.h",
|
||||
"{}/dist/include/mozilla/dom/Element.h",
|
||||
],
|
||||
"files": [
|
||||
"{}/dist/include/nsStyleStruct.h",
|
||||
],
|
||||
"build_kinds": {
|
||||
"debug": {
|
||||
"clang_flags": [
|
||||
"-DDEBUG=1",
|
||||
"-DJS_DEBUG=1",
|
||||
]
|
||||
},
|
||||
"release": {
|
||||
}
|
||||
},
|
||||
"raw_lines": [
|
||||
# We can get rid of this when the bindings move into the style crate.
|
||||
"pub enum OpaqueStyleData {}",
|
||||
],
|
||||
"whitelist_vars": [
|
||||
"NS_THEME_.*",
|
||||
"NODE_.*",
|
||||
"NS_FONT_STYLE_.*",
|
||||
"NS_STYLE_.*",
|
||||
"NS_CORNER_.*",
|
||||
"NS_RADIUS_.*",
|
||||
"BORDER_COLOR_.*",
|
||||
"BORDER_STYLE_.*"
|
||||
],
|
||||
"whitelist": [
|
||||
"RawGeckoNode",
|
||||
"RawGeckoElement",
|
||||
"RawGeckoDocument",
|
||||
"Element",
|
||||
"Side",
|
||||
"nsTArrayHeader",
|
||||
"nsCSSValueGradient",
|
||||
"nsCSSValueList_heap",
|
||||
"FrameRequestCallback",
|
||||
"nsCSSValueTriplet_heap",
|
||||
"nsCSSRect_heap",
|
||||
"AnonymousContent",
|
||||
"nsCSSValuePairList",
|
||||
"nsCSSValuePairList_heap",
|
||||
"nsCSSValuePair_heap",
|
||||
"CapturingContentInfo",
|
||||
"Runnable",
|
||||
"AudioContext",
|
||||
"FontFamilyListRefCnt",
|
||||
"ImageURL",
|
||||
"Image",
|
||||
"nsCSSValueFloatColor",
|
||||
"ServoAttrSnapshot",
|
||||
"GridNamedArea",
|
||||
"nsAttrName",
|
||||
"nsAttrValue",
|
||||
"nsCSSRect",
|
||||
"gfxFontFeature",
|
||||
"gfxAlternateValue",
|
||||
"nsCSSValueTokenStream",
|
||||
"nsSize",
|
||||
"pair",
|
||||
"StyleClipPathGeometryBox",
|
||||
"FontFamilyName",
|
||||
"nsCSSPropertyID",
|
||||
"StyleAnimation",
|
||||
"StyleTransition",
|
||||
"nsresult",
|
||||
"nsCSSValueGradientStop",
|
||||
"nsBorderColors",
|
||||
"Position",
|
||||
"nsCSSValueList",
|
||||
"nsCSSValue",
|
||||
"UniquePtr", "DefaultDelete",
|
||||
"StyleBasicShape",
|
||||
"nsMargin",
|
||||
"nsStyleContentData",
|
||||
"nsStyleFilter", "nsRect", "FragmentOrURL", "nsStyleCoord",
|
||||
"nsStyleCounterData", "StaticRefPtr", "nsTArray", "nsStyleFont",
|
||||
"nsStyleColor", "nsStyleList", "nsStyleText", "nsStyleVisibility",
|
||||
"nsStyleUserInterface", "nsStyleTableBorder", "nsStyleSVG",
|
||||
"nsStyleVariables", "nsStyleBackground", "nsStylePosition",
|
||||
"nsStyleTextReset", "nsStyleDisplay", "nsStyleContent",
|
||||
"nsStyleUIReset", "nsStyleTable", "nsStyleMargin",
|
||||
"nsStylePadding", "nsStyleBorder", "nsStyleOutline", "nsStyleXUL",
|
||||
"nsStyleSVGReset", "nsStyleColumn", "nsStyleEffects",
|
||||
"nsStyleImage", "nsStyleGradient", "nsStyleCoord",
|
||||
"nsStyleGradientStop", "nsStyleImageLayers",
|
||||
"nsStyleImageLayers_Layer", "nsStyleImageLayers_LayerType",
|
||||
"nsStyleUnit", "nsStyleUnion", "nsStyleCoord", "nsRestyleHint",
|
||||
"ServoElementSnapshot", "nsChangeHint", "SheetParsingMode",
|
||||
"nsMainThreadPtrHandle", "nsMainThreadPtrHolder", "nscolor",
|
||||
"nsFont", "FontFamilyList", "FontFamilyType", "nsIAtom",
|
||||
"nsStyleContext", "StyleClipPath", "StyleBasicShapeType",
|
||||
"StyleBasicShape", "nsCSSShadowArray",
|
||||
],
|
||||
"opaque_types": [
|
||||
"atomic___base",
|
||||
"nsAString_internal_char_traits",
|
||||
"nsAString_internal_incompatible_char_type",
|
||||
"nsACString_internal_char_traits",
|
||||
"nsACString_internal_incompatible_char_type",
|
||||
"RefPtr_Proxy", "nsAutoPtr_Proxy", "Pair_Base",
|
||||
"RefPtr_Proxy_member_function", "nsAutoPtr_Proxy_member_function",
|
||||
"nsWritingIterator_reference", "nsReadingIterator_reference",
|
||||
"Heap", "TenuredHeap", "Rooted", "WeakPtr", # <- More template magic than what
|
||||
# we support.
|
||||
"nsTObserverArray", # <- Inherits from nsAutoTObserverArray<T, 0>
|
||||
"PLArenaPool", # <- Bindgen bug
|
||||
"nsTHashtable", # <- Inheriting from inner typedefs that clang
|
||||
# doesn't expose properly.
|
||||
"nsRefPtrHashtable", "nsDataHashtable", "nsClassHashtable", # <- Ditto
|
||||
"nsIDocument_SelectorCache", # <- Inherits from nsExpirationTracker<.., 4>
|
||||
"nsIPresShell_ScrollAxis", # <- For some reason the alignment of this is 4
|
||||
# for clang.
|
||||
"nsPIDOMWindow", # <- Takes the vtable from a template parameter, and we can't
|
||||
# generate it conditionally.
|
||||
"SupportsWeakPtr",
|
||||
"Maybe", # <- AlignedStorage, which means templated union, which
|
||||
# means impossible to represent in stable rust as of
|
||||
# right now.
|
||||
"gfxSize", # <- Same, union { struct { T width; T height; }; T components[2] };
|
||||
"gfxSize_Super", # Ditto.
|
||||
],
|
||||
"servo_mapped_generic_types": [
|
||||
{
|
||||
"generic": True,
|
||||
"gecko": "ServoUnsafeCell",
|
||||
"servo": "::std::cell::UnsafeCell"
|
||||
}, {
|
||||
"generic": True,
|
||||
"gecko": "ServoCell",
|
||||
"servo": "::std::cell::Cell"
|
||||
}, {
|
||||
"generic": False,
|
||||
"gecko": "ServoNodeData",
|
||||
"servo": "OpaqueStyleData"
|
||||
}
|
||||
],
|
||||
},
|
||||
# Generation of the ffi bindings.
|
||||
"bindings": {
|
||||
"target_dir": "../gecko_bindings",
|
||||
"raw_lines": [
|
||||
"use heapsize::HeapSizeOf;",
|
||||
],
|
||||
"flags": [
|
||||
"--ignore-methods",
|
||||
],
|
||||
"match_headers": [
|
||||
"ServoBindingList.h",
|
||||
"ServoBindings.h",
|
||||
"nsStyleStructList.h",
|
||||
],
|
||||
"files": [
|
||||
"{}/dist/include/mozilla/ServoBindings.h",
|
||||
],
|
||||
|
||||
# Types to just use from the `structs` target.
|
||||
"structs_types": [
|
||||
"nsStyleFont", "nsStyleColor", "nsStyleList", "nsStyleText",
|
||||
"nsStyleVisibility", "nsStyleUserInterface", "nsStyleTableBorder",
|
||||
"nsStyleSVG", "nsStyleVariables", "nsStyleBackground",
|
||||
"nsStylePosition", "nsStyleTextReset", "nsStyleDisplay",
|
||||
"nsStyleContent", "nsStyleUIReset", "nsStyleTable",
|
||||
"nsStyleMargin", "nsStylePadding", "nsStyleBorder",
|
||||
"nsStyleOutline", "nsStyleXUL", "nsStyleSVGReset", "nsStyleColumn",
|
||||
"nsStyleEffects", "nsStyleImage", "nsStyleGradient",
|
||||
"nsStyleCoord", "nsStyleGradientStop", "nsStyleImageLayers",
|
||||
"nsStyleImageLayers_Layer", "nsStyleImageLayers_LayerType",
|
||||
"nsStyleUnit", "nsStyleUnion", "nsStyleCoord_CalcValue",
|
||||
"nsStyleCoord_Calc", "nsRestyleHint", "ServoElementSnapshot",
|
||||
"nsChangeHint", "SheetParsingMode", "nsMainThreadPtrHandle",
|
||||
"nsMainThreadPtrHolder", "nscolor", "nsFont", "FontFamilyList",
|
||||
"FontFamilyType", "nsIAtom", "nsStyleContext", "StyleClipPath",
|
||||
"StyleBasicShapeType", "StyleBasicShape", "nsCSSShadowArray",
|
||||
"nsINode", "nsIDocument", "nsIPrincipal", "nsIURI",
|
||||
"RawGeckoNode", "RawGeckoElement", "RawGeckoDocument",
|
||||
"ServoNodeData",
|
||||
],
|
||||
"servo_nullable_arc_types": [
|
||||
"ServoComputedValues", "RawServoStyleSheet",
|
||||
"ServoDeclarationBlock"
|
||||
],
|
||||
"servo_owned_types": [
|
||||
"RawServoStyleSet",
|
||||
"StyleChildrenIterator",
|
||||
],
|
||||
"servo_immutable_borrow_types": [
|
||||
"RawGeckoNode",
|
||||
"RawGeckoElement",
|
||||
"RawGeckoDocument",
|
||||
],
|
||||
"whitelist_functions": [
|
||||
"Servo_.*",
|
||||
"Gecko_.*"
|
||||
]
|
||||
},
|
||||
|
||||
"atoms": {
|
||||
"custom_build": regen_atoms.build,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def platform_dependent_defines():
|
||||
ret = []
|
||||
|
||||
if os.name == "posix":
|
||||
ret.append("-DOS_POSIX=1")
|
||||
|
||||
system = platform.system()
|
||||
if system == "Linux":
|
||||
ret.append("-DOS_LINUX=1")
|
||||
elif system == "Darwin":
|
||||
ret.append("-DOS_MACOSX=1")
|
||||
elif system == "Windows":
|
||||
ret.append("-DOS_WIN=1")
|
||||
ret.append("-DWIN32=1")
|
||||
ret.append("-use-msvc-mangling")
|
||||
msvc_platform = os.environ["PLATFORM"]
|
||||
if msvc_platform == "X86":
|
||||
ret.append("--target=i686-pc-win32")
|
||||
elif msvc_platform == "X64":
|
||||
ret.append("--target=x86_64-pc-win32")
|
||||
else:
|
||||
raise Exception("Only MSVC builds are supported on Windows")
|
||||
# For compatibility with MSVC 2015
|
||||
ret.append("-fms-compatibility-version=19")
|
||||
# To enable the builtin __builtin_offsetof so that CRT wouldn't
|
||||
# use reinterpret_cast in offsetof() which is not allowed inside
|
||||
# static_assert().
|
||||
ret.append("-D_CRT_USE_BUILTIN_OFFSETOF")
|
||||
# Enable hidden attribute (which is not supported by MSVC and
|
||||
# thus not enabled by default with a MSVC-compatibile build)
|
||||
# to exclude hidden symbols from the generated file.
|
||||
ret.append("-DHAVE_VISIBILITY_HIDDEN_ATTRIBUTE=1")
|
||||
else:
|
||||
raise Exception("Unknown platform")
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def extend_object(obj, other):
|
||||
if not obj or not other:
|
||||
return obj
|
||||
|
||||
if isinstance(obj, list) and isinstance(other, list):
|
||||
obj.extend(other)
|
||||
return
|
||||
|
||||
assert isinstance(obj, dict) and isinstance(other, dict)
|
||||
|
||||
for key in other.keys():
|
||||
if key in obj:
|
||||
extend_object(obj[key], other[key])
|
||||
else:
|
||||
obj[key] = copy.deepcopy(other[key])
|
||||
|
||||
|
||||
def build(objdir, target_name, debug, debugger, kind_name=None,
|
||||
output_filename=None, bindgen=None, skip_test=False,
|
||||
verbose=False):
|
||||
assert target_name in COMPILATION_TARGETS
|
||||
|
||||
current_target = COMPILATION_TARGETS[target_name]
|
||||
if COMMON_BUILD_KEY in COMPILATION_TARGETS:
|
||||
current_target = copy.deepcopy(COMPILATION_TARGETS[COMMON_BUILD_KEY])
|
||||
extend_object(current_target, COMPILATION_TARGETS[target_name])
|
||||
|
||||
assert ((kind_name is None and "build_kinds" not in current_target) or
|
||||
(kind_name in current_target["build_kinds"]))
|
||||
|
||||
if "custom_build" in current_target:
|
||||
print("[CUSTOM] {}::{} in \"{}\"... ".format(target_name, kind_name, objdir), end='')
|
||||
sys.stdout.flush()
|
||||
ret = current_target["custom_build"](objdir, verbose=True)
|
||||
if ret != 0:
|
||||
print("FAIL")
|
||||
else:
|
||||
print("OK")
|
||||
|
||||
return ret
|
||||
|
||||
if bindgen is None:
|
||||
bindgen = os.path.join(TOOLS_DIR, "rust-bindgen")
|
||||
|
||||
if os.path.isdir(bindgen):
|
||||
bindgen = ["cargo", "run", "--manifest-path",
|
||||
os.path.join(bindgen, "Cargo.toml"), "--features", "llvm_stable", "--"]
|
||||
else:
|
||||
bindgen = [bindgen]
|
||||
|
||||
if kind_name is not None:
|
||||
current_target = copy.deepcopy(current_target)
|
||||
extend_object(current_target, current_target["build_kinds"][kind_name])
|
||||
|
||||
target_dir = None
|
||||
if output_filename is None and "target_dir" in current_target:
|
||||
target_dir = current_target["target_dir"]
|
||||
|
||||
if output_filename is None:
|
||||
output_filename = "{}.rs".format(target_name)
|
||||
|
||||
if kind_name is not None:
|
||||
output_filename = "{}_{}.rs".format(target_name, kind_name)
|
||||
|
||||
if target_dir:
|
||||
output_filename = "{}/{}".format(target_dir, output_filename)
|
||||
|
||||
print("[BINDGEN] {}::{} in \"{}\"... ".format(target_name, kind_name, objdir), end='')
|
||||
sys.stdout.flush()
|
||||
|
||||
flags = []
|
||||
|
||||
# This makes an FFI-safe void type that can't be matched on
|
||||
# &VoidType is UB to have, because you can match on it
|
||||
# to produce a reachable unreachable. If it's wrapped in
|
||||
# a struct as a private field it becomes okay again
|
||||
#
|
||||
# Not 100% sure of how safe this is, but it's what we're using
|
||||
# in the XPCOM ffi too
|
||||
# https://github.com/nikomatsakis/rust-memory-model/issues/2
|
||||
def zero_size_type(ty, flags):
|
||||
flags.append("--blacklist-type")
|
||||
flags.append(ty)
|
||||
flags.append("--raw-line")
|
||||
flags.append("enum {0}Void{{ }}".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub struct {0}({0}Void);".format(ty))
|
||||
|
||||
if "flags" in current_target:
|
||||
flags.extend(current_target["flags"])
|
||||
|
||||
clang_flags = []
|
||||
|
||||
if "clang_flags" in current_target:
|
||||
clang_flags.extend(current_target["clang_flags"])
|
||||
|
||||
clang_flags.extend(platform_dependent_defines())
|
||||
|
||||
if "raw_lines" in current_target:
|
||||
for raw_line in current_target["raw_lines"]:
|
||||
flags.append("--raw-line")
|
||||
flags.append(raw_line)
|
||||
|
||||
if "search_dirs" in current_target:
|
||||
for dir_name in current_target["search_dirs"]:
|
||||
clang_flags.append("-I")
|
||||
clang_flags.append(dir_name.format(objdir))
|
||||
|
||||
if "includes" in current_target:
|
||||
for file_name in current_target["includes"]:
|
||||
clang_flags.append("-include")
|
||||
clang_flags.append(file_name.format(objdir))
|
||||
|
||||
if "whitelist" in current_target:
|
||||
for header in current_target["whitelist"]:
|
||||
flags.append("--whitelist-type")
|
||||
flags.append(header)
|
||||
|
||||
if "whitelist_functions" in current_target:
|
||||
for header in current_target["whitelist_functions"]:
|
||||
flags.append("--whitelist-function")
|
||||
flags.append(header)
|
||||
|
||||
if "whitelist_vars" in current_target:
|
||||
for header in current_target["whitelist_vars"]:
|
||||
flags.append("--whitelist-var")
|
||||
flags.append(header)
|
||||
|
||||
if "opaque_types" in current_target:
|
||||
for ty in current_target["opaque_types"]:
|
||||
flags.append("--opaque-type")
|
||||
flags.append(ty)
|
||||
|
||||
if "servo_nullable_arc_types" in current_target:
|
||||
for ty in current_target["servo_nullable_arc_types"]:
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}Strong".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}Strong = ::gecko_bindings::sugar::ownership::Strong<{0}>;".format(ty))
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}BorrowedOrNull".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}BorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, {0}>;".format(ty))
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}Borrowed".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}Borrowed<'a> = &'a {0};".format(ty))
|
||||
zero_size_type(ty, flags)
|
||||
|
||||
if "servo_immutable_borrow_types" in current_target:
|
||||
for ty in current_target["servo_immutable_borrow_types"]:
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}Borrowed".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}Borrowed<'a> = &'a {0};".format(ty))
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}BorrowedOrNull".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}BorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, {0}>;".format(ty))
|
||||
# Right now the only immutable borrow types are ones which we import
|
||||
# from the |structs| module. As such, we don't need to create an opaque
|
||||
# type with zero_size_type. If we ever introduce immutable borrow types
|
||||
# which _do_ need to be opaque, we'll need a separate mode.
|
||||
|
||||
if "servo_mapped_generic_types" in current_target:
|
||||
for ty in current_target["servo_mapped_generic_types"]:
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}".format(ty["gecko"]))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}{2} = {1}{2};".format(ty["gecko"], ty["servo"], "<T>" if ty["generic"] else ""))
|
||||
|
||||
if "servo_owned_types" in current_target:
|
||||
for ty in current_target["servo_owned_types"]:
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}Borrowed".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}Borrowed<'a> = &'a {0};".format(ty))
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}BorrowedMut".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}BorrowedMut<'a> = &'a mut {0};".format(ty))
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}Owned".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}Owned = ::gecko_bindings::sugar::ownership::Owned<{0}>;".format(ty))
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}BorrowedOrNull".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}BorrowedOrNull<'a> = ::gecko_bindings::sugar::ownership::Borrowed<'a, {0}>;"
|
||||
.format(ty))
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}BorrowedMutOrNull".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}BorrowedMutOrNull<'a> = ::gecko_bindings::sugar::ownership::BorrowedMut<'a, {0}>;"
|
||||
.format(ty))
|
||||
flags.append("--blacklist-type")
|
||||
flags.append("{}OwnedOrNull".format(ty))
|
||||
flags.append("--raw-line")
|
||||
flags.append("pub type {0}OwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<{0}>;".format(ty))
|
||||
zero_size_type(ty, flags)
|
||||
|
||||
if "structs_types" in current_target:
|
||||
for ty in current_target["structs_types"]:
|
||||
flags.append("--blacklist-type")
|
||||
flags.append(ty)
|
||||
flags.append("--raw-line")
|
||||
flags.append("use gecko_bindings::structs::{};".format(ty))
|
||||
|
||||
# TODO: this is hacky, figure out a better way to do it without
|
||||
# hardcoding everything...
|
||||
if ty.startswith("nsStyle"):
|
||||
flags.extend([
|
||||
"--raw-line",
|
||||
"unsafe impl Send for {} {{}}".format(ty),
|
||||
"--raw-line",
|
||||
"unsafe impl Sync for {} {{}}".format(ty),
|
||||
])
|
||||
|
||||
flags.append("-o")
|
||||
flags.append(output_filename)
|
||||
|
||||
assert len(current_target["files"]) == 1
|
||||
flags.append(current_target["files"][0].format(objdir))
|
||||
|
||||
flags = bindgen + flags + ["--"] + clang_flags
|
||||
|
||||
if verbose:
|
||||
print(flags)
|
||||
|
||||
output = ""
|
||||
try:
|
||||
if debug:
|
||||
flags = [debugger, "--args"] + flags
|
||||
subprocess.check_call(flags)
|
||||
else:
|
||||
output = subprocess.check_output(flags, stderr=subprocess.STDOUT)
|
||||
output = output.decode('utf8')
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("FAIL\n", e.output.decode('utf8'))
|
||||
return 1
|
||||
|
||||
print("OK")
|
||||
|
||||
if verbose:
|
||||
print(output)
|
||||
|
||||
if current_target.get("test", False) and not skip_test:
|
||||
print("[RUSTC]... ", end='')
|
||||
sys.stdout.flush()
|
||||
|
||||
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
test_file = f.name
|
||||
output = None
|
||||
try:
|
||||
rustc_command = ["rustc", output_filename, "--test", "-o", test_file]
|
||||
output = subprocess.check_output(rustc_command, stderr=subprocess.STDOUT)
|
||||
output = output.decode('utf8')
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("FAIL\n", e.output.decode('utf8'))
|
||||
return 1
|
||||
|
||||
print("OK")
|
||||
|
||||
if verbose:
|
||||
print(output)
|
||||
|
||||
print("[RUSTC_TEST]... ", end='')
|
||||
sys.stdout.flush()
|
||||
|
||||
try:
|
||||
output = subprocess.check_output([test_file], stderr=subprocess.STDOUT)
|
||||
output = output.decode('utf8')
|
||||
except subprocess.CalledProcessError as e:
|
||||
print("tests failed: ", e.output.decode('utf8'))
|
||||
return 1
|
||||
|
||||
os.remove(test_file)
|
||||
print("OK")
|
||||
|
||||
# TODO: this -3 is hacky as heck
|
||||
print(output.split('\n')[-3])
|
||||
|
||||
if verbose:
|
||||
print(output)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def builds_for(target_name, kind):
|
||||
if target_name == "all":
|
||||
for target in COMPILATION_TARGETS.keys():
|
||||
if target == COMMON_BUILD_KEY:
|
||||
continue
|
||||
|
||||
if "build_kinds" in COMPILATION_TARGETS[target]:
|
||||
for kind in COMPILATION_TARGETS[target]["build_kinds"].keys():
|
||||
yield (target, kind)
|
||||
else:
|
||||
yield (target, None)
|
||||
return
|
||||
|
||||
target = COMPILATION_TARGETS[target_name]
|
||||
if "build_kinds" in target:
|
||||
if kind is None:
|
||||
for kind in target["build_kinds"].keys():
|
||||
yield(target_name, kind)
|
||||
else:
|
||||
yield (target_name, kind)
|
||||
return
|
||||
|
||||
yield (target_name, None)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=DESCRIPTION)
|
||||
parser.add_argument('--target', default='all',
|
||||
help='The target to build, either "structs" or "bindings"')
|
||||
parser.add_argument('--kind',
|
||||
help='Kind of build')
|
||||
parser.add_argument('--bindgen',
|
||||
help='Override bindgen binary')
|
||||
parser.add_argument('--output', '-o',
|
||||
help='Output of the script')
|
||||
parser.add_argument('--skip-test',
|
||||
action='store_true',
|
||||
help='Skip automatic tests, useful for debugging')
|
||||
parser.add_argument('--verbose', '-v',
|
||||
action='store_true',
|
||||
help='Be... verbose')
|
||||
parser.add_argument('--debug',
|
||||
action='store_true',
|
||||
help='Try to use a debugger to debug bindgen commands (default: gdb)')
|
||||
parser.add_argument('--debugger', default='gdb',
|
||||
help='Debugger to use. Only used if --debug is passed.')
|
||||
parser.add_argument('objdir')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not os.path.isdir(args.objdir):
|
||||
print("\"{}\" doesn't seem to be a directory".format(args.objdir))
|
||||
return 1
|
||||
|
||||
if (args.target != "all" and args.target not in COMPILATION_TARGETS) or args.target == COMMON_BUILD_KEY:
|
||||
print("{} is not a valid compilation target.".format(args.target))
|
||||
print("Valid compilation targets are:")
|
||||
for target in COMPILATION_TARGETS.keys():
|
||||
if target != COMMON_BUILD_KEY:
|
||||
print("\t * {}".format(target))
|
||||
return 1
|
||||
|
||||
current_target = COMPILATION_TARGETS.get(args.target, {})
|
||||
if args.kind and "build_kinds" in current_target and args.kind not in current_target["build_kinds"]:
|
||||
print("{} is not a valid build kind.".format(args.kind))
|
||||
print("Valid build kinds are:")
|
||||
for kind in current_target["build_kinds"].keys():
|
||||
print("\t * {}".format(kind))
|
||||
return 1
|
||||
|
||||
for target, kind in builds_for(args.target, args.kind):
|
||||
ret = build(args.objdir, target, kind_name=kind,
|
||||
debug=args.debug, debugger=args.debugger,
|
||||
bindgen=args.bindgen, skip_test=args.skip_test,
|
||||
output_filename=args.output,
|
||||
verbose=args.verbose)
|
||||
if ret != 0:
|
||||
print("{}::{} failed".format(target, kind))
|
||||
return ret
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
35
components/style/binding_tools/regen.sh
Executable file
35
components/style/binding_tools/regen.sh
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# 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/.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
if [[ ${#} -eq 0 ]]; then
|
||||
echo "Usage: ${0} /path/to/gecko/objdir [other-regen.py-flags]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for rust-bindgen
|
||||
if [[ ! -d rust-bindgen ]]; then
|
||||
echo "rust-bindgen not found. Run setup_bindgen.sh first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for /usr/include
|
||||
if [[ ! -d /usr/include ]]; then
|
||||
echo "/usr/include doesn't exist." \
|
||||
"Mac users may need to run xcode-select --install."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$(uname)" == "Linux" ]]; then
|
||||
LIBCLANG_PATH=/usr/lib/llvm-3.8/lib
|
||||
else
|
||||
LIBCLANG_PATH="$(brew --prefix llvm38)/lib/llvm-3.8/lib"
|
||||
fi
|
||||
|
||||
./regen.py --target all "${@}"
|
196
components/style/binding_tools/regen_atoms.py
Executable file
196
components/style/binding_tools/regen_atoms.py
Executable file
|
@ -0,0 +1,196 @@
|
|||
#!/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
|
||||
|
||||
|
||||
def gnu_symbolify(source, ident):
|
||||
return "_ZN" + str(len(source.CLASS)) + source.CLASS + str(len(ident)) + ident + "E"
|
||||
|
||||
|
||||
def msvc64_symbolify(source, ident):
|
||||
return "?" + ident + "@" + source.CLASS + "@@2PEAV" + source.TYPE + "@@EA"
|
||||
|
||||
|
||||
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?" + ident + "@" + source.CLASS + "@@2PAV" + source.TYPE + "@@A"
|
||||
|
||||
|
||||
class GkAtomSource:
|
||||
PATTERN = re.compile('^GK_ATOM\((.+),\s*"(.*)"\)')
|
||||
FILE = "dist/include/nsGkAtomList.h"
|
||||
CLASS = "nsGkAtoms"
|
||||
TYPE = "nsIAtom"
|
||||
|
||||
|
||||
class CSSPseudoElementsAtomSource:
|
||||
PATTERN = re.compile('^CSS_PSEUDO_ELEMENT\((.+),\s*"(.*)",')
|
||||
FILE = "dist/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\((.+),\s*"(.*)"\)')
|
||||
FILE = "dist/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 collect_atoms(objdir):
|
||||
atoms = []
|
||||
for source in SOURCES:
|
||||
with open(os.path.join(objdir, source.FILE)) 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
|
||||
|
||||
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, DO NOT EDIT DIRECTLY */
|
||||
"""[1:]
|
||||
|
||||
|
||||
def write_atom_macro(atoms, file_name):
|
||||
ATOM_TEMPLATE = """
|
||||
#[link_name = "{link_name}"]
|
||||
pub static {name}: *mut {type};
|
||||
"""[1:]
|
||||
|
||||
def write_items(f, func):
|
||||
f.write(" extern {\n")
|
||||
for atom in atoms:
|
||||
f.write(ATOM_TEMPLATE.format(name=atom.ident,
|
||||
link_name=func(atom),
|
||||
type=atom.type()))
|
||||
f.write(" }\n")
|
||||
|
||||
with open(file_name, "wb") as f:
|
||||
f.write(PRELUDE)
|
||||
f.write("use style::gecko_bindings::structs::nsIAtom;\n\n")
|
||||
f.write("use Atom;\n\n")
|
||||
for source in SOURCES:
|
||||
if source.TYPE != "nsIAtom":
|
||||
f.write("pub enum {} {{}}\n\n".format(source.TYPE))
|
||||
f.write("""
|
||||
#[inline(always)] pub fn unsafe_atom_from_static(ptr: *mut nsIAtom) -> Atom {
|
||||
unsafe { Atom::from_static(ptr) }
|
||||
}\n\n
|
||||
""")
|
||||
f.write("cfg_if! {\n")
|
||||
f.write(" if #[cfg(not(target_env = \"msvc\"))] {\n")
|
||||
write_items(f, Atom.gnu_symbol)
|
||||
f.write(" } else if #[cfg(target_pointer_width = \"64\")] {\n")
|
||||
write_items(f, Atom.msvc64_symbol)
|
||||
f.write(" } else {\n")
|
||||
write_items(f, Atom.msvc32_symbol)
|
||||
f.write(" }\n")
|
||||
f.write("}\n\n")
|
||||
f.write("#[macro_export]\n")
|
||||
f.write("macro_rules! atom {\n")
|
||||
f.writelines(['("%s") => { $crate::string_cache::atom_macro::unsafe_atom_from_static($crate::string_cache::atom_macro::%s as *mut _) };\n'
|
||||
% (atom.value, atom.ident) for atom in atoms])
|
||||
f.write("}\n")
|
||||
|
||||
|
||||
PSEUDO_ELEMENT_HEADER = """
|
||||
/*
|
||||
* This file contains a helper macro invocation to aid Gecko's style system
|
||||
* pseudo-element integration.
|
||||
*
|
||||
* This file is NOT INTENDED to be compiled as a standalone module.
|
||||
*
|
||||
* Also, it guarantees the property that normal pseudo-elements are processed
|
||||
* before anonymous boxes.
|
||||
*
|
||||
* Expected usage is as follows:
|
||||
*
|
||||
* ```
|
||||
* fn have_to_use_pseudo_elements() {
|
||||
* macro_rules pseudo_element! {
|
||||
* ($pseudo_str_with_colon:expr, $pseudo_atom:expr, $is_anon_box:true) => {{
|
||||
* // Stuff stuff stuff.
|
||||
* }}
|
||||
* }
|
||||
* include!("path/to/helper.rs")
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
"""
|
||||
|
||||
PSEUDO_ELEMENT_MACRO_INVOCATION = """
|
||||
pseudo_element!(\"{}\",
|
||||
atom!(\"{}\"),
|
||||
{});
|
||||
"""[1:]
|
||||
|
||||
|
||||
def write_pseudo_element_helper(atoms, target_filename):
|
||||
with open(target_filename, "wb") as f:
|
||||
f.write(PRELUDE)
|
||||
f.write(PSEUDO_ELEMENT_HEADER)
|
||||
f.write("{\n")
|
||||
for atom in atoms:
|
||||
if atom.type() == "nsICSSPseudoElement":
|
||||
f.write(PSEUDO_ELEMENT_MACRO_INVOCATION.format(atom.value, atom.value, "false"))
|
||||
elif atom.type() == "nsICSSAnonBoxPseudo":
|
||||
f.write(PSEUDO_ELEMENT_MACRO_INVOCATION.format(atom.value, atom.value, "true"))
|
||||
f.write("}\n")
|
||||
|
||||
|
||||
def build(objdir, verbose=False):
|
||||
atoms = collect_atoms(objdir)
|
||||
write_atom_macro(atoms, "../gecko_string_cache/atom_macro.rs")
|
||||
write_pseudo_element_helper(atoms, "../generated/gecko_pseudo_element_helper.rs")
|
||||
return 0
|
45
components/style/binding_tools/setup_bindgen.sh
Executable file
45
components/style/binding_tools/setup_bindgen.sh
Executable file
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# 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/.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
# Run in the tools directory.
|
||||
cd "$(dirname ${0})"
|
||||
|
||||
# Setup and build bindgen.
|
||||
if [[ "$(uname)" == "Linux" ]]; then
|
||||
export LIBCLANG_PATH=/usr/lib/llvm-3.8/lib
|
||||
else
|
||||
export LIBCLANG_PATH="$(brew --prefix llvm38)/lib/llvm-3.8/lib"
|
||||
fi
|
||||
|
||||
# Make sure we have llvm38.
|
||||
if [[ ! -x "$(command -v clang-3.8)" ]]; then
|
||||
echo "llmv38 must be installed." \
|
||||
"Mac users should |brew install llvm38|, Linux varies by distro."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export LD_LIBRARY_PATH="${LIBCLANG_PATH}"
|
||||
export DYLD_LIBRARY_PATH="${LIBCLANG_PATH}"
|
||||
|
||||
# Check for multirust
|
||||
if [[ ! -x "$(command -v multirust)" ]]; then
|
||||
echo "multirust must be installed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Don't try to clone twice.
|
||||
if [[ ! -d rust-bindgen ]]; then
|
||||
git clone https://github.com/servo/rust-bindgen.git
|
||||
fi
|
||||
|
||||
cd rust-bindgen
|
||||
|
||||
multirust override nightly
|
||||
cargo build --features llvm_stable
|
1035
components/style/gecko_bindings/bindings.rs
Normal file
1035
components/style/gecko_bindings/bindings.rs
Normal file
File diff suppressed because it is too large
Load diff
18
components/style/gecko_bindings/mod.rs
Normal file
18
components/style/gecko_bindings/mod.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
/* 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/. */
|
||||
|
||||
#[allow(dead_code, non_camel_case_types)]
|
||||
pub mod bindings;
|
||||
pub mod ptr;
|
||||
#[cfg(debug_assertions)]
|
||||
#[allow(dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals)]
|
||||
pub mod structs {
|
||||
include!("structs_debug.rs");
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[allow(dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals)]
|
||||
pub mod structs {
|
||||
include!("structs_release.rs");
|
||||
}
|
||||
pub mod sugar;
|
64
components/style/gecko_bindings/ptr.rs
Normal file
64
components/style/gecko_bindings/ptr.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
/* 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/. */
|
||||
|
||||
use gecko_bindings::bindings::*;
|
||||
use heapsize::HeapSizeOf;
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
// Defines an Arc-like type that manages a refcounted Gecko object stored
|
||||
// in a ThreadSafeFooHolder smart pointer (for those Gecko classes that
|
||||
// do not have thread-safe refcounting support) or as raw pointers (for
|
||||
// those that do have thread-safe refcounting support). Used in tandem
|
||||
// with the NS_DECL_(HOLDER|THREADSAFE)_FFI_REFCOUNTING-defined types and
|
||||
// functions in Gecko.
|
||||
macro_rules! define_arc {
|
||||
($arc_type:ident, $name:ident, $gecko_type:ident, $addref: ident, $release: ident) => (
|
||||
#[derive(PartialEq)]
|
||||
pub struct $arc_type {
|
||||
ptr: *mut $gecko_type,
|
||||
}
|
||||
|
||||
impl $arc_type {
|
||||
pub fn new(data: *mut $gecko_type) -> $arc_type {
|
||||
debug_assert!(!data.is_null());
|
||||
unsafe { $addref(data); }
|
||||
$arc_type {
|
||||
ptr: data
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_raw(&self) -> *mut $gecko_type { self.ptr }
|
||||
}
|
||||
|
||||
unsafe impl Send for $arc_type {}
|
||||
unsafe impl Sync for $arc_type {}
|
||||
|
||||
impl Clone for $arc_type {
|
||||
fn clone(&self) -> $arc_type {
|
||||
$arc_type::new(self.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for $arc_type {
|
||||
fn drop(&mut self) {
|
||||
unsafe { $release(self.ptr); }
|
||||
}
|
||||
}
|
||||
|
||||
impl HeapSizeOf for $arc_type {
|
||||
fn heap_size_of_children(&self) -> usize { 0 }
|
||||
}
|
||||
|
||||
impl Debug for $arc_type {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, stringify!($name))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
define_arc!(GeckoArcPrincipal, Principal, ThreadSafePrincipalHolder,
|
||||
Gecko_AddRefPrincipalArbitraryThread, Gecko_ReleasePrincipalArbitraryThread);
|
||||
define_arc!(GeckoArcURI, URI, ThreadSafeURIHolder,
|
||||
Gecko_AddRefURIArbitraryThread, Gecko_ReleaseURIArbitraryThread);
|
10960
components/style/gecko_bindings/structs_debug.rs
Normal file
10960
components/style/gecko_bindings/structs_debug.rs
Normal file
File diff suppressed because it is too large
Load diff
10904
components/style/gecko_bindings/structs_release.rs
Normal file
10904
components/style/gecko_bindings/structs_release.rs
Normal file
File diff suppressed because it is too large
Load diff
9
components/style/gecko_bindings/sugar/mod.rs
Normal file
9
components/style/gecko_bindings/sugar/mod.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* 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/. */
|
||||
|
||||
mod ns_css_shadow_array;
|
||||
mod ns_style_auto_array;
|
||||
pub mod ns_style_coord;
|
||||
mod ns_t_array;
|
||||
pub mod ownership;
|
65
components/style/gecko_bindings/sugar/ns_css_shadow_array.rs
Normal file
65
components/style/gecko_bindings/sugar/ns_css_shadow_array.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
/* 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/. */
|
||||
|
||||
use gecko_bindings::bindings::Gecko_AddRefCSSShadowArrayArbitraryThread;
|
||||
use gecko_bindings::bindings::Gecko_NewCSSShadowArray;
|
||||
use gecko_bindings::bindings::Gecko_ReleaseCSSShadowArrayArbitraryThread;
|
||||
use std::{ptr, slice};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use gecko_bindings::structs::{RefPtr, nsCSSShadowArray, nsCSSShadowItem};
|
||||
|
||||
impl RefPtr<nsCSSShadowArray> {
|
||||
pub fn replace_with_new(&mut self, len: u32) {
|
||||
unsafe {
|
||||
if !self.mRawPtr.is_null() {
|
||||
Gecko_ReleaseCSSShadowArrayArbitraryThread(self.mRawPtr);
|
||||
}
|
||||
|
||||
self.mRawPtr = if len == 0 {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
Gecko_NewCSSShadowArray(len)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn copy_from(&mut self, other: &Self) {
|
||||
unsafe {
|
||||
if !self.mRawPtr.is_null() {
|
||||
Gecko_ReleaseCSSShadowArrayArbitraryThread(self.mRawPtr);
|
||||
}
|
||||
if !other.mRawPtr.is_null() {
|
||||
Gecko_AddRefCSSShadowArrayArbitraryThread(other.mRawPtr);
|
||||
}
|
||||
|
||||
self.mRawPtr = other.mRawPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for RefPtr<nsCSSShadowArray> {
|
||||
type Target = [nsCSSShadowItem];
|
||||
fn deref(&self) -> &[nsCSSShadowItem] {
|
||||
if self.mRawPtr.is_null() {
|
||||
&[]
|
||||
} else {
|
||||
unsafe {
|
||||
slice::from_raw_parts((*self.mRawPtr).mArray.as_ptr(),
|
||||
(*self.mRawPtr).mLength as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for RefPtr<nsCSSShadowArray> {
|
||||
fn deref_mut(&mut self) -> &mut [nsCSSShadowItem] {
|
||||
if self.mRawPtr.is_null() {
|
||||
&mut []
|
||||
} else {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut((*self.mRawPtr).mArray.as_mut_ptr(),
|
||||
(*self.mRawPtr).mLength as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
components/style/gecko_bindings/sugar/ns_style_auto_array.rs
Normal file
31
components/style/gecko_bindings/sugar/ns_style_auto_array.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* 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/. */
|
||||
|
||||
use std::iter::{once, Chain, Once, IntoIterator};
|
||||
use std::slice::{Iter, IterMut};
|
||||
use gecko_bindings::structs::nsStyleAutoArray;
|
||||
|
||||
impl<T> nsStyleAutoArray<T> {
|
||||
pub fn iter_mut(&mut self) -> Chain<Once<&mut T>, IterMut<T>> {
|
||||
once(&mut self.mFirstElement).chain(self.mOtherElements.iter_mut())
|
||||
}
|
||||
pub fn iter(&self) -> Chain<Once<&T>, Iter<T>> {
|
||||
once(&self.mFirstElement).chain(self.mOtherElements.iter())
|
||||
}
|
||||
|
||||
// Note that often structs containing autoarrays will have
|
||||
// additional member fields that contain the length, which must be kept
|
||||
// in sync
|
||||
pub fn len(&self) -> usize {
|
||||
1 + self.mOtherElements.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a mut nsStyleAutoArray<T> {
|
||||
type Item = &'a mut T;
|
||||
type IntoIter = Chain<Once<&'a mut T>, IterMut<'a, T>>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
397
components/style/gecko_bindings/sugar/ns_style_coord.rs
Normal file
397
components/style/gecko_bindings/sugar/ns_style_coord.rs
Normal file
|
@ -0,0 +1,397 @@
|
|||
/* 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/. */
|
||||
|
||||
use gecko_bindings::bindings::{Gecko_ResetStyleCoord, Gecko_SetStyleCoordCalcValue, Gecko_AddRefCalcArbitraryThread};
|
||||
use std::mem;
|
||||
use gecko_bindings::structs::{nsStyleCoord_Calc, nsStyleUnit, nsStyleUnion, nsStyleCoord, nsStyleSides, nsStyleCorners};
|
||||
use gecko_bindings::structs::{nsStyleCoord_CalcValue, nscoord};
|
||||
|
||||
impl nsStyleCoord {
|
||||
#[inline]
|
||||
pub fn null() -> Self {
|
||||
// Can't construct directly because it has private fields
|
||||
let mut coord: Self = unsafe { mem::zeroed() };
|
||||
coord.leaky_set_null();
|
||||
coord
|
||||
}
|
||||
}
|
||||
|
||||
impl CoordData for nsStyleCoord {
|
||||
#[inline]
|
||||
fn unit(&self) -> nsStyleUnit {
|
||||
unsafe {
|
||||
*self.get_mUnit()
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn union(&self) -> nsStyleUnion {
|
||||
unsafe {
|
||||
*self.get_mValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CoordDataMut for nsStyleCoord {
|
||||
unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) {
|
||||
let unit = self.get_mUnit_mut() as *mut _;
|
||||
let value = self.get_mValue_mut() as *mut _;
|
||||
(&mut *unit, &mut *value)
|
||||
}
|
||||
}
|
||||
|
||||
impl nsStyleCoord_CalcValue {
|
||||
pub fn new() -> Self {
|
||||
nsStyleCoord_CalcValue {
|
||||
mLength: 0,
|
||||
mPercent: 0.0,
|
||||
mHasPercent: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl nsStyleSides {
|
||||
#[inline]
|
||||
pub fn data_at(&self, index: usize) -> SidesData {
|
||||
SidesData {
|
||||
sides: self,
|
||||
index: index,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn data_at_mut(&mut self, index: usize) -> SidesDataMut {
|
||||
SidesDataMut {
|
||||
sides: self,
|
||||
index: index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SidesData<'a> {
|
||||
sides: &'a nsStyleSides,
|
||||
index: usize,
|
||||
}
|
||||
pub struct SidesDataMut<'a> {
|
||||
sides: &'a mut nsStyleSides,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a> CoordData for SidesData<'a> {
|
||||
#[inline]
|
||||
fn unit(&self) -> nsStyleUnit {
|
||||
unsafe {
|
||||
self.sides.get_mUnits()[self.index]
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn union(&self) -> nsStyleUnion {
|
||||
unsafe {
|
||||
self.sides.get_mValues()[self.index]
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> CoordData for SidesDataMut<'a> {
|
||||
#[inline]
|
||||
fn unit(&self) -> nsStyleUnit {
|
||||
unsafe {
|
||||
self.sides.get_mUnits()[self.index]
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn union(&self) -> nsStyleUnion {
|
||||
unsafe {
|
||||
self.sides.get_mValues()[self.index]
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> CoordDataMut for SidesDataMut<'a> {
|
||||
unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) {
|
||||
let unit = &mut self.sides.get_mUnits_mut()[self.index] as *mut _;
|
||||
let value = &mut self.sides.get_mValues_mut()[self.index] as *mut _;
|
||||
(&mut *unit, &mut *value)
|
||||
}
|
||||
}
|
||||
|
||||
impl nsStyleCorners {
|
||||
#[inline]
|
||||
pub fn data_at(&self, index: usize) -> CornersData {
|
||||
CornersData {
|
||||
corners: self,
|
||||
index: index,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn data_at_mut(&mut self, index: usize) -> CornersDataMut {
|
||||
CornersDataMut {
|
||||
corners: self,
|
||||
index: index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CornersData<'a> {
|
||||
corners: &'a nsStyleCorners,
|
||||
index: usize,
|
||||
}
|
||||
pub struct CornersDataMut<'a> {
|
||||
corners: &'a mut nsStyleCorners,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a> CoordData for CornersData<'a> {
|
||||
fn unit(&self) -> nsStyleUnit {
|
||||
unsafe {
|
||||
self.corners.get_mUnits()[self.index]
|
||||
}
|
||||
}
|
||||
fn union(&self) -> nsStyleUnion {
|
||||
unsafe {
|
||||
self.corners.get_mValues()[self.index]
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> CoordData for CornersDataMut<'a> {
|
||||
fn unit(&self) -> nsStyleUnit {
|
||||
unsafe {
|
||||
self.corners.get_mUnits()[self.index]
|
||||
}
|
||||
}
|
||||
fn union(&self) -> nsStyleUnion {
|
||||
unsafe {
|
||||
self.corners.get_mValues()[self.index]
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> CoordDataMut for CornersDataMut<'a> {
|
||||
unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) {
|
||||
let unit = &mut self.corners.get_mUnits_mut()[self.index] as *mut _;
|
||||
let value = &mut self.corners.get_mValues_mut()[self.index] as *mut _;
|
||||
(&mut *unit, &mut *value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
/// Enum representing the tagged union that is CoordData.
|
||||
/// In release mode this should never actually exist in the code,
|
||||
/// and will be optimized out by threading matches and inlining.
|
||||
pub enum CoordDataValue {
|
||||
Null,
|
||||
Normal,
|
||||
Auto,
|
||||
None,
|
||||
Percent(f32),
|
||||
Factor(f32),
|
||||
Degree(f32),
|
||||
Grad(f32),
|
||||
Radian(f32),
|
||||
Turn(f32),
|
||||
FlexFraction(f32),
|
||||
Coord(nscoord),
|
||||
Integer(i32),
|
||||
Enumerated(u32),
|
||||
Calc(nsStyleCoord_CalcValue),
|
||||
}
|
||||
|
||||
|
||||
pub trait CoordDataMut : CoordData {
|
||||
// This can't be two methods since we can't mutably borrow twice
|
||||
/// This is unsafe since it's possible to modify
|
||||
/// the unit without changing the union
|
||||
unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion);
|
||||
|
||||
/// Clean up any resources used by the union
|
||||
/// Currently, this only happens if the nsStyleUnit
|
||||
/// is a Calc
|
||||
#[inline]
|
||||
fn reset(&mut self) {
|
||||
unsafe {
|
||||
if self.unit() == nsStyleUnit::eStyleUnit_Calc {
|
||||
let (unit, union) = self.values_mut();
|
||||
Gecko_ResetStyleCoord(unit, union);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_from<T: CoordData>(&mut self, other: &T) {
|
||||
unsafe {
|
||||
self.reset();
|
||||
{
|
||||
let (unit, union) = self.values_mut();
|
||||
*unit = other.unit();
|
||||
*union = other.union();
|
||||
}
|
||||
self.addref_if_calc();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn copy_from_unchecked<T: CoordData>(&mut self, other: &T) {
|
||||
let (unit, union) = self.values_mut();
|
||||
*unit = other.unit();
|
||||
*union = other.union();
|
||||
}
|
||||
|
||||
/// Useful for initializing uninits
|
||||
/// (set_value may segfault on uninits)
|
||||
fn leaky_set_null(&mut self) {
|
||||
use gecko_bindings::structs::nsStyleUnit::*;
|
||||
unsafe {
|
||||
let (unit, union) = self.values_mut();
|
||||
*unit = eStyleUnit_Null;
|
||||
*union.mInt.as_mut() = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_value(&mut self, value: CoordDataValue) {
|
||||
use self::CoordDataValue::*;
|
||||
use gecko_bindings::structs::nsStyleUnit::*;
|
||||
self.reset();
|
||||
unsafe {
|
||||
let (unit, union) = self.values_mut();
|
||||
match value {
|
||||
Null => {
|
||||
*unit = eStyleUnit_Null;
|
||||
*union.mInt.as_mut() = 0;
|
||||
}
|
||||
Normal => {
|
||||
*unit = eStyleUnit_Normal;
|
||||
*union.mInt.as_mut() = 0;
|
||||
}
|
||||
Auto => {
|
||||
*unit = eStyleUnit_Auto;
|
||||
*union.mInt.as_mut() = 0;
|
||||
}
|
||||
None => {
|
||||
*unit = eStyleUnit_None;
|
||||
*union.mInt.as_mut() = 0;
|
||||
}
|
||||
Percent(f) => {
|
||||
*unit = eStyleUnit_Percent;
|
||||
*union.mFloat.as_mut() = f;
|
||||
}
|
||||
Factor(f) => {
|
||||
*unit = eStyleUnit_Factor;
|
||||
*union.mFloat.as_mut() = f;
|
||||
}
|
||||
Degree(f) => {
|
||||
*unit = eStyleUnit_Degree;
|
||||
*union.mFloat.as_mut() = f;
|
||||
}
|
||||
Grad(f) => {
|
||||
*unit = eStyleUnit_Grad;
|
||||
*union.mFloat.as_mut() = f;
|
||||
}
|
||||
Radian(f) => {
|
||||
*unit = eStyleUnit_Radian;
|
||||
*union.mFloat.as_mut() = f;
|
||||
}
|
||||
Turn(f) => {
|
||||
*unit = eStyleUnit_Turn;
|
||||
*union.mFloat.as_mut() = f;
|
||||
}
|
||||
FlexFraction(f) => {
|
||||
*unit = eStyleUnit_FlexFraction;
|
||||
*union.mFloat.as_mut() = f;
|
||||
}
|
||||
Coord(coord) => {
|
||||
*unit = eStyleUnit_Coord;
|
||||
*union.mInt.as_mut() = coord;
|
||||
}
|
||||
Integer(i) => {
|
||||
*unit = eStyleUnit_Integer;
|
||||
*union.mInt.as_mut() = i;
|
||||
}
|
||||
Enumerated(i) => {
|
||||
*unit = eStyleUnit_Enumerated;
|
||||
*union.mInt.as_mut() = i as i32;
|
||||
}
|
||||
Calc(calc) => {
|
||||
// Gecko_SetStyleCoordCalcValue changes the unit internally
|
||||
Gecko_SetStyleCoordCalcValue(unit, union, calc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_calc_mut(&mut self) -> &mut nsStyleCoord_Calc {
|
||||
debug_assert!(self.unit() == nsStyleUnit::eStyleUnit_Calc);
|
||||
&mut *(*self.union().mPointer.as_mut() as *mut nsStyleCoord_Calc)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn addref_if_calc(&mut self) {
|
||||
unsafe {
|
||||
if self.unit() == nsStyleUnit::eStyleUnit_Calc {
|
||||
Gecko_AddRefCalcArbitraryThread(self.as_calc_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub trait CoordData {
|
||||
fn unit(&self) -> nsStyleUnit;
|
||||
fn union(&self) -> nsStyleUnion;
|
||||
|
||||
|
||||
#[inline(always)]
|
||||
fn as_value(&self) -> CoordDataValue {
|
||||
use self::CoordDataValue::*;
|
||||
use gecko_bindings::structs::nsStyleUnit::*;
|
||||
unsafe {
|
||||
match self.unit() {
|
||||
eStyleUnit_Null => Null,
|
||||
eStyleUnit_Normal => Normal,
|
||||
eStyleUnit_Auto => Auto,
|
||||
eStyleUnit_None => None,
|
||||
eStyleUnit_Percent => Percent(self.get_float()),
|
||||
eStyleUnit_Factor => Factor(self.get_float()),
|
||||
eStyleUnit_Degree => Degree(self.get_float()),
|
||||
eStyleUnit_Grad => Grad(self.get_float()),
|
||||
eStyleUnit_Radian => Radian(self.get_float()),
|
||||
eStyleUnit_Turn => Turn(self.get_float()),
|
||||
eStyleUnit_FlexFraction => FlexFraction(self.get_float()),
|
||||
eStyleUnit_Coord => Coord(self.get_integer()),
|
||||
eStyleUnit_Integer => Integer(self.get_integer()),
|
||||
eStyleUnit_Enumerated => Enumerated(self.get_integer() as u32),
|
||||
eStyleUnit_Calc => Calc(self.get_calc_value()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Pretend inner value is a float; obtain it.
|
||||
unsafe fn get_float(&self) -> f32 {
|
||||
use gecko_bindings::structs::nsStyleUnit::*;
|
||||
debug_assert!(self.unit() == eStyleUnit_Percent || self.unit() == eStyleUnit_Factor
|
||||
|| self.unit() == eStyleUnit_Degree || self.unit() == eStyleUnit_Grad
|
||||
|| self.unit() == eStyleUnit_Radian || self.unit() == eStyleUnit_Turn
|
||||
|| self.unit() == eStyleUnit_FlexFraction);
|
||||
*self.union().mFloat.as_ref()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Pretend inner value is an int; obtain it.
|
||||
unsafe fn get_integer(&self) -> i32 {
|
||||
use gecko_bindings::structs::nsStyleUnit::*;
|
||||
debug_assert!(self.unit() == eStyleUnit_Coord || self.unit() == eStyleUnit_Integer
|
||||
|| self.unit() == eStyleUnit_Enumerated);
|
||||
*self.union().mInt.as_ref()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Pretend inner value is a calc; obtain it.
|
||||
/// Ensure that the unit is Calc before calling this.
|
||||
unsafe fn get_calc_value(&self) -> nsStyleCoord_CalcValue {
|
||||
debug_assert!(self.unit() == nsStyleUnit::eStyleUnit_Calc);
|
||||
(*self.as_calc())._base
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
unsafe fn as_calc(&self) -> &nsStyleCoord_Calc {
|
||||
debug_assert!(self.unit() == nsStyleUnit::eStyleUnit_Calc);
|
||||
&*(*self.union().mPointer.as_ref() as *const nsStyleCoord_Calc)
|
||||
}
|
||||
}
|
93
components/style/gecko_bindings/sugar/ns_t_array.rs
Normal file
93
components/style/gecko_bindings/sugar/ns_t_array.rs
Normal file
|
@ -0,0 +1,93 @@
|
|||
/* 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/. */
|
||||
|
||||
use gecko_bindings::bindings;
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::raw::c_void;
|
||||
use std::slice;
|
||||
use gecko_bindings::structs::{nsTArray, nsTArrayHeader};
|
||||
|
||||
impl<T> Deref for nsTArray<T> {
|
||||
type Target = [T];
|
||||
|
||||
fn deref<'a>(&'a self) -> &'a [T] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self.slice_begin(),
|
||||
self.header().mLength as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for nsTArray<T> {
|
||||
fn deref_mut<'a>(&'a mut self) -> &'a mut [T] {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self.slice_begin(),
|
||||
self.header().mLength as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> nsTArray<T> {
|
||||
#[inline]
|
||||
fn header<'a>(&'a self) -> &'a nsTArrayHeader {
|
||||
debug_assert!(!self.mBuffer.is_null());
|
||||
unsafe { mem::transmute(self.mBuffer) }
|
||||
}
|
||||
// unsafe, since header may be in shared static or something
|
||||
unsafe fn header_mut<'a>(&'a mut self) -> &'a mut nsTArrayHeader {
|
||||
debug_assert!(!self.mBuffer.is_null());
|
||||
|
||||
mem::transmute(self.mBuffer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn slice_begin(&self) -> *mut T {
|
||||
debug_assert!(!self.mBuffer.is_null());
|
||||
(self.mBuffer as *const nsTArrayHeader).offset(1) as *mut _
|
||||
}
|
||||
|
||||
/// Ensures the array has enough capacity at least to hold `cap` elements.
|
||||
///
|
||||
/// NOTE: This doesn't call the constructor on the values!
|
||||
pub fn ensure_capacity(&mut self, cap: usize) {
|
||||
if cap >= self.len() {
|
||||
unsafe {
|
||||
bindings::Gecko_EnsureTArrayCapacity(self as *mut nsTArray<T> as *mut _,
|
||||
cap, mem::size_of::<T>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the array storage without calling the destructor on the values.
|
||||
#[inline]
|
||||
pub unsafe fn clear(&mut self) {
|
||||
if self.len() != 0 {
|
||||
bindings::Gecko_ClearPODTArray(self as *mut nsTArray<T> as *mut _,
|
||||
mem::size_of::<T>(),
|
||||
mem::align_of::<T>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Clears a POD array. This is safe since copy types are memcopyable.
|
||||
#[inline]
|
||||
pub fn clear_pod(&mut self)
|
||||
where T: Copy
|
||||
{
|
||||
unsafe { self.clear() }
|
||||
}
|
||||
|
||||
// unsafe because the array may contain uninits
|
||||
// This will not call constructors, either manually
|
||||
// add bindings or run the typed ensurecapacity call
|
||||
// on the gecko side
|
||||
pub unsafe fn set_len(&mut self, len: u32) {
|
||||
// this can leak
|
||||
debug_assert!(len >= self.len() as u32);
|
||||
self.ensure_capacity(len as usize);
|
||||
let mut header = self.header_mut();
|
||||
header.mLength = len;
|
||||
}
|
||||
}
|
397
components/style/gecko_bindings/sugar/ownership.rs
Normal file
397
components/style/gecko_bindings/sugar/ownership.rs
Normal file
|
@ -0,0 +1,397 @@
|
|||
/* 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/. */
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::{forget, transmute};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Indicates that a given Servo type has a corresponding
|
||||
/// Gecko FFI type
|
||||
/// The correspondence is not defined at this stage,
|
||||
/// use HasArcFFI or similar traits to define it
|
||||
pub unsafe trait HasFFI : Sized {
|
||||
type FFIType: Sized;
|
||||
}
|
||||
|
||||
/// Indicates that a given Servo type has the same layout
|
||||
/// as the corresponding HasFFI::FFIType type
|
||||
pub unsafe trait HasSimpleFFI : HasFFI {
|
||||
#[inline]
|
||||
/// Given a Servo-side reference, converts it to an
|
||||
/// FFI-safe reference which can be passed to Gecko
|
||||
///
|
||||
/// &ServoType -> &GeckoType
|
||||
fn as_ffi(&self) -> &Self::FFIType {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
#[inline]
|
||||
/// Given a Servo-side mutable reference, converts it to an
|
||||
/// FFI-safe mutable reference which can be passed to Gecko
|
||||
///
|
||||
/// &mut ServoType -> &mut GeckoType
|
||||
fn as_ffi_mut(&mut self) -> &mut Self::FFIType {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
#[inline]
|
||||
/// Given an FFI-safe reference obtained from Gecko
|
||||
/// converts it to a Servo-side reference
|
||||
///
|
||||
/// &GeckoType -> &ServoType
|
||||
fn from_ffi(ffi: &Self::FFIType) -> &Self {
|
||||
unsafe { transmute(ffi) }
|
||||
}
|
||||
#[inline]
|
||||
/// Given an FFI-safe mutable reference obtained from Gecko
|
||||
/// converts it to a Servo-side mutable reference
|
||||
///
|
||||
/// &mut GeckoType -> &mut ServoType
|
||||
fn from_ffi_mut(ffi: &mut Self::FFIType) -> &mut Self {
|
||||
unsafe { transmute(ffi) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates that the given Servo type is passed over FFI
|
||||
/// as a Box
|
||||
pub unsafe trait HasBoxFFI : HasSimpleFFI {
|
||||
#[inline]
|
||||
fn into_ffi(self: Box<Self>) -> Owned<Self::FFIType> {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait for conversions between FFI Strong/Borrowed types and Arcs
|
||||
///
|
||||
/// Should be implemented by types which are passed over FFI as Arcs
|
||||
/// via Strong and Borrowed
|
||||
///
|
||||
/// In this case, the FFIType is the rough equivalent of ArcInner<Self>
|
||||
pub unsafe trait HasArcFFI : HasFFI {
|
||||
// these methods can't be on Borrowed because it leads to an unspecified
|
||||
// impl parameter
|
||||
/// Artificially increments the refcount of a (possibly null) borrowed Arc over FFI.
|
||||
unsafe fn addref_opt(ptr: Borrowed<Self::FFIType>) {
|
||||
forget(ptr.as_arc_opt::<Self>().clone())
|
||||
}
|
||||
|
||||
/// Given a (possibly null) borrowed FFI reference, decrements the refcount.
|
||||
/// Unsafe since it doesn't consume the backing Arc. Run it only when you
|
||||
/// know that a strong reference to the backing Arc is disappearing
|
||||
/// (usually on the C++ side) without running the Arc destructor.
|
||||
unsafe fn release_opt(ptr: Borrowed<Self::FFIType>) {
|
||||
if let Some(arc) = ptr.as_arc_opt::<Self>() {
|
||||
let _: Arc<_> = ptr::read(arc as *const Arc<_>);
|
||||
}
|
||||
}
|
||||
|
||||
/// Artificially increments the refcount of a borrowed Arc over FFI.
|
||||
unsafe fn addref(ptr: &Self::FFIType) {
|
||||
forget(Self::as_arc(&ptr).clone())
|
||||
}
|
||||
|
||||
/// Given a non-null borrowed FFI reference, decrements the refcount.
|
||||
/// Unsafe since it doesn't consume the backing Arc. Run it only when you
|
||||
/// know that a strong reference to the backing Arc is disappearing
|
||||
/// (usually on the C++ side) without running the Arc destructor.
|
||||
unsafe fn release(ptr: &Self::FFIType) {
|
||||
let _: Arc<_> = ptr::read(Self::as_arc(&ptr) as *const Arc<_>);
|
||||
}
|
||||
#[inline]
|
||||
/// Converts a borrowed FFI reference to a borrowed Arc.
|
||||
///
|
||||
/// &GeckoType -> &Arc<ServoType>
|
||||
fn as_arc<'a>(ptr: &'a &Self::FFIType) -> &'a Arc<Self> {
|
||||
debug_assert!(!(ptr as *const _).is_null());
|
||||
unsafe {
|
||||
transmute::<&&Self::FFIType, &Arc<Self>>(ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
/// Gecko-FFI-safe borrowed type
|
||||
/// This can be null.
|
||||
pub struct Borrowed<'a, T: 'a> {
|
||||
ptr: *const T,
|
||||
_marker: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
/// Gecko-FFI-safe mutably borrowed type
|
||||
/// This can be null.
|
||||
pub struct BorrowedMut<'a, T: 'a> {
|
||||
ptr: *mut T,
|
||||
_marker: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
// manual impls because derive doesn't realize that `T: Clone` isn't necessary
|
||||
impl<'a, T> Copy for Borrowed<'a, T> {}
|
||||
|
||||
impl<'a, T> Clone for Borrowed<'a, T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
|
||||
impl<'a, T> Borrowed<'a, T> {
|
||||
#[inline]
|
||||
pub fn is_null(self) -> bool {
|
||||
self.ptr == ptr::null()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Like Deref, but gives an Option
|
||||
pub fn borrow_opt(self) -> Option<&'a T> {
|
||||
if self.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { &*self.ptr })
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Borrowed<GeckoType> -> Option<&Arc<ServoType>>
|
||||
pub fn as_arc_opt<U>(&self) -> Option<&Arc<U>> where U: HasArcFFI<FFIType = T> {
|
||||
unsafe {
|
||||
if self.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(transmute::<&Borrowed<_>, &Arc<_>>(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Converts a borrowed FFI reference to a borrowed Arc.
|
||||
/// Panics on null.
|
||||
///
|
||||
/// &Borrowed<GeckoType> -> &Arc<ServoType>
|
||||
pub fn as_arc<U>(&self) -> &Arc<U> where U: HasArcFFI<FFIType = T> {
|
||||
self.as_arc_opt().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Borrowed<ServoType> -> Borrowed<GeckoType>
|
||||
pub fn as_ffi(self) -> Borrowed<'a, <Self as HasFFI>::FFIType> where Self: HasSimpleFFI {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Borrowed<GeckoType> -> Borrowed<ServoType>
|
||||
pub fn from_ffi<U>(self) -> Borrowed<'a, U> where U: HasSimpleFFI<FFIType = T> {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Borrowed<GeckoType> -> &ServoType
|
||||
pub fn as_servo_ref<U>(self) -> Option<&'a U> where U: HasSimpleFFI<FFIType = T> {
|
||||
self.borrow_opt().map(HasSimpleFFI::from_ffi)
|
||||
}
|
||||
|
||||
pub fn null() -> Borrowed<'static, T> {
|
||||
Borrowed {
|
||||
ptr: ptr::null_mut(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> BorrowedMut<'a, T> {
|
||||
#[inline]
|
||||
/// Like DerefMut, but gives an Option
|
||||
pub fn borrow_mut_opt(self) -> Option<&'a mut T> {
|
||||
// We have two choices for the signature here, it can either be
|
||||
// Self -> Option<&'a mut T> or
|
||||
// &'b mut Self -> Option<'b mut T>
|
||||
// The former consumes the BorrowedMut (which isn't Copy),
|
||||
// which can be annoying. The latter only temporarily
|
||||
// borrows it, so the return value can't exit the scope
|
||||
// even if Self has a longer lifetime ('a)
|
||||
//
|
||||
// This is basically the implicit "reborrow" pattern used with &mut
|
||||
// not cleanly translating to our custom types.
|
||||
|
||||
// I've chosen the former solution -- you can manually convert back
|
||||
// if you need to reuse the BorrowedMut.
|
||||
if self.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { &mut *self.ptr })
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// BorrowedMut<GeckoType> -> &mut ServoType
|
||||
pub fn as_servo_mut_ref<U>(self) -> Option<&'a mut U> where U: HasSimpleFFI<FFIType = T> {
|
||||
self.borrow_mut_opt().map(HasSimpleFFI::from_ffi_mut)
|
||||
}
|
||||
|
||||
pub fn null_mut() -> BorrowedMut<'static, T> {
|
||||
BorrowedMut {
|
||||
ptr: ptr::null_mut(),
|
||||
_marker: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// technically not how we're supposed to use
|
||||
// Deref, but that's a minor style issue
|
||||
impl<'a, T> Deref for BorrowedMut<'a, T> {
|
||||
type Target = Borrowed<'a, T>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
/// Gecko-FFI-safe Arc (T is an ArcInner).
|
||||
/// This can be null.
|
||||
/// Leaks on drop. Please don't drop this.
|
||||
/// TODO: Add destructor bomb once drop flags are gone
|
||||
pub struct Strong<T> {
|
||||
ptr: *const T,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Strong<T> {
|
||||
#[inline]
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ptr == ptr::null()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Given a non-null strong FFI reference,
|
||||
/// converts it into a servo-side Arc
|
||||
/// Panics on null.
|
||||
///
|
||||
/// Strong<GeckoType> -> Arc<ServoType>
|
||||
pub fn into_arc<U>(self) -> Arc<U> where U: HasArcFFI<FFIType = T> {
|
||||
self.into_arc_opt().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Given a strong FFI reference,
|
||||
/// converts it into a servo-side Arc
|
||||
/// Returns None on null.
|
||||
///
|
||||
/// Strong<GeckoType> -> Arc<ServoType>
|
||||
pub fn into_arc_opt<U>(self) -> Option<Arc<U>> where U: HasArcFFI<FFIType = T> {
|
||||
if self.is_null() {
|
||||
None
|
||||
} else {
|
||||
unsafe { Some(transmute(self)) }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Produces a null strong FFI reference
|
||||
pub fn null() -> Self {
|
||||
unsafe { transmute(ptr::null::<T>()) }
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe trait FFIArcHelpers {
|
||||
type Inner: HasArcFFI;
|
||||
/// Converts an Arc into a strong FFI reference.
|
||||
///
|
||||
/// Arc<ServoType> -> Strong<GeckoType>
|
||||
fn into_strong(self) -> Strong<<Self::Inner as HasFFI>::FFIType>;
|
||||
/// Produces a (nullable) borrowed FFI reference by borrowing an Arc.
|
||||
///
|
||||
/// &Arc<ServoType> -> Borrowed<GeckoType>
|
||||
fn as_borrowed_opt(&self) -> Borrowed<<Self::Inner as HasFFI>::FFIType>;
|
||||
/// Produces a borrowed FFI reference by borrowing an Arc.
|
||||
///
|
||||
/// &Arc<ServoType> -> &GeckoType
|
||||
fn as_borrowed(&self) -> &<Self::Inner as HasFFI>::FFIType;
|
||||
}
|
||||
|
||||
unsafe impl<T: HasArcFFI> FFIArcHelpers for Arc<T> {
|
||||
type Inner = T;
|
||||
#[inline]
|
||||
fn into_strong(self) -> Strong<T::FFIType> {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
#[inline]
|
||||
fn as_borrowed_opt(&self) -> Borrowed<T::FFIType> {
|
||||
let borrowedptr = self as *const Arc<T> as *const Borrowed<T::FFIType>;
|
||||
unsafe { ptr::read(borrowedptr) }
|
||||
}
|
||||
#[inline]
|
||||
fn as_borrowed(&self) -> &T::FFIType {
|
||||
let borrowedptr = self as *const Arc<T> as *const & T::FFIType;
|
||||
unsafe { ptr::read(borrowedptr) }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
/// Gecko-FFI-safe owned pointer
|
||||
/// Cannot be null
|
||||
/// Leaks on drop. Please don't drop this.
|
||||
pub struct Owned<T> {
|
||||
ptr: *mut T,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Owned<T> {
|
||||
/// Owned<GeckoType> -> Box<ServoType>
|
||||
pub fn into_box<U>(self) -> Box<T> where U: HasBoxFFI<FFIType = T> {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
pub fn maybe(self) -> OwnedOrNull<T> {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Owned<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for Owned<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
/// Gecko-FFI-safe owned pointer
|
||||
/// Can be null
|
||||
pub struct OwnedOrNull<T> {
|
||||
ptr: *mut T,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> OwnedOrNull<T> {
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.ptr == ptr::null_mut()
|
||||
}
|
||||
/// OwnedOrNull<GeckoType> -> Option<Box<ServoType>>
|
||||
pub fn into_box_opt<U>(self) -> Option<Box<T>> where U: HasBoxFFI<FFIType = T> {
|
||||
if self.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { transmute(self) })
|
||||
}
|
||||
}
|
||||
|
||||
/// OwnedOrNull<GeckoType> -> Option<Owned<GeckoType>>
|
||||
pub fn into_owned_opt(self) -> Option<Owned<T>> {
|
||||
if self.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { transmute(self) })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow(&self) -> Borrowed<T> {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
|
||||
pub fn borrow_mut(&self) -> BorrowedMut<T> {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
}
|
17248
components/style/gecko_string_cache/atom_macro.rs
Normal file
17248
components/style/gecko_string_cache/atom_macro.rs
Normal file
File diff suppressed because it is too large
Load diff
310
components/style/gecko_string_cache/mod.rs
Normal file
310
components/style/gecko_string_cache/mod.rs
Normal file
|
@ -0,0 +1,310 @@
|
|||
/* 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/. */
|
||||
|
||||
use gecko_bindings::bindings::Gecko_AddRefAtom;
|
||||
use gecko_bindings::bindings::Gecko_Atomize;
|
||||
use gecko_bindings::bindings::Gecko_ReleaseAtom;
|
||||
use gecko_bindings::structs::nsIAtom;
|
||||
use heapsize::HeapSizeOf;
|
||||
use selectors::bloom::BloomHash;
|
||||
use selectors::parser::FromCowStr;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::{Cow, Borrow};
|
||||
use std::char::{self, DecodeUtf16};
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter::Cloned;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::slice;
|
||||
|
||||
#[macro_use]
|
||||
#[allow(improper_ctypes)]
|
||||
pub mod atom_macro;
|
||||
#[macro_use]
|
||||
pub mod namespace;
|
||||
|
||||
pub use string_cache::namespace::{Namespace, WeakNamespace};
|
||||
|
||||
/// A strong reference to a Gecko atom.
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct Atom(*mut WeakAtom);
|
||||
|
||||
/// An atom *without* a strong reference.
|
||||
///
|
||||
/// Only usable as `&'a WeakAtom`,
|
||||
/// where `'a` is the lifetime of something that holds a strong reference to that atom.
|
||||
pub struct WeakAtom(nsIAtom);
|
||||
|
||||
pub type BorrowedAtom<'a> = &'a WeakAtom;
|
||||
|
||||
impl Deref for Atom {
|
||||
type Target = WeakAtom;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &WeakAtom {
|
||||
unsafe {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<WeakAtom> for Atom {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &WeakAtom {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for WeakAtom {}
|
||||
impl PartialEq for WeakAtom {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let weak: *const WeakAtom = self;
|
||||
let other: *const WeakAtom = other;
|
||||
weak == other
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Atom {}
|
||||
unsafe impl Sync for Atom {}
|
||||
unsafe impl Sync for WeakAtom {}
|
||||
|
||||
impl WeakAtom {
|
||||
#[inline]
|
||||
pub unsafe fn new<'a>(atom: *mut nsIAtom) -> &'a mut Self {
|
||||
&mut *(atom as *mut WeakAtom)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn clone(&self) -> Atom {
|
||||
Atom::from(self.as_ptr())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_hash(&self) -> u32 {
|
||||
self.0.mHash
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u16] {
|
||||
unsafe {
|
||||
slice::from_raw_parts((*self.as_ptr()).mString, self.len() as usize)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: don't expose this, since it's slow, and easy to be misused.
|
||||
fn chars(&self) -> DecodeUtf16<Cloned<slice::Iter<u16>>> {
|
||||
char::decode_utf16(self.as_slice().iter().cloned())
|
||||
}
|
||||
|
||||
pub fn with_str<F, Output>(&self, cb: F) -> Output
|
||||
where F: FnOnce(&str) -> Output
|
||||
{
|
||||
// FIXME(bholley): We should measure whether it makes more sense to
|
||||
// cache the UTF-8 version in the Gecko atom table somehow.
|
||||
let owned = String::from_utf16(self.as_slice()).unwrap();
|
||||
cb(&owned)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn eq_str_ignore_ascii_case(&self, s: &str) -> bool {
|
||||
self.chars().map(|r| match r {
|
||||
Ok(c) => c.to_ascii_lowercase() as u32,
|
||||
Err(e) => e.unpaired_surrogate() as u32,
|
||||
}).eq(s.chars().map(|c| c.to_ascii_lowercase() as u32))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_string(&self) -> String {
|
||||
String::from_utf16(self.as_slice()).unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_static(&self) -> bool {
|
||||
unsafe {
|
||||
(*self.as_ptr()).mIsStatic() != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> u32 {
|
||||
unsafe {
|
||||
(*self.as_ptr()).mLength()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *mut nsIAtom {
|
||||
let const_ptr: *const nsIAtom = &self.0;
|
||||
const_ptr as *mut nsIAtom
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for WeakAtom {
|
||||
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(w, "Gecko WeakAtom({:p}, {})", self, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for WeakAtom {
|
||||
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
||||
for c in self.chars() {
|
||||
try!(write!(w, "{}", c.unwrap_or(char::REPLACEMENT_CHARACTER)))
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Atom {
|
||||
pub unsafe fn with<F>(ptr: *mut nsIAtom, callback: &mut F) where F: FnMut(&Atom) {
|
||||
let atom = Atom(WeakAtom::new(ptr));
|
||||
callback(&atom);
|
||||
mem::forget(atom);
|
||||
}
|
||||
|
||||
/// Creates an atom from an static atom pointer without checking in release
|
||||
/// builds.
|
||||
///
|
||||
/// Right now it's only used by the atom macro, and ideally it should keep
|
||||
/// that way, now we have sugar for is_static, creating atoms using
|
||||
/// Atom::from should involve almost no overhead.
|
||||
#[inline]
|
||||
unsafe fn from_static(ptr: *mut nsIAtom) -> Self {
|
||||
let atom = Atom(ptr as *mut WeakAtom);
|
||||
debug_assert!(atom.is_static(),
|
||||
"Called from_static for a non-static atom!");
|
||||
atom
|
||||
}
|
||||
}
|
||||
|
||||
impl BloomHash for Atom {
|
||||
#[inline]
|
||||
fn bloom_hash(&self) -> u32 {
|
||||
self.get_hash()
|
||||
}
|
||||
}
|
||||
|
||||
impl BloomHash for WeakAtom {
|
||||
#[inline]
|
||||
fn bloom_hash(&self) -> u32 {
|
||||
self.get_hash()
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Atom {
|
||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
||||
state.write_u32(self.get_hash());
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for WeakAtom {
|
||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
||||
state.write_u32(self.get_hash());
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Atom {
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> Atom {
|
||||
Atom::from(self.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Atom {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
if !self.is_static() {
|
||||
unsafe {
|
||||
Gecko_ReleaseAtom(self.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Atom {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
atom!("")
|
||||
}
|
||||
}
|
||||
|
||||
impl HeapSizeOf for Atom {
|
||||
fn heap_size_of_children(&self) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Atom {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
|
||||
self.with_str(|s| s.serialize(serializer))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize for Atom {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Atom, D::Error> where D: Deserializer {
|
||||
let string: String = try!(Deserialize::deserialize(deserializer));
|
||||
Ok(Atom::from(&*string))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Atom {
|
||||
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(w, "Gecko Atom({:p}, {})", self.0, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Atom {
|
||||
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
||||
unsafe {
|
||||
(&*self.0).fmt(w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Atom {
|
||||
#[inline]
|
||||
fn from(string: &str) -> Atom {
|
||||
debug_assert!(string.len() <= u32::max_value() as usize);
|
||||
unsafe {
|
||||
Atom(WeakAtom::new(
|
||||
Gecko_Atomize(string.as_ptr() as *const _, string.len() as u32)
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Cow<'a, str>> for Atom {
|
||||
#[inline]
|
||||
fn from(string: Cow<'a, str>) -> Atom {
|
||||
Atom::from(&*string)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromCowStr for Atom {
|
||||
#[inline]
|
||||
fn from_cow_str(string: Cow<str>) -> Atom {
|
||||
Atom::from(&*string)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Atom {
|
||||
#[inline]
|
||||
fn from(string: String) -> Atom {
|
||||
Atom::from(&*string)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<*mut nsIAtom> for Atom {
|
||||
#[inline]
|
||||
fn from(ptr: *mut nsIAtom) -> Atom {
|
||||
debug_assert!(!ptr.is_null());
|
||||
unsafe {
|
||||
if (*ptr).mIsStatic() == 0 {
|
||||
Gecko_AddRefAtom(ptr);
|
||||
}
|
||||
Atom(WeakAtom::new(ptr))
|
||||
}
|
||||
}
|
||||
}
|
80
components/style/gecko_string_cache/namespace.rs
Normal file
80
components/style/gecko_string_cache/namespace.rs
Normal file
|
@ -0,0 +1,80 @@
|
|||
/* 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/. */
|
||||
|
||||
use string_cache::{Atom, WeakAtom};
|
||||
use gecko_bindings::structs::nsIAtom;
|
||||
use selectors::bloom::BloomHash;
|
||||
use std::borrow::Borrow;
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! ns {
|
||||
() => { $crate::string_cache::Namespace(atom!("")) }
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Default, Hash)]
|
||||
pub struct Namespace(pub Atom);
|
||||
pub struct WeakNamespace(WeakAtom);
|
||||
|
||||
impl Deref for Namespace {
|
||||
type Target = WeakNamespace;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &WeakNamespace {
|
||||
let weak: *const WeakAtom = &*self.0;
|
||||
unsafe {
|
||||
&*(weak as *const WeakNamespace)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Namespace {
|
||||
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.0.fmt(w)
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<WeakNamespace> for Namespace {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &WeakNamespace {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl WeakNamespace {
|
||||
#[inline]
|
||||
pub unsafe fn new<'a>(atom: *mut nsIAtom) -> &'a Self {
|
||||
&*(atom as *const WeakNamespace)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn clone(&self) -> Namespace {
|
||||
Namespace(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for WeakNamespace {}
|
||||
impl PartialEq for WeakNamespace {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let weak: *const WeakNamespace = self;
|
||||
let other: *const WeakNamespace = other;
|
||||
weak == other
|
||||
}
|
||||
}
|
||||
|
||||
impl BloomHash for Namespace {
|
||||
#[inline]
|
||||
fn bloom_hash(&self) -> u32 {
|
||||
self.0.get_hash()
|
||||
}
|
||||
}
|
||||
|
||||
impl BloomHash for WeakNamespace {
|
||||
#[inline]
|
||||
fn bloom_hash(&self) -> u32 {
|
||||
self.0.get_hash()
|
||||
}
|
||||
}
|
|
@ -38,6 +38,8 @@ extern crate app_units;
|
|||
#[allow(unused_extern_crates)]
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
#[macro_use] #[no_link]
|
||||
extern crate cfg_if;
|
||||
extern crate core;
|
||||
#[macro_use]
|
||||
extern crate cssparser;
|
||||
|
@ -45,9 +47,7 @@ extern crate deque;
|
|||
extern crate encoding;
|
||||
extern crate euclid;
|
||||
extern crate fnv;
|
||||
#[cfg(feature = "gecko")] extern crate gecko_bindings;
|
||||
#[cfg(feature = "gecko")] #[macro_use] extern crate gecko_string_cache as string_cache;
|
||||
#[cfg(feature = "servo")] extern crate heapsize;
|
||||
extern crate heapsize;
|
||||
#[allow(unused_extern_crates)]
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
@ -63,7 +63,7 @@ extern crate quickersort;
|
|||
extern crate rand;
|
||||
extern crate rustc_serialize;
|
||||
extern crate selectors;
|
||||
#[cfg(feature = "servo")] extern crate serde;
|
||||
extern crate serde;
|
||||
extern crate smallvec;
|
||||
#[cfg(feature = "servo")] #[macro_use] extern crate string_cache;
|
||||
#[macro_use]
|
||||
|
@ -72,6 +72,11 @@ extern crate time;
|
|||
extern crate url;
|
||||
extern crate util;
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
#[path = "./gecko_string_cache/mod.rs"]
|
||||
#[allow(unsafe_code)]
|
||||
#[macro_use] pub mod string_cache;
|
||||
|
||||
pub mod animation;
|
||||
pub mod attr;
|
||||
pub mod bezier;
|
||||
|
@ -86,6 +91,7 @@ pub mod element_state;
|
|||
pub mod error_reporting;
|
||||
pub mod font_face;
|
||||
#[cfg(feature = "gecko")] pub mod gecko_conversions;
|
||||
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko_bindings;
|
||||
#[cfg(feature = "gecko")] pub mod gecko_selector_impl;
|
||||
#[cfg(feature = "gecko")] pub mod gecko_values;
|
||||
pub mod keyframes;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue