Backed out changeset 33031c875984. Bug 90268. r=josh

This commit is contained in:
Josh Aas 2011-08-30 02:09:56 -04:00
parent 3b6b37ef98
commit 3fa80a3ea0
27 changed files with 1262 additions and 1159 deletions

View File

@ -1662,13 +1662,6 @@ public:
const nsAString& aClasses,
nsIDOMNodeList** aReturn);
/**
* Returns the widget for this document if there is one. Looks at all ancestor
* documents to try to find a widget, so for example this can still find a
* widget for documents in display:none frames that have no presentation.
*/
static nsIWidget *WidgetForDocument(nsIDocument *aDoc);
/**
* Returns a layer manager to use for the given document. Basically we
* look up the document hierarchy for the first document which has

View File

@ -51,7 +51,7 @@ interface nsIDOMClientRect;
/**
* This interface represents a content node that loads objects.
*/
[scriptable, uuid(6D8914C7-0E22-4452-8962-11B69BBE84D7)]
[scriptable, uuid(107e8048-d00f-4711-bd21-97184ccae0b1)]
interface nsIObjectLoadingContent : nsISupports
{
const unsigned long TYPE_LOADING = 0;
@ -86,6 +86,24 @@ interface nsIObjectLoadingContent : nsISupports
*/
[noscript] readonly attribute nsNPAPIPluginInstancePtr pluginInstance;
/**
* 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] nsNPAPIPluginInstancePtr ensureInstantiation();
/**
* Tells the content about an associated object frame.
* This can be called multiple times for different frames.
@ -95,8 +113,6 @@ interface nsIObjectLoadingContent : nsISupports
*/
[noscript] void hasNewFrame(in nsIObjectFrame aFrame);
[noscript] void disconnectFrame();
/**
* If this object is in going to be printed, this method
* returns the nsIObjectFrame object which should be used when
@ -109,8 +125,4 @@ interface nsIObjectLoadingContent : nsISupports
in AString pluginDumpID,
in AString browserDumpID,
in boolean submittedCrashReport);
[noscript] void stopPluginInstance();
[noscript] void startPluginInstance();
};

View File

@ -5516,8 +5516,9 @@ nsContentUtils::PlatformToDOMLineBreaks(nsString &aString)
}
}
nsIWidget *
nsContentUtils::WidgetForDocument(nsIDocument *aDoc)
static already_AddRefed<LayerManager>
LayerManagerForDocumentInternal(nsIDocument *aDoc, bool aRequirePersistent,
bool* aAllowRetaining)
{
nsIDocument* doc = aDoc;
nsIDocument* displayDoc = doc->GetDisplayDocument();
@ -5552,27 +5553,19 @@ nsContentUtils::WidgetForDocument(nsIDocument *aDoc)
if (rootView) {
nsIView* displayRoot = nsIViewManager::GetDisplayRootFor(rootView);
if (displayRoot) {
return displayRoot->GetNearestWidget(nsnull);
}
}
}
}
return nsnull;
}
static already_AddRefed<LayerManager>
LayerManagerForDocumentInternal(nsIDocument *aDoc, bool aRequirePersistent,
bool* aAllowRetaining)
{
nsIWidget *widget = nsContentUtils::WidgetForDocument(aDoc);
nsIWidget* widget = displayRoot->GetNearestWidget(nsnull);
if (widget) {
nsRefPtr<LayerManager> manager =
widget->GetLayerManager(aRequirePersistent ? nsIWidget::LAYER_MANAGER_PERSISTENT :
widget->
GetLayerManager(aRequirePersistent ? nsIWidget::LAYER_MANAGER_PERSISTENT :
nsIWidget::LAYER_MANAGER_CURRENT,
aAllowRetaining);
return manager.forget();
}
}
}
}
}
return nsnull;
}

View File

@ -173,7 +173,6 @@
#include "nsIDOMPageTransitionEvent.h"
#include "nsFrameLoader.h"
#include "nsEscape.h"
#include "nsObjectLoadingContent.h"
#ifdef MOZ_MEDIA
#include "nsHTMLMediaElement.h"
#endif // MOZ_MEDIA
@ -3748,11 +3747,6 @@ NotifyActivityChanged(nsIContent *aContent, void *aUnused)
mediaElem->NotifyOwnerDocumentActivityChanged();
}
#endif
nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aContent));
if (objectLoadingContent) {
nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
olc->NotifyOwnerDocumentActivityChanged();
}
}
void

View File

@ -66,7 +66,6 @@
#include "jsobj.h"
#include "jsgc.h"
#include "xpcpublic.h"
#include "nsObjectLoadingContent.h"
using namespace mozilla::dom;
@ -576,20 +575,15 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
}
}
if (wasRegistered && oldDoc != newDoc) {
#ifdef MOZ_MEDIA
if (wasRegistered && oldDoc != newDoc) {
nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aNode));
if (domMediaElem) {
nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aNode);
mediaElem->NotifyOwnerDocumentActivityChanged();
}
}
#endif
nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aNode));
if (objectLoadingContent) {
nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
olc->NotifyOwnerDocumentActivityChanged();
}
}
// nsImageLoadingContent needs to know when its document changes
if (oldDoc != newDoc) {

File diff suppressed because it is too large Load Diff

View File

@ -53,15 +53,11 @@
#include "nsIObjectLoadingContent.h"
#include "nsIRunnable.h"
#include "nsIFrame.h"
#include "nsPluginInstanceOwner.h"
#include "nsIThreadInternal.h"
class nsAsyncInstantiateEvent;
class nsStopPluginRunnable;
class AutoNotifier;
class AutoFallback;
class AutoSetInstantiatingToFalse;
class nsObjectFrame;
enum PluginSupportState {
ePluginUnsupported, // The plugin is not supported (e.g. not installed)
@ -100,8 +96,6 @@ class nsObjectLoadingContent : public nsImageLoadingContent
friend class AutoNotifier;
friend class AutoFallback;
friend class AutoSetInstantiatingToFalse;
friend class nsStopPluginRunnable;
friend class nsAsyncInstantiateEvent;
public:
// This enum's values must be the same as the constants on
@ -144,16 +138,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent
{
mNetworkCreated = aNetworkCreated;
}
// Both "InstantiatePluginInstance" methods can flush layout.
nsresult InstantiatePluginInstance(nsIChannel* aChannel,
nsIStreamListener** aStreamListener);
nsresult InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI);
void NotifyOwnerDocumentActivityChanged();
protected:
/**
* Load the object from the given URI.
* @param aURI The URI to load.
@ -241,14 +226,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent
nsCycleCollectionTraversalCallback &cb);
void CreateStaticClone(nsObjectLoadingContent* aDest) const;
static void DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, PRBool aDelayedStop);
private:
void TryNotifyContentObjectWrapper();
void NotifyContentObjectWrapper();
/**
* Check whether the given request represents a successful load.
*/
@ -327,7 +305,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent
eFlushLayout,
eDontFlush
};
nsObjectFrame* GetExistingFrame(FlushType aFlushType);
nsIObjectFrame* GetExistingFrame(FlushType aFlushType);
/**
* Handle being blocked by a content policy. aStatus is the nsresult
@ -337,6 +315,22 @@ class nsObjectLoadingContent : public nsImageLoadingContent
void HandleBeingBlockedByContentPolicy(nsresult aStatus,
PRInt16 aRetval);
/**
* Checks if we have a frame that's ready for instantiation, and
* if so, calls Instantiate(). Note that this can cause the frame
* to be deleted while we're instantiating the plugin.
*/
nsresult TryInstantiate(const nsACString& aMIMEType, nsIURI* aURI);
/**
* Instantiates the plugin. This differs from
* GetFrame()->Instantiate() in that it ensures that the URI will
* be non-null, and that a MIME type will be passed. Note that
* this can cause the frame to be deleted while we're
* instantiating the plugin.
*/
nsresult Instantiate(nsIObjectFrame* aFrame, const nsACString& aMIMEType, nsIURI* aURI);
/**
* Get the plugin support state for the given content node and MIME type.
* This is used for purposes of determining whether to fire PluginNotFound
@ -420,7 +414,8 @@ class nsObjectLoadingContent : public nsImageLoadingContent
nsWeakFrame mPrintFrame;
nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
friend class nsAsyncInstantiateEvent;
};
#endif

View File

@ -47,7 +47,6 @@
#include "nsContentPolicyUtils.h"
#include "nsIPropertyBag2.h"
#include "mozilla/dom/Element.h"
#include "nsObjectLoadingContent.h"
namespace mozilla {
namespace dom {
@ -145,12 +144,19 @@ PluginStreamListener::SetupPlugin()
// nsObjectFrame does that at the end of reflow.
shell->FlushPendingNotifications(Flush_Layout);
nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(embed));
if (!olc) {
nsIFrame* frame = embed->GetPrimaryFrame();
if (!frame) {
mPluginDoc->AllowNormalInstantiation();
return NS_OK;
}
nsIObjectFrame* objFrame = do_QueryFrame(frame);
if (!objFrame) {
mPluginDoc->AllowNormalInstantiation();
return NS_ERROR_UNEXPECTED;
}
nsObjectLoadingContent* olcc = static_cast<nsObjectLoadingContent*>(olc.get());
nsresult rv = olcc->InstantiatePluginInstance(mPluginDoc->GetType().get(),
nsresult rv = objFrame->Instantiate(mPluginDoc->GetType().get(),
mDocument->nsIDocument::GetDocumentURI());
if (NS_FAILED(rv)) {
return rv;
@ -349,7 +355,7 @@ PluginDocument::Print()
nsIObjectFrame* objectFrame =
do_QueryFrame(mPluginContent->GetPrimaryFrame());
if (objectFrame) {
nsRefPtr<nsNPAPIPluginInstance> pi;
nsCOMPtr<nsNPAPIPluginInstance> pi;
objectFrame->GetPluginInstance(getter_AddRefs(pi));
if (pi) {
NPPrint npprint;

View File

@ -9234,7 +9234,14 @@ nsHTMLPluginObjElementSH::GetPluginInstanceIfSafe(nsIXPConnectWrappedNative *wra
nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(content));
NS_ASSERTION(objlc, "Object nodes must implement nsIObjectLoadingContent");
// If it's not safe to run script we'll only return the instance if it
// exists.
if (!nsContentUtils::IsSafeToRunScript()) {
return objlc->GetPluginInstance(_result);
}
// Make sure that there is a plugin
return objlc->EnsureInstantiation(_result);
}
// Check if proto is already in obj's prototype chain.
@ -9338,9 +9345,20 @@ nsHTMLPluginObjElementSH::SetupProtoChain(nsIXPConnectWrappedNative *wrapper,
if (!pi_obj) {
// Didn't get a plugin instance JSObject, nothing we can do then.
return NS_OK;
}
if (IsObjInProtoChain(cx, obj, pi_obj)) {
// We must have re-entered ::PostCreate() from nsObjectFrame()
// (through the EnsureInstantiation() call in
// GetPluginInstanceIfSafe()), this means that we've already done what
// we're about to do in this function so we can just return here.
return NS_OK;
}
// If we got an xpconnect-wrapped plugin object, set obj's
// prototype's prototype to the scriptable plugin.

View File

@ -80,6 +80,7 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
#endif
mRunning(NOT_STARTED),
mWindowless(PR_FALSE),
mWindowlessLocal(PR_FALSE),
mTransparent(PR_FALSE),
mUsesDOMForCursor(PR_FALSE),
mInPluginInitCall(PR_FALSE),
@ -659,6 +660,12 @@ NPError nsNPAPIPluginInstance::SetWindowless(PRBool aWindowless)
return NPERR_NO_ERROR;
}
NPError nsNPAPIPluginInstance::SetWindowlessLocal(PRBool aWindowlessLocal)
{
mWindowlessLocal = aWindowlessLocal;
return NPERR_NO_ERROR;
}
NPError nsNPAPIPluginInstance::SetTransparent(PRBool aTransparent)
{
mTransparent = aTransparent;

View File

@ -124,6 +124,8 @@ public:
NPError SetWindowless(PRBool aWindowless);
NPError SetWindowlessLocal(PRBool aWindowlessLocal);
NPError SetTransparent(PRBool aTransparent);
NPError SetWantsAllNetworkStreams(PRBool aWantsAllNetworkStreams);
@ -212,6 +214,7 @@ protected:
// these are used to store the windowless properties
// which the browser will later query
PRPackedBool mWindowless;
PRPackedBool mWindowlessLocal;
PRPackedBool mTransparent;
PRPackedBool mUsesDOMForCursor;

View File

@ -3656,6 +3656,12 @@ nsPluginHost::NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow)
return PLUG_NewPluginNativeWindow(aPluginNativeWindow);
}
nsresult
nsPluginHost::DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow)
{
return PLUG_DeletePluginNativeWindow(aPluginNativeWindow);
}
nsresult
nsPluginHost::InstantiateDummyJavaPlugin(nsIPluginInstanceOwner *aOwner)
{

View File

@ -148,6 +148,7 @@ public:
char **outPostData, PRUint32 *outPostDataLen);
nsresult CreateTempFileToPost(const char *aPostDataURL, nsIFile **aTmpFile);
nsresult NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow);
nsresult DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow);
nsresult InstantiateDummyJavaPlugin(nsIPluginInstanceOwner *aOwner);
void AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, PRBool isVisible);

View File

@ -99,7 +99,6 @@ using mozilla::DefaultXDisplay;
static NS_DEFINE_CID(kRangeCID, NS_RANGE_CID);
#include "nsWidgetsCID.h"
static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
#ifdef XP_WIN
@ -178,7 +177,7 @@ nsPluginInstanceOwner::NotifyPaintWaiter(nsDisplayListBuilder* aBuilder)
#ifdef XP_MACOSX
static void DrawPlugin(ImageContainer* aContainer, void* aPluginInstanceOwner)
{
nsObjectFrame* frame = static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner)->GetFrame();
nsObjectFrame* frame = static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner)->GetOwner();
if (frame) {
frame->UpdateImageLayer(aContainer, gfxRect(0,0,0,0));
}
@ -285,16 +284,14 @@ nsPluginInstanceOwner::nsPluginInstanceOwner()
// create nsPluginNativeWindow object, it is derived from NPWindow
// struct and allows to manipulate native window procedure
nsCOMPtr<nsIPluginHost> pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
mPluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
if (mPluginHost)
mPluginHost->NewPluginNativeWindow(&mPluginWindow);
nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
if (pluginHost)
pluginHost->NewPluginNativeWindow(&mPluginWindow);
else
mPluginWindow = nsnull;
mObjectFrame = nsnull;
mContent = nsnull;
mTagText = nsnull;
mWidgetCreationComplete = PR_FALSE;
#ifdef XP_MACOSX
memset(&mCGPluginPortCopy, 0, sizeof(NP_CGContext));
#ifndef NP_NO_QUICKDRAW
@ -313,6 +310,7 @@ nsPluginInstanceOwner::nsPluginInstanceOwner()
mNumCachedParams = 0;
mCachedAttrParamNames = nsnull;
mCachedAttrParamValues = nsnull;
mDestroyWidget = PR_FALSE;
#ifdef XP_MACOSX
#ifndef NP_NO_QUICKDRAW
@ -369,8 +367,13 @@ nsPluginInstanceOwner::~nsPluginInstanceOwner()
mTagText = nsnull;
}
PLUG_DeletePluginNativeWindow(mPluginWindow);
// clean up plugin native window object
nsCOMPtr<nsIPluginHost> pluginHostCOM = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
if (pluginHost) {
pluginHost->DeletePluginNativeWindow(mPluginWindow);
mPluginWindow = nsnull;
}
if (mInstance) {
mInstance->InvalidateOwner();
@ -1105,6 +1108,7 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays()
!mCachedAttrParamNames,
"re-cache of attrs/params not implemented! use the DOM "
"node directy instead");
NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_NULL_POINTER);
// Convert to a 16-bit count. Subtract 2 in case we add an extra
// "src" or "wmode" entry below.
@ -1177,6 +1181,9 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays()
}
}
// We're done with DOM method calls now. Make sure we still have a frame.
NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_OUT_OF_MEMORY);
// Convert to a 16-bit count.
PRUint32 cparams = ourParams.Count();
if (cparams < 0x0000FFFF) {
@ -2448,15 +2455,70 @@ nsPluginInstanceOwner::Destroy()
if (mWidget) {
nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
if (pluginWidget) {
if (pluginWidget)
pluginWidget->SetPluginInstanceOwner(nsnull);
}
if (mDestroyWidget)
mWidget->Destroy();
}
return NS_OK;
}
/*
* Prepare to stop
*/
void
nsPluginInstanceOwner::PrepareToStop(PRBool aDelayedStop)
{
// Drop image reference because the child may destroy the surface after we return.
nsRefPtr<ImageContainer> container = mObjectFrame->GetImageContainer();
if (container) {
#ifdef XP_MACOSX
nsRefPtr<Image> image = container->GetCurrentImage();
if (image && (image->GetFormat() == Image::MAC_IO_SURFACE) && mObjectFrame) {
// Undo what we did to the current image in SetCurrentImage().
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image.get());
oglImage->SetUpdateCallback(nsnull, nsnull);
oglImage->SetDestroyCallback(nsnull);
// If we have a current image here, its destructor hasn't yet been
// called, so OnDestroyImage() can't yet have been called. So we need
// to do ourselves what OnDestroyImage() would have done.
NS_RELEASE_THIS();
}
#endif
container->SetCurrentImage(nsnull);
}
#if defined(XP_WIN) || defined(MOZ_X11)
if (aDelayedStop && mWidget) {
// To delay stopping a plugin we need to reparent the plugin
// so that we can safely tear down the
// plugin after its frame (and view) is gone.
// Also hide and disable the widget to avoid it from appearing in
// odd places after reparenting it, but before it gets destroyed.
mWidget->Show(PR_FALSE);
mWidget->Enable(PR_FALSE);
// Reparent the plugins native window. This relies on the widget
// and plugin et al not holding any other references to its
// parent.
mWidget->SetParent(nsnull);
mDestroyWidget = PR_TRUE;
}
#endif
// Unregister scroll position listeners
for (nsIFrame* f = mObjectFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
nsIScrollableFrame* sf = do_QueryFrame(f);
if (sf) {
sf->RemoveScrollPositionListener(this);
}
}
}
// Paints are handled differently, so we just simulate an update event.
#ifdef XP_MACOSX
@ -2792,19 +2854,25 @@ void nsPluginInstanceOwner::CancelTimer()
}
#endif
nsresult nsPluginInstanceOwner::Init(nsObjectFrame* aFrame, nsIContent* aContent)
nsresult nsPluginInstanceOwner::Init(nsPresContext* aPresContext,
nsObjectFrame* aFrame,
nsIContent* aContent)
{
mLastEventloopNestingLevel = GetEventloopNestingLevel();
mObjectFrame = aFrame;
mContent = aContent;
if (aFrame) {
SetFrame(aFrame);
nsWeakFrame weakFrame(aFrame);
// Some plugins require a specific sequence of shutdown and startup when
// a page is reloaded. Shutdown happens usually when the last instance
// is destroyed. Here we make sure the plugin instance in the old
// document is destroyed before we try to create the new one.
aFrame->PresContext()->EnsureVisible();
aPresContext->EnsureVisible();
if (!weakFrame.IsAlive()) {
return NS_ERROR_NOT_AVAILABLE;
}
// register context menu listener
@ -2845,6 +2913,16 @@ nsresult nsPluginInstanceOwner::Init(nsObjectFrame* aFrame, nsIContent* aContent
mContent->AddEventListener(NS_LITERAL_STRING("draggesture"), this, PR_TRUE);
mContent->AddEventListener(NS_LITERAL_STRING("dragend"), this, PR_TRUE);
// Register scroll position listeners
// We need to register a scroll position listener on every scrollable
// frame up to the top
for (nsIFrame* f = mObjectFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
nsIScrollableFrame* sf = do_QueryFrame(f);
if (sf) {
sf->AddScrollPositionListener(this);
}
}
return NS_OK;
}
@ -2887,55 +2965,20 @@ NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
nsresult rv = NS_ERROR_FAILURE;
// Can't call this twice!
if (mWidget) {
NS_WARNING("Trying to create a plugin widget twice!");
return NS_ERROR_FAILURE;
}
if (mObjectFrame) {
if (!mWidget) {
PRBool windowless = PR_FALSE;
mInstance->IsWindowless(&windowless);
if (!windowless && !nsIWidget::UsePuppetWidgets()) {
// Try to get a parent widget, on some platforms widget creation will fail without
// a parent.
nsCOMPtr<nsIWidget> parentWidget;
if (mContent) {
nsIDocument *doc = mContent->GetOwnerDoc();
if (doc) {
parentWidget = nsContentUtils::WidgetForDocument(doc);
}
}
mWidget = do_CreateInstance(kWidgetCID, &rv);
if (NS_FAILED(rv)) {
return rv;
}
// always create widgets in Twips, not pixels
nsPresContext* context = mObjectFrame->PresContext();
rv = mObjectFrame->CreateWidget(context->DevPixelsToAppUnits(mPluginWindow->width),
context->DevPixelsToAppUnits(mPluginWindow->height),
windowless);
if (NS_OK == rv) {
mWidget = mObjectFrame->GetWidget();
nsWidgetInitData initData;
initData.mWindowType = eWindowType_plugin;
initData.mUnicode = PR_FALSE;
initData.clipChildren = PR_TRUE;
initData.clipSiblings = PR_TRUE;
rv = mWidget->Create(parentWidget.get(), nsnull, nsIntRect(0,0,0,0),
nsnull, nsnull, nsnull, nsnull, &initData);
if (NS_FAILED(rv)) {
mWidget->Destroy();
mWidget = nsnull;
return rv;
}
mWidget->EnableDragDrop(PR_TRUE);
mWidget->Show(PR_FALSE);
mWidget->Enable(PR_FALSE);
}
if (mObjectFrame) {
// This has to be called even if we don't have a widget! The object
// frame will do windowless setup.
mObjectFrame->SetWidget(mWidget);
}
if (windowless) {
if (PR_TRUE == windowless) {
mPluginWindow->type = NPWindowTypeDrawable;
// this needs to be a HDC according to the spec, but I do
@ -2954,7 +2997,26 @@ NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
mFlash10Quirks = StringBeginsWith(description, flash10Head);
#endif
// Changing to windowless mode changes the NPWindow geometry.
mObjectFrame->FixupWindow(mObjectFrame->GetContentRectRelativeToSelf().Size());
} else if (mWidget) {
nsIWidget* parent = mWidget->GetParent();
NS_ASSERTION(parent, "Plugin windows must not be toplevel");
// Set the plugin window to have an empty cliprect. The cliprect
// will be reset when nsRootPresContext::UpdatePluginGeometry
// runs later. The plugin window does need to have the correct
// size here. GetEmptyClipConfiguration will probably give it the
// size, but just in case we haven't been reflowed or something, set
// the size explicitly.
nsAutoTArray<nsIWidget::Configuration,1> configuration;
mObjectFrame->GetEmptyClipConfiguration(&configuration);
if (configuration.Length() > 0) {
configuration[0].mBounds.width = mPluginWindow->width;
configuration[0].mBounds.height = mPluginWindow->height;
}
parent->ConfigureChildren(configuration);
// mPluginWindow->type is used in |GetPluginPort| so it must
// be initialized first
mPluginWindow->type = NPWindowTypeWindow;
@ -2970,14 +3032,19 @@ NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
// tell the widget about the current plugin instance owner.
nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
if (pluginWidget) {
if (pluginWidget)
pluginWidget->SetPluginInstanceOwner(this);
}
}
}
}
mWidgetCreationComplete = PR_TRUE;
return rv;
}
return NS_OK;
void nsPluginInstanceOwner::SetPluginHost(nsIPluginHost* aHost)
{
mPluginHost = static_cast<nsPluginHost*>(aHost);
}
// Mac specific code to fix up the port location and clipping region
@ -3221,85 +3288,6 @@ nsPluginInstanceOwner::CallSetWindow()
}
}
void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
{
// Don't do anything if the frame situation hasn't changed.
if (mObjectFrame == aFrame) {
return;
}
// Deal with things that depend on whether or not we used to have a frame.
if (mObjectFrame) {
// We have an old frame.
// Drop image reference because the child may destroy the surface after we return.
nsRefPtr<ImageContainer> container = mObjectFrame->GetImageContainer();
if (container) {
#ifdef XP_MACOSX
nsRefPtr<Image> image = container->GetCurrentImage();
if (image && (image->GetFormat() == Image::MAC_IO_SURFACE) && mObjectFrame) {
// Undo what we did to the current image in SetCurrentImage().
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image.get());
oglImage->SetUpdateCallback(nsnull, nsnull);
oglImage->SetDestroyCallback(nsnull);
// If we have a current image here, its destructor hasn't yet been
// called, so OnDestroyImage() can't yet have been called. So we need
// to do ourselves what OnDestroyImage() would have done.
NS_RELEASE_THIS();
}
#endif
container->SetCurrentImage(nsnull);
}
// If we had an old frame and we're not going to have a new one then
// we should unregister for some things.
if (!aFrame) {
// Unregister scroll position listeners
for (nsIFrame* f = mObjectFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
nsIScrollableFrame* sf = do_QueryFrame(f);
if (sf) {
sf->RemoveScrollPositionListener(this);
}
}
}
// Make sure the old frame isn't holding a reference to us.
mObjectFrame->SetInstanceOwner(nsnull);
} else {
if (aFrame) {
// We didn't have an object frame before but we do now!
// We need to register a scroll position listener on every scrollable
// frame up to the top
for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
nsIScrollableFrame* sf = do_QueryFrame(f);
if (sf) {
sf->AddScrollPositionListener(this);
}
}
}
}
// Swap in the new frame (or no frame)
mObjectFrame = aFrame;
// Set up a new frame
if (mObjectFrame) {
mObjectFrame->SetInstanceOwner(this);
// Can only call SetWidget on an object frame once. Don't do it here unless
// widget creation is complete. Whether or not one was actually created and
// mWidget is NULL is irrelevant.
if (mWidgetCreationComplete) {
mObjectFrame->SetWidget(mWidget);
}
mObjectFrame->FixupWindow(mObjectFrame->GetContentRectRelativeToSelf().Size());
mObjectFrame->Invalidate(mObjectFrame->GetContentRectRelativeToSelf());
}
}
nsObjectFrame* nsPluginInstanceOwner::GetFrame()
{
return mObjectFrame;
}
// Little helper function to resolve relative URL in
// |value| for certain inputs of |name|
void nsPluginInstanceOwner::FixUpURLS(const nsString &name, nsAString &value)

