Mozilla/mozilla/modules/plugin/base/src/nsPluginViewer.cpp
rods%netscape.com 40889d01ed Backing out changes - just as well, I forgot to but the bug # and r/sr/a anyway
git-svn-id: svn://10.0.0.236/trunk@116643 18797224-902f-48f8-a5cc-f745e15eee43
2002-03-15 14:49:09 +00:00

1457 lines
38 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):
* Dan Rosen <dr@netscape.com>
*
* 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 "nsCOMPtr.h"
#include "nscore.h"
#include "nsCRT.h"
#include "nsIContentViewer.h"
#include "nsIPluginHost.h"
#include "nsIPluginInstance.h"
#include "nsIStreamListener.h"
#include "nsIURL.h"
#include "nsIChannel.h"
#include "nsNetUtil.h"
#include "nsIComponentManager.h"
#include "nsWidgetsCID.h"
#include "nsILinkHandler.h"
#include "nsIWebShell.h"
#include "nsIContentViewerEdit.h"
#include "nsIWebBrowserPrint.h"
#include "nsIWidget.h"
#include "nsIContent.h"
#include "nsIDocument.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIWebBrowserChrome.h"
#include "nsIDOMDocument.h"
#include "nsPluginViewer.h"
#include "nsGUIEvent.h"
#include "nsIPluginViewer.h"
#include "nsContentCID.h"
#include "nsITimer.h"
#include "nsITimerCallback.h"
class nsIPrintSettings;
class nsIDOMWindow;
// Class IDs
static NS_DEFINE_IID(kChildWindowCID, NS_CHILD_CID);
static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID);
// Interface IDs
static NS_DEFINE_IID(kIContentViewerIID, NS_ICONTENTVIEWER_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
static NS_DEFINE_IID(kHTMLDocumentCID, NS_HTMLDOCUMENT_CID);
class PluginViewerImpl;
class PluginListener : public nsIStreamListener {
public:
PluginListener(PluginViewerImpl* aViewer);
virtual ~PluginListener();
// nsISupports
NS_DECL_ISUPPORTS
// nsIRequestObserver methods:
NS_DECL_NSIREQUESTOBSERVER
// nsIStreamListener methods:
NS_DECL_NSISTREAMLISTENER
PluginViewerImpl* mViewer;
nsIStreamListener* mNextStream;
};
class pluginInstanceOwner : public nsIPluginInstanceOwner,
public nsITimerCallback
{
public:
pluginInstanceOwner();
virtual ~pluginInstanceOwner();
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);
//nsIEventListener interface
nsEventStatus ProcessEvent(const nsGUIEvent & anEvent);
//locals
NS_IMETHOD Init(PluginViewerImpl *aViewer, nsIWidget *aWindow);
// nsITimerCallback interface
NS_IMETHOD_(void) Notify(nsITimer *timer);
void CancelTimer();
#ifdef XP_MAC
void GUItoMacEvent(const nsGUIEvent& anEvent, EventRecord& aMacEvent);
nsPluginPort* GetPluginPort();
void FixUpPluginWindow();
#endif
private:
nsPluginWindow mPluginWindow;
nsIPluginInstance *mInstance;
nsIWidget *mWindow; //we do not addref this...
PluginViewerImpl *mViewer; //we do not addref this...
nsCOMPtr<nsITimer> mPluginTimer;
};
static void GetWidgetPosAndClip(nsIWidget* aWidget,nscoord& aAbsX, nscoord& aAbsY,
nsRect& aClipRect);
class PluginViewerImpl : public nsIPluginViewer,
public nsIContentViewer,
public nsIContentViewerEdit,
public nsIWebBrowserPrint
{
public:
PluginViewerImpl(const char* aCommand);
nsresult Init(nsIStreamListener** aDocListener);
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
// nsISupports
NS_DECL_ISUPPORTS
// nsIPluginViewer
NS_IMETHOD StartLoad(nsIRequest* request, nsIStreamListener*& aResult);
// nsIContentViewer
NS_DECL_NSICONTENTVIEWER
// nsIContentViewerEdit
NS_DECL_NSICONTENTVIEWEREDIT
// nsIWebBrowserPrint
NS_DECL_NSIWEBBROWSERPRINT
virtual ~PluginViewerImpl();
nsresult CreatePlugin(nsIRequest* request, nsIPluginHost* aHost, const nsRect& aBounds,
nsIStreamListener*& aResult);
nsresult MakeWindow(nsNativeWidget aParent,
nsIDeviceContext* aDeviceContext,
const nsRect& aBounds);
void ForceRefresh(void);
nsresult GetURI(nsIURI* *aURI);
nsresult GetDocument(nsIDocument* *aDocument);
nsIWidget* mWindow;
nsIDocument* mDocument;
nsCOMPtr<nsISupports> mContainer;
nsIChannel* mChannel;
pluginInstanceOwner *mOwner;
PRBool mEnableRendering;
};
//----------------------------------------------------------------------
nsresult
NS_NewPluginContentViewer(const char* aCommand,
nsIStreamListener** aDocListener,
nsIContentViewer** aDocViewer)
{
PluginViewerImpl* it = new PluginViewerImpl(aCommand);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsresult rv = it->Init(aDocListener);
if (NS_FAILED(rv)) {
delete it;
return rv;
}
return it->QueryInterface(kIContentViewerIID, (void**) aDocViewer);
}
// Note: operator new zeros our memory
PluginViewerImpl::PluginViewerImpl(const char* aCommand)
{
NS_INIT_REFCNT();
mEnableRendering = PR_TRUE;
}
nsresult
PluginViewerImpl::Init(nsIStreamListener** aDocListener)
{
nsIStreamListener* it = new PluginListener(this);
if (it == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(it);
*aDocListener = it;
return NS_OK;
}
// ISupports implementation...
NS_IMPL_ADDREF(PluginViewerImpl)
NS_IMPL_RELEASE(PluginViewerImpl)
NS_IMPL_QUERY_INTERFACE4(PluginViewerImpl,
nsIPluginViewer,
nsIContentViewer,
nsIContentViewerEdit,
nsIWebBrowserPrint)
PluginViewerImpl::~PluginViewerImpl()
{
#ifdef XP_MAC
if (mOwner) mOwner->CancelTimer();
#endif
if(mOwner) {
nsIPluginInstance * inst;
if(NS_SUCCEEDED(mOwner->GetInstance(inst)) && inst) {
nsCOMPtr<nsIPluginHost> host = do_GetService(kCPluginManagerCID);
if(host)
host->StopPluginInstance(inst);
NS_RELEASE(inst);
}
}
NS_IF_RELEASE(mOwner);
if (nsnull != mWindow) {
mWindow->Destroy();
NS_RELEASE(mWindow);
}
NS_IF_RELEASE(mDocument);
NS_IF_RELEASE(mChannel);
}
NS_IMETHODIMP
PluginViewerImpl::SetContainer(nsISupports* aContainer)
{
mContainer = aContainer;
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::GetContainer(nsISupports** aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = mContainer;
NS_IF_ADDREF(*aResult);
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::Init(nsIWidget* aParentWidget,
nsIDeviceContext* aDeviceContext,
const nsRect& aBounds)
{
nsresult rv = MakeWindow(aParentWidget->GetNativeData(NS_NATIVE_WIDGET),
aDeviceContext, aBounds);
if (NS_OK == rv) {
mOwner = new pluginInstanceOwner();
if (nsnull != mOwner) {
NS_ADDREF(mOwner);
rv = mOwner->Init(this, mWindow);
}
}
return rv;
}
NS_IMETHODIMP
PluginViewerImpl::StartLoad(nsIRequest* request, nsIStreamListener*& aResult)
{
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
if (!channel) return NS_ERROR_FAILURE;
NS_IF_RELEASE(mChannel);
mChannel = channel;
NS_ADDREF(mChannel);
#ifdef DEBUG
char* contentType;
channel->GetContentType(&contentType);
printf("PluginViewerImpl::StartLoad: content-type=%s\n", contentType);
nsCRT::free(contentType);
#endif
aResult = nsnull;
// Only instantiate the plugin if our container can host it
nsCOMPtr<nsIPluginHost> host;
host = do_GetService(kCPluginManagerCID);
nsresult rv = NS_ERROR_FAILURE;
if(host)
{
// create a document so that we can pass something back to plugin
// instance if it wants one
nsCOMPtr<nsIDocument> doc(do_CreateInstance(kHTMLDocumentCID));
if (doc) {
mDocument = doc;
NS_ADDREF(mDocument); // released in ~nsPluginViewer
// set the document's URL
// so it can be fetched later for resolving relative URLs
nsCOMPtr<nsIURI> uri;
GetURI(getter_AddRefs(uri));
if (uri)
mDocument->SetDocumentURL(uri);
}
nsRect r;
mWindow->GetClientBounds(r);
rv = CreatePlugin(request, host, nsRect(0, 0, r.width, r.height), aResult);
}
return rv;
}
nsresult
PluginViewerImpl::CreatePlugin(nsIRequest* request, nsIPluginHost* aHost, const nsRect& aBounds,
nsIStreamListener*& aResult)
{
nsresult rv = NS_OK;
if (nsnull != mOwner) {
nsPluginWindow *win;
mOwner->GetWindow(win);
win->x = aBounds.x;
win->y = aBounds.y;
win->width = aBounds.width;
win->height = aBounds.height;
win->clipRect.top = aBounds.y;
win->clipRect.left = aBounds.x;
win->clipRect.bottom = aBounds.YMost();
win->clipRect.right = aBounds.XMost();
#ifdef XP_UNIX
win->ws_info = nsnull; //XXX need to figure out what this is. MMP
#endif
nsIURI* uri;
rv = mChannel->GetURI(&uri);
if (NS_FAILED(rv)) return rv;
nsCAutoString spec;
rv = uri->GetSpec(spec);
NS_RELEASE(uri);
if (NS_FAILED(rv)) return rv;
NS_ConvertUTF8toUCS2 str(spec);
char* ct;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
channel->GetContentType(&ct);
if (NS_FAILED(rv)) return rv;
rv = aHost->InstantiateFullPagePlugin(ct, str, aResult, mOwner);
delete[] ct;
}
return rv;
}
NS_IMETHODIMP
PluginViewerImpl::Stop(void)
{
// XXX write this
return NS_OK;
}
/*
* This method is called by the Document Loader once a document has
* been created for a particular data stream... The content viewer
* must cache this document for later use when Init(...) is called.
*/
NS_IMETHODIMP
PluginViewerImpl::LoadStart(nsISupports *aDoc)
{
#ifdef NS_DEBUG
printf("PluginViewerImpl::LoadStart\n");
#endif
return aDoc->QueryInterface(kIDocumentIID, (void**)&mDocument);
}
NS_IMETHODIMP
PluginViewerImpl::LoadComplete(nsresult aStatus)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
PluginViewerImpl::Unload(void)
{
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::Close(void)
{
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::Destroy(void)
{
// XXX ripped off from nsObjectFrame::Destroy()
// we need to finish with the plugin before native window is destroyed
// doing this in the destructor is too late.
if(mOwner != nsnull)
{
nsIPluginInstance *inst;
if(NS_OK == mOwner->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);
!doCallSetWindowAfterDestroy ? inst->SetWindow(nsnull) : 0;
inst->Stop();
inst->Destroy();
doCallSetWindowAfterDestroy ? inst->SetWindow(nsnull) : 0; }
else {
inst->SetWindow(nsnull);
inst->Stop();
}
NS_RELEASE(inst);
}
}
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::GetDOMDocument(nsIDOMDocument **aResult)
{
return (mDocument) ? CallQueryInterface(mDocument, aResult) : NS_ERROR_FAILURE;
}
NS_IMETHODIMP
PluginViewerImpl::SetDOMDocument(nsIDOMDocument *aDocument)
{
return NS_ERROR_FAILURE;
}
nsEventStatus PR_CALLBACK
HandlePluginEvent(nsGUIEvent *aEvent)
{
if (aEvent == nsnull || aEvent->widget == nsnull) //null pointer check
return nsEventStatus_eIgnore;
#ifdef XP_WIN
// on Windows, the mouse click is converted to an NS_PLUGIN_ACTIVATE
if( aEvent->message == NS_PLUGIN_ACTIVATE)
(nsIWidget*)(aEvent->widget)->SetFocus(); // send focus to child window
#else
// the Mac, and presumably others, send NS_MOUSE_ACTIVATE
if (aEvent->message == NS_MOUSE_ACTIVATE) {
(nsIWidget*)(aEvent->widget)->SetFocus(); // send focus to child window
#ifdef XP_MAC
// furthermore on the Mac nsMacEventHandler sends the NS_PLUGIN_ACTIVATE
// followed by the mouse down event, so we need to handle this
} else {
// on Mac, we store a pointer to this class as native data in the widget
void *clientData;
(nsIWidget*)(aEvent->widget)->GetClientData(clientData);
PluginViewerImpl * pluginViewer = (PluginViewerImpl *)clientData;
if (pluginViewer != nsnull && pluginViewer->mOwner != nsnull)
return pluginViewer->mOwner->ProcessEvent(*aEvent);
#endif // XP_MAC
}
#endif // else XP_WIN
return nsEventStatus_eIgnore;
}
nsresult
PluginViewerImpl::MakeWindow(nsNativeWidget aParent,
nsIDeviceContext* aDeviceContext,
const nsRect& aBounds)
{
nsresult rv =
nsComponentManager::CreateInstance(kChildWindowCID, nsnull, kIWidgetIID,
(void**)&mWindow);
if (NS_OK != rv) {
return rv;
}
mWindow->Create(aParent, aBounds,HandlePluginEvent, aDeviceContext);
mWindow->SetClientData(this);
Show();
return rv;
}
NS_IMETHODIMP
PluginViewerImpl::GetBounds(nsRect& aResult)
{
NS_PRECONDITION(nsnull != mWindow, "null window");
if (nsnull != mWindow) {
mWindow->GetBounds(aResult);
}
else {
aResult.SetRect(0, 0, 0, 0);
}
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::GetPreviousViewer(nsIContentViewer** aViewer)
{
*aViewer = nsnull;
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::SetPreviousViewer(nsIContentViewer* aViewer)
{
if (aViewer)
aViewer->Destroy();
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::SetBounds(const nsRect& aBounds)
{
NS_PRECONDITION(nsnull != mWindow, "null window");
if (nsnull != mWindow) {
// Don't have the widget repaint. Layout will generate repaint requests
// during reflow
nsIPluginInstance *inst;
mWindow->Resize(aBounds.x, aBounds.y, aBounds.width, aBounds.height, PR_FALSE);
if ((nsnull != mOwner) && (NS_OK == mOwner->GetInstance(inst)) && (nsnull != inst)) {
nsPluginWindow *win;
if (NS_OK == mOwner->GetWindow(win)) {
win->x = aBounds.x;
win->y = aBounds.y;
win->width = aBounds.width;
win->height = aBounds.height;
win->clipRect.top = aBounds.y;
win->clipRect.left = aBounds.x;
win->clipRect.bottom = aBounds.YMost();
win->clipRect.right = aBounds.XMost();
inst->SetWindow(win);
}
NS_RELEASE(inst);
}
}
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::Move(PRInt32 aX, PRInt32 aY)
{
NS_PRECONDITION(nsnull != mWindow, "null window");
if (nsnull != mWindow) {
nsIPluginInstance *inst;
mWindow->Move(aX, aY);
if ((nsnull != mOwner) && (NS_OK == mOwner->GetInstance(inst)) && (nsnull != inst)) {
nsPluginWindow *win;
if (NS_OK == mOwner->GetWindow(win)) {
win->x = aX;
win->y = aY;
win->clipRect.bottom = (win->clipRect.bottom - win->clipRect.top) + aY;
win->clipRect.right = (win->clipRect.right - win->clipRect.left) + aX;
win->clipRect.top = aY;
win->clipRect.left = aX;
inst->SetWindow(win);
}
NS_RELEASE(inst);
}
}
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::Show()
{
NS_PRECONDITION(nsnull != mWindow, "null window");
if (nsnull != mWindow) {
mWindow->Show(PR_TRUE);
}
// XXX should we call SetWindow here?
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::Hide()
{
NS_PRECONDITION(nsnull != mWindow, "null window");
if (nsnull != mWindow) {
mWindow->Show(PR_FALSE);
}
// should we call SetWindow(nsnull) here?
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::SetEnableRendering(PRBool aOn)
{
mEnableRendering = aOn;
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::GetEnableRendering(PRBool* aResult)
{
NS_PRECONDITION(nsnull != aResult, "null OUT ptr");
if (aResult) {
*aResult = mEnableRendering;
}
return NS_OK;
}
void
PluginViewerImpl::ForceRefresh()
{
mWindow->Invalidate(PR_TRUE);
}
nsresult PluginViewerImpl::GetURI(nsIURI* *aURI)
{
return mChannel->GetURI(aURI);
}
nsresult PluginViewerImpl::GetDocument(nsIDocument* *aDocument)
{
NS_IF_ADDREF(mDocument);
*aDocument = mDocument;
return NS_OK;
}
NS_IMETHODIMP pluginInstanceOwner::InvalidateRect(nsPluginRect *invalidRect)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP pluginInstanceOwner::InvalidateRegion(nsPluginRegion invalidRegion)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP pluginInstanceOwner::ForceRedraw()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP pluginInstanceOwner::GetValue(nsPluginInstancePeerVariable variable, void *value)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* ========================================================================================
* nsIContentViewerEdit
* ======================================================================================== */
NS_IMETHODIMP PluginViewerImpl::Search()
{
NS_ASSERTION(0, "NOT IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP PluginViewerImpl::GetSearchable(PRBool *aSearchable)
{
NS_ASSERTION(0, "NOT IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP PluginViewerImpl::ClearSelection()
{
NS_ASSERTION(0, "NOT IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP PluginViewerImpl::SelectAll()
{
NS_ASSERTION(0, "NOT IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP PluginViewerImpl::CopySelection()
{
NS_ASSERTION(0, "NOT IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP PluginViewerImpl::GetCopyable(PRBool *aCopyable)
{
NS_ASSERTION(0, "NOT IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP PluginViewerImpl::CutSelection()
{
NS_ASSERTION(0, "NOT IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP PluginViewerImpl::GetCutable(PRBool *aCutable)
{
NS_ASSERTION(0, "NOT IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP PluginViewerImpl::Paste()
{
NS_ASSERTION(0, "NOT IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP PluginViewerImpl::GetPasteable(PRBool *aPasteable)
{
NS_ASSERTION(0, "NOT IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
/* ========================================================================================
* nsIWebBrowserPrint
* ======================================================================================== */
NS_IMETHODIMP
PluginViewerImpl::Print(nsIPrintSettings* aPrintSettings,
nsIWebProgressListener* aWebProgressListener)
{
nsPluginPrint npprint;
npprint.mode = nsPluginMode_Full;
npprint.print.fullPrint.pluginPrinted = PR_FALSE;
npprint.print.fullPrint.printOne = PR_FALSE;
npprint.print.fullPrint.platformPrint = nsnull;
NS_ENSURE_TRUE(mOwner,NS_ERROR_FAILURE);
nsCOMPtr<nsIPluginInstance> pi;
mOwner->GetInstance(*getter_AddRefs(pi));
NS_ENSURE_TRUE(pi,NS_ERROR_FAILURE);
return pi->Print(&npprint);
}
NS_IMETHODIMP
PluginViewerImpl::GetNewPrintSettings(nsIPrintSettings * *aNewPrintSettings)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute wstring defaultPrinterName; */
NS_IMETHODIMP
PluginViewerImpl::GetDefaultPrinterName(PRUnichar * *aDefaultPrinterName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void initPrintSettingsFromPrinter (in wstring aPrinterName, in nsIPrintSettings aPrintSettings); */
NS_IMETHODIMP
PluginViewerImpl::InitPrintSettingsFromPrinter(const PRUnichar *aPrinterName, nsIPrintSettings *aPrintSettings)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute nsIPrintSettings globalPrintSettings; */
NS_IMETHODIMP
PluginViewerImpl::GetGlobalPrintSettings(nsIPrintSettings * *aGlobalPrintSettings)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIPrintSettings globalPrintSettingsValues; */
NS_IMETHODIMP
PluginViewerImpl::GetGlobalPrintSettingsValues(nsIPrintSettings * *aGlobalPrintSettingsValues)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PluginViewerImpl::SetGlobalPrintSettingsValues(nsIPrintSettings * aGlobalPrintSettingsValues)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void printPreview (in nsIPrintSettings aThePrintSettings); */
NS_IMETHODIMP
PluginViewerImpl::PrintPreview(nsIPrintSettings *aThePrintSettings)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void printPreviewNavigate (in short aNavType, in long aPageNum); */
NS_IMETHODIMP
PluginViewerImpl::PrintPreviewNavigate(PRInt16 aNavType, PRInt32 aPageNum)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute boolean doingPrintPreview; */
NS_IMETHODIMP
PluginViewerImpl::GetDoingPrintPreview(PRBool *aDoingPrintPreview)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute nsIPrintSettings currentPrintSettings; */
NS_IMETHODIMP
PluginViewerImpl::GetCurrentPrintSettings(nsIPrintSettings * *aCurrentPrintSettings)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void cancel (); */
NS_IMETHODIMP
PluginViewerImpl::Cancel()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void enumerateDocumentNames (out PRUint32 aCount, [array, size_is (aCount), retval] out wstring aResult); */
NS_IMETHODIMP
PluginViewerImpl::EnumerateDocumentNames(PRUint32 *aCount, PRUnichar ***aResult)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute boolean isFramesetDocument; */
NS_IMETHODIMP
PluginViewerImpl::GetIsFramesetDocument(PRBool *aIsFramesetDocument)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute long printPreviewNumPages; */
NS_IMETHODIMP
PluginViewerImpl::GetPrintPreviewNumPages(PRInt32 *aPrintPreviewNumPages)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void exitPrintPreview (); */
NS_IMETHODIMP
PluginViewerImpl::ExitPrintPreview()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PluginViewerImpl::GetInLink(PRBool* aInLink)
{
NS_ENSURE_ARG_POINTER(aInLink);
*aInLink = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::GetInImage(PRBool* aInImage)
{
NS_ENSURE_ARG_POINTER(aInImage);
*aInImage = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::CopyLinkLocation()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PluginViewerImpl::CopyImageLocation()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PluginViewerImpl::CopyImageContents()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
//----------------------------------------------------------------------
PluginListener::PluginListener(PluginViewerImpl* aViewer)
{
NS_INIT_REFCNT();
mViewer = aViewer;
NS_ADDREF(aViewer);
}
PluginListener::~PluginListener()
{
NS_RELEASE(mViewer);
NS_IF_RELEASE(mNextStream);
}
NS_IMPL_ISUPPORTS1(PluginListener, nsIStreamListener)
NS_IMETHODIMP
PluginListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
nsresult rv;
char* contentType = nsnull;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
rv = channel->GetContentType(&contentType);
if (NS_FAILED(rv)) {
return rv;
}
rv = mViewer->StartLoad(request, mNextStream);
if (NS_FAILED(rv)) {
return rv;
}
if (nsnull == mNextStream)
return NS_ERROR_FAILURE;
return mNextStream->OnStartRequest(request, ctxt);
}
NS_IMETHODIMP
PluginListener::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
nsresult status)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnStopRequest(request, ctxt, status);
}
NS_IMETHODIMP
PluginListener::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
}
//----------------------------------------------------------------------
pluginInstanceOwner :: pluginInstanceOwner()
{
NS_INIT_REFCNT();
memset(&mPluginWindow, 0, sizeof(mPluginWindow));
mInstance = nsnull;
mWindow = nsnull;
mViewer = nsnull;
}
pluginInstanceOwner :: ~pluginInstanceOwner()
{
// shut off the timer.
if (mPluginTimer != nsnull) {
CancelTimer();
}
NS_IF_RELEASE(mInstance);
mWindow = nsnull;
mViewer = nsnull;
}
NS_IMPL_ISUPPORTS2(pluginInstanceOwner, nsIPluginInstanceOwner,nsITimerCallback);
NS_IMETHODIMP pluginInstanceOwner :: SetInstance(nsIPluginInstance *aInstance)
{
NS_IF_RELEASE(mInstance);
mInstance = aInstance;
NS_IF_ADDREF(mInstance);
return NS_OK;
}
NS_IMETHODIMP pluginInstanceOwner :: GetInstance(nsIPluginInstance *&aInstance)
{
if(!mInstance)
return NS_ERROR_FAILURE;
NS_ADDREF(mInstance);
aInstance = mInstance;
return NS_OK;
}
NS_IMETHODIMP pluginInstanceOwner :: GetWindow(nsPluginWindow *&aWindow)
{
aWindow = &mPluginWindow;
return NS_OK;
}
NS_IMETHODIMP pluginInstanceOwner :: GetMode(nsPluginMode *aMode)
{
*aMode = nsPluginMode_Full;
return NS_OK;
}
NS_IMETHODIMP pluginInstanceOwner :: CreateWidget(void)
{
PRBool windowless;
nsresult rv = NS_OK;
if (nsnull != mInstance)
{
#if defined(XP_MAC)
// 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
mInstance->GetValue(nsPluginInstanceVariable_WindowlessBool, (void *)&windowless);
if (PR_TRUE == windowless)
{
mPluginWindow.window = nsnull; //XXX this needs to be a HDC
mPluginWindow.type = nsPluginWindowType_Drawable;
}
else if (nsnull != mWindow)
{
mPluginWindow.window = (nsPluginPort *)mWindow->GetNativeData(NS_NATIVE_PLUGIN_PORT);
mPluginWindow.type = nsPluginWindowType_Window;
}
else
return NS_ERROR_FAILURE;
}
else
return NS_ERROR_FAILURE;
#if defined(XP_MAC)
FixUpPluginWindow();
#endif
return rv;
}
NS_IMETHODIMP pluginInstanceOwner::GetURL(const char *aURL, const char *aTarget, void *aPostData, PRUint32 aPostDataLen, void *aHeadersData,
PRUint32 aHeadersDataLen, PRBool isFile)
{
NS_ENSURE_TRUE(mViewer,NS_ERROR_NULL_POINTER);
// the container of the pres context will give us the link handler
nsCOMPtr<nsISupports> container;
nsresult rv = mViewer->GetContainer(getter_AddRefs(container));
NS_ENSURE_TRUE(container,NS_ERROR_FAILURE);
nsCOMPtr<nsILinkHandler> lh = do_QueryInterface(container);
NS_ENSURE_TRUE(lh, NS_ERROR_FAILURE);
nsCOMPtr<nsIURI> uri;
rv = mViewer->GetURI(getter_AddRefs(uri));
NS_ENSURE_TRUE(NS_SUCCEEDED(rv),NS_ERROR_FAILURE);
char* absURIStr;
NS_MakeAbsoluteURI(&absURIStr, aURL, uri);
nsAutoString fullurl; fullurl.AssignWithConversion(absURIStr);
nsCRT::free(absURIStr);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv),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
NS_ASSERTION(NS_SUCCEEDED(rv),"failed in creating plugin header data stream");
if (NS_FAILED(rv)) return rv;
}
}
nsAutoString unitarget; unitarget.AssignWithConversion(aTarget);
rv = lh->OnLinkClick(nsnull, eLinkVerb_Replace,
fullurl.get(), unitarget.get(),
postDataStream, headersDataStream);
return rv;
}
NS_IMETHODIMP pluginInstanceOwner :: ShowStatus(const char *aStatusMsg)
{
nsresult rv = NS_ERROR_FAILURE;
rv = this->ShowStatus(NS_ConvertUTF8toUCS2(aStatusMsg).get());
return rv;
}
NS_IMETHODIMP pluginInstanceOwner::ShowStatus(const PRUnichar *aStatusMsg)
{
nsresult rv = NS_ERROR_FAILURE;
if (!mViewer) {
return rv;
}
nsCOMPtr<nsISupports> cont;
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
rv = mViewer->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 pluginInstanceOwner :: GetDocument(nsIDocument* *aDocument)
{
return mViewer->GetDocument(aDocument);
}
NS_IMETHODIMP pluginInstanceOwner :: Init(PluginViewerImpl *aViewer, nsIWidget *aWindow)
{
//do not addref
mWindow = aWindow;
mViewer = aViewer;
return NS_OK;
}
// Here's where we forward events to plugins.
#ifdef XP_MAC
#if TARGET_CARBON
inline Boolean OSEventAvail(EventMask mask, EventRecord* event) { return EventAvail(mask, event); }
#endif
void pluginInstanceOwner::GUItoMacEvent(const nsGUIEvent& anEvent, EventRecord& aMacEvent)
{
::OSEventAvail(0, &aMacEvent);
switch (anEvent.message) {
case NS_GOTFOCUS:
case NS_FOCUS_EVENT_START:
aMacEvent.what = nsPluginEventType_GetFocusEvent;
break;
case NS_LOSTFOCUS:
case NS_MOUSE_EXIT:
aMacEvent.what = nsPluginEventType_LoseFocusEvent;
break;
case NS_MOUSE_MOVE:
case NS_MOUSE_ENTER:
mWindow->SetFocus();
aMacEvent.what = nsPluginEventType_AdjustCursorEvent;
break;
case NS_PAINT:
aMacEvent.what = updateEvt;
break;
case NS_KEY_DOWN:
case NS_KEY_PRESS:
break;
default:
aMacEvent.what = nullEvent;
break;
}
}
#endif
nsEventStatus pluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent)
{
nsEventStatus rv = nsEventStatus_eIgnore;
if (!mInstance || !mWindow) // if the instance or the window 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_KEY_PRESS ||
anEvent.message == NS_CONTEXTMENU_MESSAGE_START) {
EventRecord macEvent;
GUItoMacEvent(anEvent, macEvent);
event = &macEvent;
if (event->what == updateEvt) {
nsPluginPort* pluginPort = GetPluginPort();
// Add in child windows absolute position to get make the dirty rect
// relative to the top-level window.
nscoord absWidgetX = 0;
nscoord absWidgetY = 0;
nsRect widgetClip(0,0,0,0);
GetWidgetPosAndClip(mWindow,absWidgetX,absWidgetY,widgetClip);
//mViewer->GetBounds(widgetClip);
//absWidgetX = widgetClip.x;
//absWidgetY = widgetClip.y;
// set the port
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;
EventRecord updateEvent;
::OSEventAvail(0, &updateEvent);
updateEvent.what = updateEvt;
updateEvent.message = UInt32(pluginPort->port);
nsPluginEvent pluginEvent = { &updateEvent, nsPluginPlatformWindowRef(pluginPort->port) };
PRBool eventHandled = PR_FALSE;
mInstance->HandleEvent(&pluginEvent, &eventHandled);
}
return nsEventStatus_eConsumeNoDefault;
}
//nsPluginPort* port = (nsPluginPort*)mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
nsPluginPort* port = (nsPluginPort*)mWindow->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)
rv = nsEventStatus_eConsumeNoDefault;
// }
#endif
//~~~
#ifdef XP_WIN
nsPluginEvent * pPluginEvent = (nsPluginEvent *)anEvent.nativeMsg;
PRBool eventHandled = PR_FALSE;
mInstance->HandleEvent(pPluginEvent, &eventHandled);
if (eventHandled)
rv = nsEventStatus_eConsumeNoDefault;
#endif
return rv;
}
// Here's how we give idle time to plugins.
NS_IMETHODIMP_(void) pluginInstanceOwner::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;
::OSEventAvail(0, &idleEvent);
idleEvent.what = nullEvent;
nsPluginPort* pluginPort = GetPluginPort();
nsPluginEvent pluginEvent = { &idleEvent, nsPluginPlatformWindowRef(pluginPort->port) };
PRBool eventHandled = PR_FALSE;
mInstance->HandleEvent(&pluginEvent, &eventHandled);
}
#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 // REPEATING_TIMERS
#endif // XP_MAC
}
void pluginInstanceOwner::CancelTimer()
{
if (mPluginTimer) {
mPluginTimer->Cancel();
mPluginTimer = nsnull;
}
}
#ifdef XP_MAC
nsPluginPort* pluginInstanceOwner::GetPluginPort()
{
nsPluginPort* result = NULL;
if (mWindow != NULL)
result = (nsPluginPort*) mWindow->GetNativeData(NS_NATIVE_PLUGIN_PORT);
return result;
}
// calculate the absolute position and clip for a widget
// and use other windows in calculating the clip
static void GetWidgetPosAndClip(nsIWidget* aWidget,nscoord& aAbsX, nscoord& aAbsY,
nsRect& aClipRect)
{
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
nsCOMPtr<nsIWidget> widget = getter_AddRefs(aWidget->GetParent());
while (widget != nsnull) {
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");
}
void pluginInstanceOwner::FixUpPluginWindow()
{
if (mWindow) {
nscoord absWidgetX = 0;
nscoord absWidgetY = 0;
nsRect widgetClip(0,0,0,0);
GetWidgetPosAndClip(mWindow,absWidgetX,absWidgetY,widgetClip);
// 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;
}
}
#endif