Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpfe/appshell/nsWebShellWindow.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
7
#include "nsWebShellWindow.h"
8
9
#include "nsLayoutCID.h"
10
#include "nsContentCID.h"
11
#include "nsIWeakReference.h"
12
#include "nsIContentViewer.h"
13
#include "nsIComponentManager.h"
14
#include "nsIServiceManager.h"
15
#include "nsIURL.h"
16
#include "nsIIOService.h"
17
#include "nsIURL.h"
18
#include "nsNetCID.h"
19
#include "nsIStringBundle.h"
20
#include "nsReadableUtils.h"
21
22
#include "nsContentUtils.h"
23
#include "nsEscape.h"
24
#include "nsPIDOMWindow.h"
25
#include "nsIWebNavigation.h"
26
#include "nsIWindowWatcher.h"
27
28
#include "nsWidgetInitData.h"
29
#include "nsWidgetsCID.h"
30
#include "nsIWidget.h"
31
#include "nsIWidgetListener.h"
32
33
#include "nsINodeList.h"
34
35
#include "nsITimer.h"
36
#include "nsXULPopupManager.h"
37
38
#include "nsFocusManager.h"
39
40
#include "nsIWebProgress.h"
41
#include "nsIWebProgressListener.h"
42
43
#include "nsIDocument.h"
44
#include "nsIDocumentLoaderFactory.h"
45
#include "nsIObserverService.h"
46
47
#include "nsIScreenManager.h"
48
#include "nsIScreen.h"
49
50
#include "nsIContent.h" // for menus
51
#include "nsIScriptSecurityManager.h"
52
53
// For calculating size
54
#include "nsIPresShell.h"
55
#include "nsPresContext.h"
56
57
#include "nsIBaseWindow.h"
58
#include "nsIDocShellTreeItem.h"
59
60
#include "mozilla/Attributes.h"
61
#include "mozilla/DebugOnly.h"
62
#include "mozilla/EventDispatcher.h"
63
#include "mozilla/MouseEvents.h"
64
65
#include "nsPIWindowRoot.h"
66
67
#include "gfxPlatform.h"
68
69
#ifdef XP_MACOSX
70
#include "nsINativeMenuService.h"
71
#define USE_NATIVE_MENUS
72
#endif
73
74
using namespace mozilla;
75
using namespace mozilla::dom;
76
77
0
#define SIZE_PERSISTENCE_TIMEOUT 500 // msec
78
79
nsWebShellWindow::nsWebShellWindow(uint32_t aChromeFlags)
80
  : nsXULWindow(aChromeFlags)
81
  , mSPTimerLock("nsWebShellWindow.mSPTimerLock")
82
  , mWidgetListenerDelegate(this)
83
0
{
84
0
}
85
86
nsWebShellWindow::~nsWebShellWindow()
87
0
{
88
0
  MutexAutoLock lock(mSPTimerLock);
89
0
  if (mSPTimer)
90
0
    mSPTimer->Cancel();
91
0
}
92
93
NS_IMPL_ADDREF_INHERITED(nsWebShellWindow, nsXULWindow)
94
NS_IMPL_RELEASE_INHERITED(nsWebShellWindow, nsXULWindow)
95
96
0
NS_INTERFACE_MAP_BEGIN(nsWebShellWindow)
97
0
  NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
98
0
NS_INTERFACE_MAP_END_INHERITING(nsXULWindow)
99
100
nsresult nsWebShellWindow::Initialize(nsIXULWindow* aParent,
101
                                      nsIXULWindow* aOpener,
102
                                      nsIURI* aUrl,
103
                                      int32_t aInitialWidth,
104
                                      int32_t aInitialHeight,
105
                                      bool aIsHiddenWindow,
106
                                      nsITabParent *aOpeningTab,
107
                                      mozIDOMWindowProxy *aOpenerWindow,
108
                                      nsWidgetInitData& widgetInitData)
109
0
{
110
0
  nsresult rv;
111
0
  nsCOMPtr<nsIWidget> parentWidget;
112
0
113
0
  mIsHiddenWindow = aIsHiddenWindow;
114
0
115
0
  int32_t initialX = 0, initialY = 0;
116
0
  nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(aOpener));
117
0
  if (base) {
118
0
    int32_t x, y, width, height;
119
0
    rv = base->GetPositionAndSize(&x, &y, &width, &height);
120
0
    if (NS_FAILED(rv)) {
121
0
      mOpenerScreenRect.SetEmpty();
122
0
    } else {
123
0
      double scale;
124
0
      if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) {
125
0
        mOpenerScreenRect.SetRect(NSToIntRound(x / scale),
126
0
                                  NSToIntRound(y / scale),
127
0
                                  NSToIntRound(width / scale),
128
0
                                  NSToIntRound(height / scale));
129
0
      } else {
130
0
        mOpenerScreenRect.SetRect(x, y, width, height);
131
0
      }
132
0
      initialX = mOpenerScreenRect.X();
133
0
      initialY = mOpenerScreenRect.Y();
134
0
      ConstrainToOpenerScreen(&initialX, &initialY);
135
0
    }
136
0
  }
137
0
138
0
  // XXX: need to get the default window size from prefs...
139
0
  // Doesn't come from prefs... will come from CSS/XUL/RDF
140
0
  DesktopIntRect deskRect(initialX, initialY, aInitialWidth, aInitialHeight);
141
0
142
0
  // Create top level window
143
0
  if (gfxPlatform::IsHeadless()) {
144
0
    mWindow = nsIWidget::CreateHeadlessWidget();
145
0
  } else {
146
0
    mWindow = nsIWidget::CreateTopLevelWindow();
147
0
  }
148
0
  if (!mWindow) {
149
0
    return NS_ERROR_FAILURE;
150
0
  }
151
0
152
0
  /* This next bit is troublesome. We carry two different versions of a pointer
153
0
     to our parent window. One is the parent window's widget, which is passed
154
0
     to our own widget. The other is a weak reference we keep here to our
155
0
     parent WebShellWindow. The former is useful to the widget, and we can't
156
0
     trust its treatment of the parent reference because they're platform-
157
0
     specific. The latter is useful to this class.
158
0
       A better implementation would be one in which the parent keeps strong
159
0
     references to its children and closes them before it allows itself
160
0
     to be closed. This would mimic the behaviour of OSes that support
161
0
     top-level child windows in OSes that do not. Later.
162
0
  */
163
0
  nsCOMPtr<nsIBaseWindow> parentAsWin(do_QueryInterface(aParent));
164
0
  if (parentAsWin) {
165
0
    parentAsWin->GetMainWidget(getter_AddRefs(parentWidget));
166
0
    mParentWindow = do_GetWeakReference(aParent);
167
0
  }
168
0
169
0
  mWindow->SetWidgetListener(&mWidgetListenerDelegate);
170
0
  rv = mWindow->Create((nsIWidget *)parentWidget, // Parent nsIWidget
171
0
                       nullptr,                   // Native parent widget
172
0
                       deskRect,                  // Widget dimensions
173
0
                       &widgetInitData);          // Widget initialization data
174
0
  NS_ENSURE_SUCCESS(rv, rv);
175
0
176
0
  LayoutDeviceIntRect r = mWindow->GetClientBounds();
177
0
  // Match the default background color of content. Important on windows
178
0
  // since we no longer use content child widgets.
179
0
  mWindow->SetBackgroundColor(NS_RGB(255,255,255));
180
0
181
0
  // Create web shell
182
0
  mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
183
0
  NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
184
0
185
0
  mDocShell->SetOpener(aOpeningTab);
186
0
187
0
  // Make sure to set the item type on the docshell _before_ calling
188
0
  // Create() so it knows what type it is.
189
0
  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
190
0
  NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
191
0
  NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE);
192
0
193
0
  docShellAsItem->SetTreeOwner(mChromeTreeOwner);
194
0
  docShellAsItem->SetItemType(nsIDocShellTreeItem::typeChrome);
195
0
196
0
  mDocShell->AttachBrowsingContext(nullptr);
197
0
198
0
  r.MoveTo(0, 0);
199
0
  nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
200
0
  NS_ENSURE_SUCCESS(docShellAsWin->InitWindow(nullptr, mWindow,
201
0
   r.X(), r.Y(), r.Width(), r.Height()), NS_ERROR_FAILURE);
202
0
  NS_ENSURE_SUCCESS(docShellAsWin->Create(), NS_ERROR_FAILURE);
203
0
204
0
  // Attach a WebProgress listener.during initialization...
205
0
  nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv));
206
0
  if (webProgress) {
207
0
    webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_NETWORK);
208
0
  }
209
0
210
0
  if (aOpenerWindow) {
211
0
    nsPIDOMWindowOuter* window = mDocShell->GetWindow();
212
0
    MOZ_ASSERT(window);
213
0
    window->SetOpenerWindow(nsPIDOMWindowOuter::From(aOpenerWindow), true);
214
0
  }
