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