1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 ci et: */
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 #include "mozilla/MathAlgorithms.h"
8 
9 // Local includes
10 #include "nsXULWindow.h"
11 #include <algorithm>
12 
13 // Helper classes
14 #include "nsPrintfCString.h"
15 #include "nsString.h"
16 #include "nsWidgetsCID.h"
17 #include "nsThreadUtils.h"
18 #include "nsNetCID.h"
19 #include "nsQueryObject.h"
20 #include "mozilla/Sprintf.h"
21 
22 // Interfaces needed to be included
23 #include "nsIAppShell.h"
24 #include "nsIAppShellService.h"
25 #include "nsIServiceManager.h"
26 #include "nsIContentViewer.h"
27 #include "nsIDocument.h"
28 #include "nsIDOMDocument.h"
29 #include "nsIDOMElement.h"
30 #include "nsIDOMXULElement.h"
31 #include "nsPIDOMWindow.h"
32 #include "nsIDOMScreen.h"
33 #include "nsIEmbeddingSiteWindow.h"
34 #include "nsIInterfaceRequestor.h"
35 #include "nsIInterfaceRequestorUtils.h"
36 #include "nsIIOService.h"
37 #include "nsILoadContext.h"
38 #include "nsIObserverService.h"
39 #include "nsIWindowMediator.h"
40 #include "nsIScreenManager.h"
41 #include "nsIScreen.h"
42 #include "nsIScrollable.h"
43 #include "nsIScriptSecurityManager.h"
44 #include "nsIWindowWatcher.h"
45 #include "nsIURI.h"
46 #include "nsAppShellCID.h"
47 #include "nsReadableUtils.h"
48 #include "nsStyleConsts.h"
49 #include "nsPresContext.h"
50 #include "nsContentUtils.h"
51 #include "nsWebShellWindow.h"  // get rid of this one, too...
52 #include "nsGlobalWindow.h"
53 #include "XULDocument.h"
54 
55 #include "prenv.h"
56 #include "mozilla/AutoRestore.h"
57 #include "mozilla/Preferences.h"
58 #include "mozilla/Services.h"
59 #include "mozilla/dom/BarProps.h"
60 #include "mozilla/dom/Element.h"
61 #include "mozilla/dom/Event.h"
62 #include "mozilla/dom/ScriptSettings.h"
63 #include "mozilla/dom/TabParent.h"
64 
65 using namespace mozilla;
66 using dom::AutoNoJSAPI;
67 
68 #define SIZEMODE_NORMAL NS_LITERAL_STRING("normal")
69 #define SIZEMODE_MAXIMIZED NS_LITERAL_STRING("maximized")
70 #define SIZEMODE_MINIMIZED NS_LITERAL_STRING("minimized")
71 #define SIZEMODE_FULLSCREEN NS_LITERAL_STRING("fullscreen")
72 
73 #define WINDOWTYPE_ATTRIBUTE NS_LITERAL_STRING("windowtype")
74 
75 #define PERSIST_ATTRIBUTE NS_LITERAL_STRING("persist")
76 #define SCREENX_ATTRIBUTE NS_LITERAL_STRING("screenX")
77 #define SCREENY_ATTRIBUTE NS_LITERAL_STRING("screenY")
78 #define WIDTH_ATTRIBUTE NS_LITERAL_STRING("width")
79 #define HEIGHT_ATTRIBUTE NS_LITERAL_STRING("height")
80 #define MODE_ATTRIBUTE NS_LITERAL_STRING("sizemode")
81 #define ZLEVEL_ATTRIBUTE NS_LITERAL_STRING("zlevel")
82 
83 //*****************************************************************************
84 //***    nsXULWindow: Object Management
85 //*****************************************************************************
86 
nsXULWindow(uint32_t aChromeFlags)87 nsXULWindow::nsXULWindow(uint32_t aChromeFlags)
88     : mChromeTreeOwner(nullptr),
89       mContentTreeOwner(nullptr),
90       mPrimaryContentTreeOwner(nullptr),
91       mModalStatus(NS_OK),
92       mContinueModalLoop(false),
93       mDebuting(false),
94       mChromeLoaded(false),
95       mShowAfterLoad(false),
96       mIntrinsicallySized(false),
97       mCenterAfterLoad(false),
98       mIsHiddenWindow(false),
99       mLockedUntilChromeLoad(false),
100       mIgnoreXULSize(false),
101       mIgnoreXULPosition(false),
102       mChromeFlagsFrozen(false),
103       mIgnoreXULSizeMode(false),
104       mDestroying(false),
105       mRegistered(false),
106       mPersistentAttributesDirty(0),
107       mPersistentAttributesMask(0),
108       mChromeFlags(aChromeFlags),
109       mNextTabParentId(0) {}
110 
~nsXULWindow()111 nsXULWindow::~nsXULWindow() { Destroy(); }
112 
113 //*****************************************************************************
114 // nsXULWindow::nsISupports
115 //*****************************************************************************
116 
117 NS_IMPL_ADDREF(nsXULWindow)
118 NS_IMPL_RELEASE(nsXULWindow)
119 
120 NS_INTERFACE_MAP_BEGIN(nsXULWindow)
121   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULWindow)
122   NS_INTERFACE_MAP_ENTRY(nsIXULWindow)
123   NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
124   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
125   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
126   if (aIID.Equals(NS_GET_IID(nsXULWindow)))
127     foundInterface = reinterpret_cast<nsISupports*>(this);
128   else
129 NS_INTERFACE_MAP_END
130 
131 //*****************************************************************************
132 // nsXULWindow::nsIIntefaceRequestor
133 //*****************************************************************************
134 
GetInterface(const nsIID & aIID,void ** aSink)135 NS_IMETHODIMP nsXULWindow::GetInterface(const nsIID& aIID, void** aSink) {
136   nsresult rv;
137 
138   NS_ENSURE_ARG_POINTER(aSink);
139 
140   if (aIID.Equals(NS_GET_IID(nsIPrompt))) {
141     rv = EnsurePrompter();
142     if (NS_FAILED(rv)) return rv;
143     return mPrompter->QueryInterface(aIID, aSink);
144   }
145   if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
146     rv = EnsureAuthPrompter();
147     if (NS_FAILED(rv)) return rv;
148     return mAuthPrompter->QueryInterface(aIID, aSink);
149   }
150   if (aIID.Equals(NS_GET_IID(mozIDOMWindowProxy))) {
151     return GetWindowDOMWindow(reinterpret_cast<mozIDOMWindowProxy**>(aSink));
152   }
153   if (aIID.Equals(NS_GET_IID(nsIDOMWindow))) {
154     nsCOMPtr<mozIDOMWindowProxy> window = nullptr;
155     rv = GetWindowDOMWindow(getter_AddRefs(window));
156     nsCOMPtr<nsIDOMWindow> domWindow = do_QueryInterface(window);
157     domWindow.forget(aSink);
158     return rv;
159   }
160   if (aIID.Equals(NS_GET_IID(nsIWebBrowserChrome)) &&
161       NS_SUCCEEDED(EnsureContentTreeOwner()) &&
162       NS_SUCCEEDED(mContentTreeOwner->QueryInterface(aIID, aSink)))
163     return NS_OK;
164 
165   if (aIID.Equals(NS_GET_IID(nsIEmbeddingSiteWindow)) &&
166       NS_SUCCEEDED(EnsureContentTreeOwner()) &&
167       NS_SUCCEEDED(mContentTreeOwner->QueryInterface(aIID, aSink)))
168     return NS_OK;
169 
170   return QueryInterface(aIID, aSink);
171 }
172 
173 //*****************************************************************************
174 // nsXULWindow::nsIXULWindow
175 //*****************************************************************************
176 
GetDocShell(nsIDocShell ** aDocShell)177 NS_IMETHODIMP nsXULWindow::GetDocShell(nsIDocShell** aDocShell) {
178   NS_ENSURE_ARG_POINTER(aDocShell);
179 
180   *aDocShell = mDocShell;
181   NS_IF_ADDREF(*aDocShell);
182   return NS_OK;
183 }
184 
GetZLevel(uint32_t * outLevel)185 NS_IMETHODIMP nsXULWindow::GetZLevel(uint32_t* outLevel) {
186   nsCOMPtr<nsIWindowMediator> mediator(
187       do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
188   if (mediator)
189     mediator->GetZLevel(this, outLevel);
190   else
191     *outLevel = normalZ;
192   return NS_OK;
193 }
194 
SetZLevel(uint32_t aLevel)195 NS_IMETHODIMP nsXULWindow::SetZLevel(uint32_t aLevel) {
196   nsCOMPtr<nsIWindowMediator> mediator(
197       do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
198   if (!mediator) return NS_ERROR_FAILURE;
199 
200   uint32_t zLevel;
201   mediator->GetZLevel(this, &zLevel);
202   if (zLevel == aLevel) return NS_OK;
203 
204   /* refuse to raise a maximized window above the normal browser level,
205      for fear it could hide newly opened browser windows */
206   if (aLevel > nsIXULWindow::normalZ && mWindow) {
207     nsSizeMode sizeMode = mWindow->SizeMode();
208     if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) {
209       return NS_ERROR_FAILURE;
210     }
211   }
212 
213   // do it
214   mediator->SetZLevel(this, aLevel);
215   PersistentAttributesDirty(PAD_MISC);
216   SavePersistentAttributes();
217 
218   nsCOMPtr<nsIContentViewer> cv;
219   mDocShell->GetContentViewer(getter_AddRefs(cv));
220   if (cv) {
221     nsCOMPtr<nsIDocument> doc = cv->GetDocument();
222     if (doc) {
223       ErrorResult rv;
224       RefPtr<dom::Event> event = doc->CreateEvent(NS_LITERAL_STRING("Events"),
225                                                   dom::CallerType::System, rv);
226       if (event) {
227         event->InitEvent(NS_LITERAL_STRING("windowZLevel"), true, false);
228 
229         event->SetTrusted(true);
230 
231         bool defaultActionEnabled;
232         doc->DispatchEvent(event, &defaultActionEnabled);
233       }
234     }
235   }
236   return NS_OK;
237 }
238 
GetChromeFlags(uint32_t * aChromeFlags)239 NS_IMETHODIMP nsXULWindow::GetChromeFlags(uint32_t* aChromeFlags) {
240   NS_ENSURE_ARG_POINTER(aChromeFlags);
241   *aChromeFlags = mChromeFlags;
242   /* mChromeFlags is kept up to date, except for scrollbar visibility.
243      That can be changed directly by the content DOM window, which
244      doesn't know to update the chrome window. So that we must check
245      separately. */
246 
247   // however, it's pointless to ask if the window isn't set up yet
248   if (!mChromeLoaded) return NS_OK;
249 
250   if (GetContentScrollbarVisibility())
251     *aChromeFlags |= nsIWebBrowserChrome::CHROME_SCROLLBARS;
252   else
253     *aChromeFlags &= ~nsIWebBrowserChrome::CHROME_SCROLLBARS;
254 
255   return NS_OK;
256 }
257 
SetChromeFlags(uint32_t aChromeFlags)258 NS_IMETHODIMP nsXULWindow::SetChromeFlags(uint32_t aChromeFlags) {
259   NS_ASSERTION(!mChromeFlagsFrozen,
260                "SetChromeFlags() after AssumeChromeFlagsAreFrozen()!");
261 
262   mChromeFlags = aChromeFlags;
263   if (mChromeLoaded) NS_ENSURE_SUCCESS(ApplyChromeFlags(), NS_ERROR_FAILURE);
264   return NS_OK;
265 }
266 
AssumeChromeFlagsAreFrozen()267 NS_IMETHODIMP nsXULWindow::AssumeChromeFlagsAreFrozen() {
268   mChromeFlagsFrozen = true;
269   return NS_OK;
270 }
271 
SetIntrinsicallySized(bool aIntrinsicallySized)272 NS_IMETHODIMP nsXULWindow::SetIntrinsicallySized(bool aIntrinsicallySized) {
273   mIntrinsicallySized = aIntrinsicallySized;
274   return NS_OK;
275 }
276 
GetIntrinsicallySized(bool * aIntrinsicallySized)277 NS_IMETHODIMP nsXULWindow::GetIntrinsicallySized(bool* aIntrinsicallySized) {
278   NS_ENSURE_ARG_POINTER(aIntrinsicallySized);
279 
280   *aIntrinsicallySized = mIntrinsicallySized;
281   return NS_OK;
282 }
283 
GetPrimaryContentShell(nsIDocShellTreeItem ** aDocShellTreeItem)284 NS_IMETHODIMP nsXULWindow::GetPrimaryContentShell(
285     nsIDocShellTreeItem** aDocShellTreeItem) {
286   NS_ENSURE_ARG_POINTER(aDocShellTreeItem);
287   NS_IF_ADDREF(*aDocShellTreeItem = mPrimaryContentShell);
288   return NS_OK;
289 }
290 
291 NS_IMETHODIMP
TabParentAdded(nsITabParent * aTab,bool aPrimary)292 nsXULWindow::TabParentAdded(nsITabParent* aTab, bool aPrimary) {
293   if (aPrimary) {
294     mPrimaryTabParent = aTab;
295     mPrimaryContentShell = nullptr;
296   } else if (mPrimaryTabParent == aTab) {
297     mPrimaryTabParent = nullptr;
298   }
299 
300   return NS_OK;
301 }
302 
303 NS_IMETHODIMP
TabParentRemoved(nsITabParent * aTab)304 nsXULWindow::TabParentRemoved(nsITabParent* aTab) {
305   if (aTab == mPrimaryTabParent) {
306     mPrimaryTabParent = nullptr;
307   }
308 
309   return NS_OK;
310 }
311 
312 NS_IMETHODIMP
GetPrimaryTabParent(nsITabParent ** aTab)313 nsXULWindow::GetPrimaryTabParent(nsITabParent** aTab) {
314   nsCOMPtr<nsITabParent> tab = mPrimaryTabParent;
315   tab.forget(aTab);
316   return NS_OK;
317 }
318 
319 nsTArray<RefPtr<mozilla::LiveResizeListener>>
GetLiveResizeListeners()320 nsXULWindow::GetLiveResizeListeners() {
321   nsTArray<RefPtr<mozilla::LiveResizeListener>> listeners;
322   if (mPrimaryTabParent) {
323     TabParent* parent = static_cast<TabParent*>(mPrimaryTabParent.get());
324     listeners.AppendElement(parent);
325   }
326   return listeners;
327 }
328 
AddChildWindow(nsIXULWindow * aChild)329 NS_IMETHODIMP nsXULWindow::AddChildWindow(nsIXULWindow* aChild) {
330   // we're not really keeping track of this right now
331   return NS_OK;
332 }
333 
RemoveChildWindow(nsIXULWindow * aChild)334 NS_IMETHODIMP nsXULWindow::RemoveChildWindow(nsIXULWindow* aChild) {
335   // we're not really keeping track of this right now
336   return NS_OK;
337 }
338 
ShowModal()339 NS_IMETHODIMP nsXULWindow::ShowModal() {
340   AUTO_PROFILER_LABEL("nsXULWindow::ShowModal", OTHER);
341 
342   // Store locally so it doesn't die on us
343   nsCOMPtr<nsIWidget> window = mWindow;
344   nsCOMPtr<nsIXULWindow> tempRef = this;
345 
346   window->SetModal(true);
347   mContinueModalLoop = true;
348   EnableParent(false);
349 
350   {
351     AutoNoJSAPI nojsapi;
352     SpinEventLoopUntil([&]() { return !mContinueModalLoop; });
353   }
354 
355   mContinueModalLoop = false;
356   window->SetModal(false);
357   /*   Note there's no EnableParent(true) here to match the false one
358      above. That's done in ExitModalLoop. It's important that the parent
359      be re-enabled before this window is made invisible; to do otherwise
360      causes bizarre z-ordering problems. At this point, the window is
361      already invisible.
362        No known current implementation of Enable would have a problem with
363      re-enabling the parent twice, so we could do it again here without
364      breaking any current implementation. But that's unnecessary if the
365      modal loop is always exited using ExitModalLoop (the other way would be
366      to change the protected member variable directly.)
367   */
368 
369   return mModalStatus;
370 }
371 
372 //*****************************************************************************
373 // nsXULWindow::nsIBaseWindow
374 //*****************************************************************************
375 
InitWindow(nativeWindow aParentNativeWindow,nsIWidget * parentWidget,int32_t x,int32_t y,int32_t cx,int32_t cy)376 NS_IMETHODIMP nsXULWindow::InitWindow(nativeWindow aParentNativeWindow,
377                                       nsIWidget* parentWidget, int32_t x,
378                                       int32_t y, int32_t cx, int32_t cy) {
379   // XXX First Check In
380   NS_ASSERTION(false, "Not Yet Implemented");
381   return NS_OK;
382 }
383 
Create()384 NS_IMETHODIMP nsXULWindow::Create() {
385   // XXX First Check In
386   NS_ASSERTION(false, "Not Yet Implemented");
387   return NS_OK;
388 }
389 
Destroy()390 NS_IMETHODIMP nsXULWindow::Destroy() {
391   if (!mWindow) return NS_OK;
392 
393   // Ensure we don't reenter this code
394   if (mDestroying) return NS_OK;
395 
396   mozilla::AutoRestore<bool> guard(mDestroying);
397   mDestroying = true;
398 
399   nsCOMPtr<nsIAppShellService> appShell(
400       do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
401   NS_ASSERTION(appShell, "Couldn't get appShell... xpcom shutdown?");
402   if (appShell)
403     appShell->UnregisterTopLevelWindow(static_cast<nsIXULWindow*>(this));
404 
405   nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow));
406   if (parentWindow) parentWindow->RemoveChildWindow(this);
407 
408   // let's make sure the window doesn't get deleted out from under us
409   // while we are trying to close....this can happen if the docshell
410   // we close ends up being the last owning reference to this xulwindow
411 
412   // XXXTAB This shouldn't be an issue anymore because the ownership model
413   // only goes in one direction.  When webshell container is fully removed
414   // try removing this...
415 
416   nsCOMPtr<nsIXULWindow> placeHolder = this;
417 
418   // Remove modality (if any) and hide while destroying. More than
419   // a convenience, the hide prevents user interaction with the partially
420   // destroyed window. This is especially necessary when the eldest window
421   // in a stack of modal windows is destroyed first. It happens.
422   ExitModalLoop(NS_OK);
423   // XXX: Skip unmapping the window on Linux due to GLX hangs on the compositor
424   // thread with NVIDIA driver 310.32. We don't need to worry about user
425   // interactions with destroyed windows on X11 either.
426 #ifndef MOZ_WIDGET_GTK
427   if (mWindow) mWindow->Show(false);
428 #endif
429 
430 #if defined(XP_WIN)
431   // We need to explicitly set the focus on Windows, but
432   // only if the parent is visible.
433   nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow));
434   if (parent) {
435     nsCOMPtr<nsIWidget> parentWidget;
436     parent->GetMainWidget(getter_AddRefs(parentWidget));
437     if (!parentWidget || parentWidget->IsVisible()) {
438       nsCOMPtr<nsIBaseWindow> baseHiddenWindow;
439       if (appShell) {
440         nsCOMPtr<nsIXULWindow> hiddenWindow;
441         appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
442         if (hiddenWindow) baseHiddenWindow = do_GetInterface(hiddenWindow);
443       }
444       // somebody screwed up somewhere. hiddenwindow shouldn't be anybody's
445       // parent. still, when it happens, skip activating it.
446       if (baseHiddenWindow != parent) {
447         nsCOMPtr<nsIWidget> parentWidget;
448         parent->GetMainWidget(getter_AddRefs(parentWidget));
449         if (parentWidget) parentWidget->PlaceBehind(eZPlacementTop, 0, true);
450       }
451     }
452   }
453 #endif
454 
455   mDOMWindow = nullptr;
456   if (mDocShell) {
457     nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
458     shellAsWin->Destroy();
459     mDocShell = nullptr;  // this can cause reentrancy of this function
460   }
461 
462   mPrimaryContentShell = nullptr;
463 
464   if (mContentTreeOwner) {
465     mContentTreeOwner->XULWindow(nullptr);
466     NS_RELEASE(mContentTreeOwner);
467   }
468   if (mPrimaryContentTreeOwner) {
469     mPrimaryContentTreeOwner->XULWindow(nullptr);
470     NS_RELEASE(mPrimaryContentTreeOwner);
471   }
472   if (mChromeTreeOwner) {
473     mChromeTreeOwner->XULWindow(nullptr);
474     NS_RELEASE(mChromeTreeOwner);
475   }
476   if (mWindow) {
477     mWindow->SetWidgetListener(nullptr);  // nsWebShellWindow hackery
478     mWindow->Destroy();
479     mWindow = nullptr;
480   }
481 
482   if (!mIsHiddenWindow && mRegistered) {
483     /* Inform appstartup we've destroyed this window and it could
484        quit now if it wanted. This must happen at least after mDocShell
485        is destroyed, because onunload handlers fire then, and those being
486        script, anything could happen. A new window could open, even.
487        See bug 130719. */
488     nsCOMPtr<nsIObserverService> obssvc = services::GetObserverService();
489     NS_ASSERTION(obssvc, "Couldn't get observer service?");
490 
491     if (obssvc)
492       obssvc->NotifyObservers(nullptr, "xul-window-destroyed", nullptr);
493   }
494 
495   return NS_OK;
496 }
497 
GetDevicePixelsPerDesktopPixel(double * aScale)498 NS_IMETHODIMP nsXULWindow::GetDevicePixelsPerDesktopPixel(double* aScale) {
499   *aScale = mWindow ? mWindow->GetDesktopToDeviceScale().scale : 1.0;
500   return NS_OK;
501 }
502 
GetUnscaledDevicePixelsPerCSSPixel(double * aScale)503 NS_IMETHODIMP nsXULWindow::GetUnscaledDevicePixelsPerCSSPixel(double* aScale) {
504   *aScale = mWindow ? mWindow->GetDefaultScale().scale : 1.0;
505   return NS_OK;
506 }
507 
SetPositionDesktopPix(int32_t aX,int32_t aY)508 NS_IMETHODIMP nsXULWindow::SetPositionDesktopPix(int32_t aX, int32_t aY) {
509   mWindow->Move(aX, aY);
510   if (!mChromeLoaded) {
511     // If we're called before the chrome is loaded someone obviously wants this
512     // window at this position. We don't persist this one-time position.
513     mIgnoreXULPosition = true;
514     return NS_OK;
515   }
516   PersistentAttributesDirty(PAD_POSITION);
517   SavePersistentAttributes();
518   return NS_OK;
519 }
520 
521 // The parameters here are device pixels; do the best we can to convert to
522 // desktop px, using the window's current scale factor (if available).
SetPosition(int32_t aX,int32_t aY)523 NS_IMETHODIMP nsXULWindow::SetPosition(int32_t aX, int32_t aY) {
524   // Don't reset the window's size mode here - platforms that don't want to move
525   // maximized windows should reset it in their respective Move implementation.
526   DesktopToLayoutDeviceScale currScale = mWindow->GetDesktopToDeviceScale();
527   DesktopPoint pos = LayoutDeviceIntPoint(aX, aY) / currScale;
528   return SetPositionDesktopPix(pos.x, pos.y);
529 }
530 
GetPosition(int32_t * aX,int32_t * aY)531 NS_IMETHODIMP nsXULWindow::GetPosition(int32_t* aX, int32_t* aY) {
532   return GetPositionAndSize(aX, aY, nullptr, nullptr);
533 }
534 
SetSize(int32_t aCX,int32_t aCY,bool aRepaint)535 NS_IMETHODIMP nsXULWindow::SetSize(int32_t aCX, int32_t aCY, bool aRepaint) {
536   /* any attempt to set the window's size or position overrides the window's
537      zoom state. this is important when these two states are competing while
538      the window is being opened. but it should probably just always be so. */
539   mWindow->SetSizeMode(nsSizeMode_Normal);
540 
541   mIntrinsicallySized = false;
542 
543   DesktopToLayoutDeviceScale scale = mWindow->GetDesktopToDeviceScale();
544   DesktopSize size = LayoutDeviceIntSize(aCX, aCY) / scale;
545   mWindow->Resize(size.width, size.height, aRepaint);
546   if (!mChromeLoaded) {
547     // If we're called before the chrome is loaded someone obviously wants this
548     // window at this size & in the normal size mode (since it is the only mode
549     // in which setting dimensions makes sense). We don't persist this one-time
550     // size.
551     mIgnoreXULSize = true;
552     mIgnoreXULSizeMode = true;
553     return NS_OK;
554   }
555   PersistentAttributesDirty(PAD_SIZE);
556   SavePersistentAttributes();
557   return NS_OK;
558 }
559 
GetSize(int32_t * aCX,int32_t * aCY)560 NS_IMETHODIMP nsXULWindow::GetSize(int32_t* aCX, int32_t* aCY) {
561   return GetPositionAndSize(nullptr, nullptr, aCX, aCY);
562 }
563 
SetPositionAndSize(int32_t aX,int32_t aY,int32_t aCX,int32_t aCY,uint32_t aFlags)564 NS_IMETHODIMP nsXULWindow::SetPositionAndSize(int32_t aX, int32_t aY,
565                                               int32_t aCX, int32_t aCY,
566                                               uint32_t aFlags) {
567   /* any attempt to set the window's size or position overrides the window's
568      zoom state. this is important when these two states are competing while
569      the window is being opened. but it should probably just always be so. */
570   mWindow->SetSizeMode(nsSizeMode_Normal);
571 
572   mIntrinsicallySized = false;
573 
574   DesktopToLayoutDeviceScale scale = mWindow->GetDesktopToDeviceScale();
575   DesktopRect rect = LayoutDeviceIntRect(aX, aY, aCX, aCY) / scale;
576   mWindow->Resize(rect.X(), rect.Y(), rect.Width(), rect.Height(),
577                   !!(aFlags & nsIBaseWindow::eRepaint));
578   if (!mChromeLoaded) {
579     // If we're called before the chrome is loaded someone obviously wants this
580     // window at this size and position. We don't persist this one-time setting.
581     mIgnoreXULPosition = true;
582     mIgnoreXULSize = true;
583     mIgnoreXULSizeMode = true;
584     return NS_OK;
585   }
586   PersistentAttributesDirty(PAD_POSITION | PAD_SIZE);
587   SavePersistentAttributes();
588   return NS_OK;
589 }
590 
GetPositionAndSize(int32_t * x,int32_t * y,int32_t * cx,int32_t * cy)591 NS_IMETHODIMP nsXULWindow::GetPositionAndSize(int32_t* x, int32_t* y,
592                                               int32_t* cx, int32_t* cy) {
593   if (!mWindow) return NS_ERROR_FAILURE;
594 
595   LayoutDeviceIntRect rect = mWindow->GetScreenBounds();
596 
597   if (x) *x = rect.X();
598   if (y) *y = rect.Y();
599   if (cx) *cx = rect.Width();
600   if (cy) *cy = rect.Height();
601 
602   return NS_OK;
603 }
604 
Center(nsIXULWindow * aRelative,bool aScreen,bool aAlert)605 NS_IMETHODIMP nsXULWindow::Center(nsIXULWindow* aRelative, bool aScreen,
606                                   bool aAlert) {
607   int32_t left, top, width, height, ourWidth, ourHeight;
608   bool screenCoordinates = false, windowCoordinates = false;
609   nsresult result;
610 
611   if (!mChromeLoaded) {
612     // note we lose the parameters. at time of writing, this isn't a problem.
613     mCenterAfterLoad = true;
614     return NS_OK;
615   }
616 
617   if (!aScreen && !aRelative) return NS_ERROR_INVALID_ARG;
618 
619   nsCOMPtr<nsIScreenManager> screenmgr =
620       do_GetService("@mozilla.org/gfx/screenmanager;1", &result);
621   if (NS_FAILED(result)) return result;
622 
623   nsCOMPtr<nsIScreen> screen;
624 
625   if (aRelative) {
626     nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(aRelative, &result));
627     if (base) {
628       // get window rect
629       result = base->GetPositionAndSize(&left, &top, &width, &height);
630       if (NS_SUCCEEDED(result)) {
631         double scale;
632         if (NS_SUCCEEDED(base->GetDevicePixelsPerDesktopPixel(&scale))) {
633           left = NSToIntRound(left / scale);
634           top = NSToIntRound(top / scale);
635           width = NSToIntRound(width / scale);
636           height = NSToIntRound(height / scale);
637         }
638         // if centering on screen, convert that to the corresponding screen
639         if (aScreen)
640           screenmgr->ScreenForRect(left, top, width, height,
641                                    getter_AddRefs(screen));
642         else
643           windowCoordinates = true;
644       } else {
645         // something's wrong with the reference window.
646         // fall back to the primary screen
647         aRelative = 0;
648         aScreen = true;
649       }
650     }
651   }
652   if (!aRelative) {
653     if (!mOpenerScreenRect.IsEmpty()) {
654       // FIXME - check if these are device or display pixels
655       screenmgr->ScreenForRect(mOpenerScreenRect.X(), mOpenerScreenRect.Y(),
656                                mOpenerScreenRect.Width(),
657                                mOpenerScreenRect.Height(),
658                                getter_AddRefs(screen));
659     } else {
660       screenmgr->GetPrimaryScreen(getter_AddRefs(screen));
661     }
662   }
663 
664   if (aScreen && screen) {
665     screen->GetAvailRectDisplayPix(&left, &top, &width, &height);
666     screenCoordinates = true;
667   }
668 
669   if (screenCoordinates || windowCoordinates) {
670     NS_ASSERTION(mWindow, "what, no window?");
671     double scale = mWindow->GetDesktopToDeviceScale().scale;
672     GetSize(&ourWidth, &ourHeight);
673     int32_t scaledWidth, scaledHeight;
674     scaledWidth = NSToIntRound(ourWidth / scale);
675     scaledHeight = NSToIntRound(ourHeight / scale);
676     left += (width - scaledWidth) / 2;
677     top += (height - scaledHeight) / (aAlert ? 3 : 2);
678     if (windowCoordinates) {
679       mWindow->ConstrainPosition(false, &left, &top);
680     }
681     SetPosition(left * scale, top * scale);
682 
683     // If moving the window caused it to change size,
684     // re-do the centering.
685     int32_t newWidth, newHeight;
686     GetSize(&newWidth, &newHeight);
687     if (newWidth != ourWidth || newHeight != ourHeight) {
688       return Center(aRelative, aScreen, aAlert);
689     }
690     return NS_OK;
691   }
692 
693   return NS_ERROR_FAILURE;
694 }
695 
Repaint(bool aForce)696 NS_IMETHODIMP nsXULWindow::Repaint(bool aForce) {
697   // XXX First Check In
698   NS_ASSERTION(false, "Not Yet Implemented");
699   return NS_OK;
700 }
701 
GetParentWidget(nsIWidget ** aParentWidget)702 NS_IMETHODIMP nsXULWindow::GetParentWidget(nsIWidget** aParentWidget) {
703   NS_ENSURE_ARG_POINTER(aParentWidget);
704   NS_ENSURE_STATE(mWindow);
705 
706   NS_IF_ADDREF(*aParentWidget = mWindow->GetParent());
707   return NS_OK;
708 }
709 
SetParentWidget(nsIWidget * aParentWidget)710 NS_IMETHODIMP nsXULWindow::SetParentWidget(nsIWidget* aParentWidget) {
711   // XXX First Check In
712   NS_ASSERTION(false, "Not Yet Implemented");
713   return NS_OK;
714 }
715 
GetParentNativeWindow(nativeWindow * aParentNativeWindow)716 NS_IMETHODIMP nsXULWindow::GetParentNativeWindow(
717     nativeWindow* aParentNativeWindow) {
718   NS_ENSURE_ARG_POINTER(aParentNativeWindow);
719 
720   nsCOMPtr<nsIWidget> parentWidget;
721   NS_ENSURE_SUCCESS(GetParentWidget(getter_AddRefs(parentWidget)),
722                     NS_ERROR_FAILURE);
723 
724   if (parentWidget) {
725     *aParentNativeWindow = parentWidget->GetNativeData(NS_NATIVE_WIDGET);
726   }
727 
728   return NS_OK;
729 }
730 
SetParentNativeWindow(nativeWindow aParentNativeWindow)731 NS_IMETHODIMP nsXULWindow::SetParentNativeWindow(
732     nativeWindow aParentNativeWindow) {
733   // XXX First Check In
734   NS_ASSERTION(false, "Not Yet Implemented");
735   return NS_OK;
736 }
737 
GetNativeHandle(nsAString & aNativeHandle)738 NS_IMETHODIMP nsXULWindow::GetNativeHandle(nsAString& aNativeHandle) {
739   nsCOMPtr<nsIWidget> mainWidget;
740   NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(mainWidget)),
741                     NS_ERROR_FAILURE);
742 
743   if (mainWidget) {
744     nativeWindow nativeWindowPtr = mainWidget->GetNativeData(NS_NATIVE_WINDOW);
745     /* the nativeWindow pointer is converted to and exposed as a string. This
746        is a more reliable way not to lose information (as opposed to JS
747        |Number| for instance) */
748     aNativeHandle =
749         NS_ConvertASCIItoUTF16(nsPrintfCString("0x%p", nativeWindowPtr));
750   }
751 
752   return NS_OK;
753 }
754 
GetVisibility(bool * aVisibility)755 NS_IMETHODIMP nsXULWindow::GetVisibility(bool* aVisibility) {
756   NS_ENSURE_ARG_POINTER(aVisibility);
757 
758   // Always claim to be visible for now. See bug
759   // https://bugzilla.mozilla.org/show_bug.cgi?id=306245.
760 
761   *aVisibility = true;
762 
763   return NS_OK;
764 }
765 
SetVisibility(bool aVisibility)766 NS_IMETHODIMP nsXULWindow::SetVisibility(bool aVisibility) {
767   if (!mChromeLoaded) {
768     mShowAfterLoad = aVisibility;
769     return NS_OK;
770   }
771 
772   if (mDebuting) {
773     return NS_OK;
774   }
775   mDebuting = true;  // (Show / Focus is recursive)
776 
777   // XXXTAB Do we really need to show docshell and the window?  Isn't
778   // the window good enough?
779   nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
780   shellAsWin->SetVisibility(aVisibility);
781   // Store locally so it doesn't die on us. 'Show' can result in the window
782   // being closed with nsXULWindow::Destroy being called. That would set
783   // mWindow to null and posibly destroy the nsIWidget while its Show method
784   // is on the stack. We need to keep it alive until Show finishes.
785   nsCOMPtr<nsIWidget> window = mWindow;
786   window->Show(aVisibility);
787 
788   nsCOMPtr<nsIWindowMediator> windowMediator(
789       do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
790   if (windowMediator)
791     windowMediator->UpdateWindowTimeStamp(static_cast<nsIXULWindow*>(this));
792 
793   // notify observers so that we can hide the splash screen if possible
794   nsCOMPtr<nsIObserverService> obssvc = services::GetObserverService();
795   NS_ASSERTION(obssvc, "Couldn't get observer service.");
796   if (obssvc) {
797     obssvc->NotifyObservers(nullptr, "xul-window-visible", nullptr);
798   }
799 
800   mDebuting = false;
801   return NS_OK;
802 }
803 
GetEnabled(bool * aEnabled)804 NS_IMETHODIMP nsXULWindow::GetEnabled(bool* aEnabled) {
805   NS_ENSURE_ARG_POINTER(aEnabled);
806 
807   if (mWindow) {
808     *aEnabled = mWindow->IsEnabled();
809     return NS_OK;
810   }
811 
812   *aEnabled = true;  // better guess than most
813   return NS_ERROR_FAILURE;
814 }
815 
SetEnabled(bool aEnable)816 NS_IMETHODIMP nsXULWindow::SetEnabled(bool aEnable) {
817   if (mWindow) {
818     mWindow->Enable(aEnable);
819     return NS_OK;
820   }
821   return NS_ERROR_FAILURE;
822 }
823 
GetMainWidget(nsIWidget ** aMainWidget)824 NS_IMETHODIMP nsXULWindow::GetMainWidget(nsIWidget** aMainWidget) {
825   NS_ENSURE_ARG_POINTER(aMainWidget);
826 
827   *aMainWidget = mWindow;
828   NS_IF_ADDREF(*aMainWidget);
829   return NS_OK;
830 }
831 
SetFocus()832 NS_IMETHODIMP nsXULWindow::SetFocus() {
833   // XXX First Check In
834   NS_ASSERTION(false, "Not Yet Implemented");
835   return NS_OK;
836 }
837 
GetTitle(nsAString & aTitle)838 NS_IMETHODIMP nsXULWindow::GetTitle(nsAString& aTitle) {
839   aTitle = mTitle;
840   return NS_OK;
841 }
842 
SetTitle(const nsAString & aTitle)843 NS_IMETHODIMP nsXULWindow::SetTitle(const nsAString& aTitle) {
844   NS_ENSURE_STATE(mWindow);
845   mTitle.Assign(aTitle);
846   mTitle.StripCRLF();
847   NS_ENSURE_SUCCESS(mWindow->SetTitle(mTitle), NS_ERROR_FAILURE);
848   return NS_OK;
849 }
850 
851 //*****************************************************************************
852 // nsXULWindow: Helpers
853 //*****************************************************************************
854 
EnsureChromeTreeOwner()855 NS_IMETHODIMP nsXULWindow::EnsureChromeTreeOwner() {
856   if (mChromeTreeOwner) return NS_OK;
857 
858   mChromeTreeOwner = new nsChromeTreeOwner();
859   NS_ADDREF(mChromeTreeOwner);
860   mChromeTreeOwner->XULWindow(this);
861 
862   return NS_OK;
863 }
864 
EnsureContentTreeOwner()865 NS_IMETHODIMP nsXULWindow::EnsureContentTreeOwner() {
866   if (mContentTreeOwner) return NS_OK;
867 
868   mContentTreeOwner = new nsContentTreeOwner(false);
869   NS_ADDREF(mContentTreeOwner);
870   mContentTreeOwner->XULWindow(this);
871 
872   return NS_OK;
873 }
874 
EnsurePrimaryContentTreeOwner()875 NS_IMETHODIMP nsXULWindow::EnsurePrimaryContentTreeOwner() {
876   if (mPrimaryContentTreeOwner) return NS_OK;
877 
878   mPrimaryContentTreeOwner = new nsContentTreeOwner(true);
879   NS_ADDREF(mPrimaryContentTreeOwner);
880   mPrimaryContentTreeOwner->XULWindow(this);
881 
882   return NS_OK;
883 }
884 
EnsurePrompter()885 NS_IMETHODIMP nsXULWindow::EnsurePrompter() {
886   if (mPrompter) return NS_OK;
887 
888   nsCOMPtr<mozIDOMWindowProxy> ourWindow;
889   nsresult rv = GetWindowDOMWindow(getter_AddRefs(ourWindow));
890   if (NS_SUCCEEDED(rv)) {
891     nsCOMPtr<nsIWindowWatcher> wwatch =
892         do_GetService(NS_WINDOWWATCHER_CONTRACTID);
893     if (wwatch) wwatch->GetNewPrompter(ourWindow, getter_AddRefs(mPrompter));
894   }
895   return mPrompter ? NS_OK : NS_ERROR_FAILURE;
896 }
897 
EnsureAuthPrompter()898 NS_IMETHODIMP nsXULWindow::EnsureAuthPrompter() {
899   if (mAuthPrompter) return NS_OK;
900 
901   nsCOMPtr<mozIDOMWindowProxy> ourWindow;
902   nsresult rv = GetWindowDOMWindow(getter_AddRefs(ourWindow));
903   if (NS_SUCCEEDED(rv)) {
904     nsCOMPtr<nsIWindowWatcher> wwatch(
905         do_GetService(NS_WINDOWWATCHER_CONTRACTID));
906     if (wwatch)
907       wwatch->GetNewAuthPrompter(ourWindow, getter_AddRefs(mAuthPrompter));
908   }
909   return mAuthPrompter ? NS_OK : NS_ERROR_FAILURE;
910 }
911 
GetAvailScreenSize(int32_t * aAvailWidth,int32_t * aAvailHeight)912 NS_IMETHODIMP nsXULWindow::GetAvailScreenSize(int32_t* aAvailWidth,
913                                               int32_t* aAvailHeight) {
914   nsresult rv;
915 
916   nsCOMPtr<mozIDOMWindowProxy> domWindow;
917   GetWindowDOMWindow(getter_AddRefs(domWindow));
918   NS_ENSURE_STATE(domWindow);
919 
920   auto* window = nsPIDOMWindowOuter::From(domWindow);
921   NS_ENSURE_STATE(window);
922 
923   nsCOMPtr<nsIDOMScreen> screen = window->GetScreen();
924   NS_ENSURE_STATE(screen);
925 
926   rv = screen->GetAvailWidth(aAvailWidth);
927   NS_ENSURE_SUCCESS(rv, rv);
928 
929   rv = screen->GetAvailHeight(aAvailHeight);
930   NS_ENSURE_SUCCESS(rv, rv);
931 
932   return NS_OK;
933 }
934 
935 // Rounds window size to 1000x1000, or, if there isn't enough available
936 // screen space, to a multiple of 200x100.
ForceRoundedDimensions()937 NS_IMETHODIMP nsXULWindow::ForceRoundedDimensions() {
938   if (mIsHiddenWindow) {
939     return NS_OK;
940   }
941 
942   int32_t availWidthCSS = 0;
943   int32_t availHeightCSS = 0;
944   int32_t contentWidthCSS = 0;
945   int32_t contentHeightCSS = 0;
946   int32_t windowWidthCSS = 0;
947   int32_t windowHeightCSS = 0;
948   double devicePerCSSPixels = 1.0;
949 
950   GetUnscaledDevicePixelsPerCSSPixel(&devicePerCSSPixels);
951 
952   GetAvailScreenSize(&availWidthCSS, &availHeightCSS);
953 
954   // To get correct chrome size, we have to resize the window to a proper
955   // size first. So, here, we size it to its available size.
956   SetSpecifiedSize(availWidthCSS, availHeightCSS);
957 
958   // Get the current window size for calculating chrome UI size.
959   GetSize(&windowWidthCSS, &windowHeightCSS);  // device pixels
960   windowWidthCSS = NSToIntRound(windowWidthCSS / devicePerCSSPixels);
961   windowHeightCSS = NSToIntRound(windowHeightCSS / devicePerCSSPixels);
962 
963   // Get the content size for calculating chrome UI size.
964   GetPrimaryContentSize(&contentWidthCSS, &contentHeightCSS);
965 
966   // Calculate the chrome UI size.
967   int32_t chromeWidth = 0, chromeHeight = 0;
968   chromeWidth = windowWidthCSS - contentWidthCSS;
969   chromeHeight = windowHeightCSS - contentHeightCSS;
970 
971   int32_t targetContentWidth = 0, targetContentHeight = 0;
972 
973   // Here, we use the available screen dimensions as the input dimensions to
974   // force the window to be rounded as the maximum available content size.
975   nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(
976       chromeWidth, chromeHeight, availWidthCSS, availHeightCSS, availWidthCSS,
977       availHeightCSS,
978       false,  // aSetOuterWidth
979       false,  // aSetOuterHeight
980       &targetContentWidth, &targetContentHeight);
981 
982   targetContentWidth = NSToIntRound(targetContentWidth * devicePerCSSPixels);
983   targetContentHeight = NSToIntRound(targetContentHeight * devicePerCSSPixels);
984 
985   SetPrimaryContentSize(targetContentWidth, targetContentHeight);
986 
987   mIgnoreXULSize = true;
988   mIgnoreXULSizeMode = true;
989 
990   return NS_OK;
991 }
992 
OnChromeLoaded()993 void nsXULWindow::OnChromeLoaded() {
994   nsresult rv = EnsureContentTreeOwner();
995 
996   if (NS_SUCCEEDED(rv)) {
997     mChromeLoaded = true;
998     ApplyChromeFlags();
999     SyncAttributesToWidget();
1000 
1001     int32_t specWidth = -1, specHeight = -1;
1002     bool gotSize = false;
1003     bool isContent = false;
1004 
1005     GetHasPrimaryContent(&isContent);
1006 
1007     // If this window has a primary content and fingerprinting resistance is
1008     // enabled, we enforce this window to rounded dimensions.
1009     if (isContent && nsContentUtils::ShouldResistFingerprinting()) {
1010       ForceRoundedDimensions();
1011     } else if (!mIgnoreXULSize) {
1012       gotSize = LoadSizeFromXUL(specWidth, specHeight);
1013     }
1014 
1015     bool positionSet = !mIgnoreXULPosition;
1016     nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow));
1017 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1018     // don't override WM placement on unix for independent, top-level windows
1019     // (however, we think the benefits of intelligent dependent window placement
1020     // trump that override.)
1021     if (!parentWindow) positionSet = false;
1022 #endif
1023     if (positionSet) {
1024       // We have to do this before sizing the window, because sizing depends
1025       // on the resolution of the screen we're on. But positioning needs to
1026       // know the size so that it can constrain to screen bounds.... as an
1027       // initial guess here, we'll use the specified size (if any).
1028       positionSet = LoadPositionFromXUL(specWidth, specHeight);
1029     }
1030 
1031     if (gotSize) {
1032       SetSpecifiedSize(specWidth, specHeight);
1033     }
1034 
1035     if (mIntrinsicallySized) {
1036       // (if LoadSizeFromXUL set the size, mIntrinsicallySized will be false)
1037       nsCOMPtr<nsIContentViewer> cv;
1038       mDocShell->GetContentViewer(getter_AddRefs(cv));
1039       if (cv) {
1040         nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
1041             do_QueryInterface(mDocShell);
1042         nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
1043         docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
1044         if (treeOwner) {
1045           // GetContentSize can fail, so initialise |width| and |height| to be
1046           // on the safe side.
1047           int32_t width = 0, height = 0;
1048           if (NS_SUCCEEDED(cv->GetContentSize(&width, &height))) {
1049             treeOwner->SizeShellTo(docShellAsItem, width, height);
1050             // Update specified size for the final LoadPositionFromXUL call.
1051             specWidth = width;
1052             specHeight = height;
1053           }
1054         }
1055       }
1056     }
1057 
1058     // Now that we have set the window's final size, we can re-do its
1059     // positioning so that it is properly constrained to the screen.
1060     if (positionSet) {
1061       LoadPositionFromXUL(specWidth, specHeight);
1062     }
1063 
1064     LoadMiscPersistentAttributesFromXUL();
1065 
1066     if (mCenterAfterLoad && !positionSet) {
1067       Center(parentWindow, parentWindow ? false : true, false);
1068     }
1069 
1070     if (mShowAfterLoad) {
1071       SetVisibility(true);
1072       // At this point the window may have been closed during Show(), so
1073       // nsXULWindow::Destroy may already have been called. Take care!
1074     }
1075   }
1076   mPersistentAttributesMask |= PAD_POSITION | PAD_SIZE | PAD_MISC;
1077 }
1078 
1079 // If aSpecWidth and/or aSpecHeight are > 0, we will use these CSS px sizes
1080 // to fit to the screen when staggering windows; if they're negative,
1081 // we use the window's current size instead.
LoadPositionFromXUL(int32_t aSpecWidth,int32_t aSpecHeight)1082 bool nsXULWindow::LoadPositionFromXUL(int32_t aSpecWidth, int32_t aSpecHeight) {
1083   bool gotPosition = false;
1084 
1085   // if we're the hidden window, don't try to validate our size/position. We're
1086   // special.
1087   if (mIsHiddenWindow) return false;
1088 
1089   nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
1090   NS_ENSURE_TRUE(windowElement, false);
1091 
1092   int32_t currX = 0;
1093   int32_t currY = 0;
1094   int32_t currWidth = 0;
1095   int32_t currHeight = 0;
1096   nsresult errorCode;
1097   int32_t temp;
1098 
1099   GetPositionAndSize(&currX, &currY, &currWidth, &currHeight);
1100 
1101   // Convert to global display pixels for consistent window management across
1102   // screens with diverse resolutions
1103   double devToDesktopScale = 1.0 / mWindow->GetDesktopToDeviceScale().scale;
1104   currX = NSToIntRound(currX * devToDesktopScale);
1105   currY = NSToIntRound(currY * devToDesktopScale);
1106 
1107   // For size, use specified value if > 0, else current value
1108   double devToCSSScale = 1.0 / mWindow->GetDefaultScale().scale;
1109   int32_t cssWidth =
1110       aSpecWidth > 0 ? aSpecWidth : NSToIntRound(currWidth * devToCSSScale);
1111   int32_t cssHeight =
1112       aSpecHeight > 0 ? aSpecHeight : NSToIntRound(currHeight * devToCSSScale);
1113 
1114   // Obtain the position information from the <xul:window> element.
1115   int32_t specX = currX;
1116   int32_t specY = currY;
1117   nsAutoString posString;
1118 
1119   windowElement->GetAttribute(SCREENX_ATTRIBUTE, posString);
1120   temp = posString.ToInteger(&errorCode);
1121   if (NS_SUCCEEDED(errorCode)) {
1122     specX = temp;
1123     gotPosition = true;
1124   }
1125   windowElement->GetAttribute(SCREENY_ATTRIBUTE, posString);
1126   temp = posString.ToInteger(&errorCode);
1127   if (NS_SUCCEEDED(errorCode)) {
1128     specY = temp;
1129     gotPosition = true;
1130   }
1131 
1132   if (gotPosition) {
1133     // our position will be relative to our parent, if any
1134     nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow));
1135     if (parent) {
1136       int32_t parentX, parentY;
1137       if (NS_SUCCEEDED(parent->GetPosition(&parentX, &parentY))) {
1138         double scale;
1139         if (NS_SUCCEEDED(parent->GetDevicePixelsPerDesktopPixel(&scale))) {
1140           parentX = NSToIntRound(parentX / scale);
1141           parentY = NSToIntRound(parentY / scale);
1142         }
1143         specX += parentX;
1144         specY += parentY;
1145       }
1146     } else {
1147       StaggerPosition(specX, specY, cssWidth, cssHeight);
1148     }
1149   }
1150   mWindow->ConstrainPosition(false, &specX, &specY);
1151   if (specX != currX || specY != currY) {
1152     SetPositionDesktopPix(specX, specY);
1153   }
1154 
1155   return gotPosition;
1156 }
1157 
LoadSizeFromXUL(int32_t & aSpecWidth,int32_t & aSpecHeight)1158 bool nsXULWindow::LoadSizeFromXUL(int32_t& aSpecWidth, int32_t& aSpecHeight) {
1159   bool gotSize = false;
1160 
1161   // if we're the hidden window, don't try to validate our size/position. We're
1162   // special.
1163   if (mIsHiddenWindow) {
1164     return false;
1165   }
1166 
1167   nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
1168   NS_ENSURE_TRUE(windowElement, false);
1169 
1170   nsresult errorCode;
1171   int32_t temp;
1172 
1173   // Obtain the sizing information from the <xul:window> element.
1174   aSpecWidth = 100;
1175   aSpecHeight = 100;
1176   nsAutoString sizeString;
1177 
1178   windowElement->GetAttribute(WIDTH_ATTRIBUTE, sizeString);
1179   temp = sizeString.ToInteger(&errorCode);
1180   if (NS_SUCCEEDED(errorCode) && temp > 0) {
1181     aSpecWidth = std::max(temp, 100);
1182     gotSize = true;
1183   }
1184   windowElement->GetAttribute(HEIGHT_ATTRIBUTE, sizeString);
1185   temp = sizeString.ToInteger(&errorCode);
1186   if (NS_SUCCEEDED(errorCode) && temp > 0) {
1187     aSpecHeight = std::max(temp, 100);
1188     gotSize = true;
1189   }
1190 
1191   return gotSize;
1192 }
1193 
SetSpecifiedSize(int32_t aSpecWidth,int32_t aSpecHeight)1194 void nsXULWindow::SetSpecifiedSize(int32_t aSpecWidth, int32_t aSpecHeight) {
1195   // constrain to screen size
1196   int32_t screenWidth;
1197   int32_t screenHeight;
1198 
1199   if (NS_SUCCEEDED(GetAvailScreenSize(&screenWidth, &screenHeight))) {
1200     if (aSpecWidth > screenWidth) {
1201       aSpecWidth = screenWidth;
1202     }
1203     if (aSpecHeight > screenHeight) {
1204       aSpecHeight = screenHeight;
1205     }
1206   }
1207 
1208   NS_ASSERTION(mWindow, "we expected to have a window already");
1209 
1210   int32_t currWidth = 0;
1211   int32_t currHeight = 0;
1212   GetSize(&currWidth, &currHeight);  // returns device pixels
1213 
1214   // convert specified values to device pixels, and resize if needed
1215   double cssToDevPx = mWindow ? mWindow->GetDefaultScale().scale : 1.0;
1216   aSpecWidth = NSToIntRound(aSpecWidth * cssToDevPx);
1217   aSpecHeight = NSToIntRound(aSpecHeight * cssToDevPx);
1218   mIntrinsicallySized = false;
1219   if (aSpecWidth != currWidth || aSpecHeight != currHeight) {
1220     SetSize(aSpecWidth, aSpecHeight, false);
1221   }
1222 }
1223 
1224 /* Miscellaneous persistent attributes are attributes named in the
1225    |persist| attribute, other than size and position. Those are special
1226    because it's important to load those before one of the misc
1227    attributes (sizemode) and they require extra processing. */
LoadMiscPersistentAttributesFromXUL()1228 bool nsXULWindow::LoadMiscPersistentAttributesFromXUL() {
1229   bool gotState = false;
1230 
1231   /* There are no misc attributes of interest to the hidden window.
1232      It's especially important not to try to validate that window's
1233      size or position, because some platforms (Mac OS X) need to
1234      make it visible and offscreen. */
1235   if (mIsHiddenWindow) return false;
1236 
1237   nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
1238   NS_ENSURE_TRUE(windowElement, false);
1239 
1240   nsAutoString stateString;
1241 
1242   // sizemode
1243   windowElement->GetAttribute(MODE_ATTRIBUTE, stateString);
1244   nsSizeMode sizeMode = nsSizeMode_Normal;
1245   /* ignore request to minimize, to not confuse novices
1246   if (stateString.Equals(SIZEMODE_MINIMIZED))
1247     sizeMode = nsSizeMode_Minimized;
1248   */
1249   if (!mIgnoreXULSizeMode && (stateString.Equals(SIZEMODE_MAXIMIZED) ||
1250                               stateString.Equals(SIZEMODE_FULLSCREEN))) {
1251     /* Honor request to maximize only if the window is sizable.
1252        An unsizable, unmaximizable, yet maximized window confuses
1253        Windows OS and is something of a travesty, anyway. */
1254     if (mChromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
1255       mIntrinsicallySized = false;
1256 
1257       if (stateString.Equals(SIZEMODE_MAXIMIZED))
1258         sizeMode = nsSizeMode_Maximized;
1259       else
1260         sizeMode = nsSizeMode_Fullscreen;
1261     }
1262   }
1263 
1264   // If we are told to ignore the size mode attribute update the
1265   // document so the attribute and window are in sync.
1266   if (mIgnoreXULSizeMode) {
1267     nsAutoString sizeString;
1268     if (sizeMode == nsSizeMode_Maximized)
1269       sizeString.Assign(SIZEMODE_MAXIMIZED);
1270     else if (sizeMode == nsSizeMode_Fullscreen)
1271       sizeString.Assign(SIZEMODE_FULLSCREEN);
1272     else if (sizeMode == nsSizeMode_Normal)
1273       sizeString.Assign(SIZEMODE_NORMAL);
1274     if (!sizeString.IsEmpty()) {
1275       ErrorResult rv;
1276       windowElement->SetAttribute(MODE_ATTRIBUTE, sizeString, rv);
1277     }
1278   }
1279 
1280   if (sizeMode == nsSizeMode_Fullscreen) {
1281     nsCOMPtr<mozIDOMWindowProxy> ourWindow;
1282     GetWindowDOMWindow(getter_AddRefs(ourWindow));
1283     auto* piWindow = nsPIDOMWindowOuter::From(ourWindow);
1284     piWindow->SetFullScreen(true);
1285   } else {
1286     // For maximized windows, ignore the XUL size attributes, as setting the
1287     // size would set the window back to the normal sizemode.
1288     if (sizeMode == nsSizeMode_Maximized) {
1289       mIgnoreXULSize = true;
1290     }
1291     mWindow->SetSizeMode(sizeMode);
1292   }
1293   gotState = true;
1294 
1295   // zlevel
1296   windowElement->GetAttribute(ZLEVEL_ATTRIBUTE, stateString);
1297   if (!stateString.IsEmpty()) {
1298     nsresult errorCode;
1299     int32_t zLevel = stateString.ToInteger(&errorCode);
1300     if (NS_SUCCEEDED(errorCode) && zLevel >= lowestZ && zLevel <= highestZ)
1301       SetZLevel(zLevel);
1302   }
1303 
1304   return gotState;
1305 }
1306 
1307 /* Stagger windows of the same type so they don't appear on top of each other.
1308    This code does have a scary double loop -- it'll keep passing through
1309    the entire list of open windows until it finds a non-collision. Doesn't
1310    seem to be a problem, but it deserves watching.
1311    The aRequested{X,Y} parameters here are in desktop pixels;
1312    the aSpec{Width,Height} parameters are CSS pixel dimensions.
1313 */
StaggerPosition(int32_t & aRequestedX,int32_t & aRequestedY,int32_t aSpecWidth,int32_t aSpecHeight)1314 void nsXULWindow::StaggerPosition(int32_t& aRequestedX, int32_t& aRequestedY,
1315                                   int32_t aSpecWidth, int32_t aSpecHeight) {
1316   // These "constants" will be converted from CSS to desktop pixels
1317   // for the appropriate screen, assuming we find a screen to use...
1318   // hence they're not actually declared const here.
1319   int32_t kOffset = 22;
1320   uint32_t kSlop = 4;
1321 
1322   bool keepTrying;
1323   int bouncedX = 0,  // bounced off vertical edge of screen
1324       bouncedY = 0;  // bounced off horizontal edge
1325 
1326   // look for any other windows of this type
1327   nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1328   if (!wm) return;
1329 
1330   nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
1331   if (!windowElement) return;
1332 
1333   nsCOMPtr<nsIXULWindow> ourXULWindow(this);
1334 
1335   nsAutoString windowType;
1336   windowElement->GetAttribute(WINDOWTYPE_ATTRIBUTE, windowType);
1337 
1338   int32_t screenTop = 0,  // it's pointless to initialize these ...
1339       screenRight = 0,    // ... but to prevent oversalubrious and ...
1340       screenBottom = 0,   // ... underbright compilers from ...
1341       screenLeft = 0;     // ... issuing warnings.
1342   bool gotScreen = false;
1343 
1344   {  // fetch screen coordinates
1345     nsCOMPtr<nsIScreenManager> screenMgr(
1346         do_GetService("@mozilla.org/gfx/screenmanager;1"));
1347     if (screenMgr) {
1348       nsCOMPtr<nsIScreen> ourScreen;
1349       // the coordinates here are already display pixels
1350       screenMgr->ScreenForRect(aRequestedX, aRequestedY, aSpecWidth,
1351                                aSpecHeight, getter_AddRefs(ourScreen));
1352       if (ourScreen) {
1353         int32_t screenWidth, screenHeight;
1354         ourScreen->GetAvailRectDisplayPix(&screenLeft, &screenTop, &screenWidth,
1355                                           &screenHeight);
1356         screenBottom = screenTop + screenHeight;
1357         screenRight = screenLeft + screenWidth;
1358         // Get the screen's scaling factors and convert staggering constants
1359         // from CSS px to desktop pixel units
1360         double desktopToDeviceScale = 1.0, cssToDeviceScale = 1.0;
1361         ourScreen->GetContentsScaleFactor(&desktopToDeviceScale);
1362         ourScreen->GetDefaultCSSScaleFactor(&cssToDeviceScale);
1363         double cssToDesktopFactor = cssToDeviceScale / desktopToDeviceScale;
1364         kOffset = NSToIntRound(kOffset * cssToDesktopFactor);
1365         kSlop = NSToIntRound(kSlop * cssToDesktopFactor);
1366         // Convert dimensions from CSS to desktop pixels
1367         aSpecWidth = NSToIntRound(aSpecWidth * cssToDesktopFactor);
1368         aSpecHeight = NSToIntRound(aSpecHeight * cssToDesktopFactor);
1369         gotScreen = true;
1370       }
1371     }
1372   }
1373 
1374   // One full pass through all windows of this type, repeat until no collisions.
1375   do {
1376     keepTrying = false;
1377     nsCOMPtr<nsISimpleEnumerator> windowList;
1378     wm->GetXULWindowEnumerator(windowType.get(), getter_AddRefs(windowList));
1379 
1380     if (!windowList) break;
1381 
1382     // One full pass through all windows of this type, offset and stop on
1383     // collision.
1384     do {
1385       bool more;
1386       windowList->HasMoreElements(&more);
1387       if (!more) break;
1388 
1389       nsCOMPtr<nsISupports> supportsWindow;
1390       windowList->GetNext(getter_AddRefs(supportsWindow));
1391 
1392       nsCOMPtr<nsIXULWindow> listXULWindow(do_QueryInterface(supportsWindow));
1393       if (listXULWindow != ourXULWindow) {
1394         int32_t listX, listY;
1395         nsCOMPtr<nsIBaseWindow> listBaseWindow(
1396             do_QueryInterface(supportsWindow));
1397         listBaseWindow->GetPosition(&listX, &listY);
1398         double scale;
1399         if (NS_SUCCEEDED(
1400                 listBaseWindow->GetDevicePixelsPerDesktopPixel(&scale))) {
1401           listX = NSToIntRound(listX / scale);
1402           listY = NSToIntRound(listY / scale);
1403         }
1404 
1405         if (Abs(listX - aRequestedX) <= kSlop &&
1406             Abs(listY - aRequestedY) <= kSlop) {
1407           // collision! offset and start over
1408           if (bouncedX & 0x1)
1409             aRequestedX -= kOffset;
1410           else
1411             aRequestedX += kOffset;
1412           aRequestedY += kOffset;
1413 
1414           if (gotScreen) {
1415             // if we're moving to the right and we need to bounce...
1416             if (!(bouncedX & 0x1) &&
1417                 ((aRequestedX + aSpecWidth) > screenRight)) {
1418               aRequestedX = screenRight - aSpecWidth;
1419               ++bouncedX;
1420             }
1421 
1422             // if we're moving to the left and we need to bounce...
1423             if ((bouncedX & 0x1) && aRequestedX < screenLeft) {
1424               aRequestedX = screenLeft;
1425               ++bouncedX;
1426             }
1427 
1428             // if we hit the bottom then bounce to the top
1429             if (aRequestedY + aSpecHeight > screenBottom) {
1430               aRequestedY = screenTop;
1431               ++bouncedY;
1432             }
1433           }
1434 
1435           /* loop around again,
1436              but it's time to give up once we've covered the screen.
1437              there's a potential infinite loop with lots of windows. */
1438           keepTrying = bouncedX < 2 || bouncedY == 0;
1439           break;
1440         }
1441       }
1442     } while (1);
1443   } while (keepTrying);
1444 }
1445 
SyncAttributesToWidget()1446 void nsXULWindow::SyncAttributesToWidget() {
1447   nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
1448   if (!windowElement) return;
1449 
1450   nsAutoString attr;
1451 
1452   // "hidechrome" attribute
1453   if (windowElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidechrome,
1454                                  nsGkAtoms::_true, eCaseMatters)) {
1455     mWindow->HideWindowChrome(true);
1456   }
1457 
1458   // "chromemargin" attribute
1459   nsIntMargin margins;
1460   windowElement->GetAttribute(NS_LITERAL_STRING("chromemargin"), attr);
1461   if (nsContentUtils::ParseIntMarginValue(attr, margins)) {
1462     LayoutDeviceIntMargin tmp =
1463         LayoutDeviceIntMargin::FromUnknownMargin(margins);
1464     mWindow->SetNonClientMargins(tmp);
1465   }
1466 
1467   // "windowtype" attribute
1468   windowElement->GetAttribute(WINDOWTYPE_ATTRIBUTE, attr);
1469   if (!attr.IsEmpty()) {
1470     mWindow->SetWindowClass(attr);
1471   }
1472 
1473   // "id" attribute for icon
1474   windowElement->GetAttribute(NS_LITERAL_STRING("id"), attr);
1475   if (attr.IsEmpty()) {
1476     attr.AssignLiteral("default");
1477   }
1478   mWindow->SetIcon(attr);
1479 
1480   // "drawtitle" attribute
1481   windowElement->GetAttribute(NS_LITERAL_STRING("drawtitle"), attr);
1482   mWindow->SetDrawsTitle(attr.LowerCaseEqualsLiteral("true"));
1483 
1484   // "toggletoolbar" attribute
1485   windowElement->GetAttribute(NS_LITERAL_STRING("toggletoolbar"), attr);
1486   mWindow->SetShowsToolbarButton(attr.LowerCaseEqualsLiteral("true"));
1487 
1488   // "fullscreenbutton" attribute
1489   windowElement->GetAttribute(NS_LITERAL_STRING("fullscreenbutton"), attr);
1490   mWindow->SetShowsFullScreenButton(attr.LowerCaseEqualsLiteral("true"));
1491 
1492   // "macanimationtype" attribute
1493   windowElement->GetAttribute(NS_LITERAL_STRING("macanimationtype"), attr);
1494   if (attr.EqualsLiteral("document")) {
1495     mWindow->SetWindowAnimationType(nsIWidget::eDocumentWindowAnimation);
1496   }
1497 }
1498 
SavePersistentAttributes()1499 NS_IMETHODIMP nsXULWindow::SavePersistentAttributes() {
1500   // can happen when the persistence timer fires at an inopportune time
1501   // during window shutdown
1502   if (!mDocShell) return NS_ERROR_FAILURE;
1503 
1504   nsCOMPtr<dom::Element> docShellElement = GetWindowDOMElement();
1505   if (!docShellElement) return NS_ERROR_FAILURE;
1506 
1507   nsAutoString persistString;
1508   docShellElement->GetAttribute(PERSIST_ATTRIBUTE, persistString);
1509   if (persistString.IsEmpty()) {  // quick check which sometimes helps
1510     mPersistentAttributesDirty = 0;
1511     return NS_OK;
1512   }
1513 
1514   bool isFullscreen = false;
1515   if (nsPIDOMWindowOuter* domWindow = mDocShell->GetWindow()) {
1516     isFullscreen = domWindow->GetFullScreen();
1517   }
1518 
1519   // get our size, position and mode to persist
1520   LayoutDeviceIntRect rect;
1521   bool gotRestoredBounds = NS_SUCCEEDED(mWindow->GetRestoredBounds(rect));
1522 
1523   // we use CSS pixels for size, but desktop pixels for position
1524   CSSToLayoutDeviceScale sizeScale = mWindow->GetDefaultScale();
1525   DesktopToLayoutDeviceScale posScale = mWindow->GetDesktopToDeviceScale();
1526 
1527   // make our position relative to our parent, if any
1528   nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow));
1529   if (parent && gotRestoredBounds) {
1530     int32_t parentX, parentY;
1531     if (NS_SUCCEEDED(parent->GetPosition(&parentX, &parentY))) {
1532       rect.MoveBy(-parentX, -parentY);
1533     }
1534   }
1535 
1536   char sizeBuf[10];
1537   nsAutoString sizeString;
1538   nsAutoString windowElementId;
1539   RefPtr<dom::XULDocument> ownerXULDoc;
1540 
1541   // fetch docShellElement's ID and XUL owner document
1542   ownerXULDoc = docShellElement->OwnerDoc()->AsXULDocument();
1543   if (docShellElement->IsXULElement()) {
1544     docShellElement->GetId(windowElementId);
1545   }
1546 
1547   bool shouldPersist = !isFullscreen && ownerXULDoc;
1548   ErrorResult rv;
1549   // (only for size elements which are persisted)
1550   if ((mPersistentAttributesDirty & PAD_POSITION) && gotRestoredBounds) {
1551     if (persistString.Find("screenX") >= 0) {
1552       SprintfLiteral(sizeBuf, "%d", NSToIntRound(rect.X() / posScale.scale));
1553       CopyASCIItoUTF16(sizeBuf, sizeString);
1554       docShellElement->SetAttribute(SCREENX_ATTRIBUTE, sizeString, rv);
1555       if (shouldPersist) {
1556         IgnoredErrorResult err;
1557         ownerXULDoc->Persist(windowElementId, SCREENX_ATTRIBUTE, err);
1558       }
1559     }
1560     if (persistString.Find("screenY") >= 0) {
1561       SprintfLiteral(sizeBuf, "%d", NSToIntRound(rect.Y() / posScale.scale));
1562       CopyASCIItoUTF16(sizeBuf, sizeString);
1563       docShellElement->SetAttribute(SCREENY_ATTRIBUTE, sizeString, rv);
1564       if (shouldPersist) {
1565         IgnoredErrorResult err;
1566         ownerXULDoc->Persist(windowElementId, SCREENY_ATTRIBUTE, err);
1567       }
1568     }
1569   }
1570 
1571   if ((mPersistentAttributesDirty & PAD_SIZE) && gotRestoredBounds) {
1572     if (persistString.Find("width") >= 0) {
1573       SprintfLiteral(sizeBuf, "%d",
1574                      NSToIntRound(rect.Width() / sizeScale.scale));
1575       CopyASCIItoUTF16(sizeBuf, sizeString);
1576       docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString, rv);
1577       if (shouldPersist) {
1578         IgnoredErrorResult err;
1579         ownerXULDoc->Persist(windowElementId, WIDTH_ATTRIBUTE, err);
1580       }
1581     }
1582     if (persistString.Find("height") >= 0) {
1583       SprintfLiteral(sizeBuf, "%d",
1584                      NSToIntRound(rect.Height() / sizeScale.scale));
1585       CopyASCIItoUTF16(sizeBuf, sizeString);
1586       docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString, rv);
1587       if (shouldPersist) {
1588         IgnoredErrorResult err;
1589         ownerXULDoc->Persist(windowElementId, HEIGHT_ATTRIBUTE, err);
1590       }
1591     }
1592   }
1593 
1594   if (mPersistentAttributesDirty & PAD_MISC) {
1595     nsSizeMode sizeMode = mWindow->SizeMode();
1596 
1597     if (sizeMode != nsSizeMode_Minimized) {
1598       if (sizeMode == nsSizeMode_Maximized)
1599         sizeString.Assign(SIZEMODE_MAXIMIZED);
1600       else if (sizeMode == nsSizeMode_Fullscreen)
1601         sizeString.Assign(SIZEMODE_FULLSCREEN);
1602       else
1603         sizeString.Assign(SIZEMODE_NORMAL);
1604       docShellElement->SetAttribute(MODE_ATTRIBUTE, sizeString, rv);
1605       if (shouldPersist && persistString.Find("sizemode") >= 0) {
1606         IgnoredErrorResult err;
1607         ownerXULDoc->Persist(windowElementId, MODE_ATTRIBUTE, err);
1608       }
1609     }
1610     if (persistString.Find("zlevel") >= 0) {
1611       uint32_t zLevel;
1612       nsCOMPtr<nsIWindowMediator> mediator(
1613           do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1614       if (mediator) {
1615         mediator->GetZLevel(this, &zLevel);
1616         SprintfLiteral(sizeBuf, "%" PRIu32, zLevel);
1617         CopyASCIItoUTF16(sizeBuf, sizeString);
1618         docShellElement->SetAttribute(ZLEVEL_ATTRIBUTE, sizeString, rv);
1619         if (shouldPersist) {
1620           IgnoredErrorResult err;
1621           ownerXULDoc->Persist(windowElementId, ZLEVEL_ATTRIBUTE, err);
1622         }
1623       }
1624     }
1625   }
1626 
1627   mPersistentAttributesDirty = 0;
1628   return NS_OK;
1629 }
1630 
GetWindowDOMWindow(mozIDOMWindowProxy ** aDOMWindow)1631 NS_IMETHODIMP nsXULWindow::GetWindowDOMWindow(mozIDOMWindowProxy** aDOMWindow) {
1632   NS_ENSURE_STATE(mDocShell);
1633 
1634   if (!mDOMWindow) mDOMWindow = mDocShell->GetWindow();
1635   NS_ENSURE_TRUE(mDOMWindow, NS_ERROR_FAILURE);
1636 
1637   *aDOMWindow = mDOMWindow;
1638   NS_ADDREF(*aDOMWindow);
1639   return NS_OK;
1640 }
1641 
GetWindowDOMElement() const1642 dom::Element* nsXULWindow::GetWindowDOMElement() const {
1643   NS_ENSURE_TRUE(mDocShell, nullptr);
1644 
1645   nsCOMPtr<nsIContentViewer> cv;
1646   mDocShell->GetContentViewer(getter_AddRefs(cv));
1647   NS_ENSURE_TRUE(cv, nullptr);
1648 
1649   const nsIDocument* document = cv->GetDocument();
1650   NS_ENSURE_TRUE(document, nullptr);
1651 
1652   return document->GetRootElement();
1653 }
1654 
ContentShellAdded(nsIDocShellTreeItem * aContentShell,bool aPrimary)1655 nsresult nsXULWindow::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
1656                                         bool aPrimary) {
1657   // Set the default content tree owner
1658   if (aPrimary) {
1659     NS_ENSURE_SUCCESS(EnsurePrimaryContentTreeOwner(), NS_ERROR_FAILURE);
1660     aContentShell->SetTreeOwner(mPrimaryContentTreeOwner);
1661     mPrimaryContentShell = aContentShell;
1662     mPrimaryTabParent = nullptr;
1663   } else {
1664     NS_ENSURE_SUCCESS(EnsureContentTreeOwner(), NS_ERROR_FAILURE);
1665     aContentShell->SetTreeOwner(mContentTreeOwner);
1666     if (mPrimaryContentShell == aContentShell) mPrimaryContentShell = nullptr;
1667   }
1668 
1669   return NS_OK;
1670 }
1671 
ContentShellRemoved(nsIDocShellTreeItem * aContentShell)1672 nsresult nsXULWindow::ContentShellRemoved(nsIDocShellTreeItem* aContentShell) {
1673   if (mPrimaryContentShell == aContentShell) {
1674     mPrimaryContentShell = nullptr;
1675   }
1676   return NS_OK;
1677 }
1678 
1679 NS_IMETHODIMP
GetPrimaryContentSize(int32_t * aWidth,int32_t * aHeight)1680 nsXULWindow::GetPrimaryContentSize(int32_t* aWidth, int32_t* aHeight) {
1681   if (mPrimaryTabParent) {
1682     return GetPrimaryTabParentSize(aWidth, aHeight);
1683   } else if (mPrimaryContentShell) {
1684     return GetPrimaryContentShellSize(aWidth, aHeight);
1685   }
1686   return NS_ERROR_UNEXPECTED;
1687 }
1688 
GetPrimaryTabParentSize(int32_t * aWidth,int32_t * aHeight)1689 nsresult nsXULWindow::GetPrimaryTabParentSize(int32_t* aWidth,
1690                                               int32_t* aHeight) {
1691   TabParent* tabParent = TabParent::GetFrom(mPrimaryTabParent);
1692   // Need strong ref, since Client* can run script.
1693   nsCOMPtr<Element> element = tabParent->GetOwnerElement();
1694   NS_ENSURE_STATE(element);
1695 
1696   *aWidth = element->ClientWidth();
1697   *aHeight = element->ClientHeight();
1698   return NS_OK;
1699 }
1700 
GetPrimaryContentShellSize(int32_t * aWidth,int32_t * aHeight)1701 nsresult nsXULWindow::GetPrimaryContentShellSize(int32_t* aWidth,
1702                                                  int32_t* aHeight) {
1703   NS_ENSURE_STATE(mPrimaryContentShell);
1704 
1705   nsCOMPtr<nsIBaseWindow> shellWindow(do_QueryInterface(mPrimaryContentShell));
1706   NS_ENSURE_STATE(shellWindow);
1707 
1708   int32_t devicePixelWidth, devicePixelHeight;
1709   double shellScale = 1.0;
1710   // We want to return CSS pixels. First, we get device pixels
1711   // from the content area...
1712   shellWindow->GetSize(&devicePixelWidth, &devicePixelHeight);
1713   // And then get the device pixel scaling factor. Dividing device
1714   // pixels by this scaling factor gives us CSS pixels.
1715   shellWindow->GetUnscaledDevicePixelsPerCSSPixel(&shellScale);
1716   *aWidth = NSToIntRound(devicePixelWidth / shellScale);
1717   *aHeight = NSToIntRound(devicePixelHeight / shellScale);
1718   return NS_OK;
1719 }
1720 
1721 NS_IMETHODIMP
SetPrimaryContentSize(int32_t aWidth,int32_t aHeight)1722 nsXULWindow::SetPrimaryContentSize(int32_t aWidth, int32_t aHeight) {
1723   if (mPrimaryTabParent) {
1724     return SetPrimaryTabParentSize(aWidth, aHeight);
1725   } else if (mPrimaryContentShell) {
1726     return SizeShellTo(mPrimaryContentShell, aWidth, aHeight);
1727   }
1728   return NS_ERROR_UNEXPECTED;
1729 }
1730 
SetPrimaryTabParentSize(int32_t aWidth,int32_t aHeight)1731 nsresult nsXULWindow::SetPrimaryTabParentSize(int32_t aWidth, int32_t aHeight) {
1732   int32_t shellWidth, shellHeight;
1733   GetPrimaryTabParentSize(&shellWidth, &shellHeight);
1734 
1735   double scale = 1.0;
1736   GetUnscaledDevicePixelsPerCSSPixel(&scale);
1737 
1738   SizeShellToWithLimit(aWidth, aHeight, shellWidth * scale,
1739                        shellHeight * scale);
1740   return NS_OK;
1741 }
1742 
GetRootShellSize(int32_t * aWidth,int32_t * aHeight)1743 nsresult nsXULWindow::GetRootShellSize(int32_t* aWidth, int32_t* aHeight) {
1744   nsCOMPtr<nsIBaseWindow> shellAsWin = do_QueryInterface(mDocShell);
1745   NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
1746   return shellAsWin->GetSize(aWidth, aHeight);
1747 }
1748 
SetRootShellSize(int32_t aWidth,int32_t aHeight)1749 nsresult nsXULWindow::SetRootShellSize(int32_t aWidth, int32_t aHeight) {
1750   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem = do_QueryInterface(mDocShell);
1751   return SizeShellTo(docShellAsItem, aWidth, aHeight);
1752 }
1753 
SizeShellTo(nsIDocShellTreeItem * aShellItem,int32_t aCX,int32_t aCY)1754 NS_IMETHODIMP nsXULWindow::SizeShellTo(nsIDocShellTreeItem* aShellItem,
1755                                        int32_t aCX, int32_t aCY) {
1756   // XXXTAB This is wrong, we should actually reflow based on the passed in
1757   // shell.  For now we are hacking and doing delta sizing.  This is bad
1758   // because it assumes all size we add will go to the shell which probably
1759   // won't happen.
1760 
1761   nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(aShellItem));
1762   NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
1763 
1764   int32_t width = 0;
1765   int32_t height = 0;
1766   shellAsWin->GetSize(&width, &height);
1767 
1768   SizeShellToWithLimit(aCX, aCY, width, height);
1769 
1770   return NS_OK;
1771 }
1772 
ExitModalLoop(nsresult aStatus)1773 NS_IMETHODIMP nsXULWindow::ExitModalLoop(nsresult aStatus) {
1774   if (mContinueModalLoop) EnableParent(true);
1775   mContinueModalLoop = false;
1776   mModalStatus = aStatus;
1777   return NS_OK;
1778 }
1779 
1780 // top-level function to create a new window
CreateNewWindow(int32_t aChromeFlags,nsITabParent * aOpeningTab,mozIDOMWindowProxy * aOpener,uint64_t aNextTabParentId,nsIXULWindow ** _retval)1781 NS_IMETHODIMP nsXULWindow::CreateNewWindow(int32_t aChromeFlags,
1782                                            nsITabParent* aOpeningTab,
1783                                            mozIDOMWindowProxy* aOpener,
1784                                            uint64_t aNextTabParentId,
1785                                            nsIXULWindow** _retval) {
1786   NS_ENSURE_ARG_POINTER(_retval);
1787 
1788   if (aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME) {
1789     MOZ_RELEASE_ASSERT(aNextTabParentId == 0,
1790                        "Unexpected next tab parent ID, should never have a "
1791                        "non-zero nextTabParentId when creating a new chrome "
1792                        "window");
1793     return CreateNewChromeWindow(aChromeFlags, aOpeningTab, aOpener, _retval);
1794   }
1795   return CreateNewContentWindow(aChromeFlags, aOpeningTab, aOpener,
1796                                 aNextTabParentId, _retval);
1797 }
1798 
CreateNewChromeWindow(int32_t aChromeFlags,nsITabParent * aOpeningTab,mozIDOMWindowProxy * aOpener,nsIXULWindow ** _retval)1799 NS_IMETHODIMP nsXULWindow::CreateNewChromeWindow(int32_t aChromeFlags,
1800                                                  nsITabParent* aOpeningTab,
1801                                                  mozIDOMWindowProxy* aOpener,
1802                                                  nsIXULWindow** _retval) {
1803   nsCOMPtr<nsIAppShellService> appShell(
1804       do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
1805   NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
1806 
1807   // Just do a normal create of a window and return.
1808   nsCOMPtr<nsIXULWindow> newWindow;
1809   appShell->CreateTopLevelWindow(
1810       this, nullptr, aChromeFlags, nsIAppShellService::SIZE_TO_CONTENT,
1811       nsIAppShellService::SIZE_TO_CONTENT, aOpeningTab, aOpener,
1812       getter_AddRefs(newWindow));
1813 
1814   NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE);
1815 
1816   *_retval = newWindow;
1817   NS_ADDREF(*_retval);
1818 
1819   return NS_OK;
1820 }
1821 
CreateNewContentWindow(int32_t aChromeFlags,nsITabParent * aOpeningTab,mozIDOMWindowProxy * aOpener,uint64_t aNextTabParentId,nsIXULWindow ** _retval)1822 NS_IMETHODIMP nsXULWindow::CreateNewContentWindow(int32_t aChromeFlags,
1823                                                   nsITabParent* aOpeningTab,
1824                                                   mozIDOMWindowProxy* aOpener,
1825                                                   uint64_t aNextTabParentId,
1826                                                   nsIXULWindow** _retval) {
1827   nsCOMPtr<nsIAppShellService> appShell(
1828       do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
1829   NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
1830 
1831   // We need to create a new top level window and then enter a nested
1832   // loop. Eventually the new window will be told that it has loaded,
1833   // at which time we know it is safe to spin out of the nested loop
1834   // and allow the opening code to proceed.
1835 
1836   nsCOMPtr<nsIURI> uri;
1837 
1838   nsAutoCString urlStr;
1839   Preferences::GetCString("browser.chromeURL", urlStr);
1840   if (urlStr.IsEmpty()) {
1841     urlStr.AssignLiteral("chrome://navigator/content/navigator.xul");
1842   }
1843 
1844   nsCOMPtr<nsIIOService> service(do_GetService(NS_IOSERVICE_CONTRACTID));
1845   if (service) {
1846     service->NewURI(urlStr, nullptr, nullptr, getter_AddRefs(uri));
1847   }
1848   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
1849 
1850   // We need to create a chrome window to contain the content window we're about
1851   // to pass back. The subject principal needs to be system while we're creating
1852   // it to make things work right, so force a system caller. See bug 799348
1853   // comment 13 for a description of what happens when we don't.
1854   nsCOMPtr<nsIXULWindow> newWindow;
1855   {
1856     AutoNoJSAPI nojsapi;
1857     // We actually want this toplevel window which we are creating to have a
1858     // null opener, as we will be creating the content xul:browser window inside
1859     // of it, so we pass nullptr as our aOpener.
1860     appShell->CreateTopLevelWindow(this, uri, aChromeFlags, 615, 480,
1861                                    aOpeningTab, nullptr,
1862                                    getter_AddRefs(newWindow));
1863     NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE);
1864   }
1865 
1866   // Specify that we want the window to remain locked until the chrome has
1867   // loaded.
1868   nsXULWindow* xulWin =
1869       static_cast<nsXULWindow*>(static_cast<nsIXULWindow*>(newWindow));
1870 
1871   if (aNextTabParentId) {
1872     xulWin->mNextTabParentId = aNextTabParentId;
1873   }
1874 
1875   if (aOpener) {
1876     nsCOMPtr<nsIDocShell> docShell;
1877     xulWin->GetDocShell(getter_AddRefs(docShell));
1878     MOZ_ASSERT(docShell);
1879     nsCOMPtr<nsPIDOMWindowOuter> window = docShell->GetWindow();
1880     MOZ_ASSERT(window);
1881     window->SetOpenerForInitialContentBrowser(
1882         nsPIDOMWindowOuter::From(aOpener));
1883   }
1884 
1885   xulWin->LockUntilChromeLoad();
1886 
1887   {
1888     AutoNoJSAPI nojsapi;
1889     SpinEventLoopUntil([&]() { return !xulWin->IsLocked(); });
1890   }
1891 
1892   NS_ENSURE_STATE(xulWin->mPrimaryContentShell || xulWin->mPrimaryTabParent);
1893   MOZ_ASSERT_IF(xulWin->mPrimaryContentShell, aNextTabParentId == 0);
1894 
1895   *_retval = newWindow;
1896   NS_ADDREF(*_retval);
1897 
1898   return NS_OK;
1899 }
1900 
GetHasPrimaryContent(bool * aResult)1901 NS_IMETHODIMP nsXULWindow::GetHasPrimaryContent(bool* aResult) {
1902   *aResult = mPrimaryTabParent || mPrimaryContentShell;
1903   return NS_OK;
1904 }
1905 
EnableParent(bool aEnable)1906 void nsXULWindow::EnableParent(bool aEnable) {
1907   nsCOMPtr<nsIBaseWindow> parentWindow;
1908   nsCOMPtr<nsIWidget> parentWidget;
1909 
1910   parentWindow = do_QueryReferent(mParentWindow);
1911   if (parentWindow) parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
1912   if (parentWidget) parentWidget->Enable(aEnable);
1913 }
1914 
1915 // Constrain the window to its proper z-level
ConstrainToZLevel(bool aImmediate,nsWindowZ * aPlacement,nsIWidget * aReqBelow,nsIWidget ** aActualBelow)1916 bool nsXULWindow::ConstrainToZLevel(bool aImmediate, nsWindowZ* aPlacement,
1917                                     nsIWidget* aReqBelow,
1918                                     nsIWidget** aActualBelow) {
1919 #if 0
1920   /* Do we have a parent window? This means our z-order is already constrained,
1921      since we're a dependent window. Our window list isn't hierarchical,
1922      so we can't properly calculate placement for such a window.
1923      Should we just abort? */
1924   nsCOMPtr<nsIBaseWindow> parentWindow = do_QueryReferent(mParentWindow);
1925   if (parentWindow)
1926     return false;
1927 #endif
1928 
1929   nsCOMPtr<nsIWindowMediator> mediator(
1930       do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1931   if (!mediator) return false;
1932 
1933   bool altered;
1934   uint32_t position, newPosition, zLevel;
1935   nsIXULWindow* us = this;
1936 
1937   altered = false;
1938   mediator->GetZLevel(this, &zLevel);
1939 
1940   // translate from WidgetGUIEvent to nsIWindowMediator constants
1941   position = nsIWindowMediator::zLevelTop;
1942   if (*aPlacement == nsWindowZBottom || zLevel == nsIXULWindow::lowestZ)
1943     position = nsIWindowMediator::zLevelBottom;
1944   else if (*aPlacement == nsWindowZRelative)
1945     position = nsIWindowMediator::zLevelBelow;
1946 
1947   if (NS_SUCCEEDED(mediator->CalculateZPosition(
1948           us, position, aReqBelow, &newPosition, aActualBelow, &altered))) {
1949     /* If we were asked to move to the top but constrained to remain
1950        below one of our other windows, first move all windows in that
1951        window's layer and above to the top. This allows the user to
1952        click a window which can't be topmost and still bring mozilla
1953        to the foreground. */
1954     if (altered &&
1955         (position == nsIWindowMediator::zLevelTop ||
1956          (position == nsIWindowMediator::zLevelBelow && aReqBelow == 0)))
1957       PlaceWindowLayersBehind(zLevel + 1, nsIXULWindow::highestZ, 0);
1958 
1959     if (*aPlacement != nsWindowZBottom &&
1960         position == nsIWindowMediator::zLevelBottom)
1961       altered = true;
1962     if (altered || aImmediate) {
1963       if (newPosition == nsIWindowMediator::zLevelTop)
1964         *aPlacement = nsWindowZTop;
1965       else if (newPosition == nsIWindowMediator::zLevelBottom)
1966         *aPlacement = nsWindowZBottom;
1967       else
1968         *aPlacement = nsWindowZRelative;
1969 
1970       if (aImmediate) {
1971         nsCOMPtr<nsIBaseWindow> ourBase = do_QueryObject(this);
1972         if (ourBase) {
1973           nsCOMPtr<nsIWidget> ourWidget;
1974           ourBase->GetMainWidget(getter_AddRefs(ourWidget));
1975           ourWidget->PlaceBehind(*aPlacement == nsWindowZBottom
1976                                      ? eZPlacementBottom
1977                                      : eZPlacementBelow,
1978                                  *aActualBelow, false);
1979         }
1980       }
1981     }
1982 
1983     /* CalculateZPosition can tell us to be below nothing, because it tries
1984        not to change something it doesn't recognize. A request to verify
1985        being below an unrecognized window, then, is treated as a request
1986        to come to the top (below null) */
1987     nsCOMPtr<nsIXULWindow> windowAbove;
1988     if (newPosition == nsIWindowMediator::zLevelBelow && *aActualBelow) {
1989       windowAbove = (*aActualBelow)->GetWidgetListener()->GetXULWindow();
1990     }
1991 
1992     mediator->SetZPosition(us, newPosition, windowAbove);
1993   }
1994 
1995   return altered;
1996 }
1997 
1998 /* Re-z-position all windows in the layers from aLowLevel to aHighLevel,
1999    inclusive, to be behind aBehind. aBehind of null means on top.
2000    Note this method actually does nothing to our relative window positions.
2001    (And therefore there's no need to inform WindowMediator we're moving
2002    things, because we aren't.) This method is useful for, say, moving
2003    a range of layers of our own windows relative to windows belonging to
2004    external applications.
2005 */
PlaceWindowLayersBehind(uint32_t aLowLevel,uint32_t aHighLevel,nsIXULWindow * aBehind)2006 void nsXULWindow::PlaceWindowLayersBehind(uint32_t aLowLevel,
2007                                           uint32_t aHighLevel,
2008                                           nsIXULWindow* aBehind) {
2009   // step through windows in z-order from top to bottommost window
2010 
2011   nsCOMPtr<nsIWindowMediator> mediator(
2012       do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
2013   if (!mediator) return;
2014 
2015   nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
2016   mediator->GetZOrderXULWindowEnumerator(0, true,
2017                                          getter_AddRefs(windowEnumerator));
2018   if (!windowEnumerator) return;
2019 
2020   // each window will be moved behind previousHighWidget, itself
2021   // a moving target. initialize it.
2022   nsCOMPtr<nsIWidget> previousHighWidget;
2023   if (aBehind) {
2024     nsCOMPtr<nsIBaseWindow> highBase(do_QueryInterface(aBehind));
2025     if (highBase) highBase->GetMainWidget(getter_AddRefs(previousHighWidget));
2026   }
2027 
2028   // get next lower window
2029   bool more;
2030   while (NS_SUCCEEDED(windowEnumerator->HasMoreElements(&more)) && more) {
2031     uint32_t nextZ;  // z-level of nextWindow
2032     nsCOMPtr<nsISupports> nextWindow;
2033     windowEnumerator->GetNext(getter_AddRefs(nextWindow));
2034     nsCOMPtr<nsIXULWindow> nextXULWindow(do_QueryInterface(nextWindow));
2035     nextXULWindow->GetZLevel(&nextZ);
2036     if (nextZ < aLowLevel)
2037       break;  // we've processed all windows through aLowLevel
2038 
2039     // move it just below its next higher window
2040     nsCOMPtr<nsIBaseWindow> nextBase(do_QueryInterface(nextXULWindow));
2041     if (nextBase) {
2042       nsCOMPtr<nsIWidget> nextWidget;
2043       nextBase->GetMainWidget(getter_AddRefs(nextWidget));
2044       if (nextZ <= aHighLevel)
2045         nextWidget->PlaceBehind(eZPlacementBelow, previousHighWidget, false);
2046       previousHighWidget = nextWidget;
2047     }
2048   }
2049 }
2050 
SetContentScrollbarVisibility(bool aVisible)2051 void nsXULWindow::SetContentScrollbarVisibility(bool aVisible) {
2052   nsCOMPtr<nsPIDOMWindowOuter> contentWin(
2053       do_GetInterface(mPrimaryContentShell));
2054   if (!contentWin) {
2055     return;
2056   }
2057 
2058   nsContentUtils::SetScrollbarsVisibility(contentWin->GetDocShell(), aVisible);
2059 }
2060 
GetContentScrollbarVisibility()2061 bool nsXULWindow::GetContentScrollbarVisibility() {
2062   // This code already exists in dom/src/base/nsBarProp.cpp, but we
2063   // can't safely get to that from here as this function is called
2064   // while the DOM window is being set up, and we need the DOM window
2065   // to get to that code.
2066   nsCOMPtr<nsIScrollable> scroller(do_QueryInterface(mPrimaryContentShell));
2067 
2068   if (scroller) {
2069     int32_t prefValue;
2070     scroller->GetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
2071                                              &prefValue);
2072     if (prefValue == nsIScrollable::Scrollbar_Never)  // try the other way
2073       scroller->GetDefaultScrollbarPreferences(
2074           nsIScrollable::ScrollOrientation_X, &prefValue);
2075 
2076     if (prefValue == nsIScrollable::Scrollbar_Never) return false;
2077   }
2078 
2079   return true;
2080 }
2081 
2082 // during spinup, attributes that haven't been loaded yet can't be dirty
PersistentAttributesDirty(uint32_t aDirtyFlags)2083 void nsXULWindow::PersistentAttributesDirty(uint32_t aDirtyFlags) {
2084   mPersistentAttributesDirty |= aDirtyFlags & mPersistentAttributesMask;
2085 }
2086 
ApplyChromeFlags()2087 NS_IMETHODIMP nsXULWindow::ApplyChromeFlags() {
2088   nsCOMPtr<dom::Element> window = GetWindowDOMElement();
2089   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
2090 
2091   if (mChromeLoaded) {
2092     // The two calls in this block don't need to happen early because they
2093     // don't cause a global restyle on the document.  Not only that, but the
2094     // scrollbar stuff needs a content area to toggle the scrollbars on anyway.
2095     // So just don't do these until mChromeLoaded is true.
2096 
2097     // Scrollbars have their own special treatment.
2098     SetContentScrollbarVisibility(
2099         mChromeFlags & nsIWebBrowserChrome::CHROME_SCROLLBARS ? true : false);
2100   }
2101 
2102   /* the other flags are handled together. we have style rules
2103      in navigator.css that trigger visibility based on
2104      the 'chromehidden' attribute of the <window> tag. */
2105   nsAutoString newvalue;
2106 
2107   if (!(mChromeFlags & nsIWebBrowserChrome::CHROME_MENUBAR))
2108     newvalue.AppendLiteral("menubar ");
2109 
2110   if (!(mChromeFlags & nsIWebBrowserChrome::CHROME_TOOLBAR))
2111     newvalue.AppendLiteral("toolbar ");
2112 
2113   if (!(mChromeFlags & nsIWebBrowserChrome::CHROME_LOCATIONBAR))
2114     newvalue.AppendLiteral("location ");
2115 
2116   if (!(mChromeFlags & nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR))
2117     newvalue.AppendLiteral("directories ");
2118 
2119   if (!(mChromeFlags & nsIWebBrowserChrome::CHROME_STATUSBAR))
2120     newvalue.AppendLiteral("status ");
2121 
2122   if (!(mChromeFlags & nsIWebBrowserChrome::CHROME_EXTRA))
2123     newvalue.AppendLiteral("extrachrome ");
2124 
2125   // Note that if we're not actually changing the value this will be a no-op,
2126   // so no need to compare to the old value.
2127   ErrorResult rv;
2128   window->SetAttribute(NS_LITERAL_STRING("chromehidden"), newvalue, rv);
2129 
2130   return NS_OK;
2131 }
2132 
GetXULBrowserWindow(nsIXULBrowserWindow ** aXULBrowserWindow)2133 NS_IMETHODIMP nsXULWindow::GetXULBrowserWindow(
2134     nsIXULBrowserWindow** aXULBrowserWindow) {
2135   NS_IF_ADDREF(*aXULBrowserWindow = mXULBrowserWindow);
2136   return NS_OK;
2137 }
2138 
SetXULBrowserWindow(nsIXULBrowserWindow * aXULBrowserWindow)2139 NS_IMETHODIMP nsXULWindow::SetXULBrowserWindow(
2140     nsIXULBrowserWindow* aXULBrowserWindow) {
2141   mXULBrowserWindow = aXULBrowserWindow;
2142   return NS_OK;
2143 }
2144 
SizeShellToWithLimit(int32_t aDesiredWidth,int32_t aDesiredHeight,int32_t shellItemWidth,int32_t shellItemHeight)2145 void nsXULWindow::SizeShellToWithLimit(int32_t aDesiredWidth,
2146                                        int32_t aDesiredHeight,
2147                                        int32_t shellItemWidth,
2148                                        int32_t shellItemHeight) {
2149   int32_t widthDelta = aDesiredWidth - shellItemWidth;
2150   int32_t heightDelta = aDesiredHeight - shellItemHeight;
2151 
2152   if (widthDelta || heightDelta) {
2153     int32_t winWidth = 0;
2154     int32_t winHeight = 0;
2155 
2156     GetSize(&winWidth, &winHeight);
2157     // There's no point in trying to make the window smaller than the
2158     // desired content area size --- that's not likely to work. This whole
2159     // function assumes that the outer docshell is adding some constant
2160     // "border" chrome to the content area.
2161     winWidth = std::max(winWidth + widthDelta, aDesiredWidth);
2162     winHeight = std::max(winHeight + heightDelta, aDesiredHeight);
2163     SetSize(winWidth, winHeight, true);
2164   }
2165 }
2166 
GetTabCount(uint32_t * aResult)2167 nsresult nsXULWindow::GetTabCount(uint32_t* aResult) {
2168   if (mXULBrowserWindow) {
2169     return mXULBrowserWindow->GetTabCount(aResult);
2170   }
2171 
2172   *aResult = 0;
2173   return NS_OK;
2174 }
2175 
GetNextTabParentId(uint64_t * aNextTabParentId)2176 nsresult nsXULWindow::GetNextTabParentId(uint64_t* aNextTabParentId) {
2177   NS_ENSURE_ARG_POINTER(aNextTabParentId);
2178   *aNextTabParentId = mNextTabParentId;
2179   return NS_OK;
2180 }
2181