xpfe/appshell/src/nsWebShellWindow.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:7bf832e59679
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 "nsEscape.h"
23 #include "nsPIDOMWindow.h"
24 #include "nsIWebNavigation.h"
25 #include "nsIWindowWatcher.h"
26
27 #include "nsIDOMXULElement.h"
28
29 #include "nsWidgetInitData.h"
30 #include "nsWidgetsCID.h"
31 #include "nsIWidget.h"
32 #include "nsIWidgetListener.h"
33
34 #include "nsIDOMCharacterData.h"
35 #include "nsIDOMNodeList.h"
36
37 #include "nsITimer.h"
38 #include "nsXULPopupManager.h"
39
40
41 #include "nsIDOMXULDocument.h"
42
43 #include "nsFocusManager.h"
44
45 #include "nsIWebProgress.h"
46 #include "nsIWebProgressListener.h"
47
48 #include "nsIDocument.h"
49 #include "nsIDOMDocument.h"
50 #include "nsIDOMNode.h"
51 #include "nsIDOMElement.h"
52 #include "nsIDocumentLoaderFactory.h"
53 #include "nsIObserverService.h"
54 #include "prprf.h"
55
56 #include "nsIScreenManager.h"
57 #include "nsIScreen.h"
58
59 #include "nsIContent.h" // for menus
60 #include "nsIScriptSecurityManager.h"
61
62 // For calculating size
63 #include "nsIPresShell.h"
64 #include "nsPresContext.h"
65
66 #include "nsIBaseWindow.h"
67 #include "nsIDocShellTreeItem.h"
68
69 #include "nsIMarkupDocumentViewer.h"
70 #include "mozilla/Attributes.h"
71 #include "mozilla/DebugOnly.h"
72 #include "mozilla/MouseEvents.h"
73
74 #ifdef XP_MACOSX
75 #include "nsINativeMenuService.h"
76 #define USE_NATIVE_MENUS
77 #endif
78
79 using namespace mozilla;
80 using namespace mozilla::dom;
81
82 /* Define Class IDs */
83 static NS_DEFINE_CID(kWindowCID, NS_WINDOW_CID);
84
85 #define SIZE_PERSISTENCE_TIMEOUT 500 // msec
86
87 nsWebShellWindow::nsWebShellWindow(uint32_t aChromeFlags)
88 : nsXULWindow(aChromeFlags)
89 , mSPTimerLock("nsWebShellWindow.mSPTimerLock")
90 {
91 }
92
93 nsWebShellWindow::~nsWebShellWindow()
94 {
95 MutexAutoLock lock(mSPTimerLock);
96 if (mSPTimer)
97 mSPTimer->Cancel();
98 }
99
100 NS_IMPL_ADDREF_INHERITED(nsWebShellWindow, nsXULWindow)
101 NS_IMPL_RELEASE_INHERITED(nsWebShellWindow, nsXULWindow)
102
103 NS_INTERFACE_MAP_BEGIN(nsWebShellWindow)
104 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
105 NS_INTERFACE_MAP_END_INHERITING(nsXULWindow)
106
107 nsresult nsWebShellWindow::Initialize(nsIXULWindow* aParent,
108 nsIXULWindow* aOpener,
109 nsIURI* aUrl,
110 int32_t aInitialWidth,
111 int32_t aInitialHeight,
112 bool aIsHiddenWindow,
113 nsWidgetInitData& widgetInitData)
114 {
115 nsresult rv;
116 nsCOMPtr<nsIWidget> parentWidget;
117
118 mIsHiddenWindow = aIsHiddenWindow;
119
120 int32_t initialX = 0, initialY = 0;
121 nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(aOpener));
122 if (base) {
123 rv = base->GetPositionAndSize(&mOpenerScreenRect.x,
124 &mOpenerScreenRect.y,
125 &mOpenerScreenRect.width,
126 &mOpenerScreenRect.height);
127 if (NS_FAILED(rv)) {
128 mOpenerScreenRect.SetEmpty();
129 } else {
130 double scale;
131 if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) {
132 mOpenerScreenRect.x = NSToIntRound(mOpenerScreenRect.x / scale);
133 mOpenerScreenRect.y = NSToIntRound(mOpenerScreenRect.y / scale);
134 mOpenerScreenRect.width = NSToIntRound(mOpenerScreenRect.width / scale);
135 mOpenerScreenRect.height = NSToIntRound(mOpenerScreenRect.height / scale);
136 }
137 initialX = mOpenerScreenRect.x;
138 initialY = mOpenerScreenRect.y;
139 ConstrainToOpenerScreen(&initialX, &initialY);
140 }
141 }
142
143 // XXX: need to get the default window size from prefs...
144 // Doesn't come from prefs... will come from CSS/XUL/RDF
145 nsIntRect r(initialX, initialY, aInitialWidth, aInitialHeight);
146
147 // Create top level window
148 mWindow = do_CreateInstance(kWindowCID, &rv);
149 if (NS_OK != rv) {
150 return rv;
151 }
152
153 /* This next bit is troublesome. We carry two different versions of a pointer
154 to our parent window. One is the parent window's widget, which is passed
155 to our own widget. The other is a weak reference we keep here to our
156 parent WebShellWindow. The former is useful to the widget, and we can't
157 trust its treatment of the parent reference because they're platform-
158 specific. The latter is useful to this class.
159 A better implementation would be one in which the parent keeps strong
160 references to its children and closes them before it allows itself
161 to be closed. This would mimic the behaviour of OSes that support
162 top-level child windows in OSes that do not. Later.
163 */
164 nsCOMPtr<nsIBaseWindow> parentAsWin(do_QueryInterface(aParent));
165 if (parentAsWin) {
166 parentAsWin->GetMainWidget(getter_AddRefs(parentWidget));
167 mParentWindow = do_GetWeakReference(aParent);
168 }
169
170 mWindow->SetWidgetListener(this);
171 mWindow->Create((nsIWidget *)parentWidget, // Parent nsIWidget
172 nullptr, // Native parent widget
173 r, // Widget dimensions
174 nullptr, // Device context
175 &widgetInitData); // Widget initialization data
176 mWindow->GetClientBounds(r);
177 // Match the default background color of content. Important on windows
178 // since we no longer use content child widgets.
179 mWindow->SetBackgroundColor(NS_RGB(255,255,255));
180
181 // Create web shell
182 mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
183 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
184
185 // Make sure to set the item type on the docshell _before_ calling
186 // Create() so it knows what type it is.
187 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
188 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
189 NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE);
190
191 docShellAsItem->SetTreeOwner(mChromeTreeOwner);
192 docShellAsItem->SetItemType(nsIDocShellTreeItem::typeChrome);
193
194 r.x = r.y = 0;
195 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
196 NS_ENSURE_SUCCESS(docShellAsWin->InitWindow(nullptr, mWindow,
197 r.x, r.y, r.width, r.height), NS_ERROR_FAILURE);
198 NS_ENSURE_SUCCESS(docShellAsWin->Create(), NS_ERROR_FAILURE);
199
200 // Attach a WebProgress listener.during initialization...
201 nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv));
202 if (webProgress) {
203 webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_NETWORK);
204 }
205
206 // Eagerly create an about:blank content viewer with the right principal here,
207 // rather than letting it happening in the upcoming call to
208 // SetInitialPrincipalToSubject. This avoids creating the about:blank document
209 // and then blowing it away with a second one, which can cause problems for the
210 // top-level chrome window case. See bug 789773.
211 nsCOMPtr<nsIScriptSecurityManager> ssm =
212 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
213 if (ssm) { // Sometimes this happens really early See bug 793370.
214 nsCOMPtr<nsIPrincipal> principal;
215 ssm->GetSubjectPrincipal(getter_AddRefs(principal));
216 if (!principal) {
217 ssm->GetSystemPrincipal(getter_AddRefs(principal));
218 }
219 rv = mDocShell->CreateAboutBlankContentViewer(principal);
220 NS_ENSURE_SUCCESS(rv, rv);
221 nsCOMPtr<nsIDocument> doc = do_GetInterface(mDocShell);
222 NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE);
223 doc->SetIsInitialDocument(true);
224 }
225
226 if (nullptr != aUrl) {
227 nsCString tmpStr;
228
229 rv = aUrl->GetSpec(tmpStr);
230 if (NS_FAILED(rv)) return rv;
231
232 NS_ConvertUTF8toUTF16 urlString(tmpStr);
233 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
234 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
235 rv = webNav->LoadURI(urlString.get(),
236 nsIWebNavigation::LOAD_FLAGS_NONE,
237 nullptr,
238 nullptr,
239 nullptr);
240 NS_ENSURE_SUCCESS(rv, rv);
241 }
242
243 return rv;
244 }
245
246 nsIPresShell*
247 nsWebShellWindow::GetPresShell()
248 {
249 if (!mDocShell)
250 return nullptr;
251
252 return mDocShell->GetPresShell();
253 }
254
255 bool
256 nsWebShellWindow::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y)
257 {
258 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
259 if (pm) {
260 nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell);
261 pm->AdjustPopupsOnWindowChange(window);
262 }
263
264 // Persist position, but not immediately, in case this OS is firing
265 // repeated move events as the user drags the window
266 SetPersistenceTimer(PAD_POSITION);
267 return false;
268 }
269
270 bool
271 nsWebShellWindow::WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight)
272 {
273 nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
274 if (shellAsWin) {
275 shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, false);
276 }
277 // Persist size, but not immediately, in case this OS is firing
278 // repeated size events as the user drags the sizing handle
279 if (!IsLocked())
280 SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC);
281 return true;
282 }
283
284 bool
285 nsWebShellWindow::RequestWindowClose(nsIWidget* aWidget)
286 {
287 // Maintain a reference to this as it is about to get destroyed.
288 nsCOMPtr<nsIXULWindow> xulWindow(this);
289
290 nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(mDocShell));
291 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(window);
292
293 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
294
295 if (!presShell) {
296 mozilla::DebugOnly<bool> dying;
297 MOZ_ASSERT(NS_SUCCEEDED(mDocShell->IsBeingDestroyed(&dying)) && dying,
298 "No presShell, but window is not being destroyed");
299 } else if (eventTarget) {
300 nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
301
302 nsEventStatus status = nsEventStatus_eIgnore;
303 WidgetMouseEvent event(true, NS_XUL_CLOSE, nullptr,
304 WidgetMouseEvent::eReal);
305 if (NS_SUCCEEDED(eventTarget->DispatchDOMEvent(&event, nullptr, presContext, &status)) &&
306 status == nsEventStatus_eConsumeNoDefault)
307 return false;
308 }
309
310 Destroy();
311 return false;
312 }
313
314 void
315 nsWebShellWindow::SizeModeChanged(nsSizeMode sizeMode)
316 {
317 // An alwaysRaised (or higher) window will hide any newly opened normal
318 // browser windows, so here we just drop a raised window to the normal
319 // zlevel if it's maximized. We make no provision for automatically
320 // re-raising it when restored.
321 if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) {
322 uint32_t zLevel;
323 GetZLevel(&zLevel);
324 if (zLevel > nsIXULWindow::normalZ)
325 SetZLevel(nsIXULWindow::normalZ);
326 }
327 mWindow->SetSizeMode(sizeMode);
328
329 // Persist mode, but not immediately, because in many (all?)
330 // cases this will merge with the similar call in NS_SIZE and
331 // write the attribute values only once.
332 SetPersistenceTimer(PAD_MISC);
333 nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(mDocShell);
334 if (ourWindow) {
335 // Let the application know if it's in fullscreen mode so it
336 // can update its UI.
337 if (sizeMode == nsSizeMode_Fullscreen) {
338 ourWindow->SetFullScreen(true);
339 }
340 else if (sizeMode != nsSizeMode_Minimized) {
341 ourWindow->SetFullScreen(false);
342 }
343
344 // And always fire a user-defined sizemodechange event on the window
345 ourWindow->DispatchCustomEvent("sizemodechange");
346 }
347
348 // Note the current implementation of SetSizeMode just stores
349 // the new state; it doesn't actually resize. So here we store
350 // the state and pass the event on to the OS. The day is coming
351 // when we'll handle the event here, and the return result will
352 // then need to be different.
353 }
354
355 void
356 nsWebShellWindow::OSToolbarButtonPressed()
357 {
358 // Keep a reference as setting the chrome flags can fire events.
359 nsCOMPtr<nsIXULWindow> xulWindow(this);
360
361 // rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA"
362 // due to components with multiple sidebar components
363 // (such as Mail/News, Addressbook, etc)... and frankly,
364 // Mac IE, OmniWeb, and other Mac OS X apps all work this way
365 uint32_t chromeMask = (nsIWebBrowserChrome::CHROME_TOOLBAR |
366 nsIWebBrowserChrome::CHROME_LOCATIONBAR |
367 nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
368
369 nsCOMPtr<nsIWebBrowserChrome> wbc(do_GetInterface(xulWindow));
370 if (!wbc)
371 return;
372
373 uint32_t chromeFlags, newChromeFlags = 0;
374 wbc->GetChromeFlags(&chromeFlags);
375 newChromeFlags = chromeFlags & chromeMask;
376 if (!newChromeFlags) chromeFlags |= chromeMask;
377 else chromeFlags &= (~newChromeFlags);
378 wbc->SetChromeFlags(chromeFlags);
379 }
380
381 bool
382 nsWebShellWindow::ZLevelChanged(bool aImmediate, nsWindowZ *aPlacement,
383 nsIWidget* aRequestBelow, nsIWidget** aActualBelow)
384 {
385 if (aActualBelow)
386 *aActualBelow = nullptr;
387
388 return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow);
389 }
390
391 void
392 nsWebShellWindow::WindowActivated()
393 {
394 nsCOMPtr<nsIXULWindow> xulWindow(this);
395
396 // focusing the window could cause it to close, so keep a reference to it
397 nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mDocShell);
398 nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
399 if (fm && window)
400 fm->WindowRaised(window);
401
402 if (mChromeLoaded) {
403 PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC);
404 SavePersistentAttributes();
405 }
406 }
407
408 void
409 nsWebShellWindow::WindowDeactivated()
410 {
411 nsCOMPtr<nsIXULWindow> xulWindow(this);
412
413 nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell);
414 nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
415 if (fm && window)
416 fm->WindowLowered(window);
417 }
418
419 #ifdef USE_NATIVE_MENUS
420 static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow)
421 {
422 // Find the menubar tag (if there is more than one, we ignore all but
423 // the first).
424 nsCOMPtr<nsIDOMNodeList> menubarElements;
425 aDOMDoc->GetElementsByTagNameNS(NS_LITERAL_STRING("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"),
426 NS_LITERAL_STRING("menubar"),
427 getter_AddRefs(menubarElements));
428
429 nsCOMPtr<nsIDOMNode> menubarNode;
430 if (menubarElements)
431 menubarElements->Item(0, getter_AddRefs(menubarNode));
432 if (!menubarNode)
433 return;
434
435 nsCOMPtr<nsINativeMenuService> nms = do_GetService("@mozilla.org/widget/nativemenuservice;1");
436 nsCOMPtr<nsIContent> menubarContent(do_QueryInterface(menubarNode));
437 if (nms && menubarContent)
438 nms->CreateNativeMenuBar(aParentWindow, menubarContent);
439 }
440 #endif
441
442 namespace mozilla {
443
444 class WebShellWindowTimerCallback MOZ_FINAL : public nsITimerCallback
445 {
446 public:
447 WebShellWindowTimerCallback(nsWebShellWindow* aWindow)
448 : mWindow(aWindow)
449 {}
450
451 NS_DECL_THREADSAFE_ISUPPORTS
452
453 NS_IMETHOD Notify(nsITimer* aTimer)
454 {
455 // Although this object participates in a refcount cycle (this -> mWindow
456 // -> mSPTimer -> this), mSPTimer is a one-shot timer and releases this
457 // after it fires. So we don't need to release mWindow here.
458
459 mWindow->FirePersistenceTimer();
460 return NS_OK;
461 }
462
463 private:
464 nsRefPtr<nsWebShellWindow> mWindow;
465 };
466
467 NS_IMPL_ISUPPORTS(WebShellWindowTimerCallback, nsITimerCallback)
468
469 } // namespace mozilla
470
471 void
472 nsWebShellWindow::SetPersistenceTimer(uint32_t aDirtyFlags)
473 {
474 MutexAutoLock lock(mSPTimerLock);
475 if (!mSPTimer) {
476 mSPTimer = do_CreateInstance("@mozilla.org/timer;1");
477 if (!mSPTimer) {
478 NS_WARNING("Couldn't create @mozilla.org/timer;1 instance?");
479 return;
480 }
481 }
482
483 nsRefPtr<WebShellWindowTimerCallback> callback =
484 new WebShellWindowTimerCallback(this);
485 mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT,
486 nsITimer::TYPE_ONE_SHOT);
487
488 PersistentAttributesDirty(aDirtyFlags);
489 }
490
491 void
492 nsWebShellWindow::FirePersistenceTimer()
493 {
494 MutexAutoLock lock(mSPTimerLock);
495 SavePersistentAttributes();
496 }
497
498
499 //----------------------------------------
500 // nsIWebProgessListener implementation
501 //----------------------------------------
502 NS_IMETHODIMP
503 nsWebShellWindow::OnProgressChange(nsIWebProgress *aProgress,
504 nsIRequest *aRequest,
505 int32_t aCurSelfProgress,
506 int32_t aMaxSelfProgress,
507 int32_t aCurTotalProgress,
508 int32_t aMaxTotalProgress)
509 {
510 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
511 return NS_OK;
512 }
513
514 NS_IMETHODIMP
515 nsWebShellWindow::OnStateChange(nsIWebProgress *aProgress,
516 nsIRequest *aRequest,
517 uint32_t aStateFlags,
518 nsresult aStatus)
519 {
520 // If the notification is not about a document finishing, then just
521 // ignore it...
522 if (!(aStateFlags & nsIWebProgressListener::STATE_STOP) ||
523 !(aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)) {
524 return NS_OK;
525 }
526
527 if (mChromeLoaded)
528 return NS_OK;
529
530 // If this document notification is for a frame then ignore it...
531 nsCOMPtr<nsIDOMWindow> eventWin;
532 aProgress->GetDOMWindow(getter_AddRefs(eventWin));
533 nsCOMPtr<nsPIDOMWindow> eventPWin(do_QueryInterface(eventWin));
534 if (eventPWin) {
535 nsPIDOMWindow *rootPWin = eventPWin->GetPrivateRoot();
536 if (eventPWin != rootPWin)
537 return NS_OK;
538 }
539
540 mChromeLoaded = true;
541 mLockedUntilChromeLoad = false;
542
543 #ifdef USE_NATIVE_MENUS
544 ///////////////////////////////
545 // Find the Menubar DOM and Load the menus, hooking them up to the loaded commands
546 ///////////////////////////////
547 nsCOMPtr<nsIContentViewer> cv;
548 mDocShell->GetContentViewer(getter_AddRefs(cv));
549 if (cv) {
550 nsCOMPtr<nsIDOMDocument> menubarDOMDoc(do_QueryInterface(cv->GetDocument()));
551 if (menubarDOMDoc)
552 LoadNativeMenus(menubarDOMDoc, mWindow);
553 }
554 #endif // USE_NATIVE_MENUS
555
556 OnChromeLoaded();
557 LoadContentAreas();
558
559 return NS_OK;
560 }
561
562 NS_IMETHODIMP
563 nsWebShellWindow::OnLocationChange(nsIWebProgress *aProgress,
564 nsIRequest *aRequest,
565 nsIURI *aURI,
566 uint32_t aFlags)
567 {
568 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
569 return NS_OK;
570 }
571
572 NS_IMETHODIMP
573 nsWebShellWindow::OnStatusChange(nsIWebProgress* aWebProgress,
574 nsIRequest* aRequest,
575 nsresult aStatus,
576 const char16_t* aMessage)
577 {
578 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
579 return NS_OK;
580 }
581
582 NS_IMETHODIMP
583 nsWebShellWindow::OnSecurityChange(nsIWebProgress *aWebProgress,
584 nsIRequest *aRequest,
585 uint32_t state)
586 {
587 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
588 return NS_OK;
589 }
590
591
592 //----------------------------------------
593
594 // if the main document URL specified URLs for any content areas, start them loading
595 void nsWebShellWindow::LoadContentAreas() {
596
597 nsAutoString searchSpec;
598
599 // fetch the chrome document URL
600 nsCOMPtr<nsIContentViewer> contentViewer;
601 // yes, it's possible for the docshell to be null even this early
602 // see bug 57514.
603 if (mDocShell)
604 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
605 if (contentViewer) {
606 nsIDocument* doc = contentViewer->GetDocument();
607 if (doc) {
608 nsIURI* mainURL = doc->GetDocumentURI();
609
610 nsCOMPtr<nsIURL> url = do_QueryInterface(mainURL);
611 if (url) {
612 nsAutoCString search;
613 url->GetQuery(search);
614
615 AppendUTF8toUTF16(search, searchSpec);
616 }
617 }
618 }
619
620 // content URLs are specified in the search part of the URL
621 // as <contentareaID>=<escapedURL>[;(repeat)]
622 if (!searchSpec.IsEmpty()) {
623 int32_t begPos,
624 eqPos,
625 endPos;
626 nsString contentAreaID,
627 contentURL;
628 char *urlChar;
629 nsresult rv;
630 for (endPos = 0; endPos < (int32_t)searchSpec.Length(); ) {
631 // extract contentAreaID and URL substrings
632 begPos = endPos;
633 eqPos = searchSpec.FindChar('=', begPos);
634 if (eqPos < 0)
635 break;
636
637 endPos = searchSpec.FindChar(';', eqPos);
638 if (endPos < 0)
639 endPos = searchSpec.Length();
640 searchSpec.Mid(contentAreaID, begPos, eqPos-begPos);
641 searchSpec.Mid(contentURL, eqPos+1, endPos-eqPos-1);
642 endPos++;
643
644 // see if we have a docshell with a matching contentAreaID
645 nsCOMPtr<nsIDocShellTreeItem> content;
646 rv = GetContentShellById(contentAreaID.get(), getter_AddRefs(content));
647 if (NS_SUCCEEDED(rv) && content) {
648 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(content));
649 if (webNav) {
650 urlChar = ToNewCString(contentURL);
651 if (urlChar) {
652 nsUnescape(urlChar);
653 contentURL.AssignWithConversion(urlChar);
654 webNav->LoadURI(contentURL.get(),
655 nsIWebNavigation::LOAD_FLAGS_NONE,
656 nullptr,
657 nullptr,
658 nullptr);
659 nsMemory::Free(urlChar);
660 }
661 }
662 }
663 }
664 }
665 }
666
667 /**
668 * ExecuteCloseHandler - Run the close handler, if any.
669 * @return true iff we found a close handler to run.
670 */
671 bool nsWebShellWindow::ExecuteCloseHandler()
672 {
673 /* If the event handler closes this window -- a likely scenario --
674 things get deleted out of order without this death grip.
675 (The problem may be the death grip in nsWindow::windowProc,
676 which forces this window's widget to remain alive longer
677 than it otherwise would.) */
678 nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this);
679
680 nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(mDocShell));
681 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(window);
682
683 if (eventTarget) {
684 nsCOMPtr<nsIContentViewer> contentViewer;
685 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
686 if (contentViewer) {
687 nsRefPtr<nsPresContext> presContext;
688 contentViewer->GetPresContext(getter_AddRefs(presContext));
689
690 nsEventStatus status = nsEventStatus_eIgnore;
691 WidgetMouseEvent event(true, NS_XUL_CLOSE, nullptr,
692 WidgetMouseEvent::eReal);
693
694 nsresult rv =
695 eventTarget->DispatchDOMEvent(&event, nullptr, presContext, &status);
696 if (NS_SUCCEEDED(rv) && status == nsEventStatus_eConsumeNoDefault)
697 return true;
698 // else fall through and return false
699 }
700 }
701
702 return false;
703 } // ExecuteCloseHandler
704
705 void nsWebShellWindow::ConstrainToOpenerScreen(int32_t* aX, int32_t* aY)
706 {
707 if (mOpenerScreenRect.IsEmpty()) {
708 *aX = *aY = 0;
709 return;
710 }
711
712 int32_t left, top, width, height;
713 // Constrain initial positions to the same screen as opener
714 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
715 if (screenmgr) {
716 nsCOMPtr<nsIScreen> screen;
717 screenmgr->ScreenForRect(mOpenerScreenRect.x, mOpenerScreenRect.y,
718 mOpenerScreenRect.width, mOpenerScreenRect.height,
719 getter_AddRefs(screen));
720 if (screen) {
721 screen->GetAvailRectDisplayPix(&left, &top, &width, &height);
722 if (*aX < left || *aX > left + width) {
723 *aX = left;
724 }
725 if (*aY < top || *aY > top + height) {
726 *aY = top;
727 }
728 }
729 }
730 }
731
732 // nsIBaseWindow
733 NS_IMETHODIMP nsWebShellWindow::Destroy()
734 {
735 nsresult rv;
736 nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv));
737 if (webProgress) {
738 webProgress->RemoveProgressListener(this);
739 }
740
741 nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this);
742 {
743 MutexAutoLock lock(mSPTimerLock);
744 if (mSPTimer) {
745 mSPTimer->Cancel();
746 SavePersistentAttributes();
747 mSPTimer = nullptr;
748 }
749 }
750 return nsXULWindow::Destroy();
751 }

mercurial