View File

@ -133,6 +133,8 @@ public:
nsresult Destroy();
void PrepareToStop(PRBool aDelayedStop);
#ifdef XP_WIN
void Paint(const RECT& aDirty, HDC aDC);
#elif defined(XP_MACOSX)
@ -159,11 +161,14 @@ public:
//locals
nsresult Init(nsObjectFrame* aFrame, nsIContent* aContent);
nsresult Init(nsPresContext* aPresContext, nsObjectFrame* aFrame,
nsIContent* aContent);
void* GetPluginPortFromWidget();
void ReleasePluginPort(void* pluginPort);
void SetPluginHost(nsIPluginHost* aHost);
nsEventStatus ProcessEvent(const nsGUIEvent & anEvent);
#ifdef XP_MACOSX
@ -203,8 +208,13 @@ public:
#endif // XP_MACOSX
void CallSetWindow();
void SetFrame(nsObjectFrame *aFrame);
nsObjectFrame* GetFrame();
void SetOwner(nsObjectFrame *aOwner)
{
mObjectFrame = aOwner;
}
nsObjectFrame* GetOwner() {
return mObjectFrame;
}
PRUint32 GetLastEventloopNestingLevel() const {
return mLastEventloopNestingLevel;
@ -298,11 +308,10 @@ private:
nsPluginNativeWindow *mPluginWindow;
nsRefPtr<nsNPAPIPluginInstance> mInstance;
nsObjectFrame *mObjectFrame;
nsIContent *mContent; // WEAK, content owns us
nsObjectFrame *mObjectFrame; // owns nsPluginInstanceOwner
nsCOMPtr<nsIContent> mContent;
nsCString mDocumentBase;
char *mTagText;
PRBool mWidgetCreationComplete;
nsCOMPtr<nsIWidget> mWidget;
nsRefPtr<nsPluginHost> mPluginHost;
@ -339,6 +348,9 @@ private:
PRPackedBool mPluginWindowVisible;
PRPackedBool mPluginDocumentActiveState;
// If true, destroy the widget on destruction. Used when plugin stop
// is being delayed to a safer point in time.
PRPackedBool mDestroyWidget;
PRUint16 mNumCachedAttrs;
PRUint16 mNumCachedParams;
char **mCachedAttrParamNames;

View File

@ -102,11 +102,6 @@ _MOCHITEST_FILES = \
test_zero_opacity.html \
test_NPPVpluginWantsAllNetworkStreams.html \
test_npruntime_npnsetexception.html \
test_display_none.html \
test_instance_re-parent.html \
test_instance_unparent1.html \
test_instance_unparent2.html \
test_instance_unparent3.html \
$(NULL)
# test_plugin_scroll_painting.html \ bug 596491
@ -131,7 +126,6 @@ _MOCHICHROME_FILES = \
ifneq ($(MOZ_WIDGET_TOOLKIT),cocoa)
_MOCHITEST_FILES += \
test_instance_re-parent-windowed.html \
test_visibility.html \
$(NULL)

View File

@ -1,37 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Test npruntime and paint count for instance in a display:none div</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="startTest()">
<p id="display"></p>
<div style="display: none;">
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
</div>
<script type="application/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
function startTest() {
var paintCount = -1;
var exceptionThrown = false;
var p = document.getElementById('plugin1');
try {
paintCount = p.getPaintCount();
} catch (e) {
exceptionThrown = true;
}
is(paintCount, 0, "Paint count test.");
is(exceptionThrown, false, "Exception test.");
SimpleTest.finish();
}
</script>
</body>
</html>

View File

@ -1,59 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Test re-parentinging an instance's DOM node</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="startTest()">
<p id="display"></p>
<div id="div1">
<embed id="plugin1" type="application/x-test" width="200" height="200" wmode="window"></embed>
</div>
<div id="div2">
</div>
<script type="application/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
var destroyed = false;
function onDestroy() {
destroyed = true;
}
function startTest() {
var exceptionThrown = false;
var p = document.getElementById('plugin1');
var d1 = document.getElementById('div1');
var d2 = document.getElementById('div2');
p.startWatchingInstanceCount();
p.callOnDestroy(onDestroy);
try {
d1.removeChild(p);
} catch (e) {
exceptionThrown = true;
}
is(exceptionThrown, false, "Testing for exception after removeChild.");
try {
d2.appendChild(p);
} catch (e) {
exceptionThrown = true;
}
is(exceptionThrown, false, "Testing for exception after appendChild.");
is(destroyed, false, "No instances should have been destroyed at this point.");
is(p.getInstanceCount(), 0, "No new instances should have been created at this point.");
p.stopWatchingInstanceCount();
SimpleTest.finish();
}
</script>
</body>
</html>

View File

@ -1,59 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Test re-parentinging an instance's DOM node</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="startTest()">
<p id="display"></p>
<div id="div1">
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
</div>
<div id="div2">
</div>
<script type="application/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
var destroyed = false;
function onDestroy() {
destroyed = true;
}
function startTest() {
var exceptionThrown = false;
var p = document.getElementById('plugin1');
var d1 = document.getElementById('div1');
var d2 = document.getElementById('div2');
p.startWatchingInstanceCount();
p.callOnDestroy(onDestroy);
try {
d1.removeChild(p);
} catch (e) {
exceptionThrown = true;
}
is(exceptionThrown, false, "Testing for exception after removeChild.");
try {
d2.appendChild(p);
} catch (e) {
exceptionThrown = true;
}
is(exceptionThrown, false, "Testing for exception after appendChild.");
is(destroyed, false, "No instances should have been destroyed at this point.");
is(p.getInstanceCount(), 0, "No new instances should have been created at this point.");
p.stopWatchingInstanceCount();
SimpleTest.finish();
}
</script>
</body>
</html>

View File

@ -1,41 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Test removing an instance's DOM node</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="startTest()">
<p id="display"></p>
<div id="div1">
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
</div>
<script type="application/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
var destroyed = false;
function onDestroy() {
destroyed = true;
}
function checkPluginAlreadyDestroyed() {
is(destroyed, true, "Plugin instance should have been destroyed.");
SimpleTest.finish();
}
function startTest() {
var p1 = document.getElementById('plugin1');
var d1 = document.getElementById('div1');
p1.callOnDestroy(onDestroy);
setTimeout(checkPluginAlreadyDestroyed, 0);
d1.removeChild(p1);
}
</script>
</body>
</html>

View File

@ -1,50 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Test removing an instance's DOM node</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="startTest()">
<p id="display"></p>
<div id="div1">
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
</div>
<div id="div2">
<div id="div3">
<embed id="plugin2" type="application/x-test" width="200" height="200"></embed>
</div>
</div>
<script type="application/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
var destroyed = false;
function onDestroy() {
destroyed = true;
}
function checkPluginAlreadyDestroyed() {
is(destroyed, true, "Plugin instance should have been destroyed.");
SimpleTest.finish();
}
function startTest() {
var p1 = document.getElementById('plugin1');
var d1 = document.getElementById('div1');
p1.callOnDestroy(onDestroy);
setTimeout(checkPluginAlreadyDestroyed, 0);
// Get two parent check events to run.
d1.removeChild(p1);
d1.appendChild(p1);
d1.removeChild(p1);
}
</script>
</body>
</html>

View File

@ -1,44 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Test removing an instance's DOM node</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="startTest()">
<p id="display"></p>
<div id="div1">
<div id="div2">
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
</div<
</div>
<script type="application/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();
var destroyed = false;
function onDestroy() {
destroyed = true;
}
function checkPluginAlreadyDestroyed() {
is(destroyed, true, "Plugin instance should have been destroyed.");
SimpleTest.finish();
}
function startTest() {
var p1 = document.getElementById('plugin1');
var d1 = document.getElementById('div1');
var d2 = document.getElementById('div2');
p1.callOnDestroy(onDestroy);
setTimeout(checkPluginAlreadyDestroyed, 0);
d1.removeChild(d2);
}
</script>
</body>
</html>

View File

@ -7581,9 +7581,10 @@ PresShell::RemoveOverrideStyleSheet(nsIStyleSheet *aSheet)
static void
FreezeElement(nsIContent *aContent, void * /* unused */)
{
nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
if (olc) {
olc->StopPluginInstance();
nsIFrame *frame = aContent->GetPrimaryFrame();
nsIObjectFrame *objectFrame = do_QueryFrame(frame);
if (objectFrame) {
objectFrame->StopPlugin();
}
}
@ -7661,9 +7662,10 @@ PresShell::FireOrClearDelayedEvents(PRBool aFireEvents)
static void
ThawElement(nsIContent *aContent, void *aShell)
{
nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent));
if (olc) {
olc->StartPluginInstance();
nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(aContent));
if (objlc) {
nsRefPtr<nsNPAPIPluginInstance> inst;
objlc->EnsureInstantiation(getter_AddRefs(inst));
}
}

