зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
f2a37733b9
Коммит
3c23130790
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче