Bug #315841 don't flush frames in order to ensure that plugins are instantiated.

also, don't flush when inside of ObjectURIChanged
r+sr=bz
This commit is contained in:
cbiesinger%web.de 2005-12-03 11:27:42 +00:00
Родитель f2a37733b9
Коммит 3c23130790
5 изменённых файлов: 120 добавлений и 70 удалений

Просмотреть файл

@ -39,11 +39,12 @@
#include "nsISupports.idl"
interface nsIObjectFrame;
interface nsIPluginInstance;
/**
* This interface represents a content node that loads objects.
*/
[scriptable, uuid(b986a24d-3dd2-4c61-b2bc-3047f4e5e276)]
[scriptable, uuid(ce744034-2bd3-4057-be9c-6f2e2f857749)]
interface nsIObjectLoadingContent : nsISupports
{
const unsigned long TYPE_LOADING = 0;
@ -65,6 +66,24 @@ interface nsIObjectLoadingContent : nsISupports
readonly attribute unsigned long displayedType;
/**
* Makes sure that a frame for this object exists, and that the plugin is
* instantiated. This method does nothing if the type is not #TYPE_PLUGIN.
* There is no guarantee that there will be a frame after this method is
* called; for example, the node may have a display:none style. If plugin
* instantiation is possible, it will be done synchronously by this method,
* and the plugin instance will be returned. A success return value does not
* necessarily mean that the instance is nonnull.
*
* This is a noscript method because it is internal and will go away once
* plugin loading moves to content.
*
* @note If there is an error instantiating the plugin, this method will
* trigger fallback to replacement content, and the type will change (and
* this method will return a failure code)
*/
[noscript] nsIPluginInstance ensureInstantiation();
/**
* Tells the content about an associated object frame.
* This can be called multiple times for different frames.

Просмотреть файл

@ -255,6 +255,18 @@ class AutoFallback {
const nsresult* mResult;
};
/**
* A class that automatically sets mInstantiating to false when it goes
* out of scope.
*/
class AutoSetInstantiatingToFalse {
public:
AutoSetInstantiatingToFalse(nsObjectLoadingContent* objlc) : mContent(objlc) {}
~AutoSetInstantiatingToFalse() { mContent->mInstantiating = PR_FALSE; }
private:
nsObjectLoadingContent* mContent;
};
// helper functions
static PRBool
IsSupportedImage(const nsCString& aMimeType)
@ -500,6 +512,69 @@ nsObjectLoadingContent::GetDisplayedType(PRUint32* aType)
}
NS_IMETHODIMP
nsObjectLoadingContent::EnsureInstantiation(nsIPluginInstance** aInstance)
{
// Must set our out parameter to null as we have various early returns with
// an NS_OK result.
*aInstance = nsnull;
if (mType != eType_Plugin) {
return NS_OK;
}
nsIObjectFrame* frame = GetFrame();
if (frame) {
// If we have a frame, we may have pending instantiate events; revoke
// them.
nsCOMPtr<nsIEventQueue> eventQ;
NS_GetCurrentEventQ(getter_AddRefs(eventQ));
if (eventQ) {
LOG(("OBJLC [%p]: Revoking events\n", this));
eventQ->RevokeEvents(this);
}
} else {
// mInstantiating is true if we're in ObjectURIChanged; we shouldn't
// recreate frames in that case, we'd confuse that function.
if (mInstantiating) {
return NS_OK;
}
// Trigger frame construction
mInstantiating = PR_TRUE;
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(NS_STATIC_CAST(nsIImageLoadingContent*, this));
NS_ASSERTION(thisContent, "must be a content");
nsIDocument* doc = thisContent->GetCurrentDoc();
PRUint32 numShells = doc->GetNumberOfShells();
for (PRUint32 i = 0; i < numShells; ++i) {
nsIPresShell* shell = doc->GetShellAt(i);
shell->RecreateFramesFor(thisContent);
}
mInstantiating = PR_FALSE;
frame = GetFrame();
if (!frame) {
return NS_OK;
}
}
// We may have a plugin instance already; if so, do nothing
nsresult rv = frame->GetPluginInstance(*aInstance);
if (!*aInstance) {
rv = Instantiate(mContentType, mURI);
if (NS_SUCCEEDED(rv)) {
rv = frame->GetPluginInstance(*aInstance);
} else {
Fallback(PR_TRUE);
}
}
return rv;
}
NS_IMETHODIMP
nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
{
@ -609,6 +684,8 @@ nsObjectLoadingContent::ObjectURIChanged(const nsAString& aURI,
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));
NS_ASSERTION(!mInstantiating, "ObjectURIChanged was reentered?");
// Avoid StringToURI in order to use the codebase attribute as base URI
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(NS_STATIC_CAST(nsIImageLoadingContent*, this));
@ -663,6 +740,13 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI,
AutoNotifier notifier(this, aNotify);
// AutoSetInstantiatingToFalse is instantiated after AutoNotifier, so that if the
// AutoNotifier triggers frame construction, events can be posted as
// appropriate.
NS_ASSERTION(!mInstantiating, "ObjectURIChanged was reentered?");
mInstantiating = PR_TRUE;
AutoSetInstantiatingToFalse autoset(this);
mUserDisabled = mSuppressed = PR_FALSE;
mURI = aURI;
@ -746,7 +830,6 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI,
if (newType != mType) {
LOG(("OBJLC [%p]: (aForceType) Changing type from %u to %u\n", this, mType, newType));
mInstantiating = PR_TRUE;
UnloadContent();
// Must have a frameloader before creating a frame, or the frame will
@ -754,14 +837,12 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI,
if (!mFrameLoader && newType == eType_Document) {
if (!thisContent->IsInDoc()) {
// XXX frameloaders can't deal with not being in a document
mInstantiating = PR_FALSE;
mURI = nsnull;
return NS_OK;
}
mFrameLoader = new nsFrameLoader(thisContent);
if (!mFrameLoader) {
mInstantiating = PR_FALSE;
return NS_ERROR_OUT_OF_MEMORY;
}
}
@ -772,7 +853,6 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI,
mType = newType;
if (aNotify)
notifier.Notify();
mInstantiating = PR_FALSE;
}
switch (newType) {
case eType_Image:
@ -798,7 +878,6 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI,
return NS_OK;
}
mInstantiating = PR_TRUE;
// If the class ID specifies a supported plugin, or if we have no explicit URI
// but a type, immediately instantiate the plugin.
PRBool isSupportedClassID = PR_FALSE;
@ -844,14 +923,12 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI,
}
rv = Instantiate(mContentType, mURI);
mInstantiating = PR_FALSE;
return NS_OK;
}
// 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;
}
@ -859,7 +936,6 @@ 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;
}
@ -872,12 +948,9 @@ nsObjectLoadingContent::ObjectURIChanged(nsIURI* aURI,
notifier.Notify();
rv = Instantiate(aTypeHint, aURI);
mInstantiating = PR_FALSE;
return NS_OK;
}
mInstantiating = PR_FALSE;
nsCOMPtr<nsILoadGroup> group = doc->GetDocumentLoadGroup();
nsCOMPtr<nsIChannel> chan;
rv = NS_NewChannel(getter_AddRefs(chan), aURI, nsnull, group, this);

