Bug 1299363 - Part 2: Allow prototype swizzling in html constructor. r=bz
authorEdgar Chen <echen@mozilla.com>
Fri, 17 Feb 2017 18:33:44 +0800
changeset 645785 0198da9fb1ba5abd8218b12b3b9377c50fb33729
parent 645784 f5cd0326e13535a051334c3ef97dd4847f8dc24b
child 645786 acdd9706f32dea1687f5c6bec3059df8f704a56e
push id73882
push userbmo:bechen@mozilla.com
push dateMon, 14 Aug 2017 07:50:30 +0000
reviewersbz
bugs1299363
milestone57.0a1
Bug 1299363 - Part 2: Allow prototype swizzling in html constructor. r=bz MozReview-Commit-ID: KGVfbAxpbfq
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -3558,17 +3558,17 @@ GetCustomElementReactionsStack(JS::Handl
   }
 
   return docGroup->CustomElementReactionsStack();
 }
 
 // https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
 already_AddRefed<nsGenericHTMLElement>
 CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
-                  ErrorResult& aRv)
+                  JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv)
 {
   // Step 1.
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
@@ -3693,17 +3693,33 @@ CreateHTMLElement(const GlobalObject& aG
   RefPtr<nsGenericHTMLElement>& element = constructionStack.LastElement();
 
   // Step 10.
   if (element == ALEADY_CONSTRUCTED_MARKER) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
-  // Step 11 is in the code output by CGClassConstructor.
+  // Step 11.
+  // Do prototype swizzling for upgrading a custom element here, for cases when
+  // we have a reflector already.  If we don't have one yet, our caller will
+  // create it with the right proto (by calling DoGetOrCreateDOMReflector with
+  // that proto).
+  JS::Rooted<JSObject*> reflector(cx, element->GetWrapper());
+  if (reflector) {
+    // reflector might be in different compartment.
+    JSAutoCompartment ac(cx, reflector);
+    JS::Rooted<JSObject*> givenProto(cx, aGivenProto);
+    if (!JS_WrapObject(cx, &givenProto) ||
+        !JS_SetPrototype(cx, reflector, givenProto)) {
+      aRv.NoteJSContextException(cx);
+      return nullptr;
+    }
+  }
+
   // Step 12 and Step 13.
   return element.forget();
 }
 
 #ifdef DEBUG
 namespace binding_detail {
 void
 AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3368,17 +3368,17 @@ GetDesiredProto(JSContext* aCx, const JS
 // (e.g. because it's not a Window global).
 CustomElementReactionsStack*
 GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj);
 // This function is expected to be called from the constructor function for an
 // HTML element interface; the global/callargs need to be whatever was passed to
 // that constructor function.
 already_AddRefed<nsGenericHTMLElement>
 CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
-                  ErrorResult& aRv);
+                  JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv);
 
 void
 SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
                              UseCounter aUseCounter);
 
 // Warnings
 void
 DeprecationWarning(JSContext* aCx, JSObject* aObject,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -7704,17 +7704,17 @@ class CGPerSignatureCall(CGThing):
                       return false;
                     }
 
                     """)))
 
             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
         # attributes. Also, JSContext is not needed for the static case
         # since GlobalObject already contains the context.
         needsCx = needCx(returnType, arguments, self.extendedAttributes,
                          not descriptor.interface.isJSImplemented(), static)
         if needsCx: