diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 87306a3de382..de6d09ed1d92 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -408,28 +408,43 @@ Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult) JSObject* Element::WrapObject(JSContext *aCx, JS::Handle aGivenProto) { - JS::Rooted obj(aCx, nsINode::WrapObject(aCx, aGivenProto)); + JS::Rooted givenProto(aCx, aGivenProto); + JS::Rooted customProto(aCx); + + if (!givenProto) { + // Custom element prototype swizzling. + CustomElementData* data = GetCustomElementData(); + if (data) { + // If this is a registered custom element then fix the prototype. + nsDocument* document = static_cast(OwnerDoc()); + document->GetCustomPrototype(NodeInfo()->NamespaceID(), data->mType, &customProto); + if (customProto && + NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(customProto))) { + // Just go ahead and create with the right proto up front. Set + // customProto to null to flag that we don't need to do any post-facto + // proto fixups here. + givenProto = customProto; + customProto = nullptr; + } + } + } + + JS::Rooted obj(aCx, nsINode::WrapObject(aCx, givenProto)); if (!obj) { return nullptr; } - // Custom element prototype swizzling. - CustomElementData* data = GetCustomElementData(); - if (obj && data) { - // If this is a registered custom element then fix the prototype. - nsDocument* document = static_cast(OwnerDoc()); - JS::Rooted prototype(aCx); - document->GetCustomPrototype(NodeInfo()->NamespaceID(), data->mType, &prototype); - if (prototype) { - // We want to set the custom prototype in the compartment where it was - // registered. In the case that |obj| and |prototype| are in different - // compartments, this will set the prototype on the |obj|'s wrapper and - // thus only visible in the wrapper's compartment. - JSAutoCompartment ac(aCx, prototype); - if (!JS_WrapObject(aCx, &obj) || !JS_SetPrototype(aCx, obj, prototype)) { - dom::Throw(aCx, NS_ERROR_FAILURE); - return nullptr; - } + if (customProto) { + // We want to set the custom prototype in the compartment where it was + // registered. In the case that |obj| and |prototype| are in different + // compartments, this will set the prototype on the |obj|'s wrapper and + // thus only visible in the wrapper's compartment, since we know obj's + // principal does not subsume customProto's in this case. + JSAutoCompartment ac(aCx, customProto); + JS::Rooted wrappedObj(aCx, obj); + if (!JS_WrapObject(aCx, &wrappedObj) || + !JS_SetPrototype(aCx, wrappedObj, customProto)) { + return nullptr; } }