123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- //#define USEWEAKREFS // (haven't quite figured that out yet)
- #include "nsWindowWatcher.h"
- #include "nsAutoWindowStateHelper.h"
- #include "nsCRT.h"
- #include "nsNetUtil.h"
- #include "nsIAuthPrompt.h"
- #include "nsIAuthPrompt2.h"
- #include "nsISimpleEnumerator.h"
- #include "nsIInterfaceRequestorUtils.h"
- #include "nsJSUtils.h"
- #include "plstr.h"
- #include "nsDocShell.h"
- #include "nsGlobalWindow.h"
- #include "nsIBaseWindow.h"
- #include "nsIBrowserDOMWindow.h"
- #include "nsIDocShell.h"
- #include "nsIDocShellLoadInfo.h"
- #include "nsIDocShellTreeItem.h"
- #include "nsIDocShellTreeOwner.h"
- #include "nsIDocumentLoader.h"
- #include "nsIDocument.h"
- #include "nsIDOMDocument.h"
- #include "nsIDOMWindow.h"
- #include "nsIDOMChromeWindow.h"
- #include "nsIDOMModalContentWindow.h"
- #include "nsIPrompt.h"
- #include "nsIScriptObjectPrincipal.h"
- #include "nsIScreen.h"
- #include "nsIScreenManager.h"
- #include "nsIScriptContext.h"
- #include "nsIObserverService.h"
- #include "nsIScriptSecurityManager.h"
- #include "nsXPCOM.h"
- #include "nsIURI.h"
- #include "nsIWebBrowser.h"
- #include "nsIWebBrowserChrome.h"
- #include "nsIWebNavigation.h"
- #include "nsIWindowCreator.h"
- #include "nsIWindowCreator2.h"
- #include "nsIXPConnect.h"
- #include "nsIXULRuntime.h"
- #include "nsPIDOMWindow.h"
- #include "nsIContentViewer.h"
- #include "nsIWindowProvider.h"
- #include "nsIMutableArray.h"
- #include "nsIDOMStorageManager.h"
- #include "nsIWidget.h"
- #include "nsFocusManager.h"
- #include "nsIPresShell.h"
- #include "nsPresContext.h"
- #include "nsContentUtils.h"
- #include "nsIPrefBranch.h"
- #include "nsIPrefService.h"
- #include "nsSandboxFlags.h"
- #include "mozilla/Preferences.h"
- #include "mozilla/dom/DOMStorage.h"
- #include "mozilla/dom/ScriptSettings.h"
- #include "mozilla/dom/TabParent.h"
- #include "mozilla/dom/DocGroup.h"
- #include "mozilla/dom/TabGroup.h"
- #include "nsIXULWindow.h"
- #include "nsIXULBrowserWindow.h"
- #include "nsGlobalWindow.h"
- #ifdef USEWEAKREFS
- #include "nsIWeakReference.h"
- #endif
- using namespace mozilla;
- using namespace mozilla::dom;
- /****************************************************************
- ******************** nsWatcherWindowEntry **********************
- ****************************************************************/
- class nsWindowWatcher;
- struct nsWatcherWindowEntry
- {
- nsWatcherWindowEntry(mozIDOMWindowProxy* aWindow, nsIWebBrowserChrome* aChrome)
- : mChrome(nullptr)
- {
- #ifdef USEWEAKREFS
- mWindow = do_GetWeakReference(aWindow);
- #else
- mWindow = aWindow;
- #endif
- nsCOMPtr<nsISupportsWeakReference> supportsweak(do_QueryInterface(aChrome));
- if (supportsweak) {
- supportsweak->GetWeakReference(getter_AddRefs(mChromeWeak));
- } else {
- mChrome = aChrome;
- mChromeWeak = nullptr;
- }
- ReferenceSelf();
- }
- ~nsWatcherWindowEntry() {}
- void InsertAfter(nsWatcherWindowEntry* aOlder);
- void Unlink();
- void ReferenceSelf();
- #ifdef USEWEAKREFS
- nsCOMPtr<nsIWeakReference> mWindow;
- #else // still not an owning ref
- mozIDOMWindowProxy* mWindow;
- #endif
- nsIWebBrowserChrome* mChrome;
- nsWeakPtr mChromeWeak;
- // each struct is in a circular, doubly-linked list
- nsWatcherWindowEntry* mYounger; // next younger in sequence
- nsWatcherWindowEntry* mOlder;
- };
- void
- nsWatcherWindowEntry::InsertAfter(nsWatcherWindowEntry* aOlder)
- {
- if (aOlder) {
- mOlder = aOlder;
- mYounger = aOlder->mYounger;
- mOlder->mYounger = this;
- if (mOlder->mOlder == mOlder) {
- mOlder->mOlder = this;
- }
- mYounger->mOlder = this;
- if (mYounger->mYounger == mYounger) {
- mYounger->mYounger = this;
- }
- }
- }
- void
- nsWatcherWindowEntry::Unlink()
- {
- mOlder->mYounger = mYounger;
- mYounger->mOlder = mOlder;
- ReferenceSelf();
- }
- void
- nsWatcherWindowEntry::ReferenceSelf()
- {
- mYounger = this;
- mOlder = this;
- }
- /****************************************************************
- ****************** nsWatcherWindowEnumerator *******************
- ****************************************************************/
- class nsWatcherWindowEnumerator : public nsISimpleEnumerator
- {
- public:
- explicit nsWatcherWindowEnumerator(nsWindowWatcher* aWatcher);
- NS_IMETHOD HasMoreElements(bool* aResult) override;
- NS_IMETHOD GetNext(nsISupports** aResult) override;
- NS_DECL_ISUPPORTS
- protected:
- virtual ~nsWatcherWindowEnumerator();
- private:
- friend class nsWindowWatcher;
- nsWatcherWindowEntry* FindNext();
- void WindowRemoved(nsWatcherWindowEntry* aInfo);
- nsWindowWatcher* mWindowWatcher;
- nsWatcherWindowEntry* mCurrentPosition;
- };
- NS_IMPL_ADDREF(nsWatcherWindowEnumerator)
- NS_IMPL_RELEASE(nsWatcherWindowEnumerator)
- NS_IMPL_QUERY_INTERFACE(nsWatcherWindowEnumerator, nsISimpleEnumerator)
- nsWatcherWindowEnumerator::nsWatcherWindowEnumerator(nsWindowWatcher* aWatcher)
- : mWindowWatcher(aWatcher)
- , mCurrentPosition(aWatcher->mOldestWindow)
- {
- mWindowWatcher->AddEnumerator(this);
- mWindowWatcher->AddRef();
- }
- nsWatcherWindowEnumerator::~nsWatcherWindowEnumerator()
- {
- mWindowWatcher->RemoveEnumerator(this);
- mWindowWatcher->Release();
- }
- NS_IMETHODIMP
- nsWatcherWindowEnumerator::HasMoreElements(bool* aResult)
- {
- if (!aResult) {
- return NS_ERROR_INVALID_ARG;
- }
- *aResult = !!mCurrentPosition;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsWatcherWindowEnumerator::GetNext(nsISupports** aResult)
- {
- if (!aResult) {
- return NS_ERROR_INVALID_ARG;
- }
- *aResult = nullptr;
- #ifdef USEWEAKREFS
- while (mCurrentPosition) {
- CallQueryReferent(mCurrentPosition->mWindow, aResult);
- if (*aResult) {
- mCurrentPosition = FindNext();
- break;
- } else { // window is gone!
- mWindowWatcher->RemoveWindow(mCurrentPosition);
- }
- }
- NS_IF_ADDREF(*aResult);
- #else
- if (mCurrentPosition) {
- CallQueryInterface(mCurrentPosition->mWindow, aResult);
- mCurrentPosition = FindNext();
- }
- #endif
- return NS_OK;
- }
- nsWatcherWindowEntry*
- nsWatcherWindowEnumerator::FindNext()
- {
- nsWatcherWindowEntry* info;
- if (!mCurrentPosition) {
- return 0;
- }
- info = mCurrentPosition->mYounger;
- return info == mWindowWatcher->mOldestWindow ? 0 : info;
- }
- // if a window is being removed adjust the iterator's current position
- void
- nsWatcherWindowEnumerator::WindowRemoved(nsWatcherWindowEntry* aInfo)
- {
- if (mCurrentPosition == aInfo) {
- mCurrentPosition =
- mCurrentPosition != aInfo->mYounger ? aInfo->mYounger : 0;
- }
- }
- /****************************************************************
- *********************** nsWindowWatcher ************************
- ****************************************************************/
- NS_IMPL_ADDREF(nsWindowWatcher)
- NS_IMPL_RELEASE(nsWindowWatcher)
- NS_IMPL_QUERY_INTERFACE(nsWindowWatcher,
- nsIWindowWatcher,
- nsIPromptFactory,
- nsPIWindowWatcher)
- nsWindowWatcher::nsWindowWatcher()
- : mEnumeratorList()
- , mOldestWindow(0)
- , mListLock("nsWindowWatcher.mListLock")
- {
- }
- nsWindowWatcher::~nsWindowWatcher()
- {
- // delete data
- while (mOldestWindow) {
- RemoveWindow(mOldestWindow);
- }
- }
- nsresult
- nsWindowWatcher::Init()
- {
- return NS_OK;
- }
- /**
- * Convert aArguments into either an nsIArray or nullptr.
- *
- * - If aArguments is nullptr, return nullptr.
- * - If aArguments is an nsArray, return nullptr if it's empty, or otherwise
- * return the array.
- * - If aArguments is an nsIArray, return nullptr if it's empty, or
- * otherwise just return the array.
- * - Otherwise, return an nsIArray with one element: aArguments.
- */
- static already_AddRefed<nsIArray>
- ConvertArgsToArray(nsISupports* aArguments)
- {
- if (!aArguments) {
- return nullptr;
- }
- nsCOMPtr<nsIArray> array = do_QueryInterface(aArguments);
- if (array) {
- uint32_t argc = 0;
- array->GetLength(&argc);
- if (argc == 0) {
- return nullptr;
- }
- return array.forget();
- }
- nsCOMPtr<nsIMutableArray> singletonArray =
- do_CreateInstance(NS_ARRAY_CONTRACTID);
- NS_ENSURE_TRUE(singletonArray, nullptr);
- nsresult rv = singletonArray->AppendElement(aArguments, /* aWeak = */ false);
- NS_ENSURE_SUCCESS(rv, nullptr);
- return singletonArray.forget();
- }
- NS_IMETHODIMP
- nsWindowWatcher::OpenWindow(mozIDOMWindowProxy* aParent,
- const char* aUrl,
- const char* aName,
- const char* aFeatures,
- nsISupports* aArguments,
- mozIDOMWindowProxy** aResult)
- {
- nsCOMPtr<nsIArray> argv = ConvertArgsToArray(aArguments);
- uint32_t argc = 0;
- if (argv) {
- argv->GetLength(&argc);
- }
- bool dialog = (argc != 0);
- return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
- /* calledFromJS = */ false, dialog,
- /* navigate = */ true, argv,
- /* aIsPopupSpam = */ false,
- /* aForceNoOpener = */ false,
- /* aLoadInfo = */ nullptr,
- aResult);
- }
- struct SizeSpec
- {
- SizeSpec()
- : mLeft(0)
- , mTop(0)
- , mOuterWidth(0)
- , mOuterHeight(0)
- , mInnerWidth(0)
- , mInnerHeight(0)
- , mLeftSpecified(false)
- , mTopSpecified(false)
- , mOuterWidthSpecified(false)
- , mOuterHeightSpecified(false)
- , mInnerWidthSpecified(false)
- , mInnerHeightSpecified(false)
- , mUseDefaultWidth(false)
- , mUseDefaultHeight(false)
- {
- }
- int32_t mLeft;
- int32_t mTop;
- int32_t mOuterWidth; // Total window width
- int32_t mOuterHeight; // Total window height
- int32_t mInnerWidth; // Content area width
- int32_t mInnerHeight; // Content area height
- bool mLeftSpecified;
- bool mTopSpecified;
- bool mOuterWidthSpecified;
- bool mOuterHeightSpecified;
- bool mInnerWidthSpecified;
- bool mInnerHeightSpecified;
- // If these booleans are true, don't look at the corresponding width values
- // even if they're specified -- they'll be bogus
- bool mUseDefaultWidth;
- bool mUseDefaultHeight;
- bool PositionSpecified() const
- {
- return mLeftSpecified || mTopSpecified;
- }
- bool SizeSpecified() const
- {
- return mOuterWidthSpecified || mOuterHeightSpecified ||
- mInnerWidthSpecified || mInnerHeightSpecified;
- }
- };
- NS_IMETHODIMP
- nsWindowWatcher::OpenWindow2(mozIDOMWindowProxy* aParent,
- const char* aUrl,
- const char* aName,
- const char* aFeatures,
- bool aCalledFromScript,
- bool aDialog,
- bool aNavigate,
- nsISupports* aArguments,
- bool aIsPopupSpam,
- bool aForceNoOpener,
- nsIDocShellLoadInfo* aLoadInfo,
- mozIDOMWindowProxy** aResult)
- {
- nsCOMPtr<nsIArray> argv = ConvertArgsToArray(aArguments);
- uint32_t argc = 0;
- if (argv) {
- argv->GetLength(&argc);
- }
- // This is extremely messed up, but this behavior is necessary because
- // callers lie about whether they're a dialog window and whether they're
- // called from script. Fixing this is bug 779939.
- bool dialog = aDialog;
- if (!aCalledFromScript) {
- dialog = argc > 0;
- }
- return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
- aCalledFromScript, dialog,
- aNavigate, argv, aIsPopupSpam,
- aForceNoOpener, aLoadInfo, aResult);
- }
- // This static function checks if the aDocShell uses an UserContextId equal to
- // the userContextId of subjectPrincipal, if not null.
- static bool
- CheckUserContextCompatibility(nsIDocShell* aDocShell)
- {
- MOZ_ASSERT(aDocShell);
- uint32_t userContextId =
- static_cast<nsDocShell*>(aDocShell)->GetOriginAttributes().mUserContextId;
- nsCOMPtr<nsIPrincipal> subjectPrincipal =
- nsContentUtils::GetCurrentJSContext()
- ? nsContentUtils::SubjectPrincipal() : nullptr;
- // If we don't have a valid principal, probably we are in e10s mode, parent
- // side.
- if (!subjectPrincipal) {
- return true;
- }
- // DocShell can have UsercontextID set but loading a document with system
- // principal. In this case, we consider everything ok.
- if (nsContentUtils::IsSystemPrincipal(subjectPrincipal)) {
- return true;
- }
- return subjectPrincipal->GetUserContextId() == userContextId;
- }
- NS_IMETHODIMP
- nsWindowWatcher::OpenWindowWithoutParent(nsITabParent** aResult)
- {
- return OpenWindowWithTabParent(nullptr, EmptyCString(), true, 1.0f, aResult);
- }
- nsresult
- nsWindowWatcher::CreateChromeWindow(const nsACString& aFeatures,
- nsIWebBrowserChrome* aParentChrome,
- uint32_t aChromeFlags,
- uint32_t aContextFlags,
- nsITabParent* aOpeningTabParent,
- mozIDOMWindowProxy* aOpener,
- nsIWebBrowserChrome** aResult)
- {
- nsCOMPtr<nsIWindowCreator2> windowCreator2(do_QueryInterface(mWindowCreator));
- if (NS_WARN_IF(!windowCreator2)) {
- return NS_ERROR_UNEXPECTED;
- }
- bool cancel = false;
- nsCOMPtr<nsIWebBrowserChrome> newWindowChrome;
- nsresult rv =
- windowCreator2->CreateChromeWindow2(aParentChrome, aChromeFlags, aContextFlags,
- aOpeningTabParent, aOpener, &cancel,
- getter_AddRefs(newWindowChrome));
- if (NS_SUCCEEDED(rv) && cancel) {
- newWindowChrome = nullptr;
- return NS_ERROR_ABORT;
- }
- newWindowChrome.forget(aResult);
- return NS_OK;
- }
- /**
- * Disable persistence of size/position in popups (determined by
- * determining whether the features parameter specifies width or height
- * in any way). We consider any overriding of the window's size or position
- * in the open call as disabling persistence of those attributes.
- * Popup windows (which should not persist size or position) generally set
- * the size.
- *
- * @param aFeatures
- * The features string that was used to open the window.
- * @param aTreeOwner
- * The nsIDocShellTreeOwner of the newly opened window. If null,
- * this function is a no-op.
- */
- void
- nsWindowWatcher::MaybeDisablePersistence(const nsACString& aFeatures,
- nsIDocShellTreeOwner* aTreeOwner)
- {
- if (!aTreeOwner) {
- return;
- }
- // At the moment, the strings "height=" or "width=" never happen
- // outside a size specification, so we can do this the Q&D way.
- if (PL_strcasestr(aFeatures.BeginReading(), "width=") ||
- PL_strcasestr(aFeatures.BeginReading(), "height=")) {
- aTreeOwner->SetPersistence(false, false, false);
- }
- }
- NS_IMETHODIMP
- nsWindowWatcher::OpenWindowWithTabParent(nsITabParent* aOpeningTabParent,
- const nsACString& aFeatures,
- bool aCalledFromJS,
- float aOpenerFullZoom,
- nsITabParent** aResult)
- {
- MOZ_ASSERT(XRE_IsParentProcess());
- MOZ_ASSERT(mWindowCreator);
- if (!nsContentUtils::IsSafeToRunScript()) {
- nsContentUtils::WarnScriptWasIgnored(nullptr);
- return NS_ERROR_FAILURE;
- }
- if (NS_WARN_IF(!mWindowCreator)) {
- return NS_ERROR_UNEXPECTED;
- }
- bool isPrivateBrowsingWindow =
- Preferences::GetBool("browser.privatebrowsing.autostart");
- nsCOMPtr<nsPIDOMWindowOuter> parentWindowOuter;
- if (aOpeningTabParent) {
- // We need to examine the window that aOpeningTabParent belongs to in
- // order to inform us of what kind of window we're going to open.
- TabParent* openingTab = TabParent::GetFrom(aOpeningTabParent);
- parentWindowOuter = openingTab->GetParentWindowOuter();
- // Propagate the privacy status of the parent window, if
- // available, to the child.
- if (!isPrivateBrowsingWindow) {
- nsCOMPtr<nsILoadContext> parentContext = openingTab->GetLoadContext();
- if (parentContext) {
- isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
- }
- }
- }
- if (!parentWindowOuter) {
- // We couldn't find a browser window for the opener, so either we
- // never were passed aOpeningTabParent, the window is closed,
- // or it's in the process of closing. Either way, we'll use
- // the most recently opened browser window instead.
- parentWindowOuter = nsContentUtils::GetMostRecentNonPBWindow();
- }
- if (NS_WARN_IF(!parentWindowOuter)) {
- return NS_ERROR_UNEXPECTED;
- }
- nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
- GetWindowTreeOwner(parentWindowOuter, getter_AddRefs(parentTreeOwner));
- if (NS_WARN_IF(!parentTreeOwner)) {
- return NS_ERROR_UNEXPECTED;
- }
- nsCOMPtr<nsIWindowCreator2> windowCreator2(do_QueryInterface(mWindowCreator));
- if (NS_WARN_IF(!windowCreator2)) {
- return NS_ERROR_UNEXPECTED;
- }
- uint32_t contextFlags = 0;
- if (parentWindowOuter->IsLoadingOrRunningTimeout()) {
- contextFlags |=
- nsIWindowCreator2::PARENT_IS_LOADING_OR_RUNNING_TIMEOUT;
- }
- uint32_t chromeFlags = CalculateChromeFlagsForChild(aFeatures);
- // A content process has asked for a new window, which implies
- // that the new window will need to be remote.
- chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
- nsCOMPtr<nsIWebBrowserChrome> parentChrome(do_GetInterface(parentTreeOwner));
- nsCOMPtr<nsIWebBrowserChrome> newWindowChrome;
- CreateChromeWindow(aFeatures, parentChrome, chromeFlags, contextFlags,
- aOpeningTabParent, nullptr, getter_AddRefs(newWindowChrome));
- if (NS_WARN_IF(!newWindowChrome)) {
- return NS_ERROR_UNEXPECTED;
- }
- nsCOMPtr<nsIDocShellTreeItem> chromeTreeItem = do_GetInterface(newWindowChrome);
- if (NS_WARN_IF(!chromeTreeItem)) {
- return NS_ERROR_UNEXPECTED;
- }
- nsCOMPtr<nsIDocShellTreeOwner> chromeTreeOwner;
- chromeTreeItem->GetTreeOwner(getter_AddRefs(chromeTreeOwner));
- if (NS_WARN_IF(!chromeTreeOwner)) {
- return NS_ERROR_UNEXPECTED;
- }
- nsCOMPtr<nsILoadContext> chromeContext = do_QueryInterface(chromeTreeItem);
- if (NS_WARN_IF(!chromeContext)) {
- return NS_ERROR_UNEXPECTED;
- }
- chromeContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
- // Tabs opened from a content process can only open new windows
- // that will also run with out-of-process tabs.
- chromeContext->SetRemoteTabs(true);
- MaybeDisablePersistence(aFeatures, chromeTreeOwner);
- SizeSpec sizeSpec;
- CalcSizeSpec(aFeatures, sizeSpec);
- SizeOpenedWindow(chromeTreeOwner, parentWindowOuter, false, sizeSpec,
- Some(aOpenerFullZoom));
- nsCOMPtr<nsITabParent> newTabParent;
- chromeTreeOwner->GetPrimaryTabParent(getter_AddRefs(newTabParent));
- if (NS_WARN_IF(!newTabParent)) {
- return NS_ERROR_UNEXPECTED;
- }
- newTabParent.forget(aResult);
- return NS_OK;
- }
- nsresult
- nsWindowWatcher::OpenWindowInternal(mozIDOMWindowProxy* aParent,
- const char* aUrl,
- const char* aName,
- const char* aFeatures,
- bool aCalledFromJS,
- bool aDialog,
- bool aNavigate,
- nsIArray* aArgv,
- bool aIsPopupSpam,
- bool aForceNoOpener,
- nsIDocShellLoadInfo* aLoadInfo,
- mozIDOMWindowProxy** aResult)
- {
- nsresult rv = NS_OK;
- bool isNewToplevelWindow = false;
- bool windowIsNew = false;
- bool windowNeedsName = false;
- bool windowIsModal = false;
- bool uriToLoadIsChrome = false;
- uint32_t chromeFlags;
- nsAutoString name; // string version of aName
- nsAutoCString features; // string version of aFeatures
- nsCOMPtr<nsIURI> uriToLoad; // from aUrl, if any
- nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner; // from the parent window, if any
- nsCOMPtr<nsIDocShellTreeItem> newDocShellItem; // from the new window
- nsCOMPtr<nsPIDOMWindowOuter> parent =
- aParent ? nsPIDOMWindowOuter::From(aParent) : nullptr;
- NS_ENSURE_ARG_POINTER(aResult);
- *aResult = 0;
- if (!nsContentUtils::IsSafeToRunScript()) {
- nsContentUtils::WarnScriptWasIgnored(nullptr);
- return NS_ERROR_FAILURE;
- }
- GetWindowTreeOwner(parent, getter_AddRefs(parentTreeOwner));
- // We expect TabParent to have provided us the absolute URI of the window
- // we're to open, so there's no need to call URIfromURL (or more importantly,
- // to check for a chrome URI, which cannot be opened from a remote tab).
- if (aUrl) {
- rv = URIfromURL(aUrl, aParent, getter_AddRefs(uriToLoad));
- if (NS_FAILED(rv)) {
- return rv;
- }
- uriToLoad->SchemeIs("chrome", &uriToLoadIsChrome);
- }
- bool nameSpecified = false;
- if (aName) {
- CopyUTF8toUTF16(aName, name);
- nameSpecified = true;
- } else {
- name.SetIsVoid(true);
- }
- if (aFeatures) {
- features.Assign(aFeatures);
- features.StripWhitespace();
- } else {
- features.SetIsVoid(true);
- }
- // try to find an extant window with the given name
- nsCOMPtr<nsPIDOMWindowOuter> foundWindow =
- SafeGetWindowByName(name, aForceNoOpener, aParent);
- GetWindowTreeItem(foundWindow, getter_AddRefs(newDocShellItem));
- // Do sandbox checks here, instead of waiting until nsIDocShell::LoadURI.
- // The state of the window can change before this call and if we are blocked
- // because of sandboxing, we wouldn't want that to happen.
- nsCOMPtr<nsPIDOMWindowOuter> parentWindow =
- aParent ? nsPIDOMWindowOuter::From(aParent) : nullptr;
- nsCOMPtr<nsIDocShell> parentDocShell;
- if (parentWindow) {
- parentDocShell = parentWindow->GetDocShell();
- if (parentDocShell) {
- nsCOMPtr<nsIDocShell> foundDocShell = do_QueryInterface(newDocShellItem);
- if (parentDocShell->IsSandboxedFrom(foundDocShell)) {
- return NS_ERROR_DOM_INVALID_ACCESS_ERR;
- }
- }
- }
- // no extant window? make a new one.
- // If no parent, consider it chrome when running in the parent process.
- bool hasChromeParent = XRE_IsContentProcess() ? false : true;
- if (aParent) {
- // Check if the parent document has chrome privileges.
- nsIDocument* doc = parentWindow->GetDoc();
- hasChromeParent = doc && nsContentUtils::IsChromeDoc(doc);
- }
- bool isCallerChrome = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
- // Make sure we calculate the chromeFlags *before* we push the
- // callee context onto the context stack so that
- // the calculation sees the actual caller when doing its
- // security checks.
- if (isCallerChrome && XRE_IsParentProcess()) {
- chromeFlags = CalculateChromeFlagsForParent(aParent, features,
- aDialog, uriToLoadIsChrome,
- hasChromeParent, aCalledFromJS);
- } else {
- chromeFlags = CalculateChromeFlagsForChild(features);
- if (aDialog) {
- MOZ_ASSERT(XRE_IsParentProcess());
- chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
- }
- }
- SizeSpec sizeSpec;
- CalcSizeSpec(features, sizeSpec);
- nsCOMPtr<nsIScriptSecurityManager> sm(
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
- // XXXbz Why is an AutoJSAPI good enough here? Wouldn't AutoEntryScript (so
- // we affect the entry global) make more sense? Or do we just want to affect
- // GetSubjectPrincipal()?
- dom::AutoJSAPI jsapiChromeGuard;
- bool windowTypeIsChrome =
- chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
- if (isCallerChrome && !hasChromeParent && !windowTypeIsChrome) {
- // open() is called from chrome on a non-chrome window, initialize an
- // AutoJSAPI with the callee to prevent the caller's privileges from leaking
- // into code that runs while opening the new window.
- //
- // The reasoning for this is in bug 289204. Basically, chrome sometimes does
- // someContentWindow.open(untrustedURL), and wants to be insulated from nasty
- // javascript: URLs and such. But there are also cases where we create a
- // window parented to a content window (such as a download dialog), usually
- // directly with nsIWindowWatcher. In those cases, we want the principal of
- // the initial about:blank document to be system, so that the subsequent XUL
- // load can reuse the inner window and avoid blowing away expandos. As such,
- // we decide whether to load with the principal of the caller or of the parent
- // based on whether the docshell type is chrome or content.
- nsCOMPtr<nsIGlobalObject> parentGlobalObject = do_QueryInterface(aParent);
- if (!aParent) {
- jsapiChromeGuard.Init();
- } else if (NS_WARN_IF(!jsapiChromeGuard.Init(parentGlobalObject))) {
- return NS_ERROR_UNEXPECTED;
- }
- }
- uint32_t activeDocsSandboxFlags = 0;
- if (!newDocShellItem) {
- // We're going to either open up a new window ourselves or ask a
- // nsIWindowProvider for one. In either case, we'll want to set the right
- // name on it.
- windowNeedsName = true;
- // If the parent trying to open a new window is sandboxed
- // without 'allow-popups', this is not allowed and we fail here.
- if (aParent) {
- if (nsIDocument* doc = parentWindow->GetDoc()) {
- // Save sandbox flags for copying to new browsing context (docShell).
- activeDocsSandboxFlags = doc->GetSandboxFlags();
- if (activeDocsSandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) {
- return NS_ERROR_DOM_INVALID_ACCESS_ERR;
- }
- }
- }
- // Now check whether it's ok to ask a window provider for a window. Don't
- // do it if we're opening a dialog or if our parent is a chrome window or
- // if we're opening something that has modal, dialog, or chrome flags set.
- nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(aParent);
- if (!aDialog && !chromeWin &&
- !(chromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
- nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
- nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) {
- nsCOMPtr<nsIWindowProvider> provider;
- if (parentTreeOwner) {
- provider = do_GetInterface(parentTreeOwner);
- } else if (XRE_IsContentProcess()) {
- // we're in a content process but we don't have a tabchild we can
- // use.
- provider = nsContentUtils::GetWindowProviderForContentProcess();
- }
- if (provider) {
- nsCOMPtr<mozIDOMWindowProxy> newWindow;
- rv = provider->ProvideWindow(aParent, chromeFlags, aCalledFromJS,
- sizeSpec.PositionSpecified(),
- sizeSpec.SizeSpecified(),
- uriToLoad, name, features, aForceNoOpener,
- &windowIsNew, getter_AddRefs(newWindow));
- if (NS_SUCCEEDED(rv)) {
- GetWindowTreeItem(newWindow, getter_AddRefs(newDocShellItem));
- if (windowIsNew && newDocShellItem) {
- // Make sure to stop any loads happening in this window that the
- // window provider might have started. Otherwise if our caller
- // manipulates the window it just opened and then the load
- // completes their stuff will get blown away.
- nsCOMPtr<nsIWebNavigation> webNav =
- do_QueryInterface(newDocShellItem);
- webNav->Stop(nsIWebNavigation::STOP_NETWORK);
- }
- // If this is a new window, but it's incompatible with the current
- // userContextId, we ignore it and we pretend that nothing has been
- // returned by ProvideWindow.
- if (!windowIsNew && newDocShellItem) {
- nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(newDocShellItem);
- if (!CheckUserContextCompatibility(docShell)) {
- newWindow = nullptr;
- newDocShellItem = nullptr;
- windowIsNew = false;
- }
- }
- } else if (rv == NS_ERROR_ABORT) {
- // NS_ERROR_ABORT means the window provider has flat-out rejected
- // the open-window call and we should bail. Don't return an error
- // here, because our caller may propagate that error, which might
- // cause e.g. window.open to throw! Just return null for our out
- // param.
- return NS_OK;
- }
- }
- }
- }
- bool newWindowShouldBeModal = false;
- bool parentIsModal = false;
- if (!newDocShellItem) {
- windowIsNew = true;
- isNewToplevelWindow = true;
- nsCOMPtr<nsIWebBrowserChrome> parentChrome(do_GetInterface(parentTreeOwner));
- // is the parent (if any) modal? if so, we must be, too.
- bool weAreModal = (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL) != 0;
- newWindowShouldBeModal = weAreModal;
- if (!weAreModal && parentChrome) {
- parentChrome->IsWindowModal(&weAreModal);
- parentIsModal = weAreModal;
- }
- if (weAreModal) {
- windowIsModal = true;
- // in case we added this because weAreModal
- chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL |
- nsIWebBrowserChrome::CHROME_DEPENDENT;
- }
- // Make sure to not create modal windows if our parent is invisible and
- // isn't a chrome window. Otherwise we can end up in a bizarre situation
- // where we can't shut down because an invisible window is open. If
- // someone tries to do this, throw.
- if (!hasChromeParent && (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL)) {
- nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(parentTreeOwner));
- nsCOMPtr<nsIWidget> parentWidget;
- if (parentWindow) {
- parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
- }
- // NOTE: the logic for this visibility check is duplicated in
- // nsIDOMWindowUtils::isParentWindowMainWidgetVisible - if we change
- // how a window is determined "visible" in this context then we should
- // also adjust that attribute and/or any consumers of it...
- if (parentWidget && !parentWidget->IsVisible()) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- }
- NS_ASSERTION(mWindowCreator,
- "attempted to open a new window with no WindowCreator");
- rv = NS_ERROR_FAILURE;
- if (mWindowCreator) {
- nsCOMPtr<nsIWebBrowserChrome> newChrome;
- nsCOMPtr<nsPIDOMWindowInner> parentTopInnerWindow;
- if (parentWindow) {
- nsCOMPtr<nsPIDOMWindowOuter> parentTopWindow = parentWindow->GetTop();
- if (parentTopWindow) {
- parentTopInnerWindow = parentTopWindow->GetCurrentInnerWindow();
- }
- }
- if (parentTopInnerWindow) {
- parentTopInnerWindow->Suspend();
- }
- /* If the window creator is an nsIWindowCreator2, we can give it
- some hints. The only hint at this time is whether the opening window
- is in a situation that's likely to mean this is an unrequested
- popup window we're creating. However we're not completely honest:
- we clear that indicator if the opener is chrome, so that the
- downstream consumer can treat the indicator to mean simply
- that the new window is subject to popup control. */
- nsCOMPtr<nsIWindowCreator2> windowCreator2(
- do_QueryInterface(mWindowCreator));
- if (windowCreator2) {
- uint32_t contextFlags = 0;
- bool popupConditions = false;
- // is the parent under popup conditions?
- if (parentWindow) {
- popupConditions = parentWindow->IsLoadingOrRunningTimeout();
- }
- // chrome is always allowed, so clear the flag if the opener is chrome
- if (popupConditions) {
- popupConditions = !isCallerChrome;
- }
- if (popupConditions) {
- contextFlags |=
- nsIWindowCreator2::PARENT_IS_LOADING_OR_RUNNING_TIMEOUT;
- }
- mozIDOMWindowProxy* openerWindow = aForceNoOpener ? nullptr : aParent;
- rv = CreateChromeWindow(features, parentChrome, chromeFlags, contextFlags,
- nullptr, openerWindow, getter_AddRefs(newChrome));
- } else {
- rv = mWindowCreator->CreateChromeWindow(parentChrome, chromeFlags,
- getter_AddRefs(newChrome));
- }
- if (parentTopInnerWindow) {
- parentTopInnerWindow->Resume();
- }
- if (newChrome) {
- nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(newChrome);
- if (xulWin) {
- nsCOMPtr<nsIXULBrowserWindow> xulBrowserWin;
- xulWin->GetXULBrowserWindow(getter_AddRefs(xulBrowserWin));
- if (xulBrowserWin) {
- nsPIDOMWindowOuter* openerWindow = aForceNoOpener ? nullptr : parentWindow.get();
- xulBrowserWin->ForceInitialBrowserNonRemote(openerWindow);
- }
- }
- /* It might be a chrome nsXULWindow, in which case it won't have
- an nsIDOMWindow (primary content shell). But in that case, it'll
- be able to hand over an nsIDocShellTreeItem directly. */
- nsCOMPtr<nsPIDOMWindowOuter> newWindow(do_GetInterface(newChrome));
- if (newWindow) {
- GetWindowTreeItem(newWindow, getter_AddRefs(newDocShellItem));
- }
- if (!newDocShellItem) {
- newDocShellItem = do_GetInterface(newChrome);
- }
- if (!newDocShellItem) {
- rv = NS_ERROR_FAILURE;
- }
- }
- }
- }
- // better have a window to use by this point
- if (!newDocShellItem) {
- return rv;
- }
- nsCOMPtr<nsIDocShell> newDocShell(do_QueryInterface(newDocShellItem));
- NS_ENSURE_TRUE(newDocShell, NS_ERROR_UNEXPECTED);
- // If our parent is sandboxed, set it as the one permitted sandboxed navigator
- // on the new window we're opening.
- if (activeDocsSandboxFlags && parentWindow) {
- newDocShell->SetOnePermittedSandboxedNavigator(
- parentWindow->GetDocShell());
- }
- // Copy sandbox flags to the new window if activeDocsSandboxFlags says to do
- // so. Note that it's only nonzero if the window is new, so clobbering
- // sandbox flags on the window makes sense in that case.
- if (activeDocsSandboxFlags &
- SANDBOX_PROPAGATES_TO_AUXILIARY_BROWSING_CONTEXTS) {
- newDocShell->SetSandboxFlags(activeDocsSandboxFlags);
- }
- rv = ReadyOpenedDocShellItem(newDocShellItem, parentWindow, windowIsNew,
- aForceNoOpener, aResult);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (isNewToplevelWindow) {
- nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
- newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
- MaybeDisablePersistence(features, newTreeOwner);
- }
- if (aDialog && aArgv) {
- // Set the args on the new window.
- nsCOMPtr<nsPIDOMWindowOuter> piwin(do_QueryInterface(*aResult));
- NS_ENSURE_TRUE(piwin, NS_ERROR_UNEXPECTED);
- rv = piwin->SetArguments(aArgv);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- /* allow a window that we found by name to keep its name (important for cases
- like _self where the given name is different (and invalid)). Also, _blank
- is not a window name. */
- if (windowNeedsName) {
- if (nameSpecified && !name.LowerCaseEqualsLiteral("_blank")) {
- newDocShellItem->SetName(name);
- } else {
- newDocShellItem->SetName(EmptyString());
- }
- }
- // Now we have to set the right opener principal on the new window. Note
- // that we have to do this _before_ starting any URI loads, thanks to the
- // sync nature of javascript: loads.
- //
- // Note: The check for the current JSContext isn't necessarily sensical.
- // It's just designed to preserve old semantics during a mass-conversion
- // patch.
- nsCOMPtr<nsIPrincipal> subjectPrincipal =
- nsContentUtils::GetCurrentJSContext() ? nsContentUtils::SubjectPrincipal() :
- nullptr;
- bool isPrivateBrowsingWindow = false;
- if (windowIsNew) {
- auto* docShell = static_cast<nsDocShell*>(newDocShell.get());
- // If this is not a chrome docShell, we apply originAttributes from the
- // subjectPrincipal unless if it's an expanded or system principal.
- if (subjectPrincipal &&
- !nsContentUtils::IsSystemOrExpandedPrincipal(subjectPrincipal) &&
- docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
- DocShellOriginAttributes attrs;
- attrs.InheritFromDocToChildDocShell(BasePrincipal::Cast(subjectPrincipal)->OriginAttributesRef());
- isPrivateBrowsingWindow = !!attrs.mPrivateBrowsingId;
- docShell->SetOriginAttributes(attrs);
- } else {
- nsCOMPtr<nsIDocShellTreeItem> parentItem;
- GetWindowTreeItem(aParent, getter_AddRefs(parentItem));
- nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(parentItem);
- if (parentContext) {
- isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
- }
- }
- bool autoPrivateBrowsing =
- Preferences::GetBool("browser.privatebrowsing.autostart");
- if (!autoPrivateBrowsing &&
- (chromeFlags & nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW)) {
- isPrivateBrowsingWindow = false;
- } else if (autoPrivateBrowsing ||
- (chromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW)) {
- isPrivateBrowsingWindow = true;
- }
- // Now set the opener principal on the new window. Note that we need to do
- // this no matter whether we were opened from JS; if there is nothing on
- // the JS stack, just use the principal of our parent window. In those
- // cases we do _not_ set the parent window principal as the owner of the
- // load--since we really don't know who the owner is, just leave it null.
- nsCOMPtr<nsPIDOMWindowOuter> newWindow = do_QueryInterface(*aResult);
- NS_ASSERTION(newWindow == newDocShell->GetWindow(), "Different windows??");
- // The principal of the initial about:blank document gets set up in
- // nsWindowWatcher::AddWindow. Make sure to call it. In the common case
- // this call already happened when the window was created, but
- // SetInitialPrincipalToSubject is safe to call multiple times.
- if (newWindow) {
- newWindow->SetInitialPrincipalToSubject();
- if (aIsPopupSpam) {
- nsGlobalWindow* globalWin = nsGlobalWindow::Cast(newWindow);
- MOZ_ASSERT(!globalWin->IsPopupSpamWindow(),
- "Who marked it as popup spam already???");
- if (!globalWin->IsPopupSpamWindow()) { // Make sure we don't mess up our
- // counter even if the above
- // assert fails.
- globalWin->SetIsPopupSpamWindow(true);
- }
- }
- }
- }
- // We rely on CalculateChromeFlags to decide whether remote (out-of-process)
- // tabs should be used.
- bool isRemoteWindow =
- !!(chromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
- if (isNewToplevelWindow) {
- nsCOMPtr<nsIDocShellTreeItem> childRoot;
- newDocShellItem->GetRootTreeItem(getter_AddRefs(childRoot));
- nsCOMPtr<nsILoadContext> childContext = do_QueryInterface(childRoot);
- if (childContext) {
- childContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
- childContext->SetRemoteTabs(isRemoteWindow);
- }
- } else if (windowIsNew) {
- nsCOMPtr<nsILoadContext> childContext = do_QueryInterface(newDocShellItem);
- if (childContext) {
- childContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
- childContext->SetRemoteTabs(isRemoteWindow);
- }
- }
- nsCOMPtr<nsIDocShellLoadInfo> loadInfo = aLoadInfo;
- if (uriToLoad && aNavigate && !loadInfo) {
- newDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
- NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
- if (subjectPrincipal) {
- loadInfo->SetTriggeringPrincipal(subjectPrincipal);
- }
- /* use the URL from the *extant* document, if any. The usual accessor
- GetDocument will synchronously create an about:blank document if
- it has no better answer, and we only care about a real document.
- Also using GetDocument to force document creation seems to
- screw up focus in the hidden window; see bug 36016.
- */
- nsCOMPtr<nsIDocument> doc = GetEntryDocument();
- if (!doc && parentWindow) {
- doc = parentWindow->GetExtantDoc();
- }
- if (doc) {
- // Set the referrer
- loadInfo->SetReferrer(doc->GetDocumentURI());
- loadInfo->SetReferrerPolicy(doc->GetReferrerPolicy());
- }
- }
- if (isNewToplevelWindow) {
- // Notify observers that the window is open and ready.
- // The window has not yet started to load a document.
- nsCOMPtr<nsIObserverService> obsSvc =
- mozilla::services::GetObserverService();
- if (obsSvc) {
- obsSvc->NotifyObservers(*aResult, "toplevel-window-ready", nullptr);
- }
- }
- // Before loading the URI we want to be 100% sure that we use the correct
- // userContextId.
- MOZ_ASSERT(CheckUserContextCompatibility(newDocShell));
- if (uriToLoad && aNavigate) {
- newDocShell->LoadURI(
- uriToLoad,
- loadInfo,
- windowIsNew ?
- static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) :
- static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_NONE),
- true);
- }
- // Copy the current session storage for the current domain.
- if (subjectPrincipal && parentDocShell) {
- nsCOMPtr<nsIDOMStorageManager> parentStorageManager =
- do_QueryInterface(parentDocShell);
- nsCOMPtr<nsIDOMStorageManager> newStorageManager =
- do_QueryInterface(newDocShell);
- if (parentStorageManager && newStorageManager) {
- nsCOMPtr<nsIDOMStorage> storage;
- nsCOMPtr<nsPIDOMWindowInner> pInnerWin = parentWindow->GetCurrentInnerWindow();
- parentStorageManager->GetStorage(pInnerWin, subjectPrincipal,
- isPrivateBrowsingWindow,
- getter_AddRefs(storage));
- if (storage) {
- newStorageManager->CloneStorage(storage);
- }
- }
- }
- if (isNewToplevelWindow) {
- nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
- newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
- SizeOpenedWindow(newTreeOwner, aParent, isCallerChrome, sizeSpec);
- }
- if (windowIsModal) {
- nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
- newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
- nsCOMPtr<nsIWebBrowserChrome> newChrome(do_GetInterface(newTreeOwner));
- // Throw an exception here if no web browser chrome is available,
- // we need that to show a modal window.
- NS_ENSURE_TRUE(newChrome, NS_ERROR_NOT_AVAILABLE);
- // Dispatch dialog events etc, but we only want to do that if
- // we're opening a modal content window (the helper classes are
- // no-ops if given no window), for chrome dialogs we don't want to
- // do any of that (it's done elsewhere for us).
- // Make sure we maintain the state on an outer window, because
- // that's where it lives; inner windows assert if you try to
- // maintain the state on them.
- nsAutoWindowStateHelper windowStateHelper(
- parentWindow ? parentWindow->GetOuterWindow() : nullptr);
- if (!windowStateHelper.DefaultEnabled()) {
- // Default to cancel not opening the modal window.
- NS_RELEASE(*aResult);
- return NS_OK;
- }
- bool isAppModal = false;
- nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(newTreeOwner));
- nsCOMPtr<nsIWidget> parentWidget;
- if (parentWindow) {
- parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
- if (parentWidget) {
- isAppModal = parentWidget->IsRunningAppModal();
- }
- }
- if (parentWidget &&
- ((!newWindowShouldBeModal && parentIsModal) || isAppModal)) {
- parentWidget->SetFakeModal(true);
- } else {
- // Reset popup state while opening a modal dialog, and firing
- // events about the dialog, to prevent the current state from
- // being active the whole time a modal dialog is open.
- nsAutoPopupStatePusher popupStatePusher(openAbused);
- newChrome->ShowAsModal();
- }
- }
- // If a website opens a popup exit DOM fullscreen
- if (windowIsNew && aCalledFromJS && !hasChromeParent && !isCallerChrome &&
- parentWindow) {
- nsIDocument::AsyncExitFullscreen(parentWindow->GetDoc());
- }
-
- if (aForceNoOpener && windowIsNew) {
- NS_RELEASE(*aResult);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsWindowWatcher::RegisterNotification(nsIObserver* aObserver)
- {
- // just a convenience method; it delegates to nsIObserverService
- if (!aObserver) {
- return NS_ERROR_INVALID_ARG;
- }
- nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
- if (!os) {
- return NS_ERROR_FAILURE;
- }
- nsresult rv = os->AddObserver(aObserver, "domwindowopened", false);
- if (NS_SUCCEEDED(rv)) {
- rv = os->AddObserver(aObserver, "domwindowclosed", false);
- }
- return rv;
- }
- NS_IMETHODIMP
- nsWindowWatcher::UnregisterNotification(nsIObserver* aObserver)
- {
- // just a convenience method; it delegates to nsIObserverService
- if (!aObserver) {
- return NS_ERROR_INVALID_ARG;
- }
- nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
- if (!os) {
- return NS_ERROR_FAILURE;
- }
- os->RemoveObserver(aObserver, "domwindowopened");
- os->RemoveObserver(aObserver, "domwindowclosed");
- return NS_OK;
- }
- NS_IMETHODIMP
- nsWindowWatcher::GetWindowEnumerator(nsISimpleEnumerator** aResult)
- {
- if (!aResult) {
- return NS_ERROR_INVALID_ARG;
- }
- MutexAutoLock lock(mListLock);
- nsWatcherWindowEnumerator* enumerator = new nsWatcherWindowEnumerator(this);
- if (enumerator) {
- return CallQueryInterface(enumerator, aResult);
- }
- return NS_ERROR_OUT_OF_MEMORY;
- }
- NS_IMETHODIMP
- nsWindowWatcher::GetNewPrompter(mozIDOMWindowProxy* aParent, nsIPrompt** aResult)
- {
- // This is for backwards compat only. Callers should just use the prompt
- // service directly.
- nsresult rv;
- nsCOMPtr<nsIPromptFactory> factory =
- do_GetService("@mozilla.org/prompter;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- return factory->GetPrompt(aParent, NS_GET_IID(nsIPrompt),
- reinterpret_cast<void**>(aResult));
- }
- NS_IMETHODIMP
- nsWindowWatcher::GetNewAuthPrompter(mozIDOMWindowProxy* aParent,
- nsIAuthPrompt** aResult)
- {
- // This is for backwards compat only. Callers should just use the prompt
- // service directly.
- nsresult rv;
- nsCOMPtr<nsIPromptFactory> factory =
- do_GetService("@mozilla.org/prompter;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- return factory->GetPrompt(aParent, NS_GET_IID(nsIAuthPrompt),
- reinterpret_cast<void**>(aResult));
- }
- NS_IMETHODIMP
- nsWindowWatcher::GetPrompt(mozIDOMWindowProxy* aParent, const nsIID& aIID,
- void** aResult)
- {
- // This is for backwards compat only. Callers should just use the prompt
- // service directly.
- nsresult rv;
- nsCOMPtr<nsIPromptFactory> factory =
- do_GetService("@mozilla.org/prompter;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = factory->GetPrompt(aParent, aIID, aResult);
- // Allow for an embedding implementation to not support nsIAuthPrompt2.
- if (rv == NS_NOINTERFACE && aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
- nsCOMPtr<nsIAuthPrompt> oldPrompt;
- rv = factory->GetPrompt(
- aParent, NS_GET_IID(nsIAuthPrompt), getter_AddRefs(oldPrompt));
- NS_ENSURE_SUCCESS(rv, rv);
- NS_WrapAuthPrompt(oldPrompt, reinterpret_cast<nsIAuthPrompt2**>(aResult));
- if (!*aResult) {
- rv = NS_ERROR_NOT_AVAILABLE;
- }
- }
- return rv;
- }
- NS_IMETHODIMP
- nsWindowWatcher::SetWindowCreator(nsIWindowCreator* aCreator)
- {
- mWindowCreator = aCreator;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsWindowWatcher::HasWindowCreator(bool* aResult)
- {
- *aResult = mWindowCreator;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsWindowWatcher::GetActiveWindow(mozIDOMWindowProxy** aActiveWindow)
- {
- *aActiveWindow = nullptr;
- nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
- if (fm) {
- return fm->GetActiveWindow(aActiveWindow);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsWindowWatcher::SetActiveWindow(mozIDOMWindowProxy* aActiveWindow)
- {
- nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
- if (fm) {
- return fm->SetActiveWindow(aActiveWindow);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsWindowWatcher::AddWindow(mozIDOMWindowProxy* aWindow, nsIWebBrowserChrome* aChrome)
- {
- if (!aWindow) {
- return NS_ERROR_INVALID_ARG;
- }
- #ifdef DEBUG
- {
- nsCOMPtr<nsPIDOMWindowOuter> win(do_QueryInterface(aWindow));
- NS_ASSERTION(win->IsOuterWindow(),
- "Uh, the active window must be an outer window!");
- }
- #endif
- {
- nsWatcherWindowEntry* info;
- MutexAutoLock lock(mListLock);
- // if we already have an entry for this window, adjust
- // its chrome mapping and return
- info = FindWindowEntry(aWindow);
- if (info) {
- nsCOMPtr<nsISupportsWeakReference> supportsweak(
- do_QueryInterface(aChrome));
- if (supportsweak) {
- supportsweak->GetWeakReference(getter_AddRefs(info->mChromeWeak));
- } else {
- info->mChrome = aChrome;
- info->mChromeWeak = nullptr;
- }
- return NS_OK;
- }
- // create a window info struct and add it to the list of windows
- info = new nsWatcherWindowEntry(aWindow, aChrome);
- if (!info) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- if (mOldestWindow) {
- info->InsertAfter(mOldestWindow->mOlder);
- } else {
- mOldestWindow = info;
- }
- } // leave the mListLock
- // a window being added to us signifies a newly opened window.
- // send notifications.
- nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
- if (!os) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsISupports> domwin(do_QueryInterface(aWindow));
- return os->NotifyObservers(domwin, "domwindowopened", 0);
- }
- NS_IMETHODIMP
- nsWindowWatcher::RemoveWindow(mozIDOMWindowProxy* aWindow)
- {
- // find the corresponding nsWatcherWindowEntry, remove it
- if (!aWindow) {
- return NS_ERROR_INVALID_ARG;
- }
- nsWatcherWindowEntry* info = FindWindowEntry(aWindow);
- if (info) {
- RemoveWindow(info);
- return NS_OK;
- }
- NS_WARNING("requested removal of nonexistent window");
- return NS_ERROR_INVALID_ARG;
- }
- nsWatcherWindowEntry*
- nsWindowWatcher::FindWindowEntry(mozIDOMWindowProxy* aWindow)
- {
- // find the corresponding nsWatcherWindowEntry
- nsWatcherWindowEntry* info;
- nsWatcherWindowEntry* listEnd;
- #ifdef USEWEAKREFS
- nsresult rv;
- bool found;
- #endif
- info = mOldestWindow;
- listEnd = 0;
- #ifdef USEWEAKREFS
- rv = NS_OK;
- found = false;
- while (info != listEnd && NS_SUCCEEDED(rv)) {
- nsCOMPtr<mozIDOMWindowProxy> infoWindow(do_QueryReferent(info->mWindow));
- if (!infoWindow) { // clean up dangling reference, while we're here
- rv = RemoveWindow(info);
- } else if (infoWindow.get() == aWindow) {
- return info;
- }
- info = info->mYounger;
- listEnd = mOldestWindow;
- }
- return 0;
- #else
- while (info != listEnd) {
- if (info->mWindow == aWindow) {
- return info;
- }
- info = info->mYounger;
- listEnd = mOldestWindow;
- }
- return 0;
- #endif
- }
- nsresult
- nsWindowWatcher::RemoveWindow(nsWatcherWindowEntry* aInfo)
- {
- uint32_t count = mEnumeratorList.Length();
- {
- // notify the enumerators
- MutexAutoLock lock(mListLock);
- for (uint32_t ctr = 0; ctr < count; ++ctr) {
- mEnumeratorList[ctr]->WindowRemoved(aInfo);
- }
- // remove the element from the list
- if (aInfo == mOldestWindow) {
- mOldestWindow = aInfo->mYounger == mOldestWindow ? 0 : aInfo->mYounger;
- }
- aInfo->Unlink();
- }
- // a window being removed from us signifies a newly closed window.
- // send notifications.
- nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
- if (os) {
- #ifdef USEWEAKREFS
- nsCOMPtr<nsISupports> domwin(do_QueryReferent(aInfo->mWindow));
- if (domwin) {
- os->NotifyObservers(domwin, "domwindowclosed", 0);
- }
- // else bummer. since the window is gone, there's nothing to notify with.
- #else
- nsCOMPtr<nsISupports> domwin(do_QueryInterface(aInfo->mWindow));
- os->NotifyObservers(domwin, "domwindowclosed", 0);
- #endif
- }
- delete aInfo;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsWindowWatcher::GetChromeForWindow(mozIDOMWindowProxy* aWindow,
- nsIWebBrowserChrome** aResult)
- {
- if (!aWindow || !aResult) {
- return NS_ERROR_INVALID_ARG;
- }
- *aResult = 0;
- MutexAutoLock lock(mListLock);
- nsWatcherWindowEntry* info = FindWindowEntry(aWindow);
- if (info) {
- if (info->mChromeWeak) {
- return info->mChromeWeak->QueryReferent(
- NS_GET_IID(nsIWebBrowserChrome), reinterpret_cast<void**>(aResult));
- }
- *aResult = info->mChrome;
- NS_IF_ADDREF(*aResult);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsWindowWatcher::GetWindowByName(const nsAString& aTargetName,
- mozIDOMWindowProxy* aCurrentWindow,
- mozIDOMWindowProxy** aResult)
- {
- if (!aResult) {
- return NS_ERROR_INVALID_ARG;
- }
- *aResult = nullptr;
- nsPIDOMWindowOuter* currentWindow =
- aCurrentWindow ? nsPIDOMWindowOuter::From(aCurrentWindow) : nullptr;
- nsCOMPtr<nsIDocShellTreeItem> treeItem;
- nsCOMPtr<nsIDocShellTreeItem> startItem;
- GetWindowTreeItem(currentWindow, getter_AddRefs(startItem));
- if (startItem) {
- // Note: original requestor is null here, per idl comments
- startItem->FindItemWithName(aTargetName, nullptr, nullptr,
- getter_AddRefs(treeItem));
- } else {
- // Note: original requestor is null here, per idl comments
- FindItemWithName(aTargetName, nullptr, nullptr, getter_AddRefs(treeItem));
- }
- if (treeItem) {
- nsCOMPtr<nsPIDOMWindowOuter> domWindow = treeItem->GetWindow();
- domWindow.forget(aResult);
- }
- return NS_OK;
- }
- bool
- nsWindowWatcher::AddEnumerator(nsWatcherWindowEnumerator* aEnumerator)
- {
- // (requires a lock; assumes it's called by someone holding the lock)
- return mEnumeratorList.AppendElement(aEnumerator) != nullptr;
- }
- bool
- nsWindowWatcher::RemoveEnumerator(nsWatcherWindowEnumerator* aEnumerator)
- {
- // (requires a lock; assumes it's called by someone holding the lock)
- return mEnumeratorList.RemoveElement(aEnumerator);
- }
- nsresult
- nsWindowWatcher::URIfromURL(const char* aURL,
- mozIDOMWindowProxy* aParent,
- nsIURI** aURI)
- {
- // Build the URI relative to the entry global.
- nsCOMPtr<nsPIDOMWindowInner> baseWindow = do_QueryInterface(GetEntryGlobal());
- // failing that, build it relative to the parent window, if possible
- if (!baseWindow && aParent) {
- baseWindow = nsPIDOMWindowOuter::From(aParent)->GetCurrentInnerWindow();
- }
- // failing that, use the given URL unmodified. It had better not be relative.
- nsIURI* baseURI = nullptr;
- // get baseWindow's document URI
- if (baseWindow) {
- if (nsIDocument* doc = baseWindow->GetDoc()) {
- baseURI = doc->GetDocBaseURI();
- }
- }
- // build and return the absolute URI
- return NS_NewURI(aURI, aURL, baseURI);
- }
- #define NS_CALCULATE_CHROME_FLAG_FOR(feature, flag) \
- prefBranch->GetBoolPref(feature, &forceEnable); \
- if (forceEnable && !aDialog && !aHasChromeParent && !aChromeURL) { \
- chromeFlags |= flag; \
- } else { \
- chromeFlags |= \
- WinHasOption(aFeatures, feature, 0, &presenceFlag) ? flag : 0; \
- }
- // static
- uint32_t
- nsWindowWatcher::CalculateChromeFlagsHelper(uint32_t aInitialFlags,
- const nsACString& aFeatures,
- bool& presenceFlag,
- bool aDialog,
- bool aHasChromeParent,
- bool aChromeURL)
- {
- uint32_t chromeFlags = aInitialFlags;
- nsresult rv;
- nsCOMPtr<nsIPrefBranch> prefBranch;
- nsCOMPtr<nsIPrefService> prefs =
- do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, nsIWebBrowserChrome::CHROME_DEFAULT);
- rv = prefs->GetBranch("dom.disable_window_open_feature.",
- getter_AddRefs(prefBranch));
- NS_ENSURE_SUCCESS(rv, nsIWebBrowserChrome::CHROME_DEFAULT);
- // NS_CALCULATE_CHROME_FLAG_FOR requires aFeatures, forceEnable, aDialog
- // aHasChromeParent, aChromeURL, presenceFlag and chromeFlags to be in
- // scope.
- bool forceEnable = false;
- NS_CALCULATE_CHROME_FLAG_FOR("titlebar",
- nsIWebBrowserChrome::CHROME_TITLEBAR);
- NS_CALCULATE_CHROME_FLAG_FOR("close",
- nsIWebBrowserChrome::CHROME_WINDOW_CLOSE);
- NS_CALCULATE_CHROME_FLAG_FOR("toolbar",
- nsIWebBrowserChrome::CHROME_TOOLBAR);
- NS_CALCULATE_CHROME_FLAG_FOR("location",
- nsIWebBrowserChrome::CHROME_LOCATIONBAR);
- NS_CALCULATE_CHROME_FLAG_FOR("personalbar",
- nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
- NS_CALCULATE_CHROME_FLAG_FOR("status",
- nsIWebBrowserChrome::CHROME_STATUSBAR);
- NS_CALCULATE_CHROME_FLAG_FOR("menubar",
- nsIWebBrowserChrome::CHROME_MENUBAR);
- NS_CALCULATE_CHROME_FLAG_FOR("resizable",
- nsIWebBrowserChrome::CHROME_WINDOW_RESIZE);
- NS_CALCULATE_CHROME_FLAG_FOR("minimizable",
- nsIWebBrowserChrome::CHROME_WINDOW_MIN);
- // default scrollbar to "on," unless explicitly turned off
- if (WinHasOption(aFeatures, "scrollbars", 1, &presenceFlag) || !presenceFlag) {
- chromeFlags |= nsIWebBrowserChrome::CHROME_SCROLLBARS;
- }
- return chromeFlags;
- }
- // static
- uint32_t
- nsWindowWatcher::EnsureFlagsSafeForContent(uint32_t aChromeFlags,
- bool aChromeURL)
- {
- aChromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR;
- aChromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE;
- aChromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_LOWERED;
- aChromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_RAISED;
- aChromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_POPUP;
- /* Untrusted script is allowed to pose modal windows with a chrome
- scheme. This check could stand to be better. But it effectively
- prevents untrusted script from opening modal windows in general
- while still allowing alerts and the like. */
- if (!aChromeURL) {
- aChromeFlags &= ~(nsIWebBrowserChrome::CHROME_MODAL |
- nsIWebBrowserChrome::CHROME_OPENAS_CHROME);
- }
- if (!(aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)) {
- aChromeFlags &= ~nsIWebBrowserChrome::CHROME_DEPENDENT;
- }
- return aChromeFlags;
- }
- /**
- * Calculate the chrome bitmask from a string list of features requested
- * from a child process. Feature strings that are restricted to the parent
- * process are ignored here.
- * @param aFeatures a string containing a list of named features
- * @return the chrome bitmask
- */
- // static
- uint32_t
- nsWindowWatcher::CalculateChromeFlagsForChild(const nsACString& aFeatures)
- {
- if (aFeatures.IsVoid()) {
- return nsIWebBrowserChrome::CHROME_ALL;
- }
- bool presenceFlag = false;
- uint32_t chromeFlags = CalculateChromeFlagsHelper(
- nsIWebBrowserChrome::CHROME_WINDOW_BORDERS, aFeatures, presenceFlag);
- return EnsureFlagsSafeForContent(chromeFlags);
- }
- /**
- * Calculate the chrome bitmask from a string list of features for a new
- * privileged window.
- * @param aParent the opener window
- * @param aFeatures a string containing a list of named chrome features
- * @param aDialog affects the assumptions made about unnamed features
- * @param aChromeURL true if the window is being sent to a chrome:// URL
- * @param aHasChromeParent true if the parent window is privileged
- * @param aCalledFromJS true if the window open request came from script.
- * @return the chrome bitmask
- */
- // static
- uint32_t
- nsWindowWatcher::CalculateChromeFlagsForParent(mozIDOMWindowProxy* aParent,
- const nsACString& aFeatures,
- bool aDialog,
- bool aChromeURL,
- bool aHasChromeParent,
- bool aCalledFromJS)
- {
- MOZ_ASSERT(XRE_IsParentProcess());
- MOZ_ASSERT(nsContentUtils::LegacyIsCallerChromeOrNativeCode());
- uint32_t chromeFlags = 0;
- // The features string is made void by OpenWindowInternal
- // if nullptr was originally passed as the features string.
- if (aFeatures.IsVoid()) {
- chromeFlags = nsIWebBrowserChrome::CHROME_ALL;
- if (aDialog) {
- chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
- nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
- }
- } else {
- chromeFlags = nsIWebBrowserChrome::CHROME_WINDOW_BORDERS;
- }
- /* This function has become complicated since browser windows and
- dialogs diverged. The difference is, browser windows assume all
- chrome not explicitly mentioned is off, if the features string
- is not null. Exceptions are some OS border chrome new with Mozilla.
- Dialogs interpret a (mostly) empty features string to mean
- "OS's choice," and also support an "all" flag explicitly disallowed
- in the standards-compliant window.(normal)open. */
- bool presenceFlag = false;
- if (aDialog && WinHasOption(aFeatures, "all", 0, &presenceFlag)) {
- chromeFlags = nsIWebBrowserChrome::CHROME_ALL;
- }
- /* Next, allow explicitly named options to override the initial settings */
- chromeFlags = CalculateChromeFlagsHelper(chromeFlags, aFeatures, presenceFlag,
- aDialog, aHasChromeParent, aChromeURL);
- // Determine whether the window is a private browsing window
- chromeFlags |= WinHasOption(aFeatures, "private", 0, &presenceFlag) ?
- nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW : 0;
- chromeFlags |= WinHasOption(aFeatures, "non-private", 0, &presenceFlag) ?
- nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW : 0;
- // Determine whether the window should have remote tabs.
- bool remote = BrowserTabsRemoteAutostart();
- if (remote) {
- remote = !WinHasOption(aFeatures, "non-remote", 0, &presenceFlag);
- } else {
- remote = WinHasOption(aFeatures, "remote", 0, &presenceFlag);
- }
- if (remote) {
- chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
- }
- chromeFlags |= WinHasOption(aFeatures, "popup", 0, &presenceFlag) ?
- nsIWebBrowserChrome::CHROME_WINDOW_POPUP : 0;
- /* OK.
- Normal browser windows, in spite of a stated pattern of turning off
- all chrome not mentioned explicitly, will want the new OS chrome (window
- borders, titlebars, closebox) on, unless explicitly turned off.
- Dialogs, on the other hand, take the absence of any explicit settings
- to mean "OS' choice." */
- // default titlebar and closebox to "on," if not mentioned at all
- if (!(chromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)) {
- if (!PL_strcasestr(aFeatures.BeginReading(), "titlebar")) {
- chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR;
- }
- if (!PL_strcasestr(aFeatures.BeginReading(), "close")) {
- chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE;
- }
- }
- if (aDialog && !aFeatures.IsVoid() && !presenceFlag) {
- chromeFlags = nsIWebBrowserChrome::CHROME_DEFAULT;
- }
- /* Finally, once all the above normal chrome has been divined, deal
- with the features that are more operating hints than appearance
- instructions. (Note modality implies dependence.) */
- if (WinHasOption(aFeatures, "alwaysLowered", 0, nullptr) ||
- WinHasOption(aFeatures, "z-lock", 0, nullptr)) {
- chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_LOWERED;
- } else if (WinHasOption(aFeatures, "alwaysRaised", 0, nullptr)) {
- chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_RAISED;
- }
- chromeFlags |= WinHasOption(aFeatures, "macsuppressanimation", 0, nullptr) ?
- nsIWebBrowserChrome::CHROME_MAC_SUPPRESS_ANIMATION : 0;
- chromeFlags |= WinHasOption(aFeatures, "chrome", 0, nullptr) ?
- nsIWebBrowserChrome::CHROME_OPENAS_CHROME : 0;
- chromeFlags |= WinHasOption(aFeatures, "extrachrome", 0, nullptr) ?
- nsIWebBrowserChrome::CHROME_EXTRA : 0;
- chromeFlags |= WinHasOption(aFeatures, "centerscreen", 0, nullptr) ?
- nsIWebBrowserChrome::CHROME_CENTER_SCREEN : 0;
- chromeFlags |= WinHasOption(aFeatures, "dependent", 0, nullptr) ?
- nsIWebBrowserChrome::CHROME_DEPENDENT : 0;
- chromeFlags |= WinHasOption(aFeatures, "modal", 0, nullptr) ?
- (nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT) : 0;
- /* On mobile we want to ignore the dialog window feature, since the mobile UI
- does not provide any affordance for dialog windows. This does not interfere
- with dialog windows created through openDialog. */
- bool disableDialogFeature = false;
- nsCOMPtr<nsIPrefBranch> branch = do_GetService(NS_PREFSERVICE_CONTRACTID);
- branch->GetBoolPref("dom.disable_window_open_dialog_feature",
- &disableDialogFeature);
- if (!disableDialogFeature) {
- chromeFlags |= WinHasOption(aFeatures, "dialog", 0, nullptr) ?
- nsIWebBrowserChrome::CHROME_OPENAS_DIALOG : 0;
- }
- /* and dialogs need to have the last word. assume dialogs are dialogs,
- and opened as chrome, unless explicitly told otherwise. */
- if (aDialog) {
- if (!PL_strcasestr(aFeatures.BeginReading(), "dialog")) {
- chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
- }
- if (!PL_strcasestr(aFeatures.BeginReading(), "chrome")) {
- chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
- }
- }
- /* missing
- chromeFlags->copy_history
- */
- // Check security state for use in determing window dimensions
- if (!aHasChromeParent) {
- chromeFlags = EnsureFlagsSafeForContent(chromeFlags, aChromeURL);
- }
- // Disable CHROME_OPENAS_DIALOG if the window is inside <iframe mozbrowser>.
- // It's up to the embedder to interpret what dialog=1 means.
- nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
- if (docshell && docshell->GetIsInMozBrowserOrApp()) {
- chromeFlags &= ~nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
- }
- return chromeFlags;
- }
- // static
- int32_t
- nsWindowWatcher::WinHasOption(const nsACString& aOptions, const char* aName,
- int32_t aDefault, bool* aPresenceFlag)
- {
- if (aOptions.IsEmpty()) {
- return 0;
- }
- const char* options = aOptions.BeginReading();
- char* comma;
- char* equal;
- int32_t found = 0;
- #ifdef DEBUG
- NS_ASSERTION(nsAutoCString(aOptions).FindCharInSet(" \n\r\t") == kNotFound,
- "There should be no whitespace in this string!");
- #endif
- while (true) {
- comma = PL_strchr(options, ',');
- if (comma) {
- *comma = '\0';
- }
- equal = PL_strchr(options, '=');
- if (equal) {
- *equal = '\0';
- }
- if (nsCRT::strcasecmp(options, aName) == 0) {
- if (aPresenceFlag) {
- *aPresenceFlag = true;
- }
- if (equal)
- if (*(equal + 1) == '*') {
- found = aDefault;
- } else if (nsCRT::strcasecmp(equal + 1, "yes") == 0) {
- found = 1;
- } else {
- found = atoi(equal + 1);
- }
- else {
- found = 1;
- }
- }
- if (equal) {
- *equal = '=';
- }
- if (comma) {
- *comma = ',';
- }
- if (found || !comma) {
- break;
- }
- options = comma + 1;
- }
- return found;
- }
- /* try to find an nsIDocShellTreeItem with the given name in any
- known open window. a failure to find the item will not
- necessarily return a failure method value. check aFoundItem.
- */
- NS_IMETHODIMP
- nsWindowWatcher::FindItemWithName(const nsAString& aName,
- nsIDocShellTreeItem* aRequestor,
- nsIDocShellTreeItem* aOriginalRequestor,
- nsIDocShellTreeItem** aFoundItem)
- {
- *aFoundItem = nullptr;
- if (aName.IsEmpty()) {
- return NS_OK;
- }
- if (aName.LowerCaseEqualsLiteral("_blank") ||
- aName.LowerCaseEqualsLiteral("_top") ||
- aName.LowerCaseEqualsLiteral("_parent") ||
- aName.LowerCaseEqualsLiteral("_self")) {
- return NS_OK;
- }
- // If we are looking for an item and we don't have a docshell we are checking
- // on, let's just look in the chrome tab group!
- return TabGroup::GetChromeTabGroup()->FindItemWithName(aName,
- aRequestor,
- aOriginalRequestor,
- aFoundItem);
- }
- already_AddRefed<nsIDocShellTreeItem>
- nsWindowWatcher::GetCallerTreeItem(nsIDocShellTreeItem* aParentItem)
- {
- nsCOMPtr<nsIWebNavigation> callerWebNav = do_GetInterface(GetEntryGlobal());
- nsCOMPtr<nsIDocShellTreeItem> callerItem = do_QueryInterface(callerWebNav);
- if (!callerItem) {
- callerItem = aParentItem;
- }
- return callerItem.forget();
- }
- nsPIDOMWindowOuter*
- nsWindowWatcher::SafeGetWindowByName(const nsAString& aName,
- bool aForceNoOpener,
- mozIDOMWindowProxy* aCurrentWindow)
- {
- if (aForceNoOpener) {
- if (!aName.LowerCaseEqualsLiteral("_self") &&
- !aName.LowerCaseEqualsLiteral("_top") &&
- !aName.LowerCaseEqualsLiteral("_parent")) {
- // Ignore all other names in the noopener case.
- return nullptr;
- }
- }
- nsCOMPtr<nsIDocShellTreeItem> startItem;
- GetWindowTreeItem(aCurrentWindow, getter_AddRefs(startItem));
- nsCOMPtr<nsIDocShellTreeItem> callerItem = GetCallerTreeItem(startItem);
- nsCOMPtr<nsIDocShellTreeItem> foundItem;
- if (startItem) {
- startItem->FindItemWithName(aName, nullptr, callerItem,
- getter_AddRefs(foundItem));
- } else {
- FindItemWithName(aName, nullptr, callerItem,
- getter_AddRefs(foundItem));
- }
- return foundItem ? foundItem->GetWindow() : nullptr;
- }
- /* Fetch the nsIDOMWindow corresponding to the given nsIDocShellTreeItem.
- This forces the creation of a script context, if one has not already
- been created. Note it also sets the window's opener to the parent,
- if applicable -- because it's just convenient, that's all. null aParent
- is acceptable. */
- nsresult
- nsWindowWatcher::ReadyOpenedDocShellItem(nsIDocShellTreeItem* aOpenedItem,
- nsPIDOMWindowOuter* aParent,
- bool aWindowIsNew,
- bool aForceNoOpener,
- mozIDOMWindowProxy** aOpenedWindow)
- {
- nsresult rv = NS_ERROR_FAILURE;
- NS_ENSURE_ARG(aOpenedWindow);
- *aOpenedWindow = 0;
- nsCOMPtr<nsPIDOMWindowOuter> piOpenedWindow = aOpenedItem->GetWindow();
- if (piOpenedWindow) {
- if (!aForceNoOpener) {
- piOpenedWindow->SetOpenerWindow(aParent, aWindowIsNew); // damnit
- } else if (aParent && aParent != piOpenedWindow) {
- MOZ_ASSERT(piOpenedWindow->TabGroup() != aParent->TabGroup(),
- "If we're forcing no opener, they should be in different tab groups");
- }
- if (aWindowIsNew) {
- #ifdef DEBUG
- // Assert that we're not loading things right now. If we are, when
- // that load completes it will clobber whatever principals we set up
- // on this new window!
- nsCOMPtr<nsIDocumentLoader> docloader = do_QueryInterface(aOpenedItem);
- NS_ASSERTION(docloader, "How can we not have a docloader here?");
- nsCOMPtr<nsIChannel> chan;
- docloader->GetDocumentChannel(getter_AddRefs(chan));
- NS_ASSERTION(!chan, "Why is there a document channel?");
- #endif
- nsCOMPtr<nsIDocument> doc = piOpenedWindow->GetExtantDoc();
- if (doc) {
- doc->SetIsInitialDocument(true);
- }
- }
- rv = CallQueryInterface(piOpenedWindow, aOpenedWindow);
- }
- return rv;
- }
- // static
- void
- nsWindowWatcher::CalcSizeSpec(const nsACString& aFeatures, SizeSpec& aResult)
- {
- // Parse position spec, if any, from aFeatures
- bool present;
- int32_t temp;
- present = false;
- if ((temp = WinHasOption(aFeatures, "left", 0, &present)) || present) {
- aResult.mLeft = temp;
- } else if ((temp = WinHasOption(aFeatures, "screenX", 0, &present)) ||
- present) {
- aResult.mLeft = temp;
- }
- aResult.mLeftSpecified = present;
- present = false;
- if ((temp = WinHasOption(aFeatures, "top", 0, &present)) || present) {
- aResult.mTop = temp;
- } else if ((temp = WinHasOption(aFeatures, "screenY", 0, &present)) ||
- present) {
- aResult.mTop = temp;
- }
- aResult.mTopSpecified = present;
- // Parse size spec, if any. Chrome size overrides content size.
- if ((temp = WinHasOption(aFeatures, "outerWidth", INT32_MIN, nullptr))) {
- if (temp == INT32_MIN) {
- aResult.mUseDefaultWidth = true;
- } else {
- aResult.mOuterWidth = temp;
- }
- aResult.mOuterWidthSpecified = true;
- } else if ((temp = WinHasOption(aFeatures, "width", INT32_MIN, nullptr)) ||
- (temp = WinHasOption(aFeatures, "innerWidth", INT32_MIN,
- nullptr))) {
- if (temp == INT32_MIN) {
- aResult.mUseDefaultWidth = true;
- } else {
- aResult.mInnerWidth = temp;
- }
- aResult.mInnerWidthSpecified = true;
- }
- if ((temp = WinHasOption(aFeatures, "outerHeight", INT32_MIN, nullptr))) {
- if (temp == INT32_MIN) {
- aResult.mUseDefaultHeight = true;
- } else {
- aResult.mOuterHeight = temp;
- }
- aResult.mOuterHeightSpecified = true;
- } else if ((temp = WinHasOption(aFeatures, "height", INT32_MIN,
- nullptr)) ||
- (temp = WinHasOption(aFeatures, "innerHeight", INT32_MIN,
- nullptr))) {
- if (temp == INT32_MIN) {
- aResult.mUseDefaultHeight = true;
- } else {
- aResult.mInnerHeight = temp;
- }
- aResult.mInnerHeightSpecified = true;
- }
- }
- /* Size and position a new window according to aSizeSpec. This method
- is assumed to be called after the window has already been given
- a default position and size; thus its current position and size are
- accurate defaults. The new window is made visible at method end.
- @param aTreeOwner
- The top-level nsIDocShellTreeOwner of the newly opened window.
- @param aParent (optional)
- The parent window from which to inherit zoom factors from if
- aOpenerFullZoom is none.
- @param aIsCallerChrome
- True if the code requesting the new window is privileged.
- @param aSizeSpec
- The size that the new window should be.
- @param aOpenerFullZoom
- If not nothing, a zoom factor to scale the content to.
- */
- void
- nsWindowWatcher::SizeOpenedWindow(nsIDocShellTreeOwner* aTreeOwner,
- mozIDOMWindowProxy* aParent,
- bool aIsCallerChrome,
- const SizeSpec& aSizeSpec,
- Maybe<float> aOpenerFullZoom)
- {
- // We should only be sizing top-level windows if we're in the parent
- // process.
- MOZ_ASSERT(XRE_IsParentProcess());
- // position and size of window
- int32_t left = 0, top = 0, width = 100, height = 100;
- // difference between chrome and content size
- int32_t chromeWidth = 0, chromeHeight = 0;
- // whether the window size spec refers to chrome or content
- bool sizeChromeWidth = true, sizeChromeHeight = true;
- // get various interfaces for aDocShellItem, used throughout this method
- nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(aTreeOwner));
- if (!treeOwnerAsWin) { // we'll need this to actually size the docshell
- return;
- }
- double openerZoom = aOpenerFullZoom.valueOr(1.0);
- if (aParent && aOpenerFullZoom.isNothing()) {
- nsCOMPtr<nsPIDOMWindowOuter> piWindow = nsPIDOMWindowOuter::From(aParent);
- if (nsIDocument* doc = piWindow->GetDoc()) {
- if (nsIPresShell* shell = doc->GetShell()) {
- if (nsPresContext* presContext = shell->GetPresContext()) {
- openerZoom = presContext->GetFullZoom();
- }
- }
- }
- }
- double scale = 1.0;
- treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale);
- /* The current position and size will be unchanged if not specified
- (and they fit entirely onscreen). Also, calculate the difference
- between chrome and content sizes on aDocShellItem's window.
- This latter point becomes important if chrome and content
- specifications are mixed in aFeatures, and when bringing the window
- back from too far off the right or bottom edges of the screen. */
- treeOwnerAsWin->GetPositionAndSize(&left, &top, &width, &height);
- left = NSToIntRound(left / scale);
- top = NSToIntRound(top / scale);
- width = NSToIntRound(width / scale);
- height = NSToIntRound(height / scale);
- {
- int32_t contentWidth, contentHeight;
- bool hasPrimaryContent = false;
- aTreeOwner->GetHasPrimaryContent(&hasPrimaryContent);
- if (hasPrimaryContent) {
- aTreeOwner->GetPrimaryContentSize(&contentWidth, &contentHeight);
- } else {
- aTreeOwner->GetRootShellSize(&contentWidth, &contentHeight);
- }
- chromeWidth = width - contentWidth;
- chromeHeight = height - contentHeight;
- }
- // Set up left/top
- if (aSizeSpec.mLeftSpecified) {
- left = NSToIntRound(aSizeSpec.mLeft * openerZoom);
- }
- if (aSizeSpec.mTopSpecified) {
- top = NSToIntRound(aSizeSpec.mTop * openerZoom);
- }
- // Set up width
- if (aSizeSpec.mOuterWidthSpecified) {
- if (!aSizeSpec.mUseDefaultWidth) {
- width = NSToIntRound(aSizeSpec.mOuterWidth * openerZoom);
- } // Else specified to default; just use our existing width
- } else if (aSizeSpec.mInnerWidthSpecified) {
- sizeChromeWidth = false;
- if (aSizeSpec.mUseDefaultWidth) {
- width = width - chromeWidth;
- } else {
- width = NSToIntRound(aSizeSpec.mInnerWidth * openerZoom);
- }
- }
- // Set up height
- if (aSizeSpec.mOuterHeightSpecified) {
- if (!aSizeSpec.mUseDefaultHeight) {
- height = NSToIntRound(aSizeSpec.mOuterHeight * openerZoom);
- } // Else specified to default; just use our existing height
- } else if (aSizeSpec.mInnerHeightSpecified) {
- sizeChromeHeight = false;
- if (aSizeSpec.mUseDefaultHeight) {
- height = height - chromeHeight;
- } else {
- height = NSToIntRound(aSizeSpec.mInnerHeight * openerZoom);
- }
- }
- bool positionSpecified = aSizeSpec.PositionSpecified();
- // Check security state for use in determing window dimensions
- bool enabled = false;
- if (aIsCallerChrome) {
- // Only enable special priveleges for chrome when chrome calls
- // open() on a chrome window
- nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(aParent));
- enabled = !aParent || chromeWin;
- }
- if (!enabled) {
- // Security check failed. Ensure all args meet minimum reqs.
- int32_t oldTop = top, oldLeft = left;
- // We'll also need the screen dimensions
- nsCOMPtr<nsIScreen> screen;
- nsCOMPtr<nsIScreenManager> screenMgr(
- do_GetService("@mozilla.org/gfx/screenmanager;1"));
- if (screenMgr)
- screenMgr->ScreenForRect(left, top, width, height,
- getter_AddRefs(screen));
- if (screen) {
- int32_t screenLeft, screenTop, screenWidth, screenHeight;
- int32_t winWidth = width + (sizeChromeWidth ? 0 : chromeWidth),
- winHeight = height + (sizeChromeHeight ? 0 : chromeHeight);
- // Get screen dimensions (in device pixels)
- screen->GetAvailRect(&screenLeft, &screenTop, &screenWidth,
- &screenHeight);
- // Convert them to CSS pixels
- screenLeft = NSToIntRound(screenLeft / scale);
- screenTop = NSToIntRound(screenTop / scale);
- screenWidth = NSToIntRound(screenWidth / scale);
- screenHeight = NSToIntRound(screenHeight / scale);
- if (aSizeSpec.SizeSpecified()) {
- /* Unlike position, force size out-of-bounds check only if
- size actually was specified. Otherwise, intrinsically sized
- windows are broken. */
- if (height < 100) {
- height = 100;
- winHeight = height + (sizeChromeHeight ? 0 : chromeHeight);
- }
- if (winHeight > screenHeight) {
- height = screenHeight - (sizeChromeHeight ? 0 : chromeHeight);
- }
- if (width < 100) {
- width = 100;
- winWidth = width + (sizeChromeWidth ? 0 : chromeWidth);
- }
- if (winWidth > screenWidth) {
- width = screenWidth - (sizeChromeWidth ? 0 : chromeWidth);
- }
- }
- if (left + winWidth > screenLeft + screenWidth ||
- left + winWidth < left) {
- left = screenLeft + screenWidth - winWidth;
- }
- if (left < screenLeft) {
- left = screenLeft;
- }
- if (top + winHeight > screenTop + screenHeight || top + winHeight < top) {
- top = screenTop + screenHeight - winHeight;
- }
- if (top < screenTop) {
- top = screenTop;
- }
- if (top != oldTop || left != oldLeft) {
- positionSpecified = true;
- }
- }
- }
- // size and position the window
- if (positionSpecified) {
- // Get the scale factor appropriate for the screen we're actually
- // positioning on.
- nsCOMPtr<nsIScreen> screen;
- nsCOMPtr<nsIScreenManager> screenMgr(
- do_GetService("@mozilla.org/gfx/screenmanager;1"));
- if (screenMgr) {
- screenMgr->ScreenForRect(left, top, 1, 1, getter_AddRefs(screen));
- }
- if (screen) {
- double cssToDevPixScale, desktopToDevPixScale;
- screen->GetDefaultCSSScaleFactor(&cssToDevPixScale);
- screen->GetContentsScaleFactor(&desktopToDevPixScale);
- double cssToDesktopScale = cssToDevPixScale / desktopToDevPixScale;
- int32_t screenLeft, screenTop, screenWd, screenHt;
- screen->GetRectDisplayPix(&screenLeft, &screenTop, &screenWd, &screenHt);
- // Adjust by desktop-pixel origin of the target screen when scaling
- // to convert from per-screen CSS-px coords to global desktop coords.
- treeOwnerAsWin->SetPositionDesktopPix(
- (left - screenLeft) * cssToDesktopScale + screenLeft,
- (top - screenTop) * cssToDesktopScale + screenTop);
- } else {
- // Couldn't find screen? This shouldn't happen.
- treeOwnerAsWin->SetPosition(left * scale, top * scale);
- }
- // This shouldn't be necessary, given the screen check above, but in case
- // moving the window didn't put it where we expected (e.g. due to issues
- // at the widget level, or whatever), let's re-fetch the scale factor for
- // wherever it really ended up
- treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale);
- }
- if (aSizeSpec.SizeSpecified()) {
- /* Prefer to trust the interfaces, which think in terms of pure
- chrome or content sizes. If we have a mix, use the chrome size
- adjusted by the chrome/content differences calculated earlier. */
- if (!sizeChromeWidth && !sizeChromeHeight) {
- bool hasPrimaryContent = false;
- aTreeOwner->GetHasPrimaryContent(&hasPrimaryContent);
- if (hasPrimaryContent) {
- aTreeOwner->SetPrimaryContentSize(width * scale, height * scale);
- } else {
- aTreeOwner->SetRootShellSize(width * scale, height * scale);
- }
- } else {
- if (!sizeChromeWidth) {
- width += chromeWidth;
- }
- if (!sizeChromeHeight) {
- height += chromeHeight;
- }
- treeOwnerAsWin->SetSize(width * scale, height * scale, false);
- }
- }
- treeOwnerAsWin->SetVisibility(true);
- }
- void
- nsWindowWatcher::GetWindowTreeItem(mozIDOMWindowProxy* aWindow,
- nsIDocShellTreeItem** aResult)
- {
- *aResult = 0;
- if (aWindow) {
- nsIDocShell* docshell = nsPIDOMWindowOuter::From(aWindow)->GetDocShell();
- if (docshell) {
- CallQueryInterface(docshell, aResult);
- }
- }
- }
- void
- nsWindowWatcher::GetWindowTreeOwner(nsPIDOMWindowOuter* aWindow,
- nsIDocShellTreeOwner** aResult)
- {
- *aResult = 0;
- nsCOMPtr<nsIDocShellTreeItem> treeItem;
- GetWindowTreeItem(aWindow, getter_AddRefs(treeItem));
- if (treeItem) {
- treeItem->GetTreeOwner(aResult);
- }
- }
- /* static */
- int32_t
- nsWindowWatcher::GetWindowOpenLocation(nsPIDOMWindowOuter* aParent,
- uint32_t aChromeFlags,
- bool aCalledFromJS,
- bool aPositionSpecified,
- bool aSizeSpecified)
- {
- bool isFullScreen = aParent->GetFullScreen();
- // Where should we open this?
- int32_t containerPref;
- if (NS_FAILED(Preferences::GetInt("browser.link.open_newwindow",
- &containerPref))) {
- // We couldn't read the user preference, so fall back on the default.
- return nsIBrowserDOMWindow::OPEN_NEWTAB;
- }
- bool isDisabledOpenNewWindow =
- isFullScreen &&
- Preferences::GetBool("browser.link.open_newwindow.disabled_in_fullscreen");
- if (isDisabledOpenNewWindow &&
- (containerPref == nsIBrowserDOMWindow::OPEN_NEWWINDOW)) {
- containerPref = nsIBrowserDOMWindow::OPEN_NEWTAB;
- }
- if (containerPref != nsIBrowserDOMWindow::OPEN_NEWTAB &&
- containerPref != nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
- // Just open a window normally
- return nsIBrowserDOMWindow::OPEN_NEWWINDOW;
- }
- if (aCalledFromJS) {
- /* Now check our restriction pref. The restriction pref is a power-user's
- fine-tuning pref. values:
- 0: no restrictions - divert everything
- 1: don't divert window.open at all
- 2: don't divert window.open with features
- */
- int32_t restrictionPref =
- Preferences::GetInt("browser.link.open_newwindow.restriction", 2);
- if (restrictionPref < 0 || restrictionPref > 2) {
- restrictionPref = 2; // Sane default behavior
- }
- if (isDisabledOpenNewWindow) {
- // In browser fullscreen, the window should be opened
- // in the current window with no features (see bug 803675)
- restrictionPref = 0;
- }
- if (restrictionPref == 1) {
- return nsIBrowserDOMWindow::OPEN_NEWWINDOW;
- }
- if (restrictionPref == 2) {
- // Only continue if there are no size/position features and no special
- // chrome flags - with the exception of the remoteness and private flags,
- // which might have been automatically flipped by Gecko.
- int32_t uiChromeFlags = aChromeFlags;
- uiChromeFlags &= ~(nsIWebBrowserChrome::CHROME_REMOTE_WINDOW |
- nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW |
- nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW |
- nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME);
- if (uiChromeFlags != nsIWebBrowserChrome::CHROME_ALL ||
- aPositionSpecified || aSizeSpecified) {
- return nsIBrowserDOMWindow::OPEN_NEWWINDOW;
- }
- }
- }
- return containerPref;
- }
|