LCOV - code coverage report
Current view: top level - toolkit/components/windowwatcher - nsWindowWatcher.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 466 1066 43.7 %
Date: 2017-07-14 16:53:18 Functions: 32 66 48.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : //#define USEWEAKREFS // (haven't quite figured that out yet)
       8             : 
       9             : #include "nsWindowWatcher.h"
      10             : #include "nsAutoWindowStateHelper.h"
      11             : 
      12             : #include "nsCRT.h"
      13             : #include "nsNetUtil.h"
      14             : #include "nsIAuthPrompt.h"
      15             : #include "nsIAuthPrompt2.h"
      16             : #include "nsISimpleEnumerator.h"
      17             : #include "nsIInterfaceRequestorUtils.h"
      18             : #include "nsJSUtils.h"
      19             : #include "plstr.h"
      20             : 
      21             : #include "nsDocShell.h"
      22             : #include "nsGlobalWindow.h"
      23             : #include "nsHashPropertyBag.h"
      24             : #include "nsIBaseWindow.h"
      25             : #include "nsIBrowserDOMWindow.h"
      26             : #include "nsIDocShell.h"
      27             : #include "nsIDocShellLoadInfo.h"
      28             : #include "nsIDocShellTreeItem.h"
      29             : #include "nsIDocShellTreeOwner.h"
      30             : #include "nsIDocumentLoader.h"
      31             : #include "nsIDocument.h"
      32             : #include "nsIDOMDocument.h"
      33             : #include "nsIDOMWindow.h"
      34             : #include "nsIDOMChromeWindow.h"
      35             : #include "nsIDOMModalContentWindow.h"
      36             : #include "nsIPrompt.h"
      37             : #include "nsIScriptObjectPrincipal.h"
      38             : #include "nsIScreen.h"
      39             : #include "nsIScreenManager.h"
      40             : #include "nsIScriptContext.h"
      41             : #include "nsIObserverService.h"
      42             : #include "nsIScriptSecurityManager.h"
      43             : #include "nsXPCOM.h"
      44             : #include "nsIURI.h"
      45             : #include "nsIWebBrowser.h"
      46             : #include "nsIWebBrowserChrome.h"
      47             : #include "nsIWebNavigation.h"
      48             : #include "nsIWindowCreator.h"
      49             : #include "nsIWindowCreator2.h"
      50             : #include "nsIXPConnect.h"
      51             : #include "nsIXULRuntime.h"
      52             : #include "nsPIDOMWindow.h"
      53             : #include "nsIContentViewer.h"
      54             : #include "nsIWindowProvider.h"
      55             : #include "nsIMutableArray.h"
      56             : #include "nsIDOMStorageManager.h"
      57             : #include "nsIWidget.h"
      58             : #include "nsFocusManager.h"
      59             : #include "nsIPresShell.h"
      60             : #include "nsPresContext.h"
      61             : #include "nsContentUtils.h"
      62             : #include "nsIPrefBranch.h"
      63             : #include "nsIPrefService.h"
      64             : #include "nsSandboxFlags.h"
      65             : #include "mozilla/Preferences.h"
      66             : #include "mozilla/dom/Element.h"
      67             : #include "mozilla/dom/Storage.h"
      68             : #include "mozilla/dom/ScriptSettings.h"
      69             : #include "mozilla/dom/TabParent.h"
      70             : #include "mozilla/dom/DocGroup.h"
      71             : #include "mozilla/dom/TabGroup.h"
      72             : #include "nsIXULWindow.h"
      73             : #include "nsIXULBrowserWindow.h"
      74             : #include "nsGlobalWindow.h"
      75             : 
      76             : #ifdef USEWEAKREFS
      77             : #include "nsIWeakReference.h"
      78             : #endif
      79             : 
      80             : using namespace mozilla;
      81             : using namespace mozilla::dom;
      82             : 
      83             : /****************************************************************
      84             :  ******************** nsWatcherWindowEntry **********************
      85             :  ****************************************************************/
      86             : 
      87             : class nsWindowWatcher;
      88             : 
      89             : struct nsWatcherWindowEntry
      90             : {
      91             : 
      92           2 :   nsWatcherWindowEntry(mozIDOMWindowProxy* aWindow, nsIWebBrowserChrome* aChrome)
      93           2 :     : mChrome(nullptr)
      94             :   {
      95             : #ifdef USEWEAKREFS
      96             :     mWindow = do_GetWeakReference(aWindow);
      97             : #else
      98           2 :     mWindow = aWindow;
      99             : #endif
     100           4 :     nsCOMPtr<nsISupportsWeakReference> supportsweak(do_QueryInterface(aChrome));
     101           2 :     if (supportsweak) {
     102           1 :       supportsweak->GetWeakReference(getter_AddRefs(mChromeWeak));
     103             :     } else {
     104           1 :       mChrome = aChrome;
     105           1 :       mChromeWeak = nullptr;
     106             :     }
     107           2 :     ReferenceSelf();
     108           2 :   }
     109           0 :   ~nsWatcherWindowEntry() {}
     110             : 
     111             :   void InsertAfter(nsWatcherWindowEntry* aOlder);
     112             :   void Unlink();
     113             :   void ReferenceSelf();
     114             : 
     115             : #ifdef USEWEAKREFS
     116             :   nsCOMPtr<nsIWeakReference> mWindow;
     117             : #else // still not an owning ref
     118             :   mozIDOMWindowProxy* mWindow;
     119             : #endif
     120             :   nsIWebBrowserChrome* mChrome;
     121             :   nsWeakPtr mChromeWeak;
     122             :   // each struct is in a circular, doubly-linked list
     123             :   nsWatcherWindowEntry* mYounger; // next younger in sequence
     124             :   nsWatcherWindowEntry* mOlder;
     125             : };
     126             : 
     127             : void
     128           0 : nsWatcherWindowEntry::InsertAfter(nsWatcherWindowEntry* aOlder)
     129             : {
     130           0 :   if (aOlder) {
     131           0 :     mOlder = aOlder;
     132           0 :     mYounger = aOlder->mYounger;
     133           0 :     mOlder->mYounger = this;
     134           0 :     if (mOlder->mOlder == mOlder) {
     135           0 :       mOlder->mOlder = this;
     136             :     }
     137           0 :     mYounger->mOlder = this;
     138           0 :     if (mYounger->mYounger == mYounger) {
     139           0 :       mYounger->mYounger = this;
     140             :     }
     141             :   }
     142           0 : }
     143             : 
     144             : void
     145           0 : nsWatcherWindowEntry::Unlink()
     146             : {
     147           0 :   mOlder->mYounger = mYounger;
     148           0 :   mYounger->mOlder = mOlder;
     149           0 :   ReferenceSelf();
     150           0 : }
     151             : 
     152             : void
     153           2 : nsWatcherWindowEntry::ReferenceSelf()
     154             : {
     155             : 
     156           2 :   mYounger = this;
     157           2 :   mOlder = this;
     158           2 : }
     159             : 
     160             : /****************************************************************
     161             :  ****************** nsWatcherWindowEnumerator *******************
     162             :  ****************************************************************/
     163             : 
     164             : class nsWatcherWindowEnumerator : public nsISimpleEnumerator
     165             : {
     166             : 
     167             : public:
     168             :   explicit nsWatcherWindowEnumerator(nsWindowWatcher* aWatcher);
     169             :   NS_IMETHOD HasMoreElements(bool* aResult) override;
     170             :   NS_IMETHOD GetNext(nsISupports** aResult) override;
     171             : 
     172             :   NS_DECL_ISUPPORTS
     173             : 
     174             : protected:
     175             :   virtual ~nsWatcherWindowEnumerator();
     176             : 
     177             : private:
     178             :   friend class nsWindowWatcher;
     179             : 
     180             :   nsWatcherWindowEntry* FindNext();
     181             :   void WindowRemoved(nsWatcherWindowEntry* aInfo);
     182             : 
     183             :   nsWindowWatcher* mWindowWatcher;
     184             :   nsWatcherWindowEntry* mCurrentPosition;
     185             : };
     186             : 
     187           0 : NS_IMPL_ADDREF(nsWatcherWindowEnumerator)
     188           0 : NS_IMPL_RELEASE(nsWatcherWindowEnumerator)
     189           0 : NS_IMPL_QUERY_INTERFACE(nsWatcherWindowEnumerator, nsISimpleEnumerator)
     190             : 
     191           0 : nsWatcherWindowEnumerator::nsWatcherWindowEnumerator(nsWindowWatcher* aWatcher)
     192             :   : mWindowWatcher(aWatcher)
     193           0 :   , mCurrentPosition(aWatcher->mOldestWindow)
     194             : {
     195           0 :   mWindowWatcher->AddEnumerator(this);
     196           0 :   mWindowWatcher->AddRef();
     197           0 : }
     198             : 
     199           0 : nsWatcherWindowEnumerator::~nsWatcherWindowEnumerator()
     200             : {
     201           0 :   mWindowWatcher->RemoveEnumerator(this);
     202           0 :   mWindowWatcher->Release();
     203           0 : }
     204             : 
     205             : NS_IMETHODIMP
     206           0 : nsWatcherWindowEnumerator::HasMoreElements(bool* aResult)
     207             : {
     208           0 :   if (!aResult) {
     209           0 :     return NS_ERROR_INVALID_ARG;
     210             :   }
     211             : 
     212           0 :   *aResult = !!mCurrentPosition;
     213           0 :   return NS_OK;
     214             : }
     215             : 
     216             : NS_IMETHODIMP
     217           0 : nsWatcherWindowEnumerator::GetNext(nsISupports** aResult)
     218             : {
     219           0 :   if (!aResult) {
     220           0 :     return NS_ERROR_INVALID_ARG;
     221             :   }
     222             : 
     223           0 :   *aResult = nullptr;
     224             : 
     225             : #ifdef USEWEAKREFS
     226             :   while (mCurrentPosition) {
     227             :     CallQueryReferent(mCurrentPosition->mWindow, aResult);
     228             :     if (*aResult) {
     229             :       mCurrentPosition = FindNext();
     230             :       break;
     231             :     } else { // window is gone!
     232             :       mWindowWatcher->RemoveWindow(mCurrentPosition);
     233             :     }
     234             :   }
     235             :   NS_IF_ADDREF(*aResult);
     236             : #else
     237           0 :   if (mCurrentPosition) {
     238           0 :     CallQueryInterface(mCurrentPosition->mWindow, aResult);
     239           0 :     mCurrentPosition = FindNext();
     240             :   }
     241             : #endif
     242           0 :   return NS_OK;
     243             : }
     244             : 
     245             : nsWatcherWindowEntry*
     246           0 : nsWatcherWindowEnumerator::FindNext()
     247             : {
     248             :   nsWatcherWindowEntry* info;
     249             : 
     250           0 :   if (!mCurrentPosition) {
     251           0 :     return 0;
     252             :   }
     253             : 
     254           0 :   info = mCurrentPosition->mYounger;
     255           0 :   return info == mWindowWatcher->mOldestWindow ? 0 : info;
     256             : }
     257             : 
     258             : // if a window is being removed adjust the iterator's current position
     259             : void
     260           0 : nsWatcherWindowEnumerator::WindowRemoved(nsWatcherWindowEntry* aInfo)
     261             : {
     262             : 
     263           0 :   if (mCurrentPosition == aInfo) {
     264           0 :     mCurrentPosition =
     265           0 :       mCurrentPosition != aInfo->mYounger ? aInfo->mYounger : 0;
     266             :   }
     267           0 : }
     268             : 
     269             : /****************************************************************
     270             :  *********************** nsWindowWatcher ************************
     271             :  ****************************************************************/
     272             : 
     273          29 : NS_IMPL_ADDREF(nsWindowWatcher)
     274          16 : NS_IMPL_RELEASE(nsWindowWatcher)
     275          51 : NS_IMPL_QUERY_INTERFACE(nsWindowWatcher,
     276             :                         nsIWindowWatcher,
     277             :                         nsIPromptFactory,
     278             :                         nsPIWindowWatcher)
     279             : 
     280           2 : nsWindowWatcher::nsWindowWatcher()
     281             :   : mEnumeratorList()
     282             :   , mOldestWindow(0)
     283           2 :   , mListLock("nsWindowWatcher.mListLock")
     284             : {
     285           2 : }
     286             : 
     287           0 : nsWindowWatcher::~nsWindowWatcher()
     288             : {
     289             :   // delete data
     290           0 :   while (mOldestWindow) {
     291           0 :     RemoveWindow(mOldestWindow);
     292             :   }
     293           0 : }
     294             : 
     295             : nsresult
     296           2 : nsWindowWatcher::Init()
     297             : {
     298           2 :   return NS_OK;
     299             : }
     300             : 
     301             : /**
     302             :  * Convert aArguments into either an nsIArray or nullptr.
     303             :  *
     304             :  *  - If aArguments is nullptr, return nullptr.
     305             :  *  - If aArguments is an nsArray, return nullptr if it's empty, or otherwise
     306             :  *    return the array.
     307             :  *  - If aArguments is an nsIArray, return nullptr if it's empty, or
     308             :  *    otherwise just return the array.
     309             :  *  - Otherwise, return an nsIArray with one element: aArguments.
     310             :  */
     311             : static already_AddRefed<nsIArray>
     312           1 : ConvertArgsToArray(nsISupports* aArguments)
     313             : {
     314           1 :   if (!aArguments) {
     315           0 :     return nullptr;
     316             :   }
     317             : 
     318           2 :   nsCOMPtr<nsIArray> array = do_QueryInterface(aArguments);
     319           1 :   if (array) {
     320           1 :     uint32_t argc = 0;
     321           1 :     array->GetLength(&argc);
     322           1 :     if (argc == 0) {
     323           0 :       return nullptr;
     324             :     }
     325             : 
     326           1 :     return array.forget();
     327             :   }
     328             : 
     329             :   nsCOMPtr<nsIMutableArray> singletonArray =
     330           0 :     do_CreateInstance(NS_ARRAY_CONTRACTID);
     331           0 :   NS_ENSURE_TRUE(singletonArray, nullptr);
     332             : 
     333           0 :   nsresult rv = singletonArray->AppendElement(aArguments, /* aWeak = */ false);
     334           0 :   NS_ENSURE_SUCCESS(rv, nullptr);
     335             : 
     336           0 :   return singletonArray.forget();
     337             : }
     338             : 
     339             : NS_IMETHODIMP
     340           1 : nsWindowWatcher::OpenWindow(mozIDOMWindowProxy* aParent,
     341             :                             const char* aUrl,
     342             :                             const char* aName,
     343             :                             const char* aFeatures,
     344             :                             nsISupports* aArguments,
     345             :                             mozIDOMWindowProxy** aResult)
     346             : {
     347           2 :   nsCOMPtr<nsIArray> argv = ConvertArgsToArray(aArguments);
     348             : 
     349           1 :   uint32_t argc = 0;
     350           1 :   if (argv) {
     351           1 :     argv->GetLength(&argc);
     352             :   }
     353           1 :   bool dialog = (argc != 0);
     354             : 
     355           1 :   return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
     356             :                             /* calledFromJS = */ false, dialog,
     357             :                             /* navigate = */ true, argv,
     358             :                             /* aIsPopupSpam = */ false,
     359             :                             /* aForceNoOpener = */ false,
     360             :                             /* aLoadInfo = */ nullptr,
     361           2 :                             aResult);
     362             : }
     363             : 
     364             : struct SizeSpec
     365             : {
     366           1 :   SizeSpec()
     367           1 :     : mLeft(0)
     368             :     , mTop(0)
     369             :     , mOuterWidth(0)
     370             :     , mOuterHeight(0)
     371             :     , mInnerWidth(0)
     372             :     , mInnerHeight(0)
     373             :     , mLeftSpecified(false)
     374             :     , mTopSpecified(false)
     375             :     , mOuterWidthSpecified(false)
     376             :     , mOuterHeightSpecified(false)
     377             :     , mInnerWidthSpecified(false)
     378             :     , mInnerHeightSpecified(false)
     379             :     , mUseDefaultWidth(false)
     380           1 :     , mUseDefaultHeight(false)
     381             :   {
     382           1 :   }
     383             : 
     384             :   int32_t mLeft;
     385             :   int32_t mTop;
     386             :   int32_t mOuterWidth;  // Total window width
     387             :   int32_t mOuterHeight; // Total window height
     388             :   int32_t mInnerWidth;  // Content area width
     389             :   int32_t mInnerHeight; // Content area height
     390             : 
     391             :   bool mLeftSpecified;
     392             :   bool mTopSpecified;
     393             :   bool mOuterWidthSpecified;
     394             :   bool mOuterHeightSpecified;
     395             :   bool mInnerWidthSpecified;
     396             :   bool mInnerHeightSpecified;
     397             : 
     398             :   // If these booleans are true, don't look at the corresponding width values
     399             :   // even if they're specified -- they'll be bogus
     400             :   bool mUseDefaultWidth;
     401             :   bool mUseDefaultHeight;
     402             : 
     403           1 :   bool PositionSpecified() const
     404             :   {
     405           1 :     return mLeftSpecified || mTopSpecified;
     406             :   }
     407             : 
     408           1 :   bool SizeSpecified() const
     409             :   {
     410           3 :     return mOuterWidthSpecified || mOuterHeightSpecified ||
     411           3 :            mInnerWidthSpecified || mInnerHeightSpecified;
     412             :   }
     413             : };
     414             : 
     415             : NS_IMETHODIMP
     416           0 : nsWindowWatcher::OpenWindow2(mozIDOMWindowProxy* aParent,
     417             :                              const char* aUrl,
     418             :                              const char* aName,
     419             :                              const char* aFeatures,
     420             :                              bool aCalledFromScript,
     421             :                              bool aDialog,
     422             :                              bool aNavigate,
     423             :                              nsISupports* aArguments,
     424             :                              bool aIsPopupSpam,
     425             :                              bool aForceNoOpener,
     426             :                              nsIDocShellLoadInfo* aLoadInfo,
     427             :                              mozIDOMWindowProxy** aResult)
     428             : {
     429           0 :   nsCOMPtr<nsIArray> argv = ConvertArgsToArray(aArguments);
     430             : 
     431           0 :   uint32_t argc = 0;
     432           0 :   if (argv) {
     433           0 :     argv->GetLength(&argc);
     434             :   }
     435             : 
     436             :   // This is extremely messed up, but this behavior is necessary because
     437             :   // callers lie about whether they're a dialog window and whether they're
     438             :   // called from script.  Fixing this is bug 779939.
     439           0 :   bool dialog = aDialog;
     440           0 :   if (!aCalledFromScript) {
     441           0 :     dialog = argc > 0;
     442             :   }
     443             : 
     444           0 :   return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
     445             :                             aCalledFromScript, dialog,
     446             :                             aNavigate, argv, aIsPopupSpam,
     447           0 :                             aForceNoOpener, aLoadInfo, aResult);
     448             : }
     449             : 
     450             : // This static function checks if the aDocShell uses an UserContextId equal to
     451             : // the userContextId of subjectPrincipal, if not null.
     452             : static bool
     453           1 : CheckUserContextCompatibility(nsIDocShell* aDocShell)
     454             : {
     455           1 :   MOZ_ASSERT(aDocShell);
     456             : 
     457             :   uint32_t userContextId =
     458           1 :     static_cast<nsDocShell*>(aDocShell)->GetOriginAttributes().mUserContextId;
     459             : 
     460             :   nsCOMPtr<nsIPrincipal> subjectPrincipal =
     461           1 :     nsContentUtils::GetCurrentJSContext()
     462           2 :       ? nsContentUtils::SubjectPrincipal() : nullptr;
     463             : 
     464             :   // If we don't have a valid principal, probably we are in e10s mode, parent
     465             :   // side.
     466           1 :   if (!subjectPrincipal) {
     467           0 :     return true;
     468             :   }
     469             : 
     470             :   // DocShell can have UsercontextID set but loading a document with system
     471             :   // principal. In this case, we consider everything ok.
     472           1 :   if (nsContentUtils::IsSystemPrincipal(subjectPrincipal)) {
     473           1 :     return true;
     474             :   }
     475             : 
     476           0 :   return subjectPrincipal->GetUserContextId() == userContextId;
     477             : }
     478             : 
     479             : nsresult
     480           1 : nsWindowWatcher::CreateChromeWindow(const nsACString& aFeatures,
     481             :                                     nsIWebBrowserChrome* aParentChrome,
     482             :                                     uint32_t aChromeFlags,
     483             :                                     nsITabParent* aOpeningTabParent,
     484             :                                     mozIDOMWindowProxy* aOpener,
     485             :                                     uint64_t aNextTabParentId,
     486             :                                     nsIWebBrowserChrome** aResult)
     487             : {
     488           2 :   nsCOMPtr<nsIWindowCreator2> windowCreator2(do_QueryInterface(mWindowCreator));
     489           1 :   if (NS_WARN_IF(!windowCreator2)) {
     490           0 :     return NS_ERROR_UNEXPECTED;
     491             :   }
     492             : 
     493             :   // B2G multi-screen support. mozDisplayId is returned from the
     494             :   // "display-changed" event, it is also platform-dependent.
     495             : #ifdef MOZ_WIDGET_GONK
     496             :   int retval = WinHasOption(aFeatures, "mozDisplayId", 0, nullptr);
     497             :   windowCreator2->SetScreenId(retval);
     498             : #endif
     499             : 
     500           1 :   bool cancel = false;
     501           2 :   nsCOMPtr<nsIWebBrowserChrome> newWindowChrome;
     502             :   nsresult rv =
     503           2 :     windowCreator2->CreateChromeWindow2(aParentChrome, aChromeFlags,
     504             :                                         aOpeningTabParent, aOpener,
     505             :                                         aNextTabParentId, &cancel,
     506           2 :                                         getter_AddRefs(newWindowChrome));
     507             : 
     508           1 :   if (NS_SUCCEEDED(rv) && cancel) {
     509           0 :     newWindowChrome = nullptr;
     510           0 :     return NS_ERROR_ABORT;
     511             :   }
     512             : 
     513           1 :   newWindowChrome.forget(aResult);
     514           1 :   return NS_OK;
     515             : }
     516             : 
     517             : /**
     518             :  * Disable persistence of size/position in popups (determined by
     519             :  * determining whether the features parameter specifies width or height
     520             :  * in any way). We consider any overriding of the window's size or position
     521             :  * in the open call as disabling persistence of those attributes.
     522             :  * Popup windows (which should not persist size or position) generally set
     523             :  * the size.
     524             :  *
     525             :  * @param aFeatures
     526             :  *        The features string that was used to open the window.
     527             :  * @param aTreeOwner
     528             :  *        The nsIDocShellTreeOwner of the newly opened window. If null,
     529             :  *        this function is a no-op.
     530             :  */
     531             : void
     532           1 : nsWindowWatcher::MaybeDisablePersistence(const nsACString& aFeatures,
     533             :                                          nsIDocShellTreeOwner* aTreeOwner)
     534             : {
     535           1 :   if (!aTreeOwner) {
     536           0 :     return;
     537             :   }
     538             : 
     539             :  // At the moment, the strings "height=" or "width=" never happen
     540             :  // outside a size specification, so we can do this the Q&D way.
     541           2 :   if (PL_strcasestr(aFeatures.BeginReading(), "width=") ||
     542           1 :       PL_strcasestr(aFeatures.BeginReading(), "height=")) {
     543           0 :     aTreeOwner->SetPersistence(false, false, false);
     544             :   }
     545             : }
     546             : 
     547             : NS_IMETHODIMP
     548           0 : nsWindowWatcher::OpenWindowWithTabParent(nsITabParent* aOpeningTabParent,
     549             :                                          const nsACString& aFeatures,
     550             :                                          bool aCalledFromJS,
     551             :                                          float aOpenerFullZoom,
     552             :                                          uint64_t aNextTabParentId,
     553             :                                          bool aForceNoOpener,
     554             :                                          nsITabParent** aResult)
     555             : {
     556           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     557           0 :   MOZ_ASSERT(mWindowCreator);
     558             : 
     559           0 :   if (!nsContentUtils::IsSafeToRunScript()) {
     560           0 :     nsContentUtils::WarnScriptWasIgnored(nullptr);
     561           0 :     return NS_ERROR_FAILURE;
     562             :   }
     563             : 
     564           0 :   if (NS_WARN_IF(!mWindowCreator)) {
     565           0 :     return NS_ERROR_UNEXPECTED;
     566             :   }
     567             : 
     568             :   bool isPrivateBrowsingWindow =
     569           0 :     Preferences::GetBool("browser.privatebrowsing.autostart");
     570             : 
     571           0 :   nsCOMPtr<nsPIDOMWindowOuter> parentWindowOuter;
     572           0 :   if (aOpeningTabParent) {
     573             :     // We need to examine the window that aOpeningTabParent belongs to in
     574             :     // order to inform us of what kind of window we're going to open.
     575           0 :     TabParent* openingTab = TabParent::GetFrom(aOpeningTabParent);
     576           0 :     parentWindowOuter = openingTab->GetParentWindowOuter();
     577             : 
     578             :     // Propagate the privacy status of the parent window, if
     579             :     // available, to the child.
     580           0 :     if (!isPrivateBrowsingWindow) {
     581           0 :       nsCOMPtr<nsILoadContext> parentContext = openingTab->GetLoadContext();
     582           0 :       if (parentContext) {
     583           0 :         isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
     584             :       }
     585             :     }
     586             :   }
     587             : 
     588           0 :   if (!parentWindowOuter) {
     589             :     // We couldn't find a browser window for the opener, so either we
     590             :     // never were passed aOpeningTabParent, the window is closed,
     591             :     // or it's in the process of closing. Either way, we'll use
     592             :     // the most recently opened browser window instead.
     593           0 :     parentWindowOuter = nsContentUtils::GetMostRecentNonPBWindow();
     594             :   }
     595             : 
     596           0 :   if (NS_WARN_IF(!parentWindowOuter)) {
     597           0 :     return NS_ERROR_UNEXPECTED;
     598             :   }
     599             : 
     600           0 :   nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
     601           0 :   GetWindowTreeOwner(parentWindowOuter, getter_AddRefs(parentTreeOwner));
     602           0 :   if (NS_WARN_IF(!parentTreeOwner)) {
     603           0 :     return NS_ERROR_UNEXPECTED;
     604             :   }
     605             : 
     606           0 :   nsCOMPtr<nsIWindowCreator2> windowCreator2(do_QueryInterface(mWindowCreator));
     607           0 :   if (NS_WARN_IF(!windowCreator2)) {
     608           0 :     return NS_ERROR_UNEXPECTED;
     609             :   }
     610             : 
     611           0 :   uint32_t chromeFlags = CalculateChromeFlagsForChild(aFeatures);
     612             : 
     613             :   // A content process has asked for a new window, which implies
     614             :   // that the new window will need to be remote.
     615           0 :   chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
     616             : 
     617           0 :   nsCOMPtr<nsIWebBrowserChrome> parentChrome(do_GetInterface(parentTreeOwner));
     618           0 :   nsCOMPtr<nsIWebBrowserChrome> newWindowChrome;
     619             : 
     620           0 :   CreateChromeWindow(aFeatures, parentChrome, chromeFlags,
     621             :                      aForceNoOpener ? nullptr : aOpeningTabParent, nullptr,
     622             :                      aNextTabParentId,
     623           0 :                      getter_AddRefs(newWindowChrome));
     624             : 
     625           0 :   if (NS_WARN_IF(!newWindowChrome)) {
     626           0 :     return NS_ERROR_UNEXPECTED;
     627             :   }
     628             : 
     629           0 :   nsCOMPtr<nsIDocShellTreeItem> chromeTreeItem = do_GetInterface(newWindowChrome);
     630           0 :   if (NS_WARN_IF(!chromeTreeItem)) {
     631           0 :     return NS_ERROR_UNEXPECTED;
     632             :   }
     633             : 
     634           0 :   nsCOMPtr<nsIDocShellTreeOwner> chromeTreeOwner;
     635           0 :   chromeTreeItem->GetTreeOwner(getter_AddRefs(chromeTreeOwner));
     636           0 :   if (NS_WARN_IF(!chromeTreeOwner)) {
     637           0 :     return NS_ERROR_UNEXPECTED;
     638             :   }
     639             : 
     640           0 :   nsCOMPtr<nsILoadContext> chromeContext = do_QueryInterface(chromeTreeItem);
     641           0 :   if (NS_WARN_IF(!chromeContext)) {
     642           0 :     return NS_ERROR_UNEXPECTED;
     643             :   }
     644             : 
     645           0 :   chromeContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
     646             : 
     647             :   // Tabs opened from a content process can only open new windows
     648             :   // that will also run with out-of-process tabs.
     649           0 :   chromeContext->SetRemoteTabs(true);
     650             : 
     651           0 :   MaybeDisablePersistence(aFeatures, chromeTreeOwner);
     652             : 
     653           0 :   SizeSpec sizeSpec;
     654           0 :   CalcSizeSpec(aFeatures, sizeSpec);
     655           0 :   SizeOpenedWindow(chromeTreeOwner, parentWindowOuter, false, sizeSpec,
     656           0 :                    Some(aOpenerFullZoom));
     657             : 
     658           0 :   nsCOMPtr<nsITabParent> newTabParent;
     659           0 :   chromeTreeOwner->GetPrimaryTabParent(getter_AddRefs(newTabParent));
     660           0 :   if (NS_WARN_IF(!newTabParent)) {
     661           0 :     return NS_ERROR_UNEXPECTED;
     662             :   }
     663             : 
     664           0 :   newTabParent.forget(aResult);
     665           0 :   return NS_OK;
     666             : }
     667             : 
     668             : nsresult
     669           1 : nsWindowWatcher::OpenWindowInternal(mozIDOMWindowProxy* aParent,
     670             :                                     const char* aUrl,
     671             :                                     const char* aName,
     672             :                                     const char* aFeatures,
     673             :                                     bool aCalledFromJS,
     674             :                                     bool aDialog,
     675             :                                     bool aNavigate,
     676             :                                     nsIArray* aArgv,
     677             :                                     bool aIsPopupSpam,
     678             :                                     bool aForceNoOpener,
     679             :                                     nsIDocShellLoadInfo* aLoadInfo,
     680             :                                     mozIDOMWindowProxy** aResult)
     681             : {
     682           1 :   nsresult rv = NS_OK;
     683           1 :   bool isNewToplevelWindow = false;
     684           1 :   bool windowIsNew = false;
     685           1 :   bool windowNeedsName = false;
     686           1 :   bool windowIsModal = false;
     687           1 :   bool uriToLoadIsChrome = false;
     688           1 :   bool windowIsModalContentDialog = false;
     689             : 
     690             :   uint32_t chromeFlags;
     691           2 :   nsAutoString name;          // string version of aName
     692           2 :   nsAutoCString features;     // string version of aFeatures
     693           2 :   nsCOMPtr<nsIURI> uriToLoad; // from aUrl, if any
     694           2 :   nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner; // from the parent window, if any
     695           2 :   nsCOMPtr<nsIDocShellTreeItem> newDocShellItem; // from the new window
     696             : 
     697             :   nsCOMPtr<nsPIDOMWindowOuter> parent =
     698           2 :     aParent ? nsPIDOMWindowOuter::From(aParent) : nullptr;
     699             : 
     700           1 :   NS_ENSURE_ARG_POINTER(aResult);
     701           1 :   *aResult = 0;
     702             : 
     703           1 :   if (!nsContentUtils::IsSafeToRunScript()) {
     704           0 :     nsContentUtils::WarnScriptWasIgnored(nullptr);
     705           0 :     return NS_ERROR_FAILURE;
     706             :   }
     707             : 
     708           1 :   GetWindowTreeOwner(parent, getter_AddRefs(parentTreeOwner));
     709             : 
     710             :   // We expect TabParent to have provided us the absolute URI of the window
     711             :   // we're to open, so there's no need to call URIfromURL (or more importantly,
     712             :   // to check for a chrome URI, which cannot be opened from a remote tab).
     713           1 :   if (aUrl) {
     714           1 :     rv = URIfromURL(aUrl, aParent, getter_AddRefs(uriToLoad));
     715           1 :     if (NS_FAILED(rv)) {
     716           0 :       return rv;
     717             :     }
     718           1 :     uriToLoad->SchemeIs("chrome", &uriToLoadIsChrome);
     719             :   }
     720             : 
     721           1 :   bool nameSpecified = false;
     722           1 :   if (aName) {
     723           1 :     CopyUTF8toUTF16(aName, name);
     724           1 :     nameSpecified = true;
     725             :   } else {
     726           0 :     name.SetIsVoid(true);
     727             :   }
     728             : 
     729           1 :   if (aFeatures) {
     730           1 :     features.Assign(aFeatures);
     731           1 :     features.StripWhitespace();
     732             :   } else {
     733           0 :     features.SetIsVoid(true);
     734             :   }
     735             : 
     736             :   // try to find an extant window with the given name
     737             :   nsCOMPtr<nsPIDOMWindowOuter> foundWindow =
     738           2 :     SafeGetWindowByName(name, aForceNoOpener, aParent);
     739           1 :   GetWindowTreeItem(foundWindow, getter_AddRefs(newDocShellItem));
     740             : 
     741             :   // Do sandbox checks here, instead of waiting until nsIDocShell::LoadURI.
     742             :   // The state of the window can change before this call and if we are blocked
     743             :   // because of sandboxing, we wouldn't want that to happen.
     744             :   nsCOMPtr<nsPIDOMWindowOuter> parentWindow =
     745           2 :     aParent ? nsPIDOMWindowOuter::From(aParent) : nullptr;
     746           2 :   nsCOMPtr<nsIDocShell> parentDocShell;
     747           1 :   if (parentWindow) {
     748           0 :     parentDocShell = parentWindow->GetDocShell();
     749           0 :     if (parentDocShell) {
     750           0 :       nsCOMPtr<nsIDocShell> foundDocShell = do_QueryInterface(newDocShellItem);
     751           0 :       if (parentDocShell->IsSandboxedFrom(foundDocShell)) {
     752           0 :         return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     753             :       }
     754             :     }
     755             :   }
     756             : 
     757             :   // no extant window? make a new one.
     758             : 
     759             :   // If no parent, consider it chrome when running in the parent process.
     760           1 :   bool hasChromeParent = XRE_IsContentProcess() ? false : true;
     761           1 :   if (aParent) {
     762             :     // Check if the parent document has chrome privileges.
     763           0 :     nsIDocument* doc = parentWindow->GetDoc();
     764           0 :     hasChromeParent = doc && nsContentUtils::IsChromeDoc(doc);
     765             :   }
     766             : 
     767           1 :   bool isCallerChrome = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
     768             : 
     769             :   // Make sure we calculate the chromeFlags *before* we push the
     770             :   // callee context onto the context stack so that
     771             :   // the calculation sees the actual caller when doing its
     772             :   // security checks.
     773           1 :   if (isCallerChrome && XRE_IsParentProcess()) {
     774           1 :     chromeFlags = CalculateChromeFlagsForParent(aParent, features,
     775             :                                                 aDialog, uriToLoadIsChrome,
     776           1 :                                                 hasChromeParent, aCalledFromJS);
     777             :   } else {
     778           0 :     chromeFlags = CalculateChromeFlagsForChild(features);
     779             : 
     780             :     // Until ShowModalDialog is removed, it's still possible for content to
     781             :     // request dialogs, but only in single-process mode.
     782           0 :     if (aDialog) {
     783           0 :       MOZ_ASSERT(XRE_IsParentProcess());
     784           0 :       chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
     785             :     }
     786             :   }
     787             : 
     788             :   // If we're not called through our JS version of the API, and we got
     789             :   // our internal modal option, treat the window we're opening as a
     790             :   // modal content window (and set the modal chrome flag).
     791           2 :   if (!aCalledFromJS && aArgv &&
     792           1 :       WinHasOption(features, "-moz-internal-modal", 0, nullptr)) {
     793           0 :     windowIsModalContentDialog = true;
     794             : 
     795             :     // CHROME_MODAL gets inherited by dependent windows, which affects various
     796             :     // platform-specific window state (especially on OSX). So we need some way
     797             :     // to determine that this window was actually opened by nsGlobalWindow::
     798             :     // ShowModalDialog(), and that somebody is actually going to be watching
     799             :     // for return values and all that.
     800           0 :     chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL_CONTENT_WINDOW;
     801           0 :     chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL;
     802             :   }
     803             : 
     804           1 :   SizeSpec sizeSpec;
     805           1 :   CalcSizeSpec(features, sizeSpec);
     806             : 
     807             :   nsCOMPtr<nsIScriptSecurityManager> sm(
     808           2 :     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
     809             : 
     810             : 
     811             :   // XXXbz Why is an AutoJSAPI good enough here?  Wouldn't AutoEntryScript (so
     812             :   // we affect the entry global) make more sense?  Or do we just want to affect
     813             :   // GetSubjectPrincipal()?
     814           2 :   dom::AutoJSAPI jsapiChromeGuard;
     815             : 
     816             :   bool windowTypeIsChrome =
     817           1 :     chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
     818           1 :   if (isCallerChrome && !hasChromeParent && !windowTypeIsChrome) {
     819             :     // open() is called from chrome on a non-chrome window, initialize an
     820             :     // AutoJSAPI with the callee to prevent the caller's privileges from leaking
     821             :     // into code that runs while opening the new window.
     822             :     //
     823             :     // The reasoning for this is in bug 289204. Basically, chrome sometimes does
     824             :     // someContentWindow.open(untrustedURL), and wants to be insulated from nasty
     825             :     // javascript: URLs and such. But there are also cases where we create a
     826             :     // window parented to a content window (such as a download dialog), usually
     827             :     // directly with nsIWindowWatcher. In those cases, we want the principal of
     828             :     // the initial about:blank document to be system, so that the subsequent XUL
     829             :     // load can reuse the inner window and avoid blowing away expandos. As such,
     830             :     // we decide whether to load with the principal of the caller or of the parent
     831             :     // based on whether the docshell type is chrome or content.
     832             : 
     833           0 :     nsCOMPtr<nsIGlobalObject> parentGlobalObject = do_QueryInterface(aParent);
     834           0 :     if (!aParent) {
     835           0 :       jsapiChromeGuard.Init();
     836           0 :     } else if (NS_WARN_IF(!jsapiChromeGuard.Init(parentGlobalObject))) {
     837           0 :       return NS_ERROR_UNEXPECTED;
     838             :     }
     839             :   }
     840             : 
     841           1 :   uint32_t activeDocsSandboxFlags = 0;
     842           1 :   if (!newDocShellItem) {
     843             :     // We're going to either open up a new window ourselves or ask a
     844             :     // nsIWindowProvider for one.  In either case, we'll want to set the right
     845             :     // name on it.
     846           1 :     windowNeedsName = true;
     847             : 
     848             :     // If the parent trying to open a new window is sandboxed
     849             :     // without 'allow-popups', this is not allowed and we fail here.
     850           1 :     if (aParent) {
     851           0 :       if (nsIDocument* doc = parentWindow->GetDoc()) {
     852             :         // Save sandbox flags for copying to new browsing context (docShell).
     853           0 :         activeDocsSandboxFlags = doc->GetSandboxFlags();
     854           0 :         if (activeDocsSandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) {
     855           0 :           return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     856             :         }
     857             :       }
     858             :     }
     859             : 
     860             :     // Now check whether it's ok to ask a window provider for a window.  Don't
     861             :     // do it if we're opening a dialog or if our parent is a chrome window or
     862             :     // if we're opening something that has modal, dialog, or chrome flags set.
     863           2 :     nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(aParent);
     864           1 :     if (!aDialog && !chromeWin &&
     865           0 :         !(chromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
     866             :                          nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
     867             :                          nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) {
     868           0 :       nsCOMPtr<nsIWindowProvider> provider;
     869           0 :       if (parentTreeOwner) {
     870           0 :         provider = do_GetInterface(parentTreeOwner);
     871           0 :       } else if (XRE_IsContentProcess()) {
     872             :         // we're in a content process but we don't have a tabchild we can
     873             :         // use.
     874           0 :         provider = nsContentUtils::GetWindowProviderForContentProcess();
     875             :       }
     876             : 
     877           0 :       if (provider) {
     878           0 :         nsCOMPtr<mozIDOMWindowProxy> newWindow;
     879           0 :         rv = provider->ProvideWindow(aParent, chromeFlags, aCalledFromJS,
     880           0 :                                      sizeSpec.PositionSpecified(),
     881           0 :                                      sizeSpec.SizeSpecified(),
     882             :                                      uriToLoad, name, features, aForceNoOpener,
     883           0 :                                      &windowIsNew, getter_AddRefs(newWindow));
     884             : 
     885           0 :         if (NS_SUCCEEDED(rv)) {
     886           0 :           GetWindowTreeItem(newWindow, getter_AddRefs(newDocShellItem));
     887           0 :           if (windowIsNew && newDocShellItem) {
     888             :             // Make sure to stop any loads happening in this window that the
     889             :             // window provider might have started.  Otherwise if our caller
     890             :             // manipulates the window it just opened and then the load
     891             :             // completes their stuff will get blown away.
     892             :             nsCOMPtr<nsIWebNavigation> webNav =
     893           0 :               do_QueryInterface(newDocShellItem);
     894           0 :             webNav->Stop(nsIWebNavigation::STOP_NETWORK);
     895             :           }
     896             : 
     897             :           // If this is a new window, but it's incompatible with the current
     898             :           // userContextId, we ignore it and we pretend that nothing has been
     899             :           // returned by ProvideWindow.
     900           0 :           if (!windowIsNew && newDocShellItem) {
     901           0 :             nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(newDocShellItem);
     902           0 :             if (!CheckUserContextCompatibility(docShell)) {
     903           0 :               newWindow = nullptr;
     904           0 :               newDocShellItem = nullptr;
     905           0 :               windowIsNew = false;
     906             :             }
     907             :           }
     908             : 
     909           0 :         } else if (rv == NS_ERROR_ABORT) {
     910             :           // NS_ERROR_ABORT means the window provider has flat-out rejected
     911             :           // the open-window call and we should bail.  Don't return an error
     912             :           // here, because our caller may propagate that error, which might
     913             :           // cause e.g. window.open to throw!  Just return null for our out
     914             :           // param.
     915           0 :           return NS_OK;
     916             :         }
     917             :       }
     918             :     }
     919             :   }
     920             : 
     921           1 :   bool newWindowShouldBeModal = false;
     922           1 :   bool parentIsModal = false;
     923           1 :   if (!newDocShellItem) {
     924           1 :     windowIsNew = true;
     925           1 :     isNewToplevelWindow = true;
     926             : 
     927           2 :     nsCOMPtr<nsIWebBrowserChrome> parentChrome(do_GetInterface(parentTreeOwner));
     928             : 
     929             :     // is the parent (if any) modal? if so, we must be, too.
     930           1 :     bool weAreModal = (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL) != 0;
     931           1 :     newWindowShouldBeModal = weAreModal;
     932           1 :     if (!weAreModal && parentChrome) {
     933           0 :       parentChrome->IsWindowModal(&weAreModal);
     934           0 :       parentIsModal = weAreModal;
     935             :     }
     936             : 
     937           1 :     if (weAreModal) {
     938           0 :       windowIsModal = true;
     939             :       // in case we added this because weAreModal
     940           0 :       chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL |
     941             :                      nsIWebBrowserChrome::CHROME_DEPENDENT;
     942             :     }
     943             : 
     944             :     // Make sure to not create modal windows if our parent is invisible and
     945             :     // isn't a chrome window.  Otherwise we can end up in a bizarre situation
     946             :     // where we can't shut down because an invisible window is open.  If
     947             :     // someone tries to do this, throw.
     948           1 :     if (!hasChromeParent && (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL)) {
     949           0 :       nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(parentTreeOwner));
     950           0 :       nsCOMPtr<nsIWidget> parentWidget;
     951           0 :       if (parentWindow) {
     952           0 :         parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
     953             :       }
     954             :       // NOTE: the logic for this visibility check is duplicated in
     955             :       // nsIDOMWindowUtils::isParentWindowMainWidgetVisible - if we change
     956             :       // how a window is determined "visible" in this context then we should
     957             :       // also adjust that attribute and/or any consumers of it...
     958           0 :       if (parentWidget && !parentWidget->IsVisible()) {
     959           0 :         return NS_ERROR_NOT_AVAILABLE;
     960             :       }
     961             :     }
     962             : 
     963           1 :     NS_ASSERTION(mWindowCreator,
     964             :                  "attempted to open a new window with no WindowCreator");
     965           1 :     rv = NS_ERROR_FAILURE;
     966           1 :     if (mWindowCreator) {
     967           2 :       nsCOMPtr<nsIWebBrowserChrome> newChrome;
     968             : 
     969           2 :       nsCOMPtr<nsPIDOMWindowInner> parentTopInnerWindow;
     970           1 :       if (parentWindow) {
     971           0 :         nsCOMPtr<nsPIDOMWindowOuter> parentTopWindow = parentWindow->GetTop();
     972           0 :         if (parentTopWindow) {
     973           0 :           parentTopInnerWindow = parentTopWindow->GetCurrentInnerWindow();
     974             :         }
     975             :       }
     976             : 
     977           1 :       if (parentTopInnerWindow) {
     978           0 :         parentTopInnerWindow->Suspend();
     979             :       }
     980             : 
     981             :       /* If the window creator is an nsIWindowCreator2, we can give it
     982             :          some hints. The only hint at this time is whether the opening window
     983             :          is in a situation that's likely to mean this is an unrequested
     984             :          popup window we're creating. However we're not completely honest:
     985             :          we clear that indicator if the opener is chrome, so that the
     986             :          downstream consumer can treat the indicator to mean simply
     987             :          that the new window is subject to popup control. */
     988             :       nsCOMPtr<nsIWindowCreator2> windowCreator2(
     989           2 :         do_QueryInterface(mWindowCreator));
     990           1 :       if (windowCreator2) {
     991           1 :         mozIDOMWindowProxy* openerWindow = aForceNoOpener ? nullptr : aParent;
     992           1 :         rv = CreateChromeWindow(features, parentChrome, chromeFlags,
     993             :                                 nullptr, openerWindow, 0,
     994           2 :                                 getter_AddRefs(newChrome));
     995             : 
     996             :       } else {
     997           0 :         rv = mWindowCreator->CreateChromeWindow(parentChrome, chromeFlags,
     998           0 :                                                 getter_AddRefs(newChrome));
     999             :       }
    1000             : 
    1001           1 :       if (parentTopInnerWindow) {
    1002           0 :         parentTopInnerWindow->Resume();
    1003             :       }
    1004             : 
    1005           1 :       if (newChrome) {
    1006           2 :         nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(newChrome);
    1007           1 :         if (xulWin) {
    1008           2 :           nsCOMPtr<nsIXULBrowserWindow> xulBrowserWin;
    1009           1 :           xulWin->GetXULBrowserWindow(getter_AddRefs(xulBrowserWin));
    1010           1 :           if (xulBrowserWin) {
    1011           0 :             nsPIDOMWindowOuter* openerWindow = aForceNoOpener ? nullptr : parentWindow.get();
    1012           0 :             xulBrowserWin->ForceInitialBrowserNonRemote(openerWindow);
    1013             :           }
    1014             :         }
    1015             :         /* It might be a chrome nsXULWindow, in which case it won't have
    1016             :             an nsIDOMWindow (primary content shell). But in that case, it'll
    1017             :             be able to hand over an nsIDocShellTreeItem directly. */
    1018           2 :         nsCOMPtr<nsPIDOMWindowOuter> newWindow(do_GetInterface(newChrome));
    1019           1 :         if (newWindow) {
    1020           0 :           GetWindowTreeItem(newWindow, getter_AddRefs(newDocShellItem));
    1021             :         }
    1022           1 :         if (!newDocShellItem) {
    1023           1 :           newDocShellItem = do_GetInterface(newChrome);
    1024             :         }
    1025           1 :         if (!newDocShellItem) {
    1026           0 :           rv = NS_ERROR_FAILURE;
    1027             :         }
    1028             :       }
    1029             :     }
    1030             :   }
    1031             : 
    1032             :   // better have a window to use by this point
    1033           1 :   if (!newDocShellItem) {
    1034           0 :     return rv;
    1035             :   }
    1036             : 
    1037           2 :   nsCOMPtr<nsIDocShell> newDocShell(do_QueryInterface(newDocShellItem));
    1038           1 :   NS_ENSURE_TRUE(newDocShell, NS_ERROR_UNEXPECTED);
    1039             : 
    1040             :   // If our parent is sandboxed, set it as the one permitted sandboxed navigator
    1041             :   // on the new window we're opening.
    1042           1 :   if (activeDocsSandboxFlags && parentWindow) {
    1043           0 :     newDocShell->SetOnePermittedSandboxedNavigator(
    1044           0 :       parentWindow->GetDocShell());
    1045             :   }
    1046             : 
    1047             :   // Copy sandbox flags to the new window if activeDocsSandboxFlags says to do
    1048             :   // so.  Note that it's only nonzero if the window is new, so clobbering
    1049             :   // sandbox flags on the window makes sense in that case.
    1050           1 :   if (activeDocsSandboxFlags &
    1051             :         SANDBOX_PROPAGATES_TO_AUXILIARY_BROWSING_CONTEXTS) {
    1052           0 :     newDocShell->SetSandboxFlags(activeDocsSandboxFlags);
    1053             :   }
    1054             : 
    1055           1 :   rv = ReadyOpenedDocShellItem(newDocShellItem, parentWindow, windowIsNew,
    1056           1 :                                aForceNoOpener, aResult);
    1057           1 :   if (NS_FAILED(rv)) {
    1058           0 :     return rv;
    1059             :   }
    1060             : 
    1061           1 :   if (isNewToplevelWindow) {
    1062           2 :     nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
    1063           1 :     newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
    1064           1 :     MaybeDisablePersistence(features, newTreeOwner);
    1065             :   }
    1066             : 
    1067           1 :   if ((aDialog || windowIsModalContentDialog) && aArgv) {
    1068             :     // Set the args on the new window.
    1069           2 :     nsCOMPtr<nsPIDOMWindowOuter> piwin(do_QueryInterface(*aResult));
    1070           1 :     NS_ENSURE_TRUE(piwin, NS_ERROR_UNEXPECTED);
    1071             : 
    1072           1 :     rv = piwin->SetArguments(aArgv);
    1073           1 :     NS_ENSURE_SUCCESS(rv, rv);
    1074             :   }
    1075             : 
    1076             :   /* allow a window that we found by name to keep its name (important for cases
    1077             :      like _self where the given name is different (and invalid)).  Also, _blank
    1078             :      is not a window name. */
    1079           1 :   if (windowNeedsName) {
    1080           1 :     if (nameSpecified && !name.LowerCaseEqualsLiteral("_blank")) {
    1081           0 :       newDocShellItem->SetName(name);
    1082             :     } else {
    1083           1 :       newDocShellItem->SetName(EmptyString());
    1084             :     }
    1085             :   }
    1086             : 
    1087             :   // Now we have to set the right opener principal on the new window.  Note
    1088             :   // that we have to do this _before_ starting any URI loads, thanks to the
    1089             :   // sync nature of javascript: loads.
    1090             :   //
    1091             :   // Note: The check for the current JSContext isn't necessarily sensical.
    1092             :   // It's just designed to preserve old semantics during a mass-conversion
    1093             :   // patch.
    1094             :   nsCOMPtr<nsIPrincipal> subjectPrincipal =
    1095           1 :     nsContentUtils::GetCurrentJSContext() ? nsContentUtils::SubjectPrincipal() :
    1096           2 :                                             nullptr;
    1097             : 
    1098           1 :   bool isPrivateBrowsingWindow = false;
    1099             : 
    1100           1 :   if (windowIsNew) {
    1101           1 :     auto* docShell = static_cast<nsDocShell*>(newDocShell.get());
    1102             : 
    1103             :     // If this is not a chrome docShell, we apply originAttributes from the
    1104             :     // subjectPrincipal unless if it's an expanded or system principal.
    1105           2 :     if (subjectPrincipal &&
    1106           1 :         !nsContentUtils::IsSystemOrExpandedPrincipal(subjectPrincipal) &&
    1107           0 :         docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
    1108           0 :       isPrivateBrowsingWindow =
    1109           0 :         !!subjectPrincipal->OriginAttributesRef().mPrivateBrowsingId;
    1110           0 :       docShell->SetOriginAttributes(subjectPrincipal->OriginAttributesRef());
    1111             :     } else {
    1112           2 :       nsCOMPtr<nsIDocShellTreeItem> parentItem;
    1113           1 :       GetWindowTreeItem(aParent, getter_AddRefs(parentItem));
    1114           2 :       nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(parentItem);
    1115           1 :       if (parentContext) {
    1116           0 :         isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
    1117             :       }
    1118             :     }
    1119             : 
    1120             :     bool autoPrivateBrowsing =
    1121           1 :       Preferences::GetBool("browser.privatebrowsing.autostart");
    1122             : 
    1123           2 :     if (!autoPrivateBrowsing &&
    1124           1 :         (chromeFlags & nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW)) {
    1125           0 :       isPrivateBrowsingWindow = false;
    1126           2 :     } else if (autoPrivateBrowsing ||
    1127           1 :                (chromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW)) {
    1128           0 :       isPrivateBrowsingWindow = true;
    1129             :     }
    1130             : 
    1131             :     // Now set the opener principal on the new window.  Note that we need to do
    1132             :     // this no matter whether we were opened from JS; if there is nothing on
    1133             :     // the JS stack, just use the principal of our parent window.  In those
    1134             :     // cases we do _not_ set the parent window principal as the owner of the
    1135             :     // load--since we really don't know who the owner is, just leave it null.
    1136           2 :     nsCOMPtr<nsPIDOMWindowOuter> newWindow = do_QueryInterface(*aResult);
    1137           1 :     NS_ASSERTION(newWindow == newDocShell->GetWindow(), "Different windows??");
    1138             : 
    1139             :     // The principal of the initial about:blank document gets set up in
    1140             :     // nsWindowWatcher::AddWindow. Make sure to call it. In the common case
    1141             :     // this call already happened when the window was created, but
    1142             :     // SetInitialPrincipalToSubject is safe to call multiple times.
    1143           1 :     if (newWindow) {
    1144           1 :       newWindow->SetInitialPrincipalToSubject();
    1145           1 :       if (aIsPopupSpam) {
    1146           0 :         nsGlobalWindow* globalWin = nsGlobalWindow::Cast(newWindow);
    1147           0 :         MOZ_ASSERT(!globalWin->IsPopupSpamWindow(),
    1148             :                    "Who marked it as popup spam already???");
    1149           0 :         if (!globalWin->IsPopupSpamWindow()) { // Make sure we don't mess up our
    1150             :                                                // counter even if the above
    1151             :                                                // assert fails.
    1152           0 :           globalWin->SetIsPopupSpamWindow(true);
    1153             :         }
    1154             :       }
    1155             :     }
    1156             :   }
    1157             : 
    1158             :   // We rely on CalculateChromeFlags to decide whether remote (out-of-process)
    1159             :   // tabs should be used.
    1160             :   bool isRemoteWindow =
    1161           1 :     !!(chromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
    1162             : 
    1163           1 :   if (isNewToplevelWindow) {
    1164           2 :     nsCOMPtr<nsIDocShellTreeItem> childRoot;
    1165           1 :     newDocShellItem->GetRootTreeItem(getter_AddRefs(childRoot));
    1166           2 :     nsCOMPtr<nsILoadContext> childContext = do_QueryInterface(childRoot);
    1167           1 :     if (childContext) {
    1168           1 :       childContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
    1169           1 :       childContext->SetRemoteTabs(isRemoteWindow);
    1170             :     }
    1171           0 :   } else if (windowIsNew) {
    1172           0 :     nsCOMPtr<nsILoadContext> childContext = do_QueryInterface(newDocShellItem);
    1173           0 :     if (childContext) {
    1174           0 :       childContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
    1175           0 :       childContext->SetRemoteTabs(isRemoteWindow);
    1176             :     }
    1177             :   }
    1178             : 
    1179           2 :   nsCOMPtr<nsIDocShellLoadInfo> loadInfo = aLoadInfo;
    1180           1 :   if (uriToLoad && aNavigate && !loadInfo) {
    1181           1 :     newDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
    1182           1 :     NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
    1183             : 
    1184           1 :     if (subjectPrincipal) {
    1185           1 :       loadInfo->SetTriggeringPrincipal(subjectPrincipal);
    1186             :     }
    1187             : 
    1188             :     /* use the URL from the *extant* document, if any. The usual accessor
    1189             :        GetDocument will synchronously create an about:blank document if
    1190             :        it has no better answer, and we only care about a real document.
    1191             :        Also using GetDocument to force document creation seems to
    1192             :        screw up focus in the hidden window; see bug 36016.
    1193             :     */
    1194           2 :     nsCOMPtr<nsIDocument> doc = GetEntryDocument();
    1195           1 :     if (!doc && parentWindow) {
    1196           0 :       doc = parentWindow->GetExtantDoc();
    1197             :     }
    1198           1 :     if (doc) {
    1199             :       // Set the referrer
    1200           0 :       loadInfo->SetReferrer(doc->GetDocumentURI());
    1201           0 :       loadInfo->SetReferrerPolicy(doc->GetReferrerPolicy());
    1202             :     }
    1203             :   }
    1204             : 
    1205           1 :   if (isNewToplevelWindow) {
    1206             :     // Notify observers that the window is open and ready.
    1207             :     // The window has not yet started to load a document.
    1208             :     nsCOMPtr<nsIObserverService> obsSvc =
    1209           2 :       mozilla::services::GetObserverService();
    1210           1 :     if (obsSvc) {
    1211           1 :       obsSvc->NotifyObservers(*aResult, "toplevel-window-ready", nullptr);
    1212             :     }
    1213             :   }
    1214             : 
    1215             :   // Before loading the URI we want to be 100% sure that we use the correct
    1216             :   // userContextId.
    1217           1 :   MOZ_ASSERT(CheckUserContextCompatibility(newDocShell));
    1218             : 
    1219             :   // If this tab or window has been opened by a window.open call, we have to provide
    1220             :   // all the data needed to send a webNavigation.onCreatedNavigationTarget event.
    1221           1 :   if (parentDocShell && newDocShellItem) {
    1222             :     nsCOMPtr<nsIObserverService> obsSvc =
    1223           0 :       mozilla::services::GetObserverService();
    1224             : 
    1225           0 :     if (obsSvc) {
    1226           0 :       RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
    1227             : 
    1228           0 :       if (uriToLoad) {
    1229             :         // The url notified in the webNavigation.onCreatedNavigationTarget event.
    1230           0 :         props->SetPropertyAsACString(NS_LITERAL_STRING("url"),
    1231           0 :                                      uriToLoad->GetSpecOrDefault());
    1232             :       }
    1233             : 
    1234           0 :       props->SetPropertyAsInterface(NS_LITERAL_STRING("sourceTabDocShell"), parentDocShell);
    1235           0 :       props->SetPropertyAsInterface(NS_LITERAL_STRING("createdTabDocShell"), newDocShellItem);
    1236             : 
    1237           0 :       obsSvc->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
    1238           0 :                               "webNavigation-createdNavigationTarget-from-js", nullptr);
    1239             :     }
    1240             :   }
    1241             : 
    1242           1 :   if (uriToLoad && aNavigate) {
    1243           2 :     newDocShell->LoadURI(
    1244             :       uriToLoad,
    1245             :       loadInfo,
    1246             :       windowIsNew ?
    1247             :         static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) :
    1248             :         static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_NONE),
    1249           2 :       true);
    1250             :   }
    1251             : 
    1252             :   // Copy the current session storage for the current domain.
    1253           1 :   if (subjectPrincipal && parentDocShell) {
    1254             :     nsCOMPtr<nsIDOMStorageManager> parentStorageManager =
    1255           0 :       do_QueryInterface(parentDocShell);
    1256             :     nsCOMPtr<nsIDOMStorageManager> newStorageManager =
    1257           0 :       do_QueryInterface(newDocShell);
    1258             : 
    1259           0 :     if (parentStorageManager && newStorageManager) {
    1260           0 :       nsCOMPtr<nsIDOMStorage> storage;
    1261           0 :       nsCOMPtr<nsPIDOMWindowInner> pInnerWin = parentWindow->GetCurrentInnerWindow();
    1262           0 :       parentStorageManager->GetStorage(pInnerWin, subjectPrincipal,
    1263             :                                        isPrivateBrowsingWindow,
    1264           0 :                                        getter_AddRefs(storage));
    1265           0 :       if (storage) {
    1266           0 :         newStorageManager->CloneStorage(storage);
    1267             :       }
    1268             :     }
    1269             :   }
    1270             : 
    1271           1 :   if (isNewToplevelWindow) {
    1272           2 :     nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
    1273           1 :     newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
    1274           1 :     SizeOpenedWindow(newTreeOwner, aParent, isCallerChrome, sizeSpec);
    1275             :   }
    1276             : 
    1277             :   // XXXbz isn't windowIsModal always true when windowIsModalContentDialog?
    1278           1 :   if (windowIsModal || windowIsModalContentDialog) {
    1279           0 :     nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
    1280           0 :     newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
    1281           0 :     nsCOMPtr<nsIWebBrowserChrome> newChrome(do_GetInterface(newTreeOwner));
    1282             : 
    1283             :     // Throw an exception here if no web browser chrome is available,
    1284             :     // we need that to show a modal window.
    1285           0 :     NS_ENSURE_TRUE(newChrome, NS_ERROR_NOT_AVAILABLE);
    1286             : 
    1287             :     // Dispatch dialog events etc, but we only want to do that if
    1288             :     // we're opening a modal content window (the helper classes are
    1289             :     // no-ops if given no window), for chrome dialogs we don't want to
    1290             :     // do any of that (it's done elsewhere for us).
    1291             :     // Make sure we maintain the state on an outer window, because
    1292             :     // that's where it lives; inner windows assert if you try to
    1293             :     // maintain the state on them.
    1294             :     nsAutoWindowStateHelper windowStateHelper(
    1295           0 :       parentWindow ? parentWindow->GetOuterWindow() : nullptr);
    1296             : 
    1297           0 :     if (!windowStateHelper.DefaultEnabled()) {
    1298             :       // Default to cancel not opening the modal window.
    1299           0 :       NS_RELEASE(*aResult);
    1300             : 
    1301           0 :       return NS_OK;
    1302             :     }
    1303             : 
    1304           0 :     bool isAppModal = false;
    1305           0 :     nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(newTreeOwner));
    1306           0 :     nsCOMPtr<nsIWidget> parentWidget;
    1307           0 :     if (parentWindow) {
    1308           0 :       parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
    1309           0 :       if (parentWidget) {
    1310           0 :         isAppModal = parentWidget->IsRunningAppModal();
    1311             :       }
    1312             :     }
    1313           0 :     if (parentWidget &&
    1314           0 :         ((!newWindowShouldBeModal && parentIsModal) || isAppModal)) {
    1315           0 :       parentWidget->SetFakeModal(true);
    1316             :     } else {
    1317             :       // Reset popup state while opening a modal dialog, and firing
    1318             :       // events about the dialog, to prevent the current state from
    1319             :       // being active the whole time a modal dialog is open.
    1320           0 :       nsAutoPopupStatePusher popupStatePusher(openAbused);
    1321             : 
    1322           0 :       newChrome->ShowAsModal();
    1323             :     }
    1324             :   }
    1325             : 
    1326           1 :   if (aForceNoOpener && windowIsNew) {
    1327           0 :     NS_RELEASE(*aResult);
    1328             :   }
    1329             : 
    1330           1 :   return NS_OK;
    1331             : }
    1332             : 
    1333             : NS_IMETHODIMP
    1334           1 : nsWindowWatcher::RegisterNotification(nsIObserver* aObserver)
    1335             : {
    1336             :   // just a convenience method; it delegates to nsIObserverService
    1337             : 
    1338           1 :   if (!aObserver) {
    1339           0 :     return NS_ERROR_INVALID_ARG;
    1340             :   }
    1341             : 
    1342           2 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    1343           1 :   if (!os) {
    1344           0 :     return NS_ERROR_FAILURE;
    1345             :   }
    1346             : 
    1347           1 :   nsresult rv = os->AddObserver(aObserver, "domwindowopened", false);
    1348           1 :   if (NS_SUCCEEDED(rv)) {
    1349           1 :     rv = os->AddObserver(aObserver, "domwindowclosed", false);
    1350             :   }
    1351             : 
    1352           1 :   return rv;
    1353             : }
    1354             : 
    1355             : NS_IMETHODIMP
    1356           0 : nsWindowWatcher::UnregisterNotification(nsIObserver* aObserver)
    1357             : {
    1358             :   // just a convenience method; it delegates to nsIObserverService
    1359             : 
    1360           0 :   if (!aObserver) {
    1361           0 :     return NS_ERROR_INVALID_ARG;
    1362             :   }
    1363             : 
    1364           0 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    1365           0 :   if (!os) {
    1366           0 :     return NS_ERROR_FAILURE;
    1367             :   }
    1368             : 
    1369           0 :   os->RemoveObserver(aObserver, "domwindowopened");
    1370           0 :   os->RemoveObserver(aObserver, "domwindowclosed");
    1371             : 
    1372           0 :   return NS_OK;
    1373             : }
    1374             : 
    1375             : NS_IMETHODIMP
    1376           0 : nsWindowWatcher::GetWindowEnumerator(nsISimpleEnumerator** aResult)
    1377             : {
    1378           0 :   if (!aResult) {
    1379           0 :     return NS_ERROR_INVALID_ARG;
    1380             :   }
    1381             : 
    1382           0 :   MutexAutoLock lock(mListLock);
    1383           0 :   nsWatcherWindowEnumerator* enumerator = new nsWatcherWindowEnumerator(this);
    1384           0 :   if (enumerator) {
    1385           0 :     return CallQueryInterface(enumerator, aResult);
    1386             :   }
    1387             : 
    1388           0 :   return NS_ERROR_OUT_OF_MEMORY;
    1389             : }
    1390             : 
    1391             : NS_IMETHODIMP
    1392           0 : nsWindowWatcher::GetNewPrompter(mozIDOMWindowProxy* aParent, nsIPrompt** aResult)
    1393             : {
    1394             :   // This is for backwards compat only. Callers should just use the prompt
    1395             :   // service directly.
    1396             :   nsresult rv;
    1397             :   nsCOMPtr<nsIPromptFactory> factory =
    1398           0 :     do_GetService("@mozilla.org/prompter;1", &rv);
    1399           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1400           0 :   return factory->GetPrompt(aParent, NS_GET_IID(nsIPrompt),
    1401           0 :                             reinterpret_cast<void**>(aResult));
    1402             : }
    1403             : 
    1404             : NS_IMETHODIMP
    1405           0 : nsWindowWatcher::GetNewAuthPrompter(mozIDOMWindowProxy* aParent,
    1406             :                                     nsIAuthPrompt** aResult)
    1407             : {
    1408             :   // This is for backwards compat only. Callers should just use the prompt
    1409             :   // service directly.
    1410             :   nsresult rv;
    1411             :   nsCOMPtr<nsIPromptFactory> factory =
    1412           0 :     do_GetService("@mozilla.org/prompter;1", &rv);
    1413           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1414           0 :   return factory->GetPrompt(aParent, NS_GET_IID(nsIAuthPrompt),
    1415           0 :                             reinterpret_cast<void**>(aResult));
    1416             : }
    1417             : 
    1418             : NS_IMETHODIMP
    1419           0 : nsWindowWatcher::GetPrompt(mozIDOMWindowProxy* aParent, const nsIID& aIID,
    1420             :                            void** aResult)
    1421             : {
    1422             :   // This is for backwards compat only. Callers should just use the prompt
    1423             :   // service directly.
    1424             :   nsresult rv;
    1425             :   nsCOMPtr<nsIPromptFactory> factory =
    1426           0 :     do_GetService("@mozilla.org/prompter;1", &rv);
    1427           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1428           0 :   rv = factory->GetPrompt(aParent, aIID, aResult);
    1429             : 
    1430             :   // Allow for an embedding implementation to not support nsIAuthPrompt2.
    1431           0 :   if (rv == NS_NOINTERFACE && aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
    1432           0 :     nsCOMPtr<nsIAuthPrompt> oldPrompt;
    1433           0 :     rv = factory->GetPrompt(
    1434           0 :       aParent, NS_GET_IID(nsIAuthPrompt), getter_AddRefs(oldPrompt));
    1435           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1436             : 
    1437           0 :     NS_WrapAuthPrompt(oldPrompt, reinterpret_cast<nsIAuthPrompt2**>(aResult));
    1438           0 :     if (!*aResult) {
    1439           0 :       rv = NS_ERROR_NOT_AVAILABLE;
    1440             :     }
    1441             :   }
    1442           0 :   return rv;
    1443             : }
    1444             : 
    1445             : NS_IMETHODIMP
    1446           1 : nsWindowWatcher::SetWindowCreator(nsIWindowCreator* aCreator)
    1447             : {
    1448           1 :   mWindowCreator = aCreator;
    1449           1 :   return NS_OK;
    1450             : }
    1451             : 
    1452             : NS_IMETHODIMP
    1453           0 : nsWindowWatcher::HasWindowCreator(bool* aResult)
    1454             : {
    1455           0 :   *aResult = mWindowCreator;
    1456           0 :   return NS_OK;
    1457             : }
    1458             : 
    1459             : NS_IMETHODIMP
    1460           0 : nsWindowWatcher::GetActiveWindow(mozIDOMWindowProxy** aActiveWindow)
    1461             : {
    1462           0 :   *aActiveWindow = nullptr;
    1463           0 :   nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
    1464           0 :   if (fm) {
    1465           0 :     return fm->GetActiveWindow(aActiveWindow);
    1466             :   }
    1467           0 :   return NS_OK;
    1468             : }
    1469             : 
    1470             : NS_IMETHODIMP
    1471           0 : nsWindowWatcher::SetActiveWindow(mozIDOMWindowProxy* aActiveWindow)
    1472             : {
    1473           0 :   nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
    1474           0 :   if (fm) {
    1475           0 :     return fm->SetActiveWindow(aActiveWindow);
    1476             :   }
    1477           0 :   return NS_OK;
    1478             : }
    1479             : 
    1480             : NS_IMETHODIMP
    1481           2 : nsWindowWatcher::AddWindow(mozIDOMWindowProxy* aWindow, nsIWebBrowserChrome* aChrome)
    1482             : {
    1483           2 :   if (!aWindow) {
    1484           0 :     return NS_ERROR_INVALID_ARG;
    1485             :   }
    1486             : 
    1487             : #ifdef DEBUG
    1488             :   {
    1489           4 :     nsCOMPtr<nsPIDOMWindowOuter> win(do_QueryInterface(aWindow));
    1490             : 
    1491           2 :     NS_ASSERTION(win->IsOuterWindow(),
    1492             :                  "Uh, the active window must be an outer window!");
    1493             :   }
    1494             : #endif
    1495             : 
    1496             :   {
    1497             :     nsWatcherWindowEntry* info;
    1498           4 :     MutexAutoLock lock(mListLock);
    1499             : 
    1500             :     // if we already have an entry for this window, adjust
    1501             :     // its chrome mapping and return
    1502           2 :     info = FindWindowEntry(aWindow);
    1503           2 :     if (info) {
    1504             :       nsCOMPtr<nsISupportsWeakReference> supportsweak(
    1505           0 :         do_QueryInterface(aChrome));
    1506           0 :       if (supportsweak) {
    1507           0 :         supportsweak->GetWeakReference(getter_AddRefs(info->mChromeWeak));
    1508             :       } else {
    1509           0 :         info->mChrome = aChrome;
    1510           0 :         info->mChromeWeak = nullptr;
    1511             :       }
    1512           0 :       return NS_OK;
    1513             :     }
    1514             : 
    1515             :     // create a window info struct and add it to the list of windows
    1516           2 :     info = new nsWatcherWindowEntry(aWindow, aChrome);
    1517           2 :     if (!info) {
    1518           0 :       return NS_ERROR_OUT_OF_MEMORY;
    1519             :     }
    1520             : 
    1521           2 :     if (mOldestWindow) {
    1522           0 :       info->InsertAfter(mOldestWindow->mOlder);
    1523             :     } else {
    1524           2 :       mOldestWindow = info;
    1525             :     }
    1526             :   } // leave the mListLock
    1527             : 
    1528             :   // a window being added to us signifies a newly opened window.
    1529             :   // send notifications.
    1530           4 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    1531           2 :   if (!os) {
    1532           0 :     return NS_ERROR_FAILURE;
    1533             :   }
    1534             : 
    1535           4 :   nsCOMPtr<nsISupports> domwin(do_QueryInterface(aWindow));
    1536           2 :   return os->NotifyObservers(domwin, "domwindowopened", 0);
    1537             : }
    1538             : 
    1539             : NS_IMETHODIMP
    1540           0 : nsWindowWatcher::RemoveWindow(mozIDOMWindowProxy* aWindow)
    1541             : {
    1542             :   // find the corresponding nsWatcherWindowEntry, remove it
    1543             : 
    1544           0 :   if (!aWindow) {
    1545           0 :     return NS_ERROR_INVALID_ARG;
    1546             :   }
    1547             : 
    1548           0 :   nsWatcherWindowEntry* info = FindWindowEntry(aWindow);
    1549           0 :   if (info) {
    1550           0 :     RemoveWindow(info);
    1551           0 :     return NS_OK;
    1552             :   }
    1553           0 :   NS_WARNING("requested removal of nonexistent window");
    1554           0 :   return NS_ERROR_INVALID_ARG;
    1555             : }
    1556             : 
    1557             : nsWatcherWindowEntry*
    1558           2 : nsWindowWatcher::FindWindowEntry(mozIDOMWindowProxy* aWindow)
    1559             : {
    1560             :   // find the corresponding nsWatcherWindowEntry
    1561             :   nsWatcherWindowEntry* info;
    1562             :   nsWatcherWindowEntry* listEnd;
    1563             : #ifdef USEWEAKREFS
    1564             :   nsresult rv;
    1565             :   bool found;
    1566             : #endif
    1567             : 
    1568           2 :   info = mOldestWindow;
    1569           2 :   listEnd = 0;
    1570             : #ifdef USEWEAKREFS
    1571             :   rv = NS_OK;
    1572             :   found = false;
    1573             :   while (info != listEnd && NS_SUCCEEDED(rv)) {
    1574             :     nsCOMPtr<mozIDOMWindowProxy> infoWindow(do_QueryReferent(info->mWindow));
    1575             :     if (!infoWindow) { // clean up dangling reference, while we're here
    1576             :       rv = RemoveWindow(info);
    1577             :     } else if (infoWindow.get() == aWindow) {
    1578             :       return info;
    1579             :     }
    1580             : 
    1581             :     info = info->mYounger;
    1582             :     listEnd = mOldestWindow;
    1583             :   }
    1584             :   return 0;
    1585             : #else
    1586           2 :   while (info != listEnd) {
    1587           0 :     if (info->mWindow == aWindow) {
    1588           0 :       return info;
    1589             :     }
    1590           0 :     info = info->mYounger;
    1591           0 :     listEnd = mOldestWindow;
    1592             :   }
    1593           2 :   return 0;
    1594             : #endif
    1595             : }
    1596             : 
    1597             : nsresult
    1598           0 : nsWindowWatcher::RemoveWindow(nsWatcherWindowEntry* aInfo)
    1599             : {
    1600           0 :   uint32_t count = mEnumeratorList.Length();
    1601             : 
    1602             :   {
    1603             :     // notify the enumerators
    1604           0 :     MutexAutoLock lock(mListLock);
    1605           0 :     for (uint32_t ctr = 0; ctr < count; ++ctr) {
    1606           0 :       mEnumeratorList[ctr]->WindowRemoved(aInfo);
    1607             :     }
    1608             : 
    1609             :     // remove the element from the list
    1610           0 :     if (aInfo == mOldestWindow) {
    1611           0 :       mOldestWindow = aInfo->mYounger == mOldestWindow ? 0 : aInfo->mYounger;
    1612             :     }
    1613           0 :     aInfo->Unlink();
    1614             :   }
    1615             : 
    1616             :   // a window being removed from us signifies a newly closed window.
    1617             :   // send notifications.
    1618           0 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    1619           0 :   if (os) {
    1620             : #ifdef USEWEAKREFS
    1621             :     nsCOMPtr<nsISupports> domwin(do_QueryReferent(aInfo->mWindow));
    1622             :     if (domwin) {
    1623             :       os->NotifyObservers(domwin, "domwindowclosed", 0);
    1624             :     }
    1625             :     // else bummer. since the window is gone, there's nothing to notify with.
    1626             : #else
    1627           0 :     nsCOMPtr<nsISupports> domwin(do_QueryInterface(aInfo->mWindow));
    1628           0 :     os->NotifyObservers(domwin, "domwindowclosed", 0);
    1629             : #endif
    1630             :   }
    1631             : 
    1632           0 :   delete aInfo;
    1633           0 :   return NS_OK;
    1634             : }
    1635             : 
    1636             : NS_IMETHODIMP
    1637           0 : nsWindowWatcher::GetChromeForWindow(mozIDOMWindowProxy* aWindow,
    1638             :                                     nsIWebBrowserChrome** aResult)
    1639             : {
    1640           0 :   if (!aWindow || !aResult) {
    1641           0 :     return NS_ERROR_INVALID_ARG;
    1642             :   }
    1643           0 :   *aResult = 0;
    1644             : 
    1645           0 :   MutexAutoLock lock(mListLock);
    1646           0 :   nsWatcherWindowEntry* info = FindWindowEntry(aWindow);
    1647           0 :   if (info) {
    1648           0 :     if (info->mChromeWeak) {
    1649           0 :       return info->mChromeWeak->QueryReferent(
    1650           0 :         NS_GET_IID(nsIWebBrowserChrome), reinterpret_cast<void**>(aResult));
    1651             :     }
    1652           0 :     *aResult = info->mChrome;
    1653           0 :     NS_IF_ADDREF(*aResult);
    1654             :   }
    1655           0 :   return NS_OK;
    1656             : }
    1657             : 
    1658             : NS_IMETHODIMP
    1659           0 : nsWindowWatcher::GetWindowByName(const nsAString& aTargetName,
    1660             :                                  mozIDOMWindowProxy* aCurrentWindow,
    1661             :                                  mozIDOMWindowProxy** aResult)
    1662             : {
    1663           0 :   if (!aResult) {
    1664           0 :     return NS_ERROR_INVALID_ARG;
    1665             :   }
    1666             : 
    1667           0 :   *aResult = nullptr;
    1668             : 
    1669             :   nsPIDOMWindowOuter* currentWindow =
    1670           0 :     aCurrentWindow ? nsPIDOMWindowOuter::From(aCurrentWindow) : nullptr;
    1671             : 
    1672           0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem;
    1673             : 
    1674           0 :   nsCOMPtr<nsIDocShellTreeItem> startItem;
    1675           0 :   GetWindowTreeItem(currentWindow, getter_AddRefs(startItem));
    1676           0 :   if (startItem) {
    1677             :     // Note: original requestor is null here, per idl comments
    1678           0 :     startItem->FindItemWithName(aTargetName, nullptr, nullptr,
    1679             :                                 /* aSkipTabGroup = */ false,
    1680           0 :                                 getter_AddRefs(treeItem));
    1681             :   } else {
    1682             :     // Note: original requestor is null here, per idl comments
    1683           0 :     FindItemWithName(aTargetName, nullptr, nullptr, getter_AddRefs(treeItem));
    1684             :   }
    1685             : 
    1686           0 :   if (treeItem) {
    1687           0 :     nsCOMPtr<nsPIDOMWindowOuter> domWindow = treeItem->GetWindow();
    1688           0 :     domWindow.forget(aResult);
    1689             :   }
    1690             : 
    1691           0 :   return NS_OK;
    1692             : }
    1693             : 
    1694             : bool
    1695           0 : nsWindowWatcher::AddEnumerator(nsWatcherWindowEnumerator* aEnumerator)
    1696             : {
    1697             :   // (requires a lock; assumes it's called by someone holding the lock)
    1698           0 :   return mEnumeratorList.AppendElement(aEnumerator) != nullptr;
    1699             : }
    1700             : 
    1701             : bool
    1702           0 : nsWindowWatcher::RemoveEnumerator(nsWatcherWindowEnumerator* aEnumerator)
    1703             : {
    1704             :   // (requires a lock; assumes it's called by someone holding the lock)
    1705           0 :   return mEnumeratorList.RemoveElement(aEnumerator);
    1706             : }
    1707             : 
    1708             : nsresult
    1709           1 : nsWindowWatcher::URIfromURL(const char* aURL,
    1710             :                             mozIDOMWindowProxy* aParent,
    1711             :                             nsIURI** aURI)
    1712             : {
    1713             :   // Build the URI relative to the entry global.
    1714           2 :   nsCOMPtr<nsPIDOMWindowInner> baseWindow = do_QueryInterface(GetEntryGlobal());
    1715             : 
    1716             :   // failing that, build it relative to the parent window, if possible
    1717           1 :   if (!baseWindow && aParent) {
    1718           0 :     baseWindow = nsPIDOMWindowOuter::From(aParent)->GetCurrentInnerWindow();
    1719             :   }
    1720             : 
    1721             :   // failing that, use the given URL unmodified. It had better not be relative.
    1722             : 
    1723           1 :   nsIURI* baseURI = nullptr;
    1724             : 
    1725             :   // get baseWindow's document URI
    1726           1 :   if (baseWindow) {
    1727           0 :     if (nsIDocument* doc = baseWindow->GetDoc()) {
    1728           0 :       baseURI = doc->GetDocBaseURI();
    1729             :     }
    1730             :   }
    1731             : 
    1732             :   // build and return the absolute URI
    1733           2 :   return NS_NewURI(aURI, aURL, baseURI);
    1734             : }
    1735             : 
    1736             : #define NS_CALCULATE_CHROME_FLAG_FOR(feature, flag)                       \
    1737             :   prefBranch->GetBoolPref(feature, &forceEnable);                     \
    1738             :   if (forceEnable && !aDialog && !aHasChromeParent && !aChromeURL) {  \
    1739             :     chromeFlags |= flag;                                              \
    1740             :   } else {                                                            \
    1741             :     chromeFlags |=                                                    \
    1742             :       WinHasOption(aFeatures, feature, 0, &presenceFlag) ? flag : 0;  \
    1743             :   }
    1744             : 
    1745             : // static
    1746             : uint32_t
    1747           1 : nsWindowWatcher::CalculateChromeFlagsHelper(uint32_t aInitialFlags,
    1748             :                                             const nsACString& aFeatures,
    1749             :                                             bool& presenceFlag,
    1750             :                                             bool aDialog,
    1751             :                                             bool aHasChromeParent,
    1752             :                                             bool aChromeURL)
    1753             : {
    1754           1 :   uint32_t chromeFlags = aInitialFlags;
    1755             : 
    1756             :   nsresult rv;
    1757           2 :   nsCOMPtr<nsIPrefBranch> prefBranch;
    1758             :   nsCOMPtr<nsIPrefService> prefs =
    1759           2 :     do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
    1760             : 
    1761           1 :   NS_ENSURE_SUCCESS(rv, nsIWebBrowserChrome::CHROME_DEFAULT);
    1762             : 
    1763           2 :   rv = prefs->GetBranch("dom.disable_window_open_feature.",
    1764           2 :                         getter_AddRefs(prefBranch));
    1765             : 
    1766           1 :   NS_ENSURE_SUCCESS(rv, nsIWebBrowserChrome::CHROME_DEFAULT);
    1767             : 
    1768             :   // NS_CALCULATE_CHROME_FLAG_FOR requires aFeatures, forceEnable, aDialog
    1769             :   // aHasChromeParent, aChromeURL, presenceFlag and chromeFlags to be in
    1770             :   // scope.
    1771           1 :   bool forceEnable = false;
    1772             : 
    1773           1 :   NS_CALCULATE_CHROME_FLAG_FOR("titlebar",
    1774             :                                nsIWebBrowserChrome::CHROME_TITLEBAR);
    1775           1 :   NS_CALCULATE_CHROME_FLAG_FOR("close",
    1776             :                                nsIWebBrowserChrome::CHROME_WINDOW_CLOSE);
    1777           1 :   NS_CALCULATE_CHROME_FLAG_FOR("toolbar",
    1778             :                                nsIWebBrowserChrome::CHROME_TOOLBAR);
    1779           1 :   NS_CALCULATE_CHROME_FLAG_FOR("location",
    1780             :                                nsIWebBrowserChrome::CHROME_LOCATIONBAR);
    1781           1 :   NS_CALCULATE_CHROME_FLAG_FOR("personalbar",
    1782             :                                nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
    1783           1 :   NS_CALCULATE_CHROME_FLAG_FOR("status",
    1784             :                                nsIWebBrowserChrome::CHROME_STATUSBAR);
    1785           1 :   NS_CALCULATE_CHROME_FLAG_FOR("menubar",
    1786             :                                nsIWebBrowserChrome::CHROME_MENUBAR);
    1787           1 :   NS_CALCULATE_CHROME_FLAG_FOR("resizable",
    1788             :                                nsIWebBrowserChrome::CHROME_WINDOW_RESIZE);
    1789           1 :   NS_CALCULATE_CHROME_FLAG_FOR("minimizable",
    1790             :                                nsIWebBrowserChrome::CHROME_WINDOW_MIN);
    1791             : 
    1792             :   // default scrollbar to "on," unless explicitly turned off
    1793           1 :   if (WinHasOption(aFeatures, "scrollbars", 1, &presenceFlag) || !presenceFlag) {
    1794           0 :     chromeFlags |= nsIWebBrowserChrome::CHROME_SCROLLBARS;
    1795             :   }
    1796             : 
    1797           1 :   return chromeFlags;
    1798             : }
    1799             : 
    1800             : // static
    1801             : uint32_t
    1802           0 : nsWindowWatcher::EnsureFlagsSafeForContent(uint32_t aChromeFlags,
    1803             :                                            bool aChromeURL)
    1804             : {
    1805           0 :   aChromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR;
    1806           0 :   aChromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE;
    1807           0 :   aChromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_LOWERED;
    1808           0 :   aChromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_RAISED;
    1809           0 :   aChromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_POPUP;
    1810             :   /* Untrusted script is allowed to pose modal windows with a chrome
    1811             :      scheme. This check could stand to be better. But it effectively
    1812             :      prevents untrusted script from opening modal windows in general
    1813             :      while still allowing alerts and the like. */
    1814           0 :   if (!aChromeURL) {
    1815           0 :     aChromeFlags &= ~(nsIWebBrowserChrome::CHROME_MODAL |
    1816             :                      nsIWebBrowserChrome::CHROME_OPENAS_CHROME);
    1817             :   }
    1818             : 
    1819           0 :   if (!(aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)) {
    1820           0 :     aChromeFlags &= ~nsIWebBrowserChrome::CHROME_DEPENDENT;
    1821             :   }
    1822             : 
    1823           0 :   return aChromeFlags;
    1824             : }
    1825             : 
    1826             : /**
    1827             :  * Calculate the chrome bitmask from a string list of features requested
    1828             :  * from a child process. Feature strings that are restricted to the parent
    1829             :  * process are ignored here.
    1830             :  * @param aFeatures a string containing a list of named features
    1831             :  * @return the chrome bitmask
    1832             :  */
    1833             : // static
    1834             : uint32_t
    1835           0 : nsWindowWatcher::CalculateChromeFlagsForChild(const nsACString& aFeatures)
    1836             : {
    1837           0 :   if (aFeatures.IsVoid()) {
    1838           0 :     return nsIWebBrowserChrome::CHROME_ALL;
    1839             :   }
    1840             : 
    1841           0 :   bool presenceFlag = false;
    1842             :   uint32_t chromeFlags = CalculateChromeFlagsHelper(
    1843           0 :     nsIWebBrowserChrome::CHROME_WINDOW_BORDERS, aFeatures, presenceFlag);
    1844             : 
    1845           0 :   return EnsureFlagsSafeForContent(chromeFlags);
    1846             : }
    1847             : 
    1848             : /**
    1849             :  * Calculate the chrome bitmask from a string list of features for a new
    1850             :  * privileged window.
    1851             :  * @param aParent the opener window
    1852             :  * @param aFeatures a string containing a list of named chrome features
    1853             :  * @param aDialog affects the assumptions made about unnamed features
    1854             :  * @param aChromeURL true if the window is being sent to a chrome:// URL
    1855             :  * @param aHasChromeParent true if the parent window is privileged
    1856             :  * @param aCalledFromJS true if the window open request came from script.
    1857             :  * @return the chrome bitmask
    1858             :  */
    1859             : // static
    1860             : uint32_t
    1861           1 : nsWindowWatcher::CalculateChromeFlagsForParent(mozIDOMWindowProxy* aParent,
    1862             :                                                const nsACString& aFeatures,
    1863             :                                                bool aDialog,
    1864             :                                                bool aChromeURL,
    1865             :                                                bool aHasChromeParent,
    1866             :                                                bool aCalledFromJS)
    1867             : {
    1868           1 :   MOZ_ASSERT(XRE_IsParentProcess());
    1869           1 :   MOZ_ASSERT(nsContentUtils::LegacyIsCallerChromeOrNativeCode());
    1870             : 
    1871           1 :   uint32_t chromeFlags = 0;
    1872             : 
    1873             :   // The features string is made void by OpenWindowInternal
    1874             :   // if nullptr was originally passed as the features string.
    1875           1 :   if (aFeatures.IsVoid()) {
    1876           0 :     chromeFlags = nsIWebBrowserChrome::CHROME_ALL;
    1877           0 :     if (aDialog) {
    1878           0 :       chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
    1879             :                      nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
    1880             :     }
    1881             :   } else {
    1882           1 :     chromeFlags = nsIWebBrowserChrome::CHROME_WINDOW_BORDERS;
    1883             :   }
    1884             : 
    1885             :   /* This function has become complicated since browser windows and
    1886             :      dialogs diverged. The difference is, browser windows assume all
    1887             :      chrome not explicitly mentioned is off, if the features string
    1888             :      is not null. Exceptions are some OS border chrome new with Mozilla.
    1889             :      Dialogs interpret a (mostly) empty features string to mean
    1890             :      "OS's choice," and also support an "all" flag explicitly disallowed
    1891             :      in the standards-compliant window.(normal)open. */
    1892             : 
    1893           1 :   bool presenceFlag = false;
    1894           1 :   if (aDialog && WinHasOption(aFeatures, "all", 0, &presenceFlag)) {
    1895           1 :     chromeFlags = nsIWebBrowserChrome::CHROME_ALL;
    1896             :   }
    1897             : 
    1898             :   /* Next, allow explicitly named options to override the initial settings */
    1899           1 :   chromeFlags = CalculateChromeFlagsHelper(chromeFlags, aFeatures, presenceFlag,
    1900           1 :                                            aDialog, aHasChromeParent, aChromeURL);
    1901             : 
    1902             :   // Determine whether the window is a private browsing window
    1903           1 :   chromeFlags |= WinHasOption(aFeatures, "private", 0, &presenceFlag) ?
    1904             :     nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW : 0;
    1905           1 :   chromeFlags |= WinHasOption(aFeatures, "non-private", 0, &presenceFlag) ?
    1906             :     nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW : 0;
    1907             : 
    1908             :   // Determine whether the window should have remote tabs.
    1909           1 :   bool remote = BrowserTabsRemoteAutostart();
    1910             : 
    1911           1 :   if (remote) {
    1912           1 :     remote = !WinHasOption(aFeatures, "non-remote", 0, &presenceFlag);
    1913             :   } else {
    1914           0 :     remote = WinHasOption(aFeatures, "remote", 0, &presenceFlag);
    1915             :   }
    1916             : 
    1917           1 :   if (remote) {
    1918           1 :     chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
    1919             :   }
    1920             : 
    1921           1 :   chromeFlags |= WinHasOption(aFeatures, "popup", 0, &presenceFlag) ?
    1922             :     nsIWebBrowserChrome::CHROME_WINDOW_POPUP : 0;
    1923             : 
    1924             :   /* OK.
    1925             :      Normal browser windows, in spite of a stated pattern of turning off
    1926             :      all chrome not mentioned explicitly, will want the new OS chrome (window
    1927             :      borders, titlebars, closebox) on, unless explicitly turned off.
    1928             :      Dialogs, on the other hand, take the absence of any explicit settings
    1929             :      to mean "OS' choice." */
    1930             : 
    1931             :   // default titlebar and closebox to "on," if not mentioned at all
    1932           1 :   if (!(chromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)) {
    1933           1 :     if (!PL_strcasestr(aFeatures.BeginReading(), "titlebar")) {
    1934           1 :       chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR;
    1935             :     }
    1936           1 :     if (!PL_strcasestr(aFeatures.BeginReading(), "close")) {
    1937           1 :       chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE;
    1938             :     }
    1939             :   }
    1940             : 
    1941           1 :   if (aDialog && !aFeatures.IsVoid() && !presenceFlag) {
    1942           0 :     chromeFlags = nsIWebBrowserChrome::CHROME_DEFAULT;
    1943             :   }
    1944             : 
    1945             :   /* Finally, once all the above normal chrome has been divined, deal
    1946             :      with the features that are more operating hints than appearance
    1947             :      instructions. (Note modality implies dependence.) */
    1948             : 
    1949           2 :   if (WinHasOption(aFeatures, "alwaysLowered", 0, nullptr) ||
    1950           1 :       WinHasOption(aFeatures, "z-lock", 0, nullptr)) {
    1951           0 :     chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_LOWERED;
    1952           1 :   } else if (WinHasOption(aFeatures, "alwaysRaised", 0, nullptr)) {
    1953           0 :     chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_RAISED;
    1954             :   }
    1955             : 
    1956           1 :   chromeFlags |= WinHasOption(aFeatures, "suppressanimation", 0, nullptr) ?
    1957             :     nsIWebBrowserChrome::CHROME_SUPPRESS_ANIMATION : 0;
    1958             : 
    1959           1 :   chromeFlags |= WinHasOption(aFeatures, "chrome", 0, nullptr) ?
    1960             :     nsIWebBrowserChrome::CHROME_OPENAS_CHROME : 0;
    1961           1 :   chromeFlags |= WinHasOption(aFeatures, "extrachrome", 0, nullptr) ?
    1962             :     nsIWebBrowserChrome::CHROME_EXTRA : 0;
    1963           1 :   chromeFlags |= WinHasOption(aFeatures, "centerscreen", 0, nullptr) ?
    1964             :     nsIWebBrowserChrome::CHROME_CENTER_SCREEN : 0;
    1965           1 :   chromeFlags |= WinHasOption(aFeatures, "dependent", 0, nullptr) ?
    1966             :     nsIWebBrowserChrome::CHROME_DEPENDENT : 0;
    1967           1 :   chromeFlags |= WinHasOption(aFeatures, "modal", 0, nullptr) ?
    1968             :     (nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT) : 0;
    1969             : 
    1970             :   /* On mobile we want to ignore the dialog window feature, since the mobile UI
    1971             :      does not provide any affordance for dialog windows. This does not interfere
    1972             :      with dialog windows created through openDialog. */
    1973           1 :   bool disableDialogFeature = false;
    1974           2 :   nsCOMPtr<nsIPrefBranch> branch = do_GetService(NS_PREFSERVICE_CONTRACTID);
    1975             : 
    1976           1 :   branch->GetBoolPref("dom.disable_window_open_dialog_feature",
    1977           1 :                       &disableDialogFeature);
    1978             : 
    1979           1 :   if (!disableDialogFeature) {
    1980           1 :     chromeFlags |= WinHasOption(aFeatures, "dialog", 0, nullptr) ?
    1981             :       nsIWebBrowserChrome::CHROME_OPENAS_DIALOG : 0;
    1982             :   }
    1983             : 
    1984             :   /* and dialogs need to have the last word. assume dialogs are dialogs,
    1985             :      and opened as chrome, unless explicitly told otherwise. */
    1986           1 :   if (aDialog) {
    1987           1 :     if (!PL_strcasestr(aFeatures.BeginReading(), "dialog")) {
    1988           0 :       chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
    1989             :     }
    1990           1 :     if (!PL_strcasestr(aFeatures.BeginReading(), "chrome")) {
    1991           0 :       chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
    1992             :     }
    1993             :   }
    1994             : 
    1995             :   /* missing
    1996             :      chromeFlags->copy_history
    1997             :    */
    1998             : 
    1999             :   // Check security state for use in determing window dimensions
    2000           1 :   if (!aHasChromeParent) {
    2001           0 :     chromeFlags = EnsureFlagsSafeForContent(chromeFlags, aChromeURL);
    2002             :   }
    2003             : 
    2004             :   // Disable CHROME_OPENAS_DIALOG if the window is inside <iframe mozbrowser>.
    2005             :   // It's up to the embedder to interpret what dialog=1 means.
    2006           2 :   nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
    2007           1 :   if (docshell && docshell->GetIsInMozBrowser()) {
    2008           0 :     chromeFlags &= ~nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
    2009             :   }
    2010             : 
    2011           2 :   return chromeFlags;
    2012             : }
    2013             : 
    2014             : // static
    2015             : int32_t
    2016          36 : nsWindowWatcher::WinHasOption(const nsACString& aOptions, const char* aName,
    2017             :                               int32_t aDefault, bool* aPresenceFlag)
    2018             : {
    2019          36 :   if (aOptions.IsEmpty()) {
    2020           0 :     return 0;
    2021             :   }
    2022             : 
    2023          36 :   const char* options = aOptions.BeginReading();
    2024             :   char* comma;
    2025             :   char* equal;
    2026          36 :   int32_t found = 0;
    2027             : 
    2028             : #ifdef DEBUG
    2029          36 :   NS_ASSERTION(nsAutoCString(aOptions).FindCharInSet(" \n\r\t") == kNotFound,
    2030             :                "There should be no whitespace in this string!");
    2031             : #endif
    2032             : 
    2033             :   while (true) {
    2034         244 :     comma = PL_strchr(options, ',');
    2035         140 :     if (comma) {
    2036         106 :       *comma = '\0';
    2037             :     }
    2038         140 :     equal = PL_strchr(options, '=');
    2039         140 :     if (equal) {
    2040          35 :       *equal = '\0';
    2041             :     }
    2042         140 :     if (nsCRT::strcasecmp(options, aName) == 0) {
    2043           4 :       if (aPresenceFlag) {
    2044           1 :         *aPresenceFlag = true;
    2045             :       }
    2046           4 :       if (equal)
    2047           1 :         if (*(equal + 1) == '*') {
    2048           0 :           found = aDefault;
    2049           1 :         } else if (nsCRT::strcasecmp(equal + 1, "yes") == 0) {
    2050           0 :           found = 1;
    2051             :         } else {
    2052           1 :           found = atoi(equal + 1);
    2053             :         }
    2054             :       else {
    2055           3 :         found = 1;
    2056             :       }
    2057             :     }
    2058         140 :     if (equal) {
    2059          35 :       *equal = '=';
    2060             :     }
    2061         140 :     if (comma) {
    2062         106 :       *comma = ',';
    2063             :     }
    2064         140 :     if (found || !comma) {
    2065             :       break;
    2066             :     }
    2067         104 :     options = comma + 1;
    2068             :   }
    2069          36 :   return found;
    2070             : }
    2071             : 
    2072             : /* try to find an nsIDocShellTreeItem with the given name in any
    2073             :    known open window. a failure to find the item will not
    2074             :    necessarily return a failure method value. check aFoundItem.
    2075             : */
    2076             : NS_IMETHODIMP
    2077           1 : nsWindowWatcher::FindItemWithName(const nsAString& aName,
    2078             :                                   nsIDocShellTreeItem* aRequestor,
    2079             :                                   nsIDocShellTreeItem* aOriginalRequestor,
    2080             :                                   nsIDocShellTreeItem** aFoundItem)
    2081             : {
    2082           1 :   *aFoundItem = nullptr;
    2083           1 :   if (aName.IsEmpty()) {
    2084           0 :     return NS_OK;
    2085             :   }
    2086             : 
    2087           2 :   if (aName.LowerCaseEqualsLiteral("_blank") ||
    2088           0 :       aName.LowerCaseEqualsLiteral("_top") ||
    2089           1 :       aName.LowerCaseEqualsLiteral("_parent") ||
    2090           0 :       aName.LowerCaseEqualsLiteral("_self")) {
    2091           1 :     return NS_OK;
    2092             :   }
    2093             : 
    2094             :   // If we are looking for an item and we don't have a docshell we are checking
    2095             :   // on, let's just look in the chrome tab group!
    2096           0 :   return TabGroup::GetChromeTabGroup()->FindItemWithName(aName,
    2097             :                                                          aRequestor,
    2098             :                                                          aOriginalRequestor,
    2099           0 :                                                          aFoundItem);
    2100             : }
    2101             : 
    2102             : already_AddRefed<nsIDocShellTreeItem>
    2103           1 : nsWindowWatcher::GetCallerTreeItem(nsIDocShellTreeItem* aParentItem)
    2104             : {
    2105           2 :   nsCOMPtr<nsIWebNavigation> callerWebNav = do_GetInterface(GetEntryGlobal());
    2106           2 :   nsCOMPtr<nsIDocShellTreeItem> callerItem = do_QueryInterface(callerWebNav);
    2107           1 :   if (!callerItem) {
    2108           1 :     callerItem = aParentItem;
    2109             :   }
    2110             : 
    2111           2 :   return callerItem.forget();
    2112             : }
    2113             : 
    2114             : nsPIDOMWindowOuter*
    2115           1 : nsWindowWatcher::SafeGetWindowByName(const nsAString& aName,
    2116             :                                      bool aForceNoOpener,
    2117             :                                      mozIDOMWindowProxy* aCurrentWindow)
    2118             : {
    2119           1 :   if (aForceNoOpener) {
    2120           0 :     if (!aName.LowerCaseEqualsLiteral("_self") &&
    2121           0 :         !aName.LowerCaseEqualsLiteral("_top") &&
    2122           0 :         !aName.LowerCaseEqualsLiteral("_parent")) {
    2123             :       // Ignore all other names in the noopener case.
    2124           0 :       return nullptr;
    2125             :     }
    2126             :   }
    2127             : 
    2128           2 :   nsCOMPtr<nsIDocShellTreeItem> startItem;
    2129           1 :   GetWindowTreeItem(aCurrentWindow, getter_AddRefs(startItem));
    2130             : 
    2131           2 :   nsCOMPtr<nsIDocShellTreeItem> callerItem = GetCallerTreeItem(startItem);
    2132             : 
    2133           2 :   nsCOMPtr<nsIDocShellTreeItem> foundItem;
    2134           1 :   if (startItem) {
    2135           0 :     startItem->FindItemWithName(aName, nullptr, callerItem,
    2136             :                                 /* aSkipTabGroup = */ false,
    2137           0 :                                 getter_AddRefs(foundItem));
    2138             :   } else {
    2139           1 :     FindItemWithName(aName, nullptr, callerItem,
    2140           2 :                      getter_AddRefs(foundItem));
    2141             :   }
    2142             : 
    2143           1 :   return foundItem ? foundItem->GetWindow() : nullptr;
    2144             : }
    2145             : 
    2146             : /* Fetch the nsIDOMWindow corresponding to the given nsIDocShellTreeItem.
    2147             :    This forces the creation of a script context, if one has not already
    2148             :    been created. Note it also sets the window's opener to the parent,
    2149             :    if applicable -- because it's just convenient, that's all. null aParent
    2150             :    is acceptable. */
    2151             : nsresult
    2152           1 : nsWindowWatcher::ReadyOpenedDocShellItem(nsIDocShellTreeItem* aOpenedItem,
    2153             :                                          nsPIDOMWindowOuter* aParent,
    2154             :                                          bool aWindowIsNew,
    2155             :                                          bool aForceNoOpener,
    2156             :                                          mozIDOMWindowProxy** aOpenedWindow)
    2157             : {
    2158           1 :   nsresult rv = NS_ERROR_FAILURE;
    2159             : 
    2160           1 :   NS_ENSURE_ARG(aOpenedWindow);
    2161             : 
    2162           1 :   *aOpenedWindow = 0;
    2163           2 :   nsCOMPtr<nsPIDOMWindowOuter> piOpenedWindow = aOpenedItem->GetWindow();
    2164           1 :   if (piOpenedWindow) {
    2165           1 :     if (!aForceNoOpener) {
    2166           1 :       piOpenedWindow->SetOpenerWindow(aParent, aWindowIsNew); // damnit
    2167           0 :     } else if (aParent && aParent != piOpenedWindow) {
    2168           0 :       MOZ_ASSERT(piOpenedWindow->TabGroup() != aParent->TabGroup(),
    2169             :                  "If we're forcing no opener, they should be in different tab groups");
    2170             :     }
    2171             : 
    2172           1 :     if (aWindowIsNew) {
    2173             : #ifdef DEBUG
    2174             :       // Assert that we're not loading things right now.  If we are, when
    2175             :       // that load completes it will clobber whatever principals we set up
    2176             :       // on this new window!
    2177           2 :       nsCOMPtr<nsIDocumentLoader> docloader = do_QueryInterface(aOpenedItem);
    2178           1 :       NS_ASSERTION(docloader, "How can we not have a docloader here?");
    2179             : 
    2180           2 :       nsCOMPtr<nsIChannel> chan;
    2181           1 :       docloader->GetDocumentChannel(getter_AddRefs(chan));
    2182           1 :       NS_ASSERTION(!chan, "Why is there a document channel?");
    2183             : #endif
    2184             : 
    2185           2 :       nsCOMPtr<nsIDocument> doc = piOpenedWindow->GetExtantDoc();
    2186           1 :       if (doc) {
    2187           1 :         doc->SetIsInitialDocument(true);
    2188             :       }
    2189             :     }
    2190           1 :     rv = CallQueryInterface(piOpenedWindow, aOpenedWindow);
    2191             :   }
    2192           1 :   return rv;
    2193             : }
    2194             : 
    2195             : // static
    2196             : void
    2197           1 : nsWindowWatcher::CalcSizeSpec(const nsACString& aFeatures, SizeSpec& aResult)
    2198             : {
    2199             :   // Parse position spec, if any, from aFeatures
    2200             :   bool present;
    2201             :   int32_t temp;
    2202             : 
    2203           1 :   present = false;
    2204           1 :   if ((temp = WinHasOption(aFeatures, "left", 0, &present)) || present) {
    2205           0 :     aResult.mLeft = temp;
    2206           1 :   } else if ((temp = WinHasOption(aFeatures, "screenX", 0, &present)) ||
    2207             :              present) {
    2208           0 :     aResult.mLeft = temp;
    2209             :   }
    2210           1 :   aResult.mLeftSpecified = present;
    2211             : 
    2212           1 :   present = false;
    2213           1 :   if ((temp = WinHasOption(aFeatures, "top", 0, &present)) || present) {
    2214           0 :     aResult.mTop = temp;
    2215           1 :   } else if ((temp = WinHasOption(aFeatures, "screenY", 0, &present)) ||
    2216             :              present) {
    2217           0 :     aResult.mTop = temp;
    2218             :   }
    2219           1 :   aResult.mTopSpecified = present;
    2220             : 
    2221             :   // Parse size spec, if any. Chrome size overrides content size.
    2222           1 :   if ((temp = WinHasOption(aFeatures, "outerWidth", INT32_MIN, nullptr))) {
    2223           0 :     if (temp == INT32_MIN) {
    2224           0 :       aResult.mUseDefaultWidth = true;
    2225             :     } else {
    2226           0 :       aResult.mOuterWidth = temp;
    2227             :     }
    2228           0 :     aResult.mOuterWidthSpecified = true;
    2229           1 :   } else if ((temp = WinHasOption(aFeatures, "width", INT32_MIN, nullptr)) ||
    2230             :              (temp = WinHasOption(aFeatures, "innerWidth", INT32_MIN,
    2231             :                                   nullptr))) {
    2232           0 :     if (temp == INT32_MIN) {
    2233           0 :       aResult.mUseDefaultWidth = true;
    2234             :     } else {
    2235           0 :       aResult.mInnerWidth = temp;
    2236             :     }
    2237           0 :     aResult.mInnerWidthSpecified = true;
    2238             :   }
    2239             : 
    2240           1 :   if ((temp = WinHasOption(aFeatures, "outerHeight", INT32_MIN, nullptr))) {
    2241           0 :     if (temp == INT32_MIN) {
    2242           0 :       aResult.mUseDefaultHeight = true;
    2243             :     } else {
    2244           0 :       aResult.mOuterHeight = temp;
    2245             :     }
    2246           0 :     aResult.mOuterHeightSpecified = true;
    2247           1 :   } else if ((temp = WinHasOption(aFeatures, "height", INT32_MIN,
    2248           1 :                                   nullptr)) ||
    2249             :              (temp = WinHasOption(aFeatures, "innerHeight", INT32_MIN,
    2250             :                                   nullptr))) {
    2251           0 :     if (temp == INT32_MIN) {
    2252           0 :       aResult.mUseDefaultHeight = true;
    2253             :     } else {
    2254           0 :       aResult.mInnerHeight = temp;
    2255             :     }
    2256           0 :     aResult.mInnerHeightSpecified = true;
    2257             :   }
    2258           1 : }
    2259             : 
    2260             : /* Size and position a new window according to aSizeSpec. This method
    2261             :    is assumed to be called after the window has already been given
    2262             :    a default position and size; thus its current position and size are
    2263             :    accurate defaults. The new window is made visible at method end.
    2264             :    @param aTreeOwner
    2265             :           The top-level nsIDocShellTreeOwner of the newly opened window.
    2266             :    @param aParent (optional)
    2267             :           The parent window from which to inherit zoom factors from if
    2268             :           aOpenerFullZoom is none.
    2269             :    @param aIsCallerChrome
    2270             :           True if the code requesting the new window is privileged.
    2271             :    @param aSizeSpec
    2272             :           The size that the new window should be.
    2273             :    @param aOpenerFullZoom
    2274             :           If not nothing, a zoom factor to scale the content to.
    2275             : */
    2276             : void
    2277           1 : nsWindowWatcher::SizeOpenedWindow(nsIDocShellTreeOwner* aTreeOwner,
    2278             :                                   mozIDOMWindowProxy* aParent,
    2279             :                                   bool aIsCallerChrome,
    2280             :                                   const SizeSpec& aSizeSpec,
    2281             :                                   const Maybe<float>& aOpenerFullZoom)
    2282             : {
    2283             :   // We should only be sizing top-level windows if we're in the parent
    2284             :   // process.
    2285           1 :   MOZ_ASSERT(XRE_IsParentProcess());
    2286             : 
    2287             :   // position and size of window
    2288           1 :   int32_t left = 0, top = 0, width = 100, height = 100;
    2289             :   // difference between chrome and content size
    2290           1 :   int32_t chromeWidth = 0, chromeHeight = 0;
    2291             :   // whether the window size spec refers to chrome or content
    2292           1 :   bool sizeChromeWidth = true, sizeChromeHeight = true;
    2293             : 
    2294             :   // get various interfaces for aDocShellItem, used throughout this method
    2295           2 :   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(aTreeOwner));
    2296           1 :   if (!treeOwnerAsWin) { // we'll need this to actually size the docshell
    2297           0 :     return;
    2298             :   }
    2299             : 
    2300           1 :   double openerZoom = aOpenerFullZoom.valueOr(1.0);
    2301           1 :   if (aParent && aOpenerFullZoom.isNothing()) {
    2302           0 :     nsCOMPtr<nsPIDOMWindowOuter> piWindow = nsPIDOMWindowOuter::From(aParent);
    2303           0 :     if (nsIDocument* doc = piWindow->GetDoc()) {
    2304           0 :       if (nsIPresShell* shell = doc->GetShell()) {
    2305           0 :         if (nsPresContext* presContext = shell->GetPresContext()) {
    2306           0 :           openerZoom = presContext->GetFullZoom();
    2307             :         }
    2308             :       }
    2309             :     }
    2310             :   }
    2311             : 
    2312           1 :   double scale = 1.0;
    2313           1 :   treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale);
    2314             : 
    2315             :   /* The current position and size will be unchanged if not specified
    2316             :      (and they fit entirely onscreen). Also, calculate the difference
    2317             :      between chrome and content sizes on aDocShellItem's window.
    2318             :      This latter point becomes important if chrome and content
    2319             :      specifications are mixed in aFeatures, and when bringing the window
    2320             :      back from too far off the right or bottom edges of the screen. */
    2321             : 
    2322           1 :   treeOwnerAsWin->GetPositionAndSize(&left, &top, &width, &height);
    2323           1 :   left = NSToIntRound(left / scale);
    2324           1 :   top = NSToIntRound(top / scale);
    2325           1 :   width = NSToIntRound(width / scale);
    2326           1 :   height = NSToIntRound(height / scale);
    2327             :   {
    2328             :     int32_t contentWidth, contentHeight;
    2329           1 :     bool hasPrimaryContent = false;
    2330           1 :     aTreeOwner->GetHasPrimaryContent(&hasPrimaryContent);
    2331           1 :     if (hasPrimaryContent) {
    2332           0 :       aTreeOwner->GetPrimaryContentSize(&contentWidth, &contentHeight);
    2333             :     } else {
    2334           1 :       aTreeOwner->GetRootShellSize(&contentWidth, &contentHeight);
    2335             :     }
    2336           1 :     chromeWidth = width - contentWidth;
    2337           1 :     chromeHeight = height - contentHeight;
    2338             :   }
    2339             : 
    2340             :   // Set up left/top
    2341           1 :   if (aSizeSpec.mLeftSpecified) {
    2342           0 :     left = NSToIntRound(aSizeSpec.mLeft * openerZoom);
    2343             :   }
    2344             : 
    2345           1 :   if (aSizeSpec.mTopSpecified) {
    2346           0 :     top = NSToIntRound(aSizeSpec.mTop * openerZoom);
    2347             :   }
    2348             : 
    2349             :   // Set up width
    2350           1 :   if (aSizeSpec.mOuterWidthSpecified) {
    2351           0 :     if (!aSizeSpec.mUseDefaultWidth) {
    2352           0 :       width = NSToIntRound(aSizeSpec.mOuterWidth * openerZoom);
    2353             :     } // Else specified to default; just use our existing width
    2354           1 :   } else if (aSizeSpec.mInnerWidthSpecified) {
    2355           0 :     sizeChromeWidth = false;
    2356           0 :     if (aSizeSpec.mUseDefaultWidth) {
    2357           0 :       width = width - chromeWidth;
    2358             :     } else {
    2359           0 :       width = NSToIntRound(aSizeSpec.mInnerWidth * openerZoom);
    2360             :     }
    2361             :   }
    2362             : 
    2363             :   // Set up height
    2364           1 :   if (aSizeSpec.mOuterHeightSpecified) {
    2365           0 :     if (!aSizeSpec.mUseDefaultHeight) {
    2366           0 :       height = NSToIntRound(aSizeSpec.mOuterHeight * openerZoom);
    2367             :     } // Else specified to default; just use our existing height
    2368           1 :   } else if (aSizeSpec.mInnerHeightSpecified) {
    2369           0 :     sizeChromeHeight = false;
    2370           0 :     if (aSizeSpec.mUseDefaultHeight) {
    2371           0 :       height = height - chromeHeight;
    2372             :     } else {
    2373           0 :       height = NSToIntRound(aSizeSpec.mInnerHeight * openerZoom);
    2374             :     }
    2375             :   }
    2376             : 
    2377           1 :   bool positionSpecified = aSizeSpec.PositionSpecified();
    2378             : 
    2379             :   // Check security state for use in determing window dimensions
    2380           1 :   bool enabled = false;
    2381           1 :   if (aIsCallerChrome) {
    2382             :     // Only enable special priveleges for chrome when chrome calls
    2383             :     // open() on a chrome window
    2384           2 :     nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(aParent));
    2385           1 :     enabled = !aParent || chromeWin;
    2386             :   }
    2387             : 
    2388           1 :   if (!enabled) {
    2389             :     // Security check failed.  Ensure all args meet minimum reqs.
    2390             : 
    2391           0 :     int32_t oldTop = top, oldLeft = left;
    2392             : 
    2393             :     // We'll also need the screen dimensions
    2394           0 :     nsCOMPtr<nsIScreen> screen;
    2395             :     nsCOMPtr<nsIScreenManager> screenMgr(
    2396           0 :       do_GetService("@mozilla.org/gfx/screenmanager;1"));
    2397           0 :     if (screenMgr)
    2398           0 :       screenMgr->ScreenForRect(left, top, width, height,
    2399           0 :                                getter_AddRefs(screen));
    2400           0 :     if (screen) {
    2401             :       int32_t screenLeft, screenTop, screenWidth, screenHeight;
    2402           0 :       int32_t winWidth = width + (sizeChromeWidth ? 0 : chromeWidth),
    2403           0 :               winHeight = height + (sizeChromeHeight ? 0 : chromeHeight);
    2404             : 
    2405             :       // Get screen dimensions (in device pixels)
    2406           0 :       screen->GetAvailRect(&screenLeft, &screenTop, &screenWidth,
    2407           0 :                            &screenHeight);
    2408             :       // Convert them to CSS pixels
    2409           0 :       screenLeft = NSToIntRound(screenLeft / scale);
    2410           0 :       screenTop = NSToIntRound(screenTop / scale);
    2411           0 :       screenWidth = NSToIntRound(screenWidth / scale);
    2412           0 :       screenHeight = NSToIntRound(screenHeight / scale);
    2413             : 
    2414           0 :       if (aSizeSpec.SizeSpecified()) {
    2415           0 :         if (!nsContentUtils::ShouldResistFingerprinting()) {
    2416             :           /* Unlike position, force size out-of-bounds check only if
    2417             :              size actually was specified. Otherwise, intrinsically sized
    2418             :              windows are broken. */
    2419           0 :           if (height < 100) {
    2420           0 :             height = 100;
    2421           0 :             winHeight = height + (sizeChromeHeight ? 0 : chromeHeight);
    2422             :           }
    2423           0 :           if (winHeight > screenHeight) {
    2424           0 :             height = screenHeight - (sizeChromeHeight ? 0 : chromeHeight);
    2425             :           }
    2426           0 :           if (width < 100) {
    2427           0 :             width = 100;
    2428           0 :             winWidth = width + (sizeChromeWidth ? 0 : chromeWidth);
    2429             :           }
    2430           0 :           if (winWidth > screenWidth) {
    2431           0 :             width = screenWidth - (sizeChromeWidth ? 0 : chromeWidth);
    2432             :           }
    2433             :         } else {
    2434           0 :           int32_t targetContentWidth  = 0;
    2435           0 :           int32_t targetContentHeight = 0;
    2436             : 
    2437           0 :           nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(
    2438             :             chromeWidth,
    2439             :             chromeHeight,
    2440             :             screenWidth,
    2441             :             screenHeight,
    2442             :             width,
    2443             :             height,
    2444             :             sizeChromeWidth,
    2445             :             sizeChromeHeight,
    2446             :             &targetContentWidth,
    2447             :             &targetContentHeight
    2448           0 :           );
    2449             : 
    2450           0 :           if (aSizeSpec.mInnerWidthSpecified ||
    2451           0 :               aSizeSpec.mOuterWidthSpecified) {
    2452           0 :             width = targetContentWidth;
    2453           0 :             winWidth = width + (sizeChromeWidth ? 0 : chromeWidth);
    2454             :           }
    2455             : 
    2456           0 :           if (aSizeSpec.mInnerHeightSpecified ||
    2457           0 :               aSizeSpec.mOuterHeightSpecified) {
    2458           0 :             height = targetContentHeight;
    2459           0 :             winHeight = height + (sizeChromeHeight ? 0 : chromeHeight);
    2460             :           }
    2461             :         }
    2462             :       }
    2463             : 
    2464           0 :       if (left + winWidth > screenLeft + screenWidth ||
    2465           0 :           left + winWidth < left) {
    2466           0 :         left = screenLeft + screenWidth - winWidth;
    2467             :       }
    2468           0 :       if (left < screenLeft) {
    2469           0 :         left = screenLeft;
    2470             :       }
    2471           0 :       if (top + winHeight > screenTop + screenHeight || top + winHeight < top) {
    2472           0 :         top = screenTop + screenHeight - winHeight;
    2473             :       }
    2474           0 :       if (top < screenTop) {
    2475           0 :         top = screenTop;
    2476             :       }
    2477           0 :       if (top != oldTop || left != oldLeft) {
    2478           0 :         positionSpecified = true;
    2479             :       }
    2480             :     }
    2481             :   }
    2482             : 
    2483             :   // size and position the window
    2484             : 
    2485           1 :   if (positionSpecified) {
    2486             :     // Get the scale factor appropriate for the screen we're actually
    2487             :     // positioning on.
    2488           0 :     nsCOMPtr<nsIScreen> screen;
    2489             :     nsCOMPtr<nsIScreenManager> screenMgr(
    2490           0 :       do_GetService("@mozilla.org/gfx/screenmanager;1"));
    2491           0 :     if (screenMgr) {
    2492           0 :       screenMgr->ScreenForRect(left, top, 1, 1, getter_AddRefs(screen));
    2493             :     }
    2494           0 :     if (screen) {
    2495             :       double cssToDevPixScale, desktopToDevPixScale;
    2496           0 :       screen->GetDefaultCSSScaleFactor(&cssToDevPixScale);
    2497           0 :       screen->GetContentsScaleFactor(&desktopToDevPixScale);
    2498           0 :       double cssToDesktopScale = cssToDevPixScale / desktopToDevPixScale;
    2499             :       int32_t screenLeft, screenTop, screenWd, screenHt;
    2500           0 :       screen->GetRectDisplayPix(&screenLeft, &screenTop, &screenWd, &screenHt);
    2501             :       // Adjust by desktop-pixel origin of the target screen when scaling
    2502             :       // to convert from per-screen CSS-px coords to global desktop coords.
    2503           0 :       treeOwnerAsWin->SetPositionDesktopPix(
    2504           0 :         (left - screenLeft) * cssToDesktopScale + screenLeft,
    2505           0 :         (top - screenTop) * cssToDesktopScale + screenTop);
    2506             :     } else {
    2507             :       // Couldn't find screen? This shouldn't happen.
    2508           0 :       treeOwnerAsWin->SetPosition(left * scale, top * scale);
    2509             :     }
    2510             :     // This shouldn't be necessary, given the screen check above, but in case
    2511             :     // moving the window didn't put it where we expected (e.g. due to issues
    2512             :     // at the widget level, or whatever), let's re-fetch the scale factor for
    2513             :     // wherever it really ended up
    2514           0 :     treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale);
    2515             :   }
    2516           1 :   if (aSizeSpec.SizeSpecified()) {
    2517             :     /* Prefer to trust the interfaces, which think in terms of pure
    2518             :        chrome or content sizes. If we have a mix, use the chrome size
    2519             :        adjusted by the chrome/content differences calculated earlier. */
    2520           0 :     if (!sizeChromeWidth && !sizeChromeHeight) {
    2521           0 :       bool hasPrimaryContent = false;
    2522           0 :       aTreeOwner->GetHasPrimaryContent(&hasPrimaryContent);
    2523           0 :       if (hasPrimaryContent) {
    2524           0 :         aTreeOwner->SetPrimaryContentSize(width * scale, height * scale);
    2525             :       } else {
    2526           0 :         aTreeOwner->SetRootShellSize(width * scale, height * scale);
    2527           0 :       }
    2528             :     } else {
    2529           0 :       if (!sizeChromeWidth) {
    2530           0 :         width += chromeWidth;
    2531             :       }
    2532           0 :       if (!sizeChromeHeight) {
    2533           0 :         height += chromeHeight;
    2534             :       }
    2535           0 :       treeOwnerAsWin->SetSize(width * scale, height * scale, false);
    2536             :     }
    2537             :   }
    2538           1 :   treeOwnerAsWin->SetVisibility(true);
    2539             : }
    2540             : 
    2541             : void
    2542           4 : nsWindowWatcher::GetWindowTreeItem(mozIDOMWindowProxy* aWindow,
    2543             :                                    nsIDocShellTreeItem** aResult)
    2544             : {
    2545           4 :   *aResult = 0;
    2546             : 
    2547           4 :   if (aWindow) {
    2548           0 :     nsIDocShell* docshell = nsPIDOMWindowOuter::From(aWindow)->GetDocShell();
    2549           0 :     if (docshell) {
    2550           0 :       CallQueryInterface(docshell, aResult);
    2551             :     }
    2552             :   }
    2553           4 : }
    2554             : 
    2555             : void
    2556           1 : nsWindowWatcher::GetWindowTreeOwner(nsPIDOMWindowOuter* aWindow,
    2557             :                                     nsIDocShellTreeOwner** aResult)
    2558             : {
    2559           1 :   *aResult = 0;
    2560             : 
    2561           2 :   nsCOMPtr<nsIDocShellTreeItem> treeItem;
    2562           1 :   GetWindowTreeItem(aWindow, getter_AddRefs(treeItem));
    2563           1 :   if (treeItem) {
    2564           0 :     treeItem->GetTreeOwner(aResult);
    2565             :   }
    2566           1 : }
    2567             : 
    2568             : /* static */
    2569             : int32_t
    2570           0 : nsWindowWatcher::GetWindowOpenLocation(nsPIDOMWindowOuter* aParent,
    2571             :                                        uint32_t aChromeFlags,
    2572             :                                        bool aCalledFromJS,
    2573             :                                        bool aPositionSpecified,
    2574             :                                        bool aSizeSpecified)
    2575             : {
    2576           0 :   bool isFullScreen = aParent->GetFullScreen();
    2577             : 
    2578             :   // Where should we open this?
    2579             :   int32_t containerPref;
    2580           0 :   if (NS_FAILED(Preferences::GetInt("browser.link.open_newwindow",
    2581             :                                     &containerPref))) {
    2582             :     // We couldn't read the user preference, so fall back on the default.
    2583           0 :     return nsIBrowserDOMWindow::OPEN_NEWTAB;
    2584             :   }
    2585             : 
    2586             :   bool isDisabledOpenNewWindow =
    2587           0 :     isFullScreen &&
    2588           0 :     Preferences::GetBool("browser.link.open_newwindow.disabled_in_fullscreen");
    2589             : 
    2590           0 :   if (isDisabledOpenNewWindow &&
    2591           0 :       (containerPref == nsIBrowserDOMWindow::OPEN_NEWWINDOW)) {
    2592           0 :     containerPref = nsIBrowserDOMWindow::OPEN_NEWTAB;
    2593             :   }
    2594             : 
    2595           0 :   if (containerPref != nsIBrowserDOMWindow::OPEN_NEWTAB &&
    2596           0 :       containerPref != nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
    2597             :     // Just open a window normally
    2598           0 :     return nsIBrowserDOMWindow::OPEN_NEWWINDOW;
    2599             :   }
    2600             : 
    2601           0 :   if (aCalledFromJS) {
    2602             :     /* Now check our restriction pref.  The restriction pref is a power-user's
    2603             :        fine-tuning pref. values:
    2604             :        0: no restrictions - divert everything
    2605             :        1: don't divert window.open at all
    2606             :        2: don't divert window.open with features
    2607             :     */
    2608             :     int32_t restrictionPref =
    2609           0 :       Preferences::GetInt("browser.link.open_newwindow.restriction", 2);
    2610           0 :     if (restrictionPref < 0 || restrictionPref > 2) {
    2611           0 :       restrictionPref = 2; // Sane default behavior
    2612             :     }
    2613             : 
    2614           0 :     if (isDisabledOpenNewWindow) {
    2615             :       // In browser fullscreen, the window should be opened
    2616             :       // in the current window with no features (see bug 803675)
    2617           0 :       restrictionPref = 0;
    2618             :     }
    2619             : 
    2620           0 :     if (restrictionPref == 1) {
    2621           0 :       return nsIBrowserDOMWindow::OPEN_NEWWINDOW;
    2622             :     }
    2623             : 
    2624           0 :     if (restrictionPref == 2) {
    2625             :       // Only continue if there are no size/position features and no special
    2626             :       // chrome flags - with the exception of the remoteness and private flags,
    2627             :       // which might have been automatically flipped by Gecko.
    2628           0 :       int32_t uiChromeFlags = aChromeFlags;
    2629           0 :       uiChromeFlags &= ~(nsIWebBrowserChrome::CHROME_REMOTE_WINDOW |
    2630             :                          nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW |
    2631             :                          nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW |
    2632             :                          nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME);
    2633           0 :       if (uiChromeFlags != nsIWebBrowserChrome::CHROME_ALL ||
    2634           0 :           aPositionSpecified || aSizeSpecified) {
    2635           0 :         return nsIBrowserDOMWindow::OPEN_NEWWINDOW;
    2636             :       }
    2637             :     }
    2638             :   }
    2639             : 
    2640           0 :   return containerPref;
    2641             : }

Generated by: LCOV version 1.13