Coverage Report

Created: 2018-09-25 14:53

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