зеркало из https://github.com/mozilla/pjs.git
Move the "force into tab" code out of Gecko and allow embeddors to do the same
sort of thing. Bug 323810, r=bsmedberg, sr=jst
This commit is contained in:
Родитель
e9a0b35561
Коммит
2dbdd7da0d
|
@ -62,7 +62,6 @@
|
|||
#include "nsIPresShell.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIBrowserDOMWindow.h"
|
||||
#include "nsIDOMCSSStyleDeclaration.h"
|
||||
#include "nsIDOMViewCSS.h"
|
||||
#include "nsIXBLService.h"
|
||||
|
@ -221,17 +220,10 @@ nsXMLElement::MaybeTriggerAutoLink(nsIDocShell *aShell)
|
|||
|
||||
// XXX Should probably do this using atoms
|
||||
if (value.EqualsLiteral("new")) {
|
||||
if (nsContentUtils::GetBoolPref("dom.disable_open_during_load")) {
|
||||
// disabling open during load
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (nsContentUtils::GetIntPref("browser.link.open_newwindow",
|
||||
nsIBrowserDOMWindow::OPEN_NEWWINDOW) ==
|
||||
nsIBrowserDOMWindow::OPEN_NEWWINDOW) {
|
||||
verb = eLinkVerb_New;
|
||||
}
|
||||
// We should just act like an HTML link with target="_blank" and if
|
||||
// someone diverts or blocks those, that's fine with us. We don't
|
||||
// care.
|
||||
verb = eLinkVerb_New;
|
||||
} else if (value.EqualsLiteral("replace")) {
|
||||
// We want to actually stop processing the current document now.
|
||||
// We do this by returning the correct value so that the one
|
||||
|
@ -307,11 +299,7 @@ nsXMLElement::HandleDOMEvent(nsPresContext* aPresContext,
|
|||
|
||||
// XXX Should probably do this using atoms
|
||||
if (show.EqualsLiteral("new")) {
|
||||
if (nsContentUtils::GetIntPref("browser.link.open_newwindow",
|
||||
nsIBrowserDOMWindow::OPEN_NEWWINDOW) ==
|
||||
nsIBrowserDOMWindow::OPEN_NEWWINDOW) {
|
||||
verb = eLinkVerb_New;
|
||||
}
|
||||
verb = eLinkVerb_New;
|
||||
} else if (show.EqualsLiteral("replace")) {
|
||||
verb = eLinkVerb_Replace;
|
||||
} else if (show.EqualsLiteral("embed")) {
|
||||
|
|
|
@ -1097,160 +1097,6 @@ nsDocShell::ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
|
|||
documentDomainSet);
|
||||
}
|
||||
|
||||
nsresult nsDocShell::FindTarget(const PRUnichar *aWindowTarget,
|
||||
PRBool *aIsNewWindow,
|
||||
nsIDocShell **aResult)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
*aResult = nsnull;
|
||||
*aIsNewWindow = PR_FALSE;
|
||||
|
||||
// Try to locate the target window...
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
||||
FindItemWithName(aWindowTarget, nsnull, this, getter_AddRefs(treeItem));
|
||||
|
||||
PRInt32 linkPref = nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW;
|
||||
// XXXbz this should live inside FindItemWithName, I think...
|
||||
if (!treeItem) {
|
||||
mPrefs->GetIntPref("browser.link.open_newwindow", &linkPref);
|
||||
if (linkPref == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
|
||||
// force new window to go to _top
|
||||
FindItemWithName(NS_LITERAL_STRING("_top").get(),
|
||||
nsnull, this, getter_AddRefs(treeItem));
|
||||
NS_ASSERTION(treeItem,
|
||||
"We better get a treeitem when asking for '_top' "
|
||||
"with |this| as the original requestor");
|
||||
}
|
||||
}
|
||||
|
||||
if (!treeItem)
|
||||
{
|
||||
/// XXXbz this should really happen in FindItemWithName too, I think...
|
||||
nsCOMPtr<nsIDOMWindow> newWindow;
|
||||
nsCOMPtr<nsIDOMWindowInternal> parentWindow;
|
||||
|
||||
// This DocShell is the parent window
|
||||
parentWindow = do_GetInterface(GetAsSupports(this));
|
||||
if (!parentWindow) {
|
||||
NS_ASSERTION(0, "Can't get nsIDOMWindowInternal from nsDocShell!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (linkPref == nsIBrowserDOMWindow::OPEN_NEWTAB) {
|
||||
|
||||
// is it a popup?
|
||||
|
||||
PRBool allowTab = PR_TRUE;
|
||||
nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(mScriptGlobal);
|
||||
if (pWindow) {
|
||||
// skip the window search-by-name of GetOpenAllow
|
||||
// by using _self. we don't care about that at this point.
|
||||
OpenAllowValue allow = pWindow->GetOpenAllow(
|
||||
NS_LITERAL_STRING("_self"));
|
||||
if (allow == allowNot || allow == allowSelf)
|
||||
allowTab = PR_FALSE;
|
||||
}
|
||||
|
||||
// try to get our tab-opening interface
|
||||
|
||||
if (allowTab) {
|
||||
nsCOMPtr<nsIBrowserDOMWindow> bwin;
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootItem;
|
||||
GetRootTreeItem(getter_AddRefs(rootItem));
|
||||
nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
|
||||
nsCOMPtr<nsIDOMChromeWindow> chromeWin(
|
||||
do_QueryInterface(rootWin));
|
||||
if (chromeWin)
|
||||
chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
|
||||
|
||||
// open a new tab
|
||||
if (bwin) {
|
||||
rv = bwin->OpenURI(0, 0, nsIBrowserDOMWindow::OPEN_NEWTAB,
|
||||
nsIBrowserDOMWindow::OPEN_NEW,
|
||||
getter_AddRefs(newWindow));
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> newPIWindow =
|
||||
do_GetInterface(newWindow);
|
||||
if (newPIWindow)
|
||||
newPIWindow->SetOpenerWindow(parentWindow);
|
||||
}
|
||||
}
|
||||
// else fall through to the normal Open method, from which
|
||||
// the appropriate measures will be taken when the popup fails
|
||||
}
|
||||
|
||||
if (!newWindow) {
|
||||
nsAutoString name(aWindowTarget);
|
||||
// XXXbz this should be handled somewhere else.... and in fact, it
|
||||
// may be safe to just pass those through here. Check.
|
||||
if (name.LowerCaseEqualsLiteral("_blank") ||
|
||||
name.LowerCaseEqualsLiteral("_new")) {
|
||||
name.Truncate();
|
||||
}
|
||||
rv = parentWindow->Open(EmptyString(), // URL to load
|
||||
name, // Window name
|
||||
EmptyString(), // Window features
|
||||
getter_AddRefs(newWindow));
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
{
|
||||
// Get the DocShell from the new window...
|
||||
nsCOMPtr<nsPIDOMWindow> piwindow(do_QueryInterface(newWindow));
|
||||
|
||||
// *aResult will be AddRef()'ed below...
|
||||
*aResult = piwindow->GetDocShell();
|
||||
}
|
||||
|
||||
// If all went well, indicate that a new window has been created.
|
||||
if (*aResult) {
|
||||
NS_ADDREF(*aResult);
|
||||
|
||||
*aIsNewWindow = PR_TRUE;
|
||||
|
||||
// if we just open a new window for this link, charset from current docshell
|
||||
// should be kept, as what we did in js openNewWindowWith(url)
|
||||
nsCOMPtr<nsIMarkupDocumentViewer> muCV, target_muCV;
|
||||
nsCOMPtr<nsIContentViewer> cv, target_cv;
|
||||
this->GetContentViewer(getter_AddRefs(cv));
|
||||
(*aResult)->GetContentViewer(getter_AddRefs(target_cv));
|
||||
if (cv && target_cv) {
|
||||
muCV = do_QueryInterface(cv);
|
||||
target_muCV = do_QueryInterface(target_cv);
|
||||
if (muCV && target_muCV) {
|
||||
nsCAutoString defaultCharset;
|
||||
nsCAutoString prevDocCharset;
|
||||
rv = muCV->GetDefaultCharacterSet(defaultCharset);
|
||||
if(NS_SUCCEEDED(rv)) {
|
||||
target_muCV->SetDefaultCharacterSet(defaultCharset);
|
||||
}
|
||||
rv = muCV->GetPrevDocCharacterSet(prevDocCharset);
|
||||
if(NS_SUCCEEDED(rv)) {
|
||||
target_muCV->SetPrevDocCharacterSet(prevDocCharset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (treeItem)
|
||||
{
|
||||
NS_ASSERTION(!*aResult, "aResult should be null if treeItem is set!");
|
||||
treeItem->QueryInterface(NS_GET_IID(nsIDocShell), (void **)aResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_IF_ADDREF(*aResult);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetEldestPresContext(nsPresContext** aPresContext)
|
||||
{
|
||||
|
@ -6336,68 +6182,38 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
// load to it...
|
||||
//
|
||||
if (aWindowTarget && *aWindowTarget) {
|
||||
PRBool bIsNewWindow;
|
||||
nsCOMPtr<nsIDocShell> targetDocShell;
|
||||
nsAutoString name(aWindowTarget);
|
||||
|
||||
//
|
||||
// This is a hack to prevent top-level windows from ever being
|
||||
// created. It really doesn't belong here, but until there is a
|
||||
// way for embeddors to get involved in window targeting, this is
|
||||
// as good a place as any...
|
||||
// XXXbz no, it's not.... fixme!!!!
|
||||
//
|
||||
PRInt32 linkPref = nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW;
|
||||
mPrefs->GetIntPref("browser.link.open_newwindow", &linkPref);
|
||||
if (linkPref == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
|
||||
PRBool bIsChromeOrResource = PR_FALSE;
|
||||
if (mCurrentURI)
|
||||
mCurrentURI->SchemeIs("chrome", &bIsChromeOrResource);
|
||||
if (!bIsChromeOrResource) {
|
||||
aURI->SchemeIs("chrome", &bIsChromeOrResource);
|
||||
if (!bIsChromeOrResource) {
|
||||
aURI->SchemeIs("resource", &bIsChromeOrResource);
|
||||
}
|
||||
}
|
||||
if (!bIsChromeOrResource) {
|
||||
if (name.LowerCaseEqualsLiteral("_blank") ||
|
||||
name.LowerCaseEqualsLiteral("_new")) {
|
||||
name.AssignLiteral("_top");
|
||||
}
|
||||
// _main is an IE target which should be case-insensitive but isn't
|
||||
// see bug 217886 for details
|
||||
else if (!name.LowerCaseEqualsLiteral("_parent") &&
|
||||
!name.LowerCaseEqualsLiteral("_self") &&
|
||||
!name.LowerCaseEqualsLiteral("_content") &&
|
||||
!name.EqualsLiteral("_main")) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> targetTreeItem;
|
||||
FindItemWithName(name.get(),
|
||||
nsnull,
|
||||
this,
|
||||
getter_AddRefs(targetTreeItem));
|
||||
if (targetTreeItem)
|
||||
targetDocShell = do_QueryInterface(targetTreeItem);
|
||||
else
|
||||
name.AssignLiteral("_top");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Locate the target DocShell.
|
||||
// This may involve creating a new toplevel window - if necessary.
|
||||
//
|
||||
if (!targetDocShell) {
|
||||
rv = FindTarget(name.get(), &bIsNewWindow,
|
||||
getter_AddRefs(targetDocShell));
|
||||
}
|
||||
nsCOMPtr<nsIDocShellTreeItem> targetItem;
|
||||
FindItemWithName(aWindowTarget, nsnull, this,
|
||||
getter_AddRefs(targetItem));
|
||||
|
||||
NS_ASSERTION(targetDocShell, "No Target docshell could be found!");
|
||||
nsCOMPtr<nsIDocShell> targetDocShell = do_QueryInterface(targetItem);
|
||||
|
||||
PRBool isNewWindow = PR_FALSE;
|
||||
if (!targetDocShell) {
|
||||
nsCOMPtr<nsIDOMWindowInternal> win =
|
||||
do_GetInterface(GetAsSupports(this));
|
||||
NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
isNewWindow = PR_TRUE;
|
||||
nsDependentString name(aWindowTarget);
|
||||
nsCOMPtr<nsIDOMWindow> newWin;
|
||||
rv = win->Open(EmptyString(), // URL to load
|
||||
name, // window name
|
||||
EmptyString(), // Features
|
||||
getter_AddRefs(newWin));
|
||||
|
||||
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
|
||||
targetDocShell = do_QueryInterface(webNav);
|
||||
}
|
||||
|
||||
//
|
||||
// Transfer the load to the target DocShell... Pass nsnull as the
|
||||
// window target name from to prevent recursive retargeting!
|
||||
//
|
||||
if (targetDocShell) {
|
||||
if (NS_SUCCEEDED(rv) && targetDocShell) {
|
||||
rv = targetDocShell->InternalLoad(aURI,
|
||||
aReferrer,
|
||||
owner,
|
||||
|
@ -6412,7 +6228,8 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
aDocShell,
|
||||
aRequest);
|
||||
if (rv == NS_ERROR_NO_CONTENT) {
|
||||
if (bIsNewWindow) {
|
||||
// XXXbz except we never reach this code!
|
||||
if (isNewWindow) {
|
||||
//
|
||||
// At this point, a new window has been created, but the
|
||||
// URI did not have any data associated with it...
|
||||
|
@ -6420,18 +6237,10 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
// So, the best we can do, is to tear down the new window
|
||||
// that was just created!
|
||||
//
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
||||
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
|
||||
|
||||
treeItem = do_QueryInterface(targetDocShell);
|
||||
treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
|
||||
if (treeOwner) {
|
||||
nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
|
||||
|
||||
treeOwnerAsWin = do_QueryInterface(treeOwner);
|
||||
if (treeOwnerAsWin) {
|
||||
treeOwnerAsWin->Destroy();
|
||||
}
|
||||
nsCOMPtr<nsIDOMWindowInternal> domWin =
|
||||
do_GetInterface(targetDocShell);
|
||||
if (domWin) {
|
||||
domWin->Close();
|
||||
}
|
||||
}
|
||||
//
|
||||
|
@ -6442,12 +6251,16 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
//
|
||||
rv = NS_OK;
|
||||
}
|
||||
else if (bIsNewWindow) {
|
||||
else if (isNewWindow) {
|
||||
// XXX: Once new windows are created hidden, the new
|
||||
// window will need to be made visible... For now,
|
||||
// do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
// Else we ran out of memory, or were a popup and got blocked,
|
||||
// or something.
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
@ -439,10 +439,6 @@ protected:
|
|||
return t_sec;
|
||||
}
|
||||
|
||||
nsresult FindTarget(const PRUnichar *aTargetName,
|
||||
PRBool *aIsNewWindow,
|
||||
nsIDocShell **aResult);
|
||||
|
||||
PRBool IsFrame();
|
||||
|
||||
//
|
||||
|
|
|
@ -768,6 +768,7 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent,
|
|||
nsresult rv;
|
||||
switch(aVerb) {
|
||||
case eLinkVerb_New:
|
||||
NS_ASSERTION(target.IsEmpty(), "Losing window name information");
|
||||
target.AssignLiteral("_blank");
|
||||
// Fall into replace case
|
||||
case eLinkVerb_Undefined:
|
||||
|
|
|
@ -66,12 +66,11 @@ enum PopupControlState {
|
|||
enum OpenAllowValue {
|
||||
allowNot = 0, // the window opening is denied
|
||||
allowNoAbuse, // allowed: not a popup
|
||||
allowSelf, // allowed: it's the same window (_self, _top, et.al.)
|
||||
allowExtant, // allowed: an already open window
|
||||
allowWhitelisted // allowed: it's whitelisted or popup blocking is disabled
|
||||
};
|
||||
|
||||
class nsIDocShell;
|
||||
class nsIDocShellTreeItem;
|
||||
class nsIFocusController;
|
||||
class nsIDocument;
|
||||
struct nsTimeout;
|
||||
|
@ -258,6 +257,11 @@ public:
|
|||
PRBool aForce) const = 0;
|
||||
virtual void PopPopupControlState(PopupControlState state) const = 0;
|
||||
virtual PopupControlState GetPopupControlState() const = 0;
|
||||
|
||||
// GetOpenAllow must not be called on a window that no longer has a docshell
|
||||
// This function is deprecated. It will assume that there is no existing
|
||||
// window with name aName for purposes of its answer. Expect this function
|
||||
// to get removed soon!
|
||||
virtual OpenAllowValue GetOpenAllow(const nsAString &aName) = 0;
|
||||
|
||||
// Returns an object containing the window's state. This also suspends
|
||||
|
|
|
@ -44,26 +44,50 @@ interface nsIURI;
|
|||
|
||||
/**
|
||||
* The C++ source has access to the browser script source through
|
||||
* nsIBrowserWindow. It is intended to be attached to the chrome
|
||||
* DOMWindow of a browser window. A DOMWindow that does not happen to
|
||||
* be a browser chrome window will simply have no access to any such
|
||||
* nsIBrowserDOMWindow. It is intended to be attached to the chrome DOMWindow
|
||||
* of a toplevel browser window (a XUL window). A DOMWindow that does not
|
||||
* happen to be a browser chrome window will simply have no access to any such
|
||||
* interface.
|
||||
*/
|
||||
interface nsIBrowserDOMWindow : nsISupports
|
||||
{
|
||||
/**
|
||||
* values for openURI's aWhere parameter
|
||||
* Values for openURI's aWhere parameter.
|
||||
*/
|
||||
/**
|
||||
* Do whatever the default is based on application state, user preferences,
|
||||
* and the value of the aContext parameter to openURI.
|
||||
*/
|
||||
const short OPEN_DEFAULTWINDOW = 0;
|
||||
/**
|
||||
* Open in the "current window". If aOpener is provided, this should be the
|
||||
* top window in aOpener's window hierarchy, but exact behavior is
|
||||
* application-dependent. If aOpener is not provided, it's up to the
|
||||
* application to decide what constitutes a "current window".
|
||||
*/
|
||||
const short OPEN_CURRENTWINDOW = 1;
|
||||
/**
|
||||
* Open in a new window.
|
||||
*/
|
||||
const short OPEN_NEWWINDOW = 2;
|
||||
/**
|
||||
* Open in a new content tab in the toplevel browser window corresponding to
|
||||
* this nsIBrowserDOMWindow.
|
||||
*/
|
||||
const short OPEN_NEWTAB = 3;
|
||||
|
||||
/**
|
||||
* values for openURI's aContext parameter
|
||||
* Values for openURI's aContext parameter. These affect the behavior of
|
||||
* OPEN_DEFAULTWINDOW.
|
||||
*/
|
||||
const short OPEN_EXTERNAL = 1; // external link
|
||||
const short OPEN_NEW = 2; // internal open new window
|
||||
/**
|
||||
* external link (load request from another application, xremote, etc).
|
||||
*/
|
||||
const short OPEN_EXTERNAL = 1;
|
||||
/**
|
||||
* internal open new window
|
||||
*/
|
||||
const short OPEN_NEW = 2;
|
||||
|
||||
/**
|
||||
* Load a URI
|
||||
|
@ -80,7 +104,7 @@ interface nsIBrowserDOMWindow : nsISupports
|
|||
/**
|
||||
* @param aWindow the window to test.
|
||||
* @return whether the window is the main content window for any
|
||||
* currently open tab.
|
||||
* currently open tab in this toplevel browser window.
|
||||
*/
|
||||
boolean isTabContentWindow(in nsIDOMWindow aWindow);
|
||||
};
|
||||
|
|
|
@ -77,8 +77,16 @@ interface nsIDOMJSWindow : nsISupports
|
|||
*/
|
||||
DOMString prompt();
|
||||
|
||||
// This is the script version of nsIDOMWindowInternal::open() that
|
||||
// takes 3 optional arguments
|
||||
/**
|
||||
* These are the scriptable versions of nsIDOMWindowInternal::open() and
|
||||
* nsIDOMWindowInternal::openDialog() that take 3 optional arguments. Unlike
|
||||
* the nsIDOMWindowInternal methods, these methods assume that they are
|
||||
* called from JavaScript and hence will look on the JS context stack to
|
||||
* determine the caller and hence correct security context for doing their
|
||||
* search for an existing named window. Also, these methods will set the
|
||||
* default charset on the newly opened window based on the current document
|
||||
* charset in the caller.
|
||||
*/
|
||||
nsIDOMWindow open();
|
||||
nsIDOMWindow openDialog();
|
||||
|
||||
|
|
|
@ -150,6 +150,13 @@ interface nsIDOMWindowInternal : nsIDOMWindow2
|
|||
//[noscript] long setInterval(/* in function,
|
||||
// in unsigned long timeout */);
|
||||
|
||||
/**
|
||||
* Open a new window with this one as the parent. This method will
|
||||
* NOT examine the JS stack for purposes of determining a caller.
|
||||
* This window will be used for security checks during the search by
|
||||
* name and the default character set on the newly opened window
|
||||
* will just be the default character set of this window.
|
||||
*/
|
||||
[noscript] nsIDOMWindow open(in DOMString url, in DOMString name,
|
||||
in DOMString options);
|
||||
// This method works like open except that aExtraArgument gets
|
||||
|
|
|
@ -435,7 +435,7 @@ nsGlobalWindow::CleanUp()
|
|||
}
|
||||
mChromeEventHandler = nsnull; // Forces Release
|
||||
|
||||
if (IsPopupSpamWindow()) {
|
||||
if (IsOuterWindow() && IsPopupSpamWindow()) {
|
||||
SetPopupSpamWindow(PR_FALSE);
|
||||
--gOpenPopupSpamCount;
|
||||
}
|
||||
|
@ -2960,43 +2960,29 @@ GetCallerDocShellTreeItem()
|
|||
}
|
||||
|
||||
PRBool
|
||||
nsGlobalWindow::WindowExists(const nsAString& aName)
|
||||
nsGlobalWindow::WindowExists(const nsAString& aName,
|
||||
PRBool aLookForCallerOnJSStack)
|
||||
{
|
||||
nsCOMPtr<nsIDocShellTreeItem> caller = GetCallerDocShellTreeItem();
|
||||
PRBool foundWindow = PR_FALSE;
|
||||
NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
|
||||
NS_PRECONDITION(mDocShell, "Must have docshell");
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> caller;
|
||||
if (aLookForCallerOnJSStack) {
|
||||
caller = GetCallerDocShellTreeItem();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShell = do_QueryInterface(mDocShell);
|
||||
NS_ASSERTION(docShell,
|
||||
"Docshell doesn't implement nsIDocShellTreeItem?");
|
||||
|
||||
if (!caller) {
|
||||
// If we can't reach a caller, try to use our own docshell
|
||||
caller = do_QueryInterface(GetDocShell());
|
||||
caller = docShell;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShell =
|
||||
do_QueryInterface(GetDocShell());
|
||||
|
||||
if (docShell) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> namedItem;
|
||||
|
||||
docShell->FindItemWithName(PromiseFlatString(aName).get(), nsnull, caller,
|
||||
getter_AddRefs(namedItem));
|
||||
|
||||
foundWindow = !!namedItem;
|
||||
} else {
|
||||
// No caller reachable and we don't have a docshell any more. Fall
|
||||
// back to using the windowwatcher service to find any window by
|
||||
// name.
|
||||
|
||||
nsCOMPtr<nsIWindowWatcher> wwatch =
|
||||
do_GetService(NS_WINDOWWATCHER_CONTRACTID);
|
||||
if (wwatch) {
|
||||
nsCOMPtr<nsIDOMWindow> namedWindow;
|
||||
wwatch->GetWindowByName(PromiseFlatString(aName).get(), nsnull,
|
||||
getter_AddRefs(namedWindow));
|
||||
|
||||
foundWindow = !!namedWindow;
|
||||
}
|
||||
}
|
||||
|
||||
return foundWindow;
|
||||
nsCOMPtr<nsIDocShellTreeItem> namedItem;
|
||||
docShell->FindItemWithName(PromiseFlatString(aName).get(), nsnull, caller,
|
||||
getter_AddRefs(namedItem));
|
||||
return namedItem != nsnull;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIWidget>
|
||||
|
@ -4072,15 +4058,16 @@ nsGlobalWindow::CheckForAbusePoint()
|
|||
{
|
||||
FORWARD_TO_OUTER(CheckForAbusePoint, (), openAbused);
|
||||
|
||||
NS_ASSERTION(mDocShell, "Must have docshell");
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(mDocShell));
|
||||
|
||||
if (item) {
|
||||
PRInt32 type = nsIDocShellTreeItem::typeChrome;
|
||||
NS_ASSERTION(item, "Docshell doesn't implenent nsIDocShellTreeItem?");
|
||||
|
||||
item->GetItemType(&type);
|
||||
if (type != nsIDocShellTreeItem::typeContent)
|
||||
return openAllowed;
|
||||
}
|
||||
PRInt32 type = nsIDocShellTreeItem::typeChrome;
|
||||
item->GetItemType(&type);
|
||||
if (type != nsIDocShellTreeItem::typeContent)
|
||||
return openAllowed;
|
||||
|
||||
// level of abuse we've detected, initialized to the current popup
|
||||
// state
|
||||
|
@ -4097,37 +4084,21 @@ nsGlobalWindow::CheckForAbusePoint()
|
|||
}
|
||||
|
||||
/* Allow or deny a window open based on whether popups are suppressed.
|
||||
A popup generally will be allowed if it's from a white-listed domain,
|
||||
or if its target is an extant window.
|
||||
A popup generally will be allowed if it's from a white-listed domain.
|
||||
Returns a value from the CheckOpenAllow enum. */
|
||||
OpenAllowValue
|
||||
nsGlobalWindow::CheckOpenAllow(PopupControlState aAbuseLevel,
|
||||
const nsAString &aName)
|
||||
nsGlobalWindow::CheckOpenAllow(PopupControlState aAbuseLevel)
|
||||
{
|
||||
NS_PRECONDITION(GetDocShell(), "Must have docshell");
|
||||
|
||||
OpenAllowValue allowWindow = allowNoAbuse; // (also used for openControlled)
|
||||
|
||||
if (aAbuseLevel >= openAbused) {
|
||||
allowWindow = allowNot;
|
||||
|
||||
// However it might still not be blocked.
|
||||
if (aAbuseLevel == openAbused && !IsPopupBlocked(mDocument))
|
||||
if (aAbuseLevel == openAbused && !IsPopupBlocked(mDocument)) {
|
||||
allowWindow = allowWhitelisted;
|
||||
else {
|
||||
// Special case items that don't actually open new windows.
|
||||
if (!aName.IsEmpty()) {
|
||||
// _main is an IE target which should be case-insensitive but isn't
|
||||
// see bug 217886 for details
|
||||
if (aName.LowerCaseEqualsLiteral("_top") ||
|
||||
aName.LowerCaseEqualsLiteral("_self") ||
|
||||
aName.LowerCaseEqualsLiteral("_content") ||
|
||||
aName.EqualsLiteral("_main"))
|
||||
allowWindow = allowSelf;
|
||||
else {
|
||||
if (WindowExists(aName)) {
|
||||
allowWindow = allowExtant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4137,7 +4108,8 @@ nsGlobalWindow::CheckOpenAllow(PopupControlState aAbuseLevel,
|
|||
OpenAllowValue
|
||||
nsGlobalWindow::GetOpenAllow(const nsAString &aName)
|
||||
{
|
||||
return CheckOpenAllow(CheckForAbusePoint(), aName);
|
||||
NS_ENSURE_TRUE(GetDocShell(), allowNot);
|
||||
return CheckOpenAllow(CheckForAbusePoint());
|
||||
}
|
||||
|
||||
/* If a window open is blocked, fire the appropriate DOM events.
|
||||
|
@ -4211,29 +4183,12 @@ NS_IMETHODIMP
|
|||
nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
|
||||
const nsAString& aOptions, nsIDOMWindow **_retval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
PopupControlState abuseLevel = CheckForAbusePoint();
|
||||
OpenAllowValue allowReason = CheckOpenAllow(abuseLevel, aName);
|
||||
if (allowReason == allowNot) {
|
||||
FireAbuseEvents(PR_TRUE, PR_FALSE, aUrl, aName, aOptions);
|
||||
return NS_ERROR_FAILURE; // unlike the public Open method, return an error
|
||||
}
|
||||
|
||||
rv = OpenInternal(aUrl, aName, aOptions, PR_FALSE, nsnull, 0, nsnull,
|
||||
_retval);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (abuseLevel >= openControlled && allowReason != allowSelf) {
|
||||
nsGlobalWindow *opened = NS_STATIC_CAST(nsGlobalWindow *, *_retval);
|
||||
if (!opened->IsPopupSpamWindow()) {
|
||||
opened->SetPopupSpamWindow(PR_TRUE);
|
||||
++gOpenPopupSpamCount;
|
||||
}
|
||||
}
|
||||
if (abuseLevel >= openAbused)
|
||||
FireAbuseEvents(PR_FALSE, PR_TRUE, aUrl, aName, aOptions);
|
||||
}
|
||||
return rv;
|
||||
return OpenInternal(aUrl, aName, aOptions,
|
||||
PR_FALSE, // aDialog
|
||||
PR_TRUE, // aCalledNoScript
|
||||
PR_FALSE, // aDoJSFixups
|
||||
nsnull, 0, nsnull, // No args
|
||||
_retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -4275,51 +4230,12 @@ nsGlobalWindow::Open(nsIDOMWindow **_retval)
|
|||
}
|
||||
}
|
||||
|
||||
PopupControlState abuseLevel = CheckForAbusePoint();
|
||||
OpenAllowValue allowReason = CheckOpenAllow(abuseLevel, name);
|
||||
if (allowReason == allowNot) {
|
||||
FireAbuseEvents(PR_TRUE, PR_FALSE, url, name, options);
|
||||
return NS_OK; // don't open the window, but also don't throw a JS exception
|
||||
}
|
||||
|
||||
rv = OpenInternal(url, name, options, PR_FALSE, nsnull, 0, nsnull, _retval);
|
||||
|
||||
nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*_retval));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (!chrome_win) {
|
||||
// A new non-chrome window was created from a call to
|
||||
// window.open() from JavaScript, make sure there's a document in
|
||||
// the new window. We do this by simply asking the new window for
|
||||
// its document, this will synchronously create an empty document
|
||||
// if there is no document in the window.
|
||||
|
||||
#ifdef DEBUG_jst
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> pidomwin(do_QueryInterface(*_retval));
|
||||
|
||||
nsIDOMDocument *temp = pidomwin->GetExtantDocument();
|
||||
|
||||
NS_ASSERTION(temp, "No document in new window!!!");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> doc;
|
||||
(*_retval)->GetDocument(getter_AddRefs(doc));
|
||||
}
|
||||
|
||||
if (abuseLevel >= openControlled && allowReason != allowSelf) {
|
||||
nsGlobalWindow *opened = NS_STATIC_CAST(nsGlobalWindow*, *_retval);
|
||||
if (!opened->IsPopupSpamWindow()) {
|
||||
opened->SetPopupSpamWindow(PR_TRUE);
|
||||
++gOpenPopupSpamCount;
|
||||
}
|
||||
}
|
||||
if (abuseLevel >= openAbused)
|
||||
FireAbuseEvents(PR_FALSE, PR_TRUE, url, name, options);
|
||||
}
|
||||
|
||||
return rv;
|
||||
return OpenInternal(url, name, options,
|
||||
PR_FALSE, // aDialog
|
||||
PR_FALSE, // aCalledNoScript
|
||||
PR_TRUE, // aDoJSFixups
|
||||
nsnull, 0, nsnull, // No args
|
||||
_retval);
|
||||
}
|
||||
|
||||
// like Open, but attaches to the new window any extra parameters past
|
||||
|
@ -4329,8 +4245,12 @@ nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
|
|||
const nsAString& aOptions,
|
||||
nsISupports* aExtraArgument, nsIDOMWindow** _retval)
|
||||
{
|
||||
return OpenInternal(aUrl, aName, aOptions, PR_TRUE, nsnull, 0,
|
||||
aExtraArgument, _retval);
|
||||
return OpenInternal(aUrl, aName, aOptions,
|
||||
PR_TRUE, // aDialog
|
||||
PR_TRUE, // aCalledNoScript
|
||||
PR_FALSE, // aDoJSFixups
|
||||
nsnull, 0, aExtraArgument, // Arguments
|
||||
_retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -4373,7 +4293,11 @@ nsGlobalWindow::OpenDialog(nsIDOMWindow** _retval)
|
|||
}
|
||||
}
|
||||
|
||||
return OpenInternal(url, name, options, PR_TRUE, argv, argc, nsnull,
|
||||
return OpenInternal(url, name, options,
|
||||
PR_TRUE, // aDialog
|
||||
PR_FALSE, // aCalledNoScript
|
||||
PR_FALSE, // aDoJSFixups
|
||||
argv, argc, nsnull, // Arguments
|
||||
_retval);
|
||||
}
|
||||
|
||||
|
@ -5657,17 +5581,28 @@ nsGlobalWindow::GetParentInternal()
|
|||
return parentInternal;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
||||
const nsAString& aOptions, PRBool aDialog,
|
||||
PRBool aCalledNoScript, PRBool aDoJSFixups,
|
||||
jsval *argv, PRUint32 argc,
|
||||
nsISupports *aExtraArgument,
|
||||
nsIDOMWindow **aReturn)
|
||||
{
|
||||
FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog, argv, argc,
|
||||
aExtraArgument, aReturn),
|
||||
FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog,
|
||||
aCalledNoScript, aDoJSFixups,
|
||||
argv, argc, aExtraArgument, aReturn),
|
||||
NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
|
||||
"Can't pass in arguments both ways");
|
||||
NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
|
||||
"Can't pass JS args when called via the noscript methods");
|
||||
NS_PRECONDITION(!aDoJSFixups || !aCalledNoScript,
|
||||
"JS fixups should not be done when called noscript");
|
||||
|
||||
*aReturn = nsnull;
|
||||
|
||||
nsCOMPtr<nsIWebBrowserChrome> chrome;
|
||||
GetWebBrowserChrome(getter_AddRefs(chrome));
|
||||
if (!chrome) {
|
||||
|
@ -5675,11 +5610,29 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
|||
// -- see nsIWindowWatcher.idl
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsXPIDLCString url;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
*aReturn = nsnull;
|
||||
NS_ASSERTION(mDocShell, "Must have docshell here");
|
||||
|
||||
const PRBool checkForPopup =
|
||||
!aDialog && !WindowExists(aName, !aCalledNoScript);
|
||||
|
||||
// These next two variables are only accessed when checkForPopup is true
|
||||
PopupControlState abuseLevel;
|
||||
OpenAllowValue allowReason;
|
||||
if (checkForPopup) {
|
||||
abuseLevel = CheckForAbusePoint();
|
||||
allowReason = CheckOpenAllow(abuseLevel);
|
||||
if (allowReason == allowNot) {
|
||||
FireAbuseEvents(PR_TRUE, PR_FALSE, aUrl, aName, aOptions);
|
||||
return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: it's very important that this be an nsXPIDLCString, since we want
|
||||
// .get() on it to return nsnull until we write stuff to it. The window
|
||||
// watcher expects a null URL string if there is no URL to load.
|
||||
nsXPIDLCString url;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!aUrl.IsEmpty()) {
|
||||
// fix bug 35076
|
||||
|
@ -5708,150 +5661,71 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// determine whether we must divert the open window to a new tab.
|
||||
|
||||
PRBool divertOpen = !WindowExists(aName);
|
||||
|
||||
// also check what the prefs prescribe?
|
||||
// XXXbz this duplicates docshell code. Need to consolidate.
|
||||
|
||||
PRInt32 containerPref = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
|
||||
|
||||
nsCOMPtr<nsIURI> tabURI;
|
||||
if (!aUrl.IsEmpty()) {
|
||||
PRBool whoCares;
|
||||
BuildURIfromBase(url.get(), getter_AddRefs(tabURI), &whoCares, 0);
|
||||
}
|
||||
|
||||
if (divertOpen) { // no such named window
|
||||
divertOpen = PR_FALSE; // more tests to pass:
|
||||
if (!aExtraArgument) {
|
||||
nsCOMPtr<nsIDOMChromeWindow> thisChrome =
|
||||
do_QueryInterface(NS_STATIC_CAST(nsIDOMWindow *, this));
|
||||
PRBool chromeTab = PR_FALSE;
|
||||
if (tabURI)
|
||||
tabURI->SchemeIs("chrome", &chromeTab);
|
||||
|
||||
if (!thisChrome && !chromeTab) {
|
||||
containerPref =
|
||||
nsContentUtils::GetIntPref("browser.link.open_newwindow",
|
||||
nsIBrowserDOMWindow::OPEN_NEWWINDOW);
|
||||
PRInt32 restrictionPref = nsContentUtils::GetIntPref(
|
||||
"browser.link.open_newwindow.restriction");
|
||||
/* The restriction pref is a power-user's fine-tuning pref. values:
|
||||
0: no restrictions - divert everything
|
||||
1: don't divert window.open at all
|
||||
2: don't divert window.open with features */
|
||||
|
||||
if (containerPref == nsIBrowserDOMWindow::OPEN_NEWTAB ||
|
||||
containerPref == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
|
||||
divertOpen = restrictionPref != 1;
|
||||
if (divertOpen && !aOptions.IsEmpty() && restrictionPref == 2)
|
||||
divertOpen = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> domReturn;
|
||||
|
||||
// divert the window.open into a new tab or into this window, if required
|
||||
nsCOMPtr<nsIWindowWatcher> wwatch =
|
||||
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
|
||||
NS_ENSURE_TRUE(wwatch, rv);
|
||||
|
||||
if (divertOpen) {
|
||||
if (containerPref == nsIBrowserDOMWindow::OPEN_NEWTAB ||
|
||||
!aUrl.IsEmpty()) {
|
||||
#ifdef DEBUG
|
||||
printf("divert window.open to new tab\n");
|
||||
#endif
|
||||
// get nsIBrowserDOMWindow interface
|
||||
NS_ConvertUTF16toUTF8 options(aOptions);
|
||||
NS_ConvertUTF16toUTF8 name(aName);
|
||||
|
||||
nsCOMPtr<nsIBrowserDOMWindow> bwin;
|
||||
const char *options_ptr = aOptions.IsEmpty() ? nsnull : options.get();
|
||||
const char *name_ptr = aName.IsEmpty() ? nsnull : name.get();
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> docItem(do_QueryInterface(mDocShell));
|
||||
if (docItem) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootItem;
|
||||
docItem->GetRootTreeItem(getter_AddRefs(rootItem));
|
||||
nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
|
||||
nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
|
||||
if (chromeWin)
|
||||
chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
|
||||
}
|
||||
{
|
||||
// Reset popup state while opening a window to prevent the
|
||||
// current state from being active the whole time a modal
|
||||
// dialog is open.
|
||||
nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
|
||||
|
||||
// open new tab
|
||||
|
||||
if (bwin) {
|
||||
// open the tab with the URL
|
||||
// discard features (meaningless in this case)
|
||||
bwin->OpenURI(tabURI, this,
|
||||
containerPref, nsIBrowserDOMWindow::OPEN_NEW,
|
||||
getter_AddRefs(domReturn));
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> domWin(do_GetInterface(domReturn));
|
||||
if (domWin) {
|
||||
domWin->SetOpenerWindow(this);
|
||||
}
|
||||
}
|
||||
if (!aCalledNoScript) {
|
||||
nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
|
||||
NS_ASSERTION(pwwatch,
|
||||
"Unable to open windows from JS because window watcher "
|
||||
"is broken");
|
||||
NS_ENSURE_TRUE(pwwatch, NS_ERROR_UNEXPECTED);
|
||||
|
||||
PRUint32 extraArgc = argc >= 3 ? argc - 3 : 0;
|
||||
rv = pwwatch->OpenWindowJS(this, url.get(), name_ptr, options_ptr,
|
||||
aDialog, extraArgc, argv + 3,
|
||||
getter_AddRefs(domReturn));
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
printf("divert window.open to current window\n");
|
||||
#endif
|
||||
GetTop(getter_AddRefs(domReturn));
|
||||
}
|
||||
// Push a null JSContext here so that the window watcher won't screw us
|
||||
// up. We do NOT want this case looking at the JS context on the stack
|
||||
// when searching. Compare comments on
|
||||
// nsIDOMWindowInternal::OpenWindow and nsIWindowWatcher::OpenWindow.
|
||||
nsCOMPtr<nsIJSContextStack> stack =
|
||||
do_GetService(sJSStackContractID);
|
||||
|
||||
if (domReturn && !aName.LowerCaseEqualsLiteral("_blank") &&
|
||||
!aName.LowerCaseEqualsLiteral("_new"))
|
||||
domReturn->SetName(aName);
|
||||
}
|
||||
if (stack) {
|
||||
rv = stack->Push(nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = wwatch->OpenWindow(this, url.get(), name_ptr, options_ptr,
|
||||
aExtraArgument, getter_AddRefs(domReturn));
|
||||
|
||||
// lacking specific instructions, or just as an error fallback,
|
||||
// open a new window.
|
||||
|
||||
if (!domReturn) {
|
||||
nsCOMPtr<nsIWindowWatcher> wwatch =
|
||||
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
|
||||
|
||||
if (wwatch) {
|
||||
NS_ConvertUTF16toUTF8 options(aOptions);
|
||||
NS_ConvertUTF16toUTF8 name(aName);
|
||||
|
||||
const char *options_ptr = aOptions.IsEmpty() ? nsnull : options.get();
|
||||
const char *name_ptr = aName.IsEmpty() ? nsnull : name.get();
|
||||
|
||||
{
|
||||
// Reset popup state while opening a window to prevent the
|
||||
// current state from being active the whole time a modal
|
||||
// dialog is open.
|
||||
nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
|
||||
|
||||
if (argc) {
|
||||
nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
|
||||
if (pwwatch) {
|
||||
PRUint32 extraArgc = argc >= 3 ? argc - 3 : 0;
|
||||
rv = pwwatch->OpenWindowJS(this, url.get(), name_ptr, options_ptr,
|
||||
aDialog, extraArgc, argv + 3,
|
||||
getter_AddRefs(domReturn));
|
||||
} else {
|
||||
NS_ERROR("WindowWatcher service not a nsPIWindowWatcher!");
|
||||
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
} else {
|
||||
rv = wwatch->OpenWindow(this, url.get(), name_ptr, options_ptr,
|
||||
aExtraArgument, getter_AddRefs(domReturn));
|
||||
}
|
||||
if (stack) {
|
||||
JSContext* cx;
|
||||
stack->Pop(&cx);
|
||||
NS_ASSERTION(!cx, "Unexpected JSContext popped!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// success!
|
||||
|
||||
if (domReturn) {
|
||||
CallQueryInterface(domReturn, aReturn);
|
||||
|
||||
// Save the principal of the calling script
|
||||
// We need it to decide whether to clear the scope in SetNewDocument
|
||||
NS_ASSERTION(sSecMan, "No Security Manager Found!");
|
||||
if (sSecMan) {
|
||||
// Note that the opener script URL is not relevant for openDialog
|
||||
// callers, since those already have chrome privileges. So we
|
||||
// only want to do this wen aDoJSFixups is true.
|
||||
if (aDoJSFixups && sSecMan) {
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
sSecMan->GetSubjectPrincipal(getter_AddRefs(principal));
|
||||
if (principal) {
|
||||
|
@ -5863,8 +5737,50 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
domReturn.swap(*aReturn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (aDoJSFixups) {
|
||||
nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
|
||||
if (!chrome_win) {
|
||||
// A new non-chrome window was created from a call to
|
||||
// window.open() from JavaScript, make sure there's a document in
|
||||
// the new window. We do this by simply asking the new window for
|
||||
// its document, this will synchronously create an empty document
|
||||
// if there is no document in the window.
|
||||
// XXXbz should this just use EnsureInnerWindow()?
|
||||
#ifdef DEBUG_jst
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> pidomwin(do_QueryInterface(*aReturn));
|
||||
|
||||
nsIDOMDocument *temp = pidomwin->GetExtantDocument();
|
||||
|
||||
NS_ASSERTION(temp, "No document in new window!!!");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> doc;
|
||||
(*aReturn)->GetDocument(getter_AddRefs(doc));
|
||||
}
|
||||
}
|
||||
|
||||
if (checkForPopup) {
|
||||
if (abuseLevel >= openControlled) {
|
||||
nsGlobalWindow *opened = NS_STATIC_CAST(nsGlobalWindow *, *aReturn);
|
||||
if (!opened->IsPopupSpamWindow()) {
|
||||
opened->SetPopupSpamWindow(PR_TRUE);
|
||||
++gOpenPopupSpamCount;
|
||||
}
|
||||
}
|
||||
if (abuseLevel >= openAbused)
|
||||
FireAbuseEvents(PR_FALSE, PR_TRUE, aUrl, aName, aOptions);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
@ -321,11 +321,46 @@ protected:
|
|||
}
|
||||
|
||||
// Window Control Functions
|
||||
NS_IMETHOD OpenInternal(const nsAString& aUrl,
|
||||
const nsAString& aName,
|
||||
const nsAString& aOptions,
|
||||
PRBool aDialog, jsval *argv, PRUint32 argc,
|
||||
nsISupports *aExtraArgument, nsIDOMWindow **aReturn);
|
||||
/**
|
||||
* @param aURL the URL to load in the new window
|
||||
* @param aName the name to use for the new window
|
||||
* @param aOptions the window options to use for the new window
|
||||
* @param aDialog true when called from variants of OpenDialog. If this is
|
||||
* true, this method will skip popup blocking checks. The
|
||||
* aDialog argument is passed on to the window watcher.
|
||||
* @param aCalledNoScript true when called via the [noscript] open()
|
||||
* and openDialog() methods. When this is true, we do
|
||||
* NOT want to use the JS stack for things like caller
|
||||
* determination.
|
||||
* @param aDoJSFixups true when this is the content-accessible JS version of
|
||||
* window opening. When true, popups do not cause us to
|
||||
* throw, we save the caller's principal in the new window
|
||||
* for later consumption, and we make sure that there is a
|
||||
* document in the newly-opened window. Note that this
|
||||
* last will only be done if the newly-opened window is
|
||||
* non-chrome.
|
||||
* @param argv The arguments to pass to the new window. The first
|
||||
* three args, if present, will be aURL, aName, and aOptions. So
|
||||
* this param only matters if there are more than 3 arguments.
|
||||
* @param argc The number of arguments in argv.
|
||||
* @param aExtraArgument Another way to pass arguments in. This is mutually
|
||||
* exclusive with the argv/argc approach.
|
||||
* @param aReturn [out] The window that was opened, if any.
|
||||
*
|
||||
* @note that the boolean args are const because the function shouldn't be
|
||||
* messing with them. That also makes it easier for the compiler to sort out
|
||||
* its build warning stuff.
|
||||
*/
|
||||
NS_HIDDEN_(nsresult) OpenInternal(const nsAString& aUrl,
|
||||
const nsAString& aName,
|
||||
const nsAString& aOptions,
|
||||
PRBool aDialog,
|
||||
PRBool aCalledNoScript,
|
||||
PRBool aDoJSFixups,
|
||||
jsval *argv, PRUint32 argc,
|
||||
nsISupports *aExtraArgument,
|
||||
nsIDOMWindow **aReturn);
|
||||
|
||||
static void CloseWindow(nsISupports* aWindow);
|
||||
static void ClearWindowScope(nsISupports* aWindow);
|
||||
|
||||
|
@ -350,8 +385,7 @@ protected:
|
|||
nsIURI **aBuiltURI,
|
||||
PRBool *aFreeSecurityPass, JSContext **aCXused);
|
||||
PopupControlState CheckForAbusePoint();
|
||||
OpenAllowValue CheckOpenAllow(PopupControlState aAbuseLevel,
|
||||
const nsAString &aName);
|
||||
OpenAllowValue CheckOpenAllow(PopupControlState aAbuseLevel);
|
||||
void FireAbuseEvents(PRBool aBlocked, PRBool aWindow,
|
||||
const nsAString &aPopupURL,
|
||||
const nsAString &aPopupWindowName,
|
||||
|
@ -390,7 +424,10 @@ protected:
|
|||
|
||||
PRBool DispatchCustomEvent(const char *aEventName);
|
||||
|
||||
PRBool WindowExists(const nsAString& aName);
|
||||
// If aLookForCallerOnJSStack is true, this method will look at the JS stack
|
||||
// to determine who the caller is. If it's false, it'll use |this| as the
|
||||
// caller.
|
||||
PRBool WindowExists(const nsAString& aName, PRBool aLookForCallerOnJSStack);
|
||||
|
||||
already_AddRefed<nsIWidget> GetMainWidget();
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ SDK_LIBRARY = \
|
|||
|
||||
XPIDLSRCS = \
|
||||
nsIWindowCreator2.idl \
|
||||
nsIWindowProvider.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(srcdir)/objs.mk
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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 Mozilla.com.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Boris Zbarsky <bzbarsky@mit.edu> (Original Author)
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
/**
|
||||
* nsIWindowProvider is a callback interface used by Gecko when it needs to
|
||||
* open a new window. This interface can be implemented by Gecko consumers who
|
||||
* wish to provide a custom "new window" of their own (for example by returning
|
||||
* a new tab, an existing window, etc) instead of just having a real new
|
||||
* toplevel window open.
|
||||
*
|
||||
* @status UNDER_REVIEW ???
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMWindow;
|
||||
interface nsIURI;
|
||||
|
||||
/**
|
||||
* The nsIWindowProvider interface exists so that the window watcher's default
|
||||
* behavior of opening a new window can be easly modified. When the window
|
||||
* watcher needs to open a new window, it will first check with the
|
||||
* nsIWindowProvider it gets from the parent window. If there is no provider
|
||||
* or the provider does not provide a window, the window watcher will proceed
|
||||
* to actually open a new window.
|
||||
*/
|
||||
[uuid(A4D32E30-9854-477A-83CB-FB7B8AE9273C)]
|
||||
interface nsIWindowProvider : nsISupports
|
||||
{
|
||||
/**
|
||||
* A method to request that this provider provide a window. The window
|
||||
* returned need not to have the right name or parent set on it; setting
|
||||
* those is the caller's responsibility. The provider can always return null
|
||||
* to have the caller create a brand-new window.
|
||||
*
|
||||
* @param aParent Must not be null. This is the window that the caller wants
|
||||
* to use as the parent for the new window. Generally,
|
||||
* nsIWindowProvider implementors can expect to be somehow
|
||||
* related to aParent; the relationship may depend on the
|
||||
* nsIWindowProvider implementation.
|
||||
* @param aChromeFlags The chrome flags the caller will use to create a new
|
||||
* window if this provider returns null. See
|
||||
* nsIWebBrowserChrome for the possible values of this
|
||||
* field.
|
||||
* @param aPositionSpecified Whether the attempt to create a window is trying
|
||||
* to specify a position for the new window.
|
||||
* @param aSizeSpecified Whether the attempt to create a window is trying to
|
||||
* specify a size for the new window.
|
||||
* @param aURI The URI to be loaded in the new window. The nsIWindowProvider
|
||||
* implementation MUST NOT load this URI in the window it
|
||||
* returns. This URI is provided solely to help the
|
||||
* nsIWindowProvider implenentation make decisions; the caller
|
||||
* will handle loading the URI in the window returned if
|
||||
* provideWindow returns a window. Note that the URI may be null
|
||||
* if the load cannot be represented by a single URI (e.g. if
|
||||
* the load has extra load flags, POST data, etc).
|
||||
* @param aName The name of the window being opened. Setting the name on the
|
||||
* return value of provideWindow will be handled by the caller;
|
||||
* aName is provided solely to help the nsIWindowProvider
|
||||
* implementation make decisions.
|
||||
* @param aFeatures The feature string for the window being opened. This may
|
||||
* be empty. The nsIWindowProvider implementation is
|
||||
* allowed to apply the feature string to the window it
|
||||
* returns in any way it sees fit. See the nsIWindowWatcher
|
||||
* interface for details on feature strings.
|
||||
* @return A window the caller should use or null if the caller should just
|
||||
* create a new window. The returned window may be newly opened by
|
||||
* the nsIWindowProvider implementation or may be a window that
|
||||
* already existed.
|
||||
*
|
||||
* @see nsIWindowWatcher for more information on aFeatures.
|
||||
* @see nsIWebBrowserChrome for more information on aChromeFlags.
|
||||
*/
|
||||
nsIDOMWindow provideWindow(in nsIDOMWindow aParent,
|
||||
in unsigned long aChromeFlags,
|
||||
in boolean aPositionSpecified,
|
||||
in boolean aSizeSpecified,
|
||||
in nsIURI aURI,
|
||||
in AString aName,
|
||||
in AUTF8String aFeatures);
|
||||
};
|
|
@ -80,13 +80,22 @@ interface nsIWindowWatcher : nsISupports {
|
|||
method will effectively act as if aParent were null.
|
||||
@param aURL url to which to open the new window. Must already be
|
||||
escaped, if applicable. can be null.
|
||||
@param aName window name from JS window.open. can be null.
|
||||
@param aName window name from JS window.open. can be null. If a window
|
||||
with this name already exists, the openWindow call may just load
|
||||
aUrl in it (if aUrl is not null) and return it.
|
||||
@param aFeatures window features from JS window.open. can be null.
|
||||
@param aArguments extra argument(s) to the new window, to be attached
|
||||
as the |arguments| property. An nsISupportsArray will be
|
||||
unwound into multiple arguments (but not recursively!).
|
||||
can be null.
|
||||
@return the new window
|
||||
|
||||
@note This method may examine the JS context stack for purposes of
|
||||
determining the security context to use for the search for a given
|
||||
window named aName.
|
||||
@note This method should try to set the default charset for the new
|
||||
window to the default charset of aParent. This is not guaranteed,
|
||||
however.
|
||||
*/
|
||||
nsIDOMWindow openWindow(in nsIDOMWindow aParent, in string aUrl,
|
||||
in string aName, in string aFeatures,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
|
@ -79,13 +79,23 @@ interface nsPIWindowWatcher : nsISupports
|
|||
method will effectively act as if aParent were null.
|
||||
@param aURL url to which to open the new window. Must already be
|
||||
escaped, if applicable. can be null.
|
||||
@param aName window name from JS window.open. can be null.
|
||||
@param aName window name from JS window.open. can be null. If a window
|
||||
with this name already exists, the openWindow call may just load
|
||||
aUrl in it (if aUrl is not null) and return it.
|
||||
@param aFeatures window features from JS window.open. can be null.
|
||||
@param aDialog use dialog defaults (see nsIDOMWindowInternal::openDialog)
|
||||
@param argc count of argv arguments
|
||||
@param argv extra JS arguments, if any
|
||||
(see nsIDOMWindowInternal::openDialog)
|
||||
@return the new window
|
||||
|
||||
@note This method may examine the JS context stack for purposes of
|
||||
determining the security context to use for the search for a given
|
||||
window named aName.
|
||||
@note This method should try to set the default charset for the new
|
||||
window to the default charset of the document in the calling window
|
||||
(which is determined based on the JS stack and the value of
|
||||
aParent). This is not guaranteed, however.
|
||||
*/
|
||||
nsIDOMWindow openWindowJS(in nsIDOMWindow aParent, in string aUrl,
|
||||
in string aName, in string aFeatures, in boolean aDialog,
|
||||
|
@ -115,9 +125,3 @@ interface nsPIWindowWatcher : nsISupports
|
|||
in nsIDocShellTreeItem aOriginalRequestor);
|
||||
};
|
||||
|
||||
%{C++
|
||||
// {d535806e-afaf-47d1-8d89-783ad088c62a}
|
||||
#define NS_PWINDOWWATCHER_IID \
|
||||
{0xd535806e, 0xafaf, 0x47d1, {0x8d, 0x89, 0x78, 0x3a, 0xd0, 0x88, 0xc6, 0x2a}}
|
||||
%}
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
#include "nsIMarkupDocumentViewer.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDocumentViewer.h"
|
||||
#include "nsIWindowProvider.h"
|
||||
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefService.h"
|
||||
|
@ -470,8 +471,8 @@ nsWindowWatcher::OpenWindow(nsIDOMWindow *aParent,
|
|||
rv = ConvertSupportsTojsvals(aParent, aArguments, &argc, &argv, &cx, &mark);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRBool dialog = argc == 0 ? PR_FALSE : PR_TRUE;
|
||||
rv = OpenWindowJS(aParent, aUrl, aName, aFeatures, dialog, argc, argv,
|
||||
_retval);
|
||||
rv = OpenWindowJSInternal(aParent, aUrl, aName, aFeatures, dialog, argc,
|
||||
argv, PR_FALSE, _retval);
|
||||
|
||||
if (argv) {
|
||||
js_FreeStack(cx, mark);
|
||||
|
@ -481,6 +482,47 @@ nsWindowWatcher::OpenWindow(nsIDOMWindow *aParent,
|
|||
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,
|
||||
|
@ -490,11 +532,27 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
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,
|
||||
windowIsNew = PR_FALSE,
|
||||
windowNeedsName = PR_FALSE,
|
||||
windowIsModal = PR_FALSE,
|
||||
uriToLoadIsChrome = PR_FALSE;
|
||||
PRUint32 chromeFlags;
|
||||
|
@ -509,8 +567,7 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
*_retval = 0;
|
||||
|
||||
if (aParent)
|
||||
GetWindowTreeOwner(aParent, getter_AddRefs(parentTreeOwner));
|
||||
GetWindowTreeOwner(aParent, getter_AddRefs(parentTreeOwner));
|
||||
|
||||
if (aUrl) {
|
||||
rv = URIfromURL(aUrl, aParent, getter_AddRefs(uriToLoad));
|
||||
|
@ -522,7 +579,9 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
nameSpecified = PR_FALSE;
|
||||
if (aName) {
|
||||
CopyUTF8toUTF16(aName, name);
|
||||
#ifdef DEBUG
|
||||
CheckWindowName(name);
|
||||
#endif
|
||||
nameSpecified = PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -534,39 +593,9 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
}
|
||||
|
||||
// try to find an extant window with the given name
|
||||
if (nameSpecified) {
|
||||
nsCOMPtr<nsIJSContextStack> stack =
|
||||
do_GetService(sJSStackContractID);
|
||||
|
||||
JSContext *cx = nsnull;
|
||||
|
||||
if (stack) {
|
||||
stack->Peek(&cx);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> callerItem;
|
||||
|
||||
if (cx) {
|
||||
nsCOMPtr<nsIWebNavigation> callerWebNav =
|
||||
do_GetInterface(nsWWJSUtils::GetDynamicScriptGlobal(cx));
|
||||
|
||||
callerItem = do_QueryInterface(callerWebNav);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentItem;
|
||||
GetWindowTreeItem(aParent, getter_AddRefs(parentItem));
|
||||
|
||||
if (!callerItem) {
|
||||
callerItem = parentItem;
|
||||
}
|
||||
|
||||
if (parentItem) {
|
||||
parentItem->FindItemWithName(name.get(), nsnull, callerItem,
|
||||
getter_AddRefs(newDocShellItem));
|
||||
} else
|
||||
FindItemWithName(name.get(), nsnull, callerItem,
|
||||
getter_AddRefs(newDocShellItem));
|
||||
}
|
||||
nsCOMPtr<nsIDOMWindow> foundWindow;
|
||||
SafeGetWindowByName(name, aParent, getter_AddRefs(foundWindow));
|
||||
GetWindowTreeItem(foundWindow, getter_AddRefs(newDocShellItem));
|
||||
|
||||
// no extant window? make a new one.
|
||||
|
||||
|
@ -580,6 +609,9 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
aDialog, uriToLoadIsChrome,
|
||||
!aParent || chromeParent);
|
||||
|
||||
SizeSpec sizeSpec;
|
||||
CalcSizeSpec(features.get(), sizeSpec);
|
||||
|
||||
PRBool isCallerChrome = PR_FALSE;
|
||||
nsCOMPtr<nsIScriptSecurityManager>
|
||||
sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
|
||||
|
@ -597,6 +629,39 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
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,
|
||||
getter_AddRefs(newWindow));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
GetWindowTreeItem(newWindow, getter_AddRefs(newDocShellItem));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!newDocShellItem) {
|
||||
windowIsNew = PR_TRUE;
|
||||
|
||||
|
@ -682,6 +747,9 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
if (!newDocShellItem)
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsIDocShell> newDocShell(do_QueryInterface(newDocShellItem));
|
||||
NS_ENSURE_TRUE(newDocShell, NS_ERROR_UNEXPECTED);
|
||||
|
||||
rv = ReadyOpenedDocShellItem(newDocShellItem, aParent, _retval);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
@ -713,36 +781,58 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
}
|
||||
}
|
||||
|
||||
/* allow an extant window to keep its name (important for cases like
|
||||
_self where the given name is different (and invalid)). also _blank
|
||||
is not a window name. */
|
||||
if (windowIsNew)
|
||||
newDocShellItem->SetName(nameSpecified && !name.LowerCaseEqualsLiteral("_blank") ?
|
||||
/* 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);
|
||||
|
||||
nsCOMPtr<nsIDocShell> newDocShell(do_QueryInterface(newDocShellItem));
|
||||
|
||||
// When a new window is opened through JavaScript, we want it to use the
|
||||
// charset of its opener as a fallback in the event the document being loaded
|
||||
// does not specify a charset. Failing to set this charset is not fatal, so we
|
||||
// want to continue in the face of errors.
|
||||
nsCOMPtr<nsPIDOMWindow> parentWin(do_QueryInterface(aParent));
|
||||
if (parentWin) {
|
||||
nsIDocShell *parentDocshell = parentWin->GetDocShell();
|
||||
// parentDocshell may be null if the parent got closed in the meantime
|
||||
if (parentDocshell) {
|
||||
nsCOMPtr<nsIContentViewer> parentContentViewer;
|
||||
parentDocshell->GetContentViewer(getter_AddRefs(parentContentViewer));
|
||||
nsCOMPtr<nsIDocumentViewer> parentDocViewer(do_QueryInterface(parentContentViewer));
|
||||
if (parentDocViewer) {
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
parentDocViewer->GetDocument(getter_AddRefs(doc));
|
||||
|
||||
nsCOMPtr<nsIContentViewer> newContentViewer;
|
||||
newDocShell->GetContentViewer(getter_AddRefs(newContentViewer));
|
||||
nsCOMPtr<nsIMarkupDocumentViewer> newMarkupDocViewer(do_QueryInterface(newContentViewer));
|
||||
if (doc && newMarkupDocViewer) {
|
||||
newMarkupDocViewer->SetDefaultCharacterSet(doc->GetDocumentCharacterSet());
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -787,8 +877,7 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
|
||||
// get its document, if any
|
||||
if (stack && NS_SUCCEEDED(stack->Peek(&ccx)) && ccx) {
|
||||
nsIScriptGlobalObject *sgo =
|
||||
nsWWJSUtils::GetStaticScriptGlobal(ccx, ::JS_GetGlobalObject(ccx));
|
||||
nsIScriptGlobalObject *sgo = nsWWJSUtils::GetDynamicScriptGlobal(ccx);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> w(do_QueryInterface(sgo));
|
||||
if (w) {
|
||||
|
@ -811,8 +900,7 @@ nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent,
|
|||
}
|
||||
|
||||
if (windowIsNew)
|
||||
SizeOpenedDocShellItem(newDocShellItem, aParent, features.get(),
|
||||
chromeFlags);
|
||||
SizeOpenedDocShellItem(newDocShellItem, aParent, sizeSpec);
|
||||
|
||||
if (windowIsModal) {
|
||||
nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
|
||||
|
@ -1111,37 +1199,22 @@ nsWindowWatcher::GetWindowByName(const PRUnichar *aTargetName,
|
|||
|
||||
*aResult = nsnull;
|
||||
|
||||
nsCOMPtr<nsIWebNavigation> webNav;
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
||||
|
||||
// First, check if the TargetName exists in the aCurrentWindow hierarchy
|
||||
webNav = do_GetInterface(aCurrentWindow);
|
||||
if (webNav) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem;
|
||||
|
||||
docShellTreeItem = do_QueryInterface(webNav);
|
||||
if (docShellTreeItem) {
|
||||
// Note: original requestor is null here, per idl comments
|
||||
docShellTreeItem->FindItemWithName(aTargetName, nsnull, nsnull,
|
||||
getter_AddRefs(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));
|
||||
}
|
||||
|
||||
// Next, see if the TargetName exists in any window hierarchy
|
||||
if (!treeItem) {
|
||||
else {
|
||||
// Note: original requestor is null here, per idl comments
|
||||
FindItemWithName(aTargetName, nsnull, nsnull, getter_AddRefs(treeItem));
|
||||
}
|
||||
|
||||
if (treeItem) {
|
||||
nsCOMPtr<nsIDOMWindow> domWindow;
|
||||
|
||||
domWindow = do_GetInterface(treeItem);
|
||||
if (domWindow) {
|
||||
*aResult = domWindow;
|
||||
NS_ADDREF(*aResult);
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(treeItem);
|
||||
domWindow.swap(*aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1203,6 +1276,7 @@ nsWindowWatcher::URIfromURL(const char *aURL,
|
|||
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). */
|
||||
|
@ -1218,15 +1292,14 @@ void nsWindowWatcher::CheckWindowName(nsString& aName)
|
|||
|
||||
// Don't use js_ReportError as this will cause the application
|
||||
// to shut down (JS_ASSERT calls abort()) See bug 32898
|
||||
nsAutoString warn;
|
||||
nsCAutoString warn;
|
||||
warn.AssignLiteral("Illegal character in window name ");
|
||||
warn.Append(aName);
|
||||
char *cp = ToNewCString(warn);
|
||||
NS_WARNING(cp);
|
||||
nsCRT::free(cp);
|
||||
AppendUTF16toUTF8(aName, warn);
|
||||
NS_WARNING(warn.get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
#define NS_CALCULATE_CHROME_FLAG_FOR(feature, flag) \
|
||||
prefBranch->GetBoolPref(feature, &forceEnable); \
|
||||
|
@ -1513,6 +1586,65 @@ nsWindowWatcher::FindItemWithName(const PRUnichar* aName,
|
|||
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,
|
||||
|
@ -1537,7 +1669,69 @@ nsWindowWatcher::ReadyOpenedDocShellItem(nsIDocShellTreeItem *aOpenedItem,
|
|||
return rv;
|
||||
}
|
||||
|
||||
/* Size and position the new window according to aFeatures. This method
|
||||
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.
|
||||
|
@ -1545,8 +1739,7 @@ nsWindowWatcher::ReadyOpenedDocShellItem(nsIDocShellTreeItem *aOpenedItem,
|
|||
void
|
||||
nsWindowWatcher::SizeOpenedDocShellItem(nsIDocShellTreeItem *aDocShellItem,
|
||||
nsIDOMWindow *aParent,
|
||||
const char *aFeatures,
|
||||
PRUint32 aChromeFlags)
|
||||
const SizeSpec & aSizeSpec)
|
||||
{
|
||||
// position and size of window
|
||||
PRInt32 left = 0,
|
||||
|
@ -1585,62 +1778,47 @@ nsWindowWatcher::SizeOpenedDocShellItem(nsIDocShellTreeItem *aDocShellItem,
|
|||
}
|
||||
}
|
||||
|
||||
// Parse position spec, if any, from aFeatures
|
||||
|
||||
PRBool positionSpecified = PR_FALSE;
|
||||
PRBool present;
|
||||
PRInt32 temp;
|
||||
|
||||
present = PR_FALSE;
|
||||
if ((temp = WinHasOption(aFeatures, "left", 0, &present)) || present)
|
||||
left = temp;
|
||||
else if ((temp = WinHasOption(aFeatures, "screenX", 0, &present)) || present)
|
||||
left = temp;
|
||||
if (present)
|
||||
positionSpecified = PR_TRUE;
|
||||
|
||||
present = PR_FALSE;
|
||||
if ((temp = WinHasOption(aFeatures, "top", 0, &present)) || present)
|
||||
top = temp;
|
||||
else if ((temp = WinHasOption(aFeatures, "screenY", 0, &present)) || present)
|
||||
top = temp;
|
||||
if (present)
|
||||
positionSpecified = PR_TRUE;
|
||||
|
||||
PRBool sizeSpecified = PR_FALSE;
|
||||
|
||||
// Parse size spec, if any. Chrome size overrides content size.
|
||||
|
||||
if ((temp = WinHasOption(aFeatures, "outerWidth", width, nsnull))) {
|
||||
width = temp;
|
||||
sizeSpecified = PR_TRUE;
|
||||
} else if ((temp = WinHasOption(aFeatures, "width",
|
||||
width - chromeWidth, nsnull))) {
|
||||
width = temp;
|
||||
sizeChromeWidth = PR_FALSE;
|
||||
sizeSpecified = PR_TRUE;
|
||||
} else if ((temp = WinHasOption(aFeatures, "innerWidth",
|
||||
width - chromeWidth, nsnull))) {
|
||||
width = temp;
|
||||
sizeChromeWidth = PR_FALSE;
|
||||
sizeSpecified = PR_TRUE;
|
||||
// Set up left/top
|
||||
if (aSizeSpec.mLeftSpecified) {
|
||||
left = aSizeSpec.mLeft;
|
||||
}
|
||||
|
||||
if ((temp = WinHasOption(aFeatures, "outerHeight", height, nsnull))) {
|
||||
height = temp;
|
||||
sizeSpecified = PR_TRUE;
|
||||
} else if ((temp = WinHasOption(aFeatures, "height",
|
||||
height - chromeHeight, nsnull))) {
|
||||
height = temp;
|
||||
sizeChromeHeight = PR_FALSE;
|
||||
sizeSpecified = PR_TRUE;
|
||||
} else if ((temp = WinHasOption(aFeatures, "innerHeight",
|
||||
height - chromeHeight, nsnull))) {
|
||||
height = temp;
|
||||
sizeChromeHeight = PR_FALSE;
|
||||
sizeSpecified = PR_TRUE;
|
||||
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;
|
||||
|
||||
|
@ -1686,7 +1864,7 @@ nsWindowWatcher::SizeOpenedDocShellItem(nsIDocShellTreeItem *aDocShellItem,
|
|||
screen->GetAvailRect(&screenLeft, &screenTop,
|
||||
&screenWidth, &screenHeight);
|
||||
|
||||
if (sizeSpecified) {
|
||||
if (aSizeSpec.SizeSpecified()) {
|
||||
/* Unlike position, force size out-of-bounds check only if
|
||||
size actually was specified. Otherwise, intrinsically sized
|
||||
windows are broken. */
|
||||
|
@ -1717,7 +1895,7 @@ nsWindowWatcher::SizeOpenedDocShellItem(nsIDocShellTreeItem *aDocShellItem,
|
|||
|
||||
if (positionSpecified)
|
||||
treeOwnerAsWin->SetPosition(left, top);
|
||||
if (sizeSpecified) {
|
||||
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. */
|
||||
|
|
|
@ -59,6 +59,7 @@ struct JSContext;
|
|||
struct JSObject;
|
||||
struct nsWatcherWindowEntry;
|
||||
struct PRLock;
|
||||
struct SizeSpec;
|
||||
|
||||
class nsWindowWatcher :
|
||||
public nsIWindowWatcher,
|
||||
|
@ -84,12 +85,38 @@ private:
|
|||
nsWatcherWindowEntry *FindWindowEntry(nsIDOMWindow *aWindow);
|
||||
nsresult RemoveWindow(nsWatcherWindowEntry *inInfo);
|
||||
|
||||
// Get the caller tree item. Look on the JS stack, then fall back
|
||||
// to the parent if there's nothing there.
|
||||
already_AddRefed<nsIDocShellTreeItem>
|
||||
GetCallerTreeItem(nsIDocShellTreeItem* aParentItem);
|
||||
|
||||
// Unlike GetWindowByName this will look for a caller on the JS
|
||||
// stack, and then fall back on aCurrentWindow if it can't find one.
|
||||
nsresult SafeGetWindowByName(const nsAString& aName,
|
||||
nsIDOMWindow* aCurrentWindow,
|
||||
nsIDOMWindow** aResult);
|
||||
|
||||
// Just like OpenWindowJS, but knows whether it got called via OpenWindowJS
|
||||
// (which means called from script) or called via OpenWindow.
|
||||
nsresult OpenWindowJSInternal(nsIDOMWindow *aParent,
|
||||
const char *aUrl,
|
||||
const char *aName,
|
||||
const char *aFeatures,
|
||||
PRBool aDialog,
|
||||
PRUint32 argc,
|
||||
jsval *argv,
|
||||
PRBool aCalledFromJS,
|
||||
nsIDOMWindow **_retval);
|
||||
|
||||
static JSContext *GetJSContextFromWindow(nsIDOMWindow *aWindow);
|
||||
static JSContext *GetJSContextFromCallStack();
|
||||
static nsresult URIfromURL(const char *aURL,
|
||||
nsIDOMWindow *aParent,
|
||||
nsIURI **aURI);
|
||||
#ifdef DEBUG
|
||||
static void CheckWindowName(nsString& aName);
|
||||
#endif
|
||||
|
||||
static PRUint32 CalculateChromeFlags(const char *aFeatures,
|
||||
PRBool aFeaturesSpecified,
|
||||
PRBool aDialog,
|
||||
|
@ -97,13 +124,14 @@ private:
|
|||
PRBool aHasChromeParent);
|
||||
static PRInt32 WinHasOption(const char *aOptions, const char *aName,
|
||||
PRInt32 aDefault, PRBool *aPresenceFlag);
|
||||
/* Compute the right SizeSpec based on aFeatures */
|
||||
static void CalcSizeSpec(const char* aFeatures, SizeSpec& aResult);
|
||||
static nsresult ReadyOpenedDocShellItem(nsIDocShellTreeItem *aOpenedItem,
|
||||
nsIDOMWindow *aParent,
|
||||
nsIDOMWindow **aOpenedWindow);
|
||||
static void SizeOpenedDocShellItem(nsIDocShellTreeItem *aDocShellItem,
|
||||
nsIDOMWindow *aParent,
|
||||
const char *aFeatures,
|
||||
PRUint32 aChromeFlags);
|
||||
const SizeSpec & aSizeSpec);
|
||||
static nsresult AttachArguments(nsIDOMWindow *aWindow,
|
||||
PRUint32 argc, jsval *argv);
|
||||
static nsresult ConvertSupportsTojsvals(nsIDOMWindow *aWindow,
|
||||
|
|
|
@ -71,6 +71,7 @@ REQUIRES = xpcom \
|
|||
xpconnect \
|
||||
intl \
|
||||
windowwatcher \
|
||||
embed_base \
|
||||
caps \
|
||||
unicharutil \
|
||||
uconv \
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMNodeList.h"
|
||||
#include "nsIDOMWindowInternal.h"
|
||||
#include "nsIDOMChromeWindow.h"
|
||||
#include "nsIBrowserDOMWindow.h"
|
||||
#include "nsIDOMXULElement.h"
|
||||
#include "nsIEmbeddingSiteWindow.h"
|
||||
#include "nsIEmbeddingSiteWindow2.h"
|
||||
|
@ -60,6 +62,9 @@
|
|||
#include "nsIPrincipal.h"
|
||||
#include "nsIURIFixup.h"
|
||||
#include "nsCDefaultURIFixup.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
|
@ -116,6 +121,9 @@ NS_INTERFACE_MAP_BEGIN(nsContentTreeOwner)
|
|||
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
|
||||
// XXXbz why not just implement those interfaces directly on this object?
|
||||
// Should file a followup and fix.
|
||||
NS_INTERFACE_MAP_ENTRY_AGGREGATED(nsIEmbeddingSiteWindow, mSiteWindow2)
|
||||
NS_INTERFACE_MAP_ENTRY_AGGREGATED(nsIEmbeddingSiteWindow2, mSiteWindow2)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
@ -682,6 +690,108 @@ NS_IMETHODIMP nsContentTreeOwner::SetTitle(const PRUnichar* aTitle)
|
|||
return mXULWindow->SetTitle(title.get());
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsContentTreeOwner: nsIWindowProvider
|
||||
//*****************************************************************************
|
||||
NS_IMETHODIMP
|
||||
nsContentTreeOwner::ProvideWindow(nsIDOMWindow* aParent,
|
||||
PRUint32 aChromeFlags,
|
||||
PRBool aPositionSpecified,
|
||||
PRBool aSizeSpecified,
|
||||
nsIURI* aURI,
|
||||
const nsAString& aName,
|
||||
const nsACString& aFeatures,
|
||||
nsIDOMWindow** aReturn)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aParent);
|
||||
|
||||
*aReturn = nsnull;
|
||||
|
||||
if (!mXULWindow) {
|
||||
// Nothing to do here
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIWebNavigation> parentNav = do_GetInterface(aParent);
|
||||
nsCOMPtr<nsIDocShellTreeOwner> parentOwner = do_GetInterface(parentNav);
|
||||
NS_ASSERTION(SameCOMIdentity(parentOwner,
|
||||
NS_STATIC_CAST(nsIDocShellTreeOwner*, this)),
|
||||
"Parent from wrong docshell tree?");
|
||||
#endif
|
||||
|
||||
// First check what our prefs say
|
||||
nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (!prefs) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> branch;
|
||||
prefs->GetBranch("browser.link.", getter_AddRefs(branch));
|
||||
if (!branch) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Where should we open this?
|
||||
PRInt32 containerPref;
|
||||
if (NS_FAILED(branch->GetIntPref("open_newwindow", &containerPref))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (containerPref != nsIBrowserDOMWindow::OPEN_NEWTAB &&
|
||||
containerPref != nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
|
||||
// Just open a window normally
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Now check our restriction pref. The restriction pref is a power-user's
|
||||
fine-tuning pref. values:
|
||||
0: no restrictions - divert everything
|
||||
1: don't divert window.open at all
|
||||
2: don't divert window.open with features
|
||||
*/
|
||||
PRInt32 restrictionPref;
|
||||
if (NS_FAILED(branch->GetIntPref("open_newwindow.restriction",
|
||||
&restrictionPref)) ||
|
||||
restrictionPref < 0 ||
|
||||
restrictionPref > 2) {
|
||||
restrictionPref = 2; // Sane default behavior
|
||||
}
|
||||
|
||||
if (restrictionPref == 1) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (restrictionPref == 2 &&
|
||||
// Only continue if there are no size/position features and no special
|
||||
// chrome flags.
|
||||
(aChromeFlags != nsIWebBrowserChrome::CHROME_ALL ||
|
||||
aPositionSpecified || aSizeSpecified)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMWindowInternal> domWin;
|
||||
mXULWindow->GetWindowDOMWindow(getter_AddRefs(domWin));
|
||||
nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(domWin);
|
||||
if (!chromeWin) {
|
||||
// Really odd... but whatever
|
||||
NS_WARNING("nsXULWindow's DOMWindow is not a chrome window");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
|
||||
chromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
|
||||
if (!browserDOMWin) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get a new rendering area from the browserDOMWin. To make this
|
||||
// safe for cases when it'll try to return an existing window or
|
||||
// something, get it with a null URI.
|
||||
return browserDOMWin->OpenURI(nsnull, aParent, containerPref,
|
||||
nsIBrowserDOMWindow::OPEN_NEW, aReturn);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsContentTreeOwner: Accessors
|
||||
//*****************************************************************************
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIWebBrowserChrome2.h"
|
||||
#include "nsIWindowProvider.h"
|
||||
|
||||
class nsXULWindow;
|
||||
class nsSiteWindow2;
|
||||
|
@ -57,7 +58,8 @@ class nsSiteWindow2;
|
|||
class nsContentTreeOwner : public nsIDocShellTreeOwner,
|
||||
public nsIBaseWindow,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIWebBrowserChrome2
|
||||
public nsIWebBrowserChrome2,
|
||||
public nsIWindowProvider
|
||||
{
|
||||
friend class nsXULWindow;
|
||||
friend class nsSiteWindow2;
|
||||
|
@ -70,6 +72,7 @@ public:
|
|||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIWEBBROWSERCHROME
|
||||
NS_DECL_NSIWEBBROWSERCHROME2
|
||||
NS_DECL_NSIWINDOWPROVIDER
|
||||
|
||||
protected:
|
||||
nsContentTreeOwner(PRBool fPrimary);
|
||||
|
|
Загрузка…
Ссылка в новой задаче