Moved from webshell/src

git-svn-id: svn://10.0.0.236/trunk@30557 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
kipp%netscape.com 1999-05-06 19:25:40 +00:00
parent cec1954858
commit 969dad1d78
6 changed files with 4371 additions and 0 deletions

View File

@ -0,0 +1,692 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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 Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
#include "nslayout.h"
#include "nsCOMPtr.h"
#include "nsCRT.h"
#include "nsString.h"
#include "nsISupports.h"
#include "nsIContentViewerContainer.h"
#include "nsIDocumentViewer.h"
#include "nsIDocument.h"
#include "nsIPresContext.h"
#include "nsIPresShell.h"
#include "nsIStyleSet.h"
#include "nsIStyleSheet.h"
#include "nsIFrame.h"
#include "nsIScriptContextOwner.h"
#include "nsIScriptGlobalObject.h"
#include "nsILinkHandler.h"
#include "nsIDOMDocument.h"
#include "nsViewsCID.h"
#include "nsWidgetsCID.h"
#include "nsGfxCIID.h"
#include "nsIDeviceContext.h"
#include "nsIDeviceContextSpec.h"
#include "nsIDeviceContextSpecFactory.h"
#include "nsIViewManager.h"
#include "nsIView.h"
#include "nsIPref.h"
#include "nsIPageSequenceFrame.h"
#include "nsIURL.h"
#ifdef NS_DEBUG
#undef NOISY_VIEWER
#else
#undef NOISY_VIEWER
#endif
class DocumentViewerImpl : public nsIDocumentViewer
{
public:
DocumentViewerImpl();
DocumentViewerImpl(nsIPresContext* aPresContext);
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
// nsISupports interface...
NS_DECL_ISUPPORTS
// nsIContentViewer interface...
NS_IMETHOD Init(nsNativeWidget aParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling = nsScrollPreference_kAuto);
NS_IMETHOD BindToDocument(nsISupports* aDoc, const char* aCommand);
NS_IMETHOD SetContainer(nsIContentViewerContainer* aContainer);
NS_IMETHOD GetContainer(nsIContentViewerContainer*& aContainerResult);
NS_IMETHOD Stop(void);
NS_IMETHOD GetBounds(nsRect& aResult);
NS_IMETHOD SetBounds(const nsRect& aBounds);
NS_IMETHOD Move(PRInt32 aX, PRInt32 aY);
NS_IMETHOD Show();
NS_IMETHOD Hide();
NS_IMETHOD Print(void);
// nsIDocumentViewer interface...
NS_IMETHOD SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet);
NS_IMETHOD GetDocument(nsIDocument*& aResult);
NS_IMETHOD GetPresShell(nsIPresShell*& aResult);
NS_IMETHOD GetPresContext(nsIPresContext*& aResult);
NS_IMETHOD CreateDocumentViewerUsing(nsIPresContext* aPresContext,
nsIDocumentViewer*& aResult);
protected:
virtual ~DocumentViewerImpl();
private:
void ForceRefresh(void);
nsresult CreateStyleSet(nsIDocument* aDocument, nsIStyleSet** aStyleSet);
nsresult MakeWindow(nsNativeWidget aNativeParent,
const nsRect& aBounds,
nsScrollPreference aScrolling);
protected:
// IMPORTANT: The ownership implicit in the following member
// variables has been explicitly checked and set using nsCOMPtr
// for owning pointers and raw COM interface pointers for weak
// (ie, non owning) references. If you add any members to this
// class, please make the ownership explicit (pinkerton, scc).
nsIContentViewerContainer* mContainer; // [WEAK] it owns me!
nsCOMPtr<nsIDeviceContext> mDeviceContext; // ??? can't hurt, but...
nsIView* mView; // [WEAK] cleaned up by view mgr
// the following six items are explicitly in this order
// so they will be destroyed in the reverse order (pinkerton, scc)
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsIWidget> mWindow; // ??? should we really own it?
nsCOMPtr<nsIViewManager> mViewManager;
nsCOMPtr<nsIPresContext> mPresContext;
nsCOMPtr<nsIPresShell> mPresShell;
nsCOMPtr<nsIStyleSheet> mUAStyleSheet;
};
//Class IDs
static NS_DEFINE_IID(kViewManagerCID, NS_VIEW_MANAGER_CID);
static NS_DEFINE_IID(kScrollingViewCID, NS_SCROLLING_VIEW_CID);
static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
static NS_DEFINE_IID(kViewCID, NS_VIEW_CID);
// Interface IDs
static NS_DEFINE_IID(kIScriptContextOwnerIID, NS_ISCRIPTCONTEXTOWNER_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID);
static NS_DEFINE_IID(kIViewManagerIID, NS_IVIEWMANAGER_IID);
static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID);
static NS_DEFINE_IID(kScrollViewIID, NS_ISCROLLABLEVIEW_IID);
static NS_DEFINE_IID(kIContentViewerIID, NS_ICONTENT_VIEWER_IID);
static NS_DEFINE_IID(kIDocumentViewerIID, NS_IDOCUMENT_VIEWER_IID);
static NS_DEFINE_IID(kILinkHandlerIID, NS_ILINKHANDLER_IID);
nsresult
NS_NewDocumentViewer(nsIDocumentViewer** aResult)
{
NS_PRECONDITION(aResult, "null OUT ptr");
if (!aResult) {
return NS_ERROR_NULL_POINTER;
}
DocumentViewerImpl* it = new DocumentViewerImpl();
if (nsnull == it) {
*aResult = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
return it->QueryInterface(kIDocumentViewerIID, (void**) aResult);
}
// Note: operator new zeros our memory
DocumentViewerImpl::DocumentViewerImpl()
{
NS_INIT_REFCNT();
}
DocumentViewerImpl::DocumentViewerImpl(nsIPresContext* aPresContext)
: mPresContext(dont_QueryInterface(aPresContext))
{
NS_INIT_REFCNT();
}
// ISupports implementation...
NS_IMPL_ADDREF(DocumentViewerImpl)
NS_IMPL_RELEASE(DocumentViewerImpl)
nsresult DocumentViewerImpl::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIContentViewerIID)) {
nsIContentViewer* tmp = this;
*aInstancePtr = (void*)tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kIDocumentViewerIID)) {
nsIDocumentViewer* tmp = this;
*aInstancePtr = (void*) tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
nsIContentViewer* tmp1 = this;
nsISupports* tmp2 = tmp1;
*aInstancePtr = (void*) tmp2;
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE;
}
DocumentViewerImpl::~DocumentViewerImpl()
{
if (mDocument) {
// Break global object circular reference on the document created
// in the DocViewer Init
nsIScriptContextOwner *mOwner = mDocument->GetScriptContextOwner();
if (nsnull != mOwner) {
nsIScriptGlobalObject *mGlobal;
mOwner->GetScriptGlobalObject(&mGlobal);
if (nsnull != mGlobal) {
mGlobal->SetNewDocument(nsnull);
NS_RELEASE(mGlobal);
}
NS_RELEASE(mOwner);
// out of band cleanup of webshell
mDocument->SetScriptContextOwner(nsnull);
}
}
if (mDeviceContext)
mDeviceContext->FlushFontCache();
if (mPresShell) {
// Break circular reference (or something)
mPresShell->EndObservingDocument();
}
}
/*
* 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
DocumentViewerImpl::BindToDocument(nsISupports *aDoc, const char *aCommand)
{
NS_PRECONDITION(!mDocument, "Viewer is already bound to a document!");
#ifdef NOISY_VIEWER
printf("DocumentViewerImpl::BindToDocument\n");
#endif
nsresult rv;
mDocument = do_QueryInterface(aDoc,&rv);
return rv;
}
NS_IMETHODIMP
DocumentViewerImpl::SetContainer(nsIContentViewerContainer* aContainer)
{
mContainer = aContainer;
if (mPresContext) {
mPresContext->SetContainer(aContainer);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetContainer(nsIContentViewerContainer*& aResult)
{
aResult = mContainer;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Init(nsNativeWidget aNativeParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling)
{
nsresult rv;
if (!mDocument) {
return NS_ERROR_NULL_POINTER;
}
mDeviceContext = dont_QueryInterface(aDeviceContext);
PRBool makeCX = PR_FALSE;
if (!mPresContext) {
// Create presentation context
rv = NS_NewGalleyContext(getter_AddRefs(mPresContext));
if (NS_OK != rv) {
return rv;
}
mPresContext->Init(aDeviceContext, aPrefs);
makeCX = PR_TRUE;
}
if (nsnull != mContainer) {
nsILinkHandler* linkHandler = nsnull;
mContainer->QueryCapability(kILinkHandlerIID, (void**)&linkHandler);
mPresContext->SetContainer(mContainer);
mPresContext->SetLinkHandler(linkHandler);
NS_IF_RELEASE(linkHandler);
// Set script-context-owner in the document
nsIScriptContextOwner* owner = nsnull;
mContainer->QueryCapability(kIScriptContextOwnerIID, (void**)&owner);
if (nsnull != owner) {
mDocument->SetScriptContextOwner(owner);
nsIScriptGlobalObject* global;
rv = owner->GetScriptGlobalObject(&global);
if (NS_SUCCEEDED(rv) && (nsnull != global)) {
nsIDOMDocument *domdoc = nsnull;
mDocument->QueryInterface(kIDOMDocumentIID,
(void**) &domdoc);
if (nsnull != domdoc) {
global->SetNewDocument(domdoc);
NS_RELEASE(domdoc);
}
NS_RELEASE(global);
}
NS_RELEASE(owner);
}
}
// Create the ViewManager and Root View...
MakeWindow(aNativeParent, aBounds, aScrolling);
// Create the style set...
nsIStyleSet* styleSet;
rv = CreateStyleSet(mDocument, &styleSet);
if (NS_OK == rv) {
// Now make the shell for the document
rv = mDocument->CreateShell(mPresContext, mViewManager, styleSet,
getter_AddRefs(mPresShell));
NS_RELEASE(styleSet);
if (NS_OK == rv) {
// Initialize our view manager
nsRect bounds;
mWindow->GetBounds(bounds);
nscoord width = bounds.width;
nscoord height = bounds.height;
float p2t;
mPresContext->GetPixelsToTwips(&p2t);
width = NSIntPixelsToTwips(width, p2t);
height = NSIntPixelsToTwips(height, p2t);
mViewManager->DisableRefresh();
mViewManager->SetWindowDimensions(width, height);
if (!makeCX) {
// Make shell an observer for next time
mPresShell->BeginObservingDocument();
// Resize-reflow this time
mPresShell->InitialReflow(width, height);
// Now trigger a refresh
mViewManager->EnableRefresh();
}
}
}
return rv;
}
NS_IMETHODIMP
DocumentViewerImpl::Stop(void)
{
if (mPresContext) {
mPresContext->Stop();
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet)
{
mUAStyleSheet = dont_QueryInterface(aUAStyleSheet);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetDocument(nsIDocument*& aResult)
{
aResult = mDocument;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetPresShell(nsIPresShell*& aResult)
{
aResult = mPresShell;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetPresContext(nsIPresContext*& aResult)
{
aResult = mPresContext;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetBounds(nsRect& aResult)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->GetBounds(aResult);
}
else {
aResult.SetRect(0, 0, 0, 0);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::SetBounds(const nsRect& aBounds)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
// Don't have the widget repaint. Layout will generate repaint requests
// during reflow
mWindow->Resize(aBounds.x, aBounds.y, aBounds.width, aBounds.height,
PR_FALSE);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Move(PRInt32 aX, PRInt32 aY)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->Move(aX, aY);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Show(void)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->Show(PR_TRUE);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Hide(void)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->Show(PR_FALSE);
}
return NS_OK;
}
static NS_DEFINE_IID(kIDeviceContextSpecFactoryIID, NS_IDEVICE_CONTEXT_SPEC_FACTORY_IID);
static NS_DEFINE_IID(kDeviceContextSpecFactoryCID, NS_DEVICE_CONTEXT_SPEC_FACTORY_CID);
NS_IMETHODIMP DocumentViewerImpl::Print(void)
{
nsIDeviceContextSpecFactory *factory = nsnull;
nsComponentManager::CreateInstance(kDeviceContextSpecFactoryCID, nsnull,
kIDeviceContextSpecFactoryIID,
(void **)&factory);
if (nsnull != factory)
{
nsIDeviceContextSpec *devspec = nsnull;
nsCOMPtr<nsIDeviceContext> dx;
nsIDeviceContext *newdx = nsnull;
factory->CreateDeviceContextSpec(nsnull, devspec, PR_FALSE);
if (nsnull != devspec) {
mPresContext->GetDeviceContext(getter_AddRefs(dx));
if (NS_OK == dx->GetDeviceContextFor(devspec, newdx))
{
nsIPresShell *ps;
nsIPresContext *cx;
nsIStyleSet *ss;
nsIPref *prefs;
nsIViewManager *vm;
PRInt32 width, height;
nsIView *view;
NS_RELEASE(devspec);
newdx->BeginDocument();
newdx->GetDeviceSurfaceDimensions(width, height);
NS_NewPrintContext(&cx);
mPresContext->GetPrefs(&prefs);
cx->Init(newdx, prefs);
CreateStyleSet(mDocument, &ss);
NS_NewPresShell(&ps);
{
nsresult rv;
rv = nsComponentManager::CreateInstance(kViewManagerCID,
nsnull,
kIViewManagerIID,
(void **)&vm);
if ((NS_OK != rv) || (NS_OK != vm->Init(newdx))) {
NS_ASSERTION(PR_FALSE, "can't get good VM");
}
nsRect tbounds = nsRect(0, 0, width, height);
// Create a child window of the parent that is our "root view/window"
// Create a view
rv = nsComponentManager::CreateInstance(kViewCID,
nsnull,
kIViewIID,
(void **)&view);
if ((NS_OK != rv) || (NS_OK != view->Init(vm,
tbounds,
nsnull))) {
NS_ASSERTION(PR_FALSE, "can't get good view");
}
// Setup hierarchical relationship in view manager
vm->SetRootView(view);
}
ps->Init(mDocument, cx, vm, ss);
//lay it out...
//newdx->BeginDocument();
ps->InitialReflow(width, height);
// Ask the page sequence frame to print all the pages
nsIPageSequenceFrame* pageSequence;
nsPrintOptions options;
ps->GetPageSequenceFrame(&pageSequence);
NS_ASSERTION(nsnull != pageSequence, "no page sequence frame");
pageSequence->Print(*cx, options, nsnull);
newdx->EndDocument();
NS_RELEASE(ps);
NS_RELEASE(vm);
NS_RELEASE(ss);
NS_RELEASE(newdx);
NS_IF_RELEASE(prefs); // XXX why is the prefs null??
}
}
NS_RELEASE(factory);
}
return NS_OK;
}
void DocumentViewerImpl::ForceRefresh()
{
mWindow->Invalidate(PR_TRUE);
}
nsresult
DocumentViewerImpl::CreateStyleSet(nsIDocument* aDocument,
nsIStyleSet** aStyleSet)
{
// this should eventually get expanded to allow for creating
// different sets for different media
nsresult rv;
if (!mUAStyleSheet) {
NS_WARNING("unable to load UA style sheet");
}
rv = NS_NewStyleSet(aStyleSet);
if (NS_OK == rv) {
PRInt32 index = aDocument->GetNumberOfStyleSheets();
while (0 < index--) {
nsIStyleSheet* sheet = aDocument->GetStyleSheetAt(index);
(*aStyleSet)->AddDocStyleSheet(sheet, aDocument);
NS_RELEASE(sheet);
}
if (mUAStyleSheet) {
(*aStyleSet)->AppendBackstopStyleSheet(mUAStyleSheet);
}
}
return rv;
}
nsresult
DocumentViewerImpl::MakeWindow(nsNativeWidget aNativeParent,
const nsRect& aBounds,
nsScrollPreference aScrolling)
{
nsresult rv;
rv = nsComponentManager::CreateInstance(kViewManagerCID,
nsnull,
kIViewManagerIID,
getter_AddRefs(mViewManager));
nsCOMPtr<nsIDeviceContext> dx;
mPresContext->GetDeviceContext(getter_AddRefs(dx));
if ((NS_OK != rv) || (NS_OK != mViewManager->Init(dx))) {
return rv;
}
nsRect tbounds = aBounds;
float p2t;
mPresContext->GetPixelsToTwips(&p2t);
tbounds *= p2t;
// Create a child window of the parent that is our "root view/window"
// Create a view
rv = nsComponentManager::CreateInstance(kViewCID,
nsnull,
kIViewIID,
(void**)&mView);
static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
if ((NS_OK != rv) || (NS_OK != mView->Init(mViewManager,
tbounds,
nsnull))) {
return rv;
}
rv = mView->CreateWidget(kWidgetCID, nsnull, aNativeParent);
if (rv != NS_OK)
return rv;
// Setup hierarchical relationship in view manager
mViewManager->SetRootView(mView);
mView->GetWidget(*getter_AddRefs(mWindow));
//set frame rate to 25 fps
mViewManager->SetFrameRate(25);
// This SetFocus is necessary so the Arrow Key and Page Key events
// go to the scrolled view as soon as the Window is created instead of going to
// the browser window (this enables keyboard scrolling of the document)
mWindow->SetFocus();
return rv;
}
NS_IMETHODIMP
DocumentViewerImpl::CreateDocumentViewerUsing(nsIPresContext* aPresContext,
nsIDocumentViewer*& aResult)
{
if (!mDocument) {
// XXX better error
return NS_ERROR_NULL_POINTER;
}
if (nsnull == aPresContext) {
return NS_ERROR_NULL_POINTER;
}
// Create new viewer
DocumentViewerImpl* viewer = new DocumentViewerImpl(aPresContext);
if (nsnull == viewer) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(viewer);
// XXX make sure the ua style sheet is used (for now; need to be
// able to specify an alternate)
viewer->SetUAStyleSheet(mUAStyleSheet);
// Bind the new viewer to the old document
nsresult rv = viewer->BindToDocument(mDocument, "create");/* XXX verb? */
aResult = viewer;
return rv;
}