View File

@ -54,6 +54,42 @@ public:
NS_IMETHOD GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance) = 0;
/**
* Instantiate a plugin for a channel, returning a stream listener for the
* data.
*
* @note Calling this method can delete the frame, so don't assume
* the frame is alive after this call returns.
*/
virtual nsresult Instantiate(nsIChannel* aChannel, nsIStreamListener** aStreamListener) = 0;
/**
* @note Calling this method can delete the frame, so don't assume
* the frame is alive after this call returns.
*/
virtual void TryNotifyContentObjectWrapper() = 0;
/**
* Instantiate a plugin that loads the data itself.
* @param aMimeType Type of the plugin to instantiate. May be null.
* @param aURI URI of the plugin data. May be null.
* @note Only one of aURI and aMimeType may be null.
* If aURI is null, aMimeType must not be the empty string.
* @note XXX this method is here only temporarily, until plugins are loaded
* from content.
*
* @note Calling this method can delete the frame, so don't assume
* the frame is alive after this call returns.
*/
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;
/**
* Get the native widget for the plugin, if any.
*/

View File

@ -322,11 +322,17 @@ NS_IMETHODIMP nsObjectFrame::GetPluginPort(HWND *aPort)
#endif
#endif
static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
NS_IMETHODIMP
nsObjectFrame::Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow)
{
NS_PRECONDITION(aContent, "How did that happen?");
mPreventInstantiation =
(aContent->GetCurrentDoc()->GetDisplayDocument() != nsnull);
PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
("Initializing nsObjectFrame %p for content %p\n", this, aContent));
@ -338,17 +344,25 @@ nsObjectFrame::Init(nsIContent* aContent,
void
nsObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
// Tell content owner of the instance to disconnect its frame.
nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(mContent));
NS_ASSERTION(objContent, "Why not an object loading content?");
objContent->DisconnectFrame();
NS_ASSERTION(!mPreventInstantiation ||
(mContent && mContent->GetCurrentDoc()->GetDisplayDocument()),
"about to crash due to bug 136927");
// we need to finish with the plugin before native window is destroyed
// doing this in the destructor is too late.
StopPluginInternal(PR_TRUE);
// StopPluginInternal might have disowned the widget; if it has,
// mWidget will be null.
if (mWidget) {
mInnerView->DetachWidgetEventHandler(mWidget);
mWidget->Destroy();
}
if (mBackgroundSink) {
mBackgroundSink->Destroy();
}
SetInstanceOwner(nsnull);
nsObjectFrameSuper::DestroyFrom(aDestructRoot);
}
@ -383,14 +397,20 @@ nsObjectFrame::GetFrameName(nsAString& aResult) const
#endif
nsresult
nsObjectFrame::SetWidget(nsIWidget *aWidget)
nsObjectFrame::CreateWidget(nscoord aWidth,
nscoord aHeight,
PRBool aViewOnly)
{
mWidget = aWidget;
nsIView* view = GetView();
NS_ASSERTION(view, "Object frames must have views");
if (!view) {
return NS_ERROR_FAILURE;
return NS_OK; //XXX why OK? MMP
}
PRBool needsWidget = !aViewOnly;
PRBool canCreateWidget = !nsIWidget::UsePuppetWidgets();
if (needsWidget && !canCreateWidget) {
NS_WARNING("Can't use native widgets, and can't hand a plugins a PuppetWidget");
}
nsIViewManager* viewMan = view->GetViewManager();
@ -398,6 +418,9 @@ nsObjectFrame::SetWidget(nsIWidget *aWidget)
// XXX is the above comment correct?
viewMan->SetViewVisibility(view, nsViewVisibility_kHide);
nsRefPtr<nsDeviceContext> dx;
viewMan->GetDeviceContext(*getter_AddRefs(dx));
//this is ugly. it was ripped off from didreflow(). MMP
// Position and size view relative to its parent, not relative to our
// parent frame (our parent frame may not have a view).
@ -415,12 +438,12 @@ nsObjectFrame::SetWidget(nsIWidget *aWidget)
return NS_ERROR_FAILURE;
}
if (mWidget) {
if (needsWidget && !mWidget && canCreateWidget) {
// XXX this breaks plugins in popups ... do we care?
nsIWidget* parentWidget = rpc->PresShell()->FrameManager()->GetRootFrame()->GetNearestWidget();
if (!parentWidget) {
nsIWidget* parentWidget =
rpc->PresShell()->FrameManager()->GetRootFrame()->GetNearestWidget();
if (!parentWidget)
return NS_ERROR_FAILURE;
}
mInnerView = viewMan->CreateView(GetContentRectRelativeToSelf(), view);
if (!mInnerView) {
@ -429,27 +452,30 @@ nsObjectFrame::SetWidget(nsIWidget *aWidget)
}
viewMan->InsertChild(view, mInnerView, nsnull, PR_TRUE);
mWidget->SetParent(parentWidget);
mWidget->Show(PR_TRUE);
mWidget->Enable(PR_TRUE);
nsresult rv;
mWidget = do_CreateInstance(kWidgetCID, &rv);
if (NS_FAILED(rv))
return rv;
// Set the plugin window to have an empty cliprect. The cliprect
// will be reset when nsRootPresContext::UpdatePluginGeometry
// runs later. The plugin window does need to have the correct
// size here. GetEmptyClipConfiguration will probably give it the
// size, but just in case we haven't been reflowed or something, set
// the size explicitly.
nsAutoTArray<nsIWidget::Configuration,1> configuration;
GetEmptyClipConfiguration(&configuration);
NS_ASSERTION(configuration.Length() > 0, "Empty widget configuration array!");
configuration[0].mBounds.width = mRect.width;
configuration[0].mBounds.height = mRect.height;
parentWidget->ConfigureChildren(configuration);
nsRefPtr<nsDeviceContext> dx;
viewMan->GetDeviceContext(*getter_AddRefs(dx));
nsWidgetInitData initData;
initData.mWindowType = eWindowType_plugin;
initData.mUnicode = PR_FALSE;
initData.clipChildren = PR_TRUE;
initData.clipSiblings = PR_TRUE;
// We want mWidget to be able to deliver events to us, especially on
// Mac where events to the plugin are routed through Gecko. So we
// allow the view to attach its event handler to mWidget even though
// mWidget isn't the view's designated widget.
EVENT_CALLBACK eventHandler = mInnerView->AttachWidgetEventHandler(mWidget);
mWidget->SetEventCallback(eventHandler, dx);
rv = mWidget->Create(parentWidget, nsnull, nsIntRect(0,0,0,0),
eventHandler, dx, nsnull, nsnull, &initData);
if (NS_FAILED(rv)) {
mWidget->Destroy();
mWidget = nsnull;
return rv;
}
mWidget->EnableDragDrop(PR_TRUE);
// If this frame has an ancestor with a widget which is not
// the root prescontext's widget, then this plugin should not be
@ -465,7 +491,9 @@ nsObjectFrame::SetWidget(nsIWidget *aWidget)
Invalidate(GetContentRectRelativeToSelf());
#endif
}
}
if (mWidget) {
rpc->RegisterPluginForGeometryUpdates(this);
rpc->RequestUpdatePluginGeometry(this);
@ -486,9 +514,8 @@ nsObjectFrame::SetWidget(nsIWidget *aWidget)
// Now that we have a widget we want to set the event model before
// any events are processed.
nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
if (!pluginWidget) {
if (!pluginWidget)
return NS_ERROR_FAILURE;
}
pluginWidget->SetPluginEventModel(mInstanceOwner->GetEventModel());
pluginWidget->SetPluginDrawingModel(mInstanceOwner->GetDrawingModel());
@ -497,9 +524,6 @@ nsObjectFrame::SetWidget(nsIWidget *aWidget)
}
#endif
} else {
// Changing to windowless mode changes the NPWindow geometry.
FixupWindow(GetContentRectRelativeToSelf().Size());
#ifndef XP_MACOSX
rpc->RegisterPluginForGeometryUpdates(this);
rpc->RequestUpdatePluginGeometry(this);
@ -510,14 +534,7 @@ nsObjectFrame::SetWidget(nsIWidget *aWidget)
viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
}
#ifdef ACCESSIBILITY
nsAccessibilityService* accService = nsIPresShell::AccService();
if (accService) {
accService->RecreateAccessible(PresContext()->PresShell(), mContent);
}
#endif
return NS_OK;
return (needsWidget && !canCreateWidget) ? NS_ERROR_NOT_AVAILABLE : NS_OK;
}
#define EMBED_DEF_WIDTH 240
@ -676,6 +693,50 @@ nsObjectFrame::ReflowCallbackCanceled()
mReflowCallbackPosted = PR_FALSE;
}
nsresult
nsObjectFrame::InstantiatePlugin(nsPluginHost* aPluginHost,
const char* aMimeType,
nsIURI* aURI)
{
NS_ASSERTION(mPreventInstantiation,
"Instantiation should be prevented here!");
// If you add early return(s), be sure to balance this call to
// appShell->SuspendNative() with additional call(s) to
// appShell->ReturnNative().
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
if (appShell) {
appShell->SuspendNative();
}
NS_ASSERTION(mContent, "We should have a content node.");
nsIDocument* doc = mContent->GetOwnerDoc();
nsCOMPtr<nsIPluginDocument> pDoc (do_QueryInterface(doc));
PRBool fullPageMode = PR_FALSE;
if (pDoc) {
pDoc->GetWillHandleInstantiation(&fullPageMode);
}
nsresult rv;
if (fullPageMode) { /* full-page mode */
nsCOMPtr<nsIStreamListener> stream;
rv = aPluginHost->InstantiateFullPagePlugin(aMimeType, aURI, mInstanceOwner, getter_AddRefs(stream));
if (NS_SUCCEEDED(rv))
pDoc->SetStreamListener(stream);
} else { /* embedded mode */
rv = aPluginHost->InstantiateEmbeddedPlugin(aMimeType, aURI, mInstanceOwner);
}
// Note that |this| may very well be destroyed already!
if (appShell) {
appShell->ResumeNative();
}
return rv;
}
void
nsObjectFrame::FixupWindow(const nsSize& aSize)
{
@ -771,38 +832,6 @@ nsObjectFrame::CallSetWindow(PRBool aCheckIsHidden)
return rv;
}
void
nsObjectFrame::SetInstanceOwner(nsPluginInstanceOwner* aOwner)
{
mInstanceOwner = aOwner;
if (!mInstanceOwner) {
nsRootPresContext* rpc = PresContext()->GetRootPresContext();
if (rpc) {
if (mWidget) {
if (mInnerView) {
mInnerView->DetachWidgetEventHandler(mWidget);
}
rpc->UnregisterPluginForGeometryUpdates(this);
// Make sure the plugin is hidden in case an update of plugin geometry
// hasn't happened since this plugin became hidden.
nsIWidget* parent = mWidget->GetParent();
if (parent) {
nsTArray<nsIWidget::Configuration> configurations;
this->GetEmptyClipConfiguration(&configurations);
parent->ConfigureChildren(configurations);
mWidget->SetParent(nsnull);
}
} else {
#ifndef XP_MACOSX
rpc->UnregisterPluginForGeometryUpdates(this);
#endif
}
}
}
}
PRBool
nsObjectFrame::IsFocusable(PRInt32 *aTabIndex, PRBool aWithMouse)
{
@ -2048,11 +2077,400 @@ nsObjectFrame::GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance)
{
*aPluginInstance = nsnull;
if (!mInstanceOwner) {
if (!mInstanceOwner)
return NS_OK;
return mInstanceOwner->GetInstance(aPluginInstance);
}
nsresult
nsObjectFrame::PrepareInstanceOwner()
{
nsWeakFrame weakFrame(this);
// First, have to stop any possibly running plugins.
StopPluginInternal(PR_FALSE);
if (!weakFrame.IsAlive()) {
return NS_ERROR_NOT_AVAILABLE;
}
NS_ASSERTION(!mInstanceOwner, "Must not have an instance owner here");
mInstanceOwner = new nsPluginInstanceOwner();
PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
("Created new instance owner %p for frame %p\n", mInstanceOwner.get(),
this));
// Note, |this| may very well be gone after this call.
return mInstanceOwner->Init(PresContext(), this, GetContent());
}
nsresult
nsObjectFrame::Instantiate(nsIChannel* aChannel, nsIStreamListener** aStreamListener)
{
if (mPreventInstantiation) {
return NS_OK;
}
return mInstanceOwner->GetInstance(aPluginInstance);
// Note: If PrepareInstanceOwner() returns an error, |this| may very
// well be deleted already.
nsresult rv = PrepareInstanceOwner();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv));
nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
if (NS_FAILED(rv)) {
return rv;
}
mInstanceOwner->SetPluginHost(pluginHostCOM);
// This must be done before instantiating the plugin
FixupWindow(GetContentRectRelativeToSelf().Size());
// Ensure we redraw when a plugin is instantiated
Invalidate(GetContentRectRelativeToSelf());
nsWeakFrame weakFrame(this);
NS_ASSERTION(!mPreventInstantiation, "Say what?");
mPreventInstantiation = PR_TRUE;
rv = pluginHost->InstantiatePluginForChannel(aChannel, mInstanceOwner, aStreamListener);
if (!weakFrame.IsAlive()) {
return NS_ERROR_NOT_AVAILABLE;
}
NS_ASSERTION(mPreventInstantiation,
"Instantiation should still be prevented!");
mPreventInstantiation = PR_FALSE;
#ifdef ACCESSIBILITY
nsAccessibilityService* accService = nsIPresShell::AccService();
if (accService) {
accService->RecreateAccessible(PresContext()->PresShell(), mContent);
}
#endif
return rv;
}
nsresult
nsObjectFrame::Instantiate(const char* aMimeType, nsIURI* aURI)
{
PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
("nsObjectFrame::Instantiate(%s) called on frame %p\n", aMimeType,
this));
if (mPreventInstantiation) {
return NS_OK;
}
// XXXbz can aMimeType ever actually be null here? If not, either
// the callers are wrong (and passing "" instead of null) or we can
// remove the codepaths dealing with null aMimeType in
// InstantiateEmbeddedPlugin.
NS_ASSERTION(aMimeType || aURI, "Need a type or a URI!");
// Note: If PrepareInstanceOwner() returns an error, |this| may very
// well be deleted already.
nsresult rv = PrepareInstanceOwner();
NS_ENSURE_SUCCESS(rv, rv);
nsWeakFrame weakFrame(this);
// This must be done before instantiating the plugin
FixupWindow(GetContentRectRelativeToSelf().Size());
// Ensure we redraw when a plugin is instantiated
Invalidate(GetContentRectRelativeToSelf());
// get the nsIPluginHost service
nsCOMPtr<nsIPluginHost> pluginHost(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv));
if (NS_FAILED(rv))
return rv;
mInstanceOwner->SetPluginHost(pluginHost);
NS_ASSERTION(!mPreventInstantiation, "Say what?");
mPreventInstantiation = PR_TRUE;
rv = InstantiatePlugin(static_cast<nsPluginHost*>(pluginHost.get()), aMimeType, aURI);
if (!weakFrame.IsAlive()) {
return NS_ERROR_NOT_AVAILABLE;
}
// finish up
if (NS_SUCCEEDED(rv)) {
TryNotifyContentObjectWrapper();
if (!weakFrame.IsAlive()) {
return NS_ERROR_NOT_AVAILABLE;
}
CallSetWindow();
}
NS_ASSERTION(mPreventInstantiation,
"Instantiation should still be prevented!");
#ifdef ACCESSIBILITY
nsAccessibilityService* accService = nsIPresShell::AccService();
if (accService) {
accService->RecreateAccessible(PresContext()->PresShell(), mContent);
}
#endif
mPreventInstantiation = PR_FALSE;
return rv;
}
void
nsObjectFrame::TryNotifyContentObjectWrapper()
{
nsRefPtr<nsNPAPIPluginInstance> inst;
mInstanceOwner->GetInstance(getter_AddRefs(inst));
if (inst) {
// The plugin may have set up new interfaces; we need to mess with our JS
// wrapper. Note that we DO NOT want to call this if there is no plugin
// instance! That would just reenter Instantiate(), trying to create
// said plugin instance.
NotifyContentObjectWrapper();
}
}
class nsStopPluginRunnable : public nsRunnable, public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
nsStopPluginRunnable(nsPluginInstanceOwner *aInstanceOwner)
: mInstanceOwner(aInstanceOwner)
{
NS_ASSERTION(aInstanceOwner, "need an owner");
}
// nsRunnable
NS_IMETHOD Run();
// nsITimerCallback
NS_IMETHOD Notify(nsITimer *timer);
private:
nsCOMPtr<nsITimer> mTimer;
nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
};
NS_IMPL_ISUPPORTS_INHERITED1(nsStopPluginRunnable, nsRunnable, nsITimerCallback)
#if defined(XP_WIN)
static const char*
GetMIMEType(nsNPAPIPluginInstance *aPluginInstance)
{
if (aPluginInstance) {
const char* mime = nsnull;
if (NS_SUCCEEDED(aPluginInstance->GetMIMEType(&mime)) && mime)
return mime;
}
return "";
}
#endif // XP_WIN
static PRBool
DoDelayedStop(nsPluginInstanceOwner *aInstanceOwner, PRBool aDelayedStop)
{
#if (MOZ_PLATFORM_MAEMO==5)
// Don't delay stop on Maemo/Hildon (bug 530739).
if (aDelayedStop && aInstanceOwner->MatchPluginName("Shockwave Flash"))
return PR_FALSE;
#endif
// Don't delay stopping QuickTime (bug 425157), Flip4Mac (bug 426524),
// XStandard (bug 430219), CMISS Zinc (bug 429604).
if (aDelayedStop
#if !(defined XP_WIN || defined MOZ_X11)
&& !aInstanceOwner->MatchPluginName("QuickTime")
&& !aInstanceOwner->MatchPluginName("Flip4Mac")
&& !aInstanceOwner->MatchPluginName("XStandard plugin")
&& !aInstanceOwner->MatchPluginName("CMISS Zinc Plugin")
#endif
) {
nsCOMPtr<nsIRunnable> evt = new nsStopPluginRunnable(aInstanceOwner);
NS_DispatchToCurrentThread(evt);
return PR_TRUE;
}
return PR_FALSE;
}
static void
DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, PRBool aDelayedStop)
{
nsRefPtr<nsNPAPIPluginInstance> inst;
aInstanceOwner->GetInstance(getter_AddRefs(inst));
if (inst) {
NPWindow *win;
aInstanceOwner->GetWindow(win);
nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
nsRefPtr<nsNPAPIPluginInstance> nullinst;
if (window)
window->CallSetWindow(nullinst);
else
inst->SetWindow(nsnull);
if (DoDelayedStop(aInstanceOwner, aDelayedStop))
return;
#if defined(XP_MACOSX)
aInstanceOwner->HidePluginWindow();
#endif
nsCOMPtr<nsIPluginHost> pluginHost = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
NS_ASSERTION(pluginHost, "Without a pluginHost, how can we have an instance to destroy?");
static_cast<nsPluginHost*>(pluginHost.get())->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);
}
aInstanceOwner->Destroy();
}
NS_IMETHODIMP
nsStopPluginRunnable::Notify(nsITimer *aTimer)
{
return Run();
}
NS_IMETHODIMP
nsStopPluginRunnable::Run()
{
// InitWithCallback calls Release before AddRef so we need to hold a
// strong ref on 'this' since we fall through to this scope if it fails.
nsCOMPtr<nsITimerCallback> kungFuDeathGrip = this;
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
if (appShell) {
PRUint32 currentLevel = 0;
appShell->GetEventloopNestingLevel(&currentLevel);
if (currentLevel > mInstanceOwner->GetLastEventloopNestingLevel()) {
if (!mTimer)
mTimer = do_CreateInstance("@mozilla.org/timer;1");
if (mTimer) {
// Fire 100ms timer to try to tear down this plugin as quickly as
// possible once the nesting level comes back down.
nsresult rv = mTimer->InitWithCallback(this, 100, nsITimer::TYPE_ONE_SHOT);
if (NS_SUCCEEDED(rv)) {
return rv;
}
}
NS_ERROR("Failed to setup a timer to stop the plugin later (at a safe "
"time). Stopping the plugin now, this might crash.");
}
}
mTimer = nsnull;
DoStopPlugin(mInstanceOwner, PR_FALSE);
return NS_OK;
}
void
nsObjectFrame::StopPlugin()
{
PRBool delayedStop = PR_FALSE;
#ifdef XP_WIN
nsRefPtr<nsNPAPIPluginInstance> inst;
if (mInstanceOwner)
mInstanceOwner->GetInstance(getter_AddRefs(inst));
if (inst) {
// Delayed stop for Real plugin only; see bug 420886, 426852.
const char* pluginType = ::GetMIMEType(inst);
delayedStop = strcmp(pluginType, "audio/x-pn-realaudio-plugin") == 0;
}
#endif
StopPluginInternal(delayedStop);
}
void
nsObjectFrame::StopPluginInternal(PRBool aDelayedStop)
{
if (!mInstanceOwner) {
return;
}
nsRootPresContext* rpc = PresContext()->GetRootPresContext();
if (!rpc) {
NS_ASSERTION(PresContext()->PresShell()->IsFrozen(),
"unable to unregister the plugin frame");
}
else if (mWidget) {
rpc->UnregisterPluginForGeometryUpdates(this);
// Make sure the plugin is hidden in case an update of plugin geometry
// hasn't happened since this plugin became hidden.
nsIWidget* parent = mWidget->GetParent();
if (parent) {
nsTArray<nsIWidget::Configuration> configurations;
GetEmptyClipConfiguration(&configurations);
parent->ConfigureChildren(configurations);
}
}
else {
#ifndef XP_MACOSX
rpc->UnregisterPluginForGeometryUpdates(this);
#endif
}
// Transfer the reference to the instance owner onto the stack so
// that if we do end up re-entering this code, or if we unwind back
// here witha deleted frame (this), we can still continue to stop
// the plugin. Note that due to that, the ordering of the code in
// this function is extremely important.
nsRefPtr<nsPluginInstanceOwner> owner;
owner.swap(mInstanceOwner);
// Make sure that our windowless rect has been zeroed out, so if we
// get reinstantiated we'll send the right messages to the plug-in.
mWindowlessRect.SetEmpty();
PRBool oldVal = mPreventInstantiation;
mPreventInstantiation = PR_TRUE;
nsWeakFrame weakFrame(this);
#if defined(XP_WIN) || defined(MOZ_X11)
if (aDelayedStop && mWidget) {
// If we're asked to do a delayed stop it means we're stopping the
// plugin because we're destroying the frame. In that case, disown
// the widget.
mInnerView->DetachWidgetEventHandler(mWidget);
mWidget = nsnull;
}
#endif
// From this point on, |this| could have been deleted, so don't
// touch it!
owner->PrepareToStop(aDelayedStop);
DoStopPlugin(owner, aDelayedStop);
// If |this| is still alive, reset mPreventInstantiation.
if (weakFrame.IsAlive()) {
NS_ASSERTION(mPreventInstantiation,
"Instantiation should still be prevented!");
mPreventInstantiation = oldVal;
}
// Break relationship between frame and plugin instance owner
owner->SetOwner(nsnull);
}
NS_IMETHODIMP
@ -2086,6 +2504,43 @@ nsObjectFrame::SetIsDocumentActive(PRBool aIsActive)
#endif
}
void
nsObjectFrame::NotifyContentObjectWrapper()
{
nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
if (!doc)
return;
nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
if (!sgo)
return;
nsIScriptContext *scx = sgo->GetContext();
if (!scx)
return;
JSContext *cx = (JSContext *)scx->GetNativeContext();
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
nsContentUtils::XPConnect()->
GetWrappedNativeOfNativeObject(cx, sgo->GetGlobalJSObject(), mContent,
NS_GET_IID(nsISupports),
getter_AddRefs(wrapper));
if (!wrapper) {
// Nothing to do here if there's no wrapper for mContent. The proto
// chain will be fixed appropriately when the wrapper is created.
return;
}
JSObject *obj = nsnull;
nsresult rv = wrapper->GetJSObject(&obj);
if (NS_FAILED(rv))
return;
nsHTMLPluginObjElementSH::SetupProtoChain(wrapper, cx, obj);
}
// static
nsIObjectFrame *
nsObjectFrame::GetNextObjectFrame(nsPresContext* aPresContext, nsIFrame* aRoot)

