From 88ca948d77fbe96e77cb3074a83150e464c3f3bd Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 12 Jun 2013 08:55:00 +0200 Subject: [PATCH] Bug 877277 - Move the document.all getter into WebIDL; r=smaug --- content/html/document/src/nsHTMLDocument.cpp | 73 ++++++-- content/html/document/src/nsHTMLDocument.h | 22 ++- dom/base/nsDOMClassInfo.cpp | 177 +------------------ dom/base/nsDOMClassInfo.h | 13 +- dom/webidl/HTMLDocument.webidl | 3 + 5 files changed, 84 insertions(+), 204 deletions(-) diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 246d7e9dac26..f8aea3a93b27 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -201,18 +201,44 @@ nsHTMLDocument::nsHTMLDocument() SetIsDOMBinding(); } +nsHTMLDocument::~nsHTMLDocument() +{ + mAll = nullptr; + NS_DROP_JS_OBJECTS(this, nsHTMLDocument); +} -NS_IMPL_CYCLE_COLLECTION_INHERITED_10(nsHTMLDocument, nsDocument, - mImages, - mApplets, - mEmbeds, - mLinks, - mAnchors, - mScripts, - mForms, - mFormControls, - mWyciwygChannel, - mMidasCommandManager) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLDocument, nsDocument) + NS_ASSERTION(!nsCCUncollectableMarker::InGeneration(cb, tmp->GetMarkedCCGeneration()), + "Shouldn't traverse nsHTMLDocument!"); + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImages) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplets) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEmbeds) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLinks) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchors) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScripts) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mForms) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFormControls) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWyciwygChannel) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMidasCommandManager) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLDocument, nsDocument) + tmp->mAll = nullptr; + NS_IMPL_CYCLE_COLLECTION_UNLINK(mImages) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplets) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mEmbeds) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mLinks) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchors) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mScripts) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mForms) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mFormControls) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mWyciwygChannel) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mMidasCommandManager) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsHTMLDocument, nsDocument) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAll) +NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_ADDREF_INHERITED(nsHTMLDocument, nsDocument) NS_IMPL_RELEASE_INHERITED(nsHTMLDocument, nsDocument) @@ -2310,10 +2336,6 @@ nsHTMLDocument::NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound, nsISupports* supp = ResolveName(aName, &cache); if (!supp) { aFound = false; - if (aName.EqualsLiteral("all")) { - JS::Rooted obj(cx, GetWrapper()); - rv = nsHTMLDocumentSH::TryResolveAll(cx, this, obj); - } return nullptr; } @@ -2698,6 +2720,27 @@ nsHTMLDocument::GetDocumentAllResult(const nsAString& aID, return cont; } +JSObject* +nsHTMLDocument::GetAll(JSContext* aCx, ErrorResult& aRv) +{ + if (!mAll) { + mAll = JS_NewObject(aCx, &sHTMLDocumentAllClass, nullptr, + JS_GetGlobalForObject(aCx, GetWrapper())); + if (!mAll) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return nullptr; + } + + // Make the JSObject hold a reference to this. + JS_SetPrivate(mAll, static_cast(this)); + NS_ADDREF_THIS(); + + NS_HOLD_JS_OBJECTS(this, nsHTMLDocument); + } + + return mAll; +} + static void NotifyEditableStateChange(nsINode *aNode, nsIDocument *aDocument) { diff --git a/content/html/document/src/nsHTMLDocument.h b/content/html/document/src/nsHTMLDocument.h index 1abd7fd9070e..a64834e37c8a 100644 --- a/content/html/document/src/nsHTMLDocument.h +++ b/content/html/document/src/nsHTMLDocument.h @@ -44,13 +44,14 @@ public: using nsDocument::GetPlugins; nsHTMLDocument(); + ~nsHTMLDocument(); virtual nsresult Init() MOZ_OVERRIDE; - NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) MOZ_OVERRIDE; - - NS_IMETHOD_(nsrefcnt) AddRef(void) MOZ_OVERRIDE; - NS_IMETHOD_(nsrefcnt) Release(void) MOZ_OVERRIDE; + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsHTMLDocument, + nsDocument) + // nsIDocument virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) MOZ_OVERRIDE; virtual void ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup, nsIPrincipal* aPrincipal) MOZ_OVERRIDE; @@ -69,9 +70,15 @@ public: virtual void StopDocumentLoad() MOZ_OVERRIDE; virtual void BeginLoad() MOZ_OVERRIDE; - virtual void EndLoad() MOZ_OVERRIDE; + virtual NS_HIDDEN_(void) Destroy() MOZ_OVERRIDE + { + mAll = nullptr; + nsDocument::Destroy(); + } + + // nsIHTMLDocument virtual void SetCompatibilityMode(nsCompatibility aMode) MOZ_OVERRIDE; virtual bool IsWriting() MOZ_OVERRIDE @@ -108,6 +115,7 @@ public: nsISupports *GetDocumentAllResult(const nsAString& aID, nsWrapperCache **aCache, nsresult *aResult); + JSObject* GetAll(JSContext* aCx, mozilla::ErrorResult& aRv); nsISupports* ResolveName(const nsAString& aName, nsWrapperCache **aCache); virtual already_AddRefed ResolveName(const nsAString& aName, @@ -155,8 +163,6 @@ public: void EndUpdate(nsUpdateType aUpdateType) MOZ_OVERRIDE; - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLDocument, nsDocument) - virtual nsresult SetEditingState(EditingState aState) MOZ_OVERRIDE; virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; @@ -294,6 +300,8 @@ protected: nsRefPtr mForms; nsRefPtr mFormControls; + JSObject* mAll; + /** # of forms in the document, synchronously set */ int32_t mNumForms; diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 0520158f276c..3d07beed449b 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -892,7 +892,6 @@ jsid nsDOMClassInfo::sTop_id = JSID_VOID; jsid nsDOMClassInfo::sDocument_id = JSID_VOID; jsid nsDOMClassInfo::sFrames_id = JSID_VOID; jsid nsDOMClassInfo::sSelf_id = JSID_VOID; -jsid nsDOMClassInfo::sAll_id = JSID_VOID; jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID; jsid nsDOMClassInfo::sURL_id = JSID_VOID; jsid nsDOMClassInfo::sOnload_id = JSID_VOID; @@ -1088,7 +1087,6 @@ nsDOMClassInfo::DefineStaticJSVals(JSContext *cx) SET_JSID_TO_STRING(sDocument_id, cx, "document"); SET_JSID_TO_STRING(sFrames_id, cx, "frames"); SET_JSID_TO_STRING(sSelf_id, cx, "self"); - SET_JSID_TO_STRING(sAll_id, cx, "all"); SET_JSID_TO_STRING(sWrappedJSObject_id, cx, "wrappedJSObject"); SET_JSID_TO_STRING(sURL_id, cx, "URL"); SET_JSID_TO_STRING(sOnload_id, cx, "onload"); @@ -2611,7 +2609,6 @@ nsDOMClassInfo::ShutDown() sDocument_id = JSID_VOID; sFrames_id = JSID_VOID; sSelf_id = JSID_VOID; - sAll_id = JSID_VOID; sWrappedJSObject_id = JSID_VOID; sOnload_id = JSID_VOID; sOnerror_id = JSID_VOID; @@ -2725,8 +2722,9 @@ ChildWindowGetter(JSContext *cx, JSHandleObject obj, JSHandleId id, static nsHTMLDocument* GetDocument(JSObject *obj) { + MOZ_ASSERT(js::GetObjectJSClass(obj) == &sHTMLDocumentAllClass); return static_cast( - static_cast(::JS_GetPrivate(obj))); + static_cast(JS_GetPrivate(obj))); } // static @@ -5625,9 +5623,9 @@ nsNamedArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, } -// HTMLDocument helper +// HTMLAllCollection -static JSClass sHTMLDocumentAllClass = { +JSClass sHTMLDocumentAllClass = { "HTML document.all class", JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_NEW_RESOLVE | JSCLASS_EMULATES_UNDEFINED | JSCLASS_HAS_RESERVED_SLOTS(1), @@ -5644,19 +5642,6 @@ static JSClass sHTMLDocumentAllClass = { }; -static JSClass sHTMLDocumentAllHelperClass = { - "HTML document.all helper class", - JSCLASS_NEW_RESOLVE, - JS_PropertyStub, /* addProperty */ - JS_DeletePropertyStub, /* delProperty */ - nsHTMLDocumentSH::DocumentAllHelperGetProperty, /* getProperty */ - JS_StrictPropertyStub, /* setProperty */ - JS_EnumerateStub, - (JSResolveOp)nsHTMLDocumentSH::DocumentAllHelperNewResolve, - JS_ConvertStub -}; - - // static JSBool nsHTMLDocumentSH::GetDocumentAllNodeList(JSContext *cx, @@ -5860,13 +5845,10 @@ nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JSHandleObject obj, JSHan return ok; } -// Finalize hook used by document related JS objects, but also by -// sGlobalScopePolluterClass! - void nsHTMLDocumentSH::ReleaseDocument(JSFreeOp *fop, JSObject *obj) { - nsIHTMLDocument *doc = static_cast(JS_GetPrivate(obj)); + nsIHTMLDocument* doc = GetDocument(obj); if (doc) { xpc::DeferredRelease(doc); } @@ -5916,155 +5898,6 @@ nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp) } -static inline bool -GetDocumentAllHelper(JSContext *cx, JS::Handle aObj, JSObject **result) -{ - JS::Rooted obj(cx, aObj); - while (obj && JS_GetClass(obj) != &sHTMLDocumentAllHelperClass) { - if (!::JS_GetPrototype(cx, obj, obj.address())) { - return false; - } - } - - *result = obj; - return true; -} - -JSBool -nsHTMLDocumentSH::DocumentAllHelperGetProperty(JSContext *cx, JSHandleObject obj, - JSHandleId id, JSMutableHandleValue vp) -{ - if (nsDOMClassInfo::sAll_id != id) { - return JS_TRUE; - } - - if (!vp.isObjectOrNull()) { - // First time through, create the collection, and set the - // document as its private nsISupports data. - nsresult rv; - nsCOMPtr doc = do_QueryWrapper(cx, obj, &rv); - if (NS_FAILED(rv)) { - xpc::Throw(cx, rv); - return JS_FALSE; - } - - JS::Rooted all(cx); - all = ::JS_NewObject(cx, &sHTMLDocumentAllClass, nullptr, - ::JS_GetGlobalForObject(cx, obj)); - if (!all) { - return JS_FALSE; - } - - // Let the JSObject take over ownership of doc. - ::JS_SetPrivate(all, doc.forget().get()); - - vp.setObject(*all); - } - - return JS_TRUE; -} - -JSBool -nsHTMLDocumentSH::DocumentAllHelperNewResolve(JSContext *cx, JSHandleObject obj, - JSHandleId id, unsigned flags, - JS::MutableHandle objp) -{ - if (nsDOMClassInfo::sAll_id == id) { - // document.all is resolved for the first time. Define it. - JS::Rooted helper(cx); - if (!GetDocumentAllHelper(cx, obj, helper.address())) { - return JS_FALSE; - } - - if (helper) { - if (!::JS_DefineProperty(cx, helper, "all", JSVAL_VOID, nullptr, nullptr, - JSPROP_ENUMERATE)) { - return JS_FALSE; - } - - objp.set(helper); - } - } - - return JS_TRUE; -} - - -static nsresult -ResolveAll(JSContext* cx, nsIDocument* doc, JS::Handle obj) -{ - JS::Rooted proto(cx); - if (!::JS_GetPrototype(cx, obj, proto.address())) { - return NS_ERROR_FAILURE; - } - - JS::Rooted helper(cx); - if (!GetDocumentAllHelper(cx, proto, helper.address())) { - return NS_ERROR_FAILURE; - } - - if (!::JS_GetPrototype(cx, helper ? helper : obj, proto.address())) { - return NS_ERROR_FAILURE; - } - - // Check if the property all is defined on obj's (or helper's - // if obj doesn't exist) prototype, if it is, don't expose our - // document.all helper. - - JSBool hasAll = JS_FALSE; - if (proto && !JS_HasProperty(cx, proto, "all", &hasAll)) { - return NS_ERROR_UNEXPECTED; - } - - if (hasAll && helper) { - // Our helper's prototype now has an "all" property, remove - // the helper out of the prototype chain to prevent - // shadowing of the now defined "all" property. - JS::Rooted tmp(cx, obj), tmpProto(cx, tmp); - - do { - tmp = tmpProto; - if (!::JS_GetPrototype(cx, tmp, tmpProto.address())) { - return NS_ERROR_UNEXPECTED; - } - } while (tmpProto != helper); - - ::JS_SetPrototype(cx, tmp, proto); - } - - // If we don't already have a helper and "all" isn't already defined on - // our prototype, create a helper. - if (!helper && !hasAll) { - if (!::JS_GetPrototype(cx, obj, proto.address())) { - return NS_ERROR_UNEXPECTED; - } - helper = ::JS_NewObject(cx, &sHTMLDocumentAllHelperClass, - proto, - ::JS_GetGlobalForObject(cx, obj)); - - if (!helper) { - return NS_ERROR_OUT_OF_MEMORY; - } - - // Insert the helper into our prototype chain. helper's prototype - // is already obj's current prototype. - if (!::JS_SetPrototype(cx, obj, helper)) { - xpc::Throw(cx, NS_ERROR_UNEXPECTED); - return NS_ERROR_UNEXPECTED; - } - } - - return NS_OK; -} - -nsresult -nsHTMLDocumentSH::TryResolveAll(JSContext* cx, nsHTMLDocument* doc, - JS::Handle obj) -{ - JSAutoCompartment ac(cx, obj); - return ResolveAll(cx, doc, obj); -} - // HTMLFormElement helper NS_IMETHODIMP diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h index 231cd7fc67b6..17006b2dc7b3 100644 --- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -217,7 +217,6 @@ public: static jsid sDocument_id; static jsid sFrames_id; static jsid sSelf_id; - static jsid sAll_id; static jsid sJava_id; static jsid sPackages_id; static jsid sWrappedJSObject_id; @@ -591,7 +590,9 @@ private: }; -// HTMLDocument helper +// HTMLAllCollection + +extern JSClass sHTMLDocumentAllClass; class nsHTMLDocumentSH { @@ -606,14 +607,6 @@ public: unsigned flags, JS::MutableHandle objp); static void ReleaseDocument(JSFreeOp *fop, JSObject *obj); static JSBool CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp); - static JSBool DocumentAllHelperGetProperty(JSContext *cx, JSHandleObject obj, - JSHandleId id, JSMutableHandleValue vp); - static JSBool DocumentAllHelperNewResolve(JSContext *cx, JSHandleObject obj, - JSHandleId id, unsigned flags, - JS::MutableHandle objp); - - static nsresult TryResolveAll(JSContext* cx, nsHTMLDocument* doc, - JS::Handle obj); }; diff --git a/dom/webidl/HTMLDocument.webidl b/dom/webidl/HTMLDocument.webidl index 1fdfb91f98f9..b8ed8e585b32 100644 --- a/dom/webidl/HTMLDocument.webidl +++ b/dom/webidl/HTMLDocument.webidl @@ -65,6 +65,9 @@ interface HTMLDocument : Document { void clear(); + [Throws] + readonly attribute object all; + // https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#selections [Throws] Selection getSelection();