Просмотреть файл

@ -51,6 +51,7 @@
struct nsAsyncInstantiateEvent;
class AutoNotifier;
class AutoFallback;
class AutoSetInstantiatingToFalse;
/**
* INVARIANTS OF THIS CLASS
@ -66,6 +67,9 @@ class AutoFallback;
* contract)
* - mFrameLoader is null while this node is not in a document (XXX this
* invariant only exists due to nsFrameLoader suckage and needs to go away)
* - mInstantiating is true while in ObjectURIChanged (it may be true in other
* cases as well). Only the function that set mInstantiating should trigger
* frame construction or notifications like ContentStatesChanged or flushes.
*/
class nsObjectLoadingContent : public nsImageLoadingContent
, public nsIStreamListener
@ -79,6 +83,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent
{
friend class AutoNotifier;
friend class AutoFallback;
friend class AutoSetInstantiatingToFalse;
public:
// This enum's values must be the same as the constants on

Просмотреть файл

@ -132,6 +132,7 @@
#include "nsIPluginInstance.h"
#include "nsIPluginInstanceInternal.h"
#include "nsIObjectFrame.h"
#include "nsIObjectLoadingContent.h"
#include "nsIScriptablePlugin.h"
#include "nsIPluginHost.h"
#include "nsPIPluginHost.h"
@ -8554,40 +8555,10 @@ nsHTMLExternalObjSH::GetPluginInstance(nsIXPConnectWrappedNative *wrapper,
nsCOMPtr<nsIContent> content(do_QueryWrappedNative(wrapper));
NS_ENSURE_TRUE(content, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIDocument> doc = content->GetDocument();
if (!doc) {
// No document, no plugin.
return NS_OK;
}
// Have to flush layout, since plugin instance instantiation
// currently happens in reflow! That's just uncool.
doc->FlushPendingNotifications(Flush_Layout);
// See if we have a frame.
nsIPresShell *shell = doc->GetShellAt(0);
if (!shell) {
return NS_OK;
}
nsIFrame* frame = shell->GetPrimaryFrameFor(content);
if (!frame) {
// No frame, no plugin
return NS_OK;
}
nsIObjectFrame* objectFrame = nsnull;
CallQueryInterface(frame, &objectFrame);
if (!objectFrame) {
return NS_OK;
}
return objectFrame->GetPluginInstance(*_result);
// Make sure that there is a plugin
nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(content));
NS_ASSERTION(objlc, "Object nodes must implement nsIObjectLoadingContent");
return objlc->EnsureInstantiation(_result);
}
// Check if proto is already in obj's prototype chain.
@ -8648,7 +8619,7 @@ nsHTMLExternalObjSH::PostCreate(nsIXPConnectWrappedNative *wrapper,
if (IsObjInProtoChain(cx, obj, pi_obj)) {
// We must have re-entered ::PostCreate() from nsObjectFrame()
// (through the FlushPendingNotifications() call in
// (through the EnsureInstantiation() call in
// GetPluginInstance()), this means that we've already done what
// we're about to do in this function so we can just return here.

Просмотреть файл

@ -152,6 +152,7 @@
#include "nsIFocusController.h"
#include "nsIPluginInstance.h"
#include "nsIObjectFrame.h"
#include "nsIObjectLoadingContent.h"
#include "nsNetUtil.h"
// Drag & Drop, Clipboard
@ -6185,15 +6186,6 @@ StopPluginInstance(PresShell *aShell, nsIContent *aContent)
if (!objectFrame)
return;
nsCOMPtr<nsIPluginInstance> instance;
objectFrame->GetPluginInstance(*getter_AddRefs(instance));
if (!instance)
return;
// Note on the frame that it used to have a plugin instance, since
// we're about to make said instance go away
frame->SetProperty(nsLayoutAtoms::objectFrame, NS_INT32_TO_PTR(1));
objectFrame->StopPlugin();
}
@ -6229,20 +6221,10 @@ PresShell::Freeze()
static void
StartPluginInstance(PresShell *aShell, nsIContent *aContent)
{
// For now we just reconstruct the frame, but only if the element
// had a plugin instance before we stopped it. Other types of
// embedded content (eg SVG) become unhappy if we do a frame
// reconstruct here.
nsIFrame *frame = aShell->GetPrimaryFrameFor(aContent);
if (frame) {
nsIObjectFrame *objFrame = nsnull;
CallQueryInterface(frame, &objFrame);
if (objFrame && frame->GetProperty(nsLayoutAtoms::objectFrame)) {
// Note: no need to remove the property here, since we're about
// to blow away the frame
aShell->RecreateFramesFor(aContent);
}
}
nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(aContent));
NS_ASSERTION(objlc, "Object nodes must implement nsIObjectLoadingContent");
nsCOMPtr<nsIPluginInstance> inst;
objlc->EnsureInstantiation(getter_AddRefs(inst));
}
PR_STATIC_CALLBACK(PRBool)