1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2123 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=78: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +//#define USEWEAKREFS // (haven't quite figured that out yet) 1.11 + 1.12 +#include "nsWindowWatcher.h" 1.13 +#include "nsAutoWindowStateHelper.h" 1.14 + 1.15 +#include "nsCRT.h" 1.16 +#include "nsNetUtil.h" 1.17 +#include "nsJSUtils.h" 1.18 +#include "plstr.h" 1.19 + 1.20 +#include "nsIBaseWindow.h" 1.21 +#include "nsIDocShell.h" 1.22 +#include "nsIDocShellLoadInfo.h" 1.23 +#include "nsIDocShellTreeItem.h" 1.24 +#include "nsIDocShellTreeOwner.h" 1.25 +#include "nsIDocumentLoader.h" 1.26 +#include "nsIDocument.h" 1.27 +#include "nsIDOMDocument.h" 1.28 +#include "nsIDOMWindow.h" 1.29 +#include "nsIDOMChromeWindow.h" 1.30 +#include "nsIDOMModalContentWindow.h" 1.31 +#include "nsIPrompt.h" 1.32 +#include "nsIScriptObjectPrincipal.h" 1.33 +#include "nsIScreen.h" 1.34 +#include "nsIScreenManager.h" 1.35 +#include "nsIScriptContext.h" 1.36 +#include "nsIObserverService.h" 1.37 +#include "nsIScriptGlobalObject.h" 1.38 +#include "nsIScriptSecurityManager.h" 1.39 +#include "nsXPCOM.h" 1.40 +#include "nsIURI.h" 1.41 +#include "nsIWebBrowser.h" 1.42 +#include "nsIWebBrowserChrome.h" 1.43 +#include "nsIWebNavigation.h" 1.44 +#include "nsIWindowCreator.h" 1.45 +#include "nsIWindowCreator2.h" 1.46 +#include "nsIXPConnect.h" 1.47 +#include "nsIXULRuntime.h" 1.48 +#include "nsPIDOMWindow.h" 1.49 +#include "nsIMarkupDocumentViewer.h" 1.50 +#include "nsIContentViewer.h" 1.51 +#include "nsIWindowProvider.h" 1.52 +#include "nsIMutableArray.h" 1.53 +#include "nsISupportsArray.h" 1.54 +#include "nsIDOMStorage.h" 1.55 +#include "nsIDOMStorageManager.h" 1.56 +#include "nsIWidget.h" 1.57 +#include "nsFocusManager.h" 1.58 +#include "nsIPresShell.h" 1.59 +#include "nsPresContext.h" 1.60 +#include "nsContentUtils.h" 1.61 +#include "nsCxPusher.h" 1.62 +#include "nsIPrefBranch.h" 1.63 +#include "nsIPrefService.h" 1.64 +#include "nsSandboxFlags.h" 1.65 +#include "mozilla/Preferences.h" 1.66 + 1.67 +#ifdef USEWEAKREFS 1.68 +#include "nsIWeakReference.h" 1.69 +#endif 1.70 + 1.71 +using namespace mozilla; 1.72 + 1.73 +/**************************************************************** 1.74 + ******************** nsWatcherWindowEntry ********************** 1.75 + ****************************************************************/ 1.76 + 1.77 +class nsWindowWatcher; 1.78 + 1.79 +struct nsWatcherWindowEntry { 1.80 + 1.81 + nsWatcherWindowEntry(nsIDOMWindow *inWindow, nsIWebBrowserChrome *inChrome) { 1.82 +#ifdef USEWEAKREFS 1.83 + mWindow = do_GetWeakReference(inWindow); 1.84 +#else 1.85 + mWindow = inWindow; 1.86 +#endif 1.87 + nsCOMPtr<nsISupportsWeakReference> supportsweak(do_QueryInterface(inChrome)); 1.88 + if (supportsweak) { 1.89 + supportsweak->GetWeakReference(getter_AddRefs(mChromeWeak)); 1.90 + } else { 1.91 + mChrome = inChrome; 1.92 + mChromeWeak = 0; 1.93 + } 1.94 + ReferenceSelf(); 1.95 + } 1.96 + ~nsWatcherWindowEntry() {} 1.97 + 1.98 + void InsertAfter(nsWatcherWindowEntry *inOlder); 1.99 + void Unlink(); 1.100 + void ReferenceSelf(); 1.101 + 1.102 +#ifdef USEWEAKREFS 1.103 + nsCOMPtr<nsIWeakReference> mWindow; 1.104 +#else // still not an owning ref 1.105 + nsIDOMWindow *mWindow; 1.106 +#endif 1.107 + nsIWebBrowserChrome *mChrome; 1.108 + nsWeakPtr mChromeWeak; 1.109 + // each struct is in a circular, doubly-linked list 1.110 + nsWatcherWindowEntry *mYounger, // next younger in sequence 1.111 + *mOlder; 1.112 +}; 1.113 + 1.114 +void nsWatcherWindowEntry::InsertAfter(nsWatcherWindowEntry *inOlder) 1.115 +{ 1.116 + if (inOlder) { 1.117 + mOlder = inOlder; 1.118 + mYounger = inOlder->mYounger; 1.119 + mOlder->mYounger = this; 1.120 + if (mOlder->mOlder == mOlder) 1.121 + mOlder->mOlder = this; 1.122 + mYounger->mOlder = this; 1.123 + if (mYounger->mYounger == mYounger) 1.124 + mYounger->mYounger = this; 1.125 + } 1.126 +} 1.127 + 1.128 +void nsWatcherWindowEntry::Unlink() { 1.129 + 1.130 + mOlder->mYounger = mYounger; 1.131 + mYounger->mOlder = mOlder; 1.132 + ReferenceSelf(); 1.133 +} 1.134 + 1.135 +void nsWatcherWindowEntry::ReferenceSelf() { 1.136 + 1.137 + mYounger = this; 1.138 + mOlder = this; 1.139 +} 1.140 + 1.141 +/**************************************************************** 1.142 + ****************** nsWatcherWindowEnumerator ******************* 1.143 + ****************************************************************/ 1.144 + 1.145 +class nsWatcherWindowEnumerator : public nsISimpleEnumerator { 1.146 + 1.147 +public: 1.148 + nsWatcherWindowEnumerator(nsWindowWatcher *inWatcher); 1.149 + virtual ~nsWatcherWindowEnumerator(); 1.150 + NS_IMETHOD HasMoreElements(bool *retval); 1.151 + NS_IMETHOD GetNext(nsISupports **retval); 1.152 + 1.153 + NS_DECL_ISUPPORTS 1.154 + 1.155 +private: 1.156 + friend class nsWindowWatcher; 1.157 + 1.158 + nsWatcherWindowEntry *FindNext(); 1.159 + void WindowRemoved(nsWatcherWindowEntry *inInfo); 1.160 + 1.161 + nsWindowWatcher *mWindowWatcher; 1.162 + nsWatcherWindowEntry *mCurrentPosition; 1.163 +}; 1.164 + 1.165 +NS_IMPL_ADDREF(nsWatcherWindowEnumerator) 1.166 +NS_IMPL_RELEASE(nsWatcherWindowEnumerator) 1.167 +NS_IMPL_QUERY_INTERFACE(nsWatcherWindowEnumerator, nsISimpleEnumerator) 1.168 + 1.169 +nsWatcherWindowEnumerator::nsWatcherWindowEnumerator(nsWindowWatcher *inWatcher) 1.170 + : mWindowWatcher(inWatcher), 1.171 + mCurrentPosition(inWatcher->mOldestWindow) 1.172 +{ 1.173 + mWindowWatcher->AddEnumerator(this); 1.174 + mWindowWatcher->AddRef(); 1.175 +} 1.176 + 1.177 +nsWatcherWindowEnumerator::~nsWatcherWindowEnumerator() 1.178 +{ 1.179 + mWindowWatcher->RemoveEnumerator(this); 1.180 + mWindowWatcher->Release(); 1.181 +} 1.182 + 1.183 +NS_IMETHODIMP 1.184 +nsWatcherWindowEnumerator::HasMoreElements(bool *retval) 1.185 +{ 1.186 + if (!retval) 1.187 + return NS_ERROR_INVALID_ARG; 1.188 + 1.189 + *retval = mCurrentPosition? true : false; 1.190 + return NS_OK; 1.191 +} 1.192 + 1.193 +NS_IMETHODIMP 1.194 +nsWatcherWindowEnumerator::GetNext(nsISupports **retval) 1.195 +{ 1.196 + if (!retval) 1.197 + return NS_ERROR_INVALID_ARG; 1.198 + 1.199 + *retval = nullptr; 1.200 + 1.201 +#ifdef USEWEAKREFS 1.202 + while (mCurrentPosition) { 1.203 + CallQueryReferent(mCurrentPosition->mWindow, retval); 1.204 + if (*retval) { 1.205 + mCurrentPosition = FindNext(); 1.206 + break; 1.207 + } else // window is gone! 1.208 + mWindowWatcher->RemoveWindow(mCurrentPosition); 1.209 + } 1.210 + NS_IF_ADDREF(*retval); 1.211 +#else 1.212 + if (mCurrentPosition) { 1.213 + CallQueryInterface(mCurrentPosition->mWindow, retval); 1.214 + mCurrentPosition = FindNext(); 1.215 + } 1.216 +#endif 1.217 + return NS_OK; 1.218 +} 1.219 + 1.220 +nsWatcherWindowEntry * 1.221 +nsWatcherWindowEnumerator::FindNext() 1.222 +{ 1.223 + nsWatcherWindowEntry *info; 1.224 + 1.225 + if (!mCurrentPosition) 1.226 + return 0; 1.227 + 1.228 + info = mCurrentPosition->mYounger; 1.229 + return info == mWindowWatcher->mOldestWindow ? 0 : info; 1.230 +} 1.231 + 1.232 +// if a window is being removed adjust the iterator's current position 1.233 +void nsWatcherWindowEnumerator::WindowRemoved(nsWatcherWindowEntry *inInfo) { 1.234 + 1.235 + if (mCurrentPosition == inInfo) 1.236 + mCurrentPosition = mCurrentPosition != inInfo->mYounger ? 1.237 + inInfo->mYounger : 0; 1.238 +} 1.239 + 1.240 +/**************************************************************** 1.241 + *********************** nsWindowWatcher ************************ 1.242 + ****************************************************************/ 1.243 + 1.244 +NS_IMPL_ADDREF(nsWindowWatcher) 1.245 +NS_IMPL_RELEASE(nsWindowWatcher) 1.246 +NS_IMPL_QUERY_INTERFACE(nsWindowWatcher, 1.247 + nsIWindowWatcher, 1.248 + nsIPromptFactory, 1.249 + nsPIWindowWatcher) 1.250 + 1.251 +nsWindowWatcher::nsWindowWatcher() : 1.252 + mEnumeratorList(), 1.253 + mOldestWindow(0), 1.254 + mListLock("nsWindowWatcher.mListLock") 1.255 +{ 1.256 +} 1.257 + 1.258 +nsWindowWatcher::~nsWindowWatcher() 1.259 +{ 1.260 + // delete data 1.261 + while (mOldestWindow) 1.262 + RemoveWindow(mOldestWindow); 1.263 +} 1.264 + 1.265 +nsresult 1.266 +nsWindowWatcher::Init() 1.267 +{ 1.268 + return NS_OK; 1.269 +} 1.270 + 1.271 +/** 1.272 + * Convert aArguments into either an nsIArray or nullptr. 1.273 + * 1.274 + * - If aArguments is nullptr, return nullptr. 1.275 + * - If aArguments is an nsArray, return nullptr if it's empty, or otherwise 1.276 + * return the array. 1.277 + * - If aArguments is an nsISupportsArray, return nullptr if it's empty, or 1.278 + * otherwise add its elements to an nsArray and return the new array. 1.279 + * - Otherwise, return an nsIArray with one element: aArguments. 1.280 + */ 1.281 +static already_AddRefed<nsIArray> 1.282 +ConvertArgsToArray(nsISupports* aArguments) 1.283 +{ 1.284 + if (!aArguments) { 1.285 + return nullptr; 1.286 + } 1.287 + 1.288 + nsCOMPtr<nsIArray> array = do_QueryInterface(aArguments); 1.289 + if (array) { 1.290 + uint32_t argc = 0; 1.291 + array->GetLength(&argc); 1.292 + if (argc == 0) 1.293 + return nullptr; 1.294 + 1.295 + return array.forget(); 1.296 + } 1.297 + 1.298 + nsCOMPtr<nsISupportsArray> supArray = do_QueryInterface(aArguments); 1.299 + if (supArray) { 1.300 + uint32_t argc = 0; 1.301 + supArray->Count(&argc); 1.302 + if (argc == 0) { 1.303 + return nullptr; 1.304 + } 1.305 + 1.306 + nsCOMPtr<nsIMutableArray> mutableArray = 1.307 + do_CreateInstance(NS_ARRAY_CONTRACTID); 1.308 + NS_ENSURE_TRUE(mutableArray, nullptr); 1.309 + 1.310 + for (uint32_t i = 0; i < argc; i++) { 1.311 + nsCOMPtr<nsISupports> elt; 1.312 + supArray->GetElementAt(i, getter_AddRefs(elt)); 1.313 + nsresult rv = mutableArray->AppendElement(elt, /* aWeak = */ false); 1.314 + NS_ENSURE_SUCCESS(rv, nullptr); 1.315 + } 1.316 + 1.317 + return mutableArray.forget(); 1.318 + } 1.319 + 1.320 + nsCOMPtr<nsIMutableArray> singletonArray = 1.321 + do_CreateInstance(NS_ARRAY_CONTRACTID); 1.322 + NS_ENSURE_TRUE(singletonArray, nullptr); 1.323 + 1.324 + nsresult rv = singletonArray->AppendElement(aArguments, /* aWeak = */ false); 1.325 + NS_ENSURE_SUCCESS(rv, nullptr); 1.326 + 1.327 + return singletonArray.forget(); 1.328 +} 1.329 + 1.330 +NS_IMETHODIMP 1.331 +nsWindowWatcher::OpenWindow(nsIDOMWindow *aParent, 1.332 + const char *aUrl, 1.333 + const char *aName, 1.334 + const char *aFeatures, 1.335 + nsISupports *aArguments, 1.336 + nsIDOMWindow **_retval) 1.337 +{ 1.338 + nsCOMPtr<nsIArray> argv = ConvertArgsToArray(aArguments); 1.339 + 1.340 + uint32_t argc = 0; 1.341 + if (argv) { 1.342 + argv->GetLength(&argc); 1.343 + } 1.344 + bool dialog = (argc != 0); 1.345 + 1.346 + return OpenWindowInternal(aParent, aUrl, aName, aFeatures, 1.347 + /* calledFromJS = */ false, dialog, 1.348 + /* navigate = */ true, argv, _retval); 1.349 +} 1.350 + 1.351 +struct SizeSpec { 1.352 + SizeSpec() : 1.353 + mLeftSpecified(false), 1.354 + mTopSpecified(false), 1.355 + mOuterWidthSpecified(false), 1.356 + mOuterHeightSpecified(false), 1.357 + mInnerWidthSpecified(false), 1.358 + mInnerHeightSpecified(false), 1.359 + mUseDefaultWidth(false), 1.360 + mUseDefaultHeight(false) 1.361 + {} 1.362 + 1.363 + int32_t mLeft; 1.364 + int32_t mTop; 1.365 + int32_t mOuterWidth; // Total window width 1.366 + int32_t mOuterHeight; // Total window height 1.367 + int32_t mInnerWidth; // Content area width 1.368 + int32_t mInnerHeight; // Content area height 1.369 + 1.370 + bool mLeftSpecified; 1.371 + bool mTopSpecified; 1.372 + bool mOuterWidthSpecified; 1.373 + bool mOuterHeightSpecified; 1.374 + bool mInnerWidthSpecified; 1.375 + bool mInnerHeightSpecified; 1.376 + 1.377 + // If these booleans are true, don't look at the corresponding width values 1.378 + // even if they're specified -- they'll be bogus 1.379 + bool mUseDefaultWidth; 1.380 + bool mUseDefaultHeight; 1.381 + 1.382 + bool PositionSpecified() const { 1.383 + return mLeftSpecified || mTopSpecified; 1.384 + } 1.385 + 1.386 + bool SizeSpecified() const { 1.387 + return mOuterWidthSpecified || mOuterHeightSpecified || 1.388 + mInnerWidthSpecified || mInnerHeightSpecified; 1.389 + } 1.390 +}; 1.391 + 1.392 +NS_IMETHODIMP 1.393 +nsWindowWatcher::OpenWindow2(nsIDOMWindow *aParent, 1.394 + const char *aUrl, 1.395 + const char *aName, 1.396 + const char *aFeatures, 1.397 + bool aCalledFromScript, 1.398 + bool aDialog, 1.399 + bool aNavigate, 1.400 + nsISupports *aArguments, 1.401 + nsIDOMWindow **_retval) 1.402 +{ 1.403 + nsCOMPtr<nsIArray> argv = ConvertArgsToArray(aArguments); 1.404 + 1.405 + uint32_t argc = 0; 1.406 + if (argv) { 1.407 + argv->GetLength(&argc); 1.408 + } 1.409 + 1.410 + // This is extremely messed up, but this behavior is necessary because 1.411 + // callers lie about whether they're a dialog window and whether they're 1.412 + // called from script. Fixing this is bug 779939. 1.413 + bool dialog = aDialog; 1.414 + if (!aCalledFromScript) { 1.415 + dialog = argc > 0; 1.416 + } 1.417 + 1.418 + return OpenWindowInternal(aParent, aUrl, aName, aFeatures, 1.419 + aCalledFromScript, dialog, 1.420 + aNavigate, argv, _retval); 1.421 +} 1.422 + 1.423 +nsresult 1.424 +nsWindowWatcher::OpenWindowInternal(nsIDOMWindow *aParent, 1.425 + const char *aUrl, 1.426 + const char *aName, 1.427 + const char *aFeatures, 1.428 + bool aCalledFromJS, 1.429 + bool aDialog, 1.430 + bool aNavigate, 1.431 + nsIArray *argv, 1.432 + nsIDOMWindow **_retval) 1.433 +{ 1.434 + nsresult rv = NS_OK; 1.435 + bool nameSpecified, 1.436 + featuresSpecified, 1.437 + isNewToplevelWindow = false, 1.438 + windowIsNew = false, 1.439 + windowNeedsName = false, 1.440 + windowIsModal = false, 1.441 + uriToLoadIsChrome = false, 1.442 + windowIsModalContentDialog = false; 1.443 + uint32_t chromeFlags; 1.444 + nsAutoString name; // string version of aName 1.445 + nsAutoCString features; // string version of aFeatures 1.446 + nsCOMPtr<nsIURI> uriToLoad; // from aUrl, if any 1.447 + nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner; // from the parent window, if any 1.448 + nsCOMPtr<nsIDocShellTreeItem> newDocShellItem; // from the new window 1.449 + nsCxPusher callerContextGuard; 1.450 + 1.451 + NS_ENSURE_ARG_POINTER(_retval); 1.452 + *_retval = 0; 1.453 + 1.454 + if (!nsContentUtils::IsSafeToRunScript()) { 1.455 + return NS_ERROR_FAILURE; 1.456 + } 1.457 + 1.458 + GetWindowTreeOwner(aParent, getter_AddRefs(parentTreeOwner)); 1.459 + 1.460 + if (aUrl) { 1.461 + rv = URIfromURL(aUrl, aParent, getter_AddRefs(uriToLoad)); 1.462 + if (NS_FAILED(rv)) 1.463 + return rv; 1.464 + uriToLoad->SchemeIs("chrome", &uriToLoadIsChrome); 1.465 + } 1.466 + 1.467 + nameSpecified = false; 1.468 + if (aName) { 1.469 + CopyUTF8toUTF16(aName, name); 1.470 + nameSpecified = true; 1.471 + } 1.472 + 1.473 + featuresSpecified = false; 1.474 + if (aFeatures) { 1.475 + features.Assign(aFeatures); 1.476 + featuresSpecified = true; 1.477 + features.StripWhitespace(); 1.478 + } 1.479 + 1.480 + // try to find an extant window with the given name 1.481 + nsCOMPtr<nsIDOMWindow> foundWindow = SafeGetWindowByName(name, aParent); 1.482 + GetWindowTreeItem(foundWindow, getter_AddRefs(newDocShellItem)); 1.483 + 1.484 + // Do sandbox checks here, instead of waiting until nsIDocShell::LoadURI. 1.485 + // The state of the window can change before this call and if we are blocked 1.486 + // because of sandboxing, we wouldn't want that to happen. 1.487 + nsCOMPtr<nsPIDOMWindow> parentWindow = do_QueryInterface(aParent); 1.488 + nsCOMPtr<nsIDocShell> parentDocShell; 1.489 + if (parentWindow) { 1.490 + parentDocShell = parentWindow->GetDocShell(); 1.491 + if (parentDocShell) { 1.492 + nsCOMPtr<nsIDocShell> foundDocShell = do_QueryInterface(newDocShellItem); 1.493 + if (parentDocShell->IsSandboxedFrom(foundDocShell)) { 1.494 + return NS_ERROR_DOM_INVALID_ACCESS_ERR; 1.495 + } 1.496 + } 1.497 + } 1.498 + 1.499 + // no extant window? make a new one. 1.500 + 1.501 + // If no parent, consider it chrome. 1.502 + bool hasChromeParent = true; 1.503 + if (aParent) { 1.504 + // Check if the parent document has chrome privileges. 1.505 + nsCOMPtr<nsIDOMDocument> domdoc; 1.506 + aParent->GetDocument(getter_AddRefs(domdoc)); 1.507 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc); 1.508 + hasChromeParent = doc && nsContentUtils::IsChromeDoc(doc); 1.509 + } 1.510 + 1.511 + // Make sure we call CalculateChromeFlags() *before* we push the 1.512 + // callee context onto the context stack so that 1.513 + // CalculateChromeFlags() sees the actual caller when doing its 1.514 + // security checks. 1.515 + chromeFlags = CalculateChromeFlags(aParent, features.get(), featuresSpecified, 1.516 + aDialog, uriToLoadIsChrome, 1.517 + hasChromeParent); 1.518 + 1.519 + // If we're not called through our JS version of the API, and we got 1.520 + // our internal modal option, treat the window we're opening as a 1.521 + // modal content window (and set the modal chrome flag). 1.522 + if (!aCalledFromJS && argv && 1.523 + WinHasOption(features.get(), "-moz-internal-modal", 0, nullptr)) { 1.524 + windowIsModalContentDialog = true; 1.525 + 1.526 + // CHROME_MODAL gets inherited by dependent windows, which affects various 1.527 + // platform-specific window state (especially on OSX). So we need some way 1.528 + // to determine that this window was actually opened by nsGlobalWindow:: 1.529 + // ShowModalDialog(), and that somebody is actually going to be watching 1.530 + // for return values and all that. 1.531 + chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL_CONTENT_WINDOW; 1.532 + chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL; 1.533 + } 1.534 + 1.535 + SizeSpec sizeSpec; 1.536 + CalcSizeSpec(features.get(), sizeSpec); 1.537 + 1.538 + nsCOMPtr<nsIScriptSecurityManager> 1.539 + sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); 1.540 + 1.541 + bool isCallerChrome = nsContentUtils::IsCallerChrome(); 1.542 + 1.543 + JSContext *cx = GetJSContextFromWindow(aParent); 1.544 + 1.545 + bool windowTypeIsChrome = chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME; 1.546 + if (isCallerChrome && !hasChromeParent && !windowTypeIsChrome && cx) { 1.547 + // open() is called from chrome on a non-chrome window, push the context of the 1.548 + // callee onto the context stack to prevent the caller's priveleges from leaking 1.549 + // into code that runs while opening the new window. 1.550 + // 1.551 + // The reasoning for this is in bug 289204. Basically, chrome sometimes does 1.552 + // someContentWindow.open(untrustedURL), and wants to be insulated from nasty 1.553 + // javascript: URLs and such. But there are also cases where we create a 1.554 + // window parented to a content window (such as a download dialog), usually 1.555 + // directly with nsIWindowWatcher. In those cases, we want the principal of 1.556 + // the initial about:blank document to be system, so that the subsequent XUL 1.557 + // load can reuse the inner window and avoid blowing away expandos. As such, 1.558 + // we decide whether to load with the principal of the caller or of the parent 1.559 + // based on whether the docshell type is chrome or content. 1.560 + 1.561 + callerContextGuard.Push(cx); 1.562 + } 1.563 + 1.564 + uint32_t activeDocsSandboxFlags = 0; 1.565 + if (!newDocShellItem) { 1.566 + // We're going to either open up a new window ourselves or ask a 1.567 + // nsIWindowProvider for one. In either case, we'll want to set the right 1.568 + // name on it. 1.569 + windowNeedsName = true; 1.570 + 1.571 + // If the parent trying to open a new window is sandboxed 1.572 + // without 'allow-popups', this is not allowed and we fail here. 1.573 + if (aParent) { 1.574 + nsCOMPtr<nsIDOMDocument> domdoc; 1.575 + aParent->GetDocument(getter_AddRefs(domdoc)); 1.576 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc); 1.577 + 1.578 + if (doc) { 1.579 + // Save sandbox flags for copying to new browsing context (docShell). 1.580 + activeDocsSandboxFlags = doc->GetSandboxFlags(); 1.581 + if (activeDocsSandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) { 1.582 + return NS_ERROR_DOM_INVALID_ACCESS_ERR; 1.583 + } 1.584 + } 1.585 + } 1.586 + 1.587 + // Now check whether it's ok to ask a window provider for a window. Don't 1.588 + // do it if we're opening a dialog or if our parent is a chrome window or 1.589 + // if we're opening something that has modal, dialog, or chrome flags set. 1.590 + nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(aParent); 1.591 + if (!aDialog && !chromeWin && 1.592 + !(chromeFlags & (nsIWebBrowserChrome::CHROME_MODAL | 1.593 + nsIWebBrowserChrome::CHROME_OPENAS_DIALOG | 1.594 + nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) { 1.595 + nsCOMPtr<nsIWindowProvider> provider = do_GetInterface(parentTreeOwner); 1.596 + if (provider) { 1.597 + NS_ASSERTION(aParent, "We've _got_ to have a parent here!"); 1.598 + 1.599 + nsCOMPtr<nsIDOMWindow> newWindow; 1.600 + rv = provider->ProvideWindow(aParent, chromeFlags, aCalledFromJS, 1.601 + sizeSpec.PositionSpecified(), 1.602 + sizeSpec.SizeSpecified(), 1.603 + uriToLoad, name, features, &windowIsNew, 1.604 + getter_AddRefs(newWindow)); 1.605 + 1.606 + if (NS_SUCCEEDED(rv)) { 1.607 + GetWindowTreeItem(newWindow, getter_AddRefs(newDocShellItem)); 1.608 + if (windowIsNew && newDocShellItem) { 1.609 + // Make sure to stop any loads happening in this window that the 1.610 + // window provider might have started. Otherwise if our caller 1.611 + // manipulates the window it just opened and then the load 1.612 + // completes their stuff will get blown away. 1.613 + nsCOMPtr<nsIWebNavigation> webNav = 1.614 + do_QueryInterface(newDocShellItem); 1.615 + webNav->Stop(nsIWebNavigation::STOP_NETWORK); 1.616 + } 1.617 + } 1.618 + else if (rv == NS_ERROR_ABORT) { 1.619 + // NS_ERROR_ABORT means the window provider has flat-out rejected 1.620 + // the open-window call and we should bail. Don't return an error 1.621 + // here, because our caller may propagate that error, which might 1.622 + // cause e.g. window.open to throw! Just return null for our out 1.623 + // param. 1.624 + return NS_OK; 1.625 + } 1.626 + } 1.627 + } 1.628 + } 1.629 + 1.630 + bool newWindowShouldBeModal = false; 1.631 + bool parentIsModal = false; 1.632 + if (!newDocShellItem) { 1.633 + windowIsNew = true; 1.634 + isNewToplevelWindow = true; 1.635 + 1.636 + nsCOMPtr<nsIWebBrowserChrome> parentChrome(do_GetInterface(parentTreeOwner)); 1.637 + 1.638 + // is the parent (if any) modal? if so, we must be, too. 1.639 + bool weAreModal = (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL) != 0; 1.640 + newWindowShouldBeModal = weAreModal; 1.641 + if (!weAreModal && parentChrome) { 1.642 + parentChrome->IsWindowModal(&weAreModal); 1.643 + parentIsModal = weAreModal; 1.644 + } 1.645 + 1.646 + if (weAreModal) { 1.647 + windowIsModal = true; 1.648 + // in case we added this because weAreModal 1.649 + chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL | 1.650 + nsIWebBrowserChrome::CHROME_DEPENDENT; 1.651 + } 1.652 + 1.653 + // Make sure to not create modal windows if our parent is invisible and 1.654 + // isn't a chrome window. Otherwise we can end up in a bizarre situation 1.655 + // where we can't shut down because an invisible window is open. If 1.656 + // someone tries to do this, throw. 1.657 + if (!hasChromeParent && (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL)) { 1.658 + nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(parentTreeOwner)); 1.659 + nsCOMPtr<nsIWidget> parentWidget; 1.660 + if (parentWindow) 1.661 + parentWindow->GetMainWidget(getter_AddRefs(parentWidget)); 1.662 + // NOTE: the logic for this visibility check is duplicated in 1.663 + // nsIDOMWindowUtils::isParentWindowMainWidgetVisible - if we change 1.664 + // how a window is determined "visible" in this context then we should 1.665 + // also adjust that attribute and/or any consumers of it... 1.666 + if (parentWidget && !parentWidget->IsVisible()) 1.667 + return NS_ERROR_NOT_AVAILABLE; 1.668 + } 1.669 + 1.670 + NS_ASSERTION(mWindowCreator, 1.671 + "attempted to open a new window with no WindowCreator"); 1.672 + rv = NS_ERROR_FAILURE; 1.673 + if (mWindowCreator) { 1.674 + nsCOMPtr<nsIWebBrowserChrome> newChrome; 1.675 + 1.676 + /* If the window creator is an nsIWindowCreator2, we can give it 1.677 + some hints. The only hint at this time is whether the opening window 1.678 + is in a situation that's likely to mean this is an unrequested 1.679 + popup window we're creating. However we're not completely honest: 1.680 + we clear that indicator if the opener is chrome, so that the 1.681 + downstream consumer can treat the indicator to mean simply 1.682 + that the new window is subject to popup control. */ 1.683 + nsCOMPtr<nsIWindowCreator2> windowCreator2(do_QueryInterface(mWindowCreator)); 1.684 + if (windowCreator2) { 1.685 + uint32_t contextFlags = 0; 1.686 + bool popupConditions = false; 1.687 + 1.688 + // is the parent under popup conditions? 1.689 + if (parentWindow) { 1.690 + popupConditions = parentWindow->IsLoadingOrRunningTimeout(); 1.691 + } 1.692 + 1.693 + // chrome is always allowed, so clear the flag if the opener is chrome 1.694 + if (popupConditions) { 1.695 + popupConditions = !isCallerChrome; 1.696 + } 1.697 + 1.698 + if (popupConditions) 1.699 + contextFlags |= nsIWindowCreator2::PARENT_IS_LOADING_OR_RUNNING_TIMEOUT; 1.700 + 1.701 + bool cancel = false; 1.702 + rv = windowCreator2->CreateChromeWindow2(parentChrome, chromeFlags, 1.703 + contextFlags, uriToLoad, 1.704 + &cancel, 1.705 + getter_AddRefs(newChrome)); 1.706 + if (NS_SUCCEEDED(rv) && cancel) { 1.707 + newChrome = 0; // just in case 1.708 + rv = NS_ERROR_ABORT; 1.709 + } 1.710 + } 1.711 + else 1.712 + rv = mWindowCreator->CreateChromeWindow(parentChrome, chromeFlags, 1.713 + getter_AddRefs(newChrome)); 1.714 + if (newChrome) { 1.715 + /* It might be a chrome nsXULWindow, in which case it won't have 1.716 + an nsIDOMWindow (primary content shell). But in that case, it'll 1.717 + be able to hand over an nsIDocShellTreeItem directly. */ 1.718 + nsCOMPtr<nsIDOMWindow> newWindow(do_GetInterface(newChrome)); 1.719 + if (newWindow) 1.720 + GetWindowTreeItem(newWindow, getter_AddRefs(newDocShellItem)); 1.721 + if (!newDocShellItem) 1.722 + newDocShellItem = do_GetInterface(newChrome); 1.723 + if (!newDocShellItem) 1.724 + rv = NS_ERROR_FAILURE; 1.725 + } 1.726 + } 1.727 + } 1.728 + 1.729 + // better have a window to use by this point 1.730 + if (!newDocShellItem) 1.731 + return rv; 1.732 + 1.733 + nsCOMPtr<nsIDocShell> newDocShell(do_QueryInterface(newDocShellItem)); 1.734 + NS_ENSURE_TRUE(newDocShell, NS_ERROR_UNEXPECTED); 1.735 + 1.736 + // Set up sandboxing attributes if the window is new. 1.737 + // The flags can only be non-zero for new windows. 1.738 + if (activeDocsSandboxFlags != 0) { 1.739 + newDocShell->SetSandboxFlags(activeDocsSandboxFlags); 1.740 + if (parentWindow) { 1.741 + newDocShell-> 1.742 + SetOnePermittedSandboxedNavigator(parentWindow->GetDocShell()); 1.743 + } 1.744 + } 1.745 + 1.746 + rv = ReadyOpenedDocShellItem(newDocShellItem, aParent, windowIsNew, _retval); 1.747 + if (NS_FAILED(rv)) 1.748 + return rv; 1.749 + 1.750 + /* disable persistence of size/position in popups (determined by 1.751 + determining whether the features parameter specifies width or height 1.752 + in any way). We consider any overriding of the window's size or position 1.753 + in the open call as disabling persistence of those attributes. 1.754 + Popup windows (which should not persist size or position) generally set 1.755 + the size. */ 1.756 + if (isNewToplevelWindow) { 1.757 + /* at the moment, the strings "height=" or "width=" never happen 1.758 + outside a size specification, so we can do this the Q&D way. */ 1.759 + 1.760 + if (PL_strcasestr(features.get(), "width=") || PL_strcasestr(features.get(), "height=")) { 1.761 + 1.762 + nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner; 1.763 + newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner)); 1.764 + if (newTreeOwner) 1.765 + newTreeOwner->SetPersistence(false, false, false); 1.766 + } 1.767 + } 1.768 + 1.769 + if ((aDialog || windowIsModalContentDialog) && argv) { 1.770 + // Set the args on the new window. 1.771 + nsCOMPtr<nsPIDOMWindow> piwin(do_QueryInterface(*_retval)); 1.772 + NS_ENSURE_TRUE(piwin, NS_ERROR_UNEXPECTED); 1.773 + 1.774 + rv = piwin->SetArguments(argv); 1.775 + NS_ENSURE_SUCCESS(rv, rv); 1.776 + } 1.777 + 1.778 + /* allow a window that we found by name to keep its name (important for cases 1.779 + like _self where the given name is different (and invalid)). Also, _blank 1.780 + is not a window name. */ 1.781 + if (windowNeedsName) { 1.782 + if (nameSpecified && !name.LowerCaseEqualsLiteral("_blank")) { 1.783 + newDocShellItem->SetName(name); 1.784 + } else { 1.785 + newDocShellItem->SetName(EmptyString()); 1.786 + } 1.787 + } 1.788 + 1.789 + // Now we have to set the right opener principal on the new window. Note 1.790 + // that we have to do this _before_ starting any URI loads, thanks to the 1.791 + // sync nature of javascript: loads. Since this is the only place where we 1.792 + // set said opener principal, we need to do it for all URIs, including 1.793 + // chrome ones. So to deal with the mess that is bug 79775, just press on in 1.794 + // a reasonable way even if GetSubjectPrincipal fails. In that case, just 1.795 + // use a null subjectPrincipal. 1.796 + nsCOMPtr<nsIPrincipal> subjectPrincipal; 1.797 + if (NS_FAILED(sm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal)))) { 1.798 + subjectPrincipal = nullptr; 1.799 + } 1.800 + 1.801 + if (windowIsNew) { 1.802 + // Now set the opener principal on the new window. Note that we need to do 1.803 + // this no matter whether we were opened from JS; if there is nothing on 1.804 + // the JS stack, just use the principal of our parent window. In those 1.805 + // cases we do _not_ set the parent window principal as the owner of the 1.806 + // load--since we really don't know who the owner is, just leave it null. 1.807 + nsCOMPtr<nsPIDOMWindow> newWindow = do_QueryInterface(*_retval); 1.808 +#ifdef DEBUG 1.809 + nsCOMPtr<nsPIDOMWindow> newDebugWindow = do_GetInterface(newDocShell); 1.810 + NS_ASSERTION(newWindow == newDebugWindow, "Different windows??"); 1.811 +#endif 1.812 + // The principal of the initial about:blank document gets set up in 1.813 + // nsWindowWatcher::AddWindow. Make sure to call it. In the common case 1.814 + // this call already happened when the window was created, but 1.815 + // SetInitialPrincipalToSubject is safe to call multiple times. 1.816 + if (newWindow) { 1.817 + newWindow->SetInitialPrincipalToSubject(); 1.818 + } 1.819 + } 1.820 + 1.821 + // If all windows should be private, make sure the new window is also 1.822 + // private. Otherwise, see if the caller has explicitly requested a 1.823 + // private or non-private window. 1.824 + bool isPrivateBrowsingWindow = 1.825 + Preferences::GetBool("browser.privatebrowsing.autostart") || 1.826 + (!!(chromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW) && 1.827 + !(chromeFlags & nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW)); 1.828 + 1.829 + // Otherwise, propagate the privacy status of the parent window, if 1.830 + // available, to the child. 1.831 + if (!isPrivateBrowsingWindow && 1.832 + !(chromeFlags & nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW)) { 1.833 + nsCOMPtr<nsIDocShellTreeItem> parentItem; 1.834 + GetWindowTreeItem(aParent, getter_AddRefs(parentItem)); 1.835 + nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(parentItem); 1.836 + if (parentContext) { 1.837 + isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing(); 1.838 + } 1.839 + } 1.840 + 1.841 + // We rely on CalculateChromeFlags to decide whether remote (out-of-process) 1.842 + // tabs should be used. 1.843 + bool isRemoteWindow = 1.844 + !!(chromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW); 1.845 + 1.846 + if (isNewToplevelWindow) { 1.847 + nsCOMPtr<nsIDocShellTreeItem> childRoot; 1.848 + newDocShellItem->GetRootTreeItem(getter_AddRefs(childRoot)); 1.849 + nsCOMPtr<nsILoadContext> childContext = do_QueryInterface(childRoot); 1.850 + if (childContext) { 1.851 + childContext->SetPrivateBrowsing(isPrivateBrowsingWindow); 1.852 + childContext->SetRemoteTabs(isRemoteWindow); 1.853 + } 1.854 + } else if (windowIsNew) { 1.855 + nsCOMPtr<nsILoadContext> childContext = do_QueryInterface(newDocShellItem); 1.856 + if (childContext) { 1.857 + childContext->SetPrivateBrowsing(isPrivateBrowsingWindow); 1.858 + childContext->SetRemoteTabs(isRemoteWindow); 1.859 + } 1.860 + } 1.861 + 1.862 + nsCOMPtr<nsIDocShellLoadInfo> loadInfo; 1.863 + if (uriToLoad && aNavigate) { // get the script principal and pass it to docshell 1.864 + 1.865 + // The historical ordering of attempts here is: 1.866 + // (1) Stack-top cx. 1.867 + // (2) cx associated with aParent. 1.868 + // (3) Safe JSContext. 1.869 + // 1.870 + // We could just use an AutoJSContext here if it weren't for (2), which 1.871 + // is probably nonsensical anyway. But we preserve the old semantics for 1.872 + // now, because this is part of a large patch where we don't want to risk 1.873 + // subtle behavioral modifications. 1.874 + cx = nsContentUtils::GetCurrentJSContext(); 1.875 + nsCxPusher pusher; 1.876 + if (!cx) { 1.877 + cx = GetJSContextFromWindow(aParent); 1.878 + if (!cx) 1.879 + cx = nsContentUtils::GetSafeJSContext(); 1.880 + pusher.Push(cx); 1.881 + } 1.882 + 1.883 + newDocShell->CreateLoadInfo(getter_AddRefs(loadInfo)); 1.884 + NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE); 1.885 + 1.886 + if (subjectPrincipal) { 1.887 + loadInfo->SetOwner(subjectPrincipal); 1.888 + } 1.889 + 1.890 + // Set the new window's referrer from the calling context's document: 1.891 + 1.892 + // get its document, if any 1.893 + JSContext* ccx = nsContentUtils::GetCurrentJSContext(); 1.894 + if (ccx) { 1.895 + nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(ccx); 1.896 + 1.897 + nsCOMPtr<nsPIDOMWindow> w(do_QueryInterface(sgo)); 1.898 + if (w) { 1.899 + /* use the URL from the *extant* document, if any. The usual accessor 1.900 + GetDocument will synchronously create an about:blank document if 1.901 + it has no better answer, and we only care about a real document. 1.902 + Also using GetDocument to force document creation seems to 1.903 + screw up focus in the hidden window; see bug 36016. 1.904 + */ 1.905 + nsCOMPtr<nsIDocument> doc = w->GetExtantDoc(); 1.906 + if (doc) { 1.907 + // Set the referrer 1.908 + loadInfo->SetReferrer(doc->GetDocumentURI()); 1.909 + } 1.910 + } 1.911 + } 1.912 + } 1.913 + 1.914 + if (isNewToplevelWindow) { 1.915 + // Notify observers that the window is open and ready. 1.916 + // The window has not yet started to load a document. 1.917 + nsCOMPtr<nsIObserverService> obsSvc = 1.918 + mozilla::services::GetObserverService(); 1.919 + if (obsSvc) 1.920 + obsSvc->NotifyObservers(*_retval, "toplevel-window-ready", nullptr); 1.921 + } 1.922 + 1.923 + if (uriToLoad && aNavigate) { 1.924 + newDocShell->LoadURI(uriToLoad, 1.925 + loadInfo, 1.926 + windowIsNew 1.927 + ? static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) 1.928 + : static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_NONE), 1.929 + true); 1.930 + } 1.931 + 1.932 + // Copy the current session storage for the current domain. 1.933 + if (subjectPrincipal && parentDocShell) { 1.934 + nsCOMPtr<nsIDOMStorageManager> parentStorageManager = do_QueryInterface(parentDocShell); 1.935 + nsCOMPtr<nsIDOMStorageManager> newStorageManager = do_QueryInterface(newDocShell); 1.936 + 1.937 + if (parentStorageManager && newStorageManager) { 1.938 + nsCOMPtr<nsIDOMStorage> storage; 1.939 + parentStorageManager->GetStorageForFirstParty(uriToLoad, subjectPrincipal, 1.940 + isPrivateBrowsingWindow, getter_AddRefs(storage)); 1.941 + if (storage) 1.942 + newStorageManager->CloneStorage(storage); 1.943 + } 1.944 + } 1.945 + 1.946 + if (isNewToplevelWindow) 1.947 + SizeOpenedDocShellItem(newDocShellItem, aParent, sizeSpec); 1.948 + 1.949 + // XXXbz isn't windowIsModal always true when windowIsModalContentDialog? 1.950 + if (windowIsModal || windowIsModalContentDialog) { 1.951 + nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner; 1.952 + newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner)); 1.953 + nsCOMPtr<nsIWebBrowserChrome> newChrome(do_GetInterface(newTreeOwner)); 1.954 + 1.955 + // Throw an exception here if no web browser chrome is available, 1.956 + // we need that to show a modal window. 1.957 + NS_ENSURE_TRUE(newChrome, NS_ERROR_NOT_AVAILABLE); 1.958 + 1.959 + // Dispatch dialog events etc, but we only want to do that if 1.960 + // we're opening a modal content window (the helper classes are 1.961 + // no-ops if given no window), for chrome dialogs we don't want to 1.962 + // do any of that (it's done elsewhere for us). 1.963 + // Make sure we maintain the state on an outer window, because 1.964 + // that's where it lives; inner windows assert if you try to 1.965 + // maintain the state on them. 1.966 + nsAutoWindowStateHelper windowStateHelper( 1.967 + parentWindow ? parentWindow->GetOuterWindow() : nullptr); 1.968 + 1.969 + if (!windowStateHelper.DefaultEnabled()) { 1.970 + // Default to cancel not opening the modal window. 1.971 + NS_RELEASE(*_retval); 1.972 + 1.973 + return NS_OK; 1.974 + } 1.975 + 1.976 + 1.977 + if (!newWindowShouldBeModal && parentIsModal) { 1.978 + nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(newTreeOwner)); 1.979 + if (parentWindow) { 1.980 + nsCOMPtr<nsIWidget> parentWidget; 1.981 + parentWindow->GetMainWidget(getter_AddRefs(parentWidget)); 1.982 + if (parentWidget) { 1.983 + parentWidget->SetModal(true); 1.984 + } 1.985 + } 1.986 + } else { 1.987 + // Reset popup state while opening a modal dialog, and firing 1.988 + // events about the dialog, to prevent the current state from 1.989 + // being active the whole time a modal dialog is open. 1.990 + nsAutoPopupStatePusher popupStatePusher(openAbused); 1.991 + 1.992 + newChrome->ShowAsModal(); 1.993 + } 1.994 + } 1.995 + 1.996 + return NS_OK; 1.997 +} 1.998 + 1.999 +NS_IMETHODIMP 1.1000 +nsWindowWatcher::RegisterNotification(nsIObserver *aObserver) 1.1001 +{ 1.1002 + // just a convenience method; it delegates to nsIObserverService 1.1003 + 1.1004 + if (!aObserver) 1.1005 + return NS_ERROR_INVALID_ARG; 1.1006 + 1.1007 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.1008 + if (!os) 1.1009 + return NS_ERROR_FAILURE; 1.1010 + 1.1011 + nsresult rv = os->AddObserver(aObserver, "domwindowopened", false); 1.1012 + if (NS_SUCCEEDED(rv)) 1.1013 + rv = os->AddObserver(aObserver, "domwindowclosed", false); 1.1014 + 1.1015 + return rv; 1.1016 +} 1.1017 + 1.1018 +NS_IMETHODIMP 1.1019 +nsWindowWatcher::UnregisterNotification(nsIObserver *aObserver) 1.1020 +{ 1.1021 + // just a convenience method; it delegates to nsIObserverService 1.1022 + 1.1023 + if (!aObserver) 1.1024 + return NS_ERROR_INVALID_ARG; 1.1025 + 1.1026 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.1027 + if (!os) 1.1028 + return NS_ERROR_FAILURE; 1.1029 + 1.1030 + os->RemoveObserver(aObserver, "domwindowopened"); 1.1031 + os->RemoveObserver(aObserver, "domwindowclosed"); 1.1032 + 1.1033 + return NS_OK; 1.1034 +} 1.1035 + 1.1036 +NS_IMETHODIMP 1.1037 +nsWindowWatcher::GetWindowEnumerator(nsISimpleEnumerator** _retval) 1.1038 +{ 1.1039 + if (!_retval) 1.1040 + return NS_ERROR_INVALID_ARG; 1.1041 + 1.1042 + MutexAutoLock lock(mListLock); 1.1043 + nsWatcherWindowEnumerator *enumerator = new nsWatcherWindowEnumerator(this); 1.1044 + if (enumerator) 1.1045 + return CallQueryInterface(enumerator, _retval); 1.1046 + 1.1047 + return NS_ERROR_OUT_OF_MEMORY; 1.1048 +} 1.1049 + 1.1050 +NS_IMETHODIMP 1.1051 +nsWindowWatcher::GetNewPrompter(nsIDOMWindow *aParent, nsIPrompt **_retval) 1.1052 +{ 1.1053 + // This is for backwards compat only. Callers should just use the prompt service directly. 1.1054 + nsresult rv; 1.1055 + nsCOMPtr<nsIPromptFactory> factory = do_GetService("@mozilla.org/prompter;1", &rv); 1.1056 + NS_ENSURE_SUCCESS(rv, rv); 1.1057 + return factory->GetPrompt(aParent, NS_GET_IID(nsIPrompt), reinterpret_cast<void**>(_retval)); 1.1058 +} 1.1059 + 1.1060 +NS_IMETHODIMP 1.1061 +nsWindowWatcher::GetNewAuthPrompter(nsIDOMWindow *aParent, nsIAuthPrompt **_retval) 1.1062 +{ 1.1063 + // This is for backwards compat only. Callers should just use the prompt service directly. 1.1064 + nsresult rv; 1.1065 + nsCOMPtr<nsIPromptFactory> factory = do_GetService("@mozilla.org/prompter;1", &rv); 1.1066 + NS_ENSURE_SUCCESS(rv, rv); 1.1067 + return factory->GetPrompt(aParent, NS_GET_IID(nsIAuthPrompt), reinterpret_cast<void**>(_retval)); 1.1068 +} 1.1069 + 1.1070 +NS_IMETHODIMP 1.1071 +nsWindowWatcher::GetPrompt(nsIDOMWindow *aParent, const nsIID& aIID, 1.1072 + void **_retval) 1.1073 +{ 1.1074 + // This is for backwards compat only. Callers should just use the prompt service directly. 1.1075 + nsresult rv; 1.1076 + nsCOMPtr<nsIPromptFactory> factory = do_GetService("@mozilla.org/prompter;1", &rv); 1.1077 + NS_ENSURE_SUCCESS(rv, rv); 1.1078 + rv = factory->GetPrompt(aParent, aIID, _retval); 1.1079 + 1.1080 + // Allow for an embedding implementation to not support nsIAuthPrompt2. 1.1081 + if (rv == NS_NOINTERFACE && aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) { 1.1082 + nsCOMPtr<nsIAuthPrompt> oldPrompt; 1.1083 + rv = factory->GetPrompt(aParent, 1.1084 + NS_GET_IID(nsIAuthPrompt), 1.1085 + getter_AddRefs(oldPrompt)); 1.1086 + NS_ENSURE_SUCCESS(rv, rv); 1.1087 + 1.1088 + NS_WrapAuthPrompt(oldPrompt, reinterpret_cast<nsIAuthPrompt2**>(_retval)); 1.1089 + if (!*_retval) 1.1090 + rv = NS_ERROR_NOT_AVAILABLE; 1.1091 + } 1.1092 + return rv; 1.1093 +} 1.1094 + 1.1095 +NS_IMETHODIMP 1.1096 +nsWindowWatcher::SetWindowCreator(nsIWindowCreator *creator) 1.1097 +{ 1.1098 + mWindowCreator = creator; // it's an nsCOMPtr, so this is an ownership ref 1.1099 + return NS_OK; 1.1100 +} 1.1101 + 1.1102 +NS_IMETHODIMP 1.1103 +nsWindowWatcher::HasWindowCreator(bool *result) 1.1104 +{ 1.1105 + *result = mWindowCreator; 1.1106 + return NS_OK; 1.1107 +} 1.1108 + 1.1109 +NS_IMETHODIMP 1.1110 +nsWindowWatcher::GetActiveWindow(nsIDOMWindow **aActiveWindow) 1.1111 +{ 1.1112 + *aActiveWindow = nullptr; 1.1113 + nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID); 1.1114 + if (fm) 1.1115 + return fm->GetActiveWindow(aActiveWindow); 1.1116 + return NS_OK; 1.1117 +} 1.1118 + 1.1119 +NS_IMETHODIMP 1.1120 +nsWindowWatcher::SetActiveWindow(nsIDOMWindow *aActiveWindow) 1.1121 +{ 1.1122 + nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID); 1.1123 + if (fm) 1.1124 + return fm->SetActiveWindow(aActiveWindow); 1.1125 + return NS_OK; 1.1126 +} 1.1127 + 1.1128 +NS_IMETHODIMP 1.1129 +nsWindowWatcher::AddWindow(nsIDOMWindow *aWindow, nsIWebBrowserChrome *aChrome) 1.1130 +{ 1.1131 + if (!aWindow) 1.1132 + return NS_ERROR_INVALID_ARG; 1.1133 + 1.1134 +#ifdef DEBUG 1.1135 + { 1.1136 + nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow)); 1.1137 + 1.1138 + NS_ASSERTION(win->IsOuterWindow(), 1.1139 + "Uh, the active window must be an outer window!"); 1.1140 + } 1.1141 +#endif 1.1142 + 1.1143 + { 1.1144 + nsWatcherWindowEntry *info; 1.1145 + MutexAutoLock lock(mListLock); 1.1146 + 1.1147 + // if we already have an entry for this window, adjust 1.1148 + // its chrome mapping and return 1.1149 + info = FindWindowEntry(aWindow); 1.1150 + if (info) { 1.1151 + nsCOMPtr<nsISupportsWeakReference> supportsweak(do_QueryInterface(aChrome)); 1.1152 + if (supportsweak) { 1.1153 + supportsweak->GetWeakReference(getter_AddRefs(info->mChromeWeak)); 1.1154 + } else { 1.1155 + info->mChrome = aChrome; 1.1156 + info->mChromeWeak = 0; 1.1157 + } 1.1158 + return NS_OK; 1.1159 + } 1.1160 + 1.1161 + // create a window info struct and add it to the list of windows 1.1162 + info = new nsWatcherWindowEntry(aWindow, aChrome); 1.1163 + if (!info) 1.1164 + return NS_ERROR_OUT_OF_MEMORY; 1.1165 + 1.1166 + if (mOldestWindow) 1.1167 + info->InsertAfter(mOldestWindow->mOlder); 1.1168 + else 1.1169 + mOldestWindow = info; 1.1170 + } // leave the mListLock 1.1171 + 1.1172 + // a window being added to us signifies a newly opened window. 1.1173 + // send notifications. 1.1174 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.1175 + if (!os) 1.1176 + return NS_ERROR_FAILURE; 1.1177 + 1.1178 + nsCOMPtr<nsISupports> domwin(do_QueryInterface(aWindow)); 1.1179 + return os->NotifyObservers(domwin, "domwindowopened", 0); 1.1180 +} 1.1181 + 1.1182 +NS_IMETHODIMP 1.1183 +nsWindowWatcher::RemoveWindow(nsIDOMWindow *aWindow) 1.1184 +{ 1.1185 + // find the corresponding nsWatcherWindowEntry, remove it 1.1186 + 1.1187 + if (!aWindow) 1.1188 + return NS_ERROR_INVALID_ARG; 1.1189 + 1.1190 + nsWatcherWindowEntry *info = FindWindowEntry(aWindow); 1.1191 + if (info) { 1.1192 + RemoveWindow(info); 1.1193 + return NS_OK; 1.1194 + } 1.1195 + NS_WARNING("requested removal of nonexistent window"); 1.1196 + return NS_ERROR_INVALID_ARG; 1.1197 +} 1.1198 + 1.1199 +nsWatcherWindowEntry * 1.1200 +nsWindowWatcher::FindWindowEntry(nsIDOMWindow *aWindow) 1.1201 +{ 1.1202 + // find the corresponding nsWatcherWindowEntry 1.1203 + nsWatcherWindowEntry *info, 1.1204 + *listEnd; 1.1205 +#ifdef USEWEAKREFS 1.1206 + nsresult rv; 1.1207 + bool found; 1.1208 +#endif 1.1209 + 1.1210 + info = mOldestWindow; 1.1211 + listEnd = 0; 1.1212 +#ifdef USEWEAKREFS 1.1213 + rv = NS_OK; 1.1214 + found = false; 1.1215 + while (info != listEnd && NS_SUCCEEDED(rv)) { 1.1216 + nsCOMPtr<nsIDOMWindow> infoWindow(do_QueryReferent(info->mWindow)); 1.1217 + if (!infoWindow) { // clean up dangling reference, while we're here 1.1218 + rv = RemoveWindow(info); 1.1219 + } 1.1220 + else if (infoWindow.get() == aWindow) 1.1221 + return info; 1.1222 + 1.1223 + info = info->mYounger; 1.1224 + listEnd = mOldestWindow; 1.1225 + } 1.1226 + return 0; 1.1227 +#else 1.1228 + while (info != listEnd) { 1.1229 + if (info->mWindow == aWindow) 1.1230 + return info; 1.1231 + info = info->mYounger; 1.1232 + listEnd = mOldestWindow; 1.1233 + } 1.1234 + return 0; 1.1235 +#endif 1.1236 +} 1.1237 + 1.1238 +nsresult nsWindowWatcher::RemoveWindow(nsWatcherWindowEntry *inInfo) 1.1239 +{ 1.1240 + uint32_t ctr, 1.1241 + count = mEnumeratorList.Length(); 1.1242 + 1.1243 + { 1.1244 + // notify the enumerators 1.1245 + MutexAutoLock lock(mListLock); 1.1246 + for (ctr = 0; ctr < count; ++ctr) 1.1247 + mEnumeratorList[ctr]->WindowRemoved(inInfo); 1.1248 + 1.1249 + // remove the element from the list 1.1250 + if (inInfo == mOldestWindow) 1.1251 + mOldestWindow = inInfo->mYounger == mOldestWindow ? 0 : inInfo->mYounger; 1.1252 + inInfo->Unlink(); 1.1253 + } 1.1254 + 1.1255 + // a window being removed from us signifies a newly closed window. 1.1256 + // send notifications. 1.1257 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.1258 + if (os) { 1.1259 +#ifdef USEWEAKREFS 1.1260 + nsCOMPtr<nsISupports> domwin(do_QueryReferent(inInfo->mWindow)); 1.1261 + if (domwin) 1.1262 + os->NotifyObservers(domwin, "domwindowclosed", 0); 1.1263 + // else bummer. since the window is gone, there's nothing to notify with. 1.1264 +#else 1.1265 + nsCOMPtr<nsISupports> domwin(do_QueryInterface(inInfo->mWindow)); 1.1266 + os->NotifyObservers(domwin, "domwindowclosed", 0); 1.1267 +#endif 1.1268 + } 1.1269 + 1.1270 + delete inInfo; 1.1271 + return NS_OK; 1.1272 +} 1.1273 + 1.1274 +NS_IMETHODIMP 1.1275 +nsWindowWatcher::GetChromeForWindow(nsIDOMWindow *aWindow, nsIWebBrowserChrome **_retval) 1.1276 +{ 1.1277 + if (!aWindow || !_retval) 1.1278 + return NS_ERROR_INVALID_ARG; 1.1279 + *_retval = 0; 1.1280 + 1.1281 + MutexAutoLock lock(mListLock); 1.1282 + nsWatcherWindowEntry *info = FindWindowEntry(aWindow); 1.1283 + if (info) { 1.1284 + if (info->mChromeWeak != nullptr) { 1.1285 + return info->mChromeWeak-> 1.1286 + QueryReferent(NS_GET_IID(nsIWebBrowserChrome), 1.1287 + reinterpret_cast<void**>(_retval)); 1.1288 + } 1.1289 + *_retval = info->mChrome; 1.1290 + NS_IF_ADDREF(*_retval); 1.1291 + } 1.1292 + return NS_OK; 1.1293 +} 1.1294 + 1.1295 +NS_IMETHODIMP 1.1296 +nsWindowWatcher::GetWindowByName(const char16_t *aTargetName, 1.1297 + nsIDOMWindow *aCurrentWindow, 1.1298 + nsIDOMWindow **aResult) 1.1299 +{ 1.1300 + if (!aResult) { 1.1301 + return NS_ERROR_INVALID_ARG; 1.1302 + } 1.1303 + 1.1304 + *aResult = nullptr; 1.1305 + 1.1306 + nsCOMPtr<nsIDocShellTreeItem> treeItem; 1.1307 + 1.1308 + nsCOMPtr<nsIDocShellTreeItem> startItem; 1.1309 + GetWindowTreeItem(aCurrentWindow, getter_AddRefs(startItem)); 1.1310 + if (startItem) { 1.1311 + // Note: original requestor is null here, per idl comments 1.1312 + startItem->FindItemWithName(aTargetName, nullptr, nullptr, 1.1313 + getter_AddRefs(treeItem)); 1.1314 + } 1.1315 + else { 1.1316 + // Note: original requestor is null here, per idl comments 1.1317 + FindItemWithName(aTargetName, nullptr, nullptr, getter_AddRefs(treeItem)); 1.1318 + } 1.1319 + 1.1320 + nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(treeItem); 1.1321 + domWindow.swap(*aResult); 1.1322 + 1.1323 + return NS_OK; 1.1324 +} 1.1325 + 1.1326 +bool 1.1327 +nsWindowWatcher::AddEnumerator(nsWatcherWindowEnumerator* inEnumerator) 1.1328 +{ 1.1329 + // (requires a lock; assumes it's called by someone holding the lock) 1.1330 + return mEnumeratorList.AppendElement(inEnumerator) != nullptr; 1.1331 +} 1.1332 + 1.1333 +bool 1.1334 +nsWindowWatcher::RemoveEnumerator(nsWatcherWindowEnumerator* inEnumerator) 1.1335 +{ 1.1336 + // (requires a lock; assumes it's called by someone holding the lock) 1.1337 + return mEnumeratorList.RemoveElement(inEnumerator); 1.1338 +} 1.1339 + 1.1340 +nsresult 1.1341 +nsWindowWatcher::URIfromURL(const char *aURL, 1.1342 + nsIDOMWindow *aParent, 1.1343 + nsIURI **aURI) 1.1344 +{ 1.1345 + nsCOMPtr<nsIDOMWindow> baseWindow; 1.1346 + 1.1347 + /* build the URI relative to the calling JS Context, if any. 1.1348 + (note this is the same context used to make the security check 1.1349 + in nsGlobalWindow.cpp.) */ 1.1350 + JSContext *cx = nsContentUtils::GetCurrentJSContext(); 1.1351 + if (cx) { 1.1352 + nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx); 1.1353 + if (scriptcx) { 1.1354 + baseWindow = do_QueryInterface(scriptcx->GetGlobalObject()); 1.1355 + } 1.1356 + } 1.1357 + 1.1358 + // failing that, build it relative to the parent window, if possible 1.1359 + if (!baseWindow) 1.1360 + baseWindow = aParent; 1.1361 + 1.1362 + // failing that, use the given URL unmodified. It had better not be relative. 1.1363 + 1.1364 + nsIURI *baseURI = nullptr; 1.1365 + 1.1366 + // get baseWindow's document URI 1.1367 + if (baseWindow) { 1.1368 + nsCOMPtr<nsIDOMDocument> domDoc; 1.1369 + baseWindow->GetDocument(getter_AddRefs(domDoc)); 1.1370 + if (domDoc) { 1.1371 + nsCOMPtr<nsIDocument> doc; 1.1372 + doc = do_QueryInterface(domDoc); 1.1373 + if (doc) { 1.1374 + baseURI = doc->GetDocBaseURI(); 1.1375 + } 1.1376 + } 1.1377 + } 1.1378 + 1.1379 + // build and return the absolute URI 1.1380 + return NS_NewURI(aURI, aURL, baseURI); 1.1381 +} 1.1382 + 1.1383 +#define NS_CALCULATE_CHROME_FLAG_FOR(feature, flag) \ 1.1384 + prefBranch->GetBoolPref(feature, &forceEnable); \ 1.1385 + if (forceEnable && !(aDialog && isCallerChrome) && \ 1.1386 + !(isCallerChrome && aHasChromeParent) && !aChromeURL) { \ 1.1387 + chromeFlags |= flag; \ 1.1388 + } else { \ 1.1389 + chromeFlags |= WinHasOption(aFeatures, feature, \ 1.1390 + 0, &presenceFlag) \ 1.1391 + ? flag : 0; \ 1.1392 + } 1.1393 + 1.1394 +/** 1.1395 + * Calculate the chrome bitmask from a string list of features. 1.1396 + * @param aParent the opener window 1.1397 + * @param aFeatures a string containing a list of named chrome features 1.1398 + * @param aNullFeatures true if aFeatures was a null pointer (which fact 1.1399 + * is lost by its conversion to a string in the caller) 1.1400 + * @param aDialog affects the assumptions made about unnamed features 1.1401 + * @return the chrome bitmask 1.1402 + */ 1.1403 +// static 1.1404 +uint32_t nsWindowWatcher::CalculateChromeFlags(nsIDOMWindow *aParent, 1.1405 + const char *aFeatures, 1.1406 + bool aFeaturesSpecified, 1.1407 + bool aDialog, 1.1408 + bool aChromeURL, 1.1409 + bool aHasChromeParent) 1.1410 +{ 1.1411 + if(!aFeaturesSpecified || !aFeatures) { 1.1412 + if(aDialog) 1.1413 + return nsIWebBrowserChrome::CHROME_ALL | 1.1414 + nsIWebBrowserChrome::CHROME_OPENAS_DIALOG | 1.1415 + nsIWebBrowserChrome::CHROME_OPENAS_CHROME; 1.1416 + else 1.1417 + return nsIWebBrowserChrome::CHROME_ALL; 1.1418 + } 1.1419 + 1.1420 + /* This function has become complicated since browser windows and 1.1421 + dialogs diverged. The difference is, browser windows assume all 1.1422 + chrome not explicitly mentioned is off, if the features string 1.1423 + is not null. Exceptions are some OS border chrome new with Mozilla. 1.1424 + Dialogs interpret a (mostly) empty features string to mean 1.1425 + "OS's choice," and also support an "all" flag explicitly disallowed 1.1426 + in the standards-compliant window.(normal)open. */ 1.1427 + 1.1428 + uint32_t chromeFlags = 0; 1.1429 + bool presenceFlag = false; 1.1430 + 1.1431 + chromeFlags = nsIWebBrowserChrome::CHROME_WINDOW_BORDERS; 1.1432 + if (aDialog && WinHasOption(aFeatures, "all", 0, &presenceFlag)) 1.1433 + chromeFlags = nsIWebBrowserChrome::CHROME_ALL; 1.1434 + 1.1435 + /* Next, allow explicitly named options to override the initial settings */ 1.1436 + 1.1437 + bool isCallerChrome = nsContentUtils::IsCallerChrome(); 1.1438 + 1.1439 + // Determine whether the window is a private browsing window 1.1440 + if (isCallerChrome) { 1.1441 + chromeFlags |= WinHasOption(aFeatures, "private", 0, &presenceFlag) ? 1.1442 + nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW : 0; 1.1443 + chromeFlags |= WinHasOption(aFeatures, "non-private", 0, &presenceFlag) ? 1.1444 + nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW : 0; 1.1445 + } 1.1446 + 1.1447 + // Determine whether the window should have remote tabs. 1.1448 + if (isCallerChrome) { 1.1449 + bool remote; 1.1450 + if (Preferences::GetBool("browser.tabs.remote.autostart")) { 1.1451 + remote = !WinHasOption(aFeatures, "non-remote", 0, &presenceFlag); 1.1452 + } else { 1.1453 + remote = WinHasOption(aFeatures, "remote", 0, &presenceFlag); 1.1454 + } 1.1455 + if (remote) { 1.1456 + chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW; 1.1457 + } 1.1458 + } 1.1459 + 1.1460 + nsresult rv; 1.1461 + 1.1462 + nsCOMPtr<nsIPrefBranch> prefBranch; 1.1463 + nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); 1.1464 + NS_ENSURE_SUCCESS(rv, true); 1.1465 + 1.1466 + rv = prefs->GetBranch("dom.disable_window_open_feature.", getter_AddRefs(prefBranch)); 1.1467 + NS_ENSURE_SUCCESS(rv, true); 1.1468 + 1.1469 + bool forceEnable = false; 1.1470 + 1.1471 + NS_CALCULATE_CHROME_FLAG_FOR("titlebar", 1.1472 + nsIWebBrowserChrome::CHROME_TITLEBAR); 1.1473 + NS_CALCULATE_CHROME_FLAG_FOR("close", 1.1474 + nsIWebBrowserChrome::CHROME_WINDOW_CLOSE); 1.1475 + NS_CALCULATE_CHROME_FLAG_FOR("toolbar", 1.1476 + nsIWebBrowserChrome::CHROME_TOOLBAR); 1.1477 + NS_CALCULATE_CHROME_FLAG_FOR("location", 1.1478 + nsIWebBrowserChrome::CHROME_LOCATIONBAR); 1.1479 + NS_CALCULATE_CHROME_FLAG_FOR("personalbar", 1.1480 + nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR); 1.1481 + NS_CALCULATE_CHROME_FLAG_FOR("status", 1.1482 + nsIWebBrowserChrome::CHROME_STATUSBAR); 1.1483 + NS_CALCULATE_CHROME_FLAG_FOR("menubar", 1.1484 + nsIWebBrowserChrome::CHROME_MENUBAR); 1.1485 + NS_CALCULATE_CHROME_FLAG_FOR("scrollbars", 1.1486 + nsIWebBrowserChrome::CHROME_SCROLLBARS); 1.1487 + NS_CALCULATE_CHROME_FLAG_FOR("resizable", 1.1488 + nsIWebBrowserChrome::CHROME_WINDOW_RESIZE); 1.1489 + NS_CALCULATE_CHROME_FLAG_FOR("minimizable", 1.1490 + nsIWebBrowserChrome::CHROME_WINDOW_MIN); 1.1491 + 1.1492 + chromeFlags |= WinHasOption(aFeatures, "popup", 0, &presenceFlag) 1.1493 + ? nsIWebBrowserChrome::CHROME_WINDOW_POPUP : 0; 1.1494 + 1.1495 + /* OK. 1.1496 + Normal browser windows, in spite of a stated pattern of turning off 1.1497 + all chrome not mentioned explicitly, will want the new OS chrome (window 1.1498 + borders, titlebars, closebox) on, unless explicitly turned off. 1.1499 + Dialogs, on the other hand, take the absence of any explicit settings 1.1500 + to mean "OS' choice." */ 1.1501 + 1.1502 + // default titlebar and closebox to "on," if not mentioned at all 1.1503 + if (!(chromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)) { 1.1504 + if (!PL_strcasestr(aFeatures, "titlebar")) 1.1505 + chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR; 1.1506 + if (!PL_strcasestr(aFeatures, "close")) 1.1507 + chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE; 1.1508 + } 1.1509 + 1.1510 + if (aDialog && !presenceFlag) 1.1511 + chromeFlags = nsIWebBrowserChrome::CHROME_DEFAULT; 1.1512 + 1.1513 + /* Finally, once all the above normal chrome has been divined, deal 1.1514 + with the features that are more operating hints than appearance 1.1515 + instructions. (Note modality implies dependence.) */ 1.1516 + 1.1517 + if (WinHasOption(aFeatures, "alwaysLowered", 0, nullptr) || 1.1518 + WinHasOption(aFeatures, "z-lock", 0, nullptr)) 1.1519 + chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_LOWERED; 1.1520 + else if (WinHasOption(aFeatures, "alwaysRaised", 0, nullptr)) 1.1521 + chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_RAISED; 1.1522 + 1.1523 + chromeFlags |= WinHasOption(aFeatures, "macsuppressanimation", 0, nullptr) ? 1.1524 + nsIWebBrowserChrome::CHROME_MAC_SUPPRESS_ANIMATION : 0; 1.1525 + 1.1526 + chromeFlags |= WinHasOption(aFeatures, "chrome", 0, nullptr) ? 1.1527 + nsIWebBrowserChrome::CHROME_OPENAS_CHROME : 0; 1.1528 + chromeFlags |= WinHasOption(aFeatures, "extrachrome", 0, nullptr) ? 1.1529 + nsIWebBrowserChrome::CHROME_EXTRA : 0; 1.1530 + chromeFlags |= WinHasOption(aFeatures, "centerscreen", 0, nullptr) ? 1.1531 + nsIWebBrowserChrome::CHROME_CENTER_SCREEN : 0; 1.1532 + chromeFlags |= WinHasOption(aFeatures, "dependent", 0, nullptr) ? 1.1533 + nsIWebBrowserChrome::CHROME_DEPENDENT : 0; 1.1534 + chromeFlags |= WinHasOption(aFeatures, "modal", 0, nullptr) ? 1.1535 + (nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT) : 0; 1.1536 + 1.1537 + /* On mobile we want to ignore the dialog window feature, since the mobile UI 1.1538 + does not provide any affordance for dialog windows. This does not interfere 1.1539 + with dialog windows created through openDialog. */ 1.1540 + bool disableDialogFeature = false; 1.1541 + nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs); 1.1542 + branch->GetBoolPref("dom.disable_window_open_dialog_feature", &disableDialogFeature); 1.1543 + 1.1544 + bool isFullScreen = false; 1.1545 + if (aParent) { 1.1546 + aParent->GetFullScreen(&isFullScreen); 1.1547 + } 1.1548 + if (isFullScreen && !isCallerChrome) { 1.1549 + // If the parent window is in fullscreen & the caller context is content, 1.1550 + // dialog feature is disabled. (see bug 803675) 1.1551 + disableDialogFeature = true; 1.1552 + } 1.1553 + 1.1554 + if (!disableDialogFeature) { 1.1555 + chromeFlags |= WinHasOption(aFeatures, "dialog", 0, nullptr) ? 1.1556 + nsIWebBrowserChrome::CHROME_OPENAS_DIALOG : 0; 1.1557 + } 1.1558 + 1.1559 + /* and dialogs need to have the last word. assume dialogs are dialogs, 1.1560 + and opened as chrome, unless explicitly told otherwise. */ 1.1561 + if (aDialog) { 1.1562 + if (!PL_strcasestr(aFeatures, "dialog")) 1.1563 + chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG; 1.1564 + if (!PL_strcasestr(aFeatures, "chrome")) 1.1565 + chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_CHROME; 1.1566 + } 1.1567 + 1.1568 + /* missing 1.1569 + chromeFlags->copy_history 1.1570 + */ 1.1571 + 1.1572 + // Check security state for use in determing window dimensions 1.1573 + if (!isCallerChrome || !aHasChromeParent) { 1.1574 + // If priv check fails (or if we're called from chrome, but the 1.1575 + // parent is not a chrome window), set all elements to minimum 1.1576 + // reqs., else leave them alone. 1.1577 + chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR; 1.1578 + chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE; 1.1579 + chromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_LOWERED; 1.1580 + chromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_RAISED; 1.1581 + chromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_POPUP; 1.1582 + /* Untrusted script is allowed to pose modal windows with a chrome 1.1583 + scheme. This check could stand to be better. But it effectively 1.1584 + prevents untrusted script from opening modal windows in general 1.1585 + while still allowing alerts and the like. */ 1.1586 + if (!aChromeURL) 1.1587 + chromeFlags &= ~(nsIWebBrowserChrome::CHROME_MODAL | 1.1588 + nsIWebBrowserChrome::CHROME_OPENAS_CHROME); 1.1589 + } 1.1590 + 1.1591 + if (!(chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)) { 1.1592 + // Remove the dependent flag if we're not opening as chrome 1.1593 + chromeFlags &= ~nsIWebBrowserChrome::CHROME_DEPENDENT; 1.1594 + } 1.1595 + 1.1596 + // Disable CHROME_OPENAS_DIALOG if the window is inside <iframe mozbrowser>. 1.1597 + // It's up to the embedder to interpret what dialog=1 means. 1.1598 + nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent); 1.1599 + if (docshell && docshell->GetIsInBrowserOrApp()) { 1.1600 + chromeFlags &= ~nsIWebBrowserChrome::CHROME_OPENAS_DIALOG; 1.1601 + } 1.1602 + 1.1603 + return chromeFlags; 1.1604 +} 1.1605 + 1.1606 +// static 1.1607 +int32_t 1.1608 +nsWindowWatcher::WinHasOption(const char *aOptions, const char *aName, 1.1609 + int32_t aDefault, bool *aPresenceFlag) 1.1610 +{ 1.1611 + if (!aOptions) 1.1612 + return 0; 1.1613 + 1.1614 + char *comma, *equal; 1.1615 + int32_t found = 0; 1.1616 + 1.1617 +#ifdef DEBUG 1.1618 + nsAutoCString options(aOptions); 1.1619 + NS_ASSERTION(options.FindCharInSet(" \n\r\t") == kNotFound, 1.1620 + "There should be no whitespace in this string!"); 1.1621 +#endif 1.1622 + 1.1623 + while (true) { 1.1624 + comma = PL_strchr(aOptions, ','); 1.1625 + if (comma) 1.1626 + *comma = '\0'; 1.1627 + equal = PL_strchr(aOptions, '='); 1.1628 + if (equal) 1.1629 + *equal = '\0'; 1.1630 + if (nsCRT::strcasecmp(aOptions, aName) == 0) { 1.1631 + if (aPresenceFlag) 1.1632 + *aPresenceFlag = true; 1.1633 + if (equal) 1.1634 + if (*(equal + 1) == '*') 1.1635 + found = aDefault; 1.1636 + else if (nsCRT::strcasecmp(equal + 1, "yes") == 0) 1.1637 + found = 1; 1.1638 + else 1.1639 + found = atoi(equal + 1); 1.1640 + else 1.1641 + found = 1; 1.1642 + } 1.1643 + if (equal) 1.1644 + *equal = '='; 1.1645 + if (comma) 1.1646 + *comma = ','; 1.1647 + if (found || !comma) 1.1648 + break; 1.1649 + aOptions = comma + 1; 1.1650 + } 1.1651 + return found; 1.1652 +} 1.1653 + 1.1654 +/* try to find an nsIDocShellTreeItem with the given name in any 1.1655 + known open window. a failure to find the item will not 1.1656 + necessarily return a failure method value. check aFoundItem. 1.1657 +*/ 1.1658 +NS_IMETHODIMP 1.1659 +nsWindowWatcher::FindItemWithName(const char16_t* aName, 1.1660 + nsIDocShellTreeItem* aRequestor, 1.1661 + nsIDocShellTreeItem* aOriginalRequestor, 1.1662 + nsIDocShellTreeItem** aFoundItem) 1.1663 +{ 1.1664 + *aFoundItem = 0; 1.1665 + 1.1666 + /* special cases */ 1.1667 + if(!aName || !*aName) 1.1668 + return NS_OK; 1.1669 + 1.1670 + nsDependentString name(aName); 1.1671 + 1.1672 + nsCOMPtr<nsISimpleEnumerator> windows; 1.1673 + GetWindowEnumerator(getter_AddRefs(windows)); 1.1674 + if (!windows) 1.1675 + return NS_ERROR_FAILURE; 1.1676 + 1.1677 + bool more; 1.1678 + nsresult rv = NS_OK; 1.1679 + 1.1680 + do { 1.1681 + windows->HasMoreElements(&more); 1.1682 + if (!more) 1.1683 + break; 1.1684 + nsCOMPtr<nsISupports> nextSupWindow; 1.1685 + windows->GetNext(getter_AddRefs(nextSupWindow)); 1.1686 + nsCOMPtr<nsIDOMWindow> nextWindow(do_QueryInterface(nextSupWindow)); 1.1687 + if (nextWindow) { 1.1688 + nsCOMPtr<nsIDocShellTreeItem> treeItem; 1.1689 + GetWindowTreeItem(nextWindow, getter_AddRefs(treeItem)); 1.1690 + if (treeItem) { 1.1691 + // Get the root tree item of same type, since roots are the only 1.1692 + // things that call into the treeowner to look for named items. 1.1693 + nsCOMPtr<nsIDocShellTreeItem> root; 1.1694 + treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root)); 1.1695 + NS_ASSERTION(root, "Must have root tree item of same type"); 1.1696 + // Make sure not to call back into aRequestor 1.1697 + if (root != aRequestor) { 1.1698 + // Get the tree owner so we can pass it in as the requestor so 1.1699 + // the child knows not to call back up, since we're walking 1.1700 + // all windows already. 1.1701 + nsCOMPtr<nsIDocShellTreeOwner> rootOwner; 1.1702 + // Note: if we have no aRequestor, then we want to also look for 1.1703 + // "special" window names, so pass a null requestor. This will mean 1.1704 + // that the treeitem calls back up to us, effectively (with a 1.1705 + // non-null aRequestor), so break the loop immediately after the 1.1706 + // call in that case. 1.1707 + if (aRequestor) { 1.1708 + root->GetTreeOwner(getter_AddRefs(rootOwner)); 1.1709 + } 1.1710 + rv = root->FindItemWithName(aName, rootOwner, aOriginalRequestor, 1.1711 + aFoundItem); 1.1712 + if (NS_FAILED(rv) || *aFoundItem || !aRequestor) 1.1713 + break; 1.1714 + } 1.1715 + } 1.1716 + } 1.1717 + } while(1); 1.1718 + 1.1719 + return rv; 1.1720 +} 1.1721 + 1.1722 +already_AddRefed<nsIDocShellTreeItem> 1.1723 +nsWindowWatcher::GetCallerTreeItem(nsIDocShellTreeItem* aParentItem) 1.1724 +{ 1.1725 + JSContext *cx = nsContentUtils::GetCurrentJSContext(); 1.1726 + nsCOMPtr<nsIDocShellTreeItem> callerItem; 1.1727 + 1.1728 + if (cx) { 1.1729 + nsCOMPtr<nsIWebNavigation> callerWebNav = 1.1730 + do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx)); 1.1731 + 1.1732 + callerItem = do_QueryInterface(callerWebNav); 1.1733 + } 1.1734 + 1.1735 + if (!callerItem) { 1.1736 + callerItem = aParentItem; 1.1737 + } 1.1738 + 1.1739 + return callerItem.forget(); 1.1740 +} 1.1741 + 1.1742 +already_AddRefed<nsIDOMWindow> 1.1743 +nsWindowWatcher::SafeGetWindowByName(const nsAString& aName, 1.1744 + nsIDOMWindow* aCurrentWindow) 1.1745 +{ 1.1746 + nsCOMPtr<nsIDocShellTreeItem> startItem; 1.1747 + GetWindowTreeItem(aCurrentWindow, getter_AddRefs(startItem)); 1.1748 + 1.1749 + nsCOMPtr<nsIDocShellTreeItem> callerItem = GetCallerTreeItem(startItem); 1.1750 + 1.1751 + const nsAFlatString& flatName = PromiseFlatString(aName); 1.1752 + 1.1753 + nsCOMPtr<nsIDocShellTreeItem> foundItem; 1.1754 + if (startItem) { 1.1755 + startItem->FindItemWithName(flatName.get(), nullptr, callerItem, 1.1756 + getter_AddRefs(foundItem)); 1.1757 + } 1.1758 + else { 1.1759 + FindItemWithName(flatName.get(), nullptr, callerItem, 1.1760 + getter_AddRefs(foundItem)); 1.1761 + } 1.1762 + 1.1763 + nsCOMPtr<nsIDOMWindow> foundWin = do_GetInterface(foundItem); 1.1764 + return foundWin.forget(); 1.1765 +} 1.1766 + 1.1767 +/* Fetch the nsIDOMWindow corresponding to the given nsIDocShellTreeItem. 1.1768 + This forces the creation of a script context, if one has not already 1.1769 + been created. Note it also sets the window's opener to the parent, 1.1770 + if applicable -- because it's just convenient, that's all. null aParent 1.1771 + is acceptable. */ 1.1772 +nsresult 1.1773 +nsWindowWatcher::ReadyOpenedDocShellItem(nsIDocShellTreeItem *aOpenedItem, 1.1774 + nsIDOMWindow *aParent, 1.1775 + bool aWindowIsNew, 1.1776 + nsIDOMWindow **aOpenedWindow) 1.1777 +{ 1.1778 + nsresult rv = NS_ERROR_FAILURE; 1.1779 + 1.1780 + *aOpenedWindow = 0; 1.1781 + nsCOMPtr<nsPIDOMWindow> piOpenedWindow(do_GetInterface(aOpenedItem)); 1.1782 + if (piOpenedWindow) { 1.1783 + if (aParent) { 1.1784 + piOpenedWindow->SetOpenerWindow(aParent, aWindowIsNew); // damnit 1.1785 + 1.1786 + if (aWindowIsNew) { 1.1787 +#ifdef DEBUG 1.1788 + // Assert that we're not loading things right now. If we are, when 1.1789 + // that load completes it will clobber whatever principals we set up 1.1790 + // on this new window! 1.1791 + nsCOMPtr<nsIDocumentLoader> docloader = 1.1792 + do_QueryInterface(aOpenedItem); 1.1793 + NS_ASSERTION(docloader, "How can we not have a docloader here?"); 1.1794 + 1.1795 + nsCOMPtr<nsIChannel> chan; 1.1796 + docloader->GetDocumentChannel(getter_AddRefs(chan)); 1.1797 + NS_ASSERTION(!chan, "Why is there a document channel?"); 1.1798 +#endif 1.1799 + 1.1800 + nsCOMPtr<nsIDocument> doc = piOpenedWindow->GetExtantDoc(); 1.1801 + if (doc) { 1.1802 + doc->SetIsInitialDocument(true); 1.1803 + } 1.1804 + } 1.1805 + } 1.1806 + rv = CallQueryInterface(piOpenedWindow, aOpenedWindow); 1.1807 + } 1.1808 + return rv; 1.1809 +} 1.1810 + 1.1811 +// static 1.1812 +void 1.1813 +nsWindowWatcher::CalcSizeSpec(const char* aFeatures, SizeSpec& aResult) 1.1814 +{ 1.1815 + // Parse position spec, if any, from aFeatures 1.1816 + bool present; 1.1817 + int32_t temp; 1.1818 + 1.1819 + present = false; 1.1820 + if ((temp = WinHasOption(aFeatures, "left", 0, &present)) || present) 1.1821 + aResult.mLeft = temp; 1.1822 + else if ((temp = WinHasOption(aFeatures, "screenX", 0, &present)) || present) 1.1823 + aResult.mLeft = temp; 1.1824 + aResult.mLeftSpecified = present; 1.1825 + 1.1826 + present = false; 1.1827 + if ((temp = WinHasOption(aFeatures, "top", 0, &present)) || present) 1.1828 + aResult.mTop = temp; 1.1829 + else if ((temp = WinHasOption(aFeatures, "screenY", 0, &present)) || present) 1.1830 + aResult.mTop = temp; 1.1831 + aResult.mTopSpecified = present; 1.1832 + 1.1833 + // Parse size spec, if any. Chrome size overrides content size. 1.1834 + if ((temp = WinHasOption(aFeatures, "outerWidth", INT32_MIN, nullptr))) { 1.1835 + if (temp == INT32_MIN) { 1.1836 + aResult.mUseDefaultWidth = true; 1.1837 + } 1.1838 + else { 1.1839 + aResult.mOuterWidth = temp; 1.1840 + } 1.1841 + aResult.mOuterWidthSpecified = true; 1.1842 + } else if ((temp = WinHasOption(aFeatures, "width", INT32_MIN, nullptr)) || 1.1843 + (temp = WinHasOption(aFeatures, "innerWidth", INT32_MIN, 1.1844 + nullptr))) { 1.1845 + if (temp == INT32_MIN) { 1.1846 + aResult.mUseDefaultWidth = true; 1.1847 + } else { 1.1848 + aResult.mInnerWidth = temp; 1.1849 + } 1.1850 + aResult.mInnerWidthSpecified = true; 1.1851 + } 1.1852 + 1.1853 + if ((temp = WinHasOption(aFeatures, "outerHeight", INT32_MIN, nullptr))) { 1.1854 + if (temp == INT32_MIN) { 1.1855 + aResult.mUseDefaultHeight = true; 1.1856 + } 1.1857 + else { 1.1858 + aResult.mOuterHeight = temp; 1.1859 + } 1.1860 + aResult.mOuterHeightSpecified = true; 1.1861 + } else if ((temp = WinHasOption(aFeatures, "height", INT32_MIN, 1.1862 + nullptr)) || 1.1863 + (temp = WinHasOption(aFeatures, "innerHeight", INT32_MIN, 1.1864 + nullptr))) { 1.1865 + if (temp == INT32_MIN) { 1.1866 + aResult.mUseDefaultHeight = true; 1.1867 + } else { 1.1868 + aResult.mInnerHeight = temp; 1.1869 + } 1.1870 + aResult.mInnerHeightSpecified = true; 1.1871 + } 1.1872 +} 1.1873 + 1.1874 +/* Size and position the new window according to aSizeSpec. This method 1.1875 + is assumed to be called after the window has already been given 1.1876 + a default position and size; thus its current position and size are 1.1877 + accurate defaults. The new window is made visible at method end. 1.1878 +*/ 1.1879 +void 1.1880 +nsWindowWatcher::SizeOpenedDocShellItem(nsIDocShellTreeItem *aDocShellItem, 1.1881 + nsIDOMWindow *aParent, 1.1882 + const SizeSpec & aSizeSpec) 1.1883 +{ 1.1884 + // position and size of window 1.1885 + int32_t left = 0, 1.1886 + top = 0, 1.1887 + width = 100, 1.1888 + height = 100; 1.1889 + // difference between chrome and content size 1.1890 + int32_t chromeWidth = 0, 1.1891 + chromeHeight = 0; 1.1892 + // whether the window size spec refers to chrome or content 1.1893 + bool sizeChromeWidth = true, 1.1894 + sizeChromeHeight = true; 1.1895 + 1.1896 + // get various interfaces for aDocShellItem, used throughout this method 1.1897 + nsCOMPtr<nsIDocShellTreeOwner> treeOwner; 1.1898 + aDocShellItem->GetTreeOwner(getter_AddRefs(treeOwner)); 1.1899 + nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(treeOwner)); 1.1900 + if (!treeOwnerAsWin) // we'll need this to actually size the docshell 1.1901 + return; 1.1902 + 1.1903 + double openerZoom = 1.0; 1.1904 + if (aParent) { 1.1905 + nsCOMPtr<nsIDOMDocument> openerDoc; 1.1906 + aParent->GetDocument(getter_AddRefs(openerDoc)); 1.1907 + if (openerDoc) { 1.1908 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(openerDoc); 1.1909 + nsIPresShell* shell = doc->GetShell(); 1.1910 + if (shell) { 1.1911 + nsPresContext* presContext = shell->GetPresContext(); 1.1912 + if (presContext) { 1.1913 + openerZoom = presContext->GetFullZoom(); 1.1914 + } 1.1915 + } 1.1916 + } 1.1917 + } 1.1918 + 1.1919 + double scale; 1.1920 + treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale); 1.1921 + 1.1922 + /* The current position and size will be unchanged if not specified 1.1923 + (and they fit entirely onscreen). Also, calculate the difference 1.1924 + between chrome and content sizes on aDocShellItem's window. 1.1925 + This latter point becomes important if chrome and content 1.1926 + specifications are mixed in aFeatures, and when bringing the window 1.1927 + back from too far off the right or bottom edges of the screen. */ 1.1928 + 1.1929 + treeOwnerAsWin->GetPositionAndSize(&left, &top, &width, &height); 1.1930 + left = NSToIntRound(left / scale); 1.1931 + top = NSToIntRound(top / scale); 1.1932 + width = NSToIntRound(width / scale); 1.1933 + height = NSToIntRound(height / scale); 1.1934 + { // scope shellWindow why not 1.1935 + nsCOMPtr<nsIBaseWindow> shellWindow(do_QueryInterface(aDocShellItem)); 1.1936 + if (shellWindow) { 1.1937 + int32_t cox, coy; 1.1938 + double shellScale; 1.1939 + shellWindow->GetSize(&cox, &coy); 1.1940 + shellWindow->GetUnscaledDevicePixelsPerCSSPixel(&shellScale); 1.1941 + chromeWidth = width - NSToIntRound(cox / shellScale); 1.1942 + chromeHeight = height - NSToIntRound(coy / shellScale); 1.1943 + } 1.1944 + } 1.1945 + 1.1946 + // Set up left/top 1.1947 + if (aSizeSpec.mLeftSpecified) { 1.1948 + left = NSToIntRound(aSizeSpec.mLeft * openerZoom); 1.1949 + } 1.1950 + 1.1951 + if (aSizeSpec.mTopSpecified) { 1.1952 + top = NSToIntRound(aSizeSpec.mTop * openerZoom); 1.1953 + } 1.1954 + 1.1955 + // Set up width 1.1956 + if (aSizeSpec.mOuterWidthSpecified) { 1.1957 + if (!aSizeSpec.mUseDefaultWidth) { 1.1958 + width = NSToIntRound(aSizeSpec.mOuterWidth * openerZoom); 1.1959 + } // Else specified to default; just use our existing width 1.1960 + } 1.1961 + else if (aSizeSpec.mInnerWidthSpecified) { 1.1962 + sizeChromeWidth = false; 1.1963 + if (aSizeSpec.mUseDefaultWidth) { 1.1964 + width = width - chromeWidth; 1.1965 + } else { 1.1966 + width = NSToIntRound(aSizeSpec.mInnerWidth * openerZoom); 1.1967 + } 1.1968 + } 1.1969 + 1.1970 + // Set up height 1.1971 + if (aSizeSpec.mOuterHeightSpecified) { 1.1972 + if (!aSizeSpec.mUseDefaultHeight) { 1.1973 + height = NSToIntRound(aSizeSpec.mOuterHeight * openerZoom); 1.1974 + } // Else specified to default; just use our existing height 1.1975 + } 1.1976 + else if (aSizeSpec.mInnerHeightSpecified) { 1.1977 + sizeChromeHeight = false; 1.1978 + if (aSizeSpec.mUseDefaultHeight) { 1.1979 + height = height - chromeHeight; 1.1980 + } else { 1.1981 + height = NSToIntRound(aSizeSpec.mInnerHeight * openerZoom); 1.1982 + } 1.1983 + } 1.1984 + 1.1985 + bool positionSpecified = aSizeSpec.PositionSpecified(); 1.1986 + 1.1987 + // Check security state for use in determing window dimensions 1.1988 + bool enabled = false; 1.1989 + if (nsContentUtils::IsCallerChrome()) { 1.1990 + // Only enable special priveleges for chrome when chrome calls 1.1991 + // open() on a chrome window 1.1992 + nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(aParent)); 1.1993 + enabled = !aParent || chromeWin; 1.1994 + } 1.1995 + 1.1996 + if (!enabled) { 1.1997 + 1.1998 + // Security check failed. Ensure all args meet minimum reqs. 1.1999 + 1.2000 + int32_t oldTop = top, 1.2001 + oldLeft = left; 1.2002 + 1.2003 + // We'll also need the screen dimensions 1.2004 + nsCOMPtr<nsIScreen> screen; 1.2005 + nsCOMPtr<nsIScreenManager> screenMgr(do_GetService( 1.2006 + "@mozilla.org/gfx/screenmanager;1")); 1.2007 + if (screenMgr) 1.2008 + screenMgr->ScreenForRect(left, top, width, height, 1.2009 + getter_AddRefs(screen)); 1.2010 + if (screen) { 1.2011 + int32_t screenLeft, screenTop, screenWidth, screenHeight; 1.2012 + int32_t winWidth = width + (sizeChromeWidth ? 0 : chromeWidth), 1.2013 + winHeight = height + (sizeChromeHeight ? 0 : chromeHeight); 1.2014 + 1.2015 + screen->GetAvailRectDisplayPix(&screenLeft, &screenTop, 1.2016 + &screenWidth, &screenHeight); 1.2017 + 1.2018 + if (aSizeSpec.SizeSpecified()) { 1.2019 + /* Unlike position, force size out-of-bounds check only if 1.2020 + size actually was specified. Otherwise, intrinsically sized 1.2021 + windows are broken. */ 1.2022 + if (height < 100) { 1.2023 + height = 100; 1.2024 + winHeight = height + (sizeChromeHeight ? 0 : chromeHeight); 1.2025 + } 1.2026 + if (winHeight > screenHeight) { 1.2027 + height = screenHeight - (sizeChromeHeight ? 0 : chromeHeight); 1.2028 + } 1.2029 + if (width < 100) { 1.2030 + width = 100; 1.2031 + winWidth = width + (sizeChromeWidth ? 0 : chromeWidth); 1.2032 + } 1.2033 + if (winWidth > screenWidth) { 1.2034 + width = screenWidth - (sizeChromeWidth ? 0 : chromeWidth); 1.2035 + } 1.2036 + } 1.2037 + 1.2038 + if (left + winWidth > screenLeft + screenWidth || left + winWidth < left) { 1.2039 + left = screenLeft + screenWidth - winWidth; 1.2040 + } 1.2041 + if (left < screenLeft) { 1.2042 + left = screenLeft; 1.2043 + } 1.2044 + if (top + winHeight > screenTop + screenHeight || top + winHeight < top) { 1.2045 + top = screenTop + screenHeight - winHeight; 1.2046 + } 1.2047 + if (top < screenTop) { 1.2048 + top = screenTop; 1.2049 + } 1.2050 + if (top != oldTop || left != oldLeft) { 1.2051 + positionSpecified = true; 1.2052 + } 1.2053 + } 1.2054 + } 1.2055 + 1.2056 + // size and position the window 1.2057 + 1.2058 + if (positionSpecified) { 1.2059 + treeOwnerAsWin->SetPosition(left * scale, top * scale); 1.2060 + // moving the window may have changed its scale factor 1.2061 + treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale); 1.2062 + } 1.2063 + if (aSizeSpec.SizeSpecified()) { 1.2064 + /* Prefer to trust the interfaces, which think in terms of pure 1.2065 + chrome or content sizes. If we have a mix, use the chrome size 1.2066 + adjusted by the chrome/content differences calculated earlier. */ 1.2067 + if (!sizeChromeWidth && !sizeChromeHeight) { 1.2068 + treeOwner->SizeShellTo(aDocShellItem, width * scale, height * scale); 1.2069 + } 1.2070 + else { 1.2071 + if (!sizeChromeWidth) 1.2072 + width += chromeWidth; 1.2073 + if (!sizeChromeHeight) 1.2074 + height += chromeHeight; 1.2075 + treeOwnerAsWin->SetSize(width * scale, height * scale, false); 1.2076 + } 1.2077 + } 1.2078 + treeOwnerAsWin->SetVisibility(true); 1.2079 +} 1.2080 + 1.2081 +void 1.2082 +nsWindowWatcher::GetWindowTreeItem(nsIDOMWindow *inWindow, 1.2083 + nsIDocShellTreeItem **outTreeItem) 1.2084 +{ 1.2085 + *outTreeItem = 0; 1.2086 + 1.2087 + nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(inWindow)); 1.2088 + if (window) { 1.2089 + nsIDocShell *docshell = window->GetDocShell(); 1.2090 + if (docshell) 1.2091 + CallQueryInterface(docshell, outTreeItem); 1.2092 + } 1.2093 +} 1.2094 + 1.2095 +void 1.2096 +nsWindowWatcher::GetWindowTreeOwner(nsIDOMWindow *inWindow, 1.2097 + nsIDocShellTreeOwner **outTreeOwner) 1.2098 +{ 1.2099 + *outTreeOwner = 0; 1.2100 + 1.2101 + nsCOMPtr<nsIDocShellTreeItem> treeItem; 1.2102 + GetWindowTreeItem(inWindow, getter_AddRefs(treeItem)); 1.2103 + if (treeItem) 1.2104 + treeItem->GetTreeOwner(outTreeOwner); 1.2105 +} 1.2106 + 1.2107 +JSContext * 1.2108 +nsWindowWatcher::GetJSContextFromWindow(nsIDOMWindow *aWindow) 1.2109 +{ 1.2110 + JSContext *cx = 0; 1.2111 + 1.2112 + if (aWindow) { 1.2113 + nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aWindow)); 1.2114 + if (sgo) { 1.2115 + nsIScriptContext *scx = sgo->GetContext(); 1.2116 + if (scx) 1.2117 + cx = scx->GetNativeContext(); 1.2118 + } 1.2119 + /* (off-topic note:) the nsIScriptContext can be retrieved by 1.2120 + nsCOMPtr<nsIScriptContext> scx; 1.2121 + nsJSUtils::GetDynamicScriptContext(cx, getter_AddRefs(scx)); 1.2122 + */ 1.2123 + } 1.2124 + 1.2125 + return cx; 1.2126 +}