View File

@ -40,6 +40,10 @@
#ifndef nsObjectFrame_h___
#define nsObjectFrame_h___
#ifdef XP_WIN
#include <windows.h>
#endif
#include "nsPluginInstanceOwner.h"
#include "nsIObjectFrame.h"
#include "nsFrame.h"
@ -120,9 +124,20 @@ public:
virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext);
NS_METHOD GetPluginInstance(nsNPAPIPluginInstance** aPluginInstance);
virtual nsresult Instantiate(nsIChannel* aChannel, nsIStreamListener** aStreamListener);
virtual nsresult Instantiate(const char* aMimeType, nsIURI* aURI);
virtual void TryNotifyContentObjectWrapper();
virtual void StopPlugin();
virtual void SetIsDocumentActive(PRBool aIsActive);
/*
* Stop a plugin instance. If aDelayedStop is true, the plugin will
* be stopped at a later point when it's safe to do so (i.e. not
* while destroying the frame tree). Delayed stopping is only
* implemented on Win32 for now.
*/
void StopPluginInternal(PRBool aDelayedStop);
NS_IMETHOD GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor);
// Compute the desired position of the plugin's widget, on the assumption
@ -148,7 +163,7 @@ public:
#endif
//local methods
nsresult SetWidget(nsIWidget *aWidget);
nsresult CreateWidget(nscoord aWidth, nscoord aHeight, PRBool aViewOnly);
// for a given aRoot, this walks the frame tree looking for the next outFrame
static nsIObjectFrame* GetNextObjectFrame(nsPresContext* aPresContext,
@ -194,19 +209,6 @@ public:
nsIWidget* GetWidget() { return mWidget; }
/**
* Adjust the plugin's idea of its size, using aSize as its new size.
* (aSize must be in twips)
*/
void FixupWindow(const nsSize& aSize);
/*
* Sets up the plugin window and calls SetWindow on the plugin.
*/
nsresult CallSetWindow(PRBool aCheckIsHidden = PR_TRUE);
void SetInstanceOwner(nsPluginInstanceOwner* aOwner);
protected:
nsObjectFrame(nsStyleContext* aContext);
virtual ~nsObjectFrame();
@ -217,6 +219,21 @@ protected:
const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aDesiredSize);
nsresult InstantiatePlugin(nsPluginHost* aPluginHost,
const char* aMimetype,
nsIURI* aURL);
/**
* Adjust the plugin's idea of its size, using aSize as its new size.
* (aSize must be in twips)
*/
void FixupWindow(const nsSize& aSize);
/**
* Sets up the plugin window and calls SetWindow on the plugin.
*/
nsresult CallSetWindow(PRBool aCheckIsHidden = PR_TRUE);
PRBool IsFocusable(PRInt32 *aTabIndex = nsnull, PRBool aWithMouse = PR_FALSE);
// check attributes and optionally CSS to see if we should display anything
@ -225,6 +242,8 @@ protected:
PRBool IsOpaque() const;
PRBool IsTransparentMode() const;
void NotifyContentObjectWrapper();
nsIntPoint GetWindowOriginInPixels(PRBool aWindowless);
static void PaintPrintPlugin(nsIFrame* aFrame,
@ -236,6 +255,12 @@ protected:
nsRenderingContext& aRenderingContext,
const nsRect& aDirtyRect, const nsRect& aPluginRect);
/**
* Makes sure that mInstanceOwner is valid and without a current plugin
* instance. Essentially, this prepares the frame to receive a new plugin.
*/
NS_HIDDEN_(nsresult) PrepareInstanceOwner();
/**
* Get the widget geometry for the plugin. aRegion is in some appunits
* coordinate system whose origin is device-pixel-aligned (if possible),
@ -267,7 +292,7 @@ private:
nsString mEventType;
};
nsPluginInstanceOwner* mInstanceOwner; // WEAK
nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
nsIView* mInnerView;
nsCOMPtr<nsIWidget> mWidget;
nsIntRect mWindowlessRect;
@ -277,6 +302,11 @@ private:
*/
PluginBackgroundSink* mBackgroundSink;
// For assertions that make it easier to determine if a crash is due
// to the underlying problem described in bug 136927, and to prevent
// reentry into instantiation.
PRBool mPreventInstantiation;
PRPackedBool mReflowCallbackPosted;
// A reference to the ImageContainer which contains the current frame

View File

@ -157,12 +157,7 @@ NPBool NS_NPAPI_ConvertPointCocoa(void* inView,
double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
double *destX, double *destY, NPCoordinateSpace destSpace)
{
// Plugins don't always have a view/frame. It would be odd to ask for a point conversion
// without a view, so we'll warn about it, but it's technically OK.
if (!inView) {
NS_WARNING("Must have a native view to convert coordinates.");
return PR_FALSE;
}
NS_ASSERTION(inView, "Must have a native view to convert coordinates.");
// Caller has to want a result.
if (!destX && !destY)