View File

@ -0,0 +1,692 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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 Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
#include "nslayout.h"
#include "nsCOMPtr.h"
#include "nsCRT.h"
#include "nsString.h"
#include "nsISupports.h"
#include "nsIContentViewerContainer.h"
#include "nsIDocumentViewer.h"
#include "nsIDocument.h"
#include "nsIPresContext.h"
#include "nsIPresShell.h"
#include "nsIStyleSet.h"
#include "nsIStyleSheet.h"
#include "nsIFrame.h"
#include "nsIScriptContextOwner.h"
#include "nsIScriptGlobalObject.h"
#include "nsILinkHandler.h"
#include "nsIDOMDocument.h"
#include "nsViewsCID.h"
#include "nsWidgetsCID.h"
#include "nsGfxCIID.h"
#include "nsIDeviceContext.h"
#include "nsIDeviceContextSpec.h"
#include "nsIDeviceContextSpecFactory.h"
#include "nsIViewManager.h"
#include "nsIView.h"
#include "nsIPref.h"
#include "nsIPageSequenceFrame.h"
#include "nsIURL.h"
#ifdef NS_DEBUG
#undef NOISY_VIEWER
#else
#undef NOISY_VIEWER
#endif
class DocumentViewerImpl : public nsIDocumentViewer
{
public:
DocumentViewerImpl();
DocumentViewerImpl(nsIPresContext* aPresContext);
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
// nsISupports interface...
NS_DECL_ISUPPORTS
// nsIContentViewer interface...
NS_IMETHOD Init(nsNativeWidget aParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling = nsScrollPreference_kAuto);
NS_IMETHOD BindToDocument(nsISupports* aDoc, const char* aCommand);
NS_IMETHOD SetContainer(nsIContentViewerContainer* aContainer);
NS_IMETHOD GetContainer(nsIContentViewerContainer*& aContainerResult);
NS_IMETHOD Stop(void);
NS_IMETHOD GetBounds(nsRect& aResult);
NS_IMETHOD SetBounds(const nsRect& aBounds);
NS_IMETHOD Move(PRInt32 aX, PRInt32 aY);
NS_IMETHOD Show();
NS_IMETHOD Hide();
NS_IMETHOD Print(void);
// nsIDocumentViewer interface...
NS_IMETHOD SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet);
NS_IMETHOD GetDocument(nsIDocument*& aResult);
NS_IMETHOD GetPresShell(nsIPresShell*& aResult);
NS_IMETHOD GetPresContext(nsIPresContext*& aResult);
NS_IMETHOD CreateDocumentViewerUsing(nsIPresContext* aPresContext,
nsIDocumentViewer*& aResult);
protected:
virtual ~DocumentViewerImpl();
private:
void ForceRefresh(void);
nsresult CreateStyleSet(nsIDocument* aDocument, nsIStyleSet** aStyleSet);
nsresult MakeWindow(nsNativeWidget aNativeParent,
const nsRect& aBounds,
nsScrollPreference aScrolling);
protected:
// IMPORTANT: The ownership implicit in the following member
// variables has been explicitly checked and set using nsCOMPtr
// for owning pointers and raw COM interface pointers for weak
// (ie, non owning) references. If you add any members to this
// class, please make the ownership explicit (pinkerton, scc).
nsIContentViewerContainer* mContainer; // [WEAK] it owns me!
nsCOMPtr<nsIDeviceContext> mDeviceContext; // ??? can't hurt, but...
nsIView* mView; // [WEAK] cleaned up by view mgr
// the following six items are explicitly in this order
// so they will be destroyed in the reverse order (pinkerton, scc)
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsIWidget> mWindow; // ??? should we really own it?
nsCOMPtr<nsIViewManager> mViewManager;
nsCOMPtr<nsIPresContext> mPresContext;
nsCOMPtr<nsIPresShell> mPresShell;
nsCOMPtr<nsIStyleSheet> mUAStyleSheet;
};
//Class IDs
static NS_DEFINE_IID(kViewManagerCID, NS_VIEW_MANAGER_CID);
static NS_DEFINE_IID(kScrollingViewCID, NS_SCROLLING_VIEW_CID);
static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
static NS_DEFINE_IID(kViewCID, NS_VIEW_CID);
// Interface IDs
static NS_DEFINE_IID(kIScriptContextOwnerIID, NS_ISCRIPTCONTEXTOWNER_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID);
static NS_DEFINE_IID(kIViewManagerIID, NS_IVIEWMANAGER_IID);
static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID);
static NS_DEFINE_IID(kScrollViewIID, NS_ISCROLLABLEVIEW_IID);
static NS_DEFINE_IID(kIContentViewerIID, NS_ICONTENT_VIEWER_IID);
static NS_DEFINE_IID(kIDocumentViewerIID, NS_IDOCUMENT_VIEWER_IID);
static NS_DEFINE_IID(kILinkHandlerIID, NS_ILINKHANDLER_IID);
nsresult
NS_NewDocumentViewer(nsIDocumentViewer** aResult)
{
NS_PRECONDITION(aResult, "null OUT ptr");
if (!aResult) {
return NS_ERROR_NULL_POINTER;
}
DocumentViewerImpl* it = new DocumentViewerImpl();
if (nsnull == it) {
*aResult = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
return it->QueryInterface(kIDocumentViewerIID, (void**) aResult);
}
// Note: operator new zeros our memory
DocumentViewerImpl::DocumentViewerImpl()
{
NS_INIT_REFCNT();
}
DocumentViewerImpl::DocumentViewerImpl(nsIPresContext* aPresContext)
: mPresContext(dont_QueryInterface(aPresContext))
{
NS_INIT_REFCNT();
}
// ISupports implementation...
NS_IMPL_ADDREF(DocumentViewerImpl)
NS_IMPL_RELEASE(DocumentViewerImpl)
nsresult DocumentViewerImpl::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIContentViewerIID)) {
nsIContentViewer* tmp = this;
*aInstancePtr = (void*)tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kIDocumentViewerIID)) {
nsIDocumentViewer* tmp = this;
*aInstancePtr = (void*) tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
nsIContentViewer* tmp1 = this;
nsISupports* tmp2 = tmp1;
*aInstancePtr = (void*) tmp2;
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE;
}
DocumentViewerImpl::~DocumentViewerImpl()
{
if (mDocument) {
// Break global object circular reference on the document created
// in the DocViewer Init
nsIScriptContextOwner *mOwner = mDocument->GetScriptContextOwner();
if (nsnull != mOwner) {
nsIScriptGlobalObject *mGlobal;
mOwner->GetScriptGlobalObject(&mGlobal);
if (nsnull != mGlobal) {
mGlobal->SetNewDocument(nsnull);
NS_RELEASE(mGlobal);
}
NS_RELEASE(mOwner);
// out of band cleanup of webshell
mDocument->SetScriptContextOwner(nsnull);
}
}
if (mDeviceContext)
mDeviceContext->FlushFontCache();
if (mPresShell) {
// Break circular reference (or something)
mPresShell->EndObservingDocument();
}
}
/*
* 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
DocumentViewerImpl::BindToDocument(nsISupports *aDoc, const char *aCommand)
{
NS_PRECONDITION(!mDocument, "Viewer is already bound to a document!");
#ifdef NOISY_VIEWER
printf("DocumentViewerImpl::BindToDocument\n");
#endif
nsresult rv;
mDocument = do_QueryInterface(aDoc,&rv);
return rv;
}
NS_IMETHODIMP
DocumentViewerImpl::SetContainer(nsIContentViewerContainer* aContainer)
{
mContainer = aContainer;
if (mPresContext) {
mPresContext->SetContainer(aContainer);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetContainer(nsIContentViewerContainer*& aResult)
{
aResult = mContainer;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Init(nsNativeWidget aNativeParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling)
{
nsresult rv;
if (!mDocument) {
return NS_ERROR_NULL_POINTER;
}
mDeviceContext = dont_QueryInterface(aDeviceContext);
PRBool makeCX = PR_FALSE;
if (!mPresContext) {
// Create presentation context
rv = NS_NewGalleyContext(getter_AddRefs(mPresContext));
if (NS_OK != rv) {
return rv;
}
mPresContext->Init(aDeviceContext, aPrefs);
makeCX = PR_TRUE;
}
if (nsnull != mContainer) {
nsILinkHandler* linkHandler = nsnull;
mContainer->QueryCapability(kILinkHandlerIID, (void**)&linkHandler);
mPresContext->SetContainer(mContainer);
mPresContext->SetLinkHandler(linkHandler);
NS_IF_RELEASE(linkHandler);
// Set script-context-owner in the document
nsIScriptContextOwner* owner = nsnull;
mContainer->QueryCapability(kIScriptContextOwnerIID, (void**)&owner);
if (nsnull != owner) {
mDocument->SetScriptContextOwner(owner);
nsIScriptGlobalObject* global;
rv = owner->GetScriptGlobalObject(&global);
if (NS_SUCCEEDED(rv) && (nsnull != global)) {
nsIDOMDocument *domdoc = nsnull;
mDocument->QueryInterface(kIDOMDocumentIID,
(void**) &domdoc);
if (nsnull != domdoc) {
global->SetNewDocument(domdoc);
NS_RELEASE(domdoc);
}
NS_RELEASE(global);
}
NS_RELEASE(owner);
}
}
// Create the ViewManager and Root View...
MakeWindow(aNativeParent, aBounds, aScrolling);
// Create the style set...
nsIStyleSet* styleSet;
rv = CreateStyleSet(mDocument, &styleSet);
if (NS_OK == rv) {
// Now make the shell for the document
rv = mDocument->CreateShell(mPresContext, mViewManager, styleSet,
getter_AddRefs(mPresShell));
NS_RELEASE(styleSet);
if (NS_OK == rv) {
// Initialize our view manager
nsRect bounds;
mWindow->GetBounds(bounds);
nscoord width = bounds.width;
nscoord height = bounds.height;
float p2t;
mPresContext->GetPixelsToTwips(&p2t);
width = NSIntPixelsToTwips(width, p2t);
height = NSIntPixelsToTwips(height, p2t);
mViewManager->DisableRefresh();
mViewManager->SetWindowDimensions(width, height);
if (!makeCX) {
// Make shell an observer for next time
mPresShell->BeginObservingDocument();
// Resize-reflow this time
mPresShell->InitialReflow(width, height);
// Now trigger a refresh
mViewManager->EnableRefresh();
}
}
}
return rv;
}
NS_IMETHODIMP
DocumentViewerImpl::Stop(void)
{
if (mPresContext) {
mPresContext->Stop();
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet)
{
mUAStyleSheet = dont_QueryInterface(aUAStyleSheet);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetDocument(nsIDocument*& aResult)
{
aResult = mDocument;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetPresShell(nsIPresShell*& aResult)
{
aResult = mPresShell;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetPresContext(nsIPresContext*& aResult)
{
aResult = mPresContext;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetBounds(nsRect& aResult)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->GetBounds(aResult);
}
else {
aResult.SetRect(0, 0, 0, 0);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::SetBounds(const nsRect& aBounds)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
// Don't have the widget repaint. Layout will generate repaint requests
// during reflow
mWindow->Resize(aBounds.x, aBounds.y, aBounds.width, aBounds.height,
PR_FALSE);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Move(PRInt32 aX, PRInt32 aY)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->Move(aX, aY);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Show(void)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->Show(PR_TRUE);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Hide(void)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->Show(PR_FALSE);
}
return NS_OK;
}
static NS_DEFINE_IID(kIDeviceContextSpecFactoryIID, NS_IDEVICE_CONTEXT_SPEC_FACTORY_IID);
static NS_DEFINE_IID(kDeviceContextSpecFactoryCID, NS_DEVICE_CONTEXT_SPEC_FACTORY_CID);
NS_IMETHODIMP DocumentViewerImpl::Print(void)
{
nsIDeviceContextSpecFactory *factory = nsnull;
nsComponentManager::CreateInstance(kDeviceContextSpecFactoryCID, nsnull,
kIDeviceContextSpecFactoryIID,
(void **)&factory);
if (nsnull != factory)
{
nsIDeviceContextSpec *devspec = nsnull;
nsCOMPtr<nsIDeviceContext> dx;
nsIDeviceContext *newdx = nsnull;
factory->CreateDeviceContextSpec(nsnull, devspec, PR_FALSE);
if (nsnull != devspec) {
mPresContext->GetDeviceContext(getter_AddRefs(dx));
if (NS_OK == dx->GetDeviceContextFor(devspec, newdx))
{
nsIPresShell *ps;
nsIPresContext *cx;
nsIStyleSet *ss;
nsIPref *prefs;
nsIViewManager *vm;
PRInt32 width, height;
nsIView *view;
NS_RELEASE(devspec);
newdx->BeginDocument();
newdx->GetDeviceSurfaceDimensions(width, height);
NS_NewPrintContext(&cx);
mPresContext->GetPrefs(&prefs);
cx->Init(newdx, prefs);
CreateStyleSet(mDocument, &ss);
NS_NewPresShell(&ps);
{
nsresult rv;
rv = nsComponentManager::CreateInstance(kViewManagerCID,
nsnull,
kIViewManagerIID,
(void **)&vm);
if ((NS_OK != rv) || (NS_OK != vm->Init(newdx))) {
NS_ASSERTION(PR_FALSE, "can't get good VM");
}
nsRect tbounds = nsRect(0, 0, width, height);
// Create a child window of the parent that is our "root view/window"
// Create a view
rv = nsComponentManager::CreateInstance(kViewCID,
nsnull,
kIViewIID,
(void **)&view);
if ((NS_OK != rv) || (NS_OK != view->Init(vm,
tbounds,
nsnull))) {
NS_ASSERTION(PR_FALSE, "can't get good view");
}
// Setup hierarchical relationship in view manager
vm->SetRootView(view);
}
ps->Init(mDocument, cx, vm, ss);
//lay it out...
//newdx->BeginDocument();
ps->InitialReflow(width, height);
// Ask the page sequence frame to print all the pages
nsIPageSequenceFrame* pageSequence;
nsPrintOptions options;
ps->GetPageSequenceFrame(&pageSequence);
NS_ASSERTION(nsnull != pageSequence, "no page sequence frame");
pageSequence->Print(*cx, options, nsnull);
newdx->EndDocument();
NS_RELEASE(ps);
NS_RELEASE(vm);
NS_RELEASE(ss);
NS_RELEASE(newdx);
NS_IF_RELEASE(prefs); // XXX why is the prefs null??
}
}
NS_RELEASE(factory);
}
return NS_OK;
}
void DocumentViewerImpl::ForceRefresh()
{
mWindow->Invalidate(PR_TRUE);
}
nsresult
DocumentViewerImpl::CreateStyleSet(nsIDocument* aDocument,
nsIStyleSet** aStyleSet)
{
// this should eventually get expanded to allow for creating
// different sets for different media
nsresult rv;
if (!mUAStyleSheet) {
NS_WARNING("unable to load UA style sheet");
}
rv = NS_NewStyleSet(aStyleSet);
if (NS_OK == rv) {
PRInt32 index = aDocument->GetNumberOfStyleSheets();
while (0 < index--) {
nsIStyleSheet* sheet = aDocument->GetStyleSheetAt(index);
(*aStyleSet)->AddDocStyleSheet(sheet, aDocument);
NS_RELEASE(sheet);
}
if (mUAStyleSheet) {
(*aStyleSet)->AppendBackstopStyleSheet(mUAStyleSheet);
}
}
return rv;
}
nsresult
DocumentViewerImpl::MakeWindow(nsNativeWidget aNativeParent,
const nsRect& aBounds,
nsScrollPreference aScrolling)
{
nsresult rv;
rv = nsComponentManager::CreateInstance(kViewManagerCID,
nsnull,
kIViewManagerIID,
getter_AddRefs(mViewManager));
nsCOMPtr<nsIDeviceContext> dx;
mPresContext->GetDeviceContext(getter_AddRefs(dx));
if ((NS_OK != rv) || (NS_OK != mViewManager->Init(dx))) {
return rv;
}
nsRect tbounds = aBounds;
float p2t;
mPresContext->GetPixelsToTwips(&p2t);
tbounds *= p2t;
// Create a child window of the parent that is our "root view/window"
// Create a view
rv = nsComponentManager::CreateInstance(kViewCID,
nsnull,
kIViewIID,
(void**)&mView);
static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
if ((NS_OK != rv) || (NS_OK != mView->Init(mViewManager,
tbounds,
nsnull))) {
return rv;
}
rv = mView->CreateWidget(kWidgetCID, nsnull, aNativeParent);
if (rv != NS_OK)
return rv;
// Setup hierarchical relationship in view manager
mViewManager->SetRootView(mView);
mView->GetWidget(*getter_AddRefs(mWindow));
//set frame rate to 25 fps
mViewManager->SetFrameRate(25);
// This SetFocus is necessary so the Arrow Key and Page Key events
// go to the scrolled view as soon as the Window is created instead of going to
// the browser window (this enables keyboard scrolling of the document)
mWindow->SetFocus();
return rv;
}
NS_IMETHODIMP
DocumentViewerImpl::CreateDocumentViewerUsing(nsIPresContext* aPresContext,
nsIDocumentViewer*& aResult)
{
if (!mDocument) {
// XXX better error
return NS_ERROR_NULL_POINTER;
}
if (nsnull == aPresContext) {
return NS_ERROR_NULL_POINTER;
}
// Create new viewer
DocumentViewerImpl* viewer = new DocumentViewerImpl(aPresContext);
if (nsnull == viewer) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(viewer);
// XXX make sure the ua style sheet is used (for now; need to be
// able to specify an alternate)
viewer->SetUAStyleSheet(mUAStyleSheet);
// Bind the new viewer to the old document
nsresult rv = viewer->BindToDocument(mDocument, "create");/* XXX verb? */
aResult = viewer;
return rv;
}

View File

@ -0,0 +1,692 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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 Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
#include "nslayout.h"
#include "nsCOMPtr.h"
#include "nsCRT.h"
#include "nsString.h"
#include "nsISupports.h"
#include "nsIContentViewerContainer.h"
#include "nsIDocumentViewer.h"
#include "nsIDocument.h"
#include "nsIPresContext.h"
#include "nsIPresShell.h"
#include "nsIStyleSet.h"
#include "nsIStyleSheet.h"
#include "nsIFrame.h"
#include "nsIScriptContextOwner.h"
#include "nsIScriptGlobalObject.h"
#include "nsILinkHandler.h"
#include "nsIDOMDocument.h"
#include "nsViewsCID.h"
#include "nsWidgetsCID.h"
#include "nsGfxCIID.h"
#include "nsIDeviceContext.h"
#include "nsIDeviceContextSpec.h"
#include "nsIDeviceContextSpecFactory.h"
#include "nsIViewManager.h"
#include "nsIView.h"
#include "nsIPref.h"
#include "nsIPageSequenceFrame.h"
#include "nsIURL.h"
#ifdef NS_DEBUG
#undef NOISY_VIEWER
#else
#undef NOISY_VIEWER
#endif
class DocumentViewerImpl : public nsIDocumentViewer
{
public:
DocumentViewerImpl();
DocumentViewerImpl(nsIPresContext* aPresContext);
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
// nsISupports interface...
NS_DECL_ISUPPORTS
// nsIContentViewer interface...
NS_IMETHOD Init(nsNativeWidget aParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling = nsScrollPreference_kAuto);
NS_IMETHOD BindToDocument(nsISupports* aDoc, const char* aCommand);
NS_IMETHOD SetContainer(nsIContentViewerContainer* aContainer);
NS_IMETHOD GetContainer(nsIContentViewerContainer*& aContainerResult);
NS_IMETHOD Stop(void);
NS_IMETHOD GetBounds(nsRect& aResult);
NS_IMETHOD SetBounds(const nsRect& aBounds);
NS_IMETHOD Move(PRInt32 aX, PRInt32 aY);
NS_IMETHOD Show();
NS_IMETHOD Hide();
NS_IMETHOD Print(void);
// nsIDocumentViewer interface...
NS_IMETHOD SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet);
NS_IMETHOD GetDocument(nsIDocument*& aResult);
NS_IMETHOD GetPresShell(nsIPresShell*& aResult);
NS_IMETHOD GetPresContext(nsIPresContext*& aResult);
NS_IMETHOD CreateDocumentViewerUsing(nsIPresContext* aPresContext,
nsIDocumentViewer*& aResult);
protected:
virtual ~DocumentViewerImpl();
private:
void ForceRefresh(void);
nsresult CreateStyleSet(nsIDocument* aDocument, nsIStyleSet** aStyleSet);
nsresult MakeWindow(nsNativeWidget aNativeParent,
const nsRect& aBounds,
nsScrollPreference aScrolling);
protected:
// IMPORTANT: The ownership implicit in the following member
// variables has been explicitly checked and set using nsCOMPtr
// for owning pointers and raw COM interface pointers for weak
// (ie, non owning) references. If you add any members to this
// class, please make the ownership explicit (pinkerton, scc).
nsIContentViewerContainer* mContainer; // [WEAK] it owns me!
nsCOMPtr<nsIDeviceContext> mDeviceContext; // ??? can't hurt, but...
nsIView* mView; // [WEAK] cleaned up by view mgr
// the following six items are explicitly in this order
// so they will be destroyed in the reverse order (pinkerton, scc)
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsIWidget> mWindow; // ??? should we really own it?
nsCOMPtr<nsIViewManager> mViewManager;
nsCOMPtr<nsIPresContext> mPresContext;
nsCOMPtr<nsIPresShell> mPresShell;
nsCOMPtr<nsIStyleSheet> mUAStyleSheet;
};
//Class IDs
static NS_DEFINE_IID(kViewManagerCID, NS_VIEW_MANAGER_CID);
static NS_DEFINE_IID(kScrollingViewCID, NS_SCROLLING_VIEW_CID);
static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
static NS_DEFINE_IID(kViewCID, NS_VIEW_CID);
// Interface IDs
static NS_DEFINE_IID(kIScriptContextOwnerIID, NS_ISCRIPTCONTEXTOWNER_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID);
static NS_DEFINE_IID(kIViewManagerIID, NS_IVIEWMANAGER_IID);
static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID);
static NS_DEFINE_IID(kScrollViewIID, NS_ISCROLLABLEVIEW_IID);
static NS_DEFINE_IID(kIContentViewerIID, NS_ICONTENT_VIEWER_IID);
static NS_DEFINE_IID(kIDocumentViewerIID, NS_IDOCUMENT_VIEWER_IID);
static NS_DEFINE_IID(kILinkHandlerIID, NS_ILINKHANDLER_IID);
nsresult
NS_NewDocumentViewer(nsIDocumentViewer** aResult)
{
NS_PRECONDITION(aResult, "null OUT ptr");
if (!aResult) {
return NS_ERROR_NULL_POINTER;
}
DocumentViewerImpl* it = new DocumentViewerImpl();
if (nsnull == it) {
*aResult = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
return it->QueryInterface(kIDocumentViewerIID, (void**) aResult);
}
// Note: operator new zeros our memory
DocumentViewerImpl::DocumentViewerImpl()
{
NS_INIT_REFCNT();
}
DocumentViewerImpl::DocumentViewerImpl(nsIPresContext* aPresContext)
: mPresContext(dont_QueryInterface(aPresContext))
{
NS_INIT_REFCNT();
}
// ISupports implementation...
NS_IMPL_ADDREF(DocumentViewerImpl)
NS_IMPL_RELEASE(DocumentViewerImpl)
nsresult DocumentViewerImpl::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIContentViewerIID)) {
nsIContentViewer* tmp = this;
*aInstancePtr = (void*)tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kIDocumentViewerIID)) {
nsIDocumentViewer* tmp = this;
*aInstancePtr = (void*) tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
nsIContentViewer* tmp1 = this;
nsISupports* tmp2 = tmp1;
*aInstancePtr = (void*) tmp2;
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE;
}
DocumentViewerImpl::~DocumentViewerImpl()
{
if (mDocument) {
// Break global object circular reference on the document created
// in the DocViewer Init
nsIScriptContextOwner *mOwner = mDocument->GetScriptContextOwner();
if (nsnull != mOwner) {
nsIScriptGlobalObject *mGlobal;
mOwner->GetScriptGlobalObject(&mGlobal);
if (nsnull != mGlobal) {
mGlobal->SetNewDocument(nsnull);
NS_RELEASE(mGlobal);
}
NS_RELEASE(mOwner);
// out of band cleanup of webshell
mDocument->SetScriptContextOwner(nsnull);
}
}
if (mDeviceContext)
mDeviceContext->FlushFontCache();
if (mPresShell) {
// Break circular reference (or something)
mPresShell->EndObservingDocument();
}
}
/*
* 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
DocumentViewerImpl::BindToDocument(nsISupports *aDoc, const char *aCommand)
{
NS_PRECONDITION(!mDocument, "Viewer is already bound to a document!");
#ifdef NOISY_VIEWER
printf("DocumentViewerImpl::BindToDocument\n");
#endif
nsresult rv;
mDocument = do_QueryInterface(aDoc,&rv);
return rv;
}
NS_IMETHODIMP
DocumentViewerImpl::SetContainer(nsIContentViewerContainer* aContainer)
{
mContainer = aContainer;
if (mPresContext) {
mPresContext->SetContainer(aContainer);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetContainer(nsIContentViewerContainer*& aResult)
{
aResult = mContainer;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Init(nsNativeWidget aNativeParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling)
{
nsresult rv;
if (!mDocument) {
return NS_ERROR_NULL_POINTER;
}
mDeviceContext = dont_QueryInterface(aDeviceContext);
PRBool makeCX = PR_FALSE;
if (!mPresContext) {
// Create presentation context
rv = NS_NewGalleyContext(getter_AddRefs(mPresContext));
if (NS_OK != rv) {
return rv;
}
mPresContext->Init(aDeviceContext, aPrefs);
makeCX = PR_TRUE;
}
if (nsnull != mContainer) {
nsILinkHandler* linkHandler = nsnull;
mContainer->QueryCapability(kILinkHandlerIID, (void**)&linkHandler);
mPresContext->SetContainer(mContainer);
mPresContext->SetLinkHandler(linkHandler);
NS_IF_RELEASE(linkHandler);
// Set script-context-owner in the document
nsIScriptContextOwner* owner = nsnull;
mContainer->QueryCapability(kIScriptContextOwnerIID, (void**)&owner);
if (nsnull != owner) {
mDocument->SetScriptContextOwner(owner);
nsIScriptGlobalObject* global;
rv = owner->GetScriptGlobalObject(&global);
if (NS_SUCCEEDED(rv) && (nsnull != global)) {
nsIDOMDocument *domdoc = nsnull;
mDocument->QueryInterface(kIDOMDocumentIID,
(void**) &domdoc);
if (nsnull != domdoc) {
global->SetNewDocument(domdoc);
NS_RELEASE(domdoc);
}
NS_RELEASE(global);
}
NS_RELEASE(owner);
}
}
// Create the ViewManager and Root View...
MakeWindow(aNativeParent, aBounds, aScrolling);
// Create the style set...
nsIStyleSet* styleSet;
rv = CreateStyleSet(mDocument, &styleSet);
if (NS_OK == rv) {
// Now make the shell for the document
rv = mDocument->CreateShell(mPresContext, mViewManager, styleSet,
getter_AddRefs(mPresShell));
NS_RELEASE(styleSet);
if (NS_OK == rv) {
// Initialize our view manager
nsRect bounds;
mWindow->GetBounds(bounds);
nscoord width = bounds.width;
nscoord height = bounds.height;
float p2t;
mPresContext->GetPixelsToTwips(&p2t);
width = NSIntPixelsToTwips(width, p2t);
height = NSIntPixelsToTwips(height, p2t);
mViewManager->DisableRefresh();
mViewManager->SetWindowDimensions(width, height);
if (!makeCX) {
// Make shell an observer for next time
mPresShell->BeginObservingDocument();
// Resize-reflow this time
mPresShell->InitialReflow(width, height);
// Now trigger a refresh
mViewManager->EnableRefresh();
}
}
}
return rv;
}
NS_IMETHODIMP
DocumentViewerImpl::Stop(void)
{
if (mPresContext) {
mPresContext->Stop();
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet)
{
mUAStyleSheet = dont_QueryInterface(aUAStyleSheet);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetDocument(nsIDocument*& aResult)
{
aResult = mDocument;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetPresShell(nsIPresShell*& aResult)
{
aResult = mPresShell;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetPresContext(nsIPresContext*& aResult)
{
aResult = mPresContext;
NS_IF_ADDREF(aResult);
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::GetBounds(nsRect& aResult)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->GetBounds(aResult);
}
else {
aResult.SetRect(0, 0, 0, 0);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::SetBounds(const nsRect& aBounds)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
// Don't have the widget repaint. Layout will generate repaint requests
// during reflow
mWindow->Resize(aBounds.x, aBounds.y, aBounds.width, aBounds.height,
PR_FALSE);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Move(PRInt32 aX, PRInt32 aY)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->Move(aX, aY);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Show(void)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->Show(PR_TRUE);
}
return NS_OK;
}
NS_IMETHODIMP
DocumentViewerImpl::Hide(void)
{
NS_PRECONDITION(mWindow, "null window");
if (mWindow) {
mWindow->Show(PR_FALSE);
}
return NS_OK;
}
static NS_DEFINE_IID(kIDeviceContextSpecFactoryIID, NS_IDEVICE_CONTEXT_SPEC_FACTORY_IID);
static NS_DEFINE_IID(kDeviceContextSpecFactoryCID, NS_DEVICE_CONTEXT_SPEC_FACTORY_CID);
NS_IMETHODIMP DocumentViewerImpl::Print(void)
{
nsIDeviceContextSpecFactory *factory = nsnull;
nsComponentManager::CreateInstance(kDeviceContextSpecFactoryCID, nsnull,
kIDeviceContextSpecFactoryIID,
(void **)&factory);
if (nsnull != factory)
{
nsIDeviceContextSpec *devspec = nsnull;
nsCOMPtr<nsIDeviceContext> dx;
nsIDeviceContext *newdx = nsnull;
factory->CreateDeviceContextSpec(nsnull, devspec, PR_FALSE);
if (nsnull != devspec) {
mPresContext->GetDeviceContext(getter_AddRefs(dx));
if (NS_OK == dx->GetDeviceContextFor(devspec, newdx))
{
nsIPresShell *ps;
nsIPresContext *cx;
nsIStyleSet *ss;
nsIPref *prefs;
nsIViewManager *vm;
PRInt32 width, height;
nsIView *view;
NS_RELEASE(devspec);
newdx->BeginDocument();
newdx->GetDeviceSurfaceDimensions(width, height);
NS_NewPrintContext(&cx);
mPresContext->GetPrefs(&prefs);
cx->Init(newdx, prefs);
CreateStyleSet(mDocument, &ss);
NS_NewPresShell(&ps);
{
nsresult rv;
rv = nsComponentManager::CreateInstance(kViewManagerCID,
nsnull,
kIViewManagerIID,
(void **)&vm);
if ((NS_OK != rv) || (NS_OK != vm->Init(newdx))) {
NS_ASSERTION(PR_FALSE, "can't get good VM");
}
nsRect tbounds = nsRect(0, 0, width, height);
// Create a child window of the parent that is our "root view/window"
// Create a view
rv = nsComponentManager::CreateInstance(kViewCID,
nsnull,
kIViewIID,
(void **)&view);
if ((NS_OK != rv) || (NS_OK != view->Init(vm,
tbounds,
nsnull))) {
NS_ASSERTION(PR_FALSE, "can't get good view");
}
// Setup hierarchical relationship in view manager
vm->SetRootView(view);
}
ps->Init(mDocument, cx, vm, ss);
//lay it out...
//newdx->BeginDocument();
ps->InitialReflow(width, height);
// Ask the page sequence frame to print all the pages
nsIPageSequenceFrame* pageSequence;
nsPrintOptions options;
ps->GetPageSequenceFrame(&pageSequence);
NS_ASSERTION(nsnull != pageSequence, "no page sequence frame");
pageSequence->Print(*cx, options, nsnull);
newdx->EndDocument();
NS_RELEASE(ps);
NS_RELEASE(vm);
NS_RELEASE(ss);
NS_RELEASE(newdx);
NS_IF_RELEASE(prefs); // XXX why is the prefs null??
}
}
NS_RELEASE(factory);
}
return NS_OK;
}
void DocumentViewerImpl::ForceRefresh()
{
mWindow->Invalidate(PR_TRUE);
}
nsresult
DocumentViewerImpl::CreateStyleSet(nsIDocument* aDocument,
nsIStyleSet** aStyleSet)
{
// this should eventually get expanded to allow for creating
// different sets for different media
nsresult rv;
if (!mUAStyleSheet) {
NS_WARNING("unable to load UA style sheet");
}
rv = NS_NewStyleSet(aStyleSet);
if (NS_OK == rv) {
PRInt32 index = aDocument->GetNumberOfStyleSheets();
while (0 < index--) {
nsIStyleSheet* sheet = aDocument->GetStyleSheetAt(index);
(*aStyleSet)->AddDocStyleSheet(sheet, aDocument);
NS_RELEASE(sheet);
}
if (mUAStyleSheet) {
(*aStyleSet)->AppendBackstopStyleSheet(mUAStyleSheet);
}
}
return rv;
}
nsresult
DocumentViewerImpl::MakeWindow(nsNativeWidget aNativeParent,
const nsRect& aBounds,
nsScrollPreference aScrolling)
{
nsresult rv;
rv = nsComponentManager::CreateInstance(kViewManagerCID,
nsnull,
kIViewManagerIID,
getter_AddRefs(mViewManager));
nsCOMPtr<nsIDeviceContext> dx;
mPresContext->GetDeviceContext(getter_AddRefs(dx));
if ((NS_OK != rv) || (NS_OK != mViewManager->Init(dx))) {
return rv;
}
nsRect tbounds = aBounds;
float p2t;
mPresContext->GetPixelsToTwips(&p2t);
tbounds *= p2t;
// Create a child window of the parent that is our "root view/window"
// Create a view
rv = nsComponentManager::CreateInstance(kViewCID,
nsnull,
kIViewIID,
(void**)&mView);
static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
if ((NS_OK != rv) || (NS_OK != mView->Init(mViewManager,
tbounds,
nsnull))) {
return rv;
}
rv = mView->CreateWidget(kWidgetCID, nsnull, aNativeParent);
if (rv != NS_OK)
return rv;
// Setup hierarchical relationship in view manager
mViewManager->SetRootView(mView);
mView->GetWidget(*getter_AddRefs(mWindow));
//set frame rate to 25 fps
mViewManager->SetFrameRate(25);
// This SetFocus is necessary so the Arrow Key and Page Key events
// go to the scrolled view as soon as the Window is created instead of going to
// the browser window (this enables keyboard scrolling of the document)
mWindow->SetFocus();
return rv;
}
NS_IMETHODIMP
DocumentViewerImpl::CreateDocumentViewerUsing(nsIPresContext* aPresContext,
nsIDocumentViewer*& aResult)
{
if (!mDocument) {
// XXX better error
return NS_ERROR_NULL_POINTER;
}
if (nsnull == aPresContext) {
return NS_ERROR_NULL_POINTER;
}
// Create new viewer
DocumentViewerImpl* viewer = new DocumentViewerImpl(aPresContext);
if (nsnull == viewer) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(viewer);
// XXX make sure the ua style sheet is used (for now; need to be
// able to specify an alternate)
viewer->SetUAStyleSheet(mUAStyleSheet);
// Bind the new viewer to the old document
nsresult rv = viewer->BindToDocument(mDocument, "create");/* XXX verb? */
aResult = viewer;
return rv;
}

