mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
1040 lines
25 KiB
C++
1040 lines
25 KiB
C++
/* -*- 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 "nsIWebShell.h"
|
|
#include "nsIDocumentLoader.h"
|
|
#include "nsIContentViewer.h"
|
|
#include "nsIDeviceContext.h"
|
|
#include "nsILinkHandler.h"
|
|
#include "nsIStreamListener.h"
|
|
#include "nsRepository.h"
|
|
#include "nsCRT.h"
|
|
#include "nsVoidArray.h"
|
|
#include "nsString.h"
|
|
#include "nsWidgetsCID.h"
|
|
#include "nsGfxCIID.h"
|
|
#include "plevent.h"
|
|
|
|
//XXX for nsIPostData; this is wrong; we shouldn't see the nsIDocument type
|
|
#include "nsIDocument.h"
|
|
|
|
#ifdef NS_DEBUG
|
|
/**
|
|
* Note: the log module is created during initialization which
|
|
* means that you cannot perform logging before then.
|
|
*/
|
|
static PRLogModuleInfo* gLogModule = PR_NewLogModule("webwidget");
|
|
#endif
|
|
|
|
#define WEB_TRACE_CALLS 0x1
|
|
#define WEB_TRACE_HISTORY 0x2
|
|
|
|
#define WEB_LOG_TEST(_lm,_bit) (PRIntn((_lm)->level) & (_bit))
|
|
|
|
#ifdef NS_DEBUG
|
|
#define WEB_TRACE(_bit,_args) \
|
|
PR_BEGIN_MACRO \
|
|
if (WEB_LOG_TEST(gLogModule,_bit)) { \
|
|
PR_LogPrint _args; \
|
|
} \
|
|
PR_END_MACRO
|
|
#else
|
|
#define WEB_TRACE(_bit,_args)
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
class nsWebShell : public nsIWebShell,
|
|
public nsIWebShellContainer,
|
|
public nsILinkHandler
|
|
{
|
|
public:
|
|
nsWebShell();
|
|
virtual ~nsWebShell();
|
|
|
|
void* operator new(size_t sz) {
|
|
void* rv = new char[sz];
|
|
nsCRT::zero(rv, sz);
|
|
return rv;
|
|
}
|
|
|
|
// nsISupports
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIContentViewerContainer
|
|
NS_IMETHOD QueryCapability(const nsIID &aIID, void** aResult);
|
|
NS_IMETHOD Embed(nsIContentViewer* aDocViewer,
|
|
const char* aCommand,
|
|
nsISupports* aExtraInfo);
|
|
|
|
// nsIWebShell
|
|
NS_IMETHOD Init(nsNativeWidget aNativeParent,
|
|
const nsRect& aBounds,
|
|
nsScrollPreference aScrolling = nsScrollPreference_kAuto);
|
|
NS_IMETHOD GetBounds(nsRect& aResult);
|
|
NS_IMETHOD SetBounds(const nsRect& aBounds);
|
|
NS_IMETHOD MoveTo(PRInt32 aX, PRInt32 aY);
|
|
NS_IMETHOD Show();
|
|
NS_IMETHOD Hide();
|
|
NS_IMETHOD GetContentViewer(nsIContentViewer*& aResult);
|
|
NS_IMETHOD SetContainer(nsIWebShellContainer* aContainer);
|
|
NS_IMETHOD GetContainer(nsIWebShellContainer*& aResult);
|
|
NS_IMETHOD GetRootWebShell(nsIWebShell*& aResult);
|
|
NS_IMETHOD SetParent(nsIWebShell* aParent);
|
|
NS_IMETHOD GetParent(nsIWebShell*& aParent);
|
|
NS_IMETHOD GetChildCount(PRInt32& aResult);
|
|
NS_IMETHOD AddChild(nsIWebShell* aChild);
|
|
NS_IMETHOD ChildAt(PRInt32 aIndex, nsIWebShell*& aResult);
|
|
NS_IMETHOD GetName(nsString& aName);
|
|
NS_IMETHOD SetName(const nsString& aName);
|
|
NS_IMETHOD FindChildWithName(const nsString& aName,
|
|
nsIWebShell*& aResult);
|
|
NS_IMETHOD Back(nsIStreamObserver* aObserver);
|
|
NS_IMETHOD Forward(nsIStreamObserver* aObserver);
|
|
NS_IMETHOD LoadURL(const nsString& aURLSpec,
|
|
nsIStreamObserver* aObserver,
|
|
nsIPostData* aPostData=nsnull);
|
|
NS_IMETHOD GoTo(PRInt32 aHistoryIndex, nsIStreamObserver* aObserver);
|
|
NS_IMETHOD GetHistoryIndex(PRInt32& aResult);
|
|
NS_IMETHOD SetTitle(const nsString& aTitle);
|
|
NS_IMETHOD GetTitle(nsString& aResult);
|
|
|
|
// nsIWebShellContainer
|
|
NS_IMETHOD WillLoadURL(nsIWebShell* aShell, const nsString& aURL);
|
|
NS_IMETHOD BeginLoadURL(nsIWebShell* aShell, const nsString& aURL);
|
|
NS_IMETHOD EndLoadURL(nsIWebShell* aShell, const nsString& aURL);
|
|
|
|
// nsILinkHandler
|
|
NS_IMETHOD OnLinkClick(nsIFrame* aFrame,
|
|
const nsString& aURLSpec,
|
|
const nsString& aTargetSpec,
|
|
nsIPostData* aPostData = 0);
|
|
NS_IMETHOD OnOverLink(nsIFrame* aFrame,
|
|
const nsString& aURLSpec,
|
|
const nsString& aTargetSpec);
|
|
NS_IMETHOD GetLinkState(const nsString& aURLSpec, nsLinkState& aState);
|
|
|
|
// nsWebShell
|
|
void HandleLinkClickEvent(const nsString& aURLSpec,
|
|
const nsString& aTargetSpec,
|
|
nsIPostData* aPostDat = 0);
|
|
|
|
void ShowHistory();
|
|
|
|
nsIWebShell* GetTarget(const nsString& aName);
|
|
|
|
static nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent);
|
|
|
|
protected:
|
|
nsIWebShellContainer* mContainer;
|
|
nsIContentViewer* mContentViewer;
|
|
nsIDeviceContext* mDeviceContext;
|
|
nsIWidget* mWindow;
|
|
nsIDocumentLoader* mDocLoader;
|
|
|
|
nsIWebShell* mParent;
|
|
nsVoidArray mChildren;
|
|
nsString mName;
|
|
|
|
nsVoidArray mHistory;
|
|
PRInt32 mHistoryIndex;
|
|
|
|
nsString mTitle;
|
|
|
|
nsString mOverURL;
|
|
nsString mOverTarget;
|
|
|
|
void ReleaseChildren();
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Class IID's
|
|
static NS_DEFINE_IID(kChildCID, NS_CHILD_CID);
|
|
static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID);
|
|
static NS_DEFINE_IID(kDocumentLoaderCID, NS_DOCUMENTLOADER_CID);
|
|
static NS_DEFINE_IID(kWebShellCID, NS_WEB_SHELL_CID);
|
|
|
|
// IID's
|
|
static NS_DEFINE_IID(kIContentViewerContainerIID,
|
|
NS_ICONTENT_VIEWER_CONTAINER_IID);
|
|
static NS_DEFINE_IID(kIDeviceContextIID, NS_IDEVICE_CONTEXT_IID);
|
|
static NS_DEFINE_IID(kIDocumentLoaderIID, NS_IDOCUMENTLOADER_IID);
|
|
static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
|
|
static NS_DEFINE_IID(kIStreamObserverIID, NS_ISTREAMOBSERVER_IID);
|
|
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
|
static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID);
|
|
static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID);
|
|
|
|
// XXX not sure
|
|
static NS_DEFINE_IID(kILinkHandlerIID, NS_ILINKHANDLER_IID);
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Note: operator new zeros our memory
|
|
nsWebShell::nsWebShell()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
mHistoryIndex = -1;
|
|
}
|
|
|
|
nsWebShell::~nsWebShell()
|
|
{
|
|
NS_IF_RELEASE(mContentViewer);
|
|
NS_IF_RELEASE(mContainer);
|
|
|
|
// Release references on our children
|
|
ReleaseChildren();
|
|
|
|
// Free up history memory
|
|
PRInt32 i, n = mHistory.Count();
|
|
for (i = 0; i < n; i++) {
|
|
nsString* s = (nsString*) mHistory.ElementAt(i);
|
|
delete s;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsWebShell::ReleaseChildren()
|
|
{
|
|
PRInt32 i, n = mChildren.Count();
|
|
for (i = 0; i < n; i++) {
|
|
nsIWebShell* shell = (nsIWebShell*) mChildren.ElementAt(i);
|
|
shell->SetParent(nsnull);
|
|
NS_RELEASE(shell);
|
|
}
|
|
mChildren.Clear();
|
|
}
|
|
|
|
NS_IMPL_ADDREF(nsWebShell)
|
|
NS_IMPL_RELEASE(nsWebShell)
|
|
|
|
//XXX missing nsIWebShellContainer!!!
|
|
nsresult
|
|
nsWebShell::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|
{
|
|
if (NULL == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
if (aIID.Equals(kIWebShellIID)) {
|
|
*aInstancePtr = (void*)(nsIWebShell*)this;
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kIContentViewerContainerIID)) {
|
|
*aInstancePtr = (void*)(nsIContentViewerContainer*)this;
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kISupportsIID)) {
|
|
*aInstancePtr = (void*)(nsISupports*)(nsIWebShell*)this;
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::QueryCapability(const nsIID &aIID, void** aInstancePtr)
|
|
{
|
|
if (nsnull == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
if (aIID.Equals(kILinkHandlerIID)) {
|
|
*aInstancePtr = (void*) ((nsILinkHandler*)this);
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::Embed(nsIContentViewer* aContentViewer,
|
|
const char* aCommand,
|
|
nsISupports* aExtraInfo)
|
|
{
|
|
nsresult rv;
|
|
nsRect bounds;
|
|
|
|
WEB_TRACE(WEB_TRACE_CALLS,
|
|
("nsWebShell::Embed: this=%p aDocViewer=%p aCommand=%s aExtraInfo=%p",
|
|
this, aContentViewer, aCommand ? aCommand : "", aExtraInfo));
|
|
|
|
NS_IF_RELEASE(mContentViewer);
|
|
mContentViewer = aContentViewer;
|
|
NS_ADDREF(aContentViewer);
|
|
|
|
mWindow->GetBounds(bounds);
|
|
bounds.x = bounds.y = 0;
|
|
rv = mContentViewer->Init(mWindow->GetNativeData(NS_NATIVE_WIDGET),
|
|
mDeviceContext,
|
|
bounds);
|
|
if (NS_OK == rv) {
|
|
mContentViewer->Show();
|
|
}
|
|
|
|
// Now that we have switch documents, forget all of our children
|
|
ReleaseChildren();
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::Init(nsNativeWidget aNativeParent,
|
|
const nsRect& aBounds,
|
|
nsScrollPreference aScrolling)
|
|
{
|
|
WEB_TRACE(WEB_TRACE_CALLS,
|
|
("nsWebShell::Init: this=%p", this));
|
|
|
|
nsresult rv = NSRepository::CreateInstance(kDocumentLoaderCID, nsnull,
|
|
kIDocumentLoaderIID,
|
|
(void**)&mDocLoader);
|
|
|
|
NS_PRECONDITION(nsnull != aNativeParent, "null Parent Window");
|
|
if (nsnull == aNativeParent) {
|
|
rv = NS_ERROR_NULL_POINTER;
|
|
goto done;
|
|
}
|
|
|
|
// Create device context
|
|
rv = NSRepository::CreateInstance(kDeviceContextCID, nsnull,
|
|
kIDeviceContextIID,
|
|
(void **)&mDeviceContext);
|
|
if (NS_OK != rv) {
|
|
goto done;
|
|
}
|
|
mDeviceContext->Init(aNativeParent);
|
|
mDeviceContext->SetDevUnitsToAppUnits(mDeviceContext->GetDevUnitsToTwips());
|
|
mDeviceContext->SetAppUnitsToDevUnits(mDeviceContext->GetTwipsToDevUnits());
|
|
mDeviceContext->SetGamma(1.7f);
|
|
|
|
// Create a Native window for the shell container...
|
|
rv = NSRepository::CreateInstance(kChildCID, nsnull, kIWidgetIID,
|
|
(void**)&mWindow);
|
|
if (NS_OK != rv) {
|
|
goto done;
|
|
}
|
|
mWindow->Create(aNativeParent, aBounds, nsWebShell::HandleEvent,
|
|
mDeviceContext, nsnull);
|
|
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetBounds(nsRect& aResult)
|
|
{
|
|
NS_PRECONDITION(nsnull != mWindow, "null window");
|
|
aResult.SetRect(0, 0, 0, 0);
|
|
if (nsnull != mWindow) {
|
|
mWindow->GetBounds(aResult);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::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
|
|
mWindow->Resize(aBounds.x, aBounds.y, aBounds.width, aBounds.height,
|
|
PR_FALSE);
|
|
}
|
|
|
|
if (nsnull != mContentViewer) {
|
|
nsRect rr(0, 0, aBounds.width, aBounds.height);
|
|
mContentViewer->SetBounds(rr);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::MoveTo(PRInt32 aX, PRInt32 aY)
|
|
{
|
|
NS_PRECONDITION(nsnull != mWindow, "null window");
|
|
|
|
if (nsnull != mWindow) {
|
|
mWindow->Move(aX, aY);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::Show()
|
|
{
|
|
NS_PRECONDITION(nsnull != mWindow, "null window");
|
|
|
|
if (nsnull != mWindow) {
|
|
mWindow->Show(PR_TRUE);
|
|
}
|
|
if (nsnull != mContentViewer) {
|
|
mContentViewer->Show();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::Hide()
|
|
{
|
|
NS_PRECONDITION(nsnull != mWindow, "null window");
|
|
|
|
if (nsnull != mWindow) {
|
|
mWindow->Show(PR_FALSE);
|
|
}
|
|
if (nsnull != mContentViewer) {
|
|
mContentViewer->Hide();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetContentViewer(nsIContentViewer*& aResult)
|
|
{
|
|
aResult = mContentViewer;
|
|
NS_IF_ADDREF(mContentViewer);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetContainer(nsIWebShellContainer* aContainer)
|
|
{
|
|
NS_IF_RELEASE(mContainer);
|
|
mContainer = aContainer;
|
|
NS_IF_ADDREF(aContainer);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetContainer(nsIWebShellContainer*& aResult)
|
|
{
|
|
aResult = mContainer;
|
|
NS_IF_ADDREF(mContainer);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsEventStatus PR_CALLBACK
|
|
nsWebShell::HandleEvent(nsGUIEvent *aEvent)
|
|
{
|
|
return nsEventStatus_eIgnore;
|
|
}
|
|
|
|
nsresult
|
|
nsWebShell::GetRootWebShell(nsIWebShell*& aResult)
|
|
{
|
|
nsIWebShell* top = this;
|
|
for (;;) {
|
|
nsIWebShell* parent;
|
|
top->GetParent(parent);
|
|
if (nsnull == parent) {
|
|
break;
|
|
}
|
|
top = parent;
|
|
}
|
|
aResult = top;
|
|
NS_ADDREF(top);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetParent(nsIWebShell* aParent)
|
|
{
|
|
NS_IF_RELEASE(mParent);
|
|
mParent = aParent;
|
|
NS_IF_ADDREF(aParent);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetParent(nsIWebShell*& aParent)
|
|
{
|
|
aParent = mParent;
|
|
NS_IF_ADDREF(mParent);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetChildCount(PRInt32& aResult)
|
|
{
|
|
aResult = mChildren.Count();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::AddChild(nsIWebShell* aChild)
|
|
{
|
|
NS_PRECONDITION(nsnull != aChild, "null ptr");
|
|
if (nsnull == aChild) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
mChildren.AppendElement(aChild);
|
|
aChild->SetParent(this);
|
|
NS_ADDREF(aChild);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::ChildAt(PRInt32 aIndex, nsIWebShell*& aResult)
|
|
{
|
|
if (PRUint32(aIndex) >= PRUint32(mChildren.Count())) {
|
|
aResult = nsnull;
|
|
}
|
|
else {
|
|
aResult = (nsIWebShell*) mChildren.ElementAt(aIndex);
|
|
NS_IF_ADDREF(aResult);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetName(nsString& aName)
|
|
{
|
|
aName = mName;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetName(const nsString& aName)
|
|
{
|
|
mName = aName;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::FindChildWithName(const nsString& aName,
|
|
nsIWebShell*& aResult)
|
|
{
|
|
aResult = nsnull;
|
|
|
|
nsAutoString childName;
|
|
PRInt32 i, n = mChildren.Count();
|
|
for (i = 0; i < n; i++) {
|
|
nsIWebShell* child = (nsIWebShell*) mChildren.ElementAt(i);
|
|
if (nsnull != child) {
|
|
child->GetName(childName);
|
|
if (childName.Equals(aName)) {
|
|
aResult = child;
|
|
NS_ADDREF(child);
|
|
break;
|
|
}
|
|
|
|
// See if child contains the shell with the given name
|
|
nsresult rv = child->FindChildWithName(aName, aResult);
|
|
if (NS_OK != rv) {
|
|
return rv;
|
|
}
|
|
if (nsnull != aResult) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------
|
|
|
|
// History methods
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::Back(nsIStreamObserver* aObserver)
|
|
{
|
|
return GoTo(mHistoryIndex - 1, aObserver);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::Forward(nsIStreamObserver* aObserver)
|
|
{
|
|
return GoTo(mHistoryIndex + 1, aObserver);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::LoadURL(const nsString& aURLSpec,
|
|
nsIStreamObserver* aObserver,
|
|
nsIPostData* aPostData)
|
|
{
|
|
nsresult rv;
|
|
|
|
// Give web-shell-container right of refusal
|
|
nsAutoString urlSpec(aURLSpec);
|
|
if (nsnull != mContainer) {
|
|
rv = mContainer->WillLoadURL(this, urlSpec);
|
|
if (NS_OK != rv) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
// Discard part of history that is no longer reachable
|
|
PRInt32 i, n = mHistory.Count();
|
|
i = mHistoryIndex + 1;
|
|
while (--n >= i) {
|
|
nsString* u = (nsString*) mHistory.ElementAt(n);
|
|
delete u;
|
|
mHistory.RemoveElementAt(n);
|
|
}
|
|
|
|
// Tack on new url
|
|
nsString* url = new nsString(urlSpec);
|
|
mHistory.AppendElement(url);
|
|
mHistoryIndex++;
|
|
ShowHistory();
|
|
|
|
// Tell web-shell-container we are loading a new url
|
|
if (nsnull != mContainer) {
|
|
rv = mContainer->BeginLoadURL(this, urlSpec);
|
|
if (NS_OK != rv) {
|
|
return rv;
|
|
}
|
|
}
|
|
rv = mDocLoader->LoadURL(urlSpec, // URL string
|
|
nsnull, // Command
|
|
this, // Container
|
|
aPostData, // Post Data
|
|
nsnull, // Extra Info...
|
|
aObserver); // Observer
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GoTo(PRInt32 aHistoryIndex, nsIStreamObserver* aObserver)
|
|
{
|
|
nsresult rv = NS_ERROR_ILLEGAL_VALUE;
|
|
if ((aHistoryIndex >= 0) &&
|
|
(aHistoryIndex <= mHistory.Count() - 1)) {
|
|
nsString* s = (nsString*) mHistory.ElementAt(aHistoryIndex);
|
|
|
|
// Give web-shell-container right of refusal
|
|
nsAutoString urlSpec(*s);
|
|
if (nsnull != mContainer) {
|
|
rv = mContainer->WillLoadURL(this, urlSpec);
|
|
if (NS_OK != rv) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
printf("Goto %d\n", aHistoryIndex);
|
|
mHistoryIndex = aHistoryIndex;
|
|
ShowHistory();
|
|
|
|
// Tell web-shell-container we are loading a new url
|
|
if (nsnull != mContainer) {
|
|
rv = mContainer->BeginLoadURL(this, urlSpec);
|
|
if (NS_OK != rv) {
|
|
return rv;
|
|
}
|
|
}
|
|
rv = mDocLoader->LoadURL(urlSpec, // URL string
|
|
nsnull, // Command
|
|
this, // Container
|
|
nsnull, // Post Data
|
|
nsnull, // Extra Info...
|
|
aObserver); // Observer
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetHistoryIndex(PRInt32& aResult)
|
|
{
|
|
aResult = mHistoryIndex;
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsWebShell::ShowHistory()
|
|
{
|
|
#ifdef NS_DEBUG
|
|
if (WEB_LOG_TEST(gLogModule, WEB_TRACE_HISTORY)) {
|
|
PRInt32 i, n = mHistory.Count();
|
|
for (i = 0; i < n; i++) {
|
|
if (i == mHistoryIndex) {
|
|
printf("**");
|
|
}
|
|
else {
|
|
printf(" ");
|
|
}
|
|
nsString* u = (nsString*) mHistory.ElementAt(i);
|
|
fputs(*u, stdout);
|
|
printf("\n");
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//----------------------------------------
|
|
|
|
// Chrome API's
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::SetTitle(const nsString& aTitle)
|
|
{
|
|
// Record local title
|
|
mTitle = aTitle;
|
|
|
|
// Title's set on the top level web-shell are passed ont to the container
|
|
if (nsnull == mParent) {
|
|
if (nsnull != mContainer) {
|
|
mContainer->SetTitle(aTitle);
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::GetTitle(nsString& aResult)
|
|
{
|
|
aResult = mTitle;
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// WebShell container implementation
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::WillLoadURL(nsIWebShell* aShell, const nsString& aURL)
|
|
{
|
|
if (nsnull != mContainer) {
|
|
return mContainer->WillLoadURL(aShell, aURL);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::BeginLoadURL(nsIWebShell* aShell, const nsString& aURL)
|
|
{
|
|
if (nsnull != mContainer) {
|
|
return mContainer->BeginLoadURL(aShell, aURL);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::EndLoadURL(nsIWebShell* aShell, const nsString& aURL)
|
|
{
|
|
if (nsnull != mContainer) {
|
|
return mContainer->EndLoadURL(aShell, aURL);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// WebShell link handling
|
|
|
|
struct OnLinkClickEvent : public PLEvent {
|
|
OnLinkClickEvent(nsWebShell* aHandler, const nsString& aURLSpec,
|
|
const nsString& aTargetSpec, nsIPostData* aPostData = 0);
|
|
~OnLinkClickEvent();
|
|
|
|
void HandleEvent() {
|
|
mHandler->HandleLinkClickEvent(*mURLSpec, *mTargetSpec, mPostData);
|
|
}
|
|
|
|
nsWebShell* mHandler;
|
|
nsString* mURLSpec;
|
|
nsString* mTargetSpec;
|
|
nsIPostData* mPostData;
|
|
};
|
|
|
|
static void PR_CALLBACK HandlePLEvent(OnLinkClickEvent* aEvent)
|
|
{
|
|
aEvent->HandleEvent();
|
|
}
|
|
|
|
static void PR_CALLBACK DestroyPLEvent(OnLinkClickEvent* aEvent)
|
|
{
|
|
delete aEvent;
|
|
}
|
|
|
|
OnLinkClickEvent::OnLinkClickEvent(nsWebShell* aHandler,
|
|
const nsString& aURLSpec,
|
|
const nsString& aTargetSpec,
|
|
nsIPostData* aPostData)
|
|
{
|
|
mHandler = aHandler;
|
|
NS_ADDREF(aHandler);
|
|
mURLSpec = new nsString(aURLSpec);
|
|
mTargetSpec = new nsString(aTargetSpec);
|
|
mPostData = aPostData;
|
|
NS_IF_ADDREF(mPostData);
|
|
|
|
#ifdef XP_PC
|
|
PL_InitEvent(this, nsnull,
|
|
(PLHandleEventProc) ::HandlePLEvent,
|
|
(PLDestroyEventProc) ::DestroyPLEvent);
|
|
|
|
PLEventQueue* eventQueue = PL_GetMainEventQueue();
|
|
PL_PostEvent(eventQueue, this);
|
|
#endif
|
|
}
|
|
|
|
OnLinkClickEvent::~OnLinkClickEvent()
|
|
{
|
|
NS_IF_RELEASE(mHandler);
|
|
NS_IF_RELEASE(mPostData);
|
|
if (nsnull != mURLSpec) delete mURLSpec;
|
|
if (nsnull != mTargetSpec) delete mTargetSpec;
|
|
}
|
|
|
|
//----------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnLinkClick(nsIFrame* aFrame,
|
|
const nsString& aURLSpec,
|
|
const nsString& aTargetSpec,
|
|
nsIPostData* aPostData)
|
|
{
|
|
new OnLinkClickEvent(this, aURLSpec, aTargetSpec, aPostData);
|
|
return NS_OK;
|
|
}
|
|
|
|
// Find the web shell in the entire tree that we can reach that the
|
|
// link click should go to.
|
|
|
|
// XXX This doesn't yet know how to target other windows with their
|
|
// own tree
|
|
nsIWebShell*
|
|
nsWebShell::GetTarget(const nsString& aName)
|
|
{
|
|
nsIWebShell* target = nsnull;
|
|
|
|
if (aName.EqualsIgnoreCase("_blank")) {
|
|
// XXX Need api in nsIWebShellContainer
|
|
NS_ASSERTION(0, "not implemented yet");
|
|
target = this;
|
|
NS_ADDREF(target);
|
|
}
|
|
else if (aName.EqualsIgnoreCase("_self")) {
|
|
target = this;
|
|
NS_ADDREF(target);
|
|
}
|
|
else if (aName.EqualsIgnoreCase("_parent")) {
|
|
if (nsnull == mParent) {
|
|
target = this;
|
|
}
|
|
else {
|
|
target = mParent;
|
|
}
|
|
NS_ADDREF(target);
|
|
}
|
|
else if (aName.EqualsIgnoreCase("_top")) {
|
|
GetRootWebShell(target);
|
|
}
|
|
else {
|
|
// Look from the top of the tree downward
|
|
nsIWebShell* top;
|
|
GetRootWebShell(top);
|
|
top->FindChildWithName(aName, target);
|
|
if (nsnull == target) {
|
|
target = this;
|
|
NS_ADDREF(target);
|
|
}
|
|
NS_RELEASE(top);
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
void
|
|
nsWebShell::HandleLinkClickEvent(const nsString& aURLSpec,
|
|
const nsString& aTargetSpec,
|
|
nsIPostData* aPostData)
|
|
{
|
|
nsIWebShell* shell = GetTarget(aTargetSpec);
|
|
if (nsnull != shell) {
|
|
shell->LoadURL(aURLSpec, nsnull, aPostData);
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell::OnOverLink(nsIFrame* aFrame,
|
|
const nsString& aURLSpec,
|
|
const nsString& aTargetSpec)
|
|
{
|
|
if (!aURLSpec.Equals(mOverURL) || !aTargetSpec.Equals(mOverTarget)) {
|
|
fputs("Was '", stdout); fputs(mOverURL, stdout); fputs("' '", stdout); fputs(mOverTarget, stdout); fputs("'\n", stdout);
|
|
fputs("Over link '", stdout);
|
|
fputs(aURLSpec, stdout);
|
|
fputs("' '", stdout);
|
|
fputs(aTargetSpec, stdout);
|
|
fputs("'\n", stdout);
|
|
mOverURL = aURLSpec;
|
|
mOverTarget = aTargetSpec;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWebShell:: GetLinkState(const nsString& aURLSpec, nsLinkState& aState)
|
|
{
|
|
aState = eLinkState_Unvisited;
|
|
#ifdef NS_DEBUG
|
|
if (aURLSpec.Equals("http://visited/")) {
|
|
aState = eLinkState_Visited;
|
|
}
|
|
else if (aURLSpec.Equals("http://out-of-date/")) {
|
|
aState = eLinkState_OutOfDate;
|
|
}
|
|
else if (aURLSpec.Equals("http://active/")) {
|
|
aState = eLinkState_Active;
|
|
}
|
|
else if (aURLSpec.Equals("http://hover/")) {
|
|
aState = eLinkState_Hover;
|
|
}
|
|
#endif
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Factory code for creating nsWebShell's
|
|
|
|
class nsWebShellFactory : public nsIFactory
|
|
{
|
|
public:
|
|
nsWebShellFactory();
|
|
~nsWebShellFactory();
|
|
|
|
// nsISupports methods
|
|
NS_IMETHOD QueryInterface(const nsIID &aIID, void **aResult);
|
|
NS_IMETHOD_(nsrefcnt) AddRef(void);
|
|
NS_IMETHOD_(nsrefcnt) Release(void);
|
|
|
|
// nsIFactory methods
|
|
NS_IMETHOD CreateInstance(nsISupports *aOuter,
|
|
const nsIID &aIID,
|
|
void **aResult);
|
|
|
|
NS_IMETHOD LockFactory(PRBool aLock);
|
|
|
|
private:
|
|
nsrefcnt mRefCnt;
|
|
};
|
|
|
|
nsWebShellFactory::nsWebShellFactory()
|
|
{
|
|
mRefCnt = 0;
|
|
}
|
|
|
|
nsWebShellFactory::~nsWebShellFactory()
|
|
{
|
|
NS_ASSERTION(mRefCnt == 0, "non-zero refcnt at destruction");
|
|
}
|
|
|
|
nsresult
|
|
nsWebShellFactory::QueryInterface(const nsIID &aIID, void **aResult)
|
|
{
|
|
if (aResult == NULL) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
// Always NULL result, in case of failure
|
|
*aResult = NULL;
|
|
|
|
if (aIID.Equals(kISupportsIID)) {
|
|
*aResult = (void *)(nsISupports*)this;
|
|
} else if (aIID.Equals(kIFactoryIID)) {
|
|
*aResult = (void *)(nsIFactory*)this;
|
|
}
|
|
|
|
if (*aResult == NULL) {
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
AddRef(); // Increase reference count for caller
|
|
return NS_OK;
|
|
}
|
|
|
|
nsrefcnt
|
|
nsWebShellFactory::AddRef()
|
|
{
|
|
return ++mRefCnt;
|
|
}
|
|
|
|
nsrefcnt
|
|
nsWebShellFactory::Release()
|
|
{
|
|
if (--mRefCnt == 0) {
|
|
delete this;
|
|
return 0; // Don't access mRefCnt after deleting!
|
|
}
|
|
return mRefCnt;
|
|
}
|
|
|
|
nsresult
|
|
nsWebShellFactory::CreateInstance(nsISupports *aOuter,
|
|
const nsIID &aIID,
|
|
void **aResult)
|
|
{
|
|
nsresult rv;
|
|
nsWebShell *inst;
|
|
|
|
if (aResult == NULL) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
*aResult = NULL;
|
|
if (nsnull != aOuter) {
|
|
rv = NS_ERROR_NO_AGGREGATION;
|
|
goto done;
|
|
}
|
|
|
|
inst = new nsWebShell();
|
|
if (inst == NULL) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
goto done;
|
|
}
|
|
|
|
NS_ADDREF(inst);
|
|
rv = inst->QueryInterface(aIID, aResult);
|
|
NS_RELEASE(inst);
|
|
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsWebShellFactory::LockFactory(PRBool aLock)
|
|
{
|
|
// Not implemented in simplest case.
|
|
return NS_OK;
|
|
}
|
|
|
|
extern "C" NS_WEB nsresult
|
|
NS_NewWebShellFactory(nsIFactory** aFactory)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
nsIFactory* inst = new nsWebShellFactory();
|
|
if (nsnull == inst) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
else {
|
|
NS_ADDREF(inst);
|
|
}
|
|
*aFactory = inst;
|
|
return rv;
|
|
}
|