From 4510cfee8dd80253fa4cfa0f4f6b284bd2785d7b Mon Sep 17 00:00:00 2001 From: "cbiesinger%web.de" Date: Mon, 31 Oct 2005 18:28:56 +0000 Subject: [PATCH] bug 309706 - Add some logging to nsObjectLoadingContent - Add a StopPlugin() method to nsIObjectFrame - Make use of that in PrepareInstanceOwner, so that loading a new plugin in the same frame works as expected - Initialize and elements to eType_Loading, so that the type is only eType_Plugin if mURI and mContentType are valid r+sr=bz git-svn-id: svn://10.0.0.236/trunk@183271 18797224-902f-48f8-a5cc-f745e15eee43 --- .../base/src/nsObjectLoadingContent.cpp | 59 ++++++- .../content/base/src/nsObjectLoadingContent.h | 6 +- .../html/content/src/nsHTMLAppletElement.cpp | 4 +- .../html/content/src/nsHTMLSharedElement.cpp | 4 +- mozilla/layout/generic/nsIObjectFrame.h | 11 +- mozilla/layout/generic/nsObjectFrame.cpp | 150 +++++++++--------- mozilla/layout/generic/nsObjectFrame.h | 1 + 7 files changed, 147 insertions(+), 88 deletions(-) diff --git a/mozilla/content/base/src/nsObjectLoadingContent.cpp b/mozilla/content/base/src/nsObjectLoadingContent.cpp index b4c2d292501..576aa3da96a 100644 --- a/mozilla/content/base/src/nsObjectLoadingContent.cpp +++ b/mozilla/content/base/src/nsObjectLoadingContent.cpp @@ -55,6 +55,7 @@ // Util headers #include "plevent.h" +#include "prlog.h" #include "nsAutoPtr.h" #include "nsContentPolicyUtils.h" @@ -72,6 +73,13 @@ static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID); +#ifdef PR_LOGGING +static PRLogModuleInfo* gObjectLog = PR_NewLogModule("objlc"); +#endif + +#define LOG(args) PR_LOG(gObjectLog, PR_LOG_DEBUG, args) +#define LOG_ENABLED() PR_LOG_TEST(gObjectLog, PR_LOG_DEBUG) + PR_BEGIN_EXTERN_C /* Note that these typedefs declare functions, not pointer to functions. That's the only way in which they differ from @@ -121,6 +129,15 @@ nsAsyncInstantiateEvent::HandleEvent(PLEvent* event) PL_GetEventOwner(event)); // Make sure that we still have the right frame if (con->GetFrame() == ev->mFrame) { + if (LOG_ENABLED()) { + nsCAutoString spec; + if (ev->mURI) { + ev->mURI->GetSpec(spec); + } + LOG(("OBJLC [%p]: Handling Instantiate event: Type=<%s> URI=%p<%s>\n", + con, ev->mContentType.get(), ev->mURI, spec.get())); + } + nsresult rv = con->Instantiate(ev->mContentType, ev->mURI); if (NS_FAILED(rv)) { con->Fallback(PR_TRUE); @@ -178,7 +195,12 @@ class AutoFallback { public: AutoFallback(nsObjectLoadingContent* aContent, const nsresult* rv) : mContent(aContent), mResult(rv) {} - ~AutoFallback() { if (NS_FAILED(*mResult)) mContent->Fallback(PR_FALSE); } + ~AutoFallback() { + if (NS_FAILED(*mResult)) { + LOG(("OBJLC [%p]: rv=%08x, falling back\n", mContent, *mResult)); + mContent->Fallback(PR_FALSE); + } + } private: nsObjectLoadingContent* mContent; const nsresult* mResult; @@ -210,9 +232,9 @@ IsSupportedPlugin(const nsCString& aMIMEType) return NS_SUCCEEDED(rv); } -nsObjectLoadingContent::nsObjectLoadingContent(ObjectType aInitialType) +nsObjectLoadingContent::nsObjectLoadingContent() : mChannel(nsnull) - , mType(aInitialType) + , mType(eType_Loading) , mInstantiating(PR_FALSE) , mUserDisabled(PR_FALSE) , mSuppressed(PR_FALSE) @@ -239,6 +261,7 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest, nsISupports *aConte AutoNotifier notifier(this, PR_TRUE); if (!IsSuccessfulRequest(aRequest)) { + LOG(("OBJLC [%p]: OnStartRequest: Request failed\n", this)); Fallback(PR_FALSE); return NS_BINDING_ABORTED; } @@ -258,6 +281,7 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest, nsISupports *aConte // UnloadContent will set our type to null; need to be sure to only set it to // the real value on success ObjectType newType = GetTypeOfContent(mContentType); + LOG(("OBJLC [%p]: OnStartRequest: Old type=%u New Type=%u\n", this, mType, newType)); if (mType != newType) { UnloadContent(); } @@ -350,11 +374,14 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest, nsISupports *aConte mType = newType; rv = mFinalListener->OnStartRequest(aRequest, aContext); if (NS_FAILED(rv)) { + LOG(("OBJLC [%p]: mFinalListener->OnStartRequest failed (%08x), falling back\n", + this, rv)); Fallback(PR_FALSE); } return rv; } + LOG(("OBJLC [%p]: Found no listener, falling back\n", this)); Fallback(PR_FALSE); return NS_BINDING_ABORTED; } @@ -424,6 +451,8 @@ nsObjectLoadingContent::GetDisplayedType(PRUint32* aType) NS_IMETHODIMP nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame) { + LOG(("OBJLC [%p]: Got frame %p (mInstantiating=%i)\n", this, aFrame, + mInstantiating)); if (!mInstantiating && aFrame && mType == eType_Plugin) { // Asynchronously call Instantiate // This can go away once plugin loading moves to content @@ -450,6 +479,7 @@ nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame) return NS_ERROR_OUT_OF_MEMORY; } + LOG((" posting event\n")); nsresult rv = eventQ->PostEvent(ev); if (NS_FAILED(rv)) { PL_DestroyEvent(ev); @@ -524,6 +554,9 @@ nsObjectLoadingContent::ObjectURIChanged(const nsAString& aURI, PRBool aForceType, PRBool aForceLoad) { + LOG(("OBJLC [%p]: Loading object: URI string=<%s> notify=%i type=<%s> forcetype=%i forceload=%i\n", + this, NS_ConvertUTF16toUTF8(aURI).get(), aNotify, aTypeHint.get(), aForceType, aForceLoad)); + // Avoid StringToURI in order to use the codebase attribute as base URI nsCOMPtr thisContent = do_QueryInterface(NS_STATIC_CAST(nsIImageLoadingContent*, this)); @@ -554,6 +587,9 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI, PRBool aForceType, PRBool aForceLoad) { + LOG(("OBJLC [%p]: Loading object: URI=<%p> notify=%i type=<%s> forcetype=%i forceload=%i\n", + this, aURI, aNotify, aTypeHint.get(), aForceType, aForceLoad)); + if (mURI && aURI && !aForceLoad) { PRBool equal; nsresult rv = mURI->Equals(aURI, &equal); @@ -582,6 +618,7 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI, // From here on, we will always change the content. This means that a // possibly-loading channel should be aborted. if (mChannel) { + LOG(("OBJLC [%p]: Cancelling existing load\n", this)); // These three statements are carefully ordered: // - onStopRequest should get a channel whose status is the same as the // status argument @@ -645,6 +682,8 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI, if (aForceType && !aTypeHint.IsEmpty()) { ObjectType newType = GetTypeOfContent(aTypeHint); if (newType != mType) { + LOG(("OBJLC [%p]: (aForceType) Changing type from %u to %u\n", this, mType, newType)); + mInstantiating = PR_TRUE; UnloadContent(); @@ -712,6 +751,7 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI, GetTypeOfContent(aTypeHint) == eType_Plugin)) { // No URI, but we have a type. The plugin will handle the load. // Or: supported class id, plugin will handle the load. + LOG(("OBJLC [%p]: (classid) Changing type from %u to eType_Plugin\n", this, mType)); mType = eType_Plugin; if (aNotify) notifier.Notify(); @@ -744,6 +784,7 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI, // If we get here, and we had a class ID, then it must have been unsupported. // Fallback in that case. if (hasID) { + LOG(("OBJLC [%p]: invalid classid\n", this)); mInstantiating = PR_FALSE; rv = NS_ERROR_NOT_AVAILABLE; return NS_OK; @@ -751,12 +792,14 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI, if (!aURI) { // No URI and no type... nothing we can do. + LOG(("OBJLC [%p]: no URI\n", this)); mInstantiating = PR_FALSE; rv = NS_ERROR_NOT_AVAILABLE; return NS_OK; } if (!CanHandleURI(aURI)) { + LOG(("OBJLC [%p]: can't handle URI\n", this)); // E.g. mms:// mType = eType_Plugin; if (aNotify) @@ -789,6 +832,7 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI, // Show fallback content in that case. rv = chan->AsyncOpen(this, nsnull); if (NS_SUCCEEDED(rv)) { + LOG(("OBJLC [%p]: Channel opened.\n", this)); mChannel = chan; mType = eType_Loading; } @@ -810,6 +854,8 @@ nsObjectLoadingContent::GetCapabilities() const void nsObjectLoadingContent::Fallback(PRBool aNotify) { + LOG(("OBJLC [%p]: Falling back (Notify=%i)\n", this, aNotify)); + AutoNotifier notifier(this, aNotify); UnloadContent(); @@ -818,6 +864,7 @@ nsObjectLoadingContent::Fallback(PRBool aNotify) void nsObjectLoadingContent::RemovedFromDocument() { + LOG(("OBJLC [%p]: Removed from doc\n", this)); if (mFrameLoader) { // XXX This is very temporary and must go away mFrameLoader->Destroy(); @@ -920,6 +967,9 @@ nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType, PRInt32 aOldState, PRBool aSync) { + LOG(("OBJLC [%p]: Notifying about state change: (%u, %x) -> (%u, %x) (sync=%i)\n", + this, aOldType, aOldState, mType, ObjectState(), aSync)); + nsCOMPtr thisContent = do_QueryInterface(NS_STATIC_CAST(nsIImageLoadingContent*, this)); NS_ASSERTION(thisContent, "must be a content"); @@ -1079,6 +1129,7 @@ nsObjectLoadingContent::Instantiate(const nsACString& aMIMEType, nsIURI* aURI) { nsIObjectFrame* frame = GetFrame(); if (!frame) { + LOG(("OBJLC [%p]: Attempted to instantiate, but have no frame\n", this)); return NS_OK; // Not a failure to have no frame } @@ -1121,6 +1172,8 @@ nsObjectLoadingContent::Instantiate(const nsACString& aMIMEType, nsIURI* aURI) // We'll always have a type or a URI by the time we get here NS_ASSERTION(aURI || !typeToUse.IsEmpty(), "Need a URI or a type"); + LOG(("OBJLC [%p]: Calling [%p]->Instantiate(<%s>, %p)\n", this, frame, + typeToUse.get(), aURI)); return frame->Instantiate(typeToUse.get(), aURI); } diff --git a/mozilla/content/base/src/nsObjectLoadingContent.h b/mozilla/content/base/src/nsObjectLoadingContent.h index 7eb464630bb..375d7561049 100644 --- a/mozilla/content/base/src/nsObjectLoadingContent.h +++ b/mozilla/content/base/src/nsObjectLoadingContent.h @@ -91,11 +91,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent eType_Null = TYPE_NULL ///< Type can't be handled }; - /** - * @param aInitialType The type this object starts as; should correspond - * to the frame that gets initially constructed for it. - */ - nsObjectLoadingContent(ObjectType aInitialType = eType_Loading); + nsObjectLoadingContent(); virtual ~nsObjectLoadingContent(); NS_DECL_NSIREQUESTOBSERVER diff --git a/mozilla/content/html/content/src/nsHTMLAppletElement.cpp b/mozilla/content/html/content/src/nsHTMLAppletElement.cpp index ca5f7f03c40..4c7dd9e57db 100644 --- a/mozilla/content/html/content/src/nsHTMLAppletElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLAppletElement.cpp @@ -121,8 +121,8 @@ NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Applet) nsHTMLAppletElement::nsHTMLAppletElement(nsINodeInfo *aNodeInfo, PRBool aFromParser) - : nsGenericHTMLElement(aNodeInfo), nsObjectLoadingContent(eType_Plugin), - mReflectedApplet(PR_FALSE), mIsDoneAddingChildren(!aFromParser) + : nsGenericHTMLElement(aNodeInfo), mReflectedApplet(PR_FALSE), + mIsDoneAddingChildren(!aFromParser) { } diff --git a/mozilla/content/html/content/src/nsHTMLSharedElement.cpp b/mozilla/content/html/content/src/nsHTMLSharedElement.cpp index f6a7eb04e90..94f01759cfa 100644 --- a/mozilla/content/html/content/src/nsHTMLSharedElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLSharedElement.cpp @@ -157,9 +157,7 @@ NS_IMPL_NS_NEW_HTML_ELEMENT(Shared) nsHTMLSharedElement::nsHTMLSharedElement(nsINodeInfo *aNodeInfo) - : nsGenericHTMLElement(aNodeInfo), - nsObjectLoadingContent(aNodeInfo->Equals(nsHTMLAtoms::embed) ? eType_Plugin - : eType_Null) + : nsGenericHTMLElement(aNodeInfo) { } diff --git a/mozilla/layout/generic/nsIObjectFrame.h b/mozilla/layout/generic/nsIObjectFrame.h index 7e148e5bba4..7d8454d9675 100644 --- a/mozilla/layout/generic/nsIObjectFrame.h +++ b/mozilla/layout/generic/nsIObjectFrame.h @@ -41,9 +41,9 @@ class nsIPluginInstance; -// {6D10B07D-E75B-11d4-9885-00C04FA0CF4B} +// {F455B51F-7A1F-4bbe-B55D-679F033AD3FE} #define NS_IOBJECTFRAME_IID \ -{ 0x6d10b07d, 0xe75b, 0x11d4, { 0x98, 0x85, 0x0, 0xc0, 0x4f, 0xa0, 0xcf, 0x4b } } +{ 0xf455b51f, 0x7a1f, 0x4bbe, { 0xb5, 0x5d, 0x67, 0x9f, 0x3, 0x3a, 0xd3, 0xfe } }; class nsIObjectFrame : public nsISupports { public: @@ -67,6 +67,13 @@ public: * from content. */ virtual nsresult Instantiate(const char* aMimeType, nsIURI* aURI) = 0; + + /** + * Stops and unloads the plugin. Makes the frame ready to receive another + * Instantiate() call. It is safe to call this method even when no plugin + * is currently active in this frame. + */ + virtual void StopPlugin() = 0; }; diff --git a/mozilla/layout/generic/nsObjectFrame.cpp b/mozilla/layout/generic/nsObjectFrame.cpp index 924fb929f5f..fd4f1cf6eef 100644 --- a/mozilla/layout/generic/nsObjectFrame.cpp +++ b/mozilla/layout/generic/nsObjectFrame.cpp @@ -584,72 +584,9 @@ nsObjectFrame::Destroy(nsPresContext* aPresContext) { NS_ASSERTION(!mInstantiating, "about to crash due to bug 136927"); - // Note: we don't want to unset the broken property here, since that would - // cause frame construction to just try constructing an object frame again... - // we need to finish with the plugin before native window is destroyed // doing this in the destructor is too late. - if (mInstanceOwner != nsnull) { - nsCOMPtr inst; - mInstanceOwner->GetInstance(*getter_AddRefs(inst)); - if (inst) { - nsPluginWindow *win; - mInstanceOwner->GetWindow(win); - nsPluginNativeWindow *window = (nsPluginNativeWindow *)win; - nsCOMPtr nullinst; - - PRBool doCache = PR_TRUE; - PRBool doCallSetWindowAfterDestroy = PR_FALSE; - - // first, determine if the plugin wants to be cached - inst->GetValue(nsPluginInstanceVariable_DoCacheBool, - (void *) &doCache); - if (!doCache) { - // then determine if the plugin wants Destroy to be called after - // Set Window. This is for bug 50547. - inst->GetValue(nsPluginInstanceVariable_CallSetWindowAfterDestroyBool, - (void *) &doCallSetWindowAfterDestroy); - if (doCallSetWindowAfterDestroy) { - inst->Stop(); - inst->Destroy(); - - if (window) - window->CallSetWindow(nullinst); - else - inst->SetWindow(nsnull); - } - else { - if (window) - window->CallSetWindow(nullinst); - else - inst->SetWindow(nsnull); - - inst->Stop(); - inst->Destroy(); - } - } - else { - if (window) - window->CallSetWindow(nullinst); - else - inst->SetWindow(nsnull); - - inst->Stop(); - } - - nsCOMPtr pluginHost = do_GetService(kCPluginManagerCID); - if (pluginHost) - pluginHost->StopPluginInstance(inst); - - // the frame is going away along with its widget - // so tell the window to forget its widget too - if (window) - window->SetPluginWidget(nsnull); - } - - mInstanceOwner->Destroy(); - NS_RELEASE(mInstanceOwner); - } + StopPlugin(); return nsObjectFrameSuper::Destroy(aPresContext); } @@ -1703,16 +1640,17 @@ nsresult nsObjectFrame::GetPluginInstance(nsIPluginInstance*& aPluginInstance) nsresult nsObjectFrame::PrepareInstanceOwner() { - if (!mInstanceOwner) { - mInstanceOwner = new nsPluginInstanceOwner(); - if (!mInstanceOwner) - return NS_ERROR_OUT_OF_MEMORY; + // First, have to stop any possibly running plugins. + StopPlugin(); - NS_ADDREF(mInstanceOwner); - mInstanceOwner->Init(GetPresContext(), this); - } else { - mInstanceOwner->SetInstance(nsnull); - } + NS_ASSERTION(!mInstanceOwner, "Must not have an instance owner here"); + + mInstanceOwner = new nsPluginInstanceOwner(); + if (!mInstanceOwner) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(mInstanceOwner); + mInstanceOwner->Init(GetPresContext(), this); return NS_OK; } @@ -1767,6 +1705,72 @@ nsObjectFrame::Instantiate(const char* aMimeType, nsIURI* aURI) return rv; } +void +nsObjectFrame::StopPlugin() +{ + if (mInstanceOwner != nsnull) { + nsCOMPtr inst; + mInstanceOwner->GetInstance(*getter_AddRefs(inst)); + if (inst) { + nsPluginWindow *win; + mInstanceOwner->GetWindow(win); + nsPluginNativeWindow *window = (nsPluginNativeWindow *)win; + nsCOMPtr nullinst; + + PRBool doCache = PR_TRUE; + PRBool doCallSetWindowAfterDestroy = PR_FALSE; + + // first, determine if the plugin wants to be cached + inst->GetValue(nsPluginInstanceVariable_DoCacheBool, + (void *) &doCache); + if (!doCache) { + // then determine if the plugin wants Destroy to be called after + // Set Window. This is for bug 50547. + inst->GetValue(nsPluginInstanceVariable_CallSetWindowAfterDestroyBool, + (void *) &doCallSetWindowAfterDestroy); + if (doCallSetWindowAfterDestroy) { + inst->Stop(); + inst->Destroy(); + + if (window) + window->CallSetWindow(nullinst); + else + inst->SetWindow(nsnull); + } + else { + if (window) + window->CallSetWindow(nullinst); + else + inst->SetWindow(nsnull); + + inst->Stop(); + inst->Destroy(); + } + } + else { + if (window) + window->CallSetWindow(nullinst); + else + inst->SetWindow(nsnull); + + inst->Stop(); + } + + nsCOMPtr pluginHost = do_GetService(kCPluginManagerCID); + if (pluginHost) + pluginHost->StopPluginInstance(inst); + + // the frame is going away along with its widget + // so tell the window to forget its widget too + if (window) + window->SetPluginWidget(nsnull); + } + + mInstanceOwner->Destroy(); + NS_RELEASE(mInstanceOwner); + } +} + void nsObjectFrame::NotifyContentObjectWrapper() { diff --git a/mozilla/layout/generic/nsObjectFrame.h b/mozilla/layout/generic/nsObjectFrame.h index b7ed50193bc..26b707806ed 100644 --- a/mozilla/layout/generic/nsObjectFrame.h +++ b/mozilla/layout/generic/nsObjectFrame.h @@ -100,6 +100,7 @@ public: NS_IMETHOD GetPluginInstance(nsIPluginInstance*& aPluginInstance); virtual nsresult Instantiate(nsIChannel* aChannel, nsIStreamListener** aStreamListener); virtual nsresult Instantiate(const char* aMimeType, nsIURI* aURI); + virtual void StopPlugin(); /* fail on any requests to get a cursor from us because plugins set their own! see bug 118877 */