mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-04 22:37:29 +09:00
Bug 1274159 - Part 2-2: Support HTMLConstructor WebIDL extended attribute for custom elements;
Tag UXP Issue #1344
This commit is contained in:
parent
64e957cc9b
commit
ed08e1aced
12 changed files with 534 additions and 30 deletions
|
|
@ -1747,6 +1747,71 @@ class CGClassConstructor(CGAbstractStaticMethod):
|
|||
else:
|
||||
ctorName = self.descriptor.interface.identifier.name
|
||||
|
||||
# [HTMLConstructor] for custom element
|
||||
# This needs to live in bindings code because it directly examines
|
||||
# newtarget and the callee function to do HTMLConstructor specific things.
|
||||
if self._ctor.isHTMLConstructor():
|
||||
htmlConstructorSanityCheck = dedent("""
|
||||
// The newTarget might be a cross-compartment wrapper. Get the underlying object
|
||||
// so we can do the spec's object-identity checks.
|
||||
JS::Rooted<JSObject*> newTarget(cx, js::CheckedUnwrap(&args.newTarget().toObject()));
|
||||
if (!newTarget) {
|
||||
return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
|
||||
}
|
||||
|
||||
// Step 2 of https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor.
|
||||
// Enter the compartment of our underlying newTarget object, so we end
|
||||
// up comparing to the constructor object for our interface from that global.
|
||||
{
|
||||
JSAutoCompartment ac(cx, newTarget);
|
||||
JS::Handle<JSObject*> constructor(GetConstructorObjectHandle(cx));
|
||||
if (!constructor) {
|
||||
return false;
|
||||
}
|
||||
if (newTarget == constructor) {
|
||||
return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR);
|
||||
}
|
||||
}
|
||||
|
||||
""")
|
||||
|
||||
# If we are unable to get desired prototype from newTarget, then we
|
||||
# fall back to the interface prototype object from newTarget's realm.
|
||||
htmlConstructorFallback = dedent("""
|
||||
if (!desiredProto) {
|
||||
// Step 7 of https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor.
|
||||
// This fallback behavior is designed to match analogous behavior for the
|
||||
// JavaScript built-ins. So we enter the compartment of our underlying
|
||||
// newTarget object and fall back to the prototype object from that global.
|
||||
// XXX The spec says to use GetFunctionRealm(), which is not actually
|
||||
// the same thing as what we have here (e.g. in the case of scripted callable proxies
|
||||
// whose target is not same-compartment with the proxy, or bound functions, etc).
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1317658
|
||||
{
|
||||
JSAutoCompartment ac(cx, newTarget);
|
||||
desiredProto = GetProtoObjectHandle(cx);
|
||||
if (!desiredProto) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// desiredProto is in the compartment of the underlying newTarget object.
|
||||
// Wrap it into the context compartment.
|
||||
if (!JS_WrapObject(cx, &desiredProto)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
""")
|
||||
else:
|
||||
htmlConstructorSanityCheck = ""
|
||||
htmlConstructorFallback = ""
|
||||
|
||||
|
||||
# If we're a constructor, "obj" may not be a function, so calling
|
||||
# XrayAwareCalleeGlobal() on it is not safe. Of course in the
|
||||
# constructor case either "obj" is an Xray or we're already in the
|
||||
# content compartment, not the Xray compartment, so just
|
||||
# constructing the GlobalObject from "obj" is fine.
|
||||
preamble = fill(
|
||||
"""
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
|
|
@ -1757,19 +1822,41 @@ class CGClassConstructor(CGAbstractStaticMethod):
|
|||
// Adding more relocations
|
||||
return ThrowConstructorWithoutNew(cx, "${ctorName}");
|
||||
}
|
||||
|
||||
GlobalObject global(cx, obj);
|
||||
if (global.Failed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$*{htmlConstructorSanityCheck}
|
||||
JS::Rooted<JSObject*> desiredProto(cx);
|
||||
if (!GetDesiredProto(cx, args, &desiredProto)) {
|
||||
return false;
|
||||
}
|
||||
$*{htmlConstructorFallback}
|
||||
""",
|
||||
chromeOnlyCheck=chromeOnlyCheck,
|
||||
ctorName=ctorName)
|
||||
ctorName=ctorName,
|
||||
htmlConstructorSanityCheck=htmlConstructorSanityCheck,
|
||||
htmlConstructorFallback=htmlConstructorFallback)
|
||||
|
||||
name = self._ctor.identifier.name
|
||||
nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
|
||||
callGenerator = CGMethodCall(nativeName, True, self.descriptor,
|
||||
self._ctor, isConstructor=True,
|
||||
constructorName=ctorName)
|
||||
if self._ctor.isHTMLConstructor():
|
||||
signatures = self._ctor.signatures()
|
||||
assert len(signatures) == 1
|
||||
# Given that HTMLConstructor takes no args, we can just codegen a
|
||||
# call to CreateHTMLElement() in BindingUtils which reuses the
|
||||
# factory thing in HTMLContentSink. Then we don't have to implement
|
||||
# Constructor on all the HTML elements.
|
||||
callGenerator = CGPerSignatureCall(signatures[0][0], signatures[0][1],
|
||||
"CreateHTMLElement", True,
|
||||
self.descriptor, self._ctor,
|
||||
isConstructor=True)
|
||||
else:
|
||||
name = self._ctor.identifier.name
|
||||
nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
|
||||
callGenerator = CGMethodCall(nativeName, True, self.descriptor,
|
||||
self._ctor, isConstructor=True,
|
||||
constructorName=ctorName)
|
||||
return preamble + "\n" + callGenerator.define()
|
||||
|
||||
|
||||
|
|
@ -7440,26 +7527,23 @@ class CGPerSignatureCall(CGThing):
|
|||
|
||||
argsPre = []
|
||||
if idlNode.isStatic():
|
||||
# If we're a constructor, "obj" may not be a function, so calling
|
||||
# XrayAwareCalleeGlobal() on it is not safe. Of course in the
|
||||
# constructor case either "obj" is an Xray or we're already in the
|
||||
# content compartment, not the Xray compartment, so just
|
||||
# constructing the GlobalObject from "obj" is fine.
|
||||
if isConstructor:
|
||||
objForGlobalObject = "obj"
|
||||
else:
|
||||
objForGlobalObject = "xpc::XrayAwareCalleeGlobal(obj)"
|
||||
cgThings.append(CGGeneric(fill(
|
||||
"""
|
||||
GlobalObject global(cx, ${obj});
|
||||
if (global.Failed()) {
|
||||
return false;
|
||||
}
|
||||
# If we're a constructor, the GlobalObject struct will be created in
|
||||
# CGClassConstructor.
|
||||
if not isConstructor:
|
||||
cgThings.append(CGGeneric(dedent(
|
||||
"""
|
||||
GlobalObject global(cx, xpc::XrayAwareCalleeGlobal(obj));
|
||||
if (global.Failed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
""")))
|
||||
|
||||
""",
|
||||
obj=objForGlobalObject)))
|
||||
argsPre.append("global")
|
||||
|
||||
if isConstructor and idlNode.isHTMLConstructor():
|
||||
argsPre.append("args")
|
||||
|
||||
# For JS-implemented interfaces we do not want to base the
|
||||
# needsCx decision on the types involved, just on our extended
|
||||
# attributes. Also, JSContext is not needed for the static case
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue