From 5222f6e9daa4cb74b404f769b23510b3d600efd9 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Thu, 2 Jan 2020 21:25:47 -0500 Subject: Bug 1274159 - Part 2-2: Support HTMLConstructor WebIDL extended attribute for custom elements; Tag UXP Issue #1344 --- dom/bindings/Codegen.py | 132 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 108 insertions(+), 24 deletions(-) (limited to 'dom/bindings/Codegen.py') diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 6b23e8225..676d91793 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -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 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 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 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() @@ -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 -- cgit v1.2.3 From 20799ce18c18ff1ad3125ad4e8a7a679b57a858f Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 4 Jan 2020 10:13:59 -0500 Subject: Bug 1309147 - Part 2: Add the name of 'this' value's JSObject* for codegen to generate CEReaction code. Tag UXP Issue #1344 --- dom/bindings/Codegen.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'dom/bindings/Codegen.py') diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 676d91793..6fd15ac90 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -7473,7 +7473,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 @@ -11069,7 +11069,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. -- cgit v1.2.3 From df23f78ad16b40c244f518dba28a8555d61bdd0c Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sat, 4 Jan 2020 10:28:38 -0500 Subject: Bug 1309147 - Part 3: Implement the support for CEReactions in Codegen. Tag UXP Issue #1344 --- dom/bindings/Codegen.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'dom/bindings/Codegen.py') diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 6fd15ac90..5bbf77bb6 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -7672,6 +7672,17 @@ class CGPerSignatureCall(CGThing): CGIfWrapper(CGList(xraySteps), "objIsXray")) + if (idlNode.getExtendedAttribute('CEReactions') is not None and + not getter): + cgThings.append(CGGeneric(fill( + """ + CustomElementReactionsStack* reactionsStack = GetCustomElementReactionsStack(${obj}); + Maybe ceReaction; + if (reactionsStack) { + ceReaction.emplace(reactionsStack); + } + """, obj=objectName))) + # 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. @@ -13840,12 +13851,18 @@ class CGBindingRoot(CGThing): iface = desc.interface return any(m.getExtendedAttribute("Deprecated") for m in iface.members + [iface]) + def descriptorHasCEReactions(desc): + iface = desc.interface + return any(m.getExtendedAttribute("CEReactions") for m in iface.members + [iface]) + bindingHeaders["nsIDocument.h"] = any( descriptorDeprecated(d) for d in descriptors) bindingHeaders["mozilla/Preferences.h"] = any( descriptorRequiresPreferences(d) for d in descriptors) bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any( d.concrete and d.proxy for d in descriptors) + bindingHeaders["mozilla/dom/CustomElementRegistry.h"] = any( + descriptorHasCEReactions(d) for d in descriptors) def descriptorHasChromeOnly(desc): ctor = desc.interface.ctor() -- cgit v1.2.3 From 3d44a0b7f022b9eb9c72042da2e76ac24278f496 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 5 Jan 2020 10:28:42 -0500 Subject: Bug 1299363 - Part 2: Allow prototype swizzling in html constructor. Tag UXP Issue #1344 --- dom/bindings/Codegen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dom/bindings/Codegen.py') diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 5bbf77bb6..730465fee 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -7542,7 +7542,7 @@ class CGPerSignatureCall(CGThing): argsPre.append("global") if isConstructor and idlNode.isHTMLConstructor(): - argsPre.append("args") + 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 -- cgit v1.2.3 From 8db81508a1ffe1c3873503a1cb2082d664714776 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Mon, 20 Jan 2020 20:14:59 -0500 Subject: Bug 1415761 - Catch the exception and rethrow it after invoking custom elements reactions; The spec was unclear on how CEReactions interact with thrown exceptions; see https://github.com/whatwg/html/issues/3217. The spec is now being clarified in https://github.com/whatwg/html/pull/3235. Tag UXP Issue #1344 --- dom/bindings/Codegen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dom/bindings/Codegen.py') diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 730465fee..8ee732cca 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -7679,7 +7679,7 @@ class CGPerSignatureCall(CGThing): CustomElementReactionsStack* reactionsStack = GetCustomElementReactionsStack(${obj}); Maybe ceReaction; if (reactionsStack) { - ceReaction.emplace(reactionsStack); + ceReaction.emplace(reactionsStack, cx); } """, obj=objectName))) -- cgit v1.2.3 From 07fe89e26f05d1cb078f008d0b5d6a5212e37296 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Sat, 8 Feb 2020 20:33:04 -0500 Subject: Directly assign PrimitiveConversions.h to the generated binding of KeyframeAnimationOptions. This is a hack to deal UnifiedBindings trying to deal with an incomplete codegen implementation so it was worked around with a hack back in Firefox 30-something. If we have anymore of this non-sense crop up as stuff is added or removed from DOM then extend this conditional. Least until something better comes along. --- dom/bindings/Codegen.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'dom/bindings/Codegen.py') diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 8ee732cca..8985863e8 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -1109,6 +1109,12 @@ class CGHeaders(CGWrapper): # Now find all the things we'll need as arguments because we # need to wrap or unwrap them. bindingHeaders = set() + + # KeyframeAnimationOptions.webidl is doing something VERY screwy and + # Unified Building really sucks so directly include this + if prefix == "KeyframeAnimationOptionsBinding": + bindingHeaders.add("mozilla/dom/PrimitiveConversions.h") + declareIncludes = set(declareIncludes) def addHeadersForType((t, dictionary)): -- cgit v1.2.3 From 010f37f47b9c15935a6113cd82e43f0673122016 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 17 Apr 2020 07:29:57 -0400 Subject: Bug 1422197 - Add fast path to get DocGroup in binding code for [CEReactions] Tag #1375 --- dom/bindings/Codegen.py | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) (limited to 'dom/bindings/Codegen.py') diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 8985863e8..c9a5e9f41 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -7680,14 +7680,14 @@ class CGPerSignatureCall(CGThing): if (idlNode.getExtendedAttribute('CEReactions') is not None and not getter): - cgThings.append(CGGeneric(fill( + cgThings.append(CGGeneric(dedent( """ - CustomElementReactionsStack* reactionsStack = GetCustomElementReactionsStack(${obj}); - Maybe ceReaction; - if (reactionsStack) { - ceReaction.emplace(reactionsStack, cx); + Maybe ceReaction; + DocGroup* docGroup = self->GetDocGroup(); + if (docGroup) { + ceReaction.emplace(docGroup->CustomElementReactionsStack(), cx); } - """, obj=objectName))) + """))) # If this is a method that was generated by a maplike/setlike # interface, use the maplike/setlike generator to fill in the body. @@ -13786,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: @@ -13857,18 +13859,15 @@ class CGBindingRoot(CGThing): iface = desc.interface return any(m.getExtendedAttribute("Deprecated") for m in iface.members + [iface]) - def descriptorHasCEReactions(desc): - iface = desc.interface - return any(m.getExtendedAttribute("CEReactions") for m in iface.members + [iface]) - bindingHeaders["nsIDocument.h"] = any( descriptorDeprecated(d) for d in descriptors) bindingHeaders["mozilla/Preferences.h"] = any( descriptorRequiresPreferences(d) for d in descriptors) bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any( d.concrete and d.proxy for d in descriptors) - bindingHeaders["mozilla/dom/CustomElementRegistry.h"] = any( - descriptorHasCEReactions(d) 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() @@ -14704,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", @@ -14724,6 +14729,9 @@ class CGBindingImplClass(CGClass): def getGetParentObjectBody(self): return None + def getGetDocGroupBody(self): + return None + def deps(self): return self._deps @@ -14863,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 @@ -15174,7 +15184,7 @@ class CGJSImplClass(CGBindingImplClass): private: RefPtr<${jsImplName}> mImpl; - nsCOMPtr mParent; + nsCOMPtr mParent; """, isupportsDecl=isupportsDecl, @@ -15253,6 +15263,16 @@ class CGJSImplClass(CGBindingImplClass): def getGetParentObjectBody(self): return "return mParent;\n" + def getGetDocGroupBody(self): + return dedent( + """ + nsCOMPtr 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 -- cgit v1.2.3