215
0
216
0
  // Eagerly create an about:blank content viewer with the right principal here,
217
0
  // rather than letting it happening in the upcoming call to
218
0
  // SetInitialPrincipalToSubject. This avoids creating the about:blank document
219
0
  // and then blowing it away with a second one, which can cause problems for the
220
0
  // top-level chrome window case. See bug 789773.
221
0
  // Note that we don't accept expanded principals here, similar to
222
0
  // SetInitialPrincipalToSubject.
223
0
  if (nsContentUtils::IsInitialized()) { // Sometimes this happens really early  See bug 793370.
224
0
    MOZ_ASSERT(mDocShell->ItemType() == nsIDocShellTreeItem::typeChrome);
225
0
    nsCOMPtr<nsIPrincipal> principal = nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
226
0
    if (nsContentUtils::IsExpandedPrincipal(principal)) {
227
0
      principal = nullptr;
228
0
    }
229
0
    rv = mDocShell->CreateAboutBlankContentViewer(principal);
230
0
    NS_ENSURE_SUCCESS(rv, rv);
231
0
    nsCOMPtr<nsIDocument> doc = mDocShell->GetDocument();
232
0
    NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE);
233
0
    doc->SetIsInitialDocument(true);
234
0
  }
235
0
236
0
  if (nullptr != aUrl)  {
237
0
    nsCString tmpStr;
238
0
239
0
    rv = aUrl->GetSpec(tmpStr);
240
0
    if (NS_FAILED(rv)) return rv;
241
0
242
0
    NS_ConvertUTF8toUTF16 urlString(tmpStr);
243
0
    nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
244
0
    NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
245
0
    rv = webNav->LoadURI(urlString,
246
0
                         nsIWebNavigation::LOAD_FLAGS_NONE,
247
0
                         nullptr,
248
0
                         nullptr,
249
0
                         nullptr,
250
0
                         nsContentUtils::GetSystemPrincipal());
251
0
    NS_ENSURE_SUCCESS(rv, rv);
252
0
  }
253
0
254
0
  return rv;
255
0
}
256
257
nsIPresShell*
258
nsWebShellWindow::GetPresShell()
259
0
{
260
0
  if (!mDocShell)
261
0
    return nullptr;
262
0
263
0
  return mDocShell->GetPresShell();
264
0
}
265
266
bool
267
nsWebShellWindow::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y)
268
0
{
269
0
  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
270
0
  if (pm) {
271
0
    nsCOMPtr<nsPIDOMWindowOuter> window =
272
0
      mDocShell ? mDocShell->GetWindow() : nullptr;
273
0
    pm->AdjustPopupsOnWindowChange(window);
274
0
  }
275
0
276
0
  // Notify all tabs that the widget moved.
277
0
  if (mDocShell && mDocShell->GetWindow()) {
278
0
    nsCOMPtr<EventTarget> eventTarget = mDocShell->GetWindow()->GetTopWindowRoot();
279
0
    nsContentUtils::DispatchChromeEvent(mDocShell->GetDocument(),
280
0
                                        eventTarget,
281
0
                                        NS_LITERAL_STRING("MozUpdateWindowPos"),
282
0
                                        CanBubble::eNo, Cancelable::eNo, nullptr);
283
0
  }
284
0
285
0
  // Persist position, but not immediately, in case this OS is firing
286
0
  // repeated move events as the user drags the window
287
0
  SetPersistenceTimer(PAD_POSITION);
288
0
  return false;
289
0
}
290
291
bool
292
nsWebShellWindow::WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight)
293
0
{
294
0
  nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
295
0
  if (shellAsWin) {
296
0
    shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, 0);
297
0
  }
298
0
  // Persist size, but not immediately, in case this OS is firing
299
0
  // repeated size events as the user drags the sizing handle
300
0
  if (!IsLocked())
301
0
    SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC);
302
0
  return true;
303
0
}
304
305
bool
306
nsWebShellWindow::RequestWindowClose(nsIWidget* aWidget)
307
0
{
308
0
  // Maintain a reference to this as it is about to get destroyed.
309
0
  nsCOMPtr<nsIXULWindow> xulWindow(this);
310
0
311
0
  nsCOMPtr<nsPIDOMWindowOuter> window(mDocShell ? mDocShell->GetWindow() : nullptr);
312
0
  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(window);
313
0
314
0
  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
315
0
  if (!presShell) {
316
0
    mozilla::DebugOnly<bool> dying;
317
0
    MOZ_ASSERT(NS_SUCCEEDED(mDocShell->IsBeingDestroyed(&dying)) && dying,
318
0
               "No presShell, but window is not being destroyed");
319
0
  } else if (eventTarget) {
320
0
    RefPtr<nsPresContext> presContext = presShell->GetPresContext();
321
0
322
0
    nsEventStatus status = nsEventStatus_eIgnore;
323
0
    WidgetMouseEvent event(true, eClose, nullptr,
324
0
                           WidgetMouseEvent::eReal);
325
0
    if (NS_SUCCEEDED(EventDispatcher::Dispatch(eventTarget, presContext,
326
0
                                               &event, nullptr, &status)) &&
327
0
        status == nsEventStatus_eConsumeNoDefault)
328
0
      return false;
329
0
  }
330
0
331
0
  Destroy();
332
0
  return false;
333
0
}
334
335
void
336
nsWebShellWindow::SizeModeChanged(nsSizeMode sizeMode)
337
0
{
338
0
  // An alwaysRaised (or higher) window will hide any newly opened normal
339
0
  // browser windows, so here we just drop a raised window to the normal
340
0
  // zlevel if it's maximized. We make no provision for automatically
341
0
  // re-raising it when restored.
342
0
  if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) {
343
0
    uint32_t zLevel;
344
0
    GetZLevel(&zLevel);
345
0
    if (zLevel > nsIXULWindow::normalZ)
346
0
      SetZLevel(nsIXULWindow::normalZ);
347
0
  }
348
0
  mWindow->SetSizeMode(sizeMode);
349
0
350
0
  // Persist mode, but not immediately, because in many (all?)
351
0
  // cases this will merge with the similar call in NS_SIZE and
352
0
  // write the attribute values only once.
353
0
  SetPersistenceTimer(PAD_MISC);
354
0
  nsCOMPtr<nsPIDOMWindowOuter> ourWindow =
355
0
    mDocShell ? mDocShell->GetWindow() : nullptr;
356
0
  if (ourWindow) {
357
0
    // Ensure that the fullscreen state is synchronized between
358
0
    // the widget and the outer window object.
359
0
    if (sizeMode == nsSizeMode_Fullscreen) {
360
0
      ourWindow->SetFullScreen(true);
361
0
    }
362
0
    else if (sizeMode != nsSizeMode_Minimized) {
363
0
      if (ourWindow->GetFullScreen()) {
364
0
        // The first SetFullscreenInternal call below ensures that we do
365
0
        // not trigger any fullscreen transition even if the window was
366
0
        // put in fullscreen only for the Fullscreen API. The second
367
0
        // SetFullScreen call ensures that the window really exit from
368
0
        // fullscreen even if it entered fullscreen for both Fullscreen
369
0
        // Mode and Fullscreen API.
370
0
        ourWindow->SetFullscreenInternal(FullscreenReason::ForForceExitFullscreen, false);
371
0
        ourWindow->SetFullScreen(false);
372
0
      }
373
0
    }
374
0
375
0
    // And always fire a user-defined sizemodechange event on the window
376
0
    ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("sizemodechange"));
377
0
  }
378
0
379
0
  nsIPresShell* presShell;
380
0
  if ((presShell = GetPresShell())) {
381
0
    presShell->GetPresContext()->SizeModeChanged(sizeMode);
382
0
  }
383
0
384
0
  // Note the current implementation of SetSizeMode just stores
385
0
  // the new state; it doesn't actually resize. So here we store
386
0
  // the state and pass the event on to the OS. The day is coming
387
0
  // when we'll handle the event here, and the return result will
388
0
  // then need to be different.
389
0
}
390
391
void
392
nsWebShellWindow::UIResolutionChanged()
393
0
{
394
0
  nsCOMPtr<nsPIDOMWindowOuter> ourWindow =
395
0
    mDocShell ? mDocShell->GetWindow() : nullptr;
396
0
  if (ourWindow) {
397
0
    ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("resolutionchange"));
398
0
  }
399
0
}
400
401
void
402
nsWebShellWindow::FullscreenWillChange(bool aInFullscreen)
403
0
{
404
0
  if (mDocShell) {
405
0
    if (nsCOMPtr<nsPIDOMWindowOuter> ourWindow = mDocShell->GetWindow()) {
406
0
      ourWindow->FullscreenWillChange(aInFullscreen);
407
0
    }
408
0
  }
409
0
}
410
411
void
412
nsWebShellWindow::FullscreenChanged(bool aInFullscreen)
413
0
{
414
0
  if (mDocShell) {
415
0
    if (nsCOMPtr<nsPIDOMWindowOuter> ourWindow = mDocShell->GetWindow()) {
416
0
      ourWindow->FinishFullscreenChange(aInFullscreen);
417
0
    }
418
0
  }
419
0
}
420
421
void
422
nsWebShellWindow::OcclusionStateChanged(bool aIsFullyOccluded)
423
0
{
424
0
  nsCOMPtr<nsPIDOMWindowOuter> ourWindow =
425
0
    mDocShell ? mDocShell->GetWindow() : nullptr;
426
0
  if (ourWindow) {
427
0
    // And always fire a user-defined occlusionstatechange event on the window
428
0
    ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("occlusionstatechange"));
429
0
  }
430
0
}
431
432
void
433
nsWebShellWindow::OSToolbarButtonPressed()
434
0
{
435
0
  // Keep a reference as setting the chrome flags can fire events.
436
0
  nsCOMPtr<nsIXULWindow> xulWindow(this);
437
0
438
0
  // rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA"
439
0
  //      due to components with multiple sidebar components
440
0
  //      (such as Mail/News, Addressbook, etc)... and frankly,
441
0
  //      Mac IE, OmniWeb, and other Mac OS X apps all work this way
442
0
  uint32_t    chromeMask = (nsIWebBrowserChrome::CHROME_TOOLBAR |
443
0
                            nsIWebBrowserChrome::CHROME_LOCATIONBAR |
444
0
                            nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
445
0
446
0
  nsCOMPtr<nsIWebBrowserChrome> wbc(do_GetInterface(xulWindow));
447
0
  if (!wbc)
448
0
    return;
449
0
450
0
  uint32_t    chromeFlags, newChromeFlags = 0;
451
0
  wbc->GetChromeFlags(&chromeFlags);
452
0
  newChromeFlags = chromeFlags & chromeMask;
453
0
  if (!newChromeFlags)    chromeFlags |= chromeMask;
454
0
  else                    chromeFlags &= (~newChromeFlags);
455
0
  wbc->SetChromeFlags(chromeFlags);
456
0
}
457
458
bool
459
nsWebShellWindow::ZLevelChanged(bool aImmediate, nsWindowZ *aPlacement,
460
                                nsIWidget* aRequestBelow, nsIWidget** aActualBelow)
461
0
{
462
0
  if (aActualBelow)
463
0
    *aActualBelow = nullptr;
464
0
465
0
  return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow);
466
0
}
467
468
void
469
nsWebShellWindow::WindowActivated()
470
0
{
471
0
  nsCOMPtr<nsIXULWindow> xulWindow(this);
472
0
473
0
  // focusing the window could cause it to close, so keep a reference to it
474
0
  nsCOMPtr<nsPIDOMWindowOuter> window = mDocShell ? mDocShell->GetWindow() : nullptr;
475
0
  nsFocusManager* fm = nsFocusManager::GetFocusManager();
476
0
  if (fm && window)
477
0
    fm->WindowRaised(window);
478
0
479
0
  if (mChromeLoaded) {
480
0
    PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC);
481
0
    SavePersistentAttributes();
482
0
   }
483
0
}
484
485
void
486
nsWebShellWindow::WindowDeactivated()
487
0
{
488
0
  nsCOMPtr<nsIXULWindow> xulWindow(this);
489
0
490
0
  nsCOMPtr<nsPIDOMWindowOuter> window =
491
0
    mDocShell ? mDocShell->GetWindow() : nullptr;
492
0
  nsFocusManager* fm = nsFocusManager::GetFocusManager();
493
0
  if (fm && window && !fm->IsTestMode())
494
0
    fm->WindowLowered(window);
495
0
}
496
497
#ifdef USE_NATIVE_MENUS
498
static void LoadNativeMenus(nsIDocument *aDoc, nsIWidget *aParentWindow)
499
{
500
  if (gfxPlatform::IsHeadless()) {
501
    return;
502
  }
503
  nsCOMPtr<nsINativeMenuService> nms = do_GetService("@mozilla.org/widget/nativemenuservice;1");
504
  if (!nms) {
505
    return;
506
  }
507
508
  // Find the menubar tag (if there is more than one, we ignore all but
509
  // the first).
510
  nsCOMPtr<nsINodeList> menubarElements =
511
    aDoc->GetElementsByTagNameNS(NS_LITERAL_STRING("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"),
512
                                 NS_LITERAL_STRING("menubar"));
513
514
  nsCOMPtr<nsINode> menubarNode;
515
  if (menubarElements) {
516
    menubarNode = menubarElements->Item(0);
517
  }
518
519
  if (menubarNode) {
520
    nsCOMPtr<Element> menubarContent(do_QueryInterface(menubarNode));
521
    nms->CreateNativeMenuBar(aParentWindow, menubarContent);
522
  } else {
523
    nms->CreateNativeMenuBar(aParentWindow, nullptr);
524
  }
525
}
526
#endif
527
528
namespace mozilla {
529
530
class WebShellWindowTimerCallback final : public nsITimerCallback
531
                                        , public nsINamed
532
{
533
public:
534
  explicit WebShellWindowTimerCallback(nsWebShellWindow* aWindow)
535
    : mWindow(aWindow)
536
0
  {}
537
538
  NS_DECL_THREADSAFE_ISUPPORTS
539
540
  NS_IMETHOD Notify(nsITimer* aTimer) override
541
0
  {
542
0
    // Although this object participates in a refcount cycle (this -> mWindow
543
0
    // -> mSPTimer -> this), mSPTimer is a one-shot timer and releases this
544
0
    // after it fires.  So we don't need to release mWindow here.
545
0
546
0
    mWindow->FirePersistenceTimer();
547
0
    return NS_OK;
548
0
  }
549
550
  NS_IMETHOD GetName(nsACString& aName) override
551
0
  {
552
0
    aName.AssignLiteral("WebShellWindowTimerCallback");
553
0
    return NS_OK;
554
0
  }
555
556
private:
557
0
  ~WebShellWindowTimerCallback() {}
558
559
  RefPtr<nsWebShellWindow> mWindow;
560
};
561
562
NS_IMPL_ISUPPORTS(WebShellWindowTimerCallback, nsITimerCallback, nsINamed)
563
564
} // namespace mozilla
565
566
void
567
nsWebShellWindow::SetPersistenceTimer(uint32_t aDirtyFlags)
568
0
{
569
0
  MutexAutoLock lock(mSPTimerLock);
570
0
  if (!mSPTimer) {
571
0
    mSPTimer = NS_NewTimer();
572
0
    if (!mSPTimer) {
573
0
      NS_WARNING("Couldn't create @mozilla.org/timer;1 instance?");
574
0
      return;
575
0
    }
576
0
  }
577
0
578
0
  RefPtr<WebShellWindowTimerCallback> callback =
579
0
    new WebShellWindowTimerCallback(this);
580
0
  mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT,
581
0
                             nsITimer::TYPE_ONE_SHOT);
582
0
583
0
  PersistentAttributesDirty(aDirtyFlags);
584
0
}
585
586
void
587
nsWebShellWindow::FirePersistenceTimer()
588
0
{
589
0
  MutexAutoLock lock(mSPTimerLock);
590
0
  SavePersistentAttributes();
591
0
}
592
593
594
//----------------------------------------
595
// nsIWebProgessListener implementation
596
//----------------------------------------
597
NS_IMETHODIMP
598
nsWebShellWindow::OnProgressChange(nsIWebProgress *aProgress,
599
                                   nsIRequest *aRequest,
600
                                   int32_t aCurSelfProgress,
601
                                   int32_t aMaxSelfProgress,
602
                                   int32_t aCurTotalProgress,
603
                                   int32_t aMaxTotalProgress)
604
0
{
605
0
  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
606
0
  return NS_OK;
607
0
}
608
609
NS_IMETHODIMP
610
nsWebShellWindow::OnStateChange(nsIWebProgress *aProgress,
611
                                nsIRequest *aRequest,
612
                                uint32_t aStateFlags,
613
                                nsresult aStatus)
614
0
{
615
0
  // If the notification is not about a document finishing, then just
616
0
  // ignore it...
617
0
  if (!(aStateFlags & nsIWebProgressListener::STATE_STOP) ||
618
0
      !(aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)) {
619
0
    return NS_OK;
620
0
  }
621
0
622
0
  if (mChromeLoaded)
623
0
    return NS_OK;
624
0
625
0
  // If this document notification is for a frame then ignore it...
626
0
  nsCOMPtr<mozIDOMWindowProxy> eventWin;
627
0
  aProgress->GetDOMWindow(getter_AddRefs(eventWin));
628
0
  auto* eventPWin = nsPIDOMWindowOuter::From(eventWin);
629
0
  if (eventPWin) {
630
0
    nsPIDOMWindowOuter *rootPWin = eventPWin->GetPrivateRoot();
631
0
    if (eventPWin != rootPWin)
632
0
      return NS_OK;
633
0
  }
634
0
635
0
  mChromeLoaded = true;
636
0
  mLockedUntilChromeLoad = false;
637
0
638
#ifdef USE_NATIVE_MENUS
639
  ///////////////////////////////
640
  // Find the Menubar DOM  and Load the menus, hooking them up to the loaded commands
641
  ///////////////////////////////
642
  nsCOMPtr<nsIContentViewer> cv;
643
  mDocShell->GetContentViewer(getter_AddRefs(cv));
644
  if (cv) {
645
    nsCOMPtr<nsIDocument> menubarDoc = cv->GetDocument();
646
    if (menubarDoc)
647
      LoadNativeMenus(menubarDoc, mWindow);
648
  }
649
#endif // USE_NATIVE_MENUS
650
651
0
  OnChromeLoaded();
652
0
653
0
  return NS_OK;
654
0
}
655
656
NS_IMETHODIMP
657
nsWebShellWindow::OnLocationChange(nsIWebProgress *aProgress,
658
                                   nsIRequest *aRequest,
659
                                   nsIURI *aURI,
660
                                   uint32_t aFlags)
661
0
{
662
0
  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
663
0
  return NS_OK;
664
0
}
665
666
NS_IMETHODIMP
667
nsWebShellWindow::OnStatusChange(nsIWebProgress* aWebProgress,
668
                                 nsIRequest* aRequest,
669
                                 nsresult aStatus,
670
                                 const char16_t* aMessage)
671
0
{
672
0
  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
673
0
  return NS_OK;
674
0
}
675
676
NS_IMETHODIMP
677
nsWebShellWindow::OnSecurityChange(nsIWebProgress *aWebProgress,
678
                                   nsIRequest *aRequest,
679
                                   uint32_t state)
680
0
{
681
0
  MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
682
0
  return NS_OK;
683
0
}
684
685
686
/**
687
 * ExecuteCloseHandler - Run the close handler, if any.
688
 * @return true iff we found a close handler to run.
689
 */
690
bool nsWebShellWindow::ExecuteCloseHandler()
691
0
{
692
0
  /* If the event handler closes this window -- a likely scenario --
693
0
     things get deleted out of order without this death grip.
694
0
     (The problem may be the death grip in nsWindow::windowProc,
695
0
     which forces this window's widget to remain alive longer
696
0
     than it otherwise would.) */
697
0
  nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this);
698
0
699
0
  nsCOMPtr<EventTarget> eventTarget;
700
0
  if (mDocShell) {
701
0
    eventTarget = do_QueryInterface(mDocShell->GetWindow());
702
0
  }
703
0
704
0
  if (eventTarget) {
705
0
    nsCOMPtr<nsIContentViewer> contentViewer;
706
0
    mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
707
0
    if (contentViewer) {
708
0
      RefPtr<nsPresContext> presContext;
709
0
      contentViewer->GetPresContext(getter_AddRefs(presContext));
710
0
711
0
      nsEventStatus status = nsEventStatus_eIgnore;
712
0
      WidgetMouseEvent event(true, eClose, nullptr,
713
0
                             WidgetMouseEvent::eReal);
714
0
715
0
      nsresult rv = EventDispatcher::Dispatch(eventTarget, presContext,
716
0
                                              &event, nullptr, &status);
717
0
      if (NS_SUCCEEDED(rv) && status == nsEventStatus_eConsumeNoDefault)
718
0
        return true;
719
0
      // else fall through and return false
720
0
    }
721
0
  }
722
0
723
0
  return false;
724
0
} // ExecuteCloseHandler
725
726
void nsWebShellWindow::ConstrainToOpenerScreen(int32_t* aX, int32_t* aY)
727
0
{
728
0
  if (mOpenerScreenRect.IsEmpty()) {
729
0
    *aX = *aY = 0;
730
0
    return;
731
0
  }
732
0
733
0
  int32_t left, top, width, height;
734
0
  // Constrain initial positions to the same screen as opener
735
0
  nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
736
0
  if (screenmgr) {
737
0
    nsCOMPtr<nsIScreen> screen;
738
0
    screenmgr->ScreenForRect(mOpenerScreenRect.X(), mOpenerScreenRect.Y(),
739
0
                             mOpenerScreenRect.Width(), mOpenerScreenRect.Height(),
740
0
                             getter_AddRefs(screen));
741
0
    if (screen) {
742
0
      screen->GetAvailRectDisplayPix(&left, &top, &width, &height);
743
0
      if (*aX < left || *aX > left + width) {
744
0
        *aX = left;
745
0
      }
746
0
      if (*aY < top || *aY > top + height) {
747
0
        *aY = top;
748
0
      }
749
0
    }
750
0
  }
751
0
}
752
753
// nsIBaseWindow
754
NS_IMETHODIMP nsWebShellWindow::Destroy()
755
0
{
756
0
  nsresult rv;
757
0
  nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv));
758
0
  if (webProgress) {
759
0
    webProgress->RemoveProgressListener(this);
760
0
  }
761
0
762
0
  nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this);
763
0
  {
764
0
    MutexAutoLock lock(mSPTimerLock);
765
0
    if (mSPTimer) {
766
0
      mSPTimer->Cancel();
767
0
      SavePersistentAttributes();
768
0
      mSPTimer = nullptr;
769
0
    }
770
0
  }
771
0
  return nsXULWindow::Destroy();
772
0
}
773
774
nsIXULWindow*
775
nsWebShellWindow::WidgetListenerDelegate::GetXULWindow()
776
0
{
777
0
  return mWebShellWindow->GetXULWindow();
778
0
}
779
780
nsIPresShell*
781
nsWebShellWindow::WidgetListenerDelegate::GetPresShell()
782
0
{
783
0
  return mWebShellWindow->GetPresShell();
784
0
}
785
786
bool
787
nsWebShellWindow::WidgetListenerDelegate::WindowMoved(
788
  nsIWidget* aWidget, int32_t aX, int32_t aY)
789
0
{
790
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
791
0
  return holder->WindowMoved(aWidget, aX, aY);
792
0
}
793
794
bool
795
nsWebShellWindow::WidgetListenerDelegate::WindowResized(
796
  nsIWidget* aWidget, int32_t aWidth, int32_t aHeight)
797
0
{
798
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
799
0
  return holder->WindowResized(aWidget, aWidth, aHeight);
800
0
}
801
802
bool
803
nsWebShellWindow::WidgetListenerDelegate::RequestWindowClose(nsIWidget* aWidget)
804
0
{
805
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
806
0
  return holder->RequestWindowClose(aWidget);
807
0
}
808
809
void
810
nsWebShellWindow::WidgetListenerDelegate::SizeModeChanged(nsSizeMode aSizeMode)
811
0
{
812
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
813
0
  holder->SizeModeChanged(aSizeMode);
814
0
}
815
816
void
817
nsWebShellWindow::WidgetListenerDelegate::UIResolutionChanged()
818
0
{
819
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
820
0
  holder->UIResolutionChanged();
821
0
}
822
823
void
824
nsWebShellWindow::WidgetListenerDelegate::FullscreenWillChange(
825
  bool aInFullscreen)
826
0
{
827
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
828
0
  holder->FullscreenWillChange(aInFullscreen);
829
0
}
830
831
void
832
nsWebShellWindow::WidgetListenerDelegate::FullscreenChanged(bool aInFullscreen)
833
0
{
834
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
835
0
  holder->FullscreenChanged(aInFullscreen);
836
0
}
837
838
void
839
nsWebShellWindow::WidgetListenerDelegate::OcclusionStateChanged(
840
  bool aIsFullyOccluded)
841
0
{
842
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
843
0
  holder->OcclusionStateChanged(aIsFullyOccluded);
844
0
}
845
846
void
847
nsWebShellWindow::WidgetListenerDelegate::OSToolbarButtonPressed()
848
0
{
849
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
850
0
  holder->OSToolbarButtonPressed();
851
0
}
852
853
bool
854
nsWebShellWindow::WidgetListenerDelegate::ZLevelChanged(
855
  bool aImmediate, nsWindowZ *aPlacement, nsIWidget* aRequestBelow,
856
  nsIWidget** aActualBelow)
857
0
{
858
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
859
0
  return holder->ZLevelChanged(aImmediate,
860
0
                               aPlacement,
861
0
                               aRequestBelow,
862
0
                               aActualBelow);
863
0
}
864
865
void
866
nsWebShellWindow::WidgetListenerDelegate::WindowActivated()
867
0
{
868
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
869
0
  holder->WindowActivated();
870
0
}
871
872
void
873
nsWebShellWindow::WidgetListenerDelegate::WindowDeactivated()
874
0
{
875
0
  RefPtr<nsWebShellWindow> holder = mWebShellWindow;
876
0
  holder->WindowDeactivated();
877
0
}