View File

@ -0,0 +1,765 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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 Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
#include "nscore.h"
#include "nsCRT.h"
#include "nsIContentViewer.h"
#include "nsIContentViewerContainer.h"
#include "nsIPluginHost.h"
#include "nsIPluginInstance.h"
#include "nsIStreamListener.h"
#include "nsIURL.h"
#include "nsIComponentManager.h"
#include "nsWidgetsCID.h"
#include "nsILinkHandler.h"
#include "nsIWebShell.h"
#include "nsIBrowserWindow.h"
#include "nsIContent.h"
#include "nsIDocument.h"
// 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_ICONTENT_VIEWER_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kIPluginHostIID, NS_IPLUGINHOST_IID);
static NS_DEFINE_IID(kIPluginInstanceOwnerIID, NS_IPLUGININSTANCEOWNER_IID);
static NS_DEFINE_IID(kILinkHandlerIID, NS_ILINKHANDLER_IID);
static NS_DEFINE_IID(kIStreamListenerIID, NS_ISTREAMLISTENER_IID);
static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID);
static NS_DEFINE_IID(kIBrowserWindowIID, NS_IBROWSER_WINDOW_IID);
static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
class PluginViewerImpl;
class PluginListener : public nsIStreamListener {
public:
PluginListener(PluginViewerImpl* aViewer);
virtual ~PluginListener();
// nsISupports
NS_DECL_ISUPPORTS
// nsIStreamListener
NS_IMETHOD OnStartBinding(nsIURL* aURL, const char *aContentType);
NS_IMETHOD OnProgress(nsIURL* aURL, PRUint32 aProgress, PRUint32 aProgressMax);
NS_IMETHOD OnStatus(nsIURL* aURL, const PRUnichar* aMsg);
NS_IMETHOD OnStopBinding(nsIURL* aURL, nsresult aStatus,
const PRUnichar* aMsg);
NS_IMETHOD GetBindInfo(nsIURL* aURL, nsStreamBindingInfo* aInfo);
NS_IMETHOD OnDataAvailable(nsIURL* aURL, nsIInputStream* aStream,
PRUint32 aCount);
PluginViewerImpl* mViewer;
nsIStreamListener* mNextStream;
};
class pluginInstanceOwner : public nsIPluginInstanceOwner {
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);
NS_IMETHOD ShowStatus(const char *aStatusMsg);
NS_IMETHOD GetDocument(nsIDocument* *aDocument);
//locals
NS_IMETHOD Init(PluginViewerImpl *aViewer, nsIWidget *aWindow);
private:
nsPluginWindow mPluginWindow;
nsIPluginInstance *mInstance;
nsIWidget *mWindow; //we do not addref this...
PluginViewerImpl *mViewer; //we do not addref this...
};
class PluginViewerImpl : public nsIContentViewer
{
public:
PluginViewerImpl(const char* aCommand, nsIStreamListener** aDocListener);
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
// nsISupports
NS_DECL_ISUPPORTS
// nsIContentViewer
NS_IMETHOD Init(nsNativeWidget aParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling = nsScrollPreference_kAuto);
NS_IMETHOD BindToDocument(nsISupports* aDoc, const char* aCommand);
NS_IMETHOD SetContainer(nsIContentViewerContainer* aContainer);
NS_IMETHOD GetContainer(nsIContentViewerContainer*& aContainerResult);
NS_IMETHOD Stop(void);
NS_IMETHOD GetBounds(nsRect& aResult);
NS_IMETHOD SetBounds(const nsRect& aBounds);
NS_IMETHOD Move(PRInt32 aX, PRInt32 aY);
NS_IMETHOD Show();
NS_IMETHOD Hide();
NS_IMETHOD Print(void);
virtual ~PluginViewerImpl();
nsresult CreatePlugin(nsIPluginHost* aHost, const nsRect& aBounds,
nsIStreamListener*& aResult);
nsresult MakeWindow(nsNativeWidget aParent,
nsIDeviceContext* aDeviceContext,
const nsRect& aBounds);
nsresult StartLoad(nsIURL* aURL, const char* aContentType,
nsIStreamListener*& aResult);
void ForceRefresh(void);
nsresult GetURL(nsIURL *&aURL);
nsresult GetDocument(nsIDocument* *aDocument);
nsIWidget* mWindow;
nsIDocument* mDocument;
nsIContentViewerContainer* mContainer;
nsIURL* mURL;
nsString mContentType;
pluginInstanceOwner *mOwner;
};
//----------------------------------------------------------------------
nsresult
NS_NewPluginContentViewer(const char* aCommand,
nsIStreamListener** aDocListener,
nsIContentViewer** aDocViewer)
{
PluginViewerImpl* it = new PluginViewerImpl(aCommand, aDocListener);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
return it->QueryInterface(kIContentViewerIID, (void**) aDocViewer);
}
// Note: operator new zeros our memory
PluginViewerImpl::PluginViewerImpl(const char* aCommand,
nsIStreamListener** aDocListener)
{
NS_INIT_REFCNT();
nsIStreamListener* it = new PluginListener(this);
*aDocListener = it;
}
// ISupports implementation...
NS_IMPL_ADDREF(PluginViewerImpl)
NS_IMPL_RELEASE(PluginViewerImpl)
nsresult
PluginViewerImpl::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIContentViewerIID)) {
nsIContentViewer* tmp = this;
*aInstancePtr = (void*)tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
nsISupports* tmp = this;
*aInstancePtr = (void*)tmp;
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE;
}
PluginViewerImpl::~PluginViewerImpl()
{
NS_IF_RELEASE(mOwner);
if (nsnull != mWindow) {
mWindow->Destroy();
NS_RELEASE(mWindow);
}
NS_IF_RELEASE(mDocument);
NS_IF_RELEASE(mContainer);
NS_IF_RELEASE(mURL);
}
/*
* 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::BindToDocument(nsISupports *aDoc, const char *aCommand)
{
#ifdef NS_DEBUG
printf("PluginViewerImpl::BindToDocument\n");
#endif
return aDoc->QueryInterface(kIDocumentIID, (void**)&mDocument);
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::SetContainer(nsIContentViewerContainer* aContainer)
{
NS_IF_RELEASE(mContainer);
mContainer = aContainer;
NS_IF_ADDREF(mContainer);
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::GetContainer(nsIContentViewerContainer*& aResult)
{
aResult = mContainer;
NS_IF_ADDREF(mContainer);
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::Init(nsNativeWidget aNativeParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling)
{
nsresult rv = MakeWindow(aNativeParent, aDeviceContext, aBounds);
if (NS_OK == rv) {
mOwner = new pluginInstanceOwner();
if (nsnull != mOwner) {
NS_ADDREF(mOwner);
rv = mOwner->Init(this, mWindow);
}
}
return rv;
}
nsresult
PluginViewerImpl::StartLoad(nsIURL* aURL, const char* aContentType,
nsIStreamListener*& aResult)
{
printf("PluginViewerImpl::StartLoad: content-type=%s\n", aContentType);
NS_IF_RELEASE(mURL);
mURL = aURL;
NS_IF_ADDREF(aURL);
mContentType = aContentType;
aResult = nsnull;
// Only instantiate the plugin if our container can host it
nsIPluginHost* host;
nsresult rv = mContainer->QueryCapability(kIPluginHostIID, (void **)&host);
if (NS_OK == rv) {
nsRect r;
mWindow->GetClientBounds(r);
rv = CreatePlugin(host, nsRect(0, 0, r.width, r.height), aResult);
NS_RELEASE(host);
}
return rv;
}
nsresult
PluginViewerImpl::CreatePlugin(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
PRUnichar* fullurl;
mURL->ToString(&fullurl);
char* ct = mContentType.ToNewCString();
nsAutoString str = fullurl;
rv = aHost->InstantiateFullPagePlugin(ct, str, aResult, mOwner);
delete fullurl;
delete[] ct;
}
return rv;
}
NS_IMETHODIMP
PluginViewerImpl::Stop(void)
{
// XXX write this
return NS_OK;
}
static nsEventStatus PR_CALLBACK
HandlePluginEvent(nsGUIEvent *aEvent)
{
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);
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::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 :: Print(void)
{
// need to call the plugin from here somehow
return NS_OK;
}
void
PluginViewerImpl::ForceRefresh()
{
mWindow->Invalidate(PR_TRUE);
}
nsresult PluginViewerImpl::GetURL(nsIURL *&aURL)
{
NS_IF_ADDREF(mURL);
aURL = mURL;
return NS_OK;
}
nsresult PluginViewerImpl::GetDocument(nsIDocument* *aDocument)
{
NS_IF_ADDREF(mDocument);
*aDocument = mDocument;
return NS_OK;
}
//----------------------------------------------------------------------
PluginListener::PluginListener(PluginViewerImpl* aViewer)
{
NS_INIT_REFCNT();
mViewer = aViewer;
NS_ADDREF(aViewer);
mRefCnt = 1;
}
PluginListener::~PluginListener()
{
NS_RELEASE(mViewer);
NS_IF_RELEASE(mNextStream);
}
NS_IMPL_ISUPPORTS(PluginListener, kIStreamListenerIID)
NS_IMETHODIMP
PluginListener::OnStartBinding(nsIURL* aURL, const char *aContentType)
{
mViewer->StartLoad(aURL, aContentType, mNextStream);
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnStartBinding(aURL, aContentType);
}
NS_IMETHODIMP
PluginListener::OnProgress(nsIURL* aURL, PRUint32 aProgress,
PRUint32 aProgressMax)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnProgress(aURL, aProgress, aProgressMax);
}
NS_IMETHODIMP
PluginListener::OnStatus(nsIURL* aURL, const PRUnichar* aMsg)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnStatus(aURL, aMsg);
}
NS_IMETHODIMP
PluginListener::OnStopBinding(nsIURL* aURL, nsresult aStatus,
const PRUnichar* aMsg)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnStopBinding(aURL, aStatus, aMsg);
}
NS_IMETHODIMP
PluginListener::GetBindInfo(nsIURL* aURL, nsStreamBindingInfo* aInfo)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->GetBindInfo(aURL, aInfo);
}
NS_IMETHODIMP
PluginListener::OnDataAvailable(nsIURL* aURL, nsIInputStream* aStream,
PRUint32 aCount)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnDataAvailable(aURL, aStream, aCount);
}
//----------------------------------------------------------------------
pluginInstanceOwner :: pluginInstanceOwner()
{
NS_INIT_REFCNT();
memset(&mPluginWindow, 0, sizeof(mPluginWindow));
mInstance = nsnull;
mWindow = nsnull;
mViewer = nsnull;
}
pluginInstanceOwner :: ~pluginInstanceOwner()
{
if (nsnull != mInstance)
{
mInstance->Stop();
mInstance->Destroy();
NS_RELEASE(mInstance);
}
mWindow = nsnull;
mViewer = nsnull;
}
NS_IMPL_ISUPPORTS(pluginInstanceOwner, kIPluginInstanceOwnerIID);
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)
{
NS_IF_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;
if (nsnull != mInstance)
{
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_WINDOW);
mPluginWindow.type = nsPluginWindowType_Window;
}
else
return NS_ERROR_FAILURE;
}
else
return NS_ERROR_FAILURE;
return NS_OK;
}
NS_IMETHODIMP pluginInstanceOwner :: GetURL(const char *aURL, const char *aTarget, void *aPostData)
{
nsresult rv;
if (nsnull != mViewer)
{
nsIContentViewerContainer *cont;
rv = mViewer->GetContainer(cont);
if (NS_OK == rv)
{
nsILinkHandler *lh;
rv = cont->QueryInterface(kILinkHandlerIID, (void **)&lh);
if (NS_OK == rv)
{
nsIURL *url;
rv = mViewer->GetURL(url);
if (NS_OK == rv)
{
nsAutoString uniurl = nsAutoString(aURL);
nsAutoString unitarget = nsAutoString(aTarget);
const char* spec;
(void)url->GetSpec(&spec);
nsAutoString base = nsAutoString(spec);
nsAutoString fullurl;
// Create an absolute URL
rv = NS_MakeAbsoluteURL(url, base, uniurl, fullurl);
if (NS_OK == rv)
rv = lh->OnLinkClick(nsnull, eLinkVerb_Replace, fullurl.GetUnicode(), unitarget.GetUnicode(), nsnull);
NS_RELEASE(url);
}
NS_RELEASE(lh);
}
NS_RELEASE(cont);
}
}
else
rv = NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP pluginInstanceOwner :: ShowStatus(const char *aStatusMsg)
{
nsresult rv = NS_ERROR_FAILURE;
if (nsnull != mViewer)
{
nsIContentViewerContainer *cont;
rv = mViewer->GetContainer(cont);
if ((NS_OK == rv) && (nsnull != cont))
{
nsIWebShell *ws;
rv = cont->QueryInterface(kIWebShellIID, (void **)&ws);
if (NS_OK == rv)
{
nsIWebShell *rootWebShell;
ws->GetRootWebShell(rootWebShell);
if (nsnull != rootWebShell)
{
nsIWebShellContainer *rootContainer;
rv = rootWebShell->GetContainer(rootContainer);
if (nsnull != rootContainer)
{
nsIBrowserWindow *browserWindow;
if (NS_OK == rootContainer->QueryInterface(kIBrowserWindowIID, (void**)&browserWindow))
{
nsAutoString msg = nsAutoString(aStatusMsg);
rv = browserWindow->SetStatus(msg.GetUnicode());
NS_RELEASE(browserWindow);
}
NS_RELEASE(rootContainer);
}
NS_RELEASE(rootWebShell);
}
NS_RELEASE(ws);
}
NS_RELEASE(cont);
}
}
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;
}

View File

@ -0,0 +1,765 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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 Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
#include "nscore.h"
#include "nsCRT.h"
#include "nsIContentViewer.h"
#include "nsIContentViewerContainer.h"
#include "nsIPluginHost.h"
#include "nsIPluginInstance.h"
#include "nsIStreamListener.h"
#include "nsIURL.h"
#include "nsIComponentManager.h"
#include "nsWidgetsCID.h"
#include "nsILinkHandler.h"
#include "nsIWebShell.h"
#include "nsIBrowserWindow.h"
#include "nsIContent.h"
#include "nsIDocument.h"
// 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_ICONTENT_VIEWER_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kIPluginHostIID, NS_IPLUGINHOST_IID);
static NS_DEFINE_IID(kIPluginInstanceOwnerIID, NS_IPLUGININSTANCEOWNER_IID);
static NS_DEFINE_IID(kILinkHandlerIID, NS_ILINKHANDLER_IID);
static NS_DEFINE_IID(kIStreamListenerIID, NS_ISTREAMLISTENER_IID);
static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID);
static NS_DEFINE_IID(kIBrowserWindowIID, NS_IBROWSER_WINDOW_IID);
static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
class PluginViewerImpl;
class PluginListener : public nsIStreamListener {
public:
PluginListener(PluginViewerImpl* aViewer);
virtual ~PluginListener();
// nsISupports
NS_DECL_ISUPPORTS
// nsIStreamListener
NS_IMETHOD OnStartBinding(nsIURL* aURL, const char *aContentType);
NS_IMETHOD OnProgress(nsIURL* aURL, PRUint32 aProgress, PRUint32 aProgressMax);
NS_IMETHOD OnStatus(nsIURL* aURL, const PRUnichar* aMsg);
NS_IMETHOD OnStopBinding(nsIURL* aURL, nsresult aStatus,
const PRUnichar* aMsg);
NS_IMETHOD GetBindInfo(nsIURL* aURL, nsStreamBindingInfo* aInfo);
NS_IMETHOD OnDataAvailable(nsIURL* aURL, nsIInputStream* aStream,
PRUint32 aCount);
PluginViewerImpl* mViewer;
nsIStreamListener* mNextStream;
};
class pluginInstanceOwner : public nsIPluginInstanceOwner {
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);
NS_IMETHOD ShowStatus(const char *aStatusMsg);
NS_IMETHOD GetDocument(nsIDocument* *aDocument);
//locals
NS_IMETHOD Init(PluginViewerImpl *aViewer, nsIWidget *aWindow);
private:
nsPluginWindow mPluginWindow;
nsIPluginInstance *mInstance;
nsIWidget *mWindow; //we do not addref this...
PluginViewerImpl *mViewer; //we do not addref this...
};
class PluginViewerImpl : public nsIContentViewer
{
public:
PluginViewerImpl(const char* aCommand, nsIStreamListener** aDocListener);
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
// nsISupports
NS_DECL_ISUPPORTS
// nsIContentViewer
NS_IMETHOD Init(nsNativeWidget aParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling = nsScrollPreference_kAuto);
NS_IMETHOD BindToDocument(nsISupports* aDoc, const char* aCommand);
NS_IMETHOD SetContainer(nsIContentViewerContainer* aContainer);
NS_IMETHOD GetContainer(nsIContentViewerContainer*& aContainerResult);
NS_IMETHOD Stop(void);
NS_IMETHOD GetBounds(nsRect& aResult);
NS_IMETHOD SetBounds(const nsRect& aBounds);
NS_IMETHOD Move(PRInt32 aX, PRInt32 aY);
NS_IMETHOD Show();
NS_IMETHOD Hide();
NS_IMETHOD Print(void);
virtual ~PluginViewerImpl();
nsresult CreatePlugin(nsIPluginHost* aHost, const nsRect& aBounds,
nsIStreamListener*& aResult);
nsresult MakeWindow(nsNativeWidget aParent,
nsIDeviceContext* aDeviceContext,
const nsRect& aBounds);
nsresult StartLoad(nsIURL* aURL, const char* aContentType,
nsIStreamListener*& aResult);
void ForceRefresh(void);
nsresult GetURL(nsIURL *&aURL);
nsresult GetDocument(nsIDocument* *aDocument);
nsIWidget* mWindow;
nsIDocument* mDocument;
nsIContentViewerContainer* mContainer;
nsIURL* mURL;
nsString mContentType;
pluginInstanceOwner *mOwner;
};
//----------------------------------------------------------------------
nsresult
NS_NewPluginContentViewer(const char* aCommand,
nsIStreamListener** aDocListener,
nsIContentViewer** aDocViewer)
{
PluginViewerImpl* it = new PluginViewerImpl(aCommand, aDocListener);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
return it->QueryInterface(kIContentViewerIID, (void**) aDocViewer);
}
// Note: operator new zeros our memory
PluginViewerImpl::PluginViewerImpl(const char* aCommand,
nsIStreamListener** aDocListener)
{
NS_INIT_REFCNT();
nsIStreamListener* it = new PluginListener(this);
*aDocListener = it;
}
// ISupports implementation...
NS_IMPL_ADDREF(PluginViewerImpl)
NS_IMPL_RELEASE(PluginViewerImpl)
nsresult
PluginViewerImpl::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIContentViewerIID)) {
nsIContentViewer* tmp = this;
*aInstancePtr = (void*)tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
nsISupports* tmp = this;
*aInstancePtr = (void*)tmp;
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE;
}
PluginViewerImpl::~PluginViewerImpl()
{
NS_IF_RELEASE(mOwner);
if (nsnull != mWindow) {
mWindow->Destroy();
NS_RELEASE(mWindow);
}
NS_IF_RELEASE(mDocument);
NS_IF_RELEASE(mContainer);
NS_IF_RELEASE(mURL);
}
/*
* 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::BindToDocument(nsISupports *aDoc, const char *aCommand)
{
#ifdef NS_DEBUG
printf("PluginViewerImpl::BindToDocument\n");
#endif
return aDoc->QueryInterface(kIDocumentIID, (void**)&mDocument);
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::SetContainer(nsIContentViewerContainer* aContainer)
{
NS_IF_RELEASE(mContainer);
mContainer = aContainer;
NS_IF_ADDREF(mContainer);
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::GetContainer(nsIContentViewerContainer*& aResult)
{
aResult = mContainer;
NS_IF_ADDREF(mContainer);
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::Init(nsNativeWidget aNativeParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling)
{
nsresult rv = MakeWindow(aNativeParent, aDeviceContext, aBounds);
if (NS_OK == rv) {
mOwner = new pluginInstanceOwner();
if (nsnull != mOwner) {
NS_ADDREF(mOwner);
rv = mOwner->Init(this, mWindow);
}
}
return rv;
}
nsresult
PluginViewerImpl::StartLoad(nsIURL* aURL, const char* aContentType,
nsIStreamListener*& aResult)
{
printf("PluginViewerImpl::StartLoad: content-type=%s\n", aContentType);
NS_IF_RELEASE(mURL);
mURL = aURL;
NS_IF_ADDREF(aURL);
mContentType = aContentType;
aResult = nsnull;
// Only instantiate the plugin if our container can host it
nsIPluginHost* host;
nsresult rv = mContainer->QueryCapability(kIPluginHostIID, (void **)&host);
if (NS_OK == rv) {
nsRect r;
mWindow->GetClientBounds(r);
rv = CreatePlugin(host, nsRect(0, 0, r.width, r.height), aResult);
NS_RELEASE(host);
}
return rv;
}
nsresult
PluginViewerImpl::CreatePlugin(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
PRUnichar* fullurl;
mURL->ToString(&fullurl);
char* ct = mContentType.ToNewCString();
nsAutoString str = fullurl;
rv = aHost->InstantiateFullPagePlugin(ct, str, aResult, mOwner);
delete fullurl;
delete[] ct;
}
return rv;
}
NS_IMETHODIMP
PluginViewerImpl::Stop(void)
{
// XXX write this
return NS_OK;
}
static nsEventStatus PR_CALLBACK
HandlePluginEvent(nsGUIEvent *aEvent)
{
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);
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::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 :: Print(void)
{
// need to call the plugin from here somehow
return NS_OK;
}
void
PluginViewerImpl::ForceRefresh()
{
mWindow->Invalidate(PR_TRUE);
}
nsresult PluginViewerImpl::GetURL(nsIURL *&aURL)
{
NS_IF_ADDREF(mURL);
aURL = mURL;
return NS_OK;
}
nsresult PluginViewerImpl::GetDocument(nsIDocument* *aDocument)
{
NS_IF_ADDREF(mDocument);
*aDocument = mDocument;
return NS_OK;
}
//----------------------------------------------------------------------
PluginListener::PluginListener(PluginViewerImpl* aViewer)
{
NS_INIT_REFCNT();
mViewer = aViewer;
NS_ADDREF(aViewer);
mRefCnt = 1;
}
PluginListener::~PluginListener()
{
NS_RELEASE(mViewer);
NS_IF_RELEASE(mNextStream);
}
NS_IMPL_ISUPPORTS(PluginListener, kIStreamListenerIID)
NS_IMETHODIMP
PluginListener::OnStartBinding(nsIURL* aURL, const char *aContentType)
{
mViewer->StartLoad(aURL, aContentType, mNextStream);
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnStartBinding(aURL, aContentType);
}
NS_IMETHODIMP
PluginListener::OnProgress(nsIURL* aURL, PRUint32 aProgress,
PRUint32 aProgressMax)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnProgress(aURL, aProgress, aProgressMax);
}
NS_IMETHODIMP
PluginListener::OnStatus(nsIURL* aURL, const PRUnichar* aMsg)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnStatus(aURL, aMsg);
}
NS_IMETHODIMP
PluginListener::OnStopBinding(nsIURL* aURL, nsresult aStatus,
const PRUnichar* aMsg)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnStopBinding(aURL, aStatus, aMsg);
}
NS_IMETHODIMP
PluginListener::GetBindInfo(nsIURL* aURL, nsStreamBindingInfo* aInfo)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->GetBindInfo(aURL, aInfo);
}
NS_IMETHODIMP
PluginListener::OnDataAvailable(nsIURL* aURL, nsIInputStream* aStream,
PRUint32 aCount)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnDataAvailable(aURL, aStream, aCount);
}
//----------------------------------------------------------------------
pluginInstanceOwner :: pluginInstanceOwner()
{
NS_INIT_REFCNT();
memset(&mPluginWindow, 0, sizeof(mPluginWindow));
mInstance = nsnull;
mWindow = nsnull;
mViewer = nsnull;
}
pluginInstanceOwner :: ~pluginInstanceOwner()
{
if (nsnull != mInstance)
{
mInstance->Stop();
mInstance->Destroy();
NS_RELEASE(mInstance);
}
mWindow = nsnull;
mViewer = nsnull;
}
NS_IMPL_ISUPPORTS(pluginInstanceOwner, kIPluginInstanceOwnerIID);
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)
{
NS_IF_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;
if (nsnull != mInstance)
{
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_WINDOW);
mPluginWindow.type = nsPluginWindowType_Window;
}
else
return NS_ERROR_FAILURE;
}
else
return NS_ERROR_FAILURE;
return NS_OK;
}
NS_IMETHODIMP pluginInstanceOwner :: GetURL(const char *aURL, const char *aTarget, void *aPostData)
{
nsresult rv;
if (nsnull != mViewer)
{
nsIContentViewerContainer *cont;
rv = mViewer->GetContainer(cont);
if (NS_OK == rv)
{
nsILinkHandler *lh;
rv = cont->QueryInterface(kILinkHandlerIID, (void **)&lh);
if (NS_OK == rv)
{
nsIURL *url;
rv = mViewer->GetURL(url);
if (NS_OK == rv)
{
nsAutoString uniurl = nsAutoString(aURL);
nsAutoString unitarget = nsAutoString(aTarget);
const char* spec;
(void)url->GetSpec(&spec);
nsAutoString base = nsAutoString(spec);
nsAutoString fullurl;
// Create an absolute URL
rv = NS_MakeAbsoluteURL(url, base, uniurl, fullurl);
if (NS_OK == rv)
rv = lh->OnLinkClick(nsnull, eLinkVerb_Replace, fullurl.GetUnicode(), unitarget.GetUnicode(), nsnull);
NS_RELEASE(url);
}
NS_RELEASE(lh);
}
NS_RELEASE(cont);
}
}
else
rv = NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP pluginInstanceOwner :: ShowStatus(const char *aStatusMsg)
{
nsresult rv = NS_ERROR_FAILURE;
if (nsnull != mViewer)
{
nsIContentViewerContainer *cont;
rv = mViewer->GetContainer(cont);
if ((NS_OK == rv) && (nsnull != cont))
{
nsIWebShell *ws;
rv = cont->QueryInterface(kIWebShellIID, (void **)&ws);
if (NS_OK == rv)
{
nsIWebShell *rootWebShell;
ws->GetRootWebShell(rootWebShell);
if (nsnull != rootWebShell)
{
nsIWebShellContainer *rootContainer;
rv = rootWebShell->GetContainer(rootContainer);
if (nsnull != rootContainer)
{
nsIBrowserWindow *browserWindow;
if (NS_OK == rootContainer->QueryInterface(kIBrowserWindowIID, (void**)&browserWindow))
{
nsAutoString msg = nsAutoString(aStatusMsg);
rv = browserWindow->SetStatus(msg.GetUnicode());
NS_RELEASE(browserWindow);
}
NS_RELEASE(rootContainer);
}
NS_RELEASE(rootWebShell);
}
NS_RELEASE(ws);
}
NS_RELEASE(cont);
}
}
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;
}

View File

@ -0,0 +1,765 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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 Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
#include "nscore.h"
#include "nsCRT.h"
#include "nsIContentViewer.h"
#include "nsIContentViewerContainer.h"
#include "nsIPluginHost.h"
#include "nsIPluginInstance.h"
#include "nsIStreamListener.h"
#include "nsIURL.h"
#include "nsIComponentManager.h"
#include "nsWidgetsCID.h"
#include "nsILinkHandler.h"
#include "nsIWebShell.h"
#include "nsIBrowserWindow.h"
#include "nsIContent.h"
#include "nsIDocument.h"
// 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_ICONTENT_VIEWER_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kIPluginHostIID, NS_IPLUGINHOST_IID);
static NS_DEFINE_IID(kIPluginInstanceOwnerIID, NS_IPLUGININSTANCEOWNER_IID);
static NS_DEFINE_IID(kILinkHandlerIID, NS_ILINKHANDLER_IID);
static NS_DEFINE_IID(kIStreamListenerIID, NS_ISTREAMLISTENER_IID);
static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID);
static NS_DEFINE_IID(kIBrowserWindowIID, NS_IBROWSER_WINDOW_IID);
static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
class PluginViewerImpl;
class PluginListener : public nsIStreamListener {
public:
PluginListener(PluginViewerImpl* aViewer);
virtual ~PluginListener();
// nsISupports
NS_DECL_ISUPPORTS
// nsIStreamListener
NS_IMETHOD OnStartBinding(nsIURL* aURL, const char *aContentType);
NS_IMETHOD OnProgress(nsIURL* aURL, PRUint32 aProgress, PRUint32 aProgressMax);
NS_IMETHOD OnStatus(nsIURL* aURL, const PRUnichar* aMsg);
NS_IMETHOD OnStopBinding(nsIURL* aURL, nsresult aStatus,
const PRUnichar* aMsg);
NS_IMETHOD GetBindInfo(nsIURL* aURL, nsStreamBindingInfo* aInfo);
NS_IMETHOD OnDataAvailable(nsIURL* aURL, nsIInputStream* aStream,
PRUint32 aCount);
PluginViewerImpl* mViewer;
nsIStreamListener* mNextStream;
};
class pluginInstanceOwner : public nsIPluginInstanceOwner {
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);
NS_IMETHOD ShowStatus(const char *aStatusMsg);
NS_IMETHOD GetDocument(nsIDocument* *aDocument);
//locals
NS_IMETHOD Init(PluginViewerImpl *aViewer, nsIWidget *aWindow);
private:
nsPluginWindow mPluginWindow;
nsIPluginInstance *mInstance;
nsIWidget *mWindow; //we do not addref this...
PluginViewerImpl *mViewer; //we do not addref this...
};
class PluginViewerImpl : public nsIContentViewer
{
public:
PluginViewerImpl(const char* aCommand, nsIStreamListener** aDocListener);
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
// nsISupports
NS_DECL_ISUPPORTS
// nsIContentViewer
NS_IMETHOD Init(nsNativeWidget aParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling = nsScrollPreference_kAuto);
NS_IMETHOD BindToDocument(nsISupports* aDoc, const char* aCommand);
NS_IMETHOD SetContainer(nsIContentViewerContainer* aContainer);
NS_IMETHOD GetContainer(nsIContentViewerContainer*& aContainerResult);
NS_IMETHOD Stop(void);
NS_IMETHOD GetBounds(nsRect& aResult);
NS_IMETHOD SetBounds(const nsRect& aBounds);
NS_IMETHOD Move(PRInt32 aX, PRInt32 aY);
NS_IMETHOD Show();
NS_IMETHOD Hide();
NS_IMETHOD Print(void);
virtual ~PluginViewerImpl();
nsresult CreatePlugin(nsIPluginHost* aHost, const nsRect& aBounds,
nsIStreamListener*& aResult);
nsresult MakeWindow(nsNativeWidget aParent,
nsIDeviceContext* aDeviceContext,
const nsRect& aBounds);
nsresult StartLoad(nsIURL* aURL, const char* aContentType,
nsIStreamListener*& aResult);
void ForceRefresh(void);
nsresult GetURL(nsIURL *&aURL);
nsresult GetDocument(nsIDocument* *aDocument);
nsIWidget* mWindow;
nsIDocument* mDocument;
nsIContentViewerContainer* mContainer;
nsIURL* mURL;
nsString mContentType;
pluginInstanceOwner *mOwner;
};
//----------------------------------------------------------------------
nsresult
NS_NewPluginContentViewer(const char* aCommand,
nsIStreamListener** aDocListener,
nsIContentViewer** aDocViewer)
{
PluginViewerImpl* it = new PluginViewerImpl(aCommand, aDocListener);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
return it->QueryInterface(kIContentViewerIID, (void**) aDocViewer);
}
// Note: operator new zeros our memory
PluginViewerImpl::PluginViewerImpl(const char* aCommand,
nsIStreamListener** aDocListener)
{
NS_INIT_REFCNT();
nsIStreamListener* it = new PluginListener(this);
*aDocListener = it;
}
// ISupports implementation...
NS_IMPL_ADDREF(PluginViewerImpl)
NS_IMPL_RELEASE(PluginViewerImpl)
nsresult
PluginViewerImpl::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIContentViewerIID)) {
nsIContentViewer* tmp = this;
*aInstancePtr = (void*)tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
nsISupports* tmp = this;
*aInstancePtr = (void*)tmp;
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE;
}
PluginViewerImpl::~PluginViewerImpl()
{
NS_IF_RELEASE(mOwner);
if (nsnull != mWindow) {
mWindow->Destroy();
NS_RELEASE(mWindow);
}
NS_IF_RELEASE(mDocument);
NS_IF_RELEASE(mContainer);
NS_IF_RELEASE(mURL);
}
/*
* 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::BindToDocument(nsISupports *aDoc, const char *aCommand)
{
#ifdef NS_DEBUG
printf("PluginViewerImpl::BindToDocument\n");
#endif
return aDoc->QueryInterface(kIDocumentIID, (void**)&mDocument);
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::SetContainer(nsIContentViewerContainer* aContainer)
{
NS_IF_RELEASE(mContainer);
mContainer = aContainer;
NS_IF_ADDREF(mContainer);
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::GetContainer(nsIContentViewerContainer*& aResult)
{
aResult = mContainer;
NS_IF_ADDREF(mContainer);
return NS_OK;
}
NS_IMETHODIMP
PluginViewerImpl::Init(nsNativeWidget aNativeParent,
nsIDeviceContext* aDeviceContext,
nsIPref* aPrefs,
const nsRect& aBounds,
nsScrollPreference aScrolling)
{
nsresult rv = MakeWindow(aNativeParent, aDeviceContext, aBounds);
if (NS_OK == rv) {
mOwner = new pluginInstanceOwner();
if (nsnull != mOwner) {
NS_ADDREF(mOwner);
rv = mOwner->Init(this, mWindow);
}
}
return rv;
}
nsresult
PluginViewerImpl::StartLoad(nsIURL* aURL, const char* aContentType,
nsIStreamListener*& aResult)
{
printf("PluginViewerImpl::StartLoad: content-type=%s\n", aContentType);
NS_IF_RELEASE(mURL);
mURL = aURL;
NS_IF_ADDREF(aURL);
mContentType = aContentType;
aResult = nsnull;
// Only instantiate the plugin if our container can host it
nsIPluginHost* host;
nsresult rv = mContainer->QueryCapability(kIPluginHostIID, (void **)&host);
if (NS_OK == rv) {
nsRect r;
mWindow->GetClientBounds(r);
rv = CreatePlugin(host, nsRect(0, 0, r.width, r.height), aResult);
NS_RELEASE(host);
}
return rv;
}
nsresult
PluginViewerImpl::CreatePlugin(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
PRUnichar* fullurl;
mURL->ToString(&fullurl);
char* ct = mContentType.ToNewCString();
nsAutoString str = fullurl;
rv = aHost->InstantiateFullPagePlugin(ct, str, aResult, mOwner);
delete fullurl;
delete[] ct;
}
return rv;
}
NS_IMETHODIMP
PluginViewerImpl::Stop(void)
{
// XXX write this
return NS_OK;
}
static nsEventStatus PR_CALLBACK
HandlePluginEvent(nsGUIEvent *aEvent)
{
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);
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::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 :: Print(void)
{
// need to call the plugin from here somehow
return NS_OK;
}
void
PluginViewerImpl::ForceRefresh()
{
mWindow->Invalidate(PR_TRUE);
}
nsresult PluginViewerImpl::GetURL(nsIURL *&aURL)
{
NS_IF_ADDREF(mURL);
aURL = mURL;
return NS_OK;
}
nsresult PluginViewerImpl::GetDocument(nsIDocument* *aDocument)
{
NS_IF_ADDREF(mDocument);
*aDocument = mDocument;
return NS_OK;
}
//----------------------------------------------------------------------
PluginListener::PluginListener(PluginViewerImpl* aViewer)
{
NS_INIT_REFCNT();
mViewer = aViewer;
NS_ADDREF(aViewer);
mRefCnt = 1;
}
PluginListener::~PluginListener()
{
NS_RELEASE(mViewer);
NS_IF_RELEASE(mNextStream);
}
NS_IMPL_ISUPPORTS(PluginListener, kIStreamListenerIID)
NS_IMETHODIMP
PluginListener::OnStartBinding(nsIURL* aURL, const char *aContentType)
{
mViewer->StartLoad(aURL, aContentType, mNextStream);
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnStartBinding(aURL, aContentType);
}
NS_IMETHODIMP
PluginListener::OnProgress(nsIURL* aURL, PRUint32 aProgress,
PRUint32 aProgressMax)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnProgress(aURL, aProgress, aProgressMax);
}
NS_IMETHODIMP
PluginListener::OnStatus(nsIURL* aURL, const PRUnichar* aMsg)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnStatus(aURL, aMsg);
}
NS_IMETHODIMP
PluginListener::OnStopBinding(nsIURL* aURL, nsresult aStatus,
const PRUnichar* aMsg)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnStopBinding(aURL, aStatus, aMsg);
}
NS_IMETHODIMP
PluginListener::GetBindInfo(nsIURL* aURL, nsStreamBindingInfo* aInfo)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->GetBindInfo(aURL, aInfo);
}
NS_IMETHODIMP
PluginListener::OnDataAvailable(nsIURL* aURL, nsIInputStream* aStream,
PRUint32 aCount)
{
if (nsnull == mNextStream) {
return NS_ERROR_FAILURE;
}
return mNextStream->OnDataAvailable(aURL, aStream, aCount);
}
//----------------------------------------------------------------------
pluginInstanceOwner :: pluginInstanceOwner()
{
NS_INIT_REFCNT();
memset(&mPluginWindow, 0, sizeof(mPluginWindow));
mInstance = nsnull;
mWindow = nsnull;
mViewer = nsnull;
}
pluginInstanceOwner :: ~pluginInstanceOwner()
{
if (nsnull != mInstance)
{
mInstance->Stop();
mInstance->Destroy();
NS_RELEASE(mInstance);
}
mWindow = nsnull;
mViewer = nsnull;
}
NS_IMPL_ISUPPORTS(pluginInstanceOwner, kIPluginInstanceOwnerIID);
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)
{
NS_IF_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;
if (nsnull != mInstance)
{
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_WINDOW);
mPluginWindow.type = nsPluginWindowType_Window;
}
else
return NS_ERROR_FAILURE;
}
else
return NS_ERROR_FAILURE;
return NS_OK;
}
NS_IMETHODIMP pluginInstanceOwner :: GetURL(const char *aURL, const char *aTarget, void *aPostData)
{
nsresult rv;
if (nsnull != mViewer)
{
nsIContentViewerContainer *cont;
rv = mViewer->GetContainer(cont);
if (NS_OK == rv)
{
nsILinkHandler *lh;
rv = cont->QueryInterface(kILinkHandlerIID, (void **)&lh);
if (NS_OK == rv)
{
nsIURL *url;
rv = mViewer->GetURL(url);
if (NS_OK == rv)
{
nsAutoString uniurl = nsAutoString(aURL);
nsAutoString unitarget = nsAutoString(aTarget);
const char* spec;
(void)url->GetSpec(&spec);
nsAutoString base = nsAutoString(spec);
nsAutoString fullurl;
// Create an absolute URL
rv = NS_MakeAbsoluteURL(url, base, uniurl, fullurl);
if (NS_OK == rv)
rv = lh->OnLinkClick(nsnull, eLinkVerb_Replace, fullurl.GetUnicode(), unitarget.GetUnicode(), nsnull);
NS_RELEASE(url);
}
NS_RELEASE(lh);
}
NS_RELEASE(cont);
}
}
else
rv = NS_ERROR_FAILURE;
return rv;
}
NS_IMETHODIMP pluginInstanceOwner :: ShowStatus(const char *aStatusMsg)
{
nsresult rv = NS_ERROR_FAILURE;
if (nsnull != mViewer)
{
nsIContentViewerContainer *cont;
rv = mViewer->GetContainer(cont);
if ((NS_OK == rv) && (nsnull != cont))
{
nsIWebShell *ws;
rv = cont->QueryInterface(kIWebShellIID, (void **)&ws);
if (NS_OK == rv)
{
nsIWebShell *rootWebShell;
ws->GetRootWebShell(rootWebShell);
if (nsnull != rootWebShell)
{
nsIWebShellContainer *rootContainer;
rv = rootWebShell->GetContainer(rootContainer);
if (nsnull != rootContainer)
{
nsIBrowserWindow *browserWindow;
if (NS_OK == rootContainer->QueryInterface(kIBrowserWindowIID, (void**)&browserWindow))
{
nsAutoString msg = nsAutoString(aStatusMsg);
rv = browserWindow->SetStatus(msg.GetUnicode());
NS_RELEASE(browserWindow);
}
NS_RELEASE(rootContainer);
}
NS_RELEASE(rootWebShell);
}
NS_RELEASE(ws);
}
NS_RELEASE(cont);
}
}
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;
}