summaryrefslogtreecommitdiffstats
path: root/dom/bindings/Codegen.py
diff options
context:
space:
mode:
Diffstat (limited to 'dom/bindings/Codegen.py')
-rw-r--r--dom/bindings/Codegen.py176
1 files changed, 149 insertions, 27 deletions
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index e3cca63b6..c9a5e9f41 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1753,6 +1753,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);
@@ -1763,19 +1828,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)
-
- name = self._ctor.identifier.name
- nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
- callGenerator = CGMethodCall(nativeName, True, self.descriptor,
- self._ctor, isConstructor=True,
- constructorName=ctorName)
+ ctorName=ctorName,
+ htmlConstructorSanityCheck=htmlConstructorSanityCheck,
+ htmlConstructorFallback=htmlConstructorFallback)
+
+ 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()
@@ -7392,7 +7479,7 @@ class CGPerSignatureCall(CGThing):
def __init__(self, returnType, arguments, nativeMethodName, static,
descriptor, idlNode, argConversionStartsAt=0, getter=False,
setter=False, isConstructor=False, useCounterName=None,
- resultVar=None):
+ resultVar=None, objectName="obj"):
assert idlNode.isMethod() == (not getter and not setter)
assert idlNode.isAttr() == (getter or setter)
# Constructors are always static
@@ -7446,26 +7533,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.extend(["args", "desiredProto"])
+
# 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
@@ -7594,6 +7678,17 @@ class CGPerSignatureCall(CGThing):
CGIfWrapper(CGList(xraySteps),
"objIsXray"))
+ if (idlNode.getExtendedAttribute('CEReactions') is not None and
+ not getter):
+ cgThings.append(CGGeneric(dedent(
+ """
+ Maybe<AutoCEReaction> ceReaction;
+ DocGroup* docGroup = self->GetDocGroup();
+ if (docGroup) {
+ ceReaction.emplace(docGroup->CustomElementReactionsStack(), cx);
+ }
+ """)))
+
# If this is a method that was generated by a maplike/setlike
# interface, use the maplike/setlike generator to fill in the body.
# Otherwise, use CGCallGenerator to call the native method.
@@ -10991,7 +11086,8 @@ class CGProxySpecialOperation(CGPerSignatureCall):
# CGPerSignatureCall won't do any argument conversion of its own.
CGPerSignatureCall.__init__(self, returnType, arguments, nativeName,
False, descriptor, operation,
- len(arguments), resultVar=resultVar)
+ len(arguments), resultVar=resultVar,
+ objectName="proxy")
if operation.isSetter() or operation.isCreator():
# arguments[0] is the index or name of the item that we're setting.
@@ -13690,6 +13786,8 @@ class CGForwardDeclarations(CGWrapper):
builder.add(d.nativeType + "Atoms", isStruct=True)
for t in getTypesFromDescriptor(d):
builder.forwardDeclareForType(t, config)
+ if d.hasCEReactions():
+ builder.addInMozillaDom("DocGroup")
for d in dictionaries:
if len(d.members) > 0:
@@ -13767,6 +13865,9 @@ class CGBindingRoot(CGThing):
descriptorRequiresPreferences(d) for d in descriptors)
bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any(
d.concrete and d.proxy for d in descriptors)
+ hasCEReactions = any(d.hasCEReactions() for d in descriptors)
+ bindingHeaders["mozilla/dom/CustomElementRegistry.h"] = hasCEReactions
+ bindingHeaders["mozilla/dom/DocGroup.h"] = hasCEReactions
def descriptorHasChromeOnly(desc):
ctor = desc.interface.ctor()
@@ -14602,6 +14703,12 @@ class CGBindingImplClass(CGClass):
breakAfterReturnDecl=" ",
override=descriptor.wrapperCache,
body=self.getWrapObjectBody()))
+ if descriptor.hasCEReactions():
+ self.methodDecls.insert(0,
+ ClassMethod("GetDocGroup", "DocGroup*", [],
+ const=True,
+ breakAfterReturnDecl=" ",
+ body=self.getGetDocGroupBody()))
if wantGetParent:
self.methodDecls.insert(0,
ClassMethod("GetParentObject",
@@ -14622,6 +14729,9 @@ class CGBindingImplClass(CGClass):
def getGetParentObjectBody(self):
return None
+ def getGetDocGroupBody(self):
+ return None
+
def deps(self):
return self._deps
@@ -14761,6 +14871,8 @@ class CGExampleRoot(CGThing):
self.root = CGNamespace.build(["mozilla", "dom"], self.root)
builder = ForwardDeclarationBuilder()
+ if descriptor.hasCEReactions():
+ builder.addInMozillaDom("DocGroup")
for member in descriptor.interface.members:
if not member.isAttr() and not member.isMethod():
continue
@@ -15072,7 +15184,7 @@ class CGJSImplClass(CGBindingImplClass):
private:
RefPtr<${jsImplName}> mImpl;
- nsCOMPtr<nsISupports> mParent;
+ nsCOMPtr<nsIGlobalObject> mParent;
""",
isupportsDecl=isupportsDecl,
@@ -15151,6 +15263,16 @@ class CGJSImplClass(CGBindingImplClass):
def getGetParentObjectBody(self):
return "return mParent;\n"
+ def getGetDocGroupBody(self):
+ return dedent(
+ """
+ nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
+ if (!window) {
+ return nullptr;
+ }
+ return window->GetDocGroup();
+ """)
+
def getCreateFromExistingBody(self):
# XXXbz we could try to get parts of this (e.g. the argument
# conversions) auto-generated by somehow creating an IDLMethod and