gecko-dev/layout/generic/nsObjectFrame.cpp
peterlubczynski%netscape.com ed6c60e365 Fixing problems with showing/hiding Mac plugins. Specifically, these problems:
* Mouse events "bleeding through" tabs so that a plugin in one tab responds to mouse movements in another (bug 120875)
* dynamic control of CSS visiblity property with plugins on mac (can hide/show plugins) (bug 137230)
* Plugins incorrectly show up on top of documents and in the wrong place in print preview. This fix will also them to be hidden like they are on other platforms. (bug 133992)
r=av sr=beard
2002-05-02 22:47:49 +00:00

3955 lines
123 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
* Jacek Piskozub <piskozub@iopan.gda.pl>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nscore.h"
#include "nsCOMPtr.h"
#include "nsHTMLParts.h"
#include "nsHTMLContainerFrame.h"
#include "nsIPresContext.h"
#include "nsIPresShell.h"
#include "nsWidgetsCID.h"
#include "nsViewsCID.h"
#include "nsIView.h"
#include "nsIViewManager.h"
#include "nsIDOMKeyListener.h"
#include "nsIPluginHost.h"
#include "nsplugin.h"
#include "nsString.h"
#include "nsReadableUtils.h"
#include "prmem.h"
#include "nsHTMLAtoms.h"
#include "nsIDocument.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsIPluginInstanceOwner.h"
#include "nsIHTMLContent.h"
#include "nsISupportsArray.h"
#include "plstr.h"
#include "nsILinkHandler.h"
#include "nsIJVMPluginTagInfo.h"
#include "nsIWebShell.h"
#include "nsINameSpaceManager.h"
#include "nsIEventListener.h"
#include "nsIScrollableView.h"
#include "nsIScrollPositionListener.h"
#include "nsIStringStream.h" // for NS_NewCharInputStream
#include "nsITimer.h"
#include "nsITimerCallback.h"
#include "nsLayoutAtoms.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIWebBrowserChrome.h"
#include "nsIDOMElement.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMHTMLObjectElement.h"
#include "nsIDOMHTMLAppletElement.h"
#include "nsContentPolicyUtils.h"
#include "nsIDOMWindow.h"
#include "nsIDOMMouseListener.h"
#include "nsIDOMMouseMotionListener.h"
#include "nsIDOMFocusListener.h"
#include "nsIDOMContextMenuListener.h"
#include "nsIDOMEventReceiver.h"
#include "nsIDOMNSEvent.h"
#include "nsIPrivateDOMEvent.h"
#include "nsIDocumentEncoder.h"
#include "nsXPIDLString.h"
#include "nsIDOMRange.h"
#include "nsIPrintContext.h"
#include "nsIPrintPreviewContext.h"
#include "nsIWidget.h"
#include "nsGUIEvent.h"
#include "nsIRenderingContext.h"
#include "nsIContentViewer.h"
#include "nsIDocShell.h"
#include "npapi.h"
#include "nsIPrintSettings.h"
#include "nsGfxCIID.h"
#include "nsHTMLUtils.h"
#include "nsUnicharUtils.h"
#include "nsTransform2D.h"
// headers for plugin scriptability
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContext.h"
#include "nsIXPConnect.h"
#include "nsIXPCScriptable.h"
#include "nsIClassInfo.h"
#include "jsapi.h"
// XXX temporary for Mac double buffering pref
#include "nsIPref.h"
// XXX For temporary paint code
#include "nsIStyleContext.h"
// For mime types
#include "nsMimeTypes.h"
#include "nsIMIMEService.h"
#include "nsCExternalHandlerService.h"
#include "nsICategoryManager.h"
#include "imgILoader.h"
#include "nsObjectFrame.h"
#include "nsIObjectFrame.h"
#include "nsContentCID.h"
static NS_DEFINE_CID(kRangeCID, NS_RANGE_CID);
// XXX temporary for Mac double buffering pref
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
/* X headers suck */
#ifdef KeyPress
#undef KeyPress
#endif
static nsresult GetContainingBlock(nsIFrame *aFrame, nsIFrame **aContainingBlock);
// special class for handeling DOM context menu events
// because for some reason it starves other mouse events if implemented on the same class
class nsPluginDOMContextMenuListener : public nsIDOMContextMenuListener,
public nsIEventListener
{
public:
nsPluginDOMContextMenuListener();
virtual ~nsPluginDOMContextMenuListener();
NS_DECL_ISUPPORTS
NS_IMETHOD ContextMenu(nsIDOMEvent* aContextMenuEvent) { return NS_ERROR_FAILURE; /* means consume event */ }
nsresult Init(nsObjectFrame *aFrame);
nsresult Destroy(nsObjectFrame *aFrame);
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; }
nsEventStatus ProcessEvent(const nsGUIEvent& anEvent) { return nsEventStatus_eConsumeNoDefault; }
};
class nsPluginInstanceOwner : public nsIPluginInstanceOwner,
public nsIPluginTagInfo2,
public nsIJVMPluginTagInfo,
public nsIEventListener,
public nsITimerCallback,
public nsIDOMMouseListener,
public nsIDOMMouseMotionListener,
public nsIDOMKeyListener,
public nsIDOMFocusListener,
public nsIScrollPositionListener
{
public:
nsPluginInstanceOwner();
virtual ~nsPluginInstanceOwner();
NS_DECL_ISUPPORTS
//nsIPluginInstanceOwner interface
NS_IMETHOD SetInstance(nsIPluginInstance *aInstance);
NS_IMETHOD GetInstance(nsIPluginInstance *&aInstance);
NS_IMETHOD GetWindow(nsPluginWindow *&aWindow);
NS_IMETHOD GetMode(nsPluginMode *aMode);
NS_IMETHOD CreateWidget(void);
NS_IMETHOD GetURL(const char *aURL, const char *aTarget, void *aPostData,
PRUint32 aPostDataLen, void *aHeadersData,
PRUint32 aHeadersDataLen, PRBool isFile = PR_FALSE);
NS_IMETHOD ShowStatus(const char *aStatusMsg);
NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg);
NS_IMETHOD GetDocument(nsIDocument* *aDocument);
NS_IMETHOD InvalidateRect(nsPluginRect *invalidRect);
NS_IMETHOD InvalidateRegion(nsPluginRegion invalidRegion);
NS_IMETHOD ForceRedraw();
NS_IMETHOD GetValue(nsPluginInstancePeerVariable variable, void *value);
//nsIPluginTagInfo interface
NS_IMETHOD GetAttributes(PRUint16& n, const char*const*& names,
const char*const*& values);
NS_IMETHOD GetAttribute(const char* name, const char* *result);
NS_IMETHOD GetDOMElement(nsIDOMElement* *result);
//nsIPluginTagInfo2 interface
NS_IMETHOD GetTagType(nsPluginTagType *result);
NS_IMETHOD GetTagText(const char* *result);
NS_IMETHOD GetParameters(PRUint16& n, const char*const*& names, const char*const*& values);
NS_IMETHOD GetParameter(const char* name, const char* *result);
NS_IMETHOD GetDocumentBase(const char* *result);
NS_IMETHOD GetDocumentEncoding(const char* *result);
NS_IMETHOD GetAlignment(const char* *result);
NS_IMETHOD GetWidth(PRUint32 *result);
NS_IMETHOD GetHeight(PRUint32 *result);
NS_IMETHOD GetBorderVertSpace(PRUint32 *result);
NS_IMETHOD GetBorderHorizSpace(PRUint32 *result);
NS_IMETHOD GetUniqueID(PRUint32 *result);
//nsIJVMPluginTagInfo interface
NS_IMETHOD GetCode(const char* *result);
NS_IMETHOD GetCodeBase(const char* *result);
NS_IMETHOD GetArchive(const char* *result);
NS_IMETHOD GetName(const char* *result);
NS_IMETHOD GetMayScript(PRBool *result);
/** nsIDOMMouseListener interfaces
* @see nsIDOMMouseListener
*/
NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent);
NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent);
NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent);
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
/* END interfaces from nsIDOMMouseListener*/
// nsIDOMMouseListener intefaces
NS_IMETHOD MouseMove(nsIDOMEvent* aMouseEvent);
NS_IMETHOD DragMove(nsIDOMEvent* aMouseEvent) { return NS_OK; }
// nsIDOMKeyListener interfaces
NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
// end nsIDOMKeyListener interfaces
// nsIDOMFocuListener interfaces
NS_IMETHOD Focus(nsIDOMEvent * aFocusEvent);
NS_IMETHOD Blur(nsIDOMEvent * aFocusEvent);
nsresult Destroy();
//nsIEventListener interface
nsEventStatus ProcessEvent(const nsGUIEvent & anEvent);
void Paint(const nsRect& aDirtyRect, PRUint32 ndc = nsnull);
// nsITimerCallback interface
NS_IMETHOD_(void) Notify(nsITimer *timer);
void CancelTimer();
// nsIScrollPositionListener interface
NS_IMETHOD ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
NS_IMETHOD ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
//locals
NS_IMETHOD Init(nsIPresContext *aPresContext, nsObjectFrame *aFrame);
nsPluginPort* GetPluginPort();
void ReleasePluginPort(nsPluginPort * pluginPort);
void SetPluginHost(nsIPluginHost* aHost);
#ifdef XP_MAC
void FixUpPluginWindow();
void GUItoMacEvent(const nsGUIEvent& anEvent, EventRecord& aMacEvent);
#endif
private:
nsPluginWindow mPluginWindow;
nsIPluginInstance *mInstance;
nsObjectFrame *mOwner;
nsCString mDocumentBase;
char *mTagText;
nsIWidget *mWidget;
nsIPresContext *mContext;
nsCOMPtr<nsITimer> mPluginTimer;
nsIPluginHost *mPluginHost;
PRPackedBool mContentFocused;
PRPackedBool mWidgetVisible; // used on Mac to store our widget's visible state
PRUint16 mNumCachedAttrs;
PRUint16 mNumCachedParams;
char **mCachedAttrParamNames;
char **mCachedAttrParamValues;
nsPluginDOMContextMenuListener * mCXMenuListener; // pointer to wrapper for nsIDOMContextMenuListener
nsresult DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent);
nsresult DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent);
nsresult DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent);
nsresult EnsureCachedAttrParamArrays();
};
static void ConvertTwipsToPixels(nsIPresContext& aPresContext, nsRect& aTwipsRect, nsRect& aPixelRect);
// Mac specific code to fix up port position and clip during paint
#ifdef XP_MAC
// get the absolute widget position and clip
static void GetWidgetPosClipAndVis(nsIWidget* aWidget,nscoord& aAbsX, nscoord& aAbsY, nsRect& aClipRect, PRBool& aIsVisible);
// convert relative coordinates to absolute
static void ConvertRelativeToWindowAbsolute(nsIFrame* aFrame, nsIPresContext* aPresContext, nsPoint& aRel, nsPoint& aAbs, nsIWidget *&aContainerWidget);
#endif // XP_MAC
nsObjectFrame::~nsObjectFrame()
{
// beard: stop the timer explicitly to reduce reference count.
if (nsnull != mInstanceOwner) {
mInstanceOwner->CancelTimer();
mInstanceOwner->Destroy();
}
NS_IF_RELEASE(mWidget);
NS_IF_RELEASE(mInstanceOwner);
NS_IF_RELEASE(mFullURL);
}
NS_IMETHODIMP
nsObjectFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
{
NS_ENSURE_ARG_POINTER(aInstancePtr);
*aInstancePtr = nsnull;
#ifdef DEBUG
if (aIID.Equals(NS_GET_IID(nsIFrameDebug))) {
*aInstancePtr = NS_STATIC_CAST(nsIFrameDebug*,this);
return NS_OK;
}
#endif
if (aIID.Equals(NS_GET_IID(nsIObjectFrame))) {
*aInstancePtr = NS_STATIC_CAST(nsIObjectFrame*,this);
return NS_OK;
} else if (aIID.Equals(NS_GET_IID(nsIFrame))) {
*aInstancePtr = NS_STATIC_CAST(nsIFrame*,this);
return NS_OK;
} else if (aIID.Equals(NS_GET_IID(nsISupports))) {
*aInstancePtr = NS_STATIC_CAST(nsIObjectFrame*,this);
return NS_OK;
}
return NS_NOINTERFACE;
}
NS_IMETHODIMP_(nsrefcnt) nsObjectFrame::AddRef(void)
{
NS_WARNING("not supported for frames");
return 1;
}
NS_IMETHODIMP_(nsrefcnt) nsObjectFrame::Release(void)
{
NS_WARNING("not supported for frames");
return 1;
}
static NS_DEFINE_CID(kViewCID, NS_VIEW_CID);
static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
static NS_DEFINE_CID(kCAppShellCID, NS_APPSHELL_CID);
static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
PRIntn
nsObjectFrame::GetSkipSides() const
{
return 0;
}
#define IMAGE_EXT_GIF "gif"
#define IMAGE_EXT_JPG "jpg"
#define IMAGE_EXT_PNG "png"
#define IMAGE_EXT_XBM "xbm"
#define IMAGE_EXT_BMP "bmp"
#define IMAGE_EXT_ICO "ico"
#define IMAGE_EXT_CUR "cur"
#define IMAGE_EXT_MNG "mng"
#define IMAGE_EXT_JNG "jng"
// #define DO_DIRTY_INTERSECT 1 // enable dirty rect intersection during paint
void nsObjectFrame::IsSupportedImage(nsIContent* aContent, PRBool* aImage)
{
*aImage = PR_FALSE;
if(aContent == NULL)
return;
nsAutoString type;
nsresult rv = aContent->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::type, type);
if((rv == NS_CONTENT_ATTR_HAS_VALUE) && (type.Length() > 0))
{
nsCOMPtr<imgILoader> loader(do_GetService("@mozilla.org/image/loader;1"));
loader->SupportImageWithMimeType(NS_LossyConvertUCS2toASCII(type).get(), aImage);
return;
}
nsAutoString data;
rv = aContent->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::data, data);
PRBool havedata = (rv == NS_CONTENT_ATTR_HAS_VALUE) && (data.Length() > 0);
if(!havedata)
{// try it once more for SRC attrubute
rv = aContent->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::src, data);
havedata = (rv == NS_CONTENT_ATTR_HAS_VALUE) && (data.Length() > 0);
}
if(havedata)
{
// should be really call to imlib
nsAutoString ext;
PRInt32 iLastCharOffset = data.Length() - 1;
PRInt32 iPointOffset = data.RFindChar('.');
if(iPointOffset != -1)
{
data.Mid(ext, iPointOffset + 1, iLastCharOffset - iPointOffset);
if(ext.EqualsIgnoreCase(IMAGE_EXT_GIF) ||
ext.EqualsIgnoreCase(IMAGE_EXT_JPG) ||
ext.EqualsIgnoreCase(IMAGE_EXT_PNG) ||
ext.EqualsIgnoreCase(IMAGE_EXT_XBM) ||
ext.EqualsIgnoreCase(IMAGE_EXT_BMP) ||
ext.EqualsIgnoreCase(IMAGE_EXT_ICO) ||
ext.EqualsIgnoreCase(IMAGE_EXT_CUR) ||
ext.EqualsIgnoreCase(IMAGE_EXT_MNG) ||
ext.EqualsIgnoreCase(IMAGE_EXT_JNG))
{
*aImage = PR_TRUE;
}
}
return;
}
}
void nsObjectFrame::IsSupportedDocument(nsIContent* aContent, PRBool* aDoc)
{
*aDoc = PR_FALSE;
nsresult rv;
if(aContent == nsnull)
return;
nsCOMPtr<nsICategoryManager> catman = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return;
nsAutoString type;
rv = aContent->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::type, type);
if((rv == NS_CONTENT_ATTR_HAS_VALUE) && (type.Length() > 0))
{
nsXPIDLCString value;
char * buf = ToNewCString(type);
rv = catman->GetCategoryEntry("Gecko-Content-Viewers",buf, getter_Copies(value));
nsMemory::Free(buf);
if (NS_SUCCEEDED(rv) && value && *value && (value.Length() > 0))
*aDoc = PR_TRUE;
return;
}
// if we don't have a TYPE= try getting the mime-type via the DATA= url
nsAutoString data;
rv = aContent->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::data, data);
if((rv == NS_CONTENT_ATTR_HAS_VALUE) && (data.Length() > 0))
{
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIURI> baseURL;
if (NS_FAILED(GetBaseURL(*getter_AddRefs(baseURL)))) return; // XXX NS_NewURI fails without base
rv = NS_NewURI(getter_AddRefs(uri), data, nsnull, baseURL);
if (NS_FAILED(rv)) return;
nsCOMPtr<nsIMIMEService> mimeService = do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return;
char * contentType = nsnull;
rv = mimeService->GetTypeFromURI(uri, &contentType);
if (NS_FAILED(rv)) {
if (contentType)
nsMemory::Free(contentType);
return;
}
nsXPIDLCString value;
rv = catman->GetCategoryEntry("Gecko-Content-Viewers",contentType, getter_Copies(value));
if (NS_SUCCEEDED(rv) && value && *value && (value.Length() > 0))
*aDoc = PR_TRUE;
if (contentType)
nsMemory::Free(contentType);
}
}
NS_IMETHODIMP nsObjectFrame::SetInitialChildList(nsIPresContext* aPresContext,
nsIAtom* aListName,
nsIFrame* aChildList)
{
// we don't want to call this if it is already set (image)
nsresult rv = NS_OK;
if(mFrames.IsEmpty())
rv = nsObjectFrameSuper::SetInitialChildList(aPresContext, aListName, aChildList);
return rv;
}
NS_IMETHODIMP
nsObjectFrame::Init(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
nsIStyleContext* aContext,
nsIFrame* aPrevInFlow)
{
nsresult rv = nsObjectFrameSuper::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
if(rv != NS_OK)
return rv;
mPresContext = aPresContext; // weak ref
PRBool bImage = PR_FALSE;
//Ideally should be call to imlib, when it is available
// and even move this code to Reflow when the stream starts to come
IsSupportedImage(aContent, &bImage);
if(bImage)
{
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
nsIFrame * aNewFrame = nsnull;
rv = NS_NewImageFrame(shell, &aNewFrame);
if(rv != NS_OK)
return rv;
rv = aNewFrame->Init(aPresContext, aContent, this, aContext, aPrevInFlow);
if(rv == NS_OK)
{
nsHTMLContainerFrame::CreateViewForFrame(aPresContext, aNewFrame, aContext, nsnull, PR_FALSE);
mFrames.AppendFrame(this, aNewFrame);
}
else
aNewFrame->Destroy(aPresContext);
return rv; // bail at this point
}
// only do the following for the object tag
nsCOMPtr<nsIAtom> tag;
aContent->GetTag(*getter_AddRefs(tag));
if (tag.get() != nsHTMLAtoms::object) return rv;
// for now, we should try to do the same for "document" types and create
// and IFrame-like sub-frame
PRBool bDoc = PR_FALSE;
IsSupportedDocument(aContent, &bDoc);
if(bDoc)
{
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
nsIFrame * aNewFrame = nsnull;
rv = NS_NewHTMLFrameOuterFrame(shell, &aNewFrame);
if(NS_FAILED(rv))
return rv;
rv = aNewFrame->Init(aPresContext, aContent, this, aContext, aPrevInFlow);
if(NS_SUCCEEDED(rv))
{
nsHTMLContainerFrame::CreateViewForFrame(aPresContext, aNewFrame, aContext, nsnull, PR_FALSE);
mFrames.AppendFrame(this, aNewFrame);
}
else
aNewFrame->Destroy(aPresContext);
}
return rv;
}
NS_IMETHODIMP
nsObjectFrame::Destroy(nsIPresContext* aPresContext)
{
// we need to finish with the plugin before native window is destroyed
// doing this in the destructor is too late.
if(mInstanceOwner != nsnull)
{
nsIPluginInstance *inst;
if(NS_OK == mInstanceOwner->GetInstance(inst))
{
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();
inst->SetWindow(nsnull);
}
else {
inst->SetWindow(nsnull);
inst->Stop();
inst->Destroy();
}
}
else {
inst->SetWindow(nsnull);
inst->Stop();
}
nsCOMPtr<nsIPluginHost> pluginHost = do_GetService(kCPluginManagerCID);
if(pluginHost)
pluginHost->StopPluginInstance(inst);
NS_RELEASE(inst);
}
}
return nsObjectFrameSuper::Destroy(aPresContext);
}
NS_IMETHODIMP
nsObjectFrame::GetFrameType(nsIAtom** aType) const
{
NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer");
*aType = nsLayoutAtoms::objectFrame;
NS_ADDREF(*aType);
return NS_OK;
}
#ifdef DEBUG
NS_IMETHODIMP
nsObjectFrame::GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("ObjectFrame"), aResult);
}
#endif
nsresult
nsObjectFrame::CreateWidget(nsIPresContext* aPresContext,
nscoord aWidth,
nscoord aHeight,
PRBool aViewOnly)
{
#ifndef XP_MAC
// Do not create a widget if 'hidden' (except for Mac, where we
// always create a widget...)
if (IsHidden())
return NS_OK;
#endif
nsIView* view;
// Create our view and widget
nsresult result =
nsComponentManager::CreateInstance(kViewCID, nsnull, NS_GET_IID(nsIView),
(void **)&view);
if (NS_OK != result) {
return result;
}
nsIViewManager *viewMan; // need to release
nsRect boundBox(0, 0, aWidth, aHeight);
nsIFrame* parWithView;
nsIView *parView;
GetParentWithView(aPresContext, &parWithView);
parWithView->GetView(aPresContext, &parView);
if (NS_OK == parView->GetViewManager(viewMan))
{
// nsWidgetInitData* initData = GetWidgetInitData(aPresContext); // needs to be deleted
// initialize the view as hidden since we don't know the (x,y) until Paint
result = view->Init(viewMan, boundBox, parView, nsViewVisibility_kHide);
// if (nsnull != initData) {
// delete(initData);
// }
if (NS_OK != result) {
result = NS_OK; //XXX why OK? MMP
goto exit; //XXX sue me. MMP
}
#if 0
// set the content's widget, so it can get content modified by the widget
nsIWidget *widget;
result = GetWidget(view, &widget);
if (NS_OK == result) {
nsInput* content = (nsInput *)mContent; // change this cast to QueryInterface
content->SetWidget(widget);
NS_IF_RELEASE(widget);
} else {
NS_ASSERTION(0, "could not get widget");
}
#endif
// Turn off double buffering on the Mac. This depends on bug 49743 and partially
// fixes 32327, 19931 amd 51787
#ifdef XP_MAC
nsCOMPtr<nsIPref> prefs(do_GetService(kPrefServiceCID));
PRBool doubleBuffer = PR_FALSE;
prefs ? prefs->GetBoolPref("plugin.enable_double_buffer", &doubleBuffer) : 0;
viewMan->AllowDoubleBuffering(doubleBuffer);
#endif
// XXX Put this last in document order
// XXX Should we be setting the z-index here?
viewMan->InsertChild(parView, view, nsnull, PR_TRUE);
if(aViewOnly != PR_TRUE) {
result = view->CreateWidget(kWidgetCID);
if (NS_OK != result) {
result = NS_OK; //XXX why OK? MMP
goto exit; //XXX sue me. MMP
}
}
}
{
// Here we set the background color for this widget because some plugins will use
// the child window background color when painting. If it's not set, it may default to gray
// Sometimes, a frame doesn't have a background color or is transparent. In this
// case, walk up the frame tree until we do find a frame with a background color
for (nsIFrame* frame = this; frame; frame->GetParent(&frame)) {
const nsStyleBackground* color;
frame->GetStyleData(eStyleStruct_Background, (const nsStyleStruct*&)color);
if (!color->BackgroundIsTransparent()) { // make sure we got an actual color
nsCOMPtr<nsIWidget> win;
view->GetWidget(*getter_AddRefs(win));
if (win)
win->SetBackgroundColor(color->mBackgroundColor);
break;
}
}
//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).
nsIView* parentWithView;
nsPoint origin;
nsRect r(0, 0, mRect.width, mRect.height);
viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
GetOffsetFromView(aPresContext, origin, &parentWithView);
viewMan->ResizeView(view, r);
viewMan->MoveViewTo(view, origin.x, origin.y);
}
SetView(aPresContext, view);
exit:
NS_IF_RELEASE(viewMan);
return result;
}
#define EMBED_DEF_WIDTH 240
#define EMBED_DEF_HEIGHT 200
void
nsObjectFrame::GetDesiredSize(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aMetrics)
{
// By default, we have no area
aMetrics.width = 0;
aMetrics.height = 0;
aMetrics.ascent = 0;
aMetrics.descent = 0;
if (IsHidden(PR_FALSE))
return;
// for EMBED and APPLET, default to 240x200 for compatibility
nsCOMPtr<nsIAtom> atom;
mContent->GetTag(*getter_AddRefs(atom));
if ( nsnull != atom &&
((atom == nsHTMLAtoms::applet) || (atom == nsHTMLAtoms::embed))) {
float p2t;
aPresContext->GetScaledPixelsToTwips(&p2t);
aMetrics.width = NSIntPixelsToTwips(EMBED_DEF_WIDTH, p2t);
aMetrics.height = NSIntPixelsToTwips(EMBED_DEF_HEIGHT, p2t);
}
// now find out size stylisticly
const nsStylePosition* position;
GetStyleData(eStyleStruct_Position, (const nsStyleStruct*&)position);
// width
nsStyleUnit unit = position->mWidth.GetUnit();
if (eStyleUnit_Coord == unit) {
aMetrics.width = position->mWidth.GetCoordValue();
}
else if (eStyleUnit_Percent == unit)
{
float factor = position->mWidth.GetPercentValue();
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth)
aMetrics.width = NSToCoordRound (factor * aReflowState.availableWidth);
else // unconstrained percent case
aMetrics.width = (NS_UNCONSTRAINEDSIZE == aReflowState.mComputedWidth) ? 0 : aReflowState.mComputedWidth;
}
// height
unit = position->mHeight.GetUnit();
if (eStyleUnit_Coord == unit) {
aMetrics.height = position->mHeight.GetCoordValue();
}
else if (eStyleUnit_Percent == unit)
{
float factor = position->mHeight.GetPercentValue();
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)
aMetrics.height = NSToCoordRound (factor * aReflowState.availableHeight);
else // unconstrained percent case
aMetrics.height = (NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) ? 0 : aReflowState.mComputedHeight;
}
// accent
aMetrics.ascent = aMetrics.height;
if (nsnull != aMetrics.maxElementSize) {
aMetrics.maxElementSize->width = aMetrics.width;
aMetrics.maxElementSize->height = aMetrics.height;
}
}
nsresult
nsObjectFrame::MakeAbsoluteURL(nsIURI* *aFullURI,
nsString aSrc,
nsIURI* aBaseURI)
{
nsresult rv;
nsCOMPtr<nsIDocument> document;
rv = mInstanceOwner->GetDocument(getter_AddRefs(document));
//trim leading and trailing whitespace
aSrc.Trim("\b\t\r\n ", PR_TRUE, PR_TRUE, PR_FALSE);
// get document charset
nsAutoString originCharset;
if (document && NS_FAILED(document->GetDocumentCharacterSet(originCharset)))
originCharset.Truncate();
return NS_NewURI(aFullURI, aSrc, NS_LossyConvertUCS2toASCII(originCharset).get(),
aBaseURI, nsHTMLUtils::IOService);
}
NS_IMETHODIMP
nsObjectFrame::Reflow(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
DO_GLOBAL_REFLOW_COUNT("nsObjectFrame", aReflowState.reason);
DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus);
nsresult rv = NS_OK;
// Get our desired size
GetDesiredSize(aPresContext, aReflowState, aMetrics);
// handle an image or iframes elsewhere
nsIFrame * child = mFrames.FirstChild();
if(child != nsnull)
return HandleChild(aPresContext, aMetrics, aReflowState, aStatus, child);
// if we are printing or print previewing, bail for now
nsCOMPtr<nsIPrintContext> thePrinterContext = do_QueryInterface(aPresContext);
nsCOMPtr<nsIPrintPreviewContext> thePrintPreviewContext = do_QueryInterface(aPresContext);
if (thePrinterContext || thePrintPreviewContext) {
aStatus = NS_FRAME_COMPLETE;
return rv;
}
// if mInstance is null, we need to determine what kind of object we are and instantiate ourselves
if (!mInstanceOwner) {
// XXX - do we need to create this for widgets as well?
mInstanceOwner = new nsPluginInstanceOwner();
if(!mInstanceOwner) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mInstanceOwner);
mInstanceOwner->Init(aPresContext, this);
nsCOMPtr<nsISupports> container;
nsCOMPtr<nsIPluginHost> pluginHost;
nsCOMPtr<nsIURI> baseURL;
nsCOMPtr<nsIURI> fullURL;
nsAutoString classid;
PRInt32 nameSpaceID;
if (NS_SUCCEEDED(rv = GetBaseURL(*getter_AddRefs(baseURL)))) {
nsAutoString codeBase;
if ((NS_CONTENT_ATTR_HAS_VALUE ==
mContent->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::codebase, codeBase)) &&
!codeBase.IsEmpty()) {
nsCOMPtr<nsIURI> codeBaseURL;
rv = MakeAbsoluteURL(getter_AddRefs(codeBaseURL), codeBase, baseURL);
if (NS_SUCCEEDED(rv)) {
baseURL = codeBaseURL;
}
}
}
// if we have a clsid, we're either an internal widget, an ActiveX control, or an applet
mContent->GetNameSpaceID(nameSpaceID);
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttr(nameSpaceID, nsHTMLAtoms::classid, classid)) {
PRBool bJavaObject;
bJavaObject = !nsCRT::strncmp(classid.get(), NS_LITERAL_STRING("java:").get(), 5);
// if we find "java:" in the class id, we have a java applet
if(bJavaObject) {
if (!baseURL) return NS_ERROR_FAILURE;
fullURL = baseURL;
// get the nsIPluginHost interface
pluginHost = do_GetService(kCPluginManagerCID);
if (!pluginHost) return NS_ERROR_FAILURE;
mInstanceOwner->SetPluginHost(pluginHost);
rv = InstantiatePlugin(aPresContext, aMetrics, aReflowState,
pluginHost, "application/x-java-vm", fullURL);
}
else { // otherwise, we're either an ActiveX control or an internal widget
// These are some builtin types that we know about for now.
// (Eventually this will move somewhere else.)
if (classid.Equals(NS_LITERAL_STRING("browser"))) {
rv = InstantiateWidget(aPresContext, aMetrics,
aReflowState, kCAppShellCID);
}
else {
// if we haven't matched to an internal type, check to see if
// we have an ActiveX handler
// if not, create the default plugin
if (!baseURL) return NS_ERROR_FAILURE;
fullURL = baseURL;
// get the nsIPluginHost interface
pluginHost = do_GetService(kCPluginManagerCID);
if (!pluginHost) return NS_ERROR_FAILURE;
mInstanceOwner->SetPluginHost(pluginHost);
if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForType("application/x-oleobject"))) {
rv = InstantiatePlugin(aPresContext, aMetrics, aReflowState, pluginHost,
"application/x-oleobject", fullURL);
}
else if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForType("application/oleobject"))) {
rv = InstantiatePlugin(aPresContext, aMetrics, aReflowState, pluginHost,
"application/oleobject", fullURL);
}
else rv = NS_ERROR_FAILURE;
}
}
// finish up
if (NS_SUCCEEDED(rv)) {
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}
}
else { // the object is either an applet or a plugin
nsAutoString src;
if (!baseURL) return NS_ERROR_FAILURE;
// get the nsIPluginHost interface
pluginHost = do_GetService(kCPluginManagerCID);
if (!pluginHost) return NS_ERROR_FAILURE;
mInstanceOwner->SetPluginHost(pluginHost);
nsCOMPtr<nsIAtom> tag;
mContent->GetTag(*getter_AddRefs(tag));
if (tag.get() == nsHTMLAtoms::applet) {
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::code, src)) {
// Create an absolute URL
rv = MakeAbsoluteURL(getter_AddRefs(fullURL), src, baseURL);
}
else
fullURL = baseURL;
rv = InstantiatePlugin(aPresContext, aMetrics, aReflowState,
pluginHost, "application/x-java-vm", fullURL);
} else { // traditional plugin
nsXPIDLCString mimeTypeStr;
nsAutoString type;
mContent->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::type, type);
if (type.Length()) {
mimeTypeStr.Adopt(ToNewCString(type));
}
//stream in the object source if there is one...
if (NS_CONTENT_ATTR_HAS_VALUE ==
mContent->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::src, src) ||
NS_CONTENT_ATTR_HAS_VALUE ==
mContent->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::data, src)) {
// Create an absolute URL
rv = MakeAbsoluteURL(getter_AddRefs(fullURL), src, baseURL);
if (NS_FAILED(rv)) {
// Failed to create URI, maybe because we didn't
// reconize the protocol handler ==> treat like
// no 'src'/'data' was specified in the embed/object tag
fullURL = baseURL;
}
}
else {
// we didn't find a src or data param, so just set the url to the base
fullURL = baseURL;
}
// now try to instantiate a plugin instance based on a mime type
const char* mimeType = mimeTypeStr.get();
if (mimeType || (src.Length() > 0)) {
if (!mimeType) {
// we don't have a mime type, try to figure it out from extension
nsXPIDLCString extension;
PRInt32 offset = src.RFindChar(PRUnichar('.'));
if (offset != kNotFound)
*getter_Copies(extension) = ToNewCString(Substring(src, offset+1, src.Length()));
pluginHost->IsPluginEnabledForExtension(extension, mimeType);
}
// if we fail to get a mime type from extension we can still try to
// instantiate plugin as it can be possible to determine it later
rv = InstantiatePlugin(aPresContext, aMetrics, aReflowState,
pluginHost, mimeType, fullURL);
}
else // if we have neither we should not bother
rv = NS_ERROR_FAILURE;
}
}
}
else { // if (!mInstanceOwner)
rv = ReinstantiatePlugin(aPresContext, aMetrics, aReflowState);
}
// finish up
if (NS_FAILED(rv)) {
// if we got an error, we are probably going to be replaced
// for a replaced object frame, clear our vertical alignment style info, see bug 36997
nsStyleTextReset* text = NS_STATIC_CAST(nsStyleTextReset*,
mStyleContext->GetUniqueStyleData(mPresContext, eStyleStruct_TextReset));
text->mVerticalAlign.SetNormalValue();
//check for alternative content with CantRenderReplacedElement()
nsIPresShell* presShell;
aPresContext->GetShell(&presShell);
rv = presShell->CantRenderReplacedElement(aPresContext, this);
NS_RELEASE(presShell);
} else {
NotifyContentObjectWrapper();
}
aStatus = NS_FRAME_COMPLETE;
return rv;
}
nsresult
nsObjectFrame::InstantiateWidget(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState,
nsCID aWidgetCID)
{
nsresult rv;
GetDesiredSize(aPresContext, aReflowState, aMetrics);
nsIView *parentWithView;
nsPoint origin;
GetOffsetFromView(aPresContext, origin, &parentWithView);
// Just make the frigging widget
float t2p;
aPresContext->GetTwipsToPixels(&t2p);
PRInt32 x = NSTwipsToIntPixels(origin.x, t2p);
PRInt32 y = NSTwipsToIntPixels(origin.y, t2p);
PRInt32 width = NSTwipsToIntPixels(aMetrics.width, t2p);
PRInt32 height = NSTwipsToIntPixels(aMetrics.height, t2p);
nsRect r = nsRect(x, y, width, height);
if((rv = nsComponentManager::CreateInstance(aWidgetCID, nsnull, NS_GET_IID(nsIWidget), (void**)&mWidget)) != NS_OK)
return rv;
nsCOMPtr<nsIWidget> parent;
parentWithView->GetOffsetFromWidget(nsnull, nsnull, *getter_AddRefs(parent));
mWidget->Create(NS_STATIC_CAST(nsIWidget*,parent), r, nsnull, nsnull);
mWidget->Show(PR_TRUE);
return rv;
}
nsresult
nsObjectFrame::InstantiatePlugin(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState,
nsIPluginHost* aPluginHost,
const char* aMimetype,
nsIURI* aURI)
{
nsIView *parentWithView;
nsPoint origin;
nsPluginWindow *window;
float t2p;
aPresContext->GetTwipsToPixels(&t2p);
SetFullURL(aURI);
// we need to recalculate this now that we have access to the nsPluginInstanceOwner
// and its size info (as set in the tag)
GetDesiredSize(aPresContext, aReflowState, aMetrics);
if (nsnull != aMetrics.maxElementSize)
{
//XXX AddBorderPaddingToMaxElementSize(borderPadding);
aMetrics.maxElementSize->width = aMetrics.width;
aMetrics.maxElementSize->height = aMetrics.height;
}
mInstanceOwner->GetWindow(window);
GetOffsetFromView(aPresContext, origin, &parentWithView);
window->x = NSTwipsToIntPixels(origin.x, t2p);
window->y = NSTwipsToIntPixels(origin.y, t2p);
window->width = NSTwipsToIntPixels(aMetrics.width, t2p);
window->height = NSTwipsToIntPixels(aMetrics.height, t2p);
// on the Mac we need to set the clipRect to { 0, 0, 0, 0 } for now. This will keep
// us from drawing on screen until the widget is properly positioned, which will not
// happen until we have finished the reflow process.
window->clipRect.top = 0;
window->clipRect.left = 0;
#ifndef XP_MAC
window->clipRect.bottom = NSTwipsToIntPixels(aMetrics.height, t2p);
window->clipRect.right = NSTwipsToIntPixels(aMetrics.width, t2p);
#else
window->clipRect.bottom = 0;
window->clipRect.right = 0;
#endif
// Check to see if content-policy wants to veto this
if(aURI != nsnull)
{
PRBool shouldLoad = PR_TRUE; // default permit
nsresult rv;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mContent, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIPresShell> shell;
rv = aPresContext->GetShell(getter_AddRefs(shell));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIDocument> document;
rv = shell->GetDocument(getter_AddRefs(document));
if (NS_FAILED(rv)) return rv;
if (! document)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIScriptGlobalObject> globalScript;
rv = document->GetScriptGlobalObject(getter_AddRefs(globalScript));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIDOMWindow> domWin(do_QueryInterface(globalScript));
if (NS_SUCCEEDED(rv) &&
NS_SUCCEEDED(NS_CheckContentLoadPolicy(nsIContentPolicy::OBJECT,
aURI, element, domWin, &shouldLoad)) &&
!shouldLoad) {
return NS_OK;
}
}
return aPluginHost->InstantiateEmbededPlugin(aMimetype, aURI, mInstanceOwner);
}
// This is called when the page containing plugin is resized, and plugin has its dimensions
// specified in percentage, so it needs to follow the page on the fly.
nsresult
nsObjectFrame::ReinstantiatePlugin(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState)
{
nsIView *parentWithView;
nsPoint origin;
nsPluginWindow *window;
float t2p;
aPresContext->GetTwipsToPixels(&t2p);
// we need to recalculate this now that we have access to the nsPluginInstanceOwner
// and its size info (as set in the tag)
GetDesiredSize(aPresContext, aReflowState, aMetrics);
if (nsnull != aMetrics.maxElementSize)
{
//XXX AddBorderPaddingToMaxElementSize(borderPadding);
aMetrics.maxElementSize->width = aMetrics.width;
aMetrics.maxElementSize->height = aMetrics.height;
}
mInstanceOwner->GetWindow(window);
GetOffsetFromView(aPresContext, origin, &parentWithView);
window->x = NSTwipsToIntPixels(origin.x, t2p);
window->y = NSTwipsToIntPixels(origin.y, t2p);
window->width = NSTwipsToIntPixels(aMetrics.width, t2p);
window->height = NSTwipsToIntPixels(aMetrics.height, t2p);
// ignore this for now on the Mac because the widget is not properly positioned
// yet and won't be until we have finished the reflow process.
#ifndef XP_MAC
window->clipRect.top = 0;
window->clipRect.left = 0;
window->clipRect.bottom = NSTwipsToIntPixels(aMetrics.height, t2p);
window->clipRect.right = NSTwipsToIntPixels(aMetrics.width, t2p);
#endif
return NS_OK;
}
nsresult
nsObjectFrame::HandleChild(nsIPresContext* aPresContext,
nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus,
nsIFrame* child)
{
nsSize availSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
nsHTMLReflowMetrics kidDesiredSize(nsnull);
nsReflowReason reflowReason;
nsFrameState frameState;
child->GetFrameState(&frameState);
if (frameState & NS_FRAME_FIRST_REFLOW)
reflowReason = eReflowReason_Initial;
else
reflowReason = eReflowReason_Resize;
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, child,
availSize, reflowReason);
if(kidReflowState.mStylePosition->mWidth.GetUnit() == eStyleUnit_Coord ||
kidReflowState.mStylePosition->mWidth.GetUnit() == eStyleUnit_Percent) {
//the object frame has already calculated the constraints
kidReflowState.mComputedWidth = aMetrics.width;
}
if(kidReflowState.mStylePosition->mHeight.GetUnit() == eStyleUnit_Coord ||
kidReflowState.mStylePosition->mHeight.GetUnit() == eStyleUnit_Percent) {
//the object frame has already calculated the constraints
kidReflowState.mComputedHeight = aMetrics.height;
}
nsReflowStatus status;
kidDesiredSize.width = NS_UNCONSTRAINEDSIZE;
kidDesiredSize.height = NS_UNCONSTRAINEDSIZE;
ReflowChild(child, aPresContext, kidDesiredSize, kidReflowState, 0, 0, 0, status);
FinishReflowChild(child, aPresContext, &kidReflowState, kidDesiredSize, 0, 0, 0);
aMetrics.width = kidDesiredSize.width;
aMetrics.height = kidDesiredSize.height;
aMetrics.ascent = kidDesiredSize.height;
aMetrics.descent = 0;
aStatus = NS_FRAME_COMPLETE;
return NS_OK;
}
nsresult
nsObjectFrame::GetBaseURL(nsIURI* &aURL)
{
nsIHTMLContent* htmlContent;
if (NS_SUCCEEDED(mContent->QueryInterface(NS_GET_IID(nsIHTMLContent), (void**)&htmlContent)))
{
htmlContent->GetBaseURL(aURL);
NS_RELEASE(htmlContent);
}
else
{
nsCOMPtr<nsIDocument> doc;
mContent->GetDocument(*getter_AddRefs(doc));
if (doc)
doc->GetBaseURL(aURL);
else
return NS_ERROR_FAILURE;
}
return NS_OK;
}
PRBool
nsObjectFrame::IsHidden(PRBool aCheckVisibilityStyle) const
{
if (aCheckVisibilityStyle) {
const nsStyleVisibility* vis = (const nsStyleVisibility*)mStyleContext->GetStyleData(eStyleStruct_Visibility);
if (vis && !vis->IsVisibleOrCollapsed())
return PR_TRUE;
}
nsCOMPtr<nsIAtom> tag;
mContent->GetTag(*getter_AddRefs(tag));
// only <embed> tags support the HIDDEN attribute
if (tag.get() == nsHTMLAtoms::embed) {
nsAutoString hidden;
mContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::hidden, hidden);
// Yes, these are really the kooky ways that you could tell 4.x
// not to hide the <embed> once you'd put the 'hidden' attribute
// on the tag...
// these |NS_ConvertASCIItoUCS2|s can't be |NS_LITERAL_STRING|s until |EqualsIgnoreCase| get's fixed
if (!hidden.IsEmpty() &&
!hidden.Equals(NS_LITERAL_STRING("false"), nsCaseInsensitiveStringComparator()) &&
!hidden.Equals(NS_LITERAL_STRING("no"), nsCaseInsensitiveStringComparator()) &&
!hidden.Equals(NS_LITERAL_STRING("off"), nsCaseInsensitiveStringComparator())) {
return PR_TRUE;
}
}
return PR_FALSE;
}
NS_IMETHODIMP
nsObjectFrame::ContentChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
nsISupports* aSubContent)
{
// Generate a reflow command with this frame as the target frame
nsCOMPtr<nsIPresShell> shell;
nsresult rv = aPresContext->GetShell(getter_AddRefs(shell));
if (NS_SUCCEEDED(rv) && shell) {
nsHTMLReflowCommand* reflowCmd;
rv = NS_NewHTMLReflowCommand(&reflowCmd, this,
eReflowType_ContentChanged);
if (NS_SUCCEEDED(rv))
shell->AppendReflowCommand(reflowCmd);
}
return rv;
}
nsresult nsObjectFrame::GetWindowOriginInPixels(nsIPresContext * aPresContext, PRBool aWindowless, nsPoint * aOrigin)
{
NS_ENSURE_ARG_POINTER(aPresContext);
NS_ENSURE_ARG_POINTER(aOrigin);
nsresult rv = NS_OK;
nsIView * parentWithView;
nsPoint origin(0,0);
GetOffsetFromView(aPresContext, origin, &parentWithView);
// if it's windowless, let's make sure we have our origin set right
// it may need to be corrected, like after scrolling
if (aWindowless && parentWithView) {
nsPoint correction(0,0);
nsCOMPtr<nsIViewManager> parentVM;
parentWithView->GetViewManager(*getter_AddRefs(parentVM));
// Walk up all the views and add up their positions. This will give us our
// absolute position which is what we want to give the plugin
nsIView* theView = parentWithView;
while (theView) {
nsCOMPtr<nsIViewManager> vm;
theView->GetViewManager(*getter_AddRefs(vm));
if (vm != parentVM)
break;
theView->GetPosition(&correction.x, &correction.y);
origin += correction;
theView->GetParent(theView);
}
}
float t2p;
aPresContext->GetTwipsToPixels(&t2p);
aOrigin->x = NSTwipsToIntPixels(origin.x, t2p);
aOrigin->y = NSTwipsToIntPixels(origin.y, t2p);
return rv;
}
NS_IMETHODIMP
nsObjectFrame::DidReflow(nsIPresContext* aPresContext,
const nsHTMLReflowState* aReflowState,
nsDidReflowStatus aStatus)
{
nsresult rv = nsObjectFrameSuper::DidReflow(aPresContext, aReflowState, aStatus);
// The view is created hidden; once we have reflowed it and it has been
// positioned then we show it.
if (aStatus != NS_FRAME_REFLOW_FINISHED)
return rv;
PRBool bHidden = IsHidden();
nsIView* view = nsnull;
GetView(aPresContext, &view);
if (view) {
nsCOMPtr<nsIViewManager> vm;
view->GetViewManager(*getter_AddRefs(vm));
if (vm)
vm->SetViewVisibility(view, bHidden ? nsViewVisibility_kHide : nsViewVisibility_kShow);
}
nsPluginWindow *window;
nsCOMPtr<nsIPluginInstance> pi;
if (!mInstanceOwner ||
NS_FAILED(rv = mInstanceOwner->GetWindow(window)) ||
NS_FAILED(rv = mInstanceOwner->GetInstance(*getter_AddRefs(pi))) ||
!pi ||
!window)
return rv;
#ifdef XP_MAC
mInstanceOwner->FixUpPluginWindow();
return rv;
#endif // XP_MAC
if (bHidden)
return rv;
PRBool windowless = (window->type == nsPluginWindowType_Drawable);
if(windowless)
return rv;
nsPoint origin;
GetWindowOriginInPixels(aPresContext, windowless, &origin);
window->x = origin.x;
window->y = origin.y;
// refresh the plugin port as well
window->window = mInstanceOwner->GetPluginPort();
pi->SetWindow(window);
mInstanceOwner->ReleasePluginPort((nsPluginPort *)window->window);
if (mWidget) {
PRInt32 x = origin.x;
PRInt32 y = origin.y;
mWidget->Move(x, y);
}
return rv;
}
NS_IMETHODIMP
nsObjectFrame::Paint(nsIPresContext* aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
nsFramePaintLayer aWhichLayer,
PRUint32 aFlags)
{
const nsStyleVisibility* vis = (const nsStyleVisibility*)mStyleContext->GetStyleData(eStyleStruct_Visibility);
if ((vis != nsnull) && !vis->IsVisibleOrCollapsed())
return NS_OK;
nsIFrame * child = mFrames.FirstChild();
if (child) { // if we have children, we are probably not really a plugin
nsObjectFrameSuper::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
return NS_OK;
}
// If we are painting in Print Preview do nothing....
nsCOMPtr<nsIPrintPreviewContext> thePrintPreviewContext = do_QueryInterface(aPresContext);
if (thePrintPreviewContext) {
return NS_OK;
}
// determine if we are printing
nsCOMPtr<nsIPrintContext> thePrinterContext = do_QueryInterface(aPresContext);
if (thePrinterContext) {
// UNIX Plugins can't PP at this time, so draw an empty box
// we only want to print on the content layer pass
if (eFramePaintLayer_Content != aWhichLayer)
return NS_OK;
// if we are printing, we need to get the correct nsIPluginInstance
// for THIS content node in order to call ->Print() on the right plugin
// first, we need to get the document
nsCOMPtr<nsIDocument> doc;
mContent->GetDocument(*getter_AddRefs(doc));
NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);
// now we need to get the shell for the screen
// XXX assuming that the shell at zero will always be the screen one
nsCOMPtr<nsIPresShell> shell;
doc->GetShellAt(0, getter_AddRefs(shell));
NS_ENSURE_TRUE(shell, NS_ERROR_NULL_POINTER);
// then the shell can give us the screen frame for this content node
nsIFrame* frame = nsnull;
shell->GetPrimaryFrameFor(mContent, &frame);
NS_ENSURE_TRUE(frame, NS_ERROR_NULL_POINTER);
// make sure this is REALLY an nsIObjectFrame
// we may need to go through the children to get it
nsIObjectFrame* objectFrame = nsnull;
CallQueryInterface(frame,&objectFrame);
if (!objectFrame)
GetNextObjectFrame(aPresContext,frame,&objectFrame);
NS_ENSURE_TRUE(objectFrame,NS_ERROR_FAILURE);
// finally we can get our plugin instance
nsCOMPtr<nsIPluginInstance> pi;
if (NS_FAILED(objectFrame->GetPluginInstance(*getter_AddRefs(pi))) || !pi)
return NS_ERROR_FAILURE;
// now we need to setup the correct location for printing
nsresult rv;
nsPluginWindow window;
nsIView *parentWithView;
nsPoint origin;
float t2p;
nsMargin margin(0,0,0,0);
window.window = nsnull;
// prepare embedded mode printing struct
nsPluginPrint npprint;
npprint.mode = nsPluginMode_Embedded;
// we need to find out if we are windowless or not
PRBool windowless = PR_FALSE;
pi->GetValue(nsPluginInstanceVariable_WindowlessBool, (void *)&windowless);
window.type = windowless ? nsPluginWindowType_Drawable : nsPluginWindowType_Window;
// get a few things
nsCOMPtr<nsIPrintSettings> printSettings;
if (thePrinterContext) {
thePrinterContext->GetPrintSettings(getter_AddRefs(printSettings));
NS_ENSURE_TRUE(printSettings, NS_ERROR_FAILURE);
printSettings->GetMarginInTwips(margin);
}
aPresContext->GetTwipsToPixels(&t2p);
GetOffsetFromView(aPresContext, origin, &parentWithView);
// set it all up
// XXX is windowless different?
window.x = NSToCoordRound((origin.x + margin.left) * t2p);
window.y = NSToCoordRound((origin.y + margin.top ) * t2p);
window.width = NSToCoordRound(mRect.width * t2p);
window.height= NSToCoordRound(mRect.height * t2p);
window.clipRect.bottom = 0; window.clipRect.top = 0;
window.clipRect.left = 0; window.clipRect.right = 0;
// XXX platform specific printing code
#if defined(XP_MAC) && !TARGET_CARBON
// Mac does things a little differently.
GrafPort *curPort;
::GetPort(&curPort); // get the current port
nsPluginPort port;
port.port = (CGrafPort*)curPort;
port.portx = window.x;
port.porty = window.y;
RgnHandle curClip = ::NewRgn();
NS_ENSURE_TRUE(curClip, NS_ERROR_NULL_POINTER);
::GetClip(curClip); // save old clip
::SetOrigin(-window.x,-window.y); // port must be set correctly prior to telling plugin to print
Rect r = {0,0,window.height,window.width};
::ClipRect(&r); // also set the clip
window.window = &port;
npprint.print.embedPrint.platformPrint = (void*)window.window;
#elif defined (XP_UNIX)
// UNIX does things completely differently
PRUnichar *printfile = nsnull;
if (printSettings) {
printSettings->GetToFileName(&printfile);
}
if (!printfile)
return NS_OK; // XXX what to do on UNIX when we don't have a PS file????
NPPrintCallbackStruct npPrintInfo;
npPrintInfo.type = NP_PRINT;
npPrintInfo.fp = (FILE*)printfile;
npprint.print.embedPrint.platformPrint = (void*) &npPrintInfo;
#else // Windows and non-UNIX, non-Mac(Classic) cases
// we need the native printer device context to pass to plugin
// On Windows, this will be the HDC
PRUint32 pDC = 0;
aRenderingContext.RetrieveCurrentNativeGraphicData(&pDC);
if (!pDC)
return NS_OK; // no dc implemented so quit
npprint.print.embedPrint.platformPrint = (void*)pDC;
#endif
npprint.print.embedPrint.window = window;
// send off print info to plugin
rv = pi->Print(&npprint);
#if defined(XP_MAC) && !TARGET_CARBON
// Clean-up on Mac
::SetOrigin(0,0);
::SetClip(curClip); // restore previous clip
::DisposeRgn(curClip);
#endif
// XXX Nav 4.x always sent a SetWindow call after print. Should we do the same?
nsCOMPtr<nsIPresContext> screenPcx;
shell->GetPresContext(getter_AddRefs(screenPcx));
nsDidReflowStatus status = NS_FRAME_REFLOW_FINISHED; // should we use a special status?
frame->DidReflow(screenPcx, nsnull, status); // DidReflow will take care of it
return rv; // done with printing
}
// Screen painting code
#if defined (XP_MAC)
// delegate all painting to the plugin instance.
if ((NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) && (nsnull != mInstanceOwner))
mInstanceOwner->Paint(aDirtyRect);
#elif defined (XP_PC)
if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
nsIPluginInstance * inst;
if (NS_OK == GetPluginInstance(inst)) {
// Look if it's windowless
nsPluginWindow * window;
mInstanceOwner->GetWindow(window);
if (window->type == nsPluginWindowType_Drawable) {
// check if we need to call SetWindow with updated parameters
PRBool doupdatewindow = PR_FALSE;
// check if we need to update hdc
PRUint32 hdc;
aRenderingContext.RetrieveCurrentNativeGraphicData(&hdc);
if(NS_REINTERPRET_CAST(PRUint32, window->window) != hdc) {
window->window = NS_REINTERPRET_CAST(nsPluginPort*, hdc);
doupdatewindow = PR_TRUE;
}
/*
* Layout now has an optimized way of painting. Now we always get
* a new drawing surface, sized to be just what's needed. Windowsless
* plugins need a transform applied to their origin so they paint
* in the right place. Since |SetWindow| is no longer being used
* to tell the plugin where it is, we dispatch a NPWindow through
* |HandleEvent| to tell the plugin when its window moved
*/
// Get the offset of the DC
nsTransform2D* rcTransform;
aRenderingContext.GetCurrentTransform(rcTransform);
nsPoint origin;
rcTransform->GetTranslationCoord(&origin.x, &origin.y);
if((window->x != origin.x) || (window->y != origin.y)) {
window->x = origin.x;
window->y = origin.y;
doupdatewindow = PR_TRUE;
}
// if our location or visible area has changed, we need to tell the plugin
if(doupdatewindow) {
#ifdef XP_WIN // Windowless plugins on windows need a special event to update their location, see bug 135737
// first, lets find out how big the window is, in pixels
nsCOMPtr<nsIPresShell> shell;
nsCOMPtr<nsIViewManager> vm;
aPresContext->GetShell(getter_AddRefs(shell));
if (shell) {
shell->GetViewManager(getter_AddRefs(vm));
if (vm) {
nsIView* view;
vm->GetRootView(view);
if (view) {
nsCOMPtr<nsIWidget> win;
view->GetWidget(*getter_AddRefs(win));
if (win) {
nsRect visibleRect;
win->GetBounds(visibleRect);
// next, get our plugin's rect so we can intersect it with the visible rect so we
// can tell the plugin where and how much to paint
GetWindowOriginInPixels(aPresContext, window->type, &origin);
nsRect winlessRect = nsRect(origin, nsSize(window->width, window->height));
winlessRect.IntersectRect(winlessRect, visibleRect);
// now check our cached window and only update plugin if something has changed
if (mWindowlessRect != winlessRect) {
mWindowlessRect = winlessRect;
WINDOWPOS winpos;
memset(&winpos, 0, sizeof(winpos));
winpos.x = mWindowlessRect.x;
winpos.y = mWindowlessRect.y;
winpos.cx = mWindowlessRect.width;
winpos.cy = mWindowlessRect.height;
// finally, update the plugin by sending it a WM_WINDOWPOSCHANGED event
nsPluginEvent pluginEvent;
pluginEvent.event = 0x0047;
pluginEvent.wParam = 0;
pluginEvent.lParam = (uint32)&winpos;
PRBool eventHandled = PR_FALSE;
inst->HandleEvent(&pluginEvent, &eventHandled);
mInstanceOwner->ReleasePluginPort((nsPluginPort *)winpos.hwnd);
}
}
}
}
}
#endif
inst->SetWindow(window);
}
mInstanceOwner->Paint(aDirtyRect, hdc);
}
NS_RELEASE(inst);
}
}
#endif /* !XP_MAC */
DO_GLOBAL_REFLOW_COUNT_DSP("nsObjectFrame", &aRenderingContext);
return NS_OK;
}
NS_IMETHODIMP
nsObjectFrame::HandleEvent(nsIPresContext* aPresContext,
nsGUIEvent* anEvent,
nsEventStatus* anEventStatus)
{
NS_ENSURE_ARG_POINTER(anEventStatus);
nsresult rv = NS_OK;
//FIX FOR CRASHING WHEN NO INSTANCE OWVER
if (!mInstanceOwner)
return NS_ERROR_NULL_POINTER;
if (anEvent->message == NS_PLUGIN_ACTIVATE)
{
nsCOMPtr<nsIContent> content;
GetContent(getter_AddRefs(content));
if (content)
{
content->SetFocus(aPresContext);
return rv;
}
}
#ifdef XP_WIN
rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
return rv;
#endif
switch (anEvent->message) {
case NS_DESTROY:
mInstanceOwner->CancelTimer();
break;
case NS_GOTFOCUS:
case NS_LOSTFOCUS:
*anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
break;
default:
// instead of using an event listener, we can dispatch events to plugins directly.
rv = nsObjectFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
}
return rv;
}
nsresult
nsObjectFrame::Scrolled(nsIView *aView)
{
return NS_OK;
}
nsresult
nsObjectFrame::SetFullURL(nsIURI* aURL)
{
NS_IF_RELEASE(mFullURL);
mFullURL = aURL;
NS_IF_ADDREF(mFullURL);
return NS_OK;
}
nsresult nsObjectFrame::GetFullURL(nsIURI*& aFullURL)
{
aFullURL = mFullURL;
NS_IF_ADDREF(aFullURL);
return NS_OK;
}
nsresult nsObjectFrame::GetPluginInstance(nsIPluginInstance*& aPluginInstance)
{
aPluginInstance = nsnull;
if(mInstanceOwner == nsnull)
return NS_ERROR_NULL_POINTER;
else
return mInstanceOwner->GetInstance(aPluginInstance);
}
nsresult
nsObjectFrame::NotifyContentObjectWrapper()
{
nsCOMPtr<nsIDocument> doc;
mContent->GetDocument(*getter_AddRefs(doc));
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIScriptGlobalObject> sgo;
doc->GetScriptGlobalObject(getter_AddRefs(sgo));
NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIScriptContext> scx;
sgo->GetContext(getter_AddRefs(scx));
NS_ENSURE_TRUE(scx, NS_ERROR_UNEXPECTED);
JSContext *cx = (JSContext *)scx->GetNativeContext();
nsresult rv = NS_OK;
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
xpc->GetWrappedNativeOfNativeObject(cx, ::JS_GetGlobalObject(cx), mContent,
NS_GET_IID(nsISupports),
getter_AddRefs(wrapper));
if (!wrapper) {
// Nothing to do here if there's no wrapper for mContent
return NS_OK;
}
nsCOMPtr<nsIClassInfo> ci(do_QueryInterface(mContent));
NS_ENSURE_TRUE(ci, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsISupports> s;
ci->GetHelperForLanguage(nsIProgrammingLanguage::JAVASCRIPT,
getter_AddRefs(s));
nsCOMPtr<nsIXPCScriptable> helper(do_QueryInterface(s));
if (!helper) {
// There's nothing we can do if there's no helper
return NS_OK;
}
JSObject *obj = nsnull;
rv = wrapper->GetJSObject(&obj);
NS_ENSURE_SUCCESS(rv, rv);
// Abuse the scriptable helper to trigger prototype setup for the
// wrapper for mContent so that this plugin becomes part of the DOM
// object.
return helper->PostCreate(wrapper, cx, obj);
}
nsresult
nsObjectFrame::GetNextObjectFrame(nsIPresContext* aPresContext,
nsIFrame* aRoot,
nsIObjectFrame** outFrame)
{
NS_ENSURE_ARG_POINTER(outFrame);
nsIFrame * child;
aRoot->FirstChild(aPresContext, nsnull, &child);
while (child != nsnull) {
*outFrame = nsnull;
CallQueryInterface(child, outFrame);
if (nsnull != *outFrame) {
nsCOMPtr<nsIPluginInstance> pi;
(*outFrame)->GetPluginInstance(*getter_AddRefs(pi)); // make sure we have a REAL plugin
if (pi) return NS_OK;
}
GetNextObjectFrame(aPresContext, child, outFrame);
child->GetNextSibling(&child);
}
return NS_ERROR_FAILURE;
}
nsresult
NS_NewObjectFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
{
NS_PRECONDITION(aNewFrame, "null OUT ptr");
if (nsnull == aNewFrame) {
return NS_ERROR_NULL_POINTER;
}
nsObjectFrame* it = new (aPresShell) nsObjectFrame;
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
*aNewFrame = it;
return NS_OK;
}
// nsPluginDOMContextMenuListener class implementation
nsPluginDOMContextMenuListener::nsPluginDOMContextMenuListener()
{
NS_INIT_REFCNT();
}
nsPluginDOMContextMenuListener::~nsPluginDOMContextMenuListener()
{
}
NS_IMPL_ISUPPORTS2(nsPluginDOMContextMenuListener, nsIDOMContextMenuListener, nsIEventListener);
nsresult nsPluginDOMContextMenuListener::Init(nsObjectFrame *aFrame)
{
nsCOMPtr<nsIContent> content;
aFrame->GetContent(getter_AddRefs(content));
// Register context menu listener
if (content) {
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(content));
if (receiver) {
nsCOMPtr<nsIDOMContextMenuListener> cxMenuListener;
QueryInterface(NS_GET_IID(nsIDOMContextMenuListener), getter_AddRefs(cxMenuListener));
if (cxMenuListener) {
receiver->AddEventListener(NS_LITERAL_STRING("contextmenu"), cxMenuListener, PR_TRUE);
return NS_OK;
}
}
}
return NS_ERROR_NO_INTERFACE;
}
nsresult nsPluginDOMContextMenuListener::Destroy(nsObjectFrame *aFrame)
{
nsCOMPtr<nsIContent> content;
aFrame->GetContent(getter_AddRefs(content));
// Unregister context menu listener
if (content) {
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(content));
if (receiver) {
nsCOMPtr<nsIDOMContextMenuListener> cxMenuListener;
QueryInterface(NS_GET_IID(nsIDOMContextMenuListener), getter_AddRefs(cxMenuListener));
if (cxMenuListener) {
receiver->RemoveEventListenerByIID(cxMenuListener, NS_GET_IID(nsIDOMContextMenuListener));
}
else NS_ASSERTION(PR_FALSE, "Unable to remove event listener for plugin");
}
else NS_ASSERTION(PR_FALSE, "plugin was not an event listener");
}
else NS_ASSERTION(PR_FALSE, "plugin had no content");
return NS_OK;
}
//plugin instance owner
nsPluginInstanceOwner::nsPluginInstanceOwner()
{
NS_INIT_REFCNT();
memset(&mPluginWindow, 0, sizeof(mPluginWindow));
mInstance = nsnull;
mOwner = nsnull;
mWidget = nsnull;
mContext = nsnull;
mTagText = nsnull;
mPluginHost = nsnull;
mContentFocused = PR_FALSE;
mWidgetVisible = PR_TRUE;
mNumCachedAttrs = 0;
mNumCachedParams = 0;
mCachedAttrParamNames = nsnull;
mCachedAttrParamValues = nsnull;
}
nsPluginInstanceOwner::~nsPluginInstanceOwner()
{
PRInt32 cnt;
// shut off the timer.
if (mPluginTimer != nsnull) {
CancelTimer();
}
NS_IF_RELEASE(mInstance);
NS_IF_RELEASE(mPluginHost);
mOwner = nsnull;
for (cnt = 0; cnt < (mNumCachedAttrs + 1 + mNumCachedParams); cnt++) {
if ((nsnull != mCachedAttrParamNames) && (nsnull != mCachedAttrParamNames[cnt])) {
PR_Free(mCachedAttrParamNames[cnt]);
mCachedAttrParamNames[cnt] = nsnull;
}
if ((nsnull != mCachedAttrParamValues) && (nsnull != mCachedAttrParamValues[cnt])) {
PR_Free(mCachedAttrParamValues[cnt]);
mCachedAttrParamValues[cnt] = nsnull;
}
}
if (nsnull != mCachedAttrParamNames) {
PR_Free(mCachedAttrParamNames);
mCachedAttrParamNames = nsnull;
}
if (nsnull != mCachedAttrParamValues) {
PR_Free(mCachedAttrParamValues);
mCachedAttrParamValues = nsnull;
}
if (nsnull != mTagText) {
nsCRT::free(mTagText);
mTagText = nsnull;
}
NS_IF_RELEASE(mWidget);
mContext = nsnull;
#ifdef XP_UNIX
// the mem for this struct is allocated
// by PR_MALLOC in ns4xPluginInstance.cpp:ns4xPluginInstance::SetWindow()
if (mPluginWindow.ws_info) {
PR_Free(mPluginWindow.ws_info);
mPluginWindow.ws_info = nsnull;
}
#endif
}
/*
* nsISupports Implementation
*/
NS_IMPL_ADDREF(nsPluginInstanceOwner)
NS_IMPL_RELEASE(nsPluginInstanceOwner)
NS_INTERFACE_MAP_BEGIN(nsPluginInstanceOwner)
NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner)
NS_INTERFACE_MAP_ENTRY(nsIPluginTagInfo)
NS_INTERFACE_MAP_ENTRY(nsIPluginTagInfo2)
NS_INTERFACE_MAP_ENTRY(nsIJVMPluginTagInfo)
NS_INTERFACE_MAP_ENTRY(nsIEventListener)
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener)
NS_INTERFACE_MAP_ENTRY(nsIDOMMouseMotionListener)
NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
NS_INTERFACE_MAP_ENTRY(nsIDOMFocusListener)
NS_INTERFACE_MAP_ENTRY(nsIScrollPositionListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPluginInstanceOwner)
NS_INTERFACE_MAP_END
NS_IMETHODIMP nsPluginInstanceOwner::SetInstance(nsIPluginInstance *aInstance)
{
NS_IF_RELEASE(mInstance);
mInstance = aInstance;
NS_IF_ADDREF(mInstance);
return NS_OK;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetWindow(nsPluginWindow *&aWindow)
{
aWindow = &mPluginWindow;
return NS_OK;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetMode(nsPluginMode *aMode)
{
*aMode = nsPluginMode_Embedded;
return NS_OK;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetAttributes(PRUint16& n,
const char*const*& names,
const char*const*& values)
{
nsresult rv = EnsureCachedAttrParamArrays();
NS_ENSURE_SUCCESS(rv, rv);
n = mNumCachedAttrs;
names = (const char **)mCachedAttrParamNames;
values = (const char **)mCachedAttrParamValues;
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetAttribute(const char* name, const char* *result)
{
NS_ENSURE_ARG_POINTER(name);
NS_ENSURE_ARG_POINTER(result);
nsresult rv = EnsureCachedAttrParamArrays();
NS_ENSURE_SUCCESS(rv, rv);
*result = nsnull;
for (int i = 0; i < mNumCachedAttrs; i++) {
if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
*result = mCachedAttrParamValues[i];
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetDOMElement(nsIDOMElement* *result)
{
NS_ENSURE_ARG_POINTER(result);
nsresult rv = NS_ERROR_FAILURE;
*result = nsnull;
if (nsnull != mOwner)
{
nsIContent *cont;
mOwner->GetContent(&cont);
if (nsnull != cont)
{
rv = cont->QueryInterface(NS_GET_IID(nsIDOMElement), (void **)result);
NS_RELEASE(cont);
}
}
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetInstance(nsIPluginInstance *&aInstance)
{
if (nsnull != mInstance)
{
aInstance = mInstance;
NS_ADDREF(mInstance);
return NS_OK;
}
else
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL, const char *aTarget, void *aPostData, PRUint32 aPostDataLen, void *aHeadersData,
PRUint32 aHeadersDataLen, PRBool isFile)
{
NS_ENSURE_TRUE(mOwner,NS_ERROR_NULL_POINTER);
NS_ENSURE_TRUE(mContext,NS_ERROR_NULL_POINTER);
// the container of the pres context will give us the link handler
nsCOMPtr<nsISupports> container;
nsresult rv = mContext->GetContainer(getter_AddRefs(container));
NS_ENSURE_TRUE(container,NS_ERROR_FAILURE);
nsCOMPtr<nsILinkHandler> lh = do_QueryInterface(container);
NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE);
nsAutoString uniurl; uniurl.AssignWithConversion(aURL);
nsAutoString unitarget; unitarget.AssignWithConversion(aTarget);
nsAutoString fullurl;
nsCOMPtr<nsIURI> baseURL;
nsCOMPtr<nsIDocument> doc;
rv = GetDocument(getter_AddRefs(doc));
if (NS_SUCCEEDED(rv) && doc) {
rv = doc->GetBaseURL(*getter_AddRefs(baseURL)); // gets the document's url
} else {
mOwner->GetFullURL(*getter_AddRefs(baseURL)); // gets the plugin's content url
}
// Create an absolute URL
NS_MakeAbsoluteURI(fullurl, uniurl, baseURL);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv),NS_ERROR_FAILURE);
nsCOMPtr<nsIContent> content;
mOwner->GetContent(getter_AddRefs(content));
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
nsCOMPtr<nsIInputStream> postDataStream;
nsCOMPtr<nsIInputStream> headersDataStream;
// deal with post data, either in a file or raw data, and any headers
if (aPostData) {
rv = NS_NewPluginPostDataStream(getter_AddRefs(postDataStream), (const char *)aPostData, aPostDataLen, isFile);
NS_ASSERTION(NS_SUCCEEDED(rv),"failed in creating plugin post data stream");
if (NS_FAILED(rv)) return rv;
if (aHeadersData) {
rv = NS_NewPluginPostDataStream(getter_AddRefs(headersDataStream),
(const char *) aHeadersData,
aHeadersDataLen,
PR_FALSE,
PR_TRUE); // last arg says we are headers, no /r/n/r/n fixup!
NS_ASSERTION(NS_SUCCEEDED(rv),"failed in creating plugin header data stream");
if (NS_FAILED(rv)) return rv;
}
}
rv = lh->OnLinkClick(content, eLinkVerb_Replace,
fullurl.get(), unitarget.get(),
postDataStream, headersDataStream);
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const char *aStatusMsg)
{
nsresult rv = NS_ERROR_FAILURE;
rv = this->ShowStatus(NS_ConvertUTF8toUCS2(aStatusMsg).get());
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::ShowStatus(const PRUnichar *aStatusMsg)
{
nsresult rv = NS_ERROR_FAILURE;
if (!mContext) {
return rv;
}
nsCOMPtr<nsISupports> cont;
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
rv = mContext->GetContainer(getter_AddRefs(cont));
if (NS_FAILED(rv) || !cont) {
return rv;
}
nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(cont, &rv));
if (NS_FAILED(rv) || !docShellItem) {
return rv;
}
rv = docShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
if (NS_FAILED(rv) || !treeOwner) {
return rv;
}
nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner, &rv));
if (NS_FAILED(rv) || !browserChrome) {
return rv;
}
rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
aStatusMsg);
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument)
{
nsresult rv = NS_ERROR_FAILURE;
if (nsnull != mContext) {
nsCOMPtr<nsIPresShell> shell;
mContext->GetShell(getter_AddRefs(shell));
rv = shell->GetDocument(aDocument);
}
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(nsPluginRect *invalidRect)
{
nsresult rv = NS_ERROR_FAILURE;
if(invalidRect)
{
//no reference count on view
nsIView* view;
rv = mOwner->GetView(mContext, &view);
if((rv == NS_OK) && view)
{
float ptot;
mContext->GetPixelsToTwips(&ptot);
nsRect rect((int)(ptot * invalidRect->left),
(int)(ptot * invalidRect->top),
(int)(ptot * (invalidRect->right - invalidRect->left)),
(int)(ptot * (invalidRect->bottom - invalidRect->top)));
nsIViewManager* manager;
rv = view->GetViewManager(manager);
//set flags to not do a synchronous update, force update does the redraw
if((rv == NS_OK) && manager)
{
rv = manager->UpdateView(view, rect, NS_VMREFRESH_NO_SYNC);
NS_RELEASE(manager);
}
}
}
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(nsPluginRegion invalidRegion)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsPluginInstanceOwner::ForceRedraw()
{
//no reference count on view
nsIView* view;
nsresult rv = mOwner->GetView(mContext, &view);
if((rv == NS_OK) && view)
{
nsIViewManager* manager;
rv = view->GetViewManager(manager);
if((rv == NS_OK) && manager)
{
rv = manager->Composite();
NS_RELEASE(manager);
}
}
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetValue(nsPluginInstancePeerVariable variable, void *value)
{
nsresult rv = NS_ERROR_FAILURE;
switch(variable)
{
case nsPluginInstancePeerVariable_NetscapeWindow:
{
// get the document's widget from the view manager
// get the view manager from the pres shell, not from the view!
// we may not have a view if we are hidden
if (mContext) {
nsCOMPtr<nsIPresShell> shell;
mContext->GetShell(getter_AddRefs(shell));
if (shell) {
nsCOMPtr<nsIViewManager> vm;
shell->GetViewManager(getter_AddRefs(vm));
if (vm) {
nsCOMPtr<nsIWidget> widget;
rv = vm->GetWidget(getter_AddRefs(widget));
if(widget) {
void** pvalue = (void**)value;
*pvalue = (void*)widget->GetNativeData(NS_NATIVE_WINDOW);
} else NS_ASSERTION(widget, "couldn't get doc's widget in getting doc's window handle");
} else NS_ASSERTION(vm, "couldn't get view manager in getting doc's window handle");
} else NS_ASSERTION(shell, "couldn't get pres shell in getting doc's window handle");
} else NS_ASSERTION(mContext, "plugin owner has no pres context in getting doc's window handle");
break;
}
}
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetTagType(nsPluginTagType *result)
{
NS_ENSURE_ARG_POINTER(result);
nsresult rv = NS_ERROR_FAILURE;
*result = nsPluginTagType_Unknown;
if (nsnull != mOwner)
{
nsIContent *cont;
mOwner->GetContent(&cont);
if (nsnull != cont)
{
nsIAtom *atom;
cont->GetTag(atom);
if (nsnull != atom)
{
if (atom == nsHTMLAtoms::applet)
*result = nsPluginTagType_Applet;
else if (atom == nsHTMLAtoms::embed)
*result = nsPluginTagType_Embed;
else if (atom == nsHTMLAtoms::object)
*result = nsPluginTagType_Object;
rv = NS_OK;
NS_RELEASE(atom);
}
NS_RELEASE(cont);
}
}
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetTagText(const char* *result)
{
NS_ENSURE_ARG_POINTER(result);
if (nsnull == mTagText) {
nsresult rv;
nsCOMPtr<nsIContent> content;
rv = mOwner->GetContent(getter_AddRefs(content));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content, &rv));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIDocument> document;
rv = GetDocument(getter_AddRefs(document));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIDocumentEncoder> docEncoder(do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "text/html", &rv));
if (NS_FAILED(rv))
return rv;
rv = docEncoder->Init(document, NS_LITERAL_STRING("text/html"), nsIDocumentEncoder::OutputEncodeEntities);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIDOMRange> range(do_CreateInstance(kRangeCID,&rv));
if (NS_FAILED(rv))
return rv;
rv = range->SelectNode(node);
if (NS_FAILED(rv))
return rv;
docEncoder->SetRange(range);
nsString elementHTML;
rv = docEncoder->EncodeToString(elementHTML);
if (NS_FAILED(rv))
return rv;
mTagText = ToNewUTF8String(elementHTML);
if (!mTagText)
return NS_ERROR_OUT_OF_MEMORY;
}
*result = mTagText;
return NS_OK;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetParameters(PRUint16& n, const char*const*& names, const char*const*& values)
{
nsresult rv = EnsureCachedAttrParamArrays();
NS_ENSURE_SUCCESS(rv, rv);
n = mNumCachedParams;
if (n) {
names = (const char **)(mCachedAttrParamNames + mNumCachedAttrs + 1);
values = (const char **)(mCachedAttrParamValues + mNumCachedAttrs + 1);
} else
names = values = nsnull;
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetParameter(const char* name, const char* *result)
{
NS_ENSURE_ARG_POINTER(name);
NS_ENSURE_ARG_POINTER(result);
nsresult rv = EnsureCachedAttrParamArrays();
NS_ENSURE_SUCCESS(rv, rv);
*result = nsnull;
for (int i = mNumCachedAttrs + 1; i < (mNumCachedParams + 1 + mNumCachedAttrs); i++) {
if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
*result = mCachedAttrParamValues[i];
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetDocumentBase(const char* *result)
{
NS_ENSURE_ARG_POINTER(result);
nsresult rv = NS_OK;
if (mDocumentBase.IsEmpty()) {
if (nsnull == mContext) {
*result = nsnull;
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIPresShell> shell;
mContext->GetShell(getter_AddRefs(shell));
nsCOMPtr<nsIDocument> doc;
shell->GetDocument(getter_AddRefs(doc));
nsCOMPtr<nsIURI> docURL;
doc->GetBaseURL(*getter_AddRefs(docURL)); // should return base + doc url
rv = docURL->GetSpec(mDocumentBase);
}
if (rv == NS_OK)
*result = ToNewCString(mDocumentBase);
return rv;
}
static nsHashtable *gCharsetMap = nsnull;
typedef struct {
char *mozName;
char *javaName;
} moz2javaCharset;
static const moz2javaCharset charsets[] =
{
{"windows-1252", "Cp1252"},
{"IBM850", "Cp850"},
{"IBM852", "Cp852"},
{"IBM855", "Cp855"},
{"IBM857", "Cp857"},
{"IBM828", "Cp862"},
{"IBM864", "Cp864"},
{"IBM866", "Cp866"},
{"windows-1250", "Cp1250"},
{"windows-1251", "Cp1251"},
{"windows-1253", "Cp1253"},
{"windows-1254", "Cp1254"},
{"windows-1255", "Cp1255"},
{"windows-1256", "Cp1256"},
{"windows-1257", "Cp1257"},
{"windows-1258", "Cp1258"},
{"EUC-JP", "EUC_JP"},
{"EUC-KR", "EUC_KR"},
{"x-euc-tw", "EUC_TW"},
{"gb18030", "GB18030"},
{"x-gbk", "GBK"},
{"ISO-2022-JP", "ISO2022JP"},
{"ISO-2022-KR", "ISO2022KR"},
{"ISO-8859-2", "ISO8859_2"},
{"ISO-8859-3", "ISO8859_3"},
{"ISO-8859-4", "ISO8859_4"},
{"ISO-8859-5", "ISO8859_5"},
{"ISO-8859-6", "ISO8859_6"},
{"ISO-8859-7", "ISO8859_7"},
{"ISO-8859-8", "ISO8859_8"},
{"ISO-8859-9", "ISO8859_9"},
{"ISO-8859-13", "ISO8859_13"},
{"x-johab", "Johab"},
{"KOI8-R", "KOI8_R"},
{"TIS-620", "MS874"},
{"windows-936", "MS936"},
{"x-windows-949", "MS949"},
{"x-mac-arabic", "MacArabic"},
{"x-mac-croatian", "MacCroatia"},
{"x-mac-cyrillic", "MacCyrillic"},
{"x-mac-greek", "MacGreek"},
{"x-mac-hebrew", "MacHebrew"},
{"x-mac-icelandic", "MacIceland"},
{"x-mac-roman", "MacRoman"},
{"x-mac-romanian", "MacRomania"},
{"x-mac-ukrainian", "MacUkraine"},
{"Shift_JIS", "SJIS"},
{"TIS-620", "TIS620"}
};
NS_IMETHODIMP nsPluginInstanceOwner::GetDocumentEncoding(const char* *result)
{
NS_ENSURE_ARG_POINTER(result);
*result = nsnull;
nsresult rv;
nsCOMPtr<nsIDocument> doc;
rv = GetDocument(getter_AddRefs(doc));
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get document");
if (NS_FAILED(rv)) return rv;
nsString charset;
rv = doc->GetDocumentCharacterSet(charset);
NS_ASSERTION(NS_SUCCEEDED(rv), "can't get charset");
if (NS_FAILED(rv)) return rv;
if (charset.IsEmpty()) return NS_OK;
// common charsets and those not requiring conversion first
if (charset == NS_LITERAL_STRING("us-acsii")) {
*result = PL_strdup("US_ASCII");
} else if (charset == NS_LITERAL_STRING("ISO-8859-1") ||
!nsCRT::strncmp(charset.get(), NS_LITERAL_STRING("UTF").get(), 3)) {
*result = ToNewUTF8String(charset);
} else {
if (!gCharsetMap) {
gCharsetMap = new nsHashtable(sizeof(charsets)/sizeof(moz2javaCharset));
if (!gCharsetMap) return NS_ERROR_OUT_OF_MEMORY;
for (PRUint16 i = 0; i < sizeof(charsets)/sizeof(moz2javaCharset); i++) {
nsCStringKey key(charsets[i].mozName);
gCharsetMap->Put(&key, (void *)(charsets[i].javaName));
}
}
nsCStringKey mozKey(NS_LossyConvertUCS2toASCII(charset).get());
// if found mapping, return it; otherwise return original charset
char *mapping = (char *)gCharsetMap->Get(&mozKey);
*result = mapping ? PL_strdup(mapping) : ToNewUTF8String(charset);
}
return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetAlignment(const char* *result)
{
return GetAttribute("ALIGN", result);
}
NS_IMETHODIMP nsPluginInstanceOwner::GetWidth(PRUint32 *result)
{
NS_ENSURE_ARG_POINTER(result);
*result = mPluginWindow.width;
return NS_OK;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetHeight(PRUint32 *result)
{
NS_ENSURE_ARG_POINTER(result);
*result = mPluginWindow.height;
return NS_OK;
}
// it would indicate a serious error in the frame model if aContainingBlock were null when
// GetContainingBlock returns
static nsresult
GetContainingBlock(nsIFrame *aFrame, nsIFrame **aContainingBlock)
{
NS_ENSURE_ARG_POINTER(aFrame);
NS_ENSURE_ARG_POINTER(aContainingBlock);
*aContainingBlock = nsnull;
nsIFrame *containingBlock = aFrame;
while (containingBlock) {
PRBool isContainingBlock=PR_FALSE;
nsresult rv = containingBlock->IsPercentageBase(isContainingBlock);
NS_ENSURE_SUCCESS(rv, rv);
if (isContainingBlock)
{
*aContainingBlock = containingBlock;
break;
}
containingBlock->GetParent(&containingBlock);
}
NS_POSTCONDITION(*aContainingBlock, "bad frame model, this object frame has no containing block");
return NS_OK;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetBorderVertSpace(PRUint32 *result)
{
nsresult rv;
const char *vspace;
rv = GetAttribute("VSPACE", &vspace);
if (NS_OK == rv)
{
if (*result != 0)
*result = (PRUint32)atol(vspace);
else
*result = 0;
}
else
*result = 0;
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetBorderHorizSpace(PRUint32 *result)
{
nsresult rv;
const char *hspace;
rv = GetAttribute("HSPACE", &hspace);
if (NS_OK == rv)
{
if (*result != 0)
*result = (PRUint32)atol(hspace);
else
*result = 0;
}
else
*result = 0;
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetUniqueID(PRUint32 *result)
{
NS_ENSURE_ARG_POINTER(result);
*result = NS_PTR_TO_INT32(mContext);
return NS_OK;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetCode(const char* *result)
{
nsresult rv;
nsPluginTagType tagType;
NS_ENSURE_SUCCESS(rv = GetTagType(&tagType), rv);
rv = NS_ERROR_FAILURE;
if (nsPluginTagType_Object != tagType)
rv = GetAttribute("CODE", result);
if (NS_FAILED(rv))
rv = GetParameter("CODE", result);
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetCodeBase(const char* *result)
{
nsresult rv;
if (NS_FAILED(rv = GetAttribute("CODEBASE", result)))
rv = GetParameter("CODEBASE", result);
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetArchive(const char* *result)
{
nsresult rv;
if (NS_FAILED(rv = GetAttribute("ARCHIVE", result)))
rv = GetParameter("ARCHIVE", result);
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetName(const char* *result)
{
nsresult rv;
nsPluginTagType tagType;
NS_ENSURE_SUCCESS(rv = GetTagType(&tagType), rv);
rv = NS_ERROR_FAILURE;
if (nsPluginTagType_Object != tagType)
rv = GetAttribute("NAME", result);
if (NS_FAILED(rv))
rv = GetParameter("NAME", result);
return rv;
}
NS_IMETHODIMP nsPluginInstanceOwner::GetMayScript(PRBool *result)
{
NS_ENSURE_ARG_POINTER(result);
nsPluginTagType tagType;
NS_ENSURE_SUCCESS(GetTagType(&tagType), NS_ERROR_FAILURE);
const char* unused;
if (nsPluginTagType_Object == tagType)
*result = NS_SUCCEEDED(GetParameter("MAYSCRIPT", &unused));
else
*result = NS_SUCCEEDED(GetAttribute("MAYSCRIPT", &unused));
return NS_OK;
}
// Cache the attributes and/or parameters of our tag into a single set of arrays
// to be compatible with 4.x. The attributes go first, followed by a PARAM/null and
// then any PARAM tags. Also, hold the cached array around for the duration
// of the life of the instance because 4.x did. See bug 111008.
nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays()
{
if (mCachedAttrParamValues)
return NS_OK;
NS_PRECONDITION((((mNumCachedAttrs + mNumCachedParams) == 0) && !mCachedAttrParamNames),
"re-cache of attrs/params not implemented! use the DOM node directy instead");
NS_ENSURE_TRUE(mOwner, NS_ERROR_NULL_POINTER);
// first, we need to find out how much we need to allocate for our arrays
// count up attributes
mNumCachedAttrs = 0;
nsCOMPtr<nsIContent> content;
nsresult rv = mOwner->GetContent(getter_AddRefs(content));
NS_ENSURE_TRUE(content, rv);
PRInt32 cattrs;
rv = content->GetAttrCount(cattrs);
NS_ENSURE_SUCCESS(rv, rv);
if (cattrs < 0x0000FFFF)
mNumCachedAttrs = NS_STATIC_CAST(PRUint16, cattrs); // signed 32 bits to unsigned 16 bits conversion
else
mNumCachedParams = 0xFFFF;
// now, we need to find all the PARAM tags that are children of us
// however, be carefull NOT to include any PARAMs that don't have us as a direct
// parent. For nested object (or applet) tags, be sure to only round up the
// param tags that coorespond with THIS instance. And also, weed out any bogus
// tags that may get in the way, see bug 39609. Then, with any param tag that meet our
// qualification, temporarly cache them in an nsISupportsArray until we can figure out
// what size to make our fixed char* array.
mNumCachedParams = 0;
nsCOMPtr<nsISupportsArray> ourParams;
rv = NS_NewISupportsArray(getter_AddRefs(ourParams));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMNode> mydomNode = do_QueryInterface(content);
NS_ENSURE_TRUE(mydomNode, NS_ERROR_NO_INTERFACE);
// use the DOM to get us ALL our dependant PARAM tags, even if not ours
nsCOMPtr<nsIDOMElement> mydomElement = do_QueryInterface(mydomNode);
NS_ENSURE_TRUE(mydomElement, NS_ERROR_NO_INTERFACE);
nsCOMPtr<nsIDOMNodeList> allParams;
mydomElement->GetElementsByTagName(NS_LITERAL_STRING("PARAM"), getter_AddRefs(allParams));
if (allParams) {
PRUint32 numAllParams;
allParams->GetLength(&numAllParams);
// loop through every so called dependant PARAM tag to check if it "belongs" to us
for (PRUint32 i = 0; i < numAllParams; i++) {
nsCOMPtr<nsIDOMNode> pnode;
allParams->Item(i, getter_AddRefs(pnode));
if (pnode) {
nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(pnode);
if (domelement) {
// let's NOT count up param tags that don't have a name attribute
nsAutoString name;
domelement->GetAttribute(NS_LITERAL_STRING("name"), name);
if (name.Length() > 0) {
nsCOMPtr<nsIDOMNode> parent;
nsCOMPtr<nsIDOMHTMLObjectElement> domobject;
nsCOMPtr<nsIDOMHTMLAppletElement> domapplet;
pnode->GetParentNode(getter_AddRefs(parent));
// walk up the parents of this PARAM until we find an object (or applet) tag
while (!(domobject || domapplet) && parent) {
domobject = do_QueryInterface(parent);
domapplet = do_QueryInterface(parent);
nsCOMPtr<nsIDOMNode> temp;
parent->GetParentNode(getter_AddRefs(temp));
parent = temp;
}
if (domapplet || domobject) {
if (domapplet)
parent = do_QueryInterface(domapplet);
else
parent = do_QueryInterface(domobject);
// now check to see if this PARAM's parent is us. if so, cache it for later
if (parent.get() == mydomNode.get()) {
nsCOMPtr<nsISupports> sup = do_QueryInterface(pnode);
NS_ASSERTION(sup, "lame! DOM node does doesn't QI to nsISupports");
ourParams->AppendElement(sup);
}
}
}
}
}
}
}
PRUint32 cparams;
ourParams->Count(&cparams); // unsigned 32 bits to unsigned 16 bits conversion
if (cparams < 0x0000FFFF)
mNumCachedParams = NS_STATIC_CAST(PRUint16, cparams);
else
mNumCachedParams = 0xFFFF;
// now lets make the arrays
mCachedAttrParamNames = (char **)PR_Calloc(sizeof(char *) * (mNumCachedAttrs + 1 + mNumCachedParams), 1);
NS_ENSURE_TRUE(mCachedAttrParamNames, NS_ERROR_OUT_OF_MEMORY);
mCachedAttrParamValues = (char **)PR_Calloc(sizeof(char *) * (mNumCachedAttrs + 1 + mNumCachedParams), 1);
NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY);
// let's fill in our attributes
PRInt16 c = 0;
for (PRInt16 index = 0; index < mNumCachedAttrs; index++) {
PRInt32 nameSpaceID;
nsCOMPtr<nsIAtom> atom;
nsCOMPtr<nsIAtom> prefix;
content->GetAttrNameAt(index, nameSpaceID,
*getter_AddRefs(atom),
*getter_AddRefs(prefix));
nsAutoString value;
if (NS_CONTENT_ATTR_NOT_THERE != content->GetAttr(nameSpaceID, atom, value)) {
nsAutoString name;
atom->ToString(name);
mCachedAttrParamNames [c] = ToNewUTF8String(name);
mCachedAttrParamValues[c] = ToNewUTF8String(value);
c++;
}
}
// add our PARAM and null seperator
mCachedAttrParamNames [mNumCachedAttrs] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
mCachedAttrParamValues[mNumCachedAttrs] = nsnull;
// now fill in the PARAM name/value pairs from the cached DOM nodes
c = 0;
for (PRInt16 idx = 0; idx < mNumCachedParams; idx++) {
nsCOMPtr<nsIDOMElement> param = do_QueryElementAt(ourParams, idx);
if (param) {
nsAutoString name;
nsAutoString value;
param->GetAttribute(NS_LITERAL_STRING("name"), name); // check for empty done above
param->GetAttribute(NS_LITERAL_STRING("value"), value);
/*
* According to the HTML 4.01 spec, at
* http://www.w3.org/TR/html4/types.html#type-cdata
* ''User agents may ignore leading and trailing
* white space in CDATA attribute values (e.g., "
* myval " may be interpreted as "myval"). Authors
* should not declare attribute values with
* leading or trailing white space.''
*/
name.CompressWhitespace(); // XXX right function?
value.CompressWhitespace();
mCachedAttrParamNames [mNumCachedAttrs + 1 + c] = ToNewUTF8String(name);
mCachedAttrParamValues[mNumCachedAttrs + 1 + c] = ToNewUTF8String(value);
c++; // rules!
}
}
return NS_OK;
}
// Here's where we forward events to plugins.
#ifdef XP_MAC
#if TARGET_CARBON
static void InitializeEventRecord(EventRecord* event)
{
memset(event, 0, sizeof(EventRecord));
GetGlobalMouse(&event->where);
event->when = TickCount();
event->modifiers = GetCurrentKeyModifiers();
}
#else
inline void InitializeEventRecord(EventRecord* event) { ::OSEventAvail(0, event); }
#endif
void nsPluginInstanceOwner::GUItoMacEvent(const nsGUIEvent& anEvent, EventRecord& aMacEvent)
{
InitializeEventRecord(&aMacEvent);
switch (anEvent.message) {
case NS_FOCUS_EVENT_START: // this is the same as NS_FOCUS_CONTENT
aMacEvent.what = nsPluginEventType_GetFocusEvent;
if (mOwner && mOwner->mPresContext) {
nsCOMPtr<nsIContent> content;
mOwner->GetContent(getter_AddRefs(content));
if (content)
content->SetFocus(mOwner->mPresContext);
}
break;
case NS_BLUR_CONTENT:
aMacEvent.what = nsPluginEventType_LoseFocusEvent;
if (mOwner && mOwner->mPresContext) {
nsCOMPtr<nsIContent> content;
mOwner->GetContent(getter_AddRefs(content));
if (content)
content->RemoveFocus(mOwner->mPresContext);
}
break;
case NS_MOUSE_MOVE:
case NS_MOUSE_ENTER:
aMacEvent.what = nsPluginEventType_AdjustCursorEvent;
break;
default:
aMacEvent.what = nullEvent;
break;
}
}
#endif
nsresult nsPluginInstanceOwner::ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
{
#ifdef XP_MAC
if (mInstance != NULL) {
EventRecord scrollEvent;
InitializeEventRecord(&scrollEvent);
scrollEvent.what = nsPluginEventType_ScrollingBeginsEvent;
nsPluginPort* pluginPort = GetPluginPort();
nsPluginEvent pluginEvent = { &scrollEvent, nsPluginPlatformWindowRef(pluginPort->port) };
PRBool eventHandled = PR_FALSE;
mInstance->HandleEvent(&pluginEvent, &eventHandled);
}
#endif
return NS_OK;
}
nsresult nsPluginInstanceOwner::ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
{
#ifdef XP_MAC
if (mInstance != NULL) {
EventRecord scrollEvent;
InitializeEventRecord(&scrollEvent);
scrollEvent.what = nsPluginEventType_ScrollingEndsEvent;
nsPluginPort* pluginPort = GetPluginPort();
nsPluginEvent pluginEvent = { &scrollEvent, nsPluginPlatformWindowRef(pluginPort->port) };
PRBool eventHandled = PR_FALSE;
mInstance->HandleEvent(&pluginEvent, &eventHandled);
if (!eventHandled) {
nsRect bogus(0,0,0,0);
Paint(bogus, 0); // send an update event to the plugin
}
}
#endif
return NS_OK;
}
/*=============== nsIFocusListener ======================*/
nsresult nsPluginInstanceOwner::Focus(nsIDOMEvent * aFocusEvent)
{
mContentFocused = PR_TRUE;
return DispatchFocusToPlugin(aFocusEvent);
}
nsresult nsPluginInstanceOwner::Blur(nsIDOMEvent * aFocusEvent)
{
mContentFocused = PR_FALSE;
return DispatchFocusToPlugin(aFocusEvent);
}
nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
{
#ifndef XP_MAC
if (nsPluginWindowType_Window == mPluginWindow.type)
return NS_ERROR_FAILURE; // means consume event
// continue only for cases without child window
#endif
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aFocusEvent));
if (privateEvent) {
nsEvent * theEvent;
privateEvent->GetInternalNSEvent(&theEvent);
if (theEvent) {
nsGUIEvent focusEvent;
memset(&focusEvent, 0, sizeof(focusEvent));
focusEvent.message = theEvent->message; // we only care about the message in ProcessEvent
nsEventStatus rv = ProcessEvent(focusEvent);
if (nsEventStatus_eConsumeNoDefault == rv) {
aFocusEvent->PreventDefault();
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aFocusEvent));
if (nsevent) {
nsevent->PreventBubble();
}
return NS_ERROR_FAILURE; // means consume event
}
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchFocusToPlugin failed, focusEvent null");
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchFocusToPlugin failed, privateEvent null");
return NS_OK;
}
/*=============== nsIKeyListener ======================*/
nsresult nsPluginInstanceOwner::KeyDown(nsIDOMEvent* aKeyEvent)
{
return DispatchKeyToPlugin(aKeyEvent);
}
nsresult nsPluginInstanceOwner::KeyUp(nsIDOMEvent* aKeyEvent)
{
return DispatchKeyToPlugin(aKeyEvent);
}
nsresult nsPluginInstanceOwner::KeyPress(nsIDOMEvent* aKeyEvent)
{
#ifdef XP_MAC // send KeyPress events only on Mac
return DispatchKeyToPlugin(aKeyEvent);
#else
if (mInstance) {
// If this event is going to the plugin, we want to kill it.
// Not actually sending keypress to the plugin, since we didn't before.
aKeyEvent->PreventDefault();
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aKeyEvent));
if (nsevent) {
nsevent->PreventBubble();
}
return NS_ERROR_FAILURE; // means consume event
}
return NS_OK;
#endif
}
nsresult nsPluginInstanceOwner::DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent)
{
#ifndef XP_MAC
if (nsPluginWindowType_Window == mPluginWindow.type)
return NS_ERROR_FAILURE; // means consume event
// continue only for cases without child window
#endif
if (mInstance) {
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aKeyEvent));
if (privateEvent) {
nsKeyEvent* keyEvent = nsnull;
privateEvent->GetInternalNSEvent((nsEvent**)&keyEvent);
if (keyEvent) {
nsEventStatus rv = ProcessEvent(*keyEvent);
if (nsEventStatus_eConsumeNoDefault == rv) {
aKeyEvent->PreventDefault();
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aKeyEvent));
if (nsevent) {
nsevent->PreventBubble();
}
return NS_ERROR_FAILURE; // means consume event
}
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchKeyToPlugin failed, keyEvent null");
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchKeyToPlugin failed, privateEvent null");
}
return NS_OK;
}
/*=============== nsIMouseMotionListener ======================*/
nsresult
nsPluginInstanceOwner::MouseMove(nsIDOMEvent* aMouseEvent)
{
#ifndef XP_MAC
if (nsPluginWindowType_Window == mPluginWindow.type)
return NS_ERROR_FAILURE; // means consume event
// continue only for cases without child window
#endif
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
if (privateEvent) {
nsMouseEvent* mouseEvent = nsnull;
privateEvent->GetInternalNSEvent((nsEvent**)&mouseEvent);
if (mouseEvent) {
nsEventStatus rv = ProcessEvent(*mouseEvent);
if (nsEventStatus_eConsumeNoDefault == rv) {
return NS_ERROR_FAILURE; // means consume event
}
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseMove failed, mouseEvent null");
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseMove failed, privateEvent null");
return NS_OK;
}
/*=============== nsIMouseListener ======================*/
nsresult
nsPluginInstanceOwner::MouseDown(nsIDOMEvent* aMouseEvent)
{
#ifndef XP_MAC
if (nsPluginWindowType_Window == mPluginWindow.type)
return NS_ERROR_FAILURE; // means consume event
// continue only for cases without child window
#endif
// if the plugin is windowless, we need to set focus ourselves
// otherwise, we might not get key events
if (mPluginWindow.type == nsPluginWindowType_Drawable) {
nsCOMPtr<nsIContent> content;
mOwner->GetContent(getter_AddRefs(content));
if (content)
content->SetFocus(mContext);
}
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
if (privateEvent) {
nsMouseEvent* mouseEvent = nsnull;
privateEvent->GetInternalNSEvent((nsEvent**)&mouseEvent);
if (mouseEvent) {
nsEventStatus rv = ProcessEvent(*mouseEvent);
if (nsEventStatus_eConsumeNoDefault == rv) {
return NS_ERROR_FAILURE; // means consume event
}
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseDown failed, mouseEvent null");
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::MouseDown failed, privateEvent null");
return NS_OK;
}
nsresult
nsPluginInstanceOwner::MouseUp(nsIDOMEvent* aMouseEvent)
{
return DispatchMouseToPlugin(aMouseEvent);
}
nsresult
nsPluginInstanceOwner::MouseClick(nsIDOMEvent* aMouseEvent)
{
return DispatchMouseToPlugin(aMouseEvent);
}
nsresult
nsPluginInstanceOwner::MouseDblClick(nsIDOMEvent* aMouseEvent)
{
return DispatchMouseToPlugin(aMouseEvent);
}
nsresult
nsPluginInstanceOwner::MouseOver(nsIDOMEvent* aMouseEvent)
{
return DispatchMouseToPlugin(aMouseEvent);
}
nsresult
nsPluginInstanceOwner::MouseOut(nsIDOMEvent* aMouseEvent)
{
return DispatchMouseToPlugin(aMouseEvent);
}
nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent)
{
#ifndef XP_MAC
if (nsPluginWindowType_Window == mPluginWindow.type)
return NS_ERROR_FAILURE; // means consume event
// continue only for cases without child window
#endif
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aMouseEvent));
if (privateEvent) {
nsMouseEvent* mouseEvent = nsnull;
privateEvent->GetInternalNSEvent((nsEvent**)&mouseEvent);
if (mouseEvent) {
nsEventStatus rv = ProcessEvent(*mouseEvent);
if (nsEventStatus_eConsumeNoDefault == rv) {
aMouseEvent->PreventDefault();
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aMouseEvent));
if (nsevent) {
nsevent->PreventBubble();
}
return NS_ERROR_FAILURE; // means consume event
}
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchMouseToPlugin failed, mouseEvent null");
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchMouseToPlugin failed, privateEvent null");
return NS_OK;
}
nsresult
nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent)
{
return NS_OK;
}
nsEventStatus nsPluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent)
{
// printf("nsGUIEvent.message: %d\n", anEvent.message);
nsEventStatus rv = nsEventStatus_eIgnore;
if (!mInstance) // if mInstance is null, we shouldn't be here
return rv;
#ifdef XP_MAC
if (mWidget != NULL) { // check for null mWidget
EventRecord* event = (EventRecord*)anEvent.nativeMsg;
if ((event == NULL) || (event->what == nullEvent) ||
(anEvent.message == NS_FOCUS_EVENT_START) ||
(anEvent.message == NS_BLUR_CONTENT) ||
(anEvent.message == NS_MOUSE_MOVE) ||
(anEvent.message == NS_MOUSE_ENTER))
{
EventRecord macEvent;
GUItoMacEvent(anEvent, macEvent);
event = &macEvent;
}
nsPluginPort* port = (nsPluginPort*)mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
nsPluginEvent pluginEvent = { event, nsPluginPlatformWindowRef(port->port) };
PRBool eventHandled = PR_FALSE;
mInstance->HandleEvent(&pluginEvent, &eventHandled);
if (eventHandled && !(anEvent.message == NS_MOUSE_LEFT_BUTTON_DOWN && !mContentFocused))
rv = nsEventStatus_eConsumeNoDefault;
}
#endif
#ifdef XP_WIN
// this code supports windowless plugins
nsPluginEvent * pPluginEvent = (nsPluginEvent *)anEvent.nativeMsg;
// we can get synthetic events from the nsEventStateManager... these have no nativeMsg
if (pPluginEvent != nsnull) {
PRBool eventHandled = PR_FALSE;
mInstance->HandleEvent(pPluginEvent, &eventHandled);
if (eventHandled)
rv = nsEventStatus_eConsumeNoDefault;
}
#endif
return rv;
}
nsresult
nsPluginInstanceOwner::Destroy()
{
nsCOMPtr<nsIContent> content;
mOwner->GetContent(getter_AddRefs(content));
// unregister context menu listener
if (mCXMenuListener) {
mCXMenuListener->Destroy(mOwner);
NS_RELEASE(mCXMenuListener);
}
// Unregister focus event listener
if (content) {
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(content));
if (receiver) {
nsCOMPtr<nsIDOMFocusListener> focusListener;
QueryInterface(NS_GET_IID(nsIDOMFocusListener), getter_AddRefs(focusListener));
if (focusListener) {
receiver->RemoveEventListenerByIID(focusListener, NS_GET_IID(nsIDOMFocusListener));
}
else NS_ASSERTION(PR_FALSE, "Unable to remove event listener for plugin");
}
else NS_ASSERTION(PR_FALSE, "plugin was not an event listener");
}
else NS_ASSERTION(PR_FALSE, "plugin had no content");
// Unregister mouse event listener
if (content) {
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(content));
if (receiver) {
nsCOMPtr<nsIDOMMouseListener> mouseListener;
QueryInterface(NS_GET_IID(nsIDOMMouseListener), getter_AddRefs(mouseListener));
if (mouseListener) {
receiver->RemoveEventListenerByIID(mouseListener, NS_GET_IID(nsIDOMMouseListener));
}
else NS_ASSERTION(PR_FALSE, "Unable to remove event listener for plugin");
// now for the mouse motion listener
nsCOMPtr<nsIDOMMouseMotionListener> mouseMotionListener;
QueryInterface(NS_GET_IID(nsIDOMMouseMotionListener), getter_AddRefs(mouseMotionListener));
if (mouseMotionListener) {
receiver->RemoveEventListenerByIID(mouseMotionListener, NS_GET_IID(nsIDOMMouseMotionListener));
}
else NS_ASSERTION(PR_FALSE, "Unable to remove event listener for plugin");
}
else NS_ASSERTION(PR_FALSE, "plugin was not an event listener");
}
else NS_ASSERTION(PR_FALSE, "plugin had no content");
// Unregister key event listener;
if (content) {
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(content));
if (receiver) {
nsCOMPtr<nsIDOMKeyListener> keyListener;
QueryInterface(NS_GET_IID(nsIDOMKeyListener), getter_AddRefs(keyListener));
if (keyListener) {
receiver->RemoveEventListener(NS_LITERAL_STRING("keypress"), keyListener, PR_TRUE);
receiver->RemoveEventListener(NS_LITERAL_STRING("keydown"), keyListener, PR_TRUE);
receiver->RemoveEventListener(NS_LITERAL_STRING("keyup"), keyListener, PR_TRUE);
}
else NS_ASSERTION(PR_FALSE, "Unable to remove event listener for plugin");
}
else NS_ASSERTION(PR_FALSE, "plugin was not an event listener");
}
else NS_ASSERTION(PR_FALSE, "plugin had no content");
// Unregister scroll position listener
if (mContext) {
nsCOMPtr<nsIPresShell> presShell;
mContext->GetShell(getter_AddRefs(presShell));
if (presShell) {
nsCOMPtr<nsIViewManager> vm;
presShell->GetViewManager(getter_AddRefs(vm));
if (vm) {
nsIScrollableView* scrollingView = nsnull;
vm->GetRootScrollableView(&scrollingView);
if (scrollingView) {
scrollingView->RemoveScrollPositionListener((nsIScrollPositionListener *)this);
}
}
}
}
mOwner = nsnull; // break relationship between frame and plugin instance owner
return NS_OK;
}
// Paints are handled differently, so we just simulate an update event.
void nsPluginInstanceOwner::Paint(const nsRect& aDirtyRect, PRUint32 ndc)
{
if(!mInstance)
return;
#ifdef XP_MAC
nsPluginPort* pluginPort = GetPluginPort();
#ifdef DO_DIRTY_INTERSECT // aDirtyRect isn't always correct, see bug 56128
nsPoint rel(aDirtyRect.x, aDirtyRect.y);
nsPoint abs(0,0);
nsCOMPtr<nsIWidget> containerWidget;
// Convert dirty rect relative coordinates to absolute and also get the containerWidget
ConvertRelativeToWindowAbsolute(mOwner, mContext, rel, abs, *getter_AddRefs(containerWidget));
nsRect absDirtyRect = nsRect(abs.x, abs.y, aDirtyRect.width, aDirtyRect.height);
// Convert to absolute pixel values for the dirty rect
nsRect absDirtyRectInPixels;
ConvertTwipsToPixels(*mContext, absDirtyRect, absDirtyRectInPixels);
#endif
FixUpPluginWindow();
EventRecord updateEvent;
InitializeEventRecord(&updateEvent);
updateEvent.what = updateEvt;
updateEvent.message = UInt32(pluginPort->port);
nsPluginEvent pluginEvent = { &updateEvent, nsPluginPlatformWindowRef(pluginPort->port) };
PRBool eventHandled = PR_FALSE;
mInstance->HandleEvent(&pluginEvent, &eventHandled);
#endif
#ifdef XP_WIN
nsPluginWindow * window;
GetWindow(window);
nsRect relDirtyRect = nsRect(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
nsRect relDirtyRectInPixels;
ConvertTwipsToPixels(*mContext, relDirtyRect, relDirtyRectInPixels);
// we got dirty rectangle in relative window coordinates, but we
// need it in absolute units and in the (left, top, right, bottom) form
RECT drc;
drc.left = relDirtyRectInPixels.x + window->x;
drc.top = relDirtyRectInPixels.y + window->y;
drc.right = drc.left + relDirtyRectInPixels.width;
drc.bottom = drc.top + relDirtyRectInPixels.height;
nsPluginEvent pluginEvent;
pluginEvent.event = 0x000F; //!!! This is bad, but is it better to include <windows.h> for WM_PAINT only?
pluginEvent.wParam = (uint32)ndc;
pluginEvent.lParam = (uint32)&drc;
PRBool eventHandled = PR_FALSE;
mInstance->HandleEvent(&pluginEvent, &eventHandled);
#endif
}
// Here's how we give idle time to plugins.
NS_IMETHODIMP_(void) nsPluginInstanceOwner::Notify(nsITimer* /* timer */)
{
#ifdef XP_MAC
// validate the plugin clipping information by syncing the plugin window info to
// reflect the current widget location. This makes sure that everything is updated
// correctly in the event of scrolling in the window.
FixUpPluginWindow();
if (mInstance != NULL) {
EventRecord idleEvent;
InitializeEventRecord(&idleEvent);
idleEvent.what = nullEvent;
nsPluginPort* pluginPort = GetPluginPort();
nsPluginEvent pluginEvent = { &idleEvent, nsPluginPlatformWindowRef(pluginPort->port) };
PRBool eventHandled = PR_FALSE;
mInstance->HandleEvent(&pluginEvent, &eventHandled);
}
#endif
#ifndef REPEATING_TIMERS
// reprime the timer? currently have to create a new timer for each call, which is
// kind of wasteful. need to get periodic timers working on all platforms.
nsresult rv;
mPluginTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (NS_SUCCEEDED(rv))
mPluginTimer->Init(this, 1020 / 60);
#endif
}
void nsPluginInstanceOwner::CancelTimer()
{
if (mPluginTimer) {
mPluginTimer->Cancel();
mPluginTimer = nsnull;
}
}
NS_IMETHODIMP nsPluginInstanceOwner::Init(nsIPresContext* aPresContext, nsObjectFrame *aFrame)
{
//do not addref to avoid circular refs. MMP
mContext = aPresContext;
mOwner = aFrame;
nsCOMPtr<nsIContent> content;
mOwner->GetContent(getter_AddRefs(content));
// This is way of ensure the previous document is gone. Important when reloading either
// the page or refreshing plugins. In the case of an OBJECT frame,
// we want to flush out the prevous content viewer which will cause the previous document
// and plugins to be cleaned up. Then we can create our new plugin without the old instance
// hanging around.
nsCOMPtr<nsISupports> container;
aPresContext->GetContainer(getter_AddRefs(container));
if (container) {
nsCOMPtr<nsIDocShell> cvc(do_QueryInterface(container));
if (cvc) {
nsCOMPtr<nsIContentViewer> cv;
cvc->GetContentViewer(getter_AddRefs(cv));
if (cv)
cv->Show();
}
}
// register context menu listener
mCXMenuListener = new nsPluginDOMContextMenuListener();
if (mCXMenuListener) {
NS_ADDREF(mCXMenuListener);
mCXMenuListener->Init(aFrame);
}
// Register focus listener
if (content) {
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(content));
if (receiver) {
nsCOMPtr<nsIDOMFocusListener> focusListener;
QueryInterface(NS_GET_IID(nsIDOMFocusListener), getter_AddRefs(focusListener));
if (focusListener) {
receiver->AddEventListenerByIID(focusListener, NS_GET_IID(nsIDOMFocusListener));
}
}
}
// Register mouse listener
if (content) {
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(content));
if (receiver) {
nsCOMPtr<nsIDOMMouseListener> mouseListener;
QueryInterface(NS_GET_IID(nsIDOMMouseListener), getter_AddRefs(mouseListener));
if (mouseListener) {
receiver->AddEventListenerByIID(mouseListener, NS_GET_IID(nsIDOMMouseListener));
}
// now do the mouse motion listener
nsCOMPtr<nsIDOMMouseMotionListener> mouseMotionListener;
QueryInterface(NS_GET_IID(nsIDOMMouseMotionListener), getter_AddRefs(mouseMotionListener));
if (mouseMotionListener) {
receiver->AddEventListenerByIID(mouseMotionListener, NS_GET_IID(nsIDOMMouseMotionListener));
}
}
}
// Register key listener
if (content) {
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(content));
if (receiver) {
nsCOMPtr<nsIDOMKeyListener> keyListener;
QueryInterface(NS_GET_IID(nsIDOMKeyListener), getter_AddRefs(keyListener));
if (keyListener) {
receiver->AddEventListener(NS_LITERAL_STRING("keypress"), keyListener, PR_TRUE);
receiver->AddEventListener(NS_LITERAL_STRING("keydown"), keyListener, PR_TRUE);
receiver->AddEventListener(NS_LITERAL_STRING("keyup"), keyListener, PR_TRUE);
}
}
}
// Register scroll position listener
if (mContext) {
nsCOMPtr<nsIPresShell> presShell;
mContext->GetShell(getter_AddRefs(presShell));
if (presShell) {
nsCOMPtr<nsIViewManager> vm;
presShell->GetViewManager(getter_AddRefs(vm));
if (vm) {
nsIScrollableView* scrollingView = nsnull;
vm->GetRootScrollableView(&scrollingView);
if (scrollingView) {
scrollingView->AddScrollPositionListener((nsIScrollPositionListener *)this);
}
}
}
}
return NS_OK;
}
nsPluginPort* nsPluginInstanceOwner::GetPluginPort()
{
//!!! Port must be released for windowless plugins on Windows, because it is HDC !!!
nsPluginPort* result = NULL;
if (mWidget != NULL)
{
#ifdef XP_WIN
if(mPluginWindow.type == nsPluginWindowType_Drawable)
result = (nsPluginPort*) mWidget->GetNativeData(NS_NATIVE_GRAPHIC);
else
#endif
result = (nsPluginPort*) mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
}
return result;
}
void nsPluginInstanceOwner::ReleasePluginPort(nsPluginPort * pluginPort)
{
#ifdef XP_WIN
if (mWidget != NULL)
{
if(mPluginWindow.type == nsPluginWindowType_Drawable)
mWidget->FreeNativeData((HDC)pluginPort, NS_NATIVE_GRAPHIC);
}
#endif
}
NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
{
nsIView *view;
nsresult rv = NS_ERROR_FAILURE;
float p2t;
if (nsnull != mOwner)
{
// Create view if necessary
mOwner->GetView(mContext, &view);
if (nsnull == view || nsnull == mWidget)
{
PRBool windowless = PR_FALSE;
mInstance->GetValue(nsPluginInstanceVariable_WindowlessBool, (void *)&windowless);
// always create widgets in Twips, not pixels
mContext->GetScaledPixelsToTwips(&p2t);
rv = mOwner->CreateWidget(mContext,
NSIntPixelsToTwips(mPluginWindow.width, p2t),
NSIntPixelsToTwips(mPluginWindow.height, p2t),
windowless);
if (NS_OK == rv)
{
mOwner->GetView(mContext, &view);
if (view)
{
view->GetWidget(mWidget);
PRBool fTransparent = PR_FALSE;
mInstance->GetValue(nsPluginInstanceVariable_TransparentBool, (void *)&fTransparent);
nsCOMPtr<nsIViewManager> vm;
view->GetViewManager(*getter_AddRefs(vm));
if (vm) {
vm->SetViewContentTransparency(view, fTransparent);
}
}
if (PR_TRUE == windowless)
{
mPluginWindow.type = nsPluginWindowType_Drawable;
mPluginWindow.window = nsnull; // this needs to be a HDC according to the spec,
// but I do not see the right way to release it
// so let's postpone passing HDC till paint event
// when it is really needed. Change spec?
}
else if (mWidget)
{
mWidget->Resize(mPluginWindow.width, mPluginWindow.height, PR_FALSE);
mPluginWindow.window = GetPluginPort();
mPluginWindow.type = nsPluginWindowType_Window;
#if defined(XP_MAC)
// Is this needed in the windowless case ???
// start a periodic timer to provide null events to the plugin instance.
mPluginTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (rv == NS_OK)
rv = mPluginTimer->Init(this, 1020 / 60, NS_PRIORITY_NORMAL, NS_TYPE_REPEATING_SLACK);
#endif
}
}
}
}
return rv;
}
void nsPluginInstanceOwner::SetPluginHost(nsIPluginHost* aHost)
{
if(mPluginHost != nsnull)
NS_RELEASE(mPluginHost);
mPluginHost = aHost;
NS_IF_ADDREF(mPluginHost);
}
// convert frame coordinates from twips to pixels
static void ConvertTwipsToPixels(nsIPresContext& aPresContext, nsRect& aTwipsRect, nsRect& aPixelRect)
{
float t2p;
aPresContext.GetTwipsToPixels(&t2p);
aPixelRect.x = NSTwipsToIntPixels(aTwipsRect.x, t2p);
aPixelRect.y = NSTwipsToIntPixels(aTwipsRect.y, t2p);
aPixelRect.width = NSTwipsToIntPixels(aTwipsRect.width, t2p);
aPixelRect.height = NSTwipsToIntPixels(aTwipsRect.height, t2p);
}
// Mac specific code to fix up the port location and clipping region
#ifdef XP_MAC
// calculate the absolute position and clip for a widget
// and use other windows in calculating the clip
static void GetWidgetPosClipAndVis(nsIWidget* aWidget,nscoord& aAbsX, nscoord& aAbsY,
nsRect& aClipRect, PRBool& aIsVisible)
{
if (aIsVisible)
aWidget->IsVisible(aIsVisible);
aWidget->GetBounds(aClipRect);
aAbsX = aClipRect.x;
aAbsY = aClipRect.y;
nscoord ancestorX = -aClipRect.x, ancestorY = -aClipRect.y;
// Calculate clipping relative to the widget passed in
aClipRect.x = 0;
aClipRect.y = 0;
// Gather up the absolute position of the widget, clip window, and visibilty
nsCOMPtr<nsIWidget> widget = getter_AddRefs(aWidget->GetParent());
while (widget != nsnull) {
if (aIsVisible)
widget->IsVisible(aIsVisible);
nsRect wrect;
widget->GetClientBounds(wrect);
nscoord wx, wy;
wx = wrect.x;
wy = wrect.y;
wrect.x = ancestorX;
wrect.y = ancestorY;
aClipRect.IntersectRect(aClipRect, wrect);
aAbsX += wx;
aAbsY += wy;
widget = getter_AddRefs(widget->GetParent());
if (widget == nsnull) {
// Don't include the top-level windows offset
// printf("Top level window offset %d %d\n", wx, wy);
aAbsX -= wx;
aAbsY -= wy;
}
ancestorX -=wx;
ancestorY -=wy;
}
aClipRect.x += aAbsX;
aClipRect.y += aAbsY;
//printf("--------------\n");
//printf("Widget clip X %d Y %d rect %d %d %d %d\n", aAbsX, aAbsY, aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height );
//printf("--------------\n");
}
#ifdef DO_DIRTY_INTERSECT
// Convert from a frame relative coordinate to a coordinate relative to its
// containing window
static void ConvertRelativeToWindowAbsolute(nsIFrame* aFrame, nsIPresContext* aPresContext, nsPoint& aRel, nsPoint& aAbs, nsIWidget *&
aContainerWidget)
{
aAbs.x = 0;
aAbs.y = 0;
nsIView *view = nsnull;
// See if this frame has a view
aFrame->GetView(aPresContext, &view);
if (nsnull == view) {
// Calculate frames offset from its nearest view
aFrame->GetOffsetFromView(aPresContext,
aAbs,
&view);
} else {
// Store frames offset from its view.
nsRect rect;
aFrame->GetRect(rect);
aAbs.x = rect.x;
aAbs.y = rect.y;
}
if (view != nsnull) {
// Caclulate the views offset from its nearest widget
nscoord viewx = 0;
nscoord viewy = 0;
view->GetWidget(aContainerWidget);
if (nsnull == aContainerWidget) {
view->GetOffsetFromWidget(&viewx, &viewy, aContainerWidget/**getter_AddRefs(widget)*/);
aAbs.x += viewx;
aAbs.y += viewy;
// GetOffsetFromWidget does not include the views offset, so we need to add
// that in.
nscoord x, y;
view->GetPosition(&x, &y);
aAbs.x += x;
aAbs.y += y;
}
nsRect widgetBounds;
aContainerWidget->GetBounds(widgetBounds);
} else {
NS_ASSERTION(PR_FALSE, "the object frame does not have a view");
}
// Add relative coordinate to the absolute coordinate that has been calculated
aAbs += aRel;
}
#endif // DO_DIRTY_INTERSECT
inline PRUint16 COLOR8TOCOLOR16(PRUint8 color8)
{
return (color8 << 8) | color8; /* (color8 * 257) == (color8 * 0x0101) */
}
void nsPluginInstanceOwner::FixUpPluginWindow()
{
if (mWidget) {
nscoord absWidgetX = 0;
nscoord absWidgetY = 0;
nsRect widgetClip(0,0,0,0);
// first, check our view for CSS visibility style
nsIView *view;
mOwner->GetView(mContext, &view);
nsViewVisibility vis;
view->GetVisibility(vis);
PRBool isVisible = (vis == nsViewVisibility_kShow) ? PR_TRUE : PR_FALSE;
GetWidgetPosClipAndVis(mWidget,absWidgetX,absWidgetY,widgetClip,isVisible);
// set the port coordinates
mPluginWindow.x = absWidgetX;
mPluginWindow.y = absWidgetY;
// fix up the clipping region
mPluginWindow.clipRect.top = widgetClip.y;
mPluginWindow.clipRect.left = widgetClip.x;
mPluginWindow.clipRect.bottom = mPluginWindow.clipRect.top + widgetClip.height;
mPluginWindow.clipRect.right = mPluginWindow.clipRect.left + widgetClip.width;
// the Mac widget doesn't set the background color right away!!
// the background color needs to be set here on the plugin port
GrafPtr savePort;
::GetPort(&savePort); // save our current port
nsPluginPort* pluginPort = GetPluginPort();
::SetPort((GrafPtr)pluginPort->port);
nscolor color = mWidget->GetBackgroundColor();
RGBColor macColor;
macColor.red = COLOR8TOCOLOR16(NS_GET_R(color)); // convert to Mac color
macColor.green = COLOR8TOCOLOR16(NS_GET_G(color));
macColor.blue = COLOR8TOCOLOR16(NS_GET_B(color));
::RGBBackColor(&macColor);
::SetPort(savePort); // restore port
// now we need to check if we've been hidden or made visible and then update the plugin
// with the correct port if visible or null if hidden,
// if visiblity has changed, then update the plugin
if (isVisible != mWidgetVisible) {
mWidgetVisible = isVisible;
nsPluginWindow *window;
GetWindow(window);
if (window && mInstance) {
window->window = mWidgetVisible ? GetPluginPort() : nsnull;
mInstance->SetWindow(window);
}
}
}
}
#endif // XP_MAC