2319 lines
71 KiB
C++
2319 lines
71 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=2 sw=2 et tw=78: */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* 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.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 2001
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Harshal Pradhan <keeda@hotpop.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
//#define USEWEAKREFS // (haven't quite figured that out yet)
|
|
|
|
#include "nsWindowWatcher.h"
|
|
|
|
#include "nsAutoLock.h"
|
|
#include "nsCRT.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsPrompt.h"
|
|
#include "nsWWJSUtils.h"
|
|
#include "plstr.h"
|
|
|
|
#include "nsIBaseWindow.h"
|
|
#include "nsIDocShell.h"
|
|
#include "nsIDocShellLoadInfo.h"
|
|
#include "nsIDocShellTreeItem.h"
|
|
#include "nsIDocShellTreeOwner.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "nsIDOMWindow.h"
|
|
#include "nsIDOMChromeWindow.h"
|
|
#include "nsIDOMWindowInternal.h"
|
|
#include "nsIScreen.h"
|
|
#include "nsIScreenManager.h"
|
|
#include "nsIScriptContext.h"
|
|
#include "nsIEventQueue.h"
|
|
#include "nsIEventQueueService.h"
|
|
#include "nsIGenericFactory.h"
|
|
#include "nsIJSContextStack.h"
|
|
#include "nsIObserverService.h"
|
|
#include "nsIScriptGlobalObject.h"
|
|
#include "nsIScriptSecurityManager.h"
|
|
#include "nsISupportsArray.h"
|
|
#include "nsXPCOM.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIWebBrowser.h"
|
|
#include "nsIWebBrowserChrome.h"
|
|
#include "nsIWebNavigation.h"
|
|
#include "nsIWindowCreator.h"
|
|
#include "nsIWindowCreator2.h"
|
|
#include "nsIXPConnect.h"
|
|
#include "nsPIDOMWindow.h"
|
|
#include "nsIMarkupDocumentViewer.h"
|
|
#include "nsIContentViewer.h"
|
|
#include "nsIDocumentViewer.h"
|
|
#include "nsIWindowProvider.h"
|
|
|
|
#include "nsIPrefBranch.h"
|
|
#include "nsIPrefService.h"
|
|
|
|
#include "jsinterp.h" // for js_AllocStack() and js_FreeStack()
|
|
|
|
#ifdef XP_UNIX
|
|
// please see bug 78421 for the eventual "right" fix for this
|
|
#define HAVE_LAME_APPSHELL
|
|
#endif
|
|
|
|
#ifdef HAVE_LAME_APPSHELL
|
|
#include "nsIAppShell.h"
|
|
// for NS_APPSHELL_CID
|
|
#include <nsWidgetsCID.h>
|
|
#endif
|
|
|
|
#ifdef USEWEAKREFS
|
|
#include "nsIWeakReference.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_LAME_APPSHELL
|
|
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
|
#endif
|
|
|
|
static const char *sJSStackContractID="@mozilla.org/js/xpc/ContextStack;1";
|
|
|
|
/****************************************************************
|
|
******************** nsWatcherWindowEntry **********************
|
|
****************************************************************/
|
|
|
|
class nsWindowWatcher;
|
|
|
|
struct nsWatcherWindowEntry {
|
|
|
|
nsWatcherWindowEntry(nsIDOMWindow *inWindow, nsIWebBrowserChrome *inChrome) {
|
|
#ifdef USEWEAKREFS
|
|
mWindow = do_GetWeakReference(inWindow);
|
|
#else
|
|
mWindow = inWindow;
|
|
#endif
|
|
nsCOMPtr<nsISupportsWeakReference> supportsweak(do_QueryInterface(inChrome));
|
|
if (supportsweak) {
|
|
supportsweak->GetWeakReference(getter_AddRefs(mChromeWeak));
|
|
} else {
|
|
mChrome = inChrome;
|
|
mChromeWeak = 0;
|
|
}
|
|
ReferenceSelf();
|
|
}
|
|
~nsWatcherWindowEntry() {}
|
|
|
|
void InsertAfter(nsWatcherWindowEntry *inOlder);
|
|
void Unlink();
|
|
void ReferenceSelf();
|
|
|
|
#ifdef USEWEAKREFS
|
|
nsCOMPtr<nsIWeakReference> mWindow;
|
|
#else // still not an owning ref
|
|
nsIDOMWindow *mWindow;
|
|
#endif
|
|
nsIWebBrowserChrome *mChrome;
|
|
nsWeakPtr mChromeWeak;
|
|
// each struct is in a circular, doubly-linked list
|
|
nsWatcherWindowEntry *mYounger, // next younger in sequence
|
|
*mOlder;
|
|
};
|
|
|
|
void nsWatcherWindowEntry::InsertAfter(nsWatcherWindowEntry *inOlder)
|
|
{
|
|
if (inOlder) {
|
|
mOlder = inOlder;
|
|
mYounger = inOlder->mYounger;
|
|
mOlder->mYounger = this;
|
|
if (mOlder->mOlder == mOlder)
|
|
mOlder->mOlder = this;
|
|
mYounger->mOlder = this;
|
|
if (mYounger->mYounger == mYounger)
|
|
mYounger->mYounger = this;
|
|
}
|
|
}
|
|
|
|
void nsWatcherWindowEntry::Unlink() {
|
|
|
|
mOlder->mYounger = mYounger;
|
|
mYounger->mOlder = mOlder;
|
|
ReferenceSelf();
|
|
}
|
|
|
|
void nsWatcherWindowEntry::ReferenceSelf() {
|
|
|
|
mYounger = this;
|
|
mOlder = this;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************** nsWatcherWindowEnumerator *******************
|
|
****************************************************************/
|
|
|
|
class nsWatcherWindowEnumerator : public nsISimpleEnumerator {
|
|
|
|
public:
|
|
nsWatcherWindowEnumerator(nsWindowWatcher *inWatcher);
|
|
virtual ~nsWatcherWindowEnumerator();
|
|
NS_IMETHOD HasMoreElements(PRBool *retval);
|
|
NS_IMETHOD GetNext(nsISupports **retval);
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
private:
|
|
friend class nsWindowWatcher;
|
|
|
|
nsWatcherWindowEntry *FindNext();
|
|
void WindowRemoved(nsWatcherWindowEntry *inInfo);
|
|
|
|
nsWindowWatcher *mWindowWatcher;
|
|
nsWatcherWindowEntry *mCurrentPosition;
|
|
};
|
|
|
|
NS_IMPL_ADDREF(nsWatcherWindowEnumerator)
|
|
NS_IMPL_RELEASE(nsWatcherWindowEnumerator)
|
|
NS_IMPL_QUERY_INTERFACE1(nsWatcherWindowEnumerator, nsISimpleEnumerator)
|
|
|
|
nsWatcherWindowEnumerator::nsWatcherWindowEnumerator(nsWindowWatcher *inWatcher)
|
|
: mWindowWatcher(inWatcher),
|
|
mCurrentPosition(inWatcher->mOldestWindow)
|
|
{
|
|
mWindowWatcher->AddEnumerator(this);
|
|
mWindowWatcher->AddRef();
|
|
}
|
|
|
|
nsWatcherWindowEnumerator::~nsWatcherWindowEnumerator()
|
|
{
|
|
mWindowWatcher->RemoveEnumerator(this);
|
|
mWindowWatcher->Release();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWatcherWindowEnumerator::HasMoreElements(PRBool *retval)
|
|
{
|
|
if (!retval)
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
*retval = mCurrentPosition? PR_TRUE : PR_FALSE;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWatcherWindowEnumerator::GetNext(nsISupports **retval)
|
|
{
|
|
if (!retval)
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
*retval = NULL;
|
|
|
|
#ifdef USEWEAKREFS
|
|
while (mCurrentPosition) {
|
|
CallQueryReferent(mCurrentPosition->mWindow, retval);
|
|
if (*retval) {
|
|
mCurrentPosition = FindNext();
|
|
break;
|
|
} else // window is gone!
|
|
mWindowWatcher->RemoveWindow(mCurrentPosition);
|
|
}
|
|
NS_IF_ADDREF(*retval);
|
|
#else
|
|
if (mCurrentPosition) {
|
|
CallQueryInterface(mCurrentPosition->mWindow, retval);
|
|
mCurrentPosition = FindNext();
|
|
}
|
|
#endif
|
|
return NS_OK;
|
|
}
|
|
|
|
nsWatcherWindowEntry *
|
|
nsWatcherWindowEnumerator::FindNext()
|
|
{
|
|
nsWatcherWindowEntry *info;
|
|
|
|
if (!mCurrentPosition)
|
|
return 0;
|
|
|
|
info = mCurrentPosition->mYounger;
|
|
return info == mWindowWatcher->mOldestWindow ? 0 : info;
|
|
}
|
|
|
|
// if a window is being removed adjust the iterator's current position
|
|
void nsWatcherWindowEnumerator::WindowRemoved(nsWatcherWindowEntry *inInfo) {
|
|
|
|
if (mCurrentPosition == inInfo)
|
|
mCurrentPosition = mCurrentPosition != inInfo->mYounger ?
|
|
inInfo->mYounger : 0;
|
|
}
|
|
|
|
/****************************************************************
|
|
********************* EventQueueAutoPopper *********************
|
|
****************************************************************/
|
|
|
|
class EventQueueAutoPopper {
|
|
public:
|
|
EventQueueAutoPopper();
|
|
~EventQueueAutoPopper();
|
|
|
|
nsresult Push();
|
|
|
|
protected:
|
|
nsCOMPtr<nsIEventQueueService> mService;
|
|
nsCOMPtr<nsIEventQueue> mQueue;
|
|
#ifdef HAVE_LAME_APPSHELL
|
|
nsCOMPtr<nsIAppShell> mAppShell;
|
|
#endif
|
|
};
|
|
|
|
EventQueueAutoPopper::EventQueueAutoPopper() : mQueue(nsnull)
|
|
{
|
|
}
|
|
|
|
EventQueueAutoPopper::~EventQueueAutoPopper()
|
|
{
|
|
#ifdef HAVE_LAME_APPSHELL
|
|
if (mAppShell) {
|
|
if (mQueue)
|
|
mAppShell->ListenToEventQueue(mQueue, PR_FALSE);
|
|
mAppShell->Spindown();
|
|
mAppShell = nsnull;
|
|
}
|
|
#endif
|
|
|
|
if(mQueue)
|
|
mService->PopThreadEventQueue(mQueue);
|
|
}
|
|
|
|
nsresult EventQueueAutoPopper::Push()
|
|
{
|
|
if (mQueue) // only once
|
|
return NS_ERROR_FAILURE;
|
|
|
|
mService = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID);
|
|
if (!mService)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// push a new queue onto it
|
|
mService->PushThreadEventQueue(getter_AddRefs(mQueue));
|
|
if (!mQueue)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
#ifdef HAVE_LAME_APPSHELL
|
|
// listen to the event queue
|
|
mAppShell = do_CreateInstance(kAppShellCID);
|
|
if (!mAppShell)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
mAppShell->Create(0, nsnull);
|
|
mAppShell->Spinup();
|
|
|
|
// listen to the new queue
|
|
mAppShell->ListenToEventQueue(mQueue, PR_TRUE);
|
|
#endif
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/****************************************************************
|
|
********************** JSContextAutoPopper *********************
|
|
****************************************************************/
|
|
|
|
class JSContextAutoPopper {
|
|
public:
|
|
JSContextAutoPopper();
|
|
~JSContextAutoPopper();
|
|
|
|
nsresult Push(JSContext *cx = nsnull);
|
|
JSContext *get() { return mContext; }
|
|
|
|
protected:
|
|
nsCOMPtr<nsIThreadJSContextStack> mService;
|
|
JSContext *mContext;
|
|
};
|
|
|
|
JSContextAutoPopper::JSContextAutoPopper() : mContext(nsnull)
|
|
{
|
|
}
|
|
|
|
JSContextAutoPopper::~JSContextAutoPopper()
|
|
{
|
|
JSContext *cx;
|
|
nsresult rv;
|
|
|
|
if(mContext) {
|
|
rv = mService->Pop(&cx);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv) && cx == mContext, "JSContext push/pop mismatch");
|
|
}
|
|
}
|
|
|
|
nsresult JSContextAutoPopper::Push(JSContext *cx)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (mContext) // only once
|
|
return NS_ERROR_FAILURE;
|
|
|
|
mService = do_GetService(sJSStackContractID);
|
|
if(mService) {
|
|
if (cx) {
|
|
mContext = cx;
|
|
} else {
|
|
rv = mService->GetSafeJSContext(&mContext);
|
|
}
|
|
|
|
if (NS_SUCCEEDED(rv) && mContext) {
|
|
rv = mService->Push(mContext);
|
|
if (NS_FAILED(rv))
|
|
mContext = 0;
|
|
}
|
|
}
|
|
return mContext ? NS_OK : NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/****************************************************************
|
|
************************** AutoFree ****************************
|
|
****************************************************************/
|
|
|
|
class AutoFree {
|
|
public:
|
|
AutoFree(void *aPtr) : mPtr(aPtr) {
|
|
}
|
|
~AutoFree() {
|
|
if (mPtr)
|
|
nsMemory::Free(mPtr);
|
|
}
|
|
void Invalidate() {
|
|
mPtr = 0;
|
|
}
|
|
private:
|
|
void *mPtr;
|
|
};
|
|
|
|
/****************************************************************
|
|
*********************** nsWindowWatcher ************************
|
|
****************************************************************/
|
|
|
|
NS_IMPL_ADDREF(nsWindowWatcher)
|
|
NS_IMPL_RELEASE(nsWindowWatcher)
|
|
NS_IMPL_QUERY_INTERFACE2(nsWindowWatcher, nsIWindowWatcher, nsPIWindowWatcher)
|
|
|
|
nsWindowWatcher::nsWindowWatcher() :
|
|
mEnumeratorList(),
|
|
mOldestWindow(0),
|
|
mActiveWindow(0),
|
|
mListLock(0)
|
|
{
|
|
}
|
|
|
|
nsWindowWatcher::~nsWindowWatcher()
|
|
{
|
|
// delete data
|
|
while (mOldestWindow)
|
|
RemoveWindow(mOldestWindow);
|
|
|
|
if (mListLock)
|
|
PR_DestroyLock(mListLock);
|
|
}
|
|
|
|
nsresult
|
|
nsWindowWatcher::Init()
|
|
{
|
|
mListLock = PR_NewLock();
|
|
if (!mListLock)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::OpenWindow(nsIDOMWindow *aParent,
|
|
const char *aUrl,
|
|
const char *aName,
|
|
const char *aFeatures,
|
|
nsISupports *aArguments,
|
|
nsIDOMWindow **_retval)
|
|
{
|
|
PRUint32 argc;
|
|
jsval *argv = nsnull;
|
|
JSContext *cx;
|
|
void *mark;
|
|
|
|
// This kungFuDeathGrip is filled when we are using aParent's context. It
|
|
// prevents the context from being destroyed before we're truly done with
|
|
// it.
|
|
nsCOMPtr<nsIScriptContext> kungFuDeathGrip;
|
|
|
|
nsresult rv = ConvertSupportsTojsvals(aParent, aArguments, &argc, &argv, &cx,
|
|
&mark, getter_AddRefs(kungFuDeathGrip));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
PRBool dialog = argc == 0 ? PR_FALSE : PR_TRUE;
|
|
rv = OpenWindowJSInternal(aParent, aUrl, aName, aFeatures, dialog, argc,
|
|
argv, PR_FALSE, _retval);
|
|
|
|
if (argv) {
|
|
js_FreeStack(cx, mark);
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
struct SizeSpec {
|
|
SizeSpec() :
|
|
mLeftSpecified(PR_FALSE),
|
|
mTopSpecified(PR_FALSE),
|
|
mOuterWidthSpecified(PR_FALSE),
|
|
mOuterHeightSpecified(PR_FALSE),
|
|
mInnerWidthSpecified(PR_FALSE),
|
|
mInnerHeightSpecified(PR_FALSE),
|
|
mUseDefaultWidth(PR_FALSE),
|
|
mUseDefaultHeight(PR_FALSE)
|
|
{}
|
|
|
|
PRInt32 mLeft;
|
|
PRInt32 mTop;
|
|
PRInt32 mOuterWidth; // Total window width
|
|
PRInt32 mOuterHeight; // Total window height
|
|
PRInt32 mInnerWidth; // Content area width
|
|
PRInt32 mInnerHeight; // Content area height
|
|
|
|
PRPackedBool mLeftSpecified;
|
|
PRPackedBool mTopSpecified;
|
|
PRPackedBool mOuterWidthSpecified;
|
|
PRPackedBool mOuterHeightSpecified;
|
|
PRPackedBool mInnerWidthSpecified;
|
|
PRPackedBool mInnerHeightSpecified;
|
|
|
|
// If these booleans are true, don't look at the corresponding width values
|
|
// even if they're specified -- they'll be bogus
|
|
PRPackedBool mUseDefaultWidth;
|
|
PRPackedBool mUseDefaultHeight;
|
|
|
|
PRBool PositionSpecified() const {
|
|
return mLeftSpecified || mTopSpecified;
|
|
}
|
|
|
|
PRBool SizeSpecified() const {
|
|
return mOuterWidthSpecified || mOuterHeightSpecified ||
|
|
mInnerWidthSpecified || mInnerHeightSpecified;
|
|
}
|
|
};
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|
const char *aUrl,
|
|
const char *aName,
|
|
const char *aFeatures,
|
|
PRBool aDialog,
|
|
PRUint32 argc,
|
|
jsval *argv,
|
|
nsIDOMWindow **_retval)
|
|
{
|
|
return OpenWindowJSInternal(aParent, aUrl, aName, aFeatures, aDialog, argc,
|
|
argv, PR_TRUE, _retval);
|
|
}
|
|
|
|
nsresult
|
|
nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
|
|
const char *aUrl,
|
|
const char *aName,
|
|
const char *aFeatures,
|
|
PRBool aDialog,
|
|
PRUint32 argc,
|
|
jsval *argv,
|
|
PRBool aCalledFromJS,
|
|
nsIDOMWindow **_retval)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
PRBool nameSpecified,
|
|
featuresSpecified,
|
|
isNewToplevelWindow = PR_FALSE,
|
|
windowIsNew = PR_FALSE,
|
|
windowNeedsName = PR_FALSE,
|
|
windowIsModal = PR_FALSE,
|
|
uriToLoadIsChrome = PR_FALSE;
|
|
PRUint32 chromeFlags;
|
|
nsAutoString name; // string version of aName
|
|
nsCAutoString features; // string version of aFeatures
|
|
nsCOMPtr<nsIURI> uriToLoad; // from aUrl, if any
|
|
nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner; // from the parent window, if any
|
|
nsCOMPtr<nsIDocShellTreeItem> newDocShellItem; // from the new window
|
|
EventQueueAutoPopper queueGuard;
|
|
JSContextAutoPopper callerContextGuard;
|
|
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
*_retval = 0;
|
|
|
|
GetWindowTreeOwner(aParent, getter_AddRefs(parentTreeOwner));
|
|
|
|
if (aUrl) {
|
|
rv = URIfromURL(aUrl, aParent, getter_AddRefs(uriToLoad));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
uriToLoad->SchemeIs("chrome", &uriToLoadIsChrome);
|
|
}
|
|
|
|
nameSpecified = PR_FALSE;
|
|
if (aName) {
|
|
CopyUTF8toUTF16(aName, name);
|
|
#ifdef DEBUG
|
|
CheckWindowName(name);
|
|
#endif
|
|
nameSpecified = PR_TRUE;
|
|
}
|
|
|
|
featuresSpecified = PR_FALSE;
|
|
if (aFeatures) {
|
|
features.Assign(aFeatures);
|
|
featuresSpecified = PR_TRUE;
|
|
features.StripWhitespace();
|
|
}
|
|
|
|
// try to find an extant window with the given name
|
|
nsCOMPtr<nsIDOMWindow> foundWindow;
|
|
SafeGetWindowByName(name, aParent, getter_AddRefs(foundWindow));
|
|
GetWindowTreeItem(foundWindow, getter_AddRefs(newDocShellItem));
|
|
|
|
// no extant window? make a new one.
|
|
|
|
nsCOMPtr<nsIDOMChromeWindow> chromeParent(do_QueryInterface(aParent));
|
|
|
|
// Make sure we call CalculateChromeFlags() *before* we push the
|
|
// callee context onto the context stack so that
|
|
// CalculateChromeFlags() sees the actual caller when doing it's
|
|
// security checks.
|
|
chromeFlags = CalculateChromeFlags(features.get(), featuresSpecified,
|
|
aDialog, uriToLoadIsChrome,
|
|
!aParent || chromeParent);
|
|
|
|
SizeSpec sizeSpec;
|
|
CalcSizeSpec(features.get(), sizeSpec);
|
|
|
|
PRBool isCallerChrome = PR_FALSE;
|
|
nsCOMPtr<nsIScriptSecurityManager>
|
|
sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
|
|
if (sm)
|
|
sm->SubjectPrincipalIsSystem(&isCallerChrome);
|
|
|
|
JSContext *cx = GetJSContextFromWindow(aParent);
|
|
|
|
if (isCallerChrome && !chromeParent && cx) {
|
|
// open() is called from chrome on a non-chrome window, push
|
|
// the context of the callee onto the context stack to
|
|
// prevent the caller's priveleges from leaking into code
|
|
// that runs while opening the new window.
|
|
|
|
callerContextGuard.Push(cx);
|
|
}
|
|
|
|
if (!newDocShellItem) {
|
|
// We're going to either open up a new window ourselves or ask a
|
|
// nsIWindowProvider for one. In either case, we'll want to set the right
|
|
// name on it.
|
|
windowNeedsName = PR_TRUE;
|
|
|
|
// Now check whether it's ok to ask a window provider for a window. Don't
|
|
// do it if we're opening a dialog or if our parent is a chrome window or
|
|
// if we're opening something that has dependent, modal, dialog, or chrome
|
|
// flags set.
|
|
nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(aParent);
|
|
if (!aDialog && !chromeWin &&
|
|
!(chromeFlags & (nsIWebBrowserChrome::CHROME_DEPENDENT |
|
|
nsIWebBrowserChrome::CHROME_MODAL |
|
|
nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
|
|
nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) {
|
|
nsCOMPtr<nsIWindowProvider> provider = do_GetInterface(parentTreeOwner);
|
|
if (provider) {
|
|
NS_ASSERTION(aParent, "We've _got_ to have a parent here!");
|
|
|
|
nsCOMPtr<nsIDOMWindow> newWindow;
|
|
rv = provider->ProvideWindow(aParent, chromeFlags,
|
|
sizeSpec.PositionSpecified(),
|
|
sizeSpec.SizeSpecified(),
|
|
uriToLoad, name, features, &windowIsNew,
|
|
getter_AddRefs(newWindow));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
GetWindowTreeItem(newWindow, getter_AddRefs(newDocShellItem));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!newDocShellItem) {
|
|
windowIsNew = PR_TRUE;
|
|
isNewToplevelWindow = PR_TRUE;
|
|
|
|
nsCOMPtr<nsIWebBrowserChrome> parentChrome(do_GetInterface(parentTreeOwner));
|
|
|
|
// is the parent (if any) modal? if so, we must be, too.
|
|
PRBool weAreModal = (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL) != 0;
|
|
if (!weAreModal && parentChrome)
|
|
parentChrome->IsWindowModal(&weAreModal);
|
|
|
|
if (weAreModal) {
|
|
rv = queueGuard.Push();
|
|
if (NS_SUCCEEDED(rv)) {
|
|
windowIsModal = PR_TRUE;
|
|
// in case we added this because weAreModal
|
|
chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL |
|
|
nsIWebBrowserChrome::CHROME_DEPENDENT;
|
|
}
|
|
}
|
|
|
|
NS_ASSERTION(mWindowCreator,
|
|
"attempted to open a new window with no WindowCreator");
|
|
rv = NS_ERROR_FAILURE;
|
|
if (mWindowCreator) {
|
|
nsCOMPtr<nsIWebBrowserChrome> newChrome;
|
|
|
|
/* If the window creator is an nsIWindowCreator2, we can give it
|
|
some hints. The only hint at this time is whether the opening window
|
|
is in a situation that's likely to mean this is an unrequested
|
|
popup window we're creating. However we're not completely honest:
|
|
we clear that indicator if the opener is chrome, so that the
|
|
downstream consumer can treat the indicator to mean simply
|
|
that the new window is subject to popup control. */
|
|
nsCOMPtr<nsIWindowCreator2> windowCreator2(do_QueryInterface(mWindowCreator));
|
|
if (windowCreator2) {
|
|
PRUint32 contextFlags = 0;
|
|
PRBool popupConditions = PR_FALSE;
|
|
|
|
// is the parent under popup conditions?
|
|
nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(aParent));
|
|
if (piWindow)
|
|
popupConditions = piWindow->IsLoadingOrRunningTimeout();
|
|
|
|
// chrome is always allowed, so clear the flag if the opener is chrome
|
|
if (popupConditions) {
|
|
PRBool isChrome = PR_FALSE;
|
|
if (sm)
|
|
sm->SubjectPrincipalIsSystem(&isChrome);
|
|
popupConditions = !isChrome;
|
|
}
|
|
|
|
if (popupConditions)
|
|
contextFlags |= nsIWindowCreator2::PARENT_IS_LOADING_OR_RUNNING_TIMEOUT;
|
|
|
|
PRBool cancel = PR_FALSE;
|
|
rv = windowCreator2->CreateChromeWindow2(parentChrome, chromeFlags,
|
|
contextFlags, uriToLoad, &cancel,
|
|
getter_AddRefs(newChrome));
|
|
if (NS_SUCCEEDED(rv) && cancel) {
|
|
newChrome = 0; // just in case
|
|
rv = NS_ERROR_ABORT;
|
|
}
|
|
}
|
|
else
|
|
rv = mWindowCreator->CreateChromeWindow(parentChrome, chromeFlags,
|
|
getter_AddRefs(newChrome));
|
|
if (newChrome) {
|
|
/* It might be a chrome nsXULWindow, in which case it won't have
|
|
an nsIDOMWindow (primary content shell). But in that case, it'll
|
|
be able to hand over an nsIDocShellTreeItem directly. */
|
|
nsCOMPtr<nsIDOMWindow> newWindow(do_GetInterface(newChrome));
|
|
if (newWindow)
|
|
GetWindowTreeItem(newWindow, getter_AddRefs(newDocShellItem));
|
|
if (!newDocShellItem)
|
|
newDocShellItem = do_GetInterface(newChrome);
|
|
if (!newDocShellItem)
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// better have a window to use by this point
|
|
if (!newDocShellItem)
|
|
return rv;
|
|
|
|
nsCOMPtr<nsIDocShell> newDocShell(do_QueryInterface(newDocShellItem));
|
|
NS_ENSURE_TRUE(newDocShell, NS_ERROR_UNEXPECTED);
|
|
|
|
rv = ReadyOpenedDocShellItem(newDocShellItem, aParent, windowIsNew, _retval);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
/* disable persistence of size/position in popups (determined by
|
|
determining whether the features parameter specifies width or height
|
|
in any way). We consider any overriding of the window's size or position
|
|
in the open call as disabling persistence of those attributes.
|
|
Popup windows (which should not persist size or position) generally set
|
|
the size. */
|
|
if (isNewToplevelWindow) {
|
|
/* at the moment, the strings "height=" or "width=" never happen
|
|
outside a size specification, so we can do this the Q&D way. */
|
|
|
|
if (PL_strcasestr(features.get(), "width=") || PL_strcasestr(features.get(), "height=")) {
|
|
|
|
nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
|
|
newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
|
|
if (newTreeOwner)
|
|
newTreeOwner->SetPersistence(PR_FALSE, PR_FALSE, PR_FALSE);
|
|
}
|
|
}
|
|
|
|
if (aDialog && argc > 0) {
|
|
rv = AttachArguments(*_retval, argc, argv);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
/* allow a window that we found by name to keep its name (important for cases
|
|
like _self where the given name is different (and invalid)). Also, _blank
|
|
and _new are not window names. */
|
|
if (windowNeedsName)
|
|
newDocShellItem->SetName(nameSpecified &&
|
|
!name.LowerCaseEqualsLiteral("_blank") &&
|
|
!name.LowerCaseEqualsLiteral("_new") ?
|
|
name.get() : nsnull);
|
|
|
|
|
|
// Inherit the right character set into the new window to use as a fallback
|
|
// in the event the document being loaded does not specify a charset. When
|
|
// aCalledFromJS is true, we want to use the character set of the document in
|
|
// the caller; otherwise we want to use the character set of aParent's
|
|
// docshell. Failing to set this charset is not fatal, so we want to continue
|
|
// in the face of errors.
|
|
nsCOMPtr<nsIContentViewer> newCV;
|
|
newDocShell->GetContentViewer(getter_AddRefs(newCV));
|
|
nsCOMPtr<nsIMarkupDocumentViewer> newMuCV = do_QueryInterface(newCV);
|
|
if (newMuCV) {
|
|
nsCOMPtr<nsIDocShellTreeItem> parentItem;
|
|
GetWindowTreeItem(aParent, getter_AddRefs(parentItem));
|
|
|
|
if (aCalledFromJS) {
|
|
nsCOMPtr<nsIDocShellTreeItem> callerItem = GetCallerTreeItem(parentItem);
|
|
nsCOMPtr<nsPIDOMWindow> callerWin = do_GetInterface(callerItem);
|
|
if (callerWin) {
|
|
nsCOMPtr<nsIDocument> doc =
|
|
do_QueryInterface(callerWin->GetExtantDocument());
|
|
if (doc) {
|
|
newMuCV->SetDefaultCharacterSet(doc->GetDocumentCharacterSet());
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
nsCOMPtr<nsIDocShell> parentDocshell = do_QueryInterface(parentItem);
|
|
// parentDocshell may be null if the parent got closed in the meantime
|
|
if (parentDocshell) {
|
|
nsCOMPtr<nsIContentViewer> parentCV;
|
|
parentDocshell->GetContentViewer(getter_AddRefs(parentCV));
|
|
nsCOMPtr<nsIMarkupDocumentViewer> parentMuCV =
|
|
do_QueryInterface(parentCV);
|
|
if (parentMuCV) {
|
|
nsCAutoString charset;
|
|
nsresult res = parentMuCV->GetDefaultCharacterSet(charset);
|
|
if (NS_SUCCEEDED(res)) {
|
|
newMuCV->SetDefaultCharacterSet(charset);
|
|
}
|
|
res = parentMuCV->GetPrevDocCharacterSet(charset);
|
|
if (NS_SUCCEEDED(res)) {
|
|
newMuCV->SetPrevDocCharacterSet(charset);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isNewToplevelWindow) {
|
|
// Notify observers that the window is open and ready.
|
|
// The window has not yet started to load a document.
|
|
nsCOMPtr<nsIObserverService> obsSvc =
|
|
do_GetService("@mozilla.org/observer-service;1");
|
|
if (obsSvc) {
|
|
obsSvc->NotifyObservers(*_retval, "toplevel-window-ready", nsnull);
|
|
}
|
|
}
|
|
|
|
if (uriToLoad) { // get the script principal and pass it to docshell
|
|
JSContextAutoPopper contextGuard;
|
|
|
|
cx = GetJSContextFromCallStack();
|
|
|
|
// get the security manager
|
|
if (!cx)
|
|
cx = GetJSContextFromWindow(aParent);
|
|
if (!cx) {
|
|
rv = contextGuard.Push();
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
cx = contextGuard.get();
|
|
}
|
|
|
|
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
|
|
newDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
|
|
NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
|
|
|
|
if (!uriToLoadIsChrome) {
|
|
nsCOMPtr<nsIPrincipal> principal;
|
|
if (NS_FAILED(sm->GetSubjectPrincipal(getter_AddRefs(principal))))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
if (principal) {
|
|
nsCOMPtr<nsISupports> owner(do_QueryInterface(principal));
|
|
loadInfo->SetOwner(owner);
|
|
}
|
|
}
|
|
|
|
// Set the new window's referrer from the calling context's document:
|
|
|
|
// get the calling context off the JS context stack
|
|
nsCOMPtr<nsIJSContextStack> stack = do_GetService(sJSStackContractID);
|
|
|
|
JSContext* ccx = nsnull;
|
|
|
|
// get its document, if any
|
|
if (stack && NS_SUCCEEDED(stack->Peek(&ccx)) && ccx) {
|
|
nsIScriptGlobalObject *sgo = nsWWJSUtils::GetDynamicScriptGlobal(ccx);
|
|
|
|
nsCOMPtr<nsPIDOMWindow> w(do_QueryInterface(sgo));
|
|
if (w) {
|
|
/* use the URL from the *extant* document, if any. The usual accessor
|
|
GetDocument will synchronously create an about:blank document if
|
|
it has no better answer, and we only care about a real document.
|
|
Also using GetDocument to force document creation seems to
|
|
screw up focus in the hidden window; see bug 36016.
|
|
*/
|
|
nsCOMPtr<nsIDocument> doc(do_QueryInterface(w->GetExtantDocument()));
|
|
if (doc) {
|
|
// Set the referrer
|
|
loadInfo->SetReferrer(doc->GetDocumentURI());
|
|
}
|
|
}
|
|
}
|
|
|
|
newDocShell->LoadURI(uriToLoad, loadInfo,
|
|
nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE);
|
|
}
|
|
|
|
if (isNewToplevelWindow)
|
|
SizeOpenedDocShellItem(newDocShellItem, aParent, sizeSpec);
|
|
|
|
if (windowIsModal) {
|
|
nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
|
|
newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
|
|
nsCOMPtr<nsIWebBrowserChrome> newChrome(do_GetInterface(newTreeOwner));
|
|
if (newChrome)
|
|
newChrome->ShowAsModal();
|
|
NS_ASSERTION(newChrome, "show modal window failed: no available chrome");
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::RegisterNotification(nsIObserver *aObserver)
|
|
{
|
|
// just a convenience method; it delegates to nsIObserverService
|
|
nsresult rv;
|
|
|
|
if (!aObserver)
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1", &rv));
|
|
if (os) {
|
|
rv = os->AddObserver(aObserver, "domwindowopened", PR_FALSE);
|
|
if (NS_SUCCEEDED(rv))
|
|
rv = os->AddObserver(aObserver, "domwindowclosed", PR_FALSE);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::UnregisterNotification(nsIObserver *aObserver)
|
|
{
|
|
// just a convenience method; it delegates to nsIObserverService
|
|
nsresult rv;
|
|
|
|
if (!aObserver)
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1", &rv));
|
|
if (os) {
|
|
os->RemoveObserver(aObserver, "domwindowopened");
|
|
os->RemoveObserver(aObserver, "domwindowclosed");
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::GetWindowEnumerator(nsISimpleEnumerator** _retval)
|
|
{
|
|
if (!_retval)
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
nsAutoLock lock(mListLock);
|
|
nsWatcherWindowEnumerator *enumerator = new nsWatcherWindowEnumerator(this);
|
|
if (enumerator)
|
|
return CallQueryInterface(enumerator, _retval);
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::GetNewPrompter(nsIDOMWindow *aParent, nsIPrompt **_retval)
|
|
{
|
|
return NS_NewPrompter(_retval, aParent);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::GetNewAuthPrompter(nsIDOMWindow *aParent, nsIAuthPrompt **_retval)
|
|
{
|
|
return NS_NewAuthPrompter(_retval, aParent);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::SetWindowCreator(nsIWindowCreator *creator)
|
|
{
|
|
mWindowCreator = creator; // it's an nsCOMPtr, so this is an ownership ref
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::GetActiveWindow(nsIDOMWindow **aActiveWindow)
|
|
{
|
|
if (!aActiveWindow)
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
*aActiveWindow = mActiveWindow;
|
|
NS_IF_ADDREF(mActiveWindow);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::SetActiveWindow(nsIDOMWindow *aActiveWindow)
|
|
{
|
|
#ifdef DEBUG
|
|
{
|
|
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aActiveWindow));
|
|
|
|
NS_ASSERTION(!win || win->IsOuterWindow(),
|
|
"Uh, the active window must be an outer window!");
|
|
}
|
|
#endif
|
|
|
|
if (FindWindowEntry(aActiveWindow)) {
|
|
mActiveWindow = aActiveWindow;
|
|
return NS_OK;
|
|
}
|
|
NS_ERROR("invalid active window");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::AddWindow(nsIDOMWindow *aWindow, nsIWebBrowserChrome *aChrome)
|
|
{
|
|
nsresult rv;
|
|
|
|
if (!aWindow)
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow));
|
|
|
|
NS_ASSERTION(win->IsOuterWindow(),
|
|
"Uh, the active window must be an outer window!");
|
|
}
|
|
#endif
|
|
|
|
{
|
|
nsWatcherWindowEntry *info;
|
|
nsAutoLock lock(mListLock);
|
|
|
|
// if we already have an entry for this window, adjust
|
|
// its chrome mapping and return
|
|
info = FindWindowEntry(aWindow);
|
|
if (info) {
|
|
nsCOMPtr<nsISupportsWeakReference> supportsweak(do_QueryInterface(aChrome));
|
|
if (supportsweak) {
|
|
supportsweak->GetWeakReference(getter_AddRefs(info->mChromeWeak));
|
|
} else {
|
|
info->mChrome = aChrome;
|
|
info->mChromeWeak = 0;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
// create a window info struct and add it to the list of windows
|
|
info = new nsWatcherWindowEntry(aWindow, aChrome);
|
|
if (!info)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
if (mOldestWindow)
|
|
info->InsertAfter(mOldestWindow->mOlder);
|
|
else
|
|
mOldestWindow = info;
|
|
} // leave the mListLock
|
|
|
|
// a window being added to us signifies a newly opened window.
|
|
// send notifications.
|
|
nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1", &rv));
|
|
if (os) {
|
|
nsCOMPtr<nsISupports> domwin(do_QueryInterface(aWindow));
|
|
rv = os->NotifyObservers(domwin, "domwindowopened", 0);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::RemoveWindow(nsIDOMWindow *aWindow)
|
|
{
|
|
// find the corresponding nsWatcherWindowEntry, remove it
|
|
|
|
if (!aWindow)
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
nsWatcherWindowEntry *info = FindWindowEntry(aWindow);
|
|
if (info) {
|
|
RemoveWindow(info);
|
|
return NS_OK;
|
|
}
|
|
NS_WARNING("requested removal of nonexistent window\n");
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
nsWatcherWindowEntry *
|
|
nsWindowWatcher::FindWindowEntry(nsIDOMWindow *aWindow)
|
|
{
|
|
// find the corresponding nsWatcherWindowEntry
|
|
nsWatcherWindowEntry *info,
|
|
*listEnd;
|
|
#ifdef USEWEAKREFS
|
|
nsresult rv;
|
|
PRBool found;
|
|
#endif
|
|
|
|
info = mOldestWindow;
|
|
listEnd = 0;
|
|
#ifdef USEWEAKREFS
|
|
rv = NS_OK;
|
|
found = PR_FALSE;
|
|
while (info != listEnd && NS_SUCCEEDED(rv)) {
|
|
nsCOMPtr<nsIDOMWindow> infoWindow(do_QueryReferent(info->mWindow));
|
|
if (!infoWindow) { // clean up dangling reference, while we're here
|
|
rv = RemoveWindow(info);
|
|
}
|
|
else if (infoWindow.get() == aWindow)
|
|
return info;
|
|
|
|
info = info->mYounger;
|
|
listEnd = mOldestWindow;
|
|
}
|
|
return 0;
|
|
#else
|
|
while (info != listEnd) {
|
|
if (info->mWindow == aWindow)
|
|
return info;
|
|
info = info->mYounger;
|
|
listEnd = mOldestWindow;
|
|
}
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
nsresult nsWindowWatcher::RemoveWindow(nsWatcherWindowEntry *inInfo)
|
|
{
|
|
PRInt32 ctr,
|
|
count = mEnumeratorList.Count();
|
|
nsresult rv;
|
|
|
|
{
|
|
// notify the enumerators
|
|
nsAutoLock lock(mListLock);
|
|
for (ctr = 0; ctr < count; ++ctr)
|
|
((nsWatcherWindowEnumerator*)mEnumeratorList[ctr])->WindowRemoved(inInfo);
|
|
|
|
// remove the element from the list
|
|
if (inInfo == mOldestWindow)
|
|
mOldestWindow = inInfo->mYounger == mOldestWindow ? 0 : inInfo->mYounger;
|
|
inInfo->Unlink();
|
|
|
|
// clear the active window, if they're the same
|
|
if (mActiveWindow == inInfo->mWindow)
|
|
mActiveWindow = 0;
|
|
}
|
|
|
|
// a window being removed from us signifies a newly closed window.
|
|
// send notifications.
|
|
nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1", &rv));
|
|
if (os) {
|
|
#ifdef USEWEAKREFS
|
|
nsCOMPtr<nsISupports> domwin(do_QueryReferent(inInfo->mWindow));
|
|
if (domwin)
|
|
rv = os->NotifyObservers(domwin, "domwindowclosed", 0);
|
|
// else bummer. since the window is gone, there's nothing to notify with.
|
|
#else
|
|
nsCOMPtr<nsISupports> domwin(do_QueryInterface(inInfo->mWindow));
|
|
rv = os->NotifyObservers(domwin, "domwindowclosed", 0);
|
|
#endif
|
|
}
|
|
|
|
delete inInfo;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::GetChromeForWindow(nsIDOMWindow *aWindow, nsIWebBrowserChrome **_retval)
|
|
{
|
|
if (!aWindow || !_retval)
|
|
return NS_ERROR_INVALID_ARG;
|
|
*_retval = 0;
|
|
|
|
nsAutoLock lock(mListLock);
|
|
nsWatcherWindowEntry *info = FindWindowEntry(aWindow);
|
|
if (info) {
|
|
if (info->mChromeWeak != nsnull) {
|
|
return info->mChromeWeak->
|
|
QueryReferent(NS_GET_IID(nsIWebBrowserChrome),
|
|
NS_REINTERPRET_CAST(void**, _retval));
|
|
}
|
|
*_retval = info->mChrome;
|
|
NS_IF_ADDREF(*_retval);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::GetWindowByName(const PRUnichar *aTargetName,
|
|
nsIDOMWindow *aCurrentWindow,
|
|
nsIDOMWindow **aResult)
|
|
{
|
|
if (!aResult) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
*aResult = nsnull;
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> startItem;
|
|
GetWindowTreeItem(aCurrentWindow, getter_AddRefs(startItem));
|
|
if (startItem) {
|
|
// Note: original requestor is null here, per idl comments
|
|
startItem->FindItemWithName(aTargetName, nsnull, nsnull,
|
|
getter_AddRefs(treeItem));
|
|
}
|
|
else {
|
|
// Note: original requestor is null here, per idl comments
|
|
FindItemWithName(aTargetName, nsnull, nsnull, getter_AddRefs(treeItem));
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(treeItem);
|
|
domWindow.swap(*aResult);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
PRBool
|
|
nsWindowWatcher::AddEnumerator(nsWatcherWindowEnumerator* inEnumerator)
|
|
{
|
|
// (requires a lock; assumes it's called by someone holding the lock)
|
|
return mEnumeratorList.AppendElement(inEnumerator);
|
|
}
|
|
|
|
PRBool
|
|
nsWindowWatcher::RemoveEnumerator(nsWatcherWindowEnumerator* inEnumerator)
|
|
{
|
|
// (requires a lock; assumes it's called by someone holding the lock)
|
|
return mEnumeratorList.RemoveElement(inEnumerator);
|
|
}
|
|
|
|
nsresult
|
|
nsWindowWatcher::URIfromURL(const char *aURL,
|
|
nsIDOMWindow *aParent,
|
|
nsIURI **aURI)
|
|
{
|
|
nsCOMPtr<nsIDOMWindow> baseWindow;
|
|
|
|
/* build the URI relative to the calling JS Context, if any.
|
|
(note this is the same context used to make the security check
|
|
in nsGlobalWindow.cpp.) */
|
|
JSContext *cx = GetJSContextFromCallStack();
|
|
if (cx) {
|
|
nsIScriptContext *scriptcx = nsWWJSUtils::GetDynamicScriptContext(cx);
|
|
if (scriptcx) {
|
|
baseWindow = do_QueryInterface(scriptcx->GetGlobalObject());
|
|
}
|
|
}
|
|
|
|
// failing that, build it relative to the parent window, if possible
|
|
if (!baseWindow)
|
|
baseWindow = aParent;
|
|
|
|
// failing that, use the given URL unmodified. It had better not be relative.
|
|
|
|
nsIURI *baseURI = nsnull;
|
|
|
|
// get baseWindow's document URI
|
|
if (baseWindow) {
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
baseWindow->GetDocument(getter_AddRefs(domDoc));
|
|
if (domDoc) {
|
|
nsCOMPtr<nsIDocument> doc;
|
|
doc = do_QueryInterface(domDoc);
|
|
if (doc) {
|
|
baseURI = doc->GetBaseURI();
|
|
}
|
|
}
|
|
}
|
|
|
|
// build and return the absolute URI
|
|
return NS_NewURI(aURI, aURL, baseURI);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
/* Check for an illegal name e.g. frame3.1
|
|
This just prints a warning message an continues; we open the window anyway,
|
|
(see bug 32898). */
|
|
void nsWindowWatcher::CheckWindowName(nsString& aName)
|
|
{
|
|
nsReadingIterator<PRUnichar> scan;
|
|
nsReadingIterator<PRUnichar> endScan;
|
|
|
|
aName.EndReading(endScan);
|
|
for (aName.BeginReading(scan); scan != endScan; ++scan)
|
|
if (!nsCRT::IsAsciiAlpha(*scan) && !nsCRT::IsAsciiDigit(*scan) &&
|
|
*scan != '_') {
|
|
|
|
// Don't use js_ReportError as this will cause the application
|
|
// to shut down (JS_ASSERT calls abort()) See bug 32898
|
|
nsCAutoString warn;
|
|
warn.AssignLiteral("Illegal character in window name ");
|
|
AppendUTF16toUTF8(aName, warn);
|
|
NS_WARNING(warn.get());
|
|
break;
|
|
}
|
|
}
|
|
#endif // DEBUG
|
|
|
|
#define NS_CALCULATE_CHROME_FLAG_FOR(feature, flag) \
|
|
prefBranch->GetBoolPref(feature, &forceEnable); \
|
|
if (forceEnable && !(isChrome && aHasChromeParent)) { \
|
|
chromeFlags |= flag; \
|
|
} else { \
|
|
chromeFlags |= WinHasOption(aFeatures, feature, \
|
|
0, &presenceFlag) \
|
|
? flag : 0; \
|
|
}
|
|
|
|
/**
|
|
* Calculate the chrome bitmask from a string list of features.
|
|
* @param aFeatures a string containing a list of named chrome features
|
|
* @param aNullFeatures true if aFeatures was a null pointer (which fact
|
|
* is lost by its conversion to a string in the caller)
|
|
* @param aDialog affects the assumptions made about unnamed features
|
|
* @return the chrome bitmask
|
|
*/
|
|
PRUint32 nsWindowWatcher::CalculateChromeFlags(const char *aFeatures,
|
|
PRBool aFeaturesSpecified,
|
|
PRBool aDialog,
|
|
PRBool aChromeURL,
|
|
PRBool aHasChromeParent)
|
|
{
|
|
if(!aFeaturesSpecified || !aFeatures) {
|
|
if(aDialog)
|
|
return nsIWebBrowserChrome::CHROME_ALL |
|
|
nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
|
|
nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
|
|
else
|
|
return nsIWebBrowserChrome::CHROME_ALL;
|
|
}
|
|
|
|
/* This function has become complicated since browser windows and
|
|
dialogs diverged. The difference is, browser windows assume all
|
|
chrome not explicitly mentioned is off, if the features string
|
|
is not null. Exceptions are some OS border chrome new with Mozilla.
|
|
Dialogs interpret a (mostly) empty features string to mean
|
|
"OS's choice," and also support an "all" flag explicitly disallowed
|
|
in the standards-compliant window.(normal)open. */
|
|
|
|
PRUint32 chromeFlags = 0;
|
|
PRBool presenceFlag = PR_FALSE;
|
|
|
|
chromeFlags = nsIWebBrowserChrome::CHROME_WINDOW_BORDERS;
|
|
if (aDialog && WinHasOption(aFeatures, "all", 0, &presenceFlag))
|
|
chromeFlags = nsIWebBrowserChrome::CHROME_ALL;
|
|
|
|
/* Next, allow explicitly named options to override the initial settings */
|
|
|
|
nsCOMPtr<nsIScriptSecurityManager>
|
|
securityManager(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
|
|
NS_ENSURE_TRUE(securityManager, NS_ERROR_FAILURE);
|
|
|
|
PRBool isChrome = PR_FALSE;
|
|
securityManager->SubjectPrincipalIsSystem(&isChrome);
|
|
|
|
nsCOMPtr<nsIPrefBranch> prefBranch;
|
|
nsresult rv;
|
|
nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, PR_TRUE);
|
|
|
|
rv = prefs->GetBranch("dom.disable_window_open_feature.", getter_AddRefs(prefBranch));
|
|
NS_ENSURE_SUCCESS(rv, PR_TRUE);
|
|
|
|
PRBool forceEnable = PR_FALSE;
|
|
|
|
NS_CALCULATE_CHROME_FLAG_FOR("titlebar",
|
|
nsIWebBrowserChrome::CHROME_TITLEBAR);
|
|
NS_CALCULATE_CHROME_FLAG_FOR("close",
|
|
nsIWebBrowserChrome::CHROME_WINDOW_CLOSE);
|
|
NS_CALCULATE_CHROME_FLAG_FOR("toolbar",
|
|
nsIWebBrowserChrome::CHROME_TOOLBAR);
|
|
NS_CALCULATE_CHROME_FLAG_FOR("location",
|
|
nsIWebBrowserChrome::CHROME_LOCATIONBAR);
|
|
NS_CALCULATE_CHROME_FLAG_FOR("directories",
|
|
nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
|
|
NS_CALCULATE_CHROME_FLAG_FOR("personalbar",
|
|
nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
|
|
NS_CALCULATE_CHROME_FLAG_FOR("status",
|
|
nsIWebBrowserChrome::CHROME_STATUSBAR);
|
|
NS_CALCULATE_CHROME_FLAG_FOR("menubar",
|
|
nsIWebBrowserChrome::CHROME_MENUBAR);
|
|
NS_CALCULATE_CHROME_FLAG_FOR("scrollbars",
|
|
nsIWebBrowserChrome::CHROME_SCROLLBARS);
|
|
NS_CALCULATE_CHROME_FLAG_FOR("resizable",
|
|
nsIWebBrowserChrome::CHROME_WINDOW_RESIZE);
|
|
NS_CALCULATE_CHROME_FLAG_FOR("minimizable",
|
|
nsIWebBrowserChrome::CHROME_WINDOW_MIN);
|
|
|
|
chromeFlags |= WinHasOption(aFeatures, "popup", 0, &presenceFlag)
|
|
? nsIWebBrowserChrome::CHROME_WINDOW_POPUP : 0;
|
|
|
|
/* OK.
|
|
Normal browser windows, in spite of a stated pattern of turning off
|
|
all chrome not mentioned explicitly, will want the new OS chrome (window
|
|
borders, titlebars, closebox) on, unless explicitly turned off.
|
|
Dialogs, on the other hand, take the absence of any explicit settings
|
|
to mean "OS' choice." */
|
|
|
|
// default titlebar and closebox to "on," if not mentioned at all
|
|
if (!PL_strcasestr(aFeatures, "titlebar"))
|
|
chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR;
|
|
if (!PL_strcasestr(aFeatures, "close"))
|
|
chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE;
|
|
|
|
if (aDialog && !presenceFlag)
|
|
chromeFlags = nsIWebBrowserChrome::CHROME_DEFAULT;
|
|
|
|
/* Finally, once all the above normal chrome has been divined, deal
|
|
with the features that are more operating hints than appearance
|
|
instructions. (Note modality implies dependence.) */
|
|
|
|
if (WinHasOption(aFeatures, "alwaysLowered", 0, nsnull) ||
|
|
WinHasOption(aFeatures, "z-lock", 0, nsnull))
|
|
chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_LOWERED;
|
|
else if (WinHasOption(aFeatures, "alwaysRaised", 0, nsnull))
|
|
chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_RAISED;
|
|
|
|
chromeFlags |= WinHasOption(aFeatures, "chrome", 0, nsnull) ?
|
|
nsIWebBrowserChrome::CHROME_OPENAS_CHROME : 0;
|
|
chromeFlags |= WinHasOption(aFeatures, "extrachrome", 0, nsnull) ?
|
|
nsIWebBrowserChrome::CHROME_EXTRA : 0;
|
|
chromeFlags |= WinHasOption(aFeatures, "centerscreen", 0, nsnull) ?
|
|
nsIWebBrowserChrome::CHROME_CENTER_SCREEN : 0;
|
|
chromeFlags |= WinHasOption(aFeatures, "dependent", 0, nsnull) ?
|
|
nsIWebBrowserChrome::CHROME_DEPENDENT : 0;
|
|
chromeFlags |= WinHasOption(aFeatures, "modal", 0, nsnull) ?
|
|
(nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT) : 0;
|
|
chromeFlags |= WinHasOption(aFeatures, "dialog", 0, nsnull) ?
|
|
nsIWebBrowserChrome::CHROME_OPENAS_DIALOG : 0;
|
|
|
|
/* and dialogs need to have the last word. assume dialogs are dialogs,
|
|
and opened as chrome, unless explicitly told otherwise. */
|
|
if (aDialog) {
|
|
if (!PL_strcasestr(aFeatures, "dialog"))
|
|
chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
|
|
if (!PL_strcasestr(aFeatures, "chrome"))
|
|
chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
|
|
}
|
|
|
|
/* missing
|
|
chromeFlags->copy_history
|
|
*/
|
|
|
|
// Check security state for use in determing window dimensions
|
|
PRBool enabled;
|
|
nsresult res =
|
|
securityManager->IsCapabilityEnabled("UniversalBrowserWrite", &enabled);
|
|
|
|
if (NS_FAILED(res) || !enabled || (isChrome && !aHasChromeParent)) {
|
|
// If priv check fails (or if we're called from chrome, but the
|
|
// parent is not a chrome window), set all elements to minimum
|
|
// reqs., else leave them alone.
|
|
chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR;
|
|
chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE;
|
|
chromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_LOWERED;
|
|
chromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_RAISED;
|
|
chromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_POPUP;
|
|
/* Untrusted script is allowed to pose modal windows with a chrome
|
|
scheme. This check could stand to be better. But it effectively
|
|
prevents untrusted script from opening modal windows in general
|
|
while still allowing alerts and the like. */
|
|
if (!aChromeURL)
|
|
chromeFlags &= ~(nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_OPENAS_CHROME);
|
|
}
|
|
|
|
return chromeFlags;
|
|
}
|
|
|
|
PRInt32
|
|
nsWindowWatcher::WinHasOption(const char *aOptions, const char *aName,
|
|
PRInt32 aDefault, PRBool *aPresenceFlag)
|
|
{
|
|
if (!aOptions)
|
|
return 0;
|
|
|
|
char *comma, *equal;
|
|
PRInt32 found = 0;
|
|
|
|
#ifdef DEBUG
|
|
nsCAutoString options(aOptions);
|
|
NS_ASSERTION(options.FindCharInSet(" \n\r\t") == kNotFound,
|
|
"There should be no whitespace in this string!");
|
|
#endif
|
|
|
|
while (PR_TRUE) {
|
|
comma = PL_strchr(aOptions, ',');
|
|
if (comma)
|
|
*comma = '\0';
|
|
equal = PL_strchr(aOptions, '=');
|
|
if (equal)
|
|
*equal = '\0';
|
|
if (nsCRT::strcasecmp(aOptions, aName) == 0) {
|
|
if (aPresenceFlag)
|
|
*aPresenceFlag = PR_TRUE;
|
|
if (equal)
|
|
if (*(equal + 1) == '*')
|
|
found = aDefault;
|
|
else if (nsCRT::strcasecmp(equal + 1, "yes") == 0)
|
|
found = 1;
|
|
else
|
|
found = atoi(equal + 1);
|
|
else
|
|
found = 1;
|
|
}
|
|
if (equal)
|
|
*equal = '=';
|
|
if (comma)
|
|
*comma = ',';
|
|
if (found || !comma)
|
|
break;
|
|
aOptions = comma + 1;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/* try to find an nsIDocShellTreeItem with the given name in any
|
|
known open window. a failure to find the item will not
|
|
necessarily return a failure method value. check aFoundItem.
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsWindowWatcher::FindItemWithName(const PRUnichar* aName,
|
|
nsIDocShellTreeItem* aRequestor,
|
|
nsIDocShellTreeItem* aOriginalRequestor,
|
|
nsIDocShellTreeItem** aFoundItem)
|
|
{
|
|
*aFoundItem = 0;
|
|
|
|
/* special cases */
|
|
if(!aName || !*aName)
|
|
return NS_OK;
|
|
|
|
nsDependentString name(aName);
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> windows;
|
|
GetWindowEnumerator(getter_AddRefs(windows));
|
|
if (!windows)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
PRBool more;
|
|
nsresult rv = NS_OK;
|
|
|
|
do {
|
|
windows->HasMoreElements(&more);
|
|
if (!more)
|
|
break;
|
|
nsCOMPtr<nsISupports> nextSupWindow;
|
|
windows->GetNext(getter_AddRefs(nextSupWindow));
|
|
nsCOMPtr<nsIDOMWindow> nextWindow(do_QueryInterface(nextSupWindow));
|
|
if (nextWindow) {
|
|
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
|
GetWindowTreeItem(nextWindow, getter_AddRefs(treeItem));
|
|
if (treeItem) {
|
|
// Get the root tree item of same type, since roots are the only
|
|
// things that call into the treeowner to look for named items.
|
|
nsCOMPtr<nsIDocShellTreeItem> root;
|
|
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
|
|
NS_ASSERTION(root, "Must have root tree item of same type");
|
|
// Make sure not to call back into aRequestor
|
|
if (root != aRequestor) {
|
|
// Get the tree owner so we can pass it in as the requestor so
|
|
// the child knows not to call back up, since we're walking
|
|
// all windows already.
|
|
nsCOMPtr<nsIDocShellTreeOwner> rootOwner;
|
|
// Note: if we have no aRequestor, then we want to also look for
|
|
// "special" window names, so pass a null requestor. This will mean
|
|
// that the treeitem calls back up to us, effectively (with a
|
|
// non-null aRequestor), so break the loop immediately after the
|
|
// call in that case.
|
|
if (aRequestor) {
|
|
root->GetTreeOwner(getter_AddRefs(rootOwner));
|
|
}
|
|
rv = root->FindItemWithName(aName, rootOwner, aOriginalRequestor,
|
|
aFoundItem);
|
|
if (NS_FAILED(rv) || *aFoundItem || !aRequestor)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} while(1);
|
|
|
|
return rv;
|
|
}
|
|
|
|
already_AddRefed<nsIDocShellTreeItem>
|
|
nsWindowWatcher::GetCallerTreeItem(nsIDocShellTreeItem* aParentItem)
|
|
{
|
|
nsCOMPtr<nsIJSContextStack> stack =
|
|
do_GetService(sJSStackContractID);
|
|
|
|
JSContext *cx = nsnull;
|
|
|
|
if (stack) {
|
|
stack->Peek(&cx);
|
|
}
|
|
|
|
nsIDocShellTreeItem* callerItem = nsnull;
|
|
|
|
if (cx) {
|
|
nsCOMPtr<nsIWebNavigation> callerWebNav =
|
|
do_GetInterface(nsWWJSUtils::GetDynamicScriptGlobal(cx));
|
|
|
|
if (callerWebNav) {
|
|
CallQueryInterface(callerWebNav, &callerItem);
|
|
}
|
|
}
|
|
|
|
if (!callerItem) {
|
|
NS_IF_ADDREF(callerItem = aParentItem);
|
|
}
|
|
|
|
return callerItem;
|
|
}
|
|
|
|
nsresult
|
|
nsWindowWatcher::SafeGetWindowByName(const nsAString& aName,
|
|
nsIDOMWindow* aCurrentWindow,
|
|
nsIDOMWindow** aResult)
|
|
{
|
|
*aResult = nsnull;
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> startItem;
|
|
GetWindowTreeItem(aCurrentWindow, getter_AddRefs(startItem));
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> callerItem = GetCallerTreeItem(startItem);
|
|
|
|
const nsAFlatString& flatName = PromiseFlatString(aName);
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> foundItem;
|
|
if (startItem) {
|
|
startItem->FindItemWithName(flatName.get(), nsnull, callerItem,
|
|
getter_AddRefs(foundItem));
|
|
}
|
|
else {
|
|
FindItemWithName(flatName.get(), nsnull, callerItem,
|
|
getter_AddRefs(foundItem));
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMWindow> foundWin = do_GetInterface(foundItem);
|
|
foundWin.swap(*aResult);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* Fetch the nsIDOMWindow corresponding to the given nsIDocShellTreeItem.
|
|
This forces the creation of a script context, if one has not already
|
|
been created. Note it also sets the window's opener to the parent,
|
|
if applicable -- because it's just convenient, that's all. null aParent
|
|
is acceptable. */
|
|
nsresult
|
|
nsWindowWatcher::ReadyOpenedDocShellItem(nsIDocShellTreeItem *aOpenedItem,
|
|
nsIDOMWindow *aParent,
|
|
PRBool aWindowIsNew,
|
|
nsIDOMWindow **aOpenedWindow)
|
|
{
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
*aOpenedWindow = 0;
|
|
nsCOMPtr<nsPIDOMWindow> piOpenedWindow(do_GetInterface(aOpenedItem));
|
|
if (piOpenedWindow) {
|
|
if (aParent) {
|
|
nsCOMPtr<nsIDOMWindowInternal> internalParent(do_QueryInterface(aParent));
|
|
piOpenedWindow->SetOpenerWindow(internalParent, aWindowIsNew); // damnit
|
|
}
|
|
rv = CallQueryInterface(piOpenedWindow, aOpenedWindow);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
void
|
|
nsWindowWatcher::CalcSizeSpec(const char* aFeatures, SizeSpec& aResult)
|
|
{
|
|
// Parse position spec, if any, from aFeatures
|
|
PRBool present;
|
|
PRInt32 temp;
|
|
|
|
present = PR_FALSE;
|
|
if ((temp = WinHasOption(aFeatures, "left", 0, &present)) || present)
|
|
aResult.mLeft = temp;
|
|
else if ((temp = WinHasOption(aFeatures, "screenX", 0, &present)) || present)
|
|
aResult.mLeft = temp;
|
|
aResult.mLeftSpecified = present;
|
|
|
|
present = PR_FALSE;
|
|
if ((temp = WinHasOption(aFeatures, "top", 0, &present)) || present)
|
|
aResult.mTop = temp;
|
|
else if ((temp = WinHasOption(aFeatures, "screenY", 0, &present)) || present)
|
|
aResult.mTop = temp;
|
|
aResult.mTopSpecified = present;
|
|
|
|
// Parse size spec, if any. Chrome size overrides content size.
|
|
if ((temp = WinHasOption(aFeatures, "outerWidth", PR_INT32_MIN, nsnull))) {
|
|
if (temp == PR_INT32_MIN) {
|
|
aResult.mUseDefaultWidth = PR_TRUE;
|
|
}
|
|
else {
|
|
aResult.mOuterWidth = temp;
|
|
}
|
|
aResult.mOuterWidthSpecified = PR_TRUE;
|
|
} else if ((temp = WinHasOption(aFeatures, "width", PR_INT32_MIN, nsnull)) ||
|
|
(temp = WinHasOption(aFeatures, "innerWidth", PR_INT32_MIN,
|
|
nsnull))) {
|
|
if (temp == PR_INT32_MIN) {
|
|
aResult.mUseDefaultWidth = PR_TRUE;
|
|
} else {
|
|
aResult.mInnerWidth = temp;
|
|
}
|
|
aResult.mInnerWidthSpecified = PR_TRUE;
|
|
}
|
|
|
|
if ((temp = WinHasOption(aFeatures, "outerHeight", PR_INT32_MIN, nsnull))) {
|
|
if (temp == PR_INT32_MIN) {
|
|
aResult.mUseDefaultHeight = PR_TRUE;
|
|
}
|
|
else {
|
|
aResult.mOuterHeight = temp;
|
|
}
|
|
aResult.mOuterHeightSpecified = PR_TRUE;
|
|
} else if ((temp = WinHasOption(aFeatures, "height", PR_INT32_MIN,
|
|
nsnull)) ||
|
|
(temp = WinHasOption(aFeatures, "innerHeight", PR_INT32_MIN,
|
|
nsnull))) {
|
|
if (temp == PR_INT32_MIN) {
|
|
aResult.mUseDefaultHeight = PR_TRUE;
|
|
} else {
|
|
aResult.mInnerHeight = temp;
|
|
}
|
|
aResult.mInnerHeightSpecified = PR_TRUE;
|
|
}
|
|
}
|
|
|
|
/* Size and position the new window according to aSizeSpec. This method
|
|
is assumed to be called after the window has already been given
|
|
a default position and size; thus its current position and size are
|
|
accurate defaults. The new window is made visible at method end.
|
|
*/
|
|
void
|
|
nsWindowWatcher::SizeOpenedDocShellItem(nsIDocShellTreeItem *aDocShellItem,
|
|
nsIDOMWindow *aParent,
|
|
const SizeSpec & aSizeSpec)
|
|
{
|
|
// position and size of window
|
|
PRInt32 left = 0,
|
|
top = 0,
|
|
width = 100,
|
|
height = 100;
|
|
// difference between chrome and content size
|
|
PRInt32 chromeWidth = 0,
|
|
chromeHeight = 0;
|
|
// whether the window size spec refers to chrome or content
|
|
PRBool sizeChromeWidth = PR_TRUE,
|
|
sizeChromeHeight = PR_TRUE;
|
|
|
|
// get various interfaces for aDocShellItem, used throughout this method
|
|
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
|
|
aDocShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
|
|
nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(treeOwner));
|
|
if (!treeOwnerAsWin) // we'll need this to actually size the docshell
|
|
return;
|
|
|
|
/* The current position and size will be unchanged if not specified
|
|
(and they fit entirely onscreen). Also, calculate the difference
|
|
between chrome and content sizes on aDocShellItem's window.
|
|
This latter point becomes important if chrome and content
|
|
specifications are mixed in aFeatures, and when bringing the window
|
|
back from too far off the right or bottom edges of the screen. */
|
|
|
|
treeOwnerAsWin->GetPositionAndSize(&left, &top, &width, &height);
|
|
{ // scope shellWindow why not
|
|
nsCOMPtr<nsIBaseWindow> shellWindow(do_QueryInterface(aDocShellItem));
|
|
if (shellWindow) {
|
|
PRInt32 cox, coy;
|
|
shellWindow->GetSize(&cox, &coy);
|
|
chromeWidth = width - cox;
|
|
chromeHeight = height - coy;
|
|
}
|
|
}
|
|
|
|
// Set up left/top
|
|
if (aSizeSpec.mLeftSpecified) {
|
|
left = aSizeSpec.mLeft;
|
|
}
|
|
|
|
if (aSizeSpec.mTopSpecified) {
|
|
top = aSizeSpec.mTop;
|
|
}
|
|
|
|
// Set up width
|
|
if (aSizeSpec.mOuterWidthSpecified) {
|
|
if (!aSizeSpec.mUseDefaultWidth) {
|
|
width = aSizeSpec.mOuterWidth;
|
|
} // Else specified to default; just use our existing width
|
|
}
|
|
else if (aSizeSpec.mInnerWidthSpecified) {
|
|
sizeChromeWidth = PR_FALSE;
|
|
if (aSizeSpec.mUseDefaultWidth) {
|
|
width = width - chromeWidth;
|
|
} else {
|
|
width = aSizeSpec.mInnerWidth;
|
|
}
|
|
}
|
|
|
|
// Set up height
|
|
if (aSizeSpec.mOuterHeightSpecified) {
|
|
if (!aSizeSpec.mUseDefaultHeight) {
|
|
height = aSizeSpec.mOuterHeight;
|
|
} // Else specified to default; just use our existing height
|
|
}
|
|
else if (aSizeSpec.mInnerHeightSpecified) {
|
|
sizeChromeHeight = PR_FALSE;
|
|
if (aSizeSpec.mUseDefaultHeight) {
|
|
height = height - chromeHeight;
|
|
} else {
|
|
height = aSizeSpec.mInnerHeight;
|
|
}
|
|
}
|
|
|
|
PRBool positionSpecified = aSizeSpec.PositionSpecified();
|
|
|
|
nsresult res;
|
|
PRBool enabled = PR_FALSE;
|
|
|
|
// Check security state for use in determing window dimensions
|
|
nsCOMPtr<nsIScriptSecurityManager>
|
|
securityManager(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
|
|
if (securityManager) {
|
|
res = securityManager->IsCapabilityEnabled("UniversalBrowserWrite",
|
|
&enabled);
|
|
if (NS_FAILED(res))
|
|
enabled = PR_FALSE;
|
|
else if (enabled && aParent) {
|
|
nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(aParent));
|
|
|
|
PRBool isChrome = PR_FALSE;
|
|
securityManager->SubjectPrincipalIsSystem(&isChrome);
|
|
|
|
// Only enable special priveleges for chrome when chrome calls
|
|
// open() on a chrome window
|
|
enabled = !(isChrome && chromeWin == nsnull);
|
|
}
|
|
}
|
|
|
|
if (!enabled) {
|
|
|
|
// Security check failed. Ensure all args meet minimum reqs.
|
|
|
|
PRInt32 oldTop = top,
|
|
oldLeft = left;
|
|
|
|
// We'll also need the screen dimensions
|
|
nsCOMPtr<nsIScreen> screen;
|
|
nsCOMPtr<nsIScreenManager> screenMgr(do_GetService(
|
|
"@mozilla.org/gfx/screenmanager;1"));
|
|
if (screenMgr)
|
|
screenMgr->ScreenForRect(left, top, width, height,
|
|
getter_AddRefs(screen));
|
|
if (screen) {
|
|
PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
|
|
PRInt32 winWidth = width + (sizeChromeWidth ? 0 : chromeWidth),
|
|
winHeight = height + (sizeChromeHeight ? 0 : chromeHeight);
|
|
|
|
screen->GetAvailRect(&screenLeft, &screenTop,
|
|
&screenWidth, &screenHeight);
|
|
|
|
if (aSizeSpec.SizeSpecified()) {
|
|
/* Unlike position, force size out-of-bounds check only if
|
|
size actually was specified. Otherwise, intrinsically sized
|
|
windows are broken. */
|
|
if (height < 100)
|
|
height = 100;
|
|
if (winHeight > screenHeight)
|
|
height = screenHeight - (sizeChromeHeight ? 0 : chromeHeight);
|
|
if (width < 100)
|
|
width = 100;
|
|
if (winWidth > screenWidth)
|
|
width = screenWidth - (sizeChromeWidth ? 0 : chromeWidth);
|
|
}
|
|
|
|
if (left+winWidth > screenLeft+screenWidth)
|
|
left = screenLeft+screenWidth - winWidth;
|
|
if (left < screenLeft)
|
|
left = screenLeft;
|
|
if (top+winHeight > screenTop+screenHeight)
|
|
top = screenTop+screenHeight - winHeight;
|
|
if (top < screenTop)
|
|
top = screenTop;
|
|
if (top != oldTop || left != oldLeft)
|
|
positionSpecified = PR_TRUE;
|
|
}
|
|
}
|
|
|
|
// size and position the window
|
|
|
|
if (positionSpecified)
|
|
treeOwnerAsWin->SetPosition(left, top);
|
|
if (aSizeSpec.SizeSpecified()) {
|
|
/* Prefer to trust the interfaces, which think in terms of pure
|
|
chrome or content sizes. If we have a mix, use the chrome size
|
|
adjusted by the chrome/content differences calculated earlier. */
|
|
if (!sizeChromeWidth && !sizeChromeHeight)
|
|
treeOwner->SizeShellTo(aDocShellItem, width, height);
|
|
else {
|
|
if (!sizeChromeWidth)
|
|
width += chromeWidth;
|
|
if (!sizeChromeHeight)
|
|
height += chromeHeight;
|
|
treeOwnerAsWin->SetSize(width, height, PR_FALSE);
|
|
}
|
|
}
|
|
treeOwnerAsWin->SetVisibility(PR_TRUE);
|
|
}
|
|
|
|
// attach the given array of JS values to the given window, as a property array
|
|
// named "arguments"
|
|
nsresult
|
|
nsWindowWatcher::AttachArguments(nsIDOMWindow *aWindow,
|
|
PRUint32 argc, jsval *argv)
|
|
{
|
|
if (argc == 0)
|
|
return NS_OK;
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(do_QueryInterface(aWindow));
|
|
NS_ENSURE_TRUE(scriptGlobal, NS_ERROR_UNEXPECTED);
|
|
|
|
// Just ask the global to attach the args for us
|
|
return scriptGlobal->SetNewArguments(argc, NS_STATIC_CAST(void*, argv));
|
|
}
|
|
|
|
nsresult
|
|
nsWindowWatcher::ConvertSupportsTojsvals(nsIDOMWindow *aWindow,
|
|
nsISupports *aArgs,
|
|
PRUint32 *aArgc, jsval **aArgv,
|
|
JSContext **aUsedContext,
|
|
void **aMarkp,
|
|
nsIScriptContext **aScriptContext)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
*aArgv = nsnull;
|
|
*aArgc = 0;
|
|
|
|
// copy the elements in aArgsArray into the JS array
|
|
// window.arguments in the new window
|
|
|
|
if (!aArgs)
|
|
return NS_OK;
|
|
|
|
PRUint32 argCtr, argCount;
|
|
nsCOMPtr<nsISupportsArray> argsArray(do_QueryInterface(aArgs));
|
|
|
|
if (argsArray) {
|
|
argsArray->Count(&argCount);
|
|
if (argCount == 0)
|
|
return NS_OK;
|
|
} else
|
|
argCount = 1; // the nsISupports which is not an array
|
|
|
|
JSContext *cx;
|
|
JSContextAutoPopper contextGuard;
|
|
|
|
cx = GetJSContextFromWindow(aWindow);
|
|
if (cx) {
|
|
// Our caller needs to hold a strong ref to keep this context alive.
|
|
*aScriptContext = GetScriptContextFromJSContext(cx);
|
|
NS_ASSERTION(*aScriptContext,
|
|
"The window's context doesn't have a script context?");
|
|
NS_ADDREF(*aScriptContext);
|
|
} else {
|
|
*aScriptContext = nsnull;
|
|
}
|
|
if (!cx)
|
|
cx = GetJSContextFromCallStack();
|
|
if (!cx) {
|
|
rv = contextGuard.Push();
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
cx = contextGuard.get();
|
|
}
|
|
|
|
jsval *argv = js_AllocStack(cx, argCount, aMarkp);
|
|
NS_ENSURE_TRUE(argv, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
if (argsArray)
|
|
for (argCtr = 0; argCtr < argCount && NS_SUCCEEDED(rv); argCtr++) {
|
|
nsCOMPtr<nsISupports> s(dont_AddRef(argsArray->ElementAt(argCtr)));
|
|
rv = AddSupportsTojsvals(s, cx, argv + argCtr);
|
|
}
|
|
else
|
|
rv = AddSupportsTojsvals(aArgs, cx, argv);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
js_FreeStack(cx, *aMarkp);
|
|
|
|
return rv;
|
|
}
|
|
|
|
*aUsedContext = cx;
|
|
*aArgv = argv;
|
|
*aArgc = argCount;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsWindowWatcher::AddInterfaceTojsvals(nsISupports *aArg,
|
|
JSContext *cx,
|
|
jsval *aArgv)
|
|
{
|
|
nsresult rv;
|
|
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
|
|
rv = xpc->WrapNative(cx, ::JS_GetGlobalObject(cx), aArg,
|
|
NS_GET_IID(nsISupports), getter_AddRefs(wrapper));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
JSObject *obj;
|
|
rv = wrapper->GetJSObject(&obj);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
*aArgv = OBJECT_TO_JSVAL(obj);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsWindowWatcher::AddSupportsTojsvals(nsISupports *aArg,
|
|
JSContext *cx, jsval *aArgv)
|
|
{
|
|
if (!aArg) {
|
|
*aArgv = JSVAL_NULL;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCOMPtr<nsISupportsPrimitive> argPrimitive(do_QueryInterface(aArg));
|
|
if (!argPrimitive)
|
|
return AddInterfaceTojsvals(aArg, cx, aArgv);
|
|
|
|
PRUint16 type;
|
|
argPrimitive->GetType(&type);
|
|
|
|
switch(type) {
|
|
case nsISupportsPrimitive::TYPE_CSTRING : {
|
|
nsCOMPtr<nsISupportsCString> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
nsCAutoString data;
|
|
|
|
p->GetData(data);
|
|
|
|
|
|
JSString *str = ::JS_NewStringCopyN(cx, data.get(), data.Length());
|
|
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
*aArgv = STRING_TO_JSVAL(str);
|
|
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_STRING : {
|
|
nsCOMPtr<nsISupportsString> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
nsAutoString data;
|
|
|
|
p->GetData(data);
|
|
|
|
// cast is probably safe since wchar_t and jschar are expected
|
|
// to be equivalent; both unsigned 16-bit entities
|
|
JSString *str =
|
|
::JS_NewUCStringCopyN(cx,
|
|
NS_REINTERPRET_CAST(const jschar *,data.get()),
|
|
data.Length());
|
|
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
*aArgv = STRING_TO_JSVAL(str);
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_PRBOOL : {
|
|
nsCOMPtr<nsISupportsPRBool> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
PRBool data;
|
|
|
|
p->GetData(&data);
|
|
|
|
*aArgv = BOOLEAN_TO_JSVAL(data);
|
|
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_PRUINT8 : {
|
|
nsCOMPtr<nsISupportsPRUint8> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
PRUint8 data;
|
|
|
|
p->GetData(&data);
|
|
|
|
*aArgv = INT_TO_JSVAL(data);
|
|
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_PRUINT16 : {
|
|
nsCOMPtr<nsISupportsPRUint16> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
PRUint16 data;
|
|
|
|
p->GetData(&data);
|
|
|
|
*aArgv = INT_TO_JSVAL(data);
|
|
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_PRUINT32 : {
|
|
nsCOMPtr<nsISupportsPRUint32> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
PRUint32 data;
|
|
|
|
p->GetData(&data);
|
|
|
|
*aArgv = INT_TO_JSVAL(data);
|
|
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_CHAR : {
|
|
nsCOMPtr<nsISupportsChar> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
char data;
|
|
|
|
p->GetData(&data);
|
|
|
|
JSString *str = ::JS_NewStringCopyN(cx, &data, 1);
|
|
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
*aArgv = STRING_TO_JSVAL(str);
|
|
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_PRINT16 : {
|
|
nsCOMPtr<nsISupportsPRInt16> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
PRInt16 data;
|
|
|
|
p->GetData(&data);
|
|
|
|
*aArgv = INT_TO_JSVAL(data);
|
|
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_PRINT32 : {
|
|
nsCOMPtr<nsISupportsPRInt32> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
PRInt32 data;
|
|
|
|
p->GetData(&data);
|
|
|
|
*aArgv = INT_TO_JSVAL(data);
|
|
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_FLOAT : {
|
|
nsCOMPtr<nsISupportsFloat> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
float data;
|
|
|
|
p->GetData(&data);
|
|
|
|
jsdouble *d = ::JS_NewDouble(cx, data);
|
|
|
|
*aArgv = DOUBLE_TO_JSVAL(d);
|
|
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_DOUBLE : {
|
|
nsCOMPtr<nsISupportsDouble> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
double data;
|
|
|
|
p->GetData(&data);
|
|
|
|
jsdouble *d = ::JS_NewDouble(cx, data);
|
|
|
|
*aArgv = DOUBLE_TO_JSVAL(d);
|
|
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_INTERFACE_POINTER : {
|
|
nsCOMPtr<nsISupportsInterfacePointer> p(do_QueryInterface(argPrimitive));
|
|
NS_ENSURE_TRUE(p, NS_ERROR_UNEXPECTED);
|
|
|
|
nsCOMPtr<nsISupports> data;
|
|
nsIID *iid = nsnull;
|
|
|
|
p->GetData(getter_AddRefs(data));
|
|
p->GetDataIID(&iid);
|
|
NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
|
|
|
|
AutoFree iidGuard(iid); // Free iid upon destruction.
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
|
|
rv = xpc->WrapNative(cx, ::JS_GetGlobalObject(cx), data,
|
|
*iid, getter_AddRefs(wrapper));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
JSObject *obj;
|
|
rv = wrapper->GetJSObject(&obj);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
*aArgv = OBJECT_TO_JSVAL(obj);
|
|
|
|
break;
|
|
}
|
|
case nsISupportsPrimitive::TYPE_ID :
|
|
case nsISupportsPrimitive::TYPE_PRUINT64 :
|
|
case nsISupportsPrimitive::TYPE_PRINT64 :
|
|
case nsISupportsPrimitive::TYPE_PRTIME :
|
|
case nsISupportsPrimitive::TYPE_VOID : {
|
|
NS_WARNING("Unsupported primitive type used");
|
|
*aArgv = JSVAL_NULL;
|
|
break;
|
|
}
|
|
default : {
|
|
NS_WARNING("Unknown primitive type used");
|
|
*aArgv = JSVAL_NULL;
|
|
break;
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsWindowWatcher::GetWindowTreeItem(nsIDOMWindow *inWindow,
|
|
nsIDocShellTreeItem **outTreeItem)
|
|
{
|
|
*outTreeItem = 0;
|
|
|
|
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(inWindow));
|
|
if (window) {
|
|
nsIDocShell *docshell = window->GetDocShell();
|
|
if (docshell)
|
|
CallQueryInterface(docshell, outTreeItem);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsWindowWatcher::GetWindowTreeOwner(nsIDOMWindow *inWindow,
|
|
nsIDocShellTreeOwner **outTreeOwner)
|
|
{
|
|
*outTreeOwner = 0;
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
|
GetWindowTreeItem(inWindow, getter_AddRefs(treeItem));
|
|
if (treeItem)
|
|
treeItem->GetTreeOwner(outTreeOwner);
|
|
}
|
|
|
|
JSContext *
|
|
nsWindowWatcher::GetJSContextFromCallStack()
|
|
{
|
|
JSContext *cx = 0;
|
|
|
|
nsCOMPtr<nsIThreadJSContextStack> cxStack(do_GetService(sJSStackContractID));
|
|
if (cxStack)
|
|
cxStack->Peek(&cx);
|
|
|
|
return cx;
|
|
}
|
|
|
|
JSContext *
|
|
nsWindowWatcher::GetJSContextFromWindow(nsIDOMWindow *aWindow)
|
|
{
|
|
JSContext *cx = 0;
|
|
|
|
if (aWindow) {
|
|
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aWindow));
|
|
if (sgo) {
|
|
nsIScriptContext *scx = sgo->GetContext();
|
|
if (scx)
|
|
cx = (JSContext *) scx->GetNativeContext();
|
|
}
|
|
/* (off-topic note:) the nsIScriptContext can be retrieved by
|
|
nsCOMPtr<nsIScriptContext> scx;
|
|
nsJSUtils::GetDynamicScriptContext(cx, getter_AddRefs(scx));
|
|
*/
|
|
}
|
|
|
|
return cx;
|
|
}
|