Bug 574778 - Disable intrinsic sizing for chrome documents when enabling fullscreen...
[mozilla-central.git] / dom / base / nsGlobalWindow.cpp
blobb7369e14f57fbbeae0ce7fc5cd1ae643518876e2
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=2 et tw=78: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Travis Bogard <travis@netscape.com>
25 * Brendan Eich <brendan@mozilla.org>
26 * David Hyatt (hyatt@netscape.com)
27 * Dan Rosen <dr@netscape.com>
28 * Vidur Apparao <vidur@netscape.com>
29 * Johnny Stenback <jst@netscape.com>
30 * Mark Hammond <mhammond@skippinet.com.au>
31 * Ryan Jones <sciguyryan@gmail.com>
32 * Jeff Walden <jwalden+code@mit.edu>
34 * Alternatively, the contents of this file may be used under the terms of
35 * either of the GNU General Public License Version 2 or later (the "GPL"),
36 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
37 * in which case the provisions of the GPL or the LGPL are applicable instead
38 * of those above. If you wish to allow use of your version of this file only
39 * under the terms of either the GPL or the LGPL, and not to allow others to
40 * use your version of this file under the terms of the MPL, indicate your
41 * decision by deleting the provisions above and replace them with the notice
42 * and other provisions required by the GPL or the LGPL. If you do not delete
43 * the provisions above, a recipient may use your version of this file under
44 * the terms of any one of the MPL, the GPL or the LGPL.
46 * ***** END LICENSE BLOCK ***** */
48 #ifdef MOZ_IPC
49 #include "base/basictypes.h"
50 #endif
52 // Local Includes
53 #include "nsGlobalWindow.h"
54 #include "nsScreen.h"
55 #include "nsHistory.h"
56 #include "nsBarProps.h"
57 #include "nsDOMStorage.h"
58 #include "nsDOMOfflineResourceList.h"
59 #include "nsDOMError.h"
61 // Helper Classes
62 #include "nsXPIDLString.h"
63 #include "nsJSUtils.h"
64 #include "prmem.h"
65 #include "jsapi.h" // for JSAutoRequest
66 #include "jsdbgapi.h" // for JS_ClearWatchPointsForObject
67 #include "nsReadableUtils.h"
68 #include "nsDOMClassInfo.h"
69 #include "nsContentUtils.h"
71 // Other Classes
72 #include "nsIEventListenerManager.h"
73 #include "nsEscape.h"
74 #include "nsStyleCoord.h"
75 #include "nsMimeTypeArray.h"
76 #include "nsNetUtil.h"
77 #include "nsICachingChannel.h"
78 #include "nsPluginArray.h"
79 #include "nsIPluginHost.h"
80 #include "nsGeolocation.h"
81 #include "nsContentCID.h"
82 #include "nsLayoutStatics.h"
83 #include "nsCycleCollector.h"
84 #include "nsCCUncollectableMarker.h"
85 #include "nsDOMThreadService.h"
86 #include "nsAutoJSValHolder.h"
88 // Interfaces Needed
89 #include "nsIFrame.h"
90 #include "nsCanvasFrame.h"
91 #include "nsIWidget.h"
92 #include "nsIBaseWindow.h"
93 #include "nsAccelerometer.h"
94 #include "nsIContent.h"
95 #include "nsIContentViewerEdit.h"
96 #include "nsIDocShell.h"
97 #include "nsIDocShellLoadInfo.h"
98 #include "nsIDocShellTreeItem.h"
99 #include "nsIDocShellTreeNode.h"
100 #include "nsIEditorDocShell.h"
101 #include "nsIDocCharset.h"
102 #include "nsIDocument.h"
103 #include "nsIHTMLDocument.h"
104 #include "nsIDOMHTMLDocument.h"
105 #include "nsIDOMHTMLElement.h"
106 #include "nsIDOMCrypto.h"
107 #include "nsIDOMDocument.h"
108 #include "nsIDOM3Document.h"
109 #include "nsIDOMNSDocument.h"
110 #include "nsIDOMDocumentView.h"
111 #include "nsIDOMElement.h"
112 #include "nsIDOMDocumentEvent.h"
113 #include "nsIDOMEvent.h"
114 #include "nsIDOMHTMLAnchorElement.h"
115 #include "nsIDOMKeyEvent.h"
116 #include "nsIDOMMessageEvent.h"
117 #include "nsIDOMPopupBlockedEvent.h"
118 #include "nsIDOMPopStateEvent.h"
119 #include "nsIDOMOfflineResourceList.h"
120 #include "nsIDOMGeoGeolocation.h"
121 #include "nsPIDOMStorage.h"
122 #include "nsDOMString.h"
123 #include "nsIEmbeddingSiteWindow2.h"
124 #include "nsThreadUtils.h"
125 #include "nsIEventStateManager.h"
126 #include "nsIHttpProtocolHandler.h"
127 #include "nsIJSContextStack.h"
128 #include "nsIJSRuntimeService.h"
129 #include "nsIMarkupDocumentViewer.h"
130 #include "nsIPrefBranch.h"
131 #include "nsIPresShell.h"
132 #include "nsIPrivateDOMEvent.h"
133 #include "nsIProgrammingLanguage.h"
134 #include "nsIServiceManager.h"
135 #include "nsIScriptGlobalObjectOwner.h"
136 #include "nsIScriptSecurityManager.h"
137 #include "nsIScrollableFrame.h"
138 #include "nsIView.h"
139 #include "nsIViewManager.h"
140 #include "nsISelectionController.h"
141 #include "nsISelection.h"
142 #include "nsIPrompt.h"
143 #include "nsIPromptService.h"
144 #include "nsIWebNavigation.h"
145 #include "nsIWebBrowser.h"
146 #include "nsIWebBrowserChrome.h"
147 #include "nsIWebBrowserFind.h" // For window.find()
148 #include "nsIWebContentHandlerRegistrar.h"
149 #include "nsIWindowMediator.h" // For window.find()
150 #include "nsComputedDOMStyle.h"
151 #include "nsIEntropyCollector.h"
152 #include "nsDOMCID.h"
153 #include "nsDOMError.h"
154 #include "nsDOMWindowUtils.h"
155 #include "nsIWindowWatcher.h"
156 #include "nsPIWindowWatcher.h"
157 #include "nsIContentViewer.h"
158 #include "nsDOMClassInfo.h"
159 #include "nsIJSNativeInitializer.h"
160 #include "nsIScriptError.h"
161 #include "nsIScriptEventManager.h" // For GetInterface()
162 #include "nsIConsoleService.h"
163 #include "nsIControllers.h"
164 #include "nsIControllerContext.h"
165 #include "nsGlobalWindowCommands.h"
166 #include "nsAutoPtr.h"
167 #include "nsContentUtils.h"
168 #include "nsCSSProps.h"
169 #include "nsIURIFixup.h"
170 #include "mozilla/FunctionTimer.h"
171 #include "nsCDefaultURIFixup.h"
172 #include "nsEventDispatcher.h"
173 #include "nsIObserverService.h"
174 #include "nsIXULAppInfo.h"
175 #include "nsNetUtil.h"
176 #include "nsFocusManager.h"
177 #include "nsIJSON.h"
178 #include "nsIXULWindow.h"
179 #ifdef MOZ_XUL
180 #include "nsXULPopupManager.h"
181 #include "nsIDOMXULControlElement.h"
182 #include "nsIFrame.h"
183 #endif
185 #include "plbase64.h"
187 #ifdef NS_PRINTING
188 #include "nsIPrintSettings.h"
189 #include "nsIPrintSettingsService.h"
190 #include "nsIWebBrowserPrint.h"
191 #endif
193 #include "nsWindowRoot.h"
194 #include "nsNetCID.h"
195 #include "nsIArray.h"
196 #include "nsIScriptRuntime.h"
198 // XXX An unfortunate dependency exists here (two XUL files).
199 #include "nsIDOMXULDocument.h"
200 #include "nsIDOMXULCommandDispatcher.h"
202 #include "nsBindingManager.h"
203 #include "nsIXBLService.h"
205 // used for popup blocking, needs to be converted to something
206 // belonging to the back-end like nsIContentPolicy
207 #include "nsIPopupWindowManager.h"
209 #include "nsIDragService.h"
210 #include "mozilla/dom/Element.h"
211 #include "nsFrameLoader.h"
212 #include "nsISupportsPrimitives.h"
213 #include "nsXPCOMCID.h"
215 #include "mozilla/FunctionTimer.h"
217 #ifdef MOZ_LOGGING
218 // so we can get logging even in release builds
219 #define FORCE_PR_LOG 1
220 #endif
221 #include "prlog.h"
223 #include "mozilla/dom/indexedDB/IDBFactory.h"
225 #ifdef PR_LOGGING
226 static PRLogModuleInfo* gDOMLeakPRLog;
227 #endif
229 using namespace mozilla::dom;
231 nsIDOMStorageList *nsGlobalWindow::sGlobalStorageList = nsnull;
233 static nsIEntropyCollector *gEntropyCollector = nsnull;
234 static PRInt32 gRefCnt = 0;
235 static PRInt32 gOpenPopupSpamCount = 0;
236 static PopupControlState gPopupControlState = openAbused;
237 static PRInt32 gRunningTimeoutDepth = 0;
238 static PRPackedBool gMouseDown = PR_FALSE;
239 static PRPackedBool gDragServiceDisabled = PR_FALSE;
240 static FILE *gDumpFile = nsnull;
241 static PRUint64 gNextWindowID = 0;
243 #ifdef DEBUG
244 static PRUint32 gSerialCounter = 0;
245 #endif
247 #ifdef DEBUG_jst
248 PRInt32 gTimeoutCnt = 0;
249 #endif
251 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
252 static PRBool gDOMWindowDumpEnabled = PR_FALSE;
253 #endif
255 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
256 #define DEBUG_PAGE_CACHE
257 #endif
259 // The shortest interval/timeout we permit
260 #define DOM_MIN_TIMEOUT_VALUE 10 // 10ms
262 // The number of nested timeouts before we start clamping. HTML5 says 1, WebKit
263 // uses 5.
264 #define DOM_CLAMP_TIMEOUT_NESTING_LEVEL 5
266 // The longest interval (as PRIntervalTime) we permit, or that our
267 // timer code can handle, really. See DELAY_INTERVAL_LIMIT in
268 // nsTimerImpl.h for details.
269 #define DOM_MAX_TIMEOUT_VALUE PR_BIT(8 * sizeof(PRIntervalTime) - 1)
271 #define FORWARD_TO_OUTER(method, args, err_rval) \
272 PR_BEGIN_MACRO \
273 if (IsInnerWindow()) { \
274 nsGlobalWindow *outer = GetOuterWindowInternal(); \
275 if (!outer) { \
276 NS_WARNING("No outer window available!"); \
277 return err_rval; \
279 return outer->method args; \
281 PR_END_MACRO
283 #define FORWARD_TO_OUTER_VOID(method, args) \
284 PR_BEGIN_MACRO \
285 if (IsInnerWindow()) { \
286 nsGlobalWindow *outer = GetOuterWindowInternal(); \
287 if (!outer) { \
288 NS_WARNING("No outer window available!"); \
289 return; \
291 outer->method args; \
292 return; \
294 PR_END_MACRO
296 #define FORWARD_TO_OUTER_CHROME(method, args, err_rval) \
297 PR_BEGIN_MACRO \
298 if (IsInnerWindow()) { \
299 nsGlobalWindow *outer = GetOuterWindowInternal(); \
300 if (!outer) { \
301 NS_WARNING("No outer window available!"); \
302 return err_rval; \
304 return ((nsGlobalChromeWindow *)outer)->method args; \
306 PR_END_MACRO
308 #define FORWARD_TO_INNER_CHROME(method, args, err_rval) \
309 PR_BEGIN_MACRO \
310 if (IsOuterWindow()) { \
311 if (!mInnerWindow) { \
312 NS_WARNING("No inner window available!"); \
313 return err_rval; \
315 return ((nsGlobalChromeWindow *)mInnerWindow)->method args; \
317 PR_END_MACRO
319 #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
320 PR_BEGIN_MACRO \
321 if (IsInnerWindow()) { \
322 nsGlobalWindow *outer = GetOuterWindowInternal(); \
323 if (!outer) { \
324 NS_WARNING("No outer window available!"); \
325 return err_rval; \
327 return ((nsGlobalModalWindow *)outer)->method args; \
329 PR_END_MACRO
331 #define FORWARD_TO_INNER(method, args, err_rval) \
332 PR_BEGIN_MACRO \
333 if (IsOuterWindow()) { \
334 if (!mInnerWindow) { \
335 NS_WARNING("No inner window available!"); \
336 return err_rval; \
338 return GetCurrentInnerWindowInternal()->method args; \
340 PR_END_MACRO
342 #define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
343 PR_BEGIN_MACRO \
344 if (IsOuterWindow()) { \
345 if (!mInnerWindow) { \
346 NS_WARNING("No inner window available!"); \
347 return err_rval; \
349 return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \
351 PR_END_MACRO
353 #define FORWARD_TO_INNER_VOID(method, args) \
354 PR_BEGIN_MACRO \
355 if (IsOuterWindow()) { \
356 if (!mInnerWindow) { \
357 NS_WARNING("No inner window available!"); \
358 return; \
360 GetCurrentInnerWindowInternal()->method args; \
361 return; \
363 PR_END_MACRO
365 // Same as FORWARD_TO_INNER, but this will create a fresh inner if an
366 // inner doesn't already exists.
367 #define FORWARD_TO_INNER_CREATE(method, args, err_rval) \
368 PR_BEGIN_MACRO \
369 if (IsOuterWindow()) { \
370 if (!mInnerWindow) { \
371 if (mIsClosed) { \
372 return err_rval; \
374 nsCOMPtr<nsIDOMDocument> doc; \
375 nsresult fwdic_nr = GetDocument(getter_AddRefs(doc)); \
376 NS_ENSURE_SUCCESS(fwdic_nr, err_rval); \
377 if (!mInnerWindow) { \
378 return err_rval; \
381 return GetCurrentInnerWindowInternal()->method args; \
383 PR_END_MACRO
385 // CIDs
386 static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
388 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
390 static const char kCryptoContractID[] = NS_CRYPTO_CONTRACTID;
391 static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
393 static const char sPopStatePrefStr[] = "browser.history.allowPopState";
395 static PRBool
396 IsAboutBlank(nsIURI* aURI)
398 NS_PRECONDITION(aURI, "Must have URI");
400 // GetSpec can be expensive for some URIs, so check the scheme first.
401 PRBool isAbout = PR_FALSE;
402 if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
403 return PR_FALSE;
406 nsCAutoString str;
407 aURI->GetSpec(str);
408 return str.EqualsLiteral("about:blank");
411 class nsDummyJavaPluginOwner : public nsIPluginInstanceOwner
413 public:
414 nsDummyJavaPluginOwner(nsIDocument *aDocument)
415 : mDocument(aDocument)
419 void Destroy();
421 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
422 NS_DECL_NSIPLUGININSTANCEOWNER
424 NS_IMETHOD GetURL(const char *aURL, const char *aTarget,
425 nsIInputStream *aPostStream,
426 void *aHeadersData, PRUint32 aHeadersDataLen);
427 NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg);
428 NPError ShowNativeContextMenu(NPMenu* menu, void* event);
429 NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
430 double *destX, double *destY, NPCoordinateSpace destSpace);
431 void SendIdleEvent();
433 NS_DECL_CYCLE_COLLECTION_CLASS(nsDummyJavaPluginOwner)
435 private:
436 nsCOMPtr<nsIPluginInstance> mInstance;
437 nsCOMPtr<nsIDocument> mDocument;
440 NS_IMPL_CYCLE_COLLECTION_2(nsDummyJavaPluginOwner, mDocument, mInstance)
442 // QueryInterface implementation for nsDummyJavaPluginOwner
443 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDummyJavaPluginOwner)
444 NS_INTERFACE_MAP_ENTRY(nsISupports)
445 NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner)
446 NS_INTERFACE_MAP_END
448 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDummyJavaPluginOwner)
449 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDummyJavaPluginOwner)
452 void
453 nsDummyJavaPluginOwner::Destroy()
455 // If we have a plugin instance, stop it and destroy it now.
456 if (mInstance) {
457 mInstance->Stop();
458 mInstance->InvalidateOwner();
459 mInstance = nsnull;
462 mDocument = nsnull;
465 NS_IMETHODIMP
466 nsDummyJavaPluginOwner::SetInstance(nsIPluginInstance *aInstance)
468 mInstance = aInstance;
470 return NS_OK;
473 NS_IMETHODIMP
474 nsDummyJavaPluginOwner::GetInstance(nsIPluginInstance *&aInstance)
476 NS_IF_ADDREF(aInstance = mInstance);
478 return NS_OK;
481 NS_IMETHODIMP
482 nsDummyJavaPluginOwner::GetWindow(NPWindow *&aWindow)
484 aWindow = nsnull;
486 return NS_OK;
489 NS_IMETHODIMP
490 nsDummyJavaPluginOwner::GetMode(PRInt32 *aMode)
492 // This is wrong, but there's no better alternative.
493 *aMode = NP_EMBED;
495 return NS_ERROR_NOT_IMPLEMENTED;
498 NS_IMETHODIMP
499 nsDummyJavaPluginOwner::CreateWidget(void)
501 return NS_ERROR_NOT_IMPLEMENTED;
504 NS_IMETHODIMP
505 nsDummyJavaPluginOwner::GetURL(const char *aURL, const char *aTarget,
506 nsIInputStream *aPostStream,
507 void *aHeadersData, PRUint32 aHeadersDataLen)
509 return NS_ERROR_NOT_IMPLEMENTED;
512 NS_IMETHODIMP
513 nsDummyJavaPluginOwner::ShowStatus(const char *aStatusMsg)
515 return NS_ERROR_NOT_IMPLEMENTED;
518 NS_IMETHODIMP
519 nsDummyJavaPluginOwner::ShowStatus(const PRUnichar *aStatusMsg)
521 return NS_ERROR_NOT_IMPLEMENTED;
524 NPError
525 nsDummyJavaPluginOwner::ShowNativeContextMenu(NPMenu* menu, void* event)
527 return NPERR_GENERIC_ERROR;
530 NPBool
531 nsDummyJavaPluginOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
532 double *destX, double *destY, NPCoordinateSpace destSpace)
534 return PR_FALSE;
537 NS_IMETHODIMP
538 nsDummyJavaPluginOwner::GetDocument(nsIDocument **aDocument)
540 NS_IF_ADDREF(*aDocument = mDocument);
542 return NS_OK;
545 NS_IMETHODIMP
546 nsDummyJavaPluginOwner::InvalidateRect(NPRect *invalidRect)
548 return NS_ERROR_NOT_IMPLEMENTED;
551 NS_IMETHODIMP
552 nsDummyJavaPluginOwner::InvalidateRegion(NPRegion invalidRegion)
554 return NS_ERROR_NOT_IMPLEMENTED;
557 NS_IMETHODIMP
558 nsDummyJavaPluginOwner::ForceRedraw()
560 return NS_ERROR_NOT_IMPLEMENTED;
563 NS_IMETHODIMP
564 nsDummyJavaPluginOwner::GetNetscapeWindow(void *value)
566 return NS_ERROR_NOT_IMPLEMENTED;
569 NS_IMETHODIMP
570 nsDummyJavaPluginOwner::SetEventModel(PRInt32 eventModel)
572 return NS_ERROR_NOT_IMPLEMENTED;
575 void
576 nsDummyJavaPluginOwner::SendIdleEvent()
581 * An indirect observer object that means we don't have to implement nsIObserver
582 * on nsGlobalWindow, where any script could see it.
584 class nsGlobalWindowObserver : public nsIObserver {
585 public:
586 nsGlobalWindowObserver(nsGlobalWindow* aWindow) : mWindow(aWindow) {}
587 NS_DECL_ISUPPORTS
588 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData)
590 if (!mWindow)
591 return NS_OK;
592 return mWindow->Observe(aSubject, aTopic, aData);
594 void Forget() { mWindow = nsnull; }
595 private:
596 nsGlobalWindow* mWindow;
599 NS_IMPL_ISUPPORTS1(nsGlobalWindowObserver, nsIObserver)
601 nsTimeout::nsTimeout()
603 #ifdef DEBUG_jst
605 extern int gTimeoutCnt;
607 ++gTimeoutCnt;
609 #endif
611 memset(this, 0, sizeof(*this));
613 MOZ_COUNT_CTOR(nsTimeout);
616 nsTimeout::~nsTimeout()
618 #ifdef DEBUG_jst
620 extern int gTimeoutCnt;
622 --gTimeoutCnt;
624 #endif
626 MOZ_COUNT_DTOR(nsTimeout);
629 NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout)
630 NS_IMPL_CYCLE_COLLECTION_UNLINK_NATIVE_0(nsTimeout)
631 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsTimeout)
632 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWindow,
633 nsIScriptGlobalObject)
634 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrincipal)
635 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptHandler)
636 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
637 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
638 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
640 nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
641 : mFrameElement(nsnull), mDocShell(nsnull), mModalStateDepth(0),
642 mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(PR_FALSE),
643 mIsHandlingResizeEvent(PR_FALSE), mIsInnerWindow(aOuterWindow != nsnull),
644 mMayHavePaintEventListener(PR_FALSE),
645 mIsModalContentWindow(PR_FALSE), mIsActive(PR_FALSE),
646 mInnerWindow(nsnull), mOuterWindow(aOuterWindow) {}
648 nsPIDOMWindow::~nsPIDOMWindow() {}
650 //*****************************************************************************
651 //*** nsGlobalWindow: Object Management
652 //*****************************************************************************
654 nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
655 : nsPIDOMWindow(aOuterWindow),
656 mIsFrozen(PR_FALSE),
657 mDidInitJavaProperties(PR_FALSE),
658 mFullScreen(PR_FALSE),
659 mIsClosed(PR_FALSE),
660 mInClose(PR_FALSE),
661 mHavePendingClose(PR_FALSE),
662 mHadOriginalOpener(PR_FALSE),
663 mIsPopupSpam(PR_FALSE),
664 mBlockScriptedClosingFlag(PR_FALSE),
665 mFireOfflineStatusChangeEventOnThaw(PR_FALSE),
666 mCreatingInnerWindow(PR_FALSE),
667 mIsChrome(PR_FALSE),
668 mNeedsFocus(PR_TRUE),
669 mHasFocus(PR_FALSE),
670 #if defined(XP_MAC) || defined(XP_MACOSX)
671 mShowAccelerators(PR_FALSE),
672 mShowFocusRings(PR_FALSE),
673 #else
674 mShowAccelerators(PR_TRUE),
675 mShowFocusRings(PR_TRUE),
676 #endif
677 mShowFocusRingForContent(PR_FALSE),
678 mFocusByKeyOccurred(PR_FALSE),
679 mHasAcceleration(PR_FALSE),
680 mNotifiedIDDestroyed(PR_FALSE),
681 mTimeoutInsertionPoint(nsnull),
682 mTimeoutPublicIdCounter(1),
683 mTimeoutFiringDepth(0),
684 mJSObject(nsnull),
685 mPendingStorageEventsObsolete(nsnull),
686 mTimeoutsSuspendDepth(0),
687 mFocusMethod(0)
688 #ifdef DEBUG
689 , mSetOpenerWindowCalled(PR_FALSE)
690 #endif
691 , mCleanedUp(PR_FALSE)
692 , mCallCleanUpAfterModalDialogCloses(PR_FALSE)
693 , mWindowID(gNextWindowID++)
695 nsLayoutStatics::AddRef();
697 // Initialize the PRCList (this).
698 PR_INIT_CLIST(this);
700 // Initialize timeout storage
701 PR_INIT_CLIST(&mTimeouts);
703 if (aOuterWindow) {
704 // |this| is an inner window, add this inner window to the outer
705 // window list of inners.
706 PR_INSERT_AFTER(this, aOuterWindow);
708 mObserver = new nsGlobalWindowObserver(this);
709 if (mObserver) {
710 NS_ADDREF(mObserver);
711 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
712 if (os) {
713 // Watch for online/offline status changes so we can fire events. Use
714 // a strong reference.
715 os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
716 PR_FALSE);
718 // Watch for dom-storage-changed so we can fire storage
719 // events. Use a strong reference.
720 os->AddObserver(mObserver, "dom-storage2-changed", PR_FALSE);
721 os->AddObserver(mObserver, "dom-storage-changed", PR_FALSE);
724 } else {
725 // |this| is an outer window. Outer windows start out frozen and
726 // remain frozen until they get an inner window, so freeze this
727 // outer window here.
728 Freeze();
730 mObserver = nsnull;
733 // We could have failed the first time through trying
734 // to create the entropy collector, so we should
735 // try to get one until we succeed.
737 gRefCnt++;
739 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
740 if (gRefCnt == 1) {
741 static const char* prefName = "browser.dom.window.dump.enabled";
742 nsContentUtils::AddBoolPrefVarCache(prefName, &gDOMWindowDumpEnabled);
743 gDOMWindowDumpEnabled = nsContentUtils::GetBoolPref(prefName);
745 #endif
747 if (gDumpFile == nsnull) {
748 const nsAdoptingCString& fname =
749 nsContentUtils::GetCharPref("browser.dom.window.dump.file");
750 if (!fname.IsEmpty()) {
751 // if this fails to open, Dump() knows to just go to stdout
752 // on null.
753 gDumpFile = fopen(fname, "wb+");
754 } else {
755 gDumpFile = stdout;
759 if (!gEntropyCollector) {
760 CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
763 #ifdef DEBUG
764 printf("++DOMWINDOW == %d (%p) [serial = %d] [outer = %p]\n", gRefCnt,
765 static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
766 ++gSerialCounter, static_cast<void*>(aOuterWindow));
767 mSerial = gSerialCounter;
768 #endif
770 #ifdef PR_LOGGING
771 if (!gDOMLeakPRLog)
772 gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
774 if (gDOMLeakPRLog)
775 PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
776 ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
777 #endif
780 nsGlobalWindow::~nsGlobalWindow()
782 if (!--gRefCnt) {
783 NS_IF_RELEASE(gEntropyCollector);
785 #ifdef DEBUG
786 nsCAutoString url;
787 if (mLastOpenedURI) {
788 mLastOpenedURI->GetSpec(url);
791 printf("--DOMWINDOW == %d (%p) [serial = %d] [outer = %p] [url = %s]\n",
792 gRefCnt, static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
793 mSerial, static_cast<void*>(mOuterWindow), url.get());
794 #endif
796 #ifdef PR_LOGGING
797 if (gDOMLeakPRLog)
798 PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
799 ("DOMWINDOW %p destroyed", this));
800 #endif
802 if (mObserver) {
803 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
804 if (os) {
805 os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
806 os->RemoveObserver(mObserver, "dom-storage2-changed");
807 os->RemoveObserver(mObserver, "dom-storage-changed");
810 // Drop its reference to this dying window, in case for some bogus reason
811 // the object stays around.
812 mObserver->Forget();
813 NS_RELEASE(mObserver);
816 if (IsOuterWindow()) {
817 // An outer window is destroyed with inner windows still possibly
818 // alive, iterate through the inner windows and null out their
819 // back pointer to this outer, and pull them out of the list of
820 // inner windows.
822 nsGlobalWindow *w;
823 while ((w = (nsGlobalWindow *)PR_LIST_HEAD(this)) != this) {
824 NS_ASSERTION(w->mOuterWindow == this, "Uh, bad outer window pointer?");
826 w->mOuterWindow = nsnull;
828 PR_REMOVE_AND_INIT_LINK(w);
830 } else {
831 if (mListenerManager) {
832 mListenerManager->Disconnect();
833 mListenerManager = nsnull;
836 // An inner window is destroyed, pull it out of the outer window's
837 // list if inner windows.
839 PR_REMOVE_LINK(this);
841 // If our outer window's inner window is this window, null out the
842 // outer window's reference to this window that's being deleted.
843 nsGlobalWindow *outer = GetOuterWindowInternal();
844 if (outer && outer->mInnerWindow == this) {
845 outer->mInnerWindow = nsnull;
849 mDocument = nsnull; // Forces Release
850 mDoc = nsnull;
852 NS_ASSERTION(!mArguments, "mArguments wasn't cleaned up properly!");
854 CleanUp(PR_TRUE);
856 #ifdef DEBUG
857 nsCycleCollector_DEBUG_wasFreed(static_cast<nsIScriptGlobalObject*>(this));
858 #endif
860 delete mPendingStorageEventsObsolete;
862 nsLayoutStatics::Release();
865 // static
866 void
867 nsGlobalWindow::ShutDown()
869 NS_IF_RELEASE(sGlobalStorageList);
871 if (gDumpFile && gDumpFile != stdout) {
872 fclose(gDumpFile);
874 gDumpFile = nsnull;
877 // static
878 void
879 nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
881 if (aWindow->mCachedXBLPrototypeHandlers.IsInitialized() &&
882 aWindow->mCachedXBLPrototypeHandlers.Count() > 0) {
883 aWindow->mCachedXBLPrototypeHandlers.Clear();
885 nsCOMPtr<nsISupports> supports;
886 aWindow->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
887 getter_AddRefs(supports));
888 NS_ASSERTION(supports, "Failed to QI to nsCycleCollectionISupports?!");
890 nsContentUtils::DropJSObjects(supports);
894 void
895 nsGlobalWindow::MaybeForgiveSpamCount()
897 if (IsOuterWindow() &&
898 IsPopupSpamWindow())
900 SetPopupSpamWindow(PR_FALSE);
901 --gOpenPopupSpamCount;
902 NS_ASSERTION(gOpenPopupSpamCount >= 0,
903 "Unbalanced decrement of gOpenPopupSpamCount");
907 void
908 nsGlobalWindow::CleanUp(PRBool aIgnoreModalDialog)
910 if (IsOuterWindow() && !aIgnoreModalDialog) {
911 nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
912 nsCOMPtr<nsIDOMModalContentWindow>
913 dlg(do_QueryInterface(static_cast<nsPIDOMWindow*>(inner)));
914 if (dlg) {
915 // The window we're trying to clean up is the outer window of a
916 // modal dialog. Defer cleanup until the window closes, and let
917 // ShowModalDialog take care of calling CleanUp.
918 mCallCleanUpAfterModalDialogCloses = PR_TRUE;
919 return;
923 // Guarantee idempotence.
924 if (mCleanedUp)
925 return;
926 mCleanedUp = PR_TRUE;
928 mNavigator = nsnull;
929 mScreen = nsnull;
930 mHistory = nsnull;
931 mMenubar = nsnull;
932 mToolbar = nsnull;
933 mLocationbar = nsnull;
934 mPersonalbar = nsnull;
935 mStatusbar = nsnull;
936 mScrollbars = nsnull;
937 mLocation = nsnull;
938 mFrames = nsnull;
939 mApplicationCache = nsnull;
940 mIndexedDB = nsnull;
942 ClearControllers();
944 mOpener = nsnull; // Forces Release
945 if (mContext) {
946 #ifdef DEBUG
947 nsCycleCollector_DEBUG_shouldBeFreed(mContext);
948 #endif
949 mContext = nsnull; // Forces Release
951 mChromeEventHandler = nsnull; // Forces Release
952 mParentTarget = nsnull;
954 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
956 if (inner) {
957 inner->CleanUp(aIgnoreModalDialog);
960 if (mHasAcceleration) {
961 nsCOMPtr<nsIAccelerometer> ac = do_GetService(NS_ACCELEROMETER_CONTRACTID);
962 if (ac)
963 ac->RemoveWindowListener(this);
966 if (mIsChrome && static_cast<nsGlobalChromeWindow*>(this)->mMessageManager) {
967 static_cast<nsFrameMessageManager*>(
968 static_cast<nsGlobalChromeWindow*>(
969 this)->mMessageManager.get())->Disconnect();
972 mInnerWindowHolder = nsnull;
973 mArguments = nsnull;
974 mArgumentsLast = nsnull;
975 mArgumentsOrigin = nsnull;
977 CleanupCachedXBLHandlers(this);
979 #ifdef DEBUG
980 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
981 #endif
984 void
985 nsGlobalWindow::ClearControllers()
987 if (mControllers) {
988 PRUint32 count;
989 mControllers->GetControllerCount(&count);
991 while (count--) {
992 nsCOMPtr<nsIController> controller;
993 mControllers->GetControllerAt(count, getter_AddRefs(controller));
995 nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
996 if (context)
997 context->SetCommandContext(nsnull);
1000 mControllers = nsnull;
1004 class ClearScopeEvent : public nsRunnable
1006 public:
1007 ClearScopeEvent(nsGlobalWindow *innerWindow)
1008 : mInnerWindow(innerWindow) {
1011 NS_IMETHOD Run()
1013 mInnerWindow->ReallyClearScope(this);
1014 return NS_OK;
1017 private:
1018 nsRefPtr<nsGlobalWindow> mInnerWindow;
1021 void
1022 nsGlobalWindow::ReallyClearScope(nsRunnable *aRunnable)
1024 NS_ASSERTION(IsInnerWindow(), "Must be an inner window");
1026 nsIScriptContext *jsscx = GetContextInternal();
1027 if (jsscx && jsscx->GetExecutingScript()) {
1028 if (!aRunnable) {
1029 aRunnable = new ClearScopeEvent(this);
1030 if (!aRunnable) {
1031 // The only reason that we clear scope here is to try to prevent
1032 // leaks. Failing to clear scope might mean that we'll leak more
1033 // but if we don't have enough memory to allocate a ClearScopeEvent
1034 // we probably don't have to worry about this anyway.
1035 return;
1039 NS_DispatchToMainThread(aRunnable);
1040 return;
1043 NotifyWindowIDDestroyed("inner-window-destroyed");
1044 nsIScriptContext *scx = GetContextInternal();
1045 if (scx) {
1046 scx->ClearScope(mJSObject, PR_TRUE);
1050 void
1051 nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
1053 NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
1055 // Kill all of the workers for this window.
1056 nsDOMThreadService* dts = nsDOMThreadService::get();
1057 if (dts) {
1058 nsIScriptContext *scx = GetContextInternal();
1060 JSContext *cx = scx ? (JSContext *)scx->GetNativeContext() : nsnull;
1062 // Have to suspend this request here because CancelWorkersForGlobal will
1063 // lock until the worker has died and that could cause a deadlock.
1064 JSAutoSuspendRequest asr(cx);
1066 dts->CancelWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
1069 ClearAllTimeouts();
1071 mChromeEventHandler = nsnull;
1073 if (mListenerManager) {
1074 mListenerManager->Disconnect();
1075 mListenerManager = nsnull;
1078 if (mDocument) {
1079 NS_ASSERTION(mDoc, "Why is mDoc null?");
1081 // Remember the document's principal.
1082 mDocumentPrincipal = mDoc->NodePrincipal();
1085 #ifdef DEBUG
1086 if (mDocument)
1087 nsCycleCollector_DEBUG_shouldBeFreed(nsCOMPtr<nsISupports>(do_QueryInterface(mDocument)));
1088 #endif
1090 // Make sure that this is called before we null out the document.
1091 NotifyDOMWindowDestroyed(this);
1093 // Remove our reference to the document and the document principal.
1094 mDocument = nsnull;
1095 mDoc = nsnull;
1097 if (mApplicationCache) {
1098 static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
1099 mApplicationCache = nsnull;
1102 mIndexedDB = nsnull;
1104 if (aClearScope) {
1105 // NB: This might not clear our scope, but fire an event to do so
1106 // instead.
1107 ReallyClearScope(nsnull);
1110 if (mDummyJavaPluginOwner) {
1111 // Tear down the dummy java plugin.
1113 // XXXjst: On a general note, should windows with java stuff in
1114 // them ever even make it into the fast-back cache?
1116 mDummyJavaPluginOwner->Destroy();
1118 mDummyJavaPluginOwner = nsnull;
1121 CleanupCachedXBLHandlers(this);
1123 #ifdef DEBUG
1124 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
1125 #endif
1128 //*****************************************************************************
1129 // nsGlobalWindow::nsISupports
1130 //*****************************************************************************
1132 #define WINDOW_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(_class) \
1133 if (aIID.Equals(NS_GET_IID(nsIClassInfo)) || \
1134 aIID.Equals(NS_GET_IID(nsXPCClassInfo))) { \
1135 foundInterface = NS_GetDOMClassInfoInstance(IsInnerWindow() \
1136 ? eDOMClassInfo_Inner##_class##_id \
1137 : eDOMClassInfo_##_class##_id);\
1138 if (!foundInterface) { \
1139 *aInstancePtr = nsnull; \
1140 return NS_ERROR_OUT_OF_MEMORY; \
1142 } else
1144 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
1146 DOMCI_DATA(Window, nsGlobalWindow)
1147 DOMCI_DATA(InnerWindow, nsGlobalWindow)
1149 // QueryInterface implementation for nsGlobalWindow
1150 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
1151 // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
1152 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObject)
1153 NS_INTERFACE_MAP_ENTRY(nsIDOMWindowInternal)
1154 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
1155 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow2)
1156 NS_INTERFACE_MAP_ENTRY(nsIDOMJSWindow)
1157 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
1158 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
1159 NS_INTERFACE_MAP_ENTRY(nsPIDOMEventTarget)
1160 NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
1161 NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
1162 NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
1163 NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow)
1164 NS_INTERFACE_MAP_ENTRY(nsIDOMViewCSS)
1165 NS_INTERFACE_MAP_ENTRY(nsIDOMAbstractView)
1166 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageWindow)
1167 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
1168 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
1169 WINDOW_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
1170 NS_INTERFACE_MAP_END
1173 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGlobalWindow, nsIScriptGlobalObject)
1174 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsGlobalWindow,
1175 nsIScriptGlobalObject)
1178 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGlobalWindow)
1179 if (tmp->mDoc && nsCCUncollectableMarker::InGeneration(
1180 cb, tmp->mDoc->GetMarkedCCGeneration())) {
1181 return NS_SUCCESS_INTERRUPTED_TRAVERSE;
1184 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
1186 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mControllers)
1187 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArguments)
1188 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArgumentsLast)
1190 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInnerWindowHolder)
1192 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOpenerScriptPrincipal)
1193 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListenerManager)
1195 for (nsTimeout* timeout = tmp->FirstTimeout();
1196 tmp->IsTimeout(timeout);
1197 timeout = timeout->Next()) {
1198 cb.NoteNativeChild(timeout, &NS_CYCLE_COLLECTION_NAME(nsTimeout));
1201 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSessionStorage)
1202 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mApplicationCache)
1203 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocumentPrincipal)
1204 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDoc)
1206 // Traverse stuff from nsPIDOMWindow
1207 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChromeEventHandler)
1208 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParentTarget)
1209 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
1210 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFrameElement)
1212 // Traverse mDummyJavaPluginOwner
1213 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDummyJavaPluginOwner)
1215 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFocusedNode)
1217 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1219 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
1220 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
1222 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mControllers)
1223 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArguments)
1224 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArgumentsLast)
1226 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInnerWindowHolder)
1228 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOpenerScriptPrincipal)
1229 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager)
1230 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSessionStorage)
1231 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mApplicationCache)
1232 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocumentPrincipal)
1234 // Unlink stuff from nsPIDOMWindow
1235 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChromeEventHandler)
1236 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParentTarget)
1237 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
1238 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFrameElement)
1240 // Unlink mDummyJavaPluginOwner
1241 if (tmp->mDummyJavaPluginOwner) {
1242 tmp->mDummyJavaPluginOwner->Destroy();
1243 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDummyJavaPluginOwner)
1246 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFocusedNode)
1248 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1250 struct TraceData
1252 TraceData(TraceCallback& aCallback, void* aClosure) :
1253 callback(aCallback), closure(aClosure) {}
1255 TraceCallback& callback;
1256 void* closure;
1259 static PLDHashOperator
1260 TraceXBLHandlers(const void* aKey, void* aData, void* aClosure)
1262 TraceData* data = static_cast<TraceData*>(aClosure);
1263 data->callback(nsIProgrammingLanguage::JAVASCRIPT, aData, data->closure);
1264 return PL_DHASH_NEXT;
1267 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
1268 if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
1269 TraceData data(aCallback, aClosure);
1270 tmp->mCachedXBLPrototypeHandlers.EnumerateRead(TraceXBLHandlers, &data);
1272 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1274 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsGlobalWindow)
1275 nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
1276 NS_IMPL_CYCLE_COLLECTION_ROOT_END
1278 //*****************************************************************************
1279 // nsGlobalWindow::nsIScriptGlobalObject
1280 //*****************************************************************************
1282 nsresult
1283 nsGlobalWindow::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aScriptContext)
1285 NS_ASSERTION(lang_id == nsIProgrammingLanguage::JAVASCRIPT,
1286 "We don't support this language ID");
1287 NS_ASSERTION(IsOuterWindow(), "Uh, SetScriptContext() called on inner window!");
1289 if (!aScriptContext) {
1290 NS_WARNING("Possibly early removal of script object, see bug #41608");
1291 } else {
1292 // should probably assert the context is clean???
1293 aScriptContext->WillInitializeContext();
1295 // Bind the script context and the global object
1296 nsresult rv = aScriptContext->InitContext(this);
1297 NS_ENSURE_SUCCESS(rv, rv);
1300 NS_ASSERTION(!aScriptContext || !mContext, "Bad call to SetContext()!");
1302 void *script_glob = nsnull;
1304 if (aScriptContext) {
1305 if (IsFrame()) {
1306 // This window is a [i]frame, don't bother GC'ing when the
1307 // frame's context is destroyed since a GC will happen when the
1308 // frameset or host document is destroyed anyway.
1310 aScriptContext->SetGCOnDestruction(PR_FALSE);
1313 aScriptContext->DidInitializeContext();
1314 script_glob = aScriptContext->GetNativeGlobal();
1315 NS_ASSERTION(script_glob, "GetNativeGlobal returned NULL!");
1318 mContext = aScriptContext;
1319 mJSObject = (JSObject *)script_glob;
1320 return NS_OK;
1323 nsresult
1324 nsGlobalWindow::EnsureScriptEnvironment(PRUint32 aLangID)
1326 NS_ASSERTION(aLangID == nsIProgrammingLanguage::JAVASCRIPT,
1327 "We don't support this language ID");
1328 FORWARD_TO_OUTER(EnsureScriptEnvironment, (aLangID), NS_ERROR_NOT_INITIALIZED);
1330 if (mJSObject)
1331 return NS_OK;
1333 NS_ASSERTION(!GetCurrentInnerWindowInternal(), "Huh?");
1335 nsCOMPtr<nsIScriptRuntime> scriptRuntime;
1336 nsresult rv = NS_GetScriptRuntimeByID(aLangID, getter_AddRefs(scriptRuntime));
1337 NS_ENSURE_SUCCESS(rv, rv);
1339 nsCOMPtr<nsIScriptContext> context;
1340 rv = scriptRuntime->CreateContext(getter_AddRefs(context));
1341 NS_ENSURE_SUCCESS(rv, rv);
1343 return SetScriptContext(aLangID, context);
1346 nsIScriptContext *
1347 nsGlobalWindow::GetScriptContext(PRUint32 lang)
1349 NS_ASSERTION(lang == nsIProgrammingLanguage::JAVASCRIPT,
1350 "We don't support this language ID");
1352 FORWARD_TO_OUTER(GetScriptContext, (lang), nsnull);
1353 return mContext;
1356 void *
1357 nsGlobalWindow::GetScriptGlobal(PRUint32 lang)
1359 NS_ASSERTION(lang == nsIProgrammingLanguage::JAVASCRIPT,
1360 "We don't support this language ID");
1361 return mJSObject;
1364 nsIScriptContext *
1365 nsGlobalWindow::GetContext()
1367 FORWARD_TO_OUTER(GetContext, (), nsnull);
1369 // check GetContext is indeed identical to GetScriptContext()
1370 NS_ASSERTION(mContext == GetScriptContext(nsIProgrammingLanguage::JAVASCRIPT),
1371 "GetContext confused?");
1372 return mContext;
1375 JSObject *
1376 nsGlobalWindow::GetGlobalJSObject()
1378 NS_ASSERTION(mJSObject == GetScriptGlobal(nsIProgrammingLanguage::JAVASCRIPT),
1379 "GetGlobalJSObject confused?");
1380 return FastGetGlobalJSObject();
1383 PRBool
1384 nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
1386 // We reuse the inner window when:
1387 // a. We are currently at our original document.
1388 // b. At least one of the following conditions are true:
1389 // -- We are not currently a content window (i.e., we're currently a chrome
1390 // window).
1391 // -- The new document is the same as the old document. This means that we're
1392 // getting called from document.open().
1393 // -- The new document has the same origin as what we have loaded right now.
1395 if (!mDoc || !aNewDocument) {
1396 return PR_FALSE;
1399 if (!mDoc->IsInitialDocument()) {
1400 return PR_FALSE;
1403 NS_ASSERTION(IsAboutBlank(mDoc->GetDocumentURI()),
1404 "How'd this happen?");
1406 // Great, we're the original document, check for one of the other
1407 // conditions.
1408 if (mDoc == aNewDocument) {
1409 // aClearScopeHint is false.
1410 return PR_TRUE;
1413 PRBool equal;
1414 if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
1415 &equal)) &&
1416 equal) {
1417 // The origin is the same.
1418 return PR_TRUE;
1421 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
1423 if (treeItem) {
1424 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
1425 treeItem->GetItemType(&itemType);
1427 // If we're a chrome window, then we want to reuse the inner window.
1428 return itemType == nsIDocShellTreeItem::typeChrome;
1431 // No treeItem: don't reuse the current inner window.
1432 return PR_FALSE;
1435 void
1436 nsGlobalWindow::SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal)
1438 FORWARD_TO_OUTER_VOID(SetOpenerScriptPrincipal, (aPrincipal));
1440 if (mDoc) {
1441 if (!mDoc->IsInitialDocument()) {
1442 // We have a document already, and it's not the original one. Bail out.
1443 // Do NOT set mOpenerScriptPrincipal in this case, just to be safe.
1444 return;
1447 #ifdef DEBUG
1448 // We better have an about:blank document loaded at this point. Otherwise,
1449 // something is really weird.
1450 nsCOMPtr<nsIURI> uri;
1451 mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
1452 NS_ASSERTION(uri && IsAboutBlank(uri) &&
1453 IsAboutBlank(mDoc->GetDocumentURI()),
1454 "Unexpected original document");
1455 #endif
1457 // Set the opener principal on our document; given the above check, this
1458 // is safe.
1459 mDoc->SetPrincipal(aPrincipal);
1462 mOpenerScriptPrincipal = aPrincipal;
1465 nsIPrincipal*
1466 nsGlobalWindow::GetOpenerScriptPrincipal()
1468 FORWARD_TO_OUTER(GetOpenerScriptPrincipal, (), nsnull);
1470 return mOpenerScriptPrincipal;
1473 PopupControlState
1474 PushPopupControlState(PopupControlState aState, PRBool aForce)
1476 PopupControlState oldState = gPopupControlState;
1478 if (aState < gPopupControlState || aForce) {
1479 gPopupControlState = aState;
1482 return oldState;
1485 void
1486 PopPopupControlState(PopupControlState aState)
1488 gPopupControlState = aState;
1491 PopupControlState
1492 nsGlobalWindow::PushPopupControlState(PopupControlState aState,
1493 PRBool aForce) const
1495 return ::PushPopupControlState(aState, aForce);
1498 void
1499 nsGlobalWindow::PopPopupControlState(PopupControlState aState) const
1501 ::PopPopupControlState(aState);
1504 PopupControlState
1505 nsGlobalWindow::GetPopupControlState() const
1507 return gPopupControlState;
1510 #define WINDOWSTATEHOLDER_IID \
1511 {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
1513 class WindowStateHolder : public nsISupports
1515 public:
1516 NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
1517 NS_DECL_ISUPPORTS
1519 WindowStateHolder(nsGlobalWindow *aWindow,
1520 nsIXPConnectJSObjectHolder *aHolder,
1521 nsNavigator *aNavigator,
1522 nsLocation *aLocation,
1523 nsIXPConnectJSObjectHolder *aOuterProto);
1525 nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
1526 nsIXPConnectJSObjectHolder *GetInnerWindowHolder()
1527 { return mInnerWindowHolder; }
1529 nsNavigator* GetNavigator() { return mNavigator; }
1530 nsLocation* GetLocation() { return mLocation; }
1531 nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
1533 void DidRestoreWindow()
1535 mInnerWindow = nsnull;
1537 mInnerWindowHolder = nsnull;
1538 mNavigator = nsnull;
1539 mLocation = nsnull;
1540 mOuterProto = nsnull;
1543 protected:
1544 ~WindowStateHolder();
1546 nsGlobalWindow *mInnerWindow;
1547 // We hold onto this to make sure the inner window doesn't go away. The outer
1548 // window ends up recalculating it anyway.
1549 nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
1550 nsRefPtr<nsNavigator> mNavigator;
1551 nsRefPtr<nsLocation> mLocation;
1552 nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
1555 NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
1557 WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
1558 nsIXPConnectJSObjectHolder *aHolder,
1559 nsNavigator *aNavigator,
1560 nsLocation *aLocation,
1561 nsIXPConnectJSObjectHolder *aOuterProto)
1562 : mInnerWindow(aWindow),
1563 mNavigator(aNavigator),
1564 mLocation(aLocation),
1565 mOuterProto(aOuterProto)
1567 NS_PRECONDITION(aWindow, "null window");
1568 NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
1570 mInnerWindowHolder = aHolder;
1572 aWindow->SuspendTimeouts();
1575 WindowStateHolder::~WindowStateHolder()
1577 if (mInnerWindow) {
1578 // This window was left in the bfcache and is now going away. We need to
1579 // free it up.
1580 // Note that FreeInnerObjects may already have been called on the
1581 // inner window if its outer has already had SetDocShell(null)
1582 // called. In this case the contexts will all be null and the
1583 // PR_TRUE for aClearScope won't do anything; this is OK since
1584 // SetDocShell(null) already did it.
1585 mInnerWindow->FreeInnerObjects(PR_TRUE);
1589 NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder)
1591 nsresult
1592 nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
1593 nsISupports* aState)
1595 NS_TIME_FUNCTION;
1597 NS_PRECONDITION(mDocumentPrincipal == nsnull,
1598 "mDocumentPrincipal prematurely set!");
1600 if (!aDocument) {
1601 NS_ERROR("SetNewDocument(null) called!");
1603 return NS_ERROR_INVALID_ARG;
1606 if (IsInnerWindow()) {
1607 if (!mOuterWindow) {
1608 return NS_ERROR_NOT_INITIALIZED;
1611 // Refuse to set a new document if the call came from an inner
1612 // window that's not the current inner window.
1613 if (mOuterWindow->GetCurrentInnerWindow() != this) {
1614 return NS_ERROR_NOT_AVAILABLE;
1617 return GetOuterWindowInternal()->SetNewDocument(aDocument, aState);
1620 NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
1622 if (IsFrozen()) {
1623 // This outer is now getting its first inner, thaw the outer now
1624 // that it's ready and is getting an inner window.
1625 Thaw();
1628 NS_ASSERTION(!GetCurrentInnerWindow() ||
1629 GetCurrentInnerWindow()->GetExtantDocument() == mDocument,
1630 "Uh, mDocument doesn't match the current inner window "
1631 "document!");
1633 nsresult rv = NS_OK;
1635 nsCOMPtr<nsIDocument> oldDoc(do_QueryInterface(mDocument));
1637 nsIScriptContext *scx = GetContextInternal();
1638 NS_ENSURE_TRUE(scx, NS_ERROR_NOT_INITIALIZED);
1640 JSContext *cx = (JSContext *)scx->GetNativeContext();
1642 // clear smartcard events, our document has gone away.
1643 if (mCrypto) {
1644 mCrypto->SetEnableSmartCardEvents(PR_FALSE);
1647 if (!mDocument) {
1648 // First document load.
1650 // Get our private root. If it is equal to us, then we need to
1651 // attach our global key bindings that handles browser scrolling
1652 // and other browser commands.
1653 nsIDOMWindowInternal *internal = nsGlobalWindow::GetPrivateRoot();
1655 if (internal == static_cast<nsIDOMWindowInternal *>(this)) {
1656 nsCOMPtr<nsIXBLService> xblService = do_GetService("@mozilla.org/xbl;1");
1657 if (xblService) {
1658 nsCOMPtr<nsPIDOMEventTarget> piTarget =
1659 do_QueryInterface(mChromeEventHandler);
1660 xblService->AttachGlobalKeyHandler(piTarget);
1665 /* No mDocShell means we're already been partially closed down. When that
1666 happens, setting status isn't a big requirement, so don't. (Doesn't happen
1667 under normal circumstances, but bug 49615 describes a case.) */
1669 nsContentUtils::AddScriptRunner(
1670 NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus));
1672 PRBool reUseInnerWindow = WouldReuseInnerWindow(aDocument);
1674 // Remember the old document's principal.
1675 nsIPrincipal *oldPrincipal = nsnull;
1676 if (oldDoc) {
1677 oldPrincipal = oldDoc->NodePrincipal();
1680 // Drop our reference to the navigator object unless we're reusing
1681 // the existing inner window or the new document is from the same
1682 // origin as the old document.
1683 if (!reUseInnerWindow && mNavigator && oldPrincipal) {
1684 PRBool equal;
1685 rv = oldPrincipal->Equals(aDocument->NodePrincipal(), &equal);
1687 if (NS_FAILED(rv) || !equal) {
1688 // Different origins. Release the navigator object so it gets
1689 // recreated for the new document. The plugins or mime types
1690 // arrays may have changed. See bug 150087.
1691 mNavigator->SetDocShell(nsnull);
1693 mNavigator = nsnull;
1697 if (mNavigator && aDocument != oldDoc) {
1698 // We didn't drop our reference to our old navigator object and
1699 // we're loading a new document. Notify the navigator object about
1700 // the new document load so that it can make sure it is ready for
1701 // the new document.
1703 mNavigator->LoadingNewDocument();
1706 // Set mDocument even if this is an outer window to avoid
1707 // having to *always* reach into the inner window to find the
1708 // document.
1709 mDocument = do_QueryInterface(aDocument);
1710 mDoc = aDocument;
1712 #ifdef DEBUG
1713 mLastOpenedURI = aDocument->GetDocumentURI();
1714 #endif
1716 mContext->WillInitializeContext();
1718 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
1720 nsRefPtr<nsGlobalWindow> newInnerWindow;
1722 PRBool thisChrome = IsChromeWindow();
1723 nsCOMPtr<nsIXPConnectJSObjectHolder> navigatorHolder;
1724 jsval nav;
1726 PRBool isChrome = PR_FALSE;
1728 nsCxPusher cxPusher;
1729 if (!cxPusher.Push(cx)) {
1730 return NS_ERROR_FAILURE;
1733 JSAutoRequest ar(cx);
1735 // Make sure to clear scope on the outer window *before* we
1736 // initialize the new inner window. If we don't, things
1737 // (Object.prototype etc) could leak from the old outer to the new
1738 // inner scope.
1739 mContext->ClearScope(mJSObject, PR_FALSE);
1741 if (reUseInnerWindow) {
1742 // We're reusing the current inner window.
1743 NS_ASSERTION(!currentInner->IsFrozen(),
1744 "We should never be reusing a shared inner window");
1745 newInnerWindow = currentInner;
1747 if (aDocument != oldDoc) {
1748 nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject);
1750 } else {
1751 if (aState) {
1752 nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
1753 NS_ASSERTION(wsh, "What kind of weird state are you giving me here?");
1755 newInnerWindow = wsh->GetInnerWindow();
1756 mInnerWindowHolder = wsh->GetInnerWindowHolder();
1758 // These assignments addref.
1759 mNavigator = wsh->GetNavigator();
1760 mLocation = wsh->GetLocation();
1762 if (mNavigator) {
1763 // Update mNavigator's docshell pointer now.
1764 mNavigator->SetDocShell(mDocShell);
1765 mNavigator->LoadingNewDocument();
1767 } else {
1768 if (thisChrome) {
1769 newInnerWindow = new nsGlobalChromeWindow(this);
1771 isChrome = PR_TRUE;
1772 } else {
1773 if (mIsModalContentWindow) {
1774 newInnerWindow = new nsGlobalModalWindow(this);
1775 } else {
1776 newInnerWindow = new nsGlobalWindow(this);
1780 mLocation = nsnull;
1783 if (!newInnerWindow) {
1784 return NS_ERROR_OUT_OF_MEMORY;
1787 if (currentInner && currentInner->mJSObject) {
1788 if (mNavigator && !aState) {
1789 // Hold on to the navigator wrapper so that we can set
1790 // window.navigator in the new window to point to the same
1791 // object (assuming we didn't change origins etc). See bug
1792 // 163645 for more on why we need this.
1794 nsIDOMNavigator* navigator =
1795 static_cast<nsIDOMNavigator*>(mNavigator.get());
1796 nsContentUtils::WrapNative(cx, currentInner->mJSObject, navigator,
1797 &NS_GET_IID(nsIDOMNavigator), &nav,
1798 getter_AddRefs(navigatorHolder));
1802 if (!aState) {
1803 // This is redundant if we're restoring from a previous inner window.
1804 nsIScriptGlobalObject *sgo =
1805 (nsIScriptGlobalObject *)newInnerWindow.get();
1807 // Freeze the outer window and null out the inner window so
1808 // that initializing classes on the new inner doesn't end up
1809 // reaching into the old inner window for classes etc.
1811 // [This happens with Object.prototype when XPConnect creates
1812 // a temporary global while initializing classes; the reason
1813 // being that xpconnect creates the temp global w/o a parent
1814 // and proto, which makes the JS engine look up classes in
1815 // cx->globalObject, i.e. this outer window].
1817 mInnerWindow = nsnull;
1819 Freeze();
1820 mCreatingInnerWindow = PR_TRUE;
1821 // Every script context we are initialized with must create a
1822 // new global.
1823 void *&newGlobal = (void *&)newInnerWindow->mJSObject;
1824 nsCOMPtr<nsIXPConnectJSObjectHolder> &holder = mInnerWindowHolder;
1825 rv = mContext->CreateNativeGlobalForInner(sgo, isChrome,
1826 &newGlobal,
1827 getter_AddRefs(holder));
1828 NS_ASSERTION(NS_SUCCEEDED(rv) && newGlobal && holder,
1829 "Failed to get script global and holder");
1830 newInnerWindow->mJSObject = (JSObject *)newGlobal;
1832 mCreatingInnerWindow = PR_FALSE;
1833 Thaw();
1835 NS_ENSURE_SUCCESS(rv, rv);
1838 if (currentInner && currentInner->mJSObject) {
1839 PRBool termFuncSet = PR_FALSE;
1841 if (oldDoc == aDocument) {
1842 // Suspend the current context's request before Pop() resumes the old
1843 // context's request.
1844 JSAutoSuspendRequest asr(cx);
1846 // Pop our context here so that we get the correct one for the
1847 // termination function.
1848 cxPusher.Pop();
1850 JSContext *oldCx = nsContentUtils::GetCurrentJSContext();
1852 nsIScriptContext *callerScx;
1853 if (oldCx && (callerScx = GetScriptContextFromJSContext(oldCx))) {
1854 // We're called from document.open() (and document.open() is
1855 // called from JS), clear the scope etc in a termination
1856 // function on the calling context to prevent clearing the
1857 // calling scope.
1858 NS_ASSERTION(!currentInner->IsFrozen(),
1859 "How does this opened window get into session history");
1861 JSAutoRequest ar(oldCx);
1863 callerScx->SetTerminationFunction(ClearWindowScope,
1864 static_cast<nsIDOMWindow *>
1865 (currentInner));
1867 termFuncSet = PR_TRUE;
1870 // Re-push our context.
1871 cxPusher.Push(cx);
1874 // Don't clear scope on our current inner window if it's going to be
1875 // held in the bfcache.
1876 if (!currentInner->IsFrozen()) {
1877 // Skip the ClearScope if we set a termination function to do
1878 // it ourselves, later.
1879 currentInner->FreeInnerObjects(!termFuncSet);
1883 mInnerWindow = newInnerWindow;
1886 if (!aState && !reUseInnerWindow) {
1887 // Loading a new page and creating a new inner window, *not*
1888 // restoring from session history.
1890 // InitClassesWithNewWrappedGlobal() (via CreateNativeGlobalForInner)
1891 // for the new inner window
1892 // sets the global object in cx to be the new wrapped global. We
1893 // don't want that, but re-initializing the outer window will
1894 // fix that for us. And perhaps more importantly, this will
1895 // ensure that the outer window gets a new prototype so we don't
1896 // leak prototype properties from the old inner window to the
1897 // new one.
1898 JS_BeginRequest((JSContext *)mContext->GetNativeContext());
1899 mContext->InitContext(this);
1901 // Now that both the the inner and outer windows are initialized
1902 // let the script context do its magic to hook them together.
1903 mContext->ConnectToInner(newInnerWindow, mJSObject);
1904 JS_EndRequest((JSContext *)mContext->GetNativeContext());
1906 nsCOMPtr<nsIContent> frame = do_QueryInterface(GetFrameElementInternal());
1907 if (frame && frame->GetOwnerDoc()) {
1908 nsPIDOMWindow* parentWindow = frame->GetOwnerDoc()->GetWindow();
1909 if (parentWindow && parentWindow->TimeoutSuspendCount()) {
1910 SuspendTimeouts(parentWindow->TimeoutSuspendCount());
1915 // Tell the contexts we have completed setting up the doc.
1916 // Add an extra ref in case we release mContext during GC.
1917 nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
1918 nsCOMPtr<nsIDOMDocument> dd(do_QueryInterface(aDocument));
1919 mContext->DidSetDocument(dd, newInnerWindow->mJSObject);
1921 // Now that the prototype is all set up, install the global scope
1922 // polluter. This must happen after the above prototype fixup. If
1923 // the GSP was to be installed on the inner window's real
1924 // prototype (as it would be if this was done before the prototype
1925 // fixup above) we would end up holding the GSP alive (through
1926 // XPConnect's internal marking of wrapper prototypes) as long as
1927 // the inner window was around, and if the GSP had properties on
1928 // it that held an element alive we'd hold the document alive,
1929 // which could hold event handlers alive, which hold the context
1930 // alive etc.
1932 if ((!reUseInnerWindow || aDocument != oldDoc) && !aState) {
1933 nsCOMPtr<nsIHTMLDocument> html_doc(do_QueryInterface(mDocument));
1934 nsWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject,
1935 html_doc);
1938 // This code should not be called during shutdown any more (now that
1939 // we don't ever call SetNewDocument(nsnull), so no need to null
1940 // check xpc here.
1941 nsIXPConnect *xpc = nsContentUtils::XPConnect();
1943 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
1944 if (aState) {
1945 // Restoring from session history.
1947 nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
1948 NS_ASSERTION(wsh, "What kind of weird state are you giving me here?");
1950 // Restore the prototype for the Window/ChromeWindow class in
1951 // the outer window scope.
1952 nsCOMPtr<nsIClassInfo> ci =
1953 do_QueryInterface((nsIScriptGlobalObject *)this);
1955 rv = xpc->RestoreWrappedNativePrototype(cx, mJSObject, ci,
1956 wsh->GetOuterProto());
1957 NS_ENSURE_SUCCESS(rv, rv);
1959 // Refresh the outer window's prototype to what it was when the
1960 // window state was saved. This will make the outer window
1961 // object (and wrapper) pick up the prototype it had when the
1962 // window state was saved. This means Object.prototype etc from
1963 // the old inner will again be on the outer window's prototype
1964 // chain.
1966 rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
1967 getter_AddRefs(wrapper));
1968 NS_ENSURE_SUCCESS(rv, rv);
1970 rv = wrapper->RefreshPrototype();
1971 NS_ENSURE_SUCCESS(rv, rv);
1974 if (aDocument) {
1975 aDocument->SetScriptGlobalObject(newInnerWindow);
1978 if (!aState) {
1979 if (reUseInnerWindow) {
1980 if (newInnerWindow->mDoc != aDocument) {
1981 newInnerWindow->mDocument = do_QueryInterface(aDocument);
1982 newInnerWindow->mDoc = aDocument;
1984 // We're reusing the inner window for a new document. In this
1985 // case we don't clear the inner window's scope, but we must
1986 // make sure the cached document property gets updated.
1988 // XXXmarkh - tell other languages about this?
1989 JSAutoRequest ar(cx);
1990 ::JS_DeleteProperty(cx, currentInner->mJSObject, "document");
1992 } else {
1993 rv = newInnerWindow->InnerSetNewDocument(aDocument);
1994 NS_ENSURE_SUCCESS(rv, rv);
1996 // Initialize DOM classes etc on the inner window.
1997 rv = mContext->InitClasses(mJSObject);
1998 NS_ENSURE_SUCCESS(rv, rv);
2000 if (navigatorHolder) {
2001 // Restore window.navigator onto the new inner window.
2002 JSAutoRequest ar(cx);
2004 ::JS_DefineProperty(cx, newInnerWindow->mJSObject, "navigator",
2005 nav, nsnull, nsnull,
2006 JSPROP_ENUMERATE | JSPROP_PERMANENT |
2007 JSPROP_READONLY);
2009 // The Navigator's prototype object keeps a reference to the
2010 // window in which it was first created and can thus cause that
2011 // window to stay alive for too long. Reparenting it here allows
2012 // the window to be collected sooner.
2013 nsIDOMNavigator* navigator =
2014 static_cast<nsIDOMNavigator*>(mNavigator);
2016 xpc->
2017 ReparentWrappedNativeIfFound(cx, JSVAL_TO_OBJECT(nav),
2018 newInnerWindow->mJSObject,
2019 navigator,
2020 getter_AddRefs(navigatorHolder));
2024 if (mArguments) {
2025 newInnerWindow->DefineArgumentsProperty(mArguments);
2026 newInnerWindow->mArguments = mArguments;
2027 newInnerWindow->mArgumentsOrigin = mArgumentsOrigin;
2029 mArguments = nsnull;
2030 mArgumentsOrigin = nsnull;
2033 // Give the new inner window our chrome event handler (since it
2034 // doesn't have one).
2035 newInnerWindow->mChromeEventHandler = mChromeEventHandler;
2038 mContext->GC();
2039 mContext->DidInitializeContext();
2041 if (!wrapper) {
2042 rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
2043 getter_AddRefs(wrapper));
2044 NS_ENSURE_SUCCESS(rv, rv);
2047 rv = xpc->UpdateXOWs((JSContext *)GetContextInternal()->GetNativeContext(),
2048 wrapper, nsIXPConnect::XPC_XOW_NAVIGATED);
2049 NS_ENSURE_SUCCESS(rv, rv);
2051 nsContentUtils::AddScriptRunner(
2052 NS_NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated));
2054 return NS_OK;
2057 void
2058 nsGlobalWindow::DispatchDOMWindowCreated()
2060 if (!mDoc || !mDocument) {
2061 return;
2064 // Fire DOMWindowCreated at chrome event listeners
2065 nsContentUtils::DispatchChromeEvent(mDoc, mDocument, NS_LITERAL_STRING("DOMWindowCreated"),
2066 PR_TRUE /* bubbles */,
2067 PR_FALSE /* not cancellable */);
2069 nsCOMPtr<nsIObserverService> observerService =
2070 mozilla::services::GetObserverService();
2071 if (observerService) {
2072 nsAutoString origin;
2073 nsIPrincipal* principal = mDoc->NodePrincipal();
2074 nsContentUtils::GetUTFOrigin(principal, origin);
2075 observerService->
2076 NotifyObservers(static_cast<nsIDOMWindow*>(this),
2077 nsContentUtils::IsSystemPrincipal(principal) ?
2078 "chrome-document-global-created" :
2079 "content-document-global-created",
2080 origin.get());
2084 void
2085 nsGlobalWindow::ClearStatus()
2087 SetStatus(EmptyString());
2088 SetDefaultStatus(EmptyString());
2091 nsresult
2092 nsGlobalWindow::InnerSetNewDocument(nsIDocument* aDocument)
2094 NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
2096 #ifdef PR_LOGGING
2097 if (aDocument && gDOMLeakPRLog &&
2098 PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
2099 nsIURI *uri = aDocument->GetDocumentURI();
2100 nsCAutoString spec;
2101 if (uri)
2102 uri->GetSpec(spec);
2103 PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
2105 #endif
2107 mDocument = do_QueryInterface(aDocument);
2108 mDoc = aDocument;
2109 mLocalStorage = nsnull;
2110 mSessionStorage = nsnull;
2112 #ifdef DEBUG
2113 mLastOpenedURI = aDocument->GetDocumentURI();
2114 #endif
2116 // Clear our mutation bitfield.
2117 mMutationBits = 0;
2119 return NS_OK;
2122 void
2123 nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
2125 NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
2127 if (aDocShell == mDocShell)
2128 return;
2130 // SetDocShell(nsnull) means the window is being torn down. Drop our
2131 // reference to the script context, allowing it to be deleted
2132 // later. Meanwhile, keep our weak reference to the script object
2133 // (mJSObject) so that it can be retrieved later (until it is
2134 // finalized by the JS GC).
2136 if (!aDocShell) {
2137 NS_ASSERTION(PR_CLIST_IS_EMPTY(&mTimeouts),
2138 "Uh, outer window holds timeouts!");
2140 // Call FreeInnerObjects on all inner windows, not just the current
2141 // one, since some could be held by WindowStateHolder objects that
2142 // are GC-owned.
2143 for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
2144 inner != this;
2145 inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
2146 NS_ASSERTION(inner->mOuterWindow == this, "bad outer window pointer");
2147 inner->FreeInnerObjects(PR_TRUE);
2150 // Make sure that this is called before we null out the document.
2151 NotifyDOMWindowDestroyed(this);
2153 NotifyWindowIDDestroyed("outer-window-destroyed");
2155 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
2157 if (currentInner) {
2158 NS_ASSERTION(mDoc, "Must have doc!");
2160 // Remember the document's principal.
2161 mDocumentPrincipal = mDoc->NodePrincipal();
2163 // Release our document reference
2164 mDocument = nsnull;
2165 mDoc = nsnull;
2168 mContext->ClearScope(mJSObject, PR_TRUE);
2170 ClearControllers();
2172 mChromeEventHandler = nsnull; // force release now
2174 if (mArguments) {
2175 // We got no new document after someone called
2176 // SetArguments(), drop our reference to the arguments.
2177 mArguments = nsnull;
2178 mArgumentsLast = nsnull;
2179 mArgumentsOrigin = nsnull;
2182 mContext->GC();
2183 mContext->FinalizeContext();
2184 mContext = nsnull;
2186 #ifdef DEBUG
2187 nsCycleCollector_DEBUG_shouldBeFreed(mContext);
2188 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
2189 #endif
2192 mDocShell = aDocShell; // Weak Reference
2194 if (mNavigator)
2195 mNavigator->SetDocShell(aDocShell);
2196 if (mLocation)
2197 mLocation->SetDocShell(aDocShell);
2198 if (mHistory)
2199 mHistory->SetDocShell(aDocShell);
2200 if (mFrames)
2201 mFrames->SetDocShell(aDocShell);
2202 if (mScreen)
2203 mScreen->SetDocShell(aDocShell);
2205 if (!mDocShell) {
2206 MaybeForgiveSpamCount();
2207 CleanUp(PR_FALSE);
2208 } else {
2209 // tell our member elements about the new browserwindow
2210 if (mMenubar) {
2211 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2212 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2213 mMenubar->SetWebBrowserChrome(browserChrome);
2216 // Get our enclosing chrome shell and retrieve its global window impl, so
2217 // that we can do some forwarding to the chrome document.
2218 nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
2219 mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
2220 mChromeEventHandler = do_QueryInterface(chromeEventHandler);
2221 if (!mChromeEventHandler) {
2222 // We have no chrome event handler. If we have a parent,
2223 // get our chrome event handler from the parent. If
2224 // we don't have a parent, then we need to make a new
2225 // window root object that will function as a chrome event
2226 // handler and receive all events that occur anywhere inside
2227 // our window.
2228 nsCOMPtr<nsIDOMWindow> parentWindow;
2229 GetParent(getter_AddRefs(parentWindow));
2230 if (parentWindow.get() != static_cast<nsIDOMWindow*>(this)) {
2231 nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(parentWindow));
2232 mChromeEventHandler = piWindow->GetChromeEventHandler();
2234 else NS_NewWindowRoot(this, getter_AddRefs(mChromeEventHandler));
2239 void
2240 nsGlobalWindow::SetOpenerWindow(nsIDOMWindowInternal* aOpener,
2241 PRBool aOriginalOpener)
2243 FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
2245 NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
2246 "aOriginalOpener is true, but not first call to "
2247 "SetOpenerWindow!");
2248 NS_ASSERTION(aOpener || !aOriginalOpener,
2249 "Shouldn't set mHadOriginalOpener if aOpener is null");
2251 mOpener = do_GetWeakReference(aOpener);
2252 NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
2254 if (aOriginalOpener) {
2255 mHadOriginalOpener = PR_TRUE;
2258 #ifdef DEBUG
2259 mSetOpenerWindowCalled = PR_TRUE;
2260 #endif
2263 void
2264 nsGlobalWindow::UpdateParentTarget()
2266 nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(mChromeEventHandler);
2267 if (flo) {
2268 nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
2269 if (fl) {
2270 mParentTarget = fl->GetTabChildGlobalAsEventTarget();
2273 if (!mParentTarget) {
2274 mParentTarget = mChromeEventHandler;
2278 nsresult
2279 nsGlobalWindow::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
2281 NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
2282 static PRUint32 count = 0;
2283 PRUint32 msg = aVisitor.mEvent->message;
2285 aVisitor.mCanHandle = PR_TRUE;
2286 aVisitor.mForceContentDispatch = PR_TRUE; //FIXME! Bug 329119
2287 if ((msg == NS_MOUSE_MOVE) && gEntropyCollector) {
2288 //Chances are this counter will overflow during the life of the
2289 //process, but that's OK for our case. Means we get a little
2290 //more entropy.
2291 if (count++ % 100 == 0) {
2292 //Since the high bits seem to be zero's most of the time,
2293 //let's only take the lowest half of the point structure.
2294 PRInt16 myCoord[2];
2296 myCoord[0] = aVisitor.mEvent->refPoint.x;
2297 myCoord[1] = aVisitor.mEvent->refPoint.y;
2298 gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
2299 gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
2300 sizeof(PRUint32));
2302 } else if (msg == NS_RESIZE_EVENT) {
2303 mIsHandlingResizeEvent = PR_TRUE;
2304 } else if (msg == NS_MOUSE_BUTTON_DOWN &&
2305 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2306 gMouseDown = PR_TRUE;
2307 } else if (msg == NS_MOUSE_BUTTON_UP &&
2308 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2309 gMouseDown = PR_FALSE;
2310 if (gDragServiceDisabled) {
2311 nsCOMPtr<nsIDragService> ds =
2312 do_GetService("@mozilla.org/widget/dragservice;1");
2313 if (ds) {
2314 gDragServiceDisabled = PR_FALSE;
2315 ds->Unsuppress();
2320 aVisitor.mParentTarget = GetParentTarget();
2321 return NS_OK;
2324 nsresult
2325 nsGlobalWindow::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
2327 NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
2329 // Return early if there is nothing to do.
2330 switch (aVisitor.mEvent->message) {
2331 case NS_RESIZE_EVENT:
2332 case NS_PAGE_UNLOAD:
2333 case NS_LOAD:
2334 break;
2335 default:
2336 return NS_OK;
2339 /* mChromeEventHandler and mContext go dangling in the middle of this
2340 function under some circumstances (events that destroy the window)
2341 without this addref. */
2342 nsCOMPtr<nsPIDOMEventTarget> kungFuDeathGrip1(mChromeEventHandler);
2343 nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
2345 if (aVisitor.mEvent->message == NS_RESIZE_EVENT) {
2346 mIsHandlingResizeEvent = PR_FALSE;
2347 } else if (aVisitor.mEvent->message == NS_PAGE_UNLOAD &&
2348 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2349 // Execute bindingdetached handlers before we tear ourselves
2350 // down.
2351 if (mDocument) {
2352 NS_ASSERTION(mDoc, "Must have doc");
2353 mDoc->BindingManager()->ExecuteDetachedHandlers();
2355 mIsDocumentLoaded = PR_FALSE;
2356 } else if (aVisitor.mEvent->message == NS_LOAD &&
2357 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2358 // This is page load event since load events don't propagate to |window|.
2359 // @see nsDocument::PreHandleEvent.
2360 mIsDocumentLoaded = PR_TRUE;
2362 nsCOMPtr<nsIContent> content(do_QueryInterface(GetFrameElementInternal()));
2363 nsCOMPtr<nsIDocShellTreeItem> treeItem =
2364 do_QueryInterface(GetDocShell());
2366 PRInt32 itemType = nsIDocShellTreeItem::typeChrome;
2368 if (treeItem) {
2369 treeItem->GetItemType(&itemType);
2372 if (content && GetParentInternal() &&
2373 itemType != nsIDocShellTreeItem::typeChrome) {
2374 // If we're not in chrome, or at a chrome boundary, fire the
2375 // onload event for the frame element.
2377 nsEventStatus status = nsEventStatus_eIgnore;
2378 nsEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), NS_LOAD);
2379 event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
2381 // Most of the time we could get a pres context to pass in here,
2382 // but not always (i.e. if this window is not shown there won't
2383 // be a pres context available). Since we're not firing a GUI
2384 // event we don't need a pres context anyway so we just pass
2385 // null as the pres context all the time here.
2387 nsEventDispatcher::Dispatch(content, nsnull, &event, nsnull, &status);
2391 return NS_OK;
2394 nsresult
2395 nsGlobalWindow::DispatchDOMEvent(nsEvent* aEvent,
2396 nsIDOMEvent* aDOMEvent,
2397 nsPresContext* aPresContext,
2398 nsEventStatus* aEventStatus)
2400 return
2401 nsEventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow*>(this),
2402 aEvent, aDOMEvent, aPresContext,
2403 aEventStatus);
2406 void
2407 nsGlobalWindow::OnFinalize(PRUint32 aLangID, void *aObject)
2409 NS_ASSERTION(aLangID == nsIProgrammingLanguage::JAVASCRIPT,
2410 "We don't support this language ID");
2412 if (aObject == mJSObject) {
2413 mJSObject = nsnull;
2417 void
2418 nsGlobalWindow::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
2420 FORWARD_TO_INNER_VOID(SetScriptsEnabled, (aEnabled, aFireTimeouts));
2422 if (aEnabled && aFireTimeouts) {
2423 // Scripts are enabled (again?) on this context, run timeouts that
2424 // fired on this context while scripts were disabled.
2425 void (nsGlobalWindow::*run)() = &nsGlobalWindow::RunTimeout;
2426 NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, run));
2430 nsresult
2431 nsGlobalWindow::SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin)
2433 FORWARD_TO_OUTER(SetArguments, (aArguments, aOrigin),
2434 NS_ERROR_NOT_INITIALIZED);
2436 // Hold on to the arguments so that we can re-set them once the next
2437 // document is loaded.
2438 mArguments = aArguments;
2439 mArgumentsOrigin = aOrigin;
2441 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
2443 if (!mIsModalContentWindow) {
2444 mArgumentsLast = aArguments;
2445 } else if (currentInner) {
2446 // SetArguments() is being called on a modal content window that
2447 // already has an inner window. This can happen when loading
2448 // javascript: URIs as modal content dialogs. In this case, we'll
2449 // set up the dialog window, both inner and outer, before we call
2450 // SetArguments() on the window, so to deal with that, make sure
2451 // here that the arguments are propagated to the inner window.
2453 currentInner->mArguments = aArguments;
2454 currentInner->mArgumentsOrigin = aOrigin;
2457 return currentInner ?
2458 currentInner->DefineArgumentsProperty(aArguments) : NS_OK;
2461 nsresult
2462 nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
2464 JSContext *cx;
2465 nsIScriptContext *ctx = GetOuterWindowInternal()->mContext;
2466 NS_ENSURE_TRUE(aArguments && ctx &&
2467 (cx = (JSContext *)ctx->GetNativeContext()),
2468 NS_ERROR_NOT_INITIALIZED);
2470 if (mIsModalContentWindow) {
2471 // Modal content windows don't have an "arguments" property, they
2472 // have a "dialogArguments" property which is handled
2473 // separately. See nsWindowSH::NewResolve().
2475 return NS_OK;
2478 return GetContextInternal()->SetProperty(mJSObject, "arguments", aArguments);
2481 //*****************************************************************************
2482 // nsGlobalWindow::nsIScriptObjectPrincipal
2483 //*****************************************************************************
2485 nsIPrincipal*
2486 nsGlobalWindow::GetPrincipal()
2488 if (mDoc) {
2489 // If we have a document, get the principal from the document
2490 return mDoc->NodePrincipal();
2493 if (mDocumentPrincipal) {
2494 return mDocumentPrincipal;
2497 // If we don't have a principal and we don't have a document we
2498 // ask the parent window for the principal. This can happen when
2499 // loading a frameset that has a <frame src="javascript:xxx">, in
2500 // that case the global window is used in JS before we've loaded
2501 // a document into the window.
2503 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2504 do_QueryInterface(GetParentInternal());
2506 if (objPrincipal) {
2507 return objPrincipal->GetPrincipal();
2510 return nsnull;
2513 //*****************************************************************************
2514 // nsGlobalWindow::nsIDOMWindow
2515 //*****************************************************************************
2517 NS_IMETHODIMP
2518 nsGlobalWindow::GetDocument(nsIDOMDocument** aDocument)
2520 // This method *should* forward calls to the outer window, but since
2521 // there's nothing here that *depends* on anything in the outer
2522 // (GetDocShell() eliminates that dependency), we won't do that to
2523 // avoid the extra virtual function call.
2525 // lazily instantiate an about:blank document if necessary, and if
2526 // we have what it takes to do so. Note that domdoc here is the same
2527 // thing as our mDocument, but we don't have to explicitly set the
2528 // member variable because the docshell has already called
2529 // SetNewDocument().
2530 nsIDocShell *docShell;
2531 if (!mDocument && (docShell = GetDocShell()))
2532 nsCOMPtr<nsIDOMDocument> domdoc(do_GetInterface(docShell));
2534 NS_IF_ADDREF(*aDocument = mDocument);
2536 return NS_OK;
2539 //*****************************************************************************
2540 // nsGlobalWindow::nsIDOMWindowInternal
2541 //*****************************************************************************
2543 NS_IMETHODIMP
2544 nsGlobalWindow::GetWindow(nsIDOMWindowInternal** aWindow)
2546 FORWARD_TO_OUTER(GetWindow, (aWindow), NS_ERROR_NOT_INITIALIZED);
2548 *aWindow = static_cast<nsIDOMWindowInternal *>(this);
2549 NS_ADDREF(*aWindow);
2550 return NS_OK;
2553 NS_IMETHODIMP
2554 nsGlobalWindow::GetSelf(nsIDOMWindowInternal** aWindow)
2556 FORWARD_TO_OUTER(GetSelf, (aWindow), NS_ERROR_NOT_INITIALIZED);
2558 *aWindow = static_cast<nsIDOMWindowInternal *>(this);
2559 NS_ADDREF(*aWindow);
2560 return NS_OK;
2563 NS_IMETHODIMP
2564 nsGlobalWindow::GetNavigator(nsIDOMNavigator** aNavigator)
2566 FORWARD_TO_OUTER(GetNavigator, (aNavigator), NS_ERROR_NOT_INITIALIZED);
2568 *aNavigator = nsnull;
2570 if (!mNavigator) {
2571 mNavigator = new nsNavigator(mDocShell);
2572 if (!mNavigator) {
2573 return NS_ERROR_OUT_OF_MEMORY;
2577 NS_ADDREF(*aNavigator = mNavigator);
2579 return NS_OK;
2582 NS_IMETHODIMP
2583 nsGlobalWindow::GetScreen(nsIDOMScreen** aScreen)
2585 FORWARD_TO_OUTER(GetScreen, (aScreen), NS_ERROR_NOT_INITIALIZED);
2587 *aScreen = nsnull;
2589 if (!mScreen && mDocShell) {
2590 mScreen = new nsScreen(mDocShell);
2591 if (!mScreen) {
2592 return NS_ERROR_OUT_OF_MEMORY;
2596 NS_IF_ADDREF(*aScreen = mScreen);
2598 return NS_OK;
2601 NS_IMETHODIMP
2602 nsGlobalWindow::GetHistory(nsIDOMHistory** aHistory)
2604 FORWARD_TO_OUTER(GetHistory, (aHistory), NS_ERROR_NOT_INITIALIZED);
2606 *aHistory = nsnull;
2608 if (!mHistory && mDocShell) {
2609 mHistory = new nsHistory(mDocShell);
2610 if (!mHistory) {
2611 return NS_ERROR_OUT_OF_MEMORY;
2615 NS_IF_ADDREF(*aHistory = mHistory);
2616 return NS_OK;
2619 NS_IMETHODIMP
2620 nsGlobalWindow::GetParent(nsIDOMWindow** aParent)
2622 FORWARD_TO_OUTER(GetParent, (aParent), NS_ERROR_NOT_INITIALIZED);
2624 *aParent = nsnull;
2625 if (!mDocShell)
2626 return NS_OK;
2628 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
2629 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
2631 nsCOMPtr<nsIDocShellTreeItem> parent;
2632 docShellAsItem->GetSameTypeParent(getter_AddRefs(parent));
2634 if (parent) {
2635 nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(parent));
2636 NS_ENSURE_SUCCESS(CallQueryInterface(globalObject.get(), aParent),
2637 NS_ERROR_FAILURE);
2639 else {
2640 *aParent = static_cast<nsIDOMWindowInternal *>(this);
2641 NS_ADDREF(*aParent);
2643 return NS_OK;
2646 NS_IMETHODIMP
2647 nsGlobalWindow::GetTop(nsIDOMWindow** aTop)
2649 FORWARD_TO_OUTER(GetTop, (aTop), NS_ERROR_NOT_INITIALIZED);
2651 nsresult ret = NS_OK;
2653 *aTop = nsnull;
2654 if (mDocShell) {
2655 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
2656 nsCOMPtr<nsIDocShellTreeItem> root;
2657 docShellAsItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
2659 if (root) {
2660 nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(root));
2661 CallQueryInterface(globalObject.get(), aTop);
2665 return ret;
2668 NS_IMETHODIMP
2669 nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
2671 FORWARD_TO_OUTER(GetContent, (aContent), NS_ERROR_NOT_INITIALIZED);
2673 *aContent = nsnull;
2675 nsCOMPtr<nsIDocShellTreeItem> primaryContent;
2677 if (!nsContentUtils::IsCallerChrome()) {
2678 // If we're called by non-chrome code, make sure we don't return
2679 // the primary content window if the calling tab is hidden. In
2680 // such a case we return the same-type root in the hidden tab,
2681 // which is "good enough", for now.
2682 nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
2684 if (baseWin) {
2685 PRBool visible = PR_FALSE;
2686 baseWin->GetVisibility(&visible);
2688 if (!visible) {
2689 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
2691 treeItem->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
2696 if (!primaryContent) {
2697 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
2698 GetTreeOwner(getter_AddRefs(treeOwner));
2699 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
2701 treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
2704 nsCOMPtr<nsIDOMWindowInternal> domWindow(do_GetInterface(primaryContent));
2705 NS_IF_ADDREF(*aContent = domWindow);
2707 return NS_OK;
2710 NS_IMETHODIMP
2711 nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
2713 FORWARD_TO_OUTER(GetPrompter, (aPrompt), NS_ERROR_NOT_INITIALIZED);
2715 if (!mDocShell)
2716 return NS_ERROR_FAILURE;
2718 nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
2719 NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE);
2721 NS_ADDREF(*aPrompt = prompter);
2722 return NS_OK;
2725 NS_IMETHODIMP
2726 nsGlobalWindow::GetMenubar(nsIDOMBarProp** aMenubar)
2728 FORWARD_TO_OUTER(GetMenubar, (aMenubar), NS_ERROR_NOT_INITIALIZED);
2730 *aMenubar = nsnull;
2732 if (!mMenubar) {
2733 mMenubar = new nsMenubarProp();
2734 if (!mMenubar) {
2735 return NS_ERROR_OUT_OF_MEMORY;
2738 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2739 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2741 mMenubar->SetWebBrowserChrome(browserChrome);
2744 NS_ADDREF(*aMenubar = mMenubar);
2746 return NS_OK;
2749 NS_IMETHODIMP
2750 nsGlobalWindow::GetToolbar(nsIDOMBarProp** aToolbar)
2752 FORWARD_TO_OUTER(GetToolbar, (aToolbar), NS_ERROR_NOT_INITIALIZED);
2754 *aToolbar = nsnull;
2756 if (!mToolbar) {
2757 mToolbar = new nsToolbarProp();
2758 if (!mToolbar) {
2759 return NS_ERROR_OUT_OF_MEMORY;
2762 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2763 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2765 mToolbar->SetWebBrowserChrome(browserChrome);
2768 NS_ADDREF(*aToolbar = mToolbar);
2770 return NS_OK;
2773 NS_IMETHODIMP
2774 nsGlobalWindow::GetLocationbar(nsIDOMBarProp** aLocationbar)
2776 FORWARD_TO_OUTER(GetLocationbar, (aLocationbar), NS_ERROR_NOT_INITIALIZED);
2778 *aLocationbar = nsnull;
2780 if (!mLocationbar) {
2781 mLocationbar = new nsLocationbarProp();
2782 if (!mLocationbar) {
2783 return NS_ERROR_OUT_OF_MEMORY;
2786 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2787 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2789 mLocationbar->SetWebBrowserChrome(browserChrome);
2792 NS_ADDREF(*aLocationbar = mLocationbar);
2794 return NS_OK;
2797 NS_IMETHODIMP
2798 nsGlobalWindow::GetPersonalbar(nsIDOMBarProp** aPersonalbar)
2800 FORWARD_TO_OUTER(GetPersonalbar, (aPersonalbar), NS_ERROR_NOT_INITIALIZED);
2802 *aPersonalbar = nsnull;
2804 if (!mPersonalbar) {
2805 mPersonalbar = new nsPersonalbarProp();
2806 if (!mPersonalbar) {
2807 return NS_ERROR_OUT_OF_MEMORY;
2810 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2811 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2813 mPersonalbar->SetWebBrowserChrome(browserChrome);
2816 NS_ADDREF(*aPersonalbar = mPersonalbar);
2818 return NS_OK;
2821 NS_IMETHODIMP
2822 nsGlobalWindow::GetStatusbar(nsIDOMBarProp** aStatusbar)
2824 FORWARD_TO_OUTER(GetStatusbar, (aStatusbar), NS_ERROR_NOT_INITIALIZED);
2826 *aStatusbar = nsnull;
2828 if (!mStatusbar) {
2829 mStatusbar = new nsStatusbarProp();
2830 if (!mStatusbar) {
2831 return NS_ERROR_OUT_OF_MEMORY;
2834 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2835 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2837 mStatusbar->SetWebBrowserChrome(browserChrome);
2840 NS_ADDREF(*aStatusbar = mStatusbar);
2842 return NS_OK;
2845 NS_IMETHODIMP
2846 nsGlobalWindow::GetScrollbars(nsIDOMBarProp** aScrollbars)
2848 FORWARD_TO_OUTER(GetScrollbars, (aScrollbars), NS_ERROR_NOT_INITIALIZED);
2850 *aScrollbars = nsnull;
2852 if (!mScrollbars) {
2853 mScrollbars = new nsScrollbarsProp(this);
2854 if (!mScrollbars) {
2855 return NS_ERROR_OUT_OF_MEMORY;
2858 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2859 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2861 mScrollbars->SetWebBrowserChrome(browserChrome);
2864 NS_ADDREF(*aScrollbars = mScrollbars);
2866 return NS_OK;
2869 NS_IMETHODIMP
2870 nsGlobalWindow::GetClosed(PRBool* aClosed)
2872 FORWARD_TO_OUTER(GetClosed, (aClosed), NS_ERROR_NOT_INITIALIZED);
2874 // If someone called close(), or if we don't have a docshell, we're
2875 // closed.
2876 *aClosed = mIsClosed || !mDocShell;
2878 return NS_OK;
2881 NS_IMETHODIMP
2882 nsGlobalWindow::GetFrames(nsIDOMWindowCollection** aFrames)
2884 FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
2886 *aFrames = nsnull;
2888 if (!mFrames && mDocShell) {
2889 mFrames = new nsDOMWindowList(mDocShell);
2890 if (!mFrames) {
2891 return NS_ERROR_OUT_OF_MEMORY;
2895 *aFrames = static_cast<nsIDOMWindowCollection *>(mFrames);
2896 NS_IF_ADDREF(*aFrames);
2897 return NS_OK;
2900 NS_IMETHODIMP
2901 nsGlobalWindow::GetApplicationCache(nsIDOMOfflineResourceList **aApplicationCache)
2903 FORWARD_TO_INNER(GetApplicationCache, (aApplicationCache), NS_ERROR_UNEXPECTED);
2905 NS_ENSURE_ARG_POINTER(aApplicationCache);
2907 if (!mApplicationCache) {
2908 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
2909 if (!webNav) {
2910 return NS_ERROR_FAILURE;
2913 nsCOMPtr<nsIURI> uri;
2914 nsresult rv = webNav->GetCurrentURI(getter_AddRefs(uri));
2915 NS_ENSURE_SUCCESS(rv, rv);
2917 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
2918 nsCOMPtr<nsIURI> manifestURI;
2919 nsContentUtils::GetOfflineAppManifest(doc, getter_AddRefs(manifestURI));
2921 nsIScriptContext* scriptContext = GetContext();
2922 NS_ENSURE_STATE(scriptContext);
2924 nsRefPtr<nsDOMOfflineResourceList> applicationCache =
2925 new nsDOMOfflineResourceList(manifestURI, uri, this, scriptContext);
2926 NS_ENSURE_TRUE(applicationCache, NS_ERROR_OUT_OF_MEMORY);
2928 applicationCache->Init();
2930 mApplicationCache = applicationCache;
2933 NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
2935 return NS_OK;
2938 NS_IMETHODIMP
2939 nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
2941 FORWARD_TO_OUTER(GetCrypto, (aCrypto), NS_ERROR_NOT_INITIALIZED);
2943 if (!mCrypto) {
2944 mCrypto = do_CreateInstance(kCryptoContractID);
2947 NS_IF_ADDREF(*aCrypto = mCrypto);
2949 return NS_OK;
2952 NS_IMETHODIMP
2953 nsGlobalWindow::GetPkcs11(nsIDOMPkcs11** aPkcs11)
2955 *aPkcs11 = nsnull;
2956 return NS_OK;
2959 NS_IMETHODIMP
2960 nsGlobalWindow::GetControllers(nsIControllers** aResult)
2962 FORWARD_TO_OUTER(GetControllers, (aResult), NS_ERROR_NOT_INITIALIZED);
2964 if (!mControllers) {
2965 nsresult rv;
2966 mControllers = do_CreateInstance(kXULControllersCID, &rv);
2967 NS_ENSURE_SUCCESS(rv, rv);
2969 // Add in the default controller
2970 nsCOMPtr<nsIController> controller = do_CreateInstance(
2971 NS_WINDOWCONTROLLER_CONTRACTID, &rv);
2972 NS_ENSURE_SUCCESS(rv, rv);
2974 mControllers->InsertControllerAt(0, controller);
2975 nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
2976 if (!controllerContext) return NS_ERROR_FAILURE;
2978 controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
2981 *aResult = mControllers;
2982 NS_ADDREF(*aResult);
2983 return NS_OK;
2986 NS_IMETHODIMP
2987 nsGlobalWindow::GetOpener(nsIDOMWindowInternal** aOpener)
2989 FORWARD_TO_OUTER(GetOpener, (aOpener), NS_ERROR_NOT_INITIALIZED);
2991 *aOpener = nsnull;
2993 nsCOMPtr<nsPIDOMWindow> opener = do_QueryReferent(mOpener);
2994 if (!opener) {
2995 return NS_OK;
2998 // First, check if we were called from a privileged chrome script
2999 if (nsContentUtils::IsCallerTrustedForRead()) {
3000 NS_ADDREF(*aOpener = opener);
3001 return NS_OK;
3004 nsCOMPtr<nsPIDOMWindow> openerPwin(do_QueryInterface(opener));
3005 if (!openerPwin) {
3006 return NS_OK;
3009 // First, ensure that we're not handing back a chrome window.
3010 nsGlobalWindow *win = static_cast<nsGlobalWindow *>(openerPwin.get());
3011 if (win->IsChromeWindow()) {
3012 return NS_OK;
3015 // We don't want to reveal the opener if the opener is a mail window,
3016 // because opener can be used to spoof the contents of a message (bug 105050).
3017 // So, we look in the opener's root docshell to see if it's a mail window.
3018 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
3019 do_QueryInterface(openerPwin->GetDocShell());
3021 if (docShellAsItem) {
3022 nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
3023 docShellAsItem->GetRootTreeItem(getter_AddRefs(openerRootItem));
3024 nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
3025 if (openerRootDocShell) {
3026 PRUint32 appType;
3027 nsresult rv = openerRootDocShell->GetAppType(&appType);
3028 if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
3029 *aOpener = opener;
3034 NS_IF_ADDREF(*aOpener);
3035 return NS_OK;
3038 NS_IMETHODIMP
3039 nsGlobalWindow::SetOpener(nsIDOMWindowInternal* aOpener)
3041 // check if we were called from a privileged chrome script.
3042 // If not, opener is settable only to null.
3043 if (aOpener && !nsContentUtils::IsCallerTrustedForWrite()) {
3044 return NS_OK;
3047 SetOpenerWindow(aOpener, PR_FALSE);
3049 return NS_OK;
3052 NS_IMETHODIMP
3053 nsGlobalWindow::GetStatus(nsAString& aStatus)
3055 FORWARD_TO_OUTER(GetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
3057 aStatus = mStatus;
3058 return NS_OK;
3061 NS_IMETHODIMP
3062 nsGlobalWindow::SetStatus(const nsAString& aStatus)
3064 FORWARD_TO_OUTER(SetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
3067 * If caller is not chrome and dom.disable_window_status_change is true,
3068 * prevent setting window.status by exiting early
3071 if (!CanSetProperty("dom.disable_window_status_change")) {
3072 return NS_OK;
3075 mStatus = aStatus;
3077 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3078 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3079 if(browserChrome) {
3080 browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
3081 PromiseFlatString(aStatus).get());
3084 return NS_OK;
3087 NS_IMETHODIMP
3088 nsGlobalWindow::GetDefaultStatus(nsAString& aDefaultStatus)
3090 FORWARD_TO_OUTER(GetDefaultStatus, (aDefaultStatus),
3091 NS_ERROR_NOT_INITIALIZED);
3093 aDefaultStatus = mDefaultStatus;
3094 return NS_OK;
3097 NS_IMETHODIMP
3098 nsGlobalWindow::SetDefaultStatus(const nsAString& aDefaultStatus)
3100 FORWARD_TO_OUTER(SetDefaultStatus, (aDefaultStatus),
3101 NS_ERROR_NOT_INITIALIZED);
3104 * If caller is not chrome and dom.disable_window_status_change is true,
3105 * prevent setting window.defaultStatus by exiting early
3108 if (!CanSetProperty("dom.disable_window_status_change")) {
3109 return NS_OK;
3112 mDefaultStatus = aDefaultStatus;
3114 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3115 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3116 if (browserChrome) {
3117 browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT_DEFAULT,
3118 PromiseFlatString(aDefaultStatus).get());
3121 return NS_OK;
3124 NS_IMETHODIMP
3125 nsGlobalWindow::GetName(nsAString& aName)
3127 FORWARD_TO_OUTER(GetName, (aName), NS_ERROR_NOT_INITIALIZED);
3129 nsXPIDLString name;
3130 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3131 if (docShellAsItem)
3132 docShellAsItem->GetName(getter_Copies(name));
3134 aName.Assign(name);
3135 return NS_OK;
3138 NS_IMETHODIMP
3139 nsGlobalWindow::SetName(const nsAString& aName)
3141 FORWARD_TO_OUTER(SetName, (aName), NS_ERROR_NOT_INITIALIZED);
3143 nsresult result = NS_OK;
3144 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3145 if (docShellAsItem)
3146 result = docShellAsItem->SetName(PromiseFlatString(aName).get());
3147 return result;
3150 // Helper functions used by many methods below.
3151 PRInt32
3152 nsGlobalWindow::DevToCSSIntPixels(PRInt32 px)
3154 if (!mDocShell)
3155 return px; // assume 1:1
3157 nsRefPtr<nsPresContext> presContext;
3158 mDocShell->GetPresContext(getter_AddRefs(presContext));
3159 if (!presContext)
3160 return px;
3162 return presContext->DevPixelsToIntCSSPixels(px);
3165 PRInt32
3166 nsGlobalWindow::CSSToDevIntPixels(PRInt32 px)
3168 if (!mDocShell)
3169 return px; // assume 1:1
3171 nsRefPtr<nsPresContext> presContext;
3172 mDocShell->GetPresContext(getter_AddRefs(presContext));
3173 if (!presContext)
3174 return px;
3176 return presContext->CSSPixelsToDevPixels(px);
3179 nsIntSize
3180 nsGlobalWindow::DevToCSSIntPixels(nsIntSize px)
3182 if (!mDocShell)
3183 return px; // assume 1:1
3185 nsRefPtr<nsPresContext> presContext;
3186 mDocShell->GetPresContext(getter_AddRefs(presContext));
3187 if (!presContext)
3188 return px;
3190 return nsIntSize(
3191 presContext->DevPixelsToIntCSSPixels(px.width),
3192 presContext->DevPixelsToIntCSSPixels(px.height));
3195 nsIntSize
3196 nsGlobalWindow::CSSToDevIntPixels(nsIntSize px)
3198 if (!mDocShell)
3199 return px; // assume 1:1
3201 nsRefPtr<nsPresContext> presContext;
3202 mDocShell->GetPresContext(getter_AddRefs(presContext));
3203 if (!presContext)
3204 return px;
3206 return nsIntSize(
3207 presContext->CSSPixelsToDevPixels(px.width),
3208 presContext->CSSPixelsToDevPixels(px.height));
3212 NS_IMETHODIMP
3213 nsGlobalWindow::GetInnerWidth(PRInt32* aInnerWidth)
3215 FORWARD_TO_OUTER(GetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
3217 NS_ENSURE_STATE(mDocShell);
3219 EnsureSizeUpToDate();
3221 nsCOMPtr<nsIBaseWindow> docShellWin(do_QueryInterface(mDocShell));
3222 nsRefPtr<nsPresContext> presContext;
3223 mDocShell->GetPresContext(getter_AddRefs(presContext));
3225 if (docShellWin && presContext) {
3226 PRInt32 width, notused;
3227 docShellWin->GetSize(&width, &notused);
3228 *aInnerWidth = nsPresContext::
3229 AppUnitsToIntCSSPixels(presContext->DevPixelsToAppUnits(width));
3230 } else {
3231 *aInnerWidth = 0;
3234 return NS_OK;
3237 NS_IMETHODIMP
3238 nsGlobalWindow::SetInnerWidth(PRInt32 aInnerWidth)
3240 FORWARD_TO_OUTER(SetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
3242 NS_ENSURE_STATE(mDocShell);
3245 * If caller is not chrome and the user has not explicitly exempted the site,
3246 * prevent setting window.innerWidth by exiting early
3249 if (!CanMoveResizeWindows() || IsFrame()) {
3250 return NS_OK;
3253 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3254 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
3256 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
3257 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
3258 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
3260 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aInnerWidth, nsnull),
3261 NS_ERROR_FAILURE);
3263 PRInt32 width = CSSToDevIntPixels(aInnerWidth);
3265 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3266 PRInt32 notused, height = 0;
3267 docShellAsWin->GetSize(&notused, &height);
3269 NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, width, height),
3270 NS_ERROR_FAILURE);
3272 return NS_OK;
3275 NS_IMETHODIMP
3276 nsGlobalWindow::GetInnerHeight(PRInt32* aInnerHeight)
3278 FORWARD_TO_OUTER(GetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
3280 NS_ENSURE_STATE(mDocShell);
3282 EnsureSizeUpToDate();
3284 nsCOMPtr<nsIBaseWindow> docShellWin(do_QueryInterface(mDocShell));
3285 nsRefPtr<nsPresContext> presContext;
3286 mDocShell->GetPresContext(getter_AddRefs(presContext));
3288 if (docShellWin && presContext) {
3289 PRInt32 height, notused;
3290 docShellWin->GetSize(&notused, &height);
3291 *aInnerHeight = nsPresContext::
3292 AppUnitsToIntCSSPixels(presContext->DevPixelsToAppUnits(height));
3293 } else {
3294 *aInnerHeight = 0;
3296 return NS_OK;
3299 NS_IMETHODIMP
3300 nsGlobalWindow::SetInnerHeight(PRInt32 aInnerHeight)
3302 FORWARD_TO_OUTER(SetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
3304 NS_ENSURE_STATE(mDocShell);
3307 * If caller is not chrome and the user has not explicitly exempted the site,
3308 * prevent setting window.innerHeight by exiting early
3311 if (!CanMoveResizeWindows() || IsFrame()) {
3312 return NS_OK;
3315 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3316 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
3318 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
3319 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
3320 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
3322 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(nsnull, &aInnerHeight),
3323 NS_ERROR_FAILURE);
3325 PRInt32 height = CSSToDevIntPixels(aInnerHeight);
3327 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3328 PRInt32 width = 0, notused;
3329 docShellAsWin->GetSize(&width, &notused);
3331 NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, width, height),
3332 NS_ERROR_FAILURE);
3334 return NS_OK;
3337 nsresult
3338 nsGlobalWindow::GetOuterSize(nsIntSize* aSizeCSSPixels)
3340 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3341 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3342 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3344 nsGlobalWindow* rootWindow =
3345 static_cast<nsGlobalWindow *>(GetPrivateRoot());
3346 if (rootWindow) {
3347 rootWindow->FlushPendingNotifications(Flush_Layout);
3350 nsIntSize sizeDevPixels;
3351 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&sizeDevPixels.width,
3352 &sizeDevPixels.height),
3353 NS_ERROR_FAILURE);
3355 *aSizeCSSPixels = DevToCSSIntPixels(sizeDevPixels);
3356 return NS_OK;
3359 NS_IMETHODIMP
3360 nsGlobalWindow::GetOuterWidth(PRInt32* aOuterWidth)
3362 FORWARD_TO_OUTER(GetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
3364 nsIntSize sizeCSSPixels;
3365 nsresult rv = GetOuterSize(&sizeCSSPixels);
3366 NS_ENSURE_SUCCESS(rv, rv);
3368 *aOuterWidth = sizeCSSPixels.width;
3369 return NS_OK;
3372 NS_IMETHODIMP
3373 nsGlobalWindow::GetOuterHeight(PRInt32* aOuterHeight)
3375 FORWARD_TO_OUTER(GetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
3377 nsIntSize sizeCSSPixels;
3378 nsresult rv = GetOuterSize(&sizeCSSPixels);
3379 NS_ENSURE_SUCCESS(rv, rv);
3381 *aOuterHeight = sizeCSSPixels.height;
3382 return NS_OK;
3385 nsresult
3386 nsGlobalWindow::SetOuterSize(PRInt32 aLengthCSSPixels, PRBool aIsWidth)
3389 * If caller is not chrome and the user has not explicitly exempted the site,
3390 * prevent setting window.outerWidth by exiting early
3393 if (!CanMoveResizeWindows() || IsFrame()) {
3394 return NS_OK;
3397 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3398 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3399 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3401 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(
3402 aIsWidth ? &aLengthCSSPixels : nsnull,
3403 aIsWidth ? nsnull : &aLengthCSSPixels),
3404 NS_ERROR_FAILURE);
3406 PRInt32 width, height;
3407 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&width, &height), NS_ERROR_FAILURE);
3409 PRInt32 lengthDevPixels = CSSToDevIntPixels(aLengthCSSPixels);
3410 if (aIsWidth) {
3411 width = lengthDevPixels;
3412 } else {
3413 height = lengthDevPixels;
3415 return treeOwnerAsWin->SetSize(width, height, PR_TRUE);
3418 NS_IMETHODIMP
3419 nsGlobalWindow::SetOuterWidth(PRInt32 aOuterWidth)
3421 FORWARD_TO_OUTER(SetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
3423 return SetOuterSize(aOuterWidth, PR_TRUE);
3426 NS_IMETHODIMP
3427 nsGlobalWindow::SetOuterHeight(PRInt32 aOuterHeight)
3429 FORWARD_TO_OUTER(SetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
3431 return SetOuterSize(aOuterHeight, PR_FALSE);
3434 NS_IMETHODIMP
3435 nsGlobalWindow::GetScreenX(PRInt32* aScreenX)
3437 FORWARD_TO_OUTER(GetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3439 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3440 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3441 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3443 PRInt32 x, y;
3445 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3446 NS_ERROR_FAILURE);
3448 *aScreenX = DevToCSSIntPixels(x);
3449 return NS_OK;
3452 nsRect
3453 nsGlobalWindow::GetInnerScreenRect()
3455 if (!mDocShell)
3456 return nsRect();
3458 nsGlobalWindow* rootWindow =
3459 static_cast<nsGlobalWindow*>(GetPrivateRoot());
3460 if (rootWindow) {
3461 rootWindow->FlushPendingNotifications(Flush_Layout);
3464 nsCOMPtr<nsIPresShell> presShell;
3465 mDocShell->GetPresShell(getter_AddRefs(presShell));
3466 if (!presShell)
3467 return nsRect();
3468 nsIFrame* rootFrame = presShell->GetRootFrame();
3469 if (!rootFrame)
3470 return nsRect();
3472 return rootFrame->GetScreenRectInAppUnits();
3475 NS_IMETHODIMP
3476 nsGlobalWindow::GetMozInnerScreenX(float* aScreenX)
3478 FORWARD_TO_OUTER(GetMozInnerScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3480 nsRect r = GetInnerScreenRect();
3481 *aScreenX = nsPresContext::AppUnitsToFloatCSSPixels(r.x);
3482 return NS_OK;
3485 NS_IMETHODIMP
3486 nsGlobalWindow::GetMozInnerScreenY(float* aScreenY)
3488 FORWARD_TO_OUTER(GetMozInnerScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3490 nsRect r = GetInnerScreenRect();
3491 *aScreenY = nsPresContext::AppUnitsToFloatCSSPixels(r.y);
3492 return NS_OK;
3495 NS_IMETHODIMP
3496 nsGlobalWindow::GetMozPaintCount(PRUint64* aResult)
3498 FORWARD_TO_OUTER(GetMozPaintCount, (aResult), NS_ERROR_NOT_INITIALIZED);
3500 *aResult = 0;
3502 if (!mDocShell)
3503 return NS_OK;
3505 nsCOMPtr<nsIPresShell> presShell;
3506 mDocShell->GetPresShell(getter_AddRefs(presShell));
3507 if (!presShell)
3508 return NS_OK;
3510 *aResult = presShell->GetPaintCount();
3511 return NS_OK;
3514 NS_IMETHODIMP
3515 nsGlobalWindow::SetScreenX(PRInt32 aScreenX)
3517 FORWARD_TO_OUTER(SetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3520 * If caller is not chrome and the user has not explicitly exempted the site,
3521 * prevent setting window.screenX by exiting early
3524 if (!CanMoveResizeWindows() || IsFrame()) {
3525 return NS_OK;
3528 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3529 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3530 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3532 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aScreenX, nsnull),
3533 NS_ERROR_FAILURE);
3535 PRInt32 x, y;
3536 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3537 NS_ERROR_FAILURE);
3539 x = CSSToDevIntPixels(aScreenX);
3541 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(x, y),
3542 NS_ERROR_FAILURE);
3544 return NS_OK;
3547 NS_IMETHODIMP
3548 nsGlobalWindow::GetScreenY(PRInt32* aScreenY)
3550 FORWARD_TO_OUTER(GetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3552 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3553 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3554 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3556 PRInt32 x, y;
3558 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3559 NS_ERROR_FAILURE);
3561 *aScreenY = DevToCSSIntPixels(y);
3562 return NS_OK;
3565 NS_IMETHODIMP
3566 nsGlobalWindow::SetScreenY(PRInt32 aScreenY)
3568 FORWARD_TO_OUTER(SetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3571 * If caller is not chrome and the user has not explicitly exempted the site,
3572 * prevent setting window.screenY by exiting early
3575 if (!CanMoveResizeWindows() || IsFrame()) {
3576 return NS_OK;
3579 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3580 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3581 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3583 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(nsnull, &aScreenY),
3584 NS_ERROR_FAILURE);
3586 PRInt32 x, y;
3587 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3588 NS_ERROR_FAILURE);
3590 y = CSSToDevIntPixels(aScreenY);
3592 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(x, y),
3593 NS_ERROR_FAILURE);
3595 return NS_OK;
3598 // NOTE: Arguments to this function should have values scaled to
3599 // CSS pixels, not device pixels.
3600 nsresult
3601 nsGlobalWindow::CheckSecurityWidthAndHeight(PRInt32* aWidth, PRInt32* aHeight)
3603 #ifdef MOZ_XUL
3604 if (!nsContentUtils::IsCallerTrustedForWrite()) {
3605 // if attempting to resize the window, hide any open popups
3606 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
3607 nsContentUtils::HidePopupsInDocument(doc);
3609 #endif
3611 // This one is easy. Just ensure the variable is greater than 100;
3612 if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
3613 // Check security state for use in determing window dimensions
3615 if (!nsContentUtils::IsCallerTrustedForWrite()) {
3616 //sec check failed
3617 if (aWidth && *aWidth < 100) {
3618 *aWidth = 100;
3620 if (aHeight && *aHeight < 100) {
3621 *aHeight = 100;
3626 return NS_OK;
3629 // NOTE: Arguments to this function should have values scaled to
3630 // CSS pixels, not device pixels.
3631 nsresult
3632 nsGlobalWindow::CheckSecurityLeftAndTop(PRInt32* aLeft, PRInt32* aTop)
3634 // This one is harder. We have to get the screen size and window dimensions.
3636 // Check security state for use in determing window dimensions
3638 if (!nsContentUtils::IsCallerTrustedForWrite()) {
3639 #ifdef MOZ_XUL
3640 // if attempting to move the window, hide any open popups
3641 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
3642 nsContentUtils::HidePopupsInDocument(doc);
3643 #endif
3645 nsGlobalWindow* rootWindow =
3646 static_cast<nsGlobalWindow*>(GetPrivateRoot());
3647 if (rootWindow) {
3648 rootWindow->FlushPendingNotifications(Flush_Layout);
3651 nsCOMPtr<nsIBaseWindow> treeOwner;
3652 GetTreeOwner(getter_AddRefs(treeOwner));
3654 nsCOMPtr<nsIDOMScreen> screen;
3655 GetScreen(getter_AddRefs(screen));
3657 if (treeOwner && screen) {
3658 PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
3659 PRInt32 winLeft, winTop, winWidth, winHeight;
3661 // Get the window size
3662 treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
3664 // convert those values to CSS pixels
3665 // XXX four separate retrievals of the prescontext
3666 winLeft = DevToCSSIntPixels(winLeft);
3667 winTop = DevToCSSIntPixels(winTop);
3668 winWidth = DevToCSSIntPixels(winWidth);
3669 winHeight = DevToCSSIntPixels(winHeight);
3671 // Get the screen dimensions
3672 // XXX This should use nsIScreenManager once it's fully fleshed out.
3673 screen->GetAvailLeft(&screenLeft);
3674 screen->GetAvailWidth(&screenWidth);
3675 screen->GetAvailHeight(&screenHeight);
3676 #if defined(XP_MAC) || defined(XP_MACOSX)
3677 /* The mac's coordinate system is different from the assumed Windows'
3678 system. It offsets by the height of the menubar so that a window
3679 placed at (0,0) will be entirely visible. Unfortunately that
3680 correction is made elsewhere (in Widget) and the meaning of
3681 the Avail... coordinates is overloaded. Here we allow a window
3682 to be placed at (0,0) because it does make sense to do so.
3684 screen->GetTop(&screenTop);
3685 #else
3686 screen->GetAvailTop(&screenTop);
3687 #endif
3689 if (aLeft) {
3690 if (screenLeft+screenWidth < *aLeft+winWidth)
3691 *aLeft = screenLeft+screenWidth - winWidth;
3692 if (screenLeft > *aLeft)
3693 *aLeft = screenLeft;
3695 if (aTop) {
3696 if (screenTop+screenHeight < *aTop+winHeight)
3697 *aTop = screenTop+screenHeight - winHeight;
3698 if (screenTop > *aTop)
3699 *aTop = screenTop;
3701 } else {
3702 if (aLeft)
3703 *aLeft = 0;
3704 if (aTop)
3705 *aTop = 0;
3709 return NS_OK;
3712 NS_IMETHODIMP
3713 nsGlobalWindow::GetPageXOffset(PRInt32* aPageXOffset)
3715 return GetScrollX(aPageXOffset);
3718 NS_IMETHODIMP
3719 nsGlobalWindow::GetPageYOffset(PRInt32* aPageYOffset)
3721 return GetScrollY(aPageYOffset);
3724 nsresult
3725 nsGlobalWindow::GetScrollMaxXY(PRInt32* aScrollMaxX, PRInt32* aScrollMaxY)
3727 FORWARD_TO_OUTER(GetScrollMaxXY, (aScrollMaxX, aScrollMaxY),
3728 NS_ERROR_NOT_INITIALIZED);
3730 FlushPendingNotifications(Flush_Layout);
3731 nsIScrollableFrame *sf = GetScrollFrame();
3732 if (!sf)
3733 return NS_OK;
3735 nsRect scrollRange = sf->GetScrollRange();
3737 if (aScrollMaxX)
3738 *aScrollMaxX = NS_MAX(0,
3739 (PRInt32)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.XMost())));
3740 if (aScrollMaxY)
3741 *aScrollMaxY = NS_MAX(0,
3742 (PRInt32)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.YMost())));
3744 return NS_OK;
3747 NS_IMETHODIMP
3748 nsGlobalWindow::GetScrollMaxX(PRInt32* aScrollMaxX)
3750 NS_ENSURE_ARG_POINTER(aScrollMaxX);
3751 *aScrollMaxX = 0;
3752 return GetScrollMaxXY(aScrollMaxX, nsnull);
3755 NS_IMETHODIMP
3756 nsGlobalWindow::GetScrollMaxY(PRInt32* aScrollMaxY)
3758 NS_ENSURE_ARG_POINTER(aScrollMaxY);
3759 *aScrollMaxY = 0;
3760 return GetScrollMaxXY(nsnull, aScrollMaxY);
3763 nsresult
3764 nsGlobalWindow::GetScrollXY(PRInt32* aScrollX, PRInt32* aScrollY,
3765 PRBool aDoFlush)
3767 FORWARD_TO_OUTER(GetScrollXY, (aScrollX, aScrollY, aDoFlush),
3768 NS_ERROR_NOT_INITIALIZED);
3770 if (aDoFlush) {
3771 FlushPendingNotifications(Flush_Layout);
3772 } else {
3773 EnsureSizeUpToDate();
3776 nsIScrollableFrame *sf = GetScrollFrame();
3777 if (!sf)
3778 return NS_OK;
3780 nsPoint scrollPos = sf->GetScrollPosition();
3781 if (scrollPos != nsPoint(0,0) && !aDoFlush) {
3782 // Oh, well. This is the expensive case -- the window is scrolled and we
3783 // didn't actually flush yet. Repeat, but with a flush, since the content
3784 // may get shorter and hence our scroll position may decrease.
3785 return GetScrollXY(aScrollX, aScrollY, PR_TRUE);
3788 if (aScrollX)
3789 *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
3790 if (aScrollY)
3791 *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
3793 return NS_OK;
3796 NS_IMETHODIMP
3797 nsGlobalWindow::GetScrollX(PRInt32* aScrollX)
3799 NS_ENSURE_ARG_POINTER(aScrollX);
3800 *aScrollX = 0;
3801 return GetScrollXY(aScrollX, nsnull, PR_FALSE);
3804 NS_IMETHODIMP
3805 nsGlobalWindow::GetScrollY(PRInt32* aScrollY)
3807 NS_ENSURE_ARG_POINTER(aScrollY);
3808 *aScrollY = 0;
3809 return GetScrollXY(nsnull, aScrollY, PR_FALSE);
3812 NS_IMETHODIMP
3813 nsGlobalWindow::GetLength(PRUint32* aLength)
3815 nsCOMPtr<nsIDOMWindowCollection> frames;
3816 if (NS_SUCCEEDED(GetFrames(getter_AddRefs(frames))) && frames) {
3817 return frames->GetLength(aLength);
3819 return NS_ERROR_FAILURE;
3822 PRBool
3823 nsGlobalWindow::DispatchCustomEvent(const char *aEventName)
3825 PRBool defaultActionEnabled = PR_TRUE;
3826 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
3827 nsContentUtils::DispatchTrustedEvent(doc,
3828 static_cast<nsIScriptGlobalObject*>(this),
3829 NS_ConvertASCIItoUTF16(aEventName),
3830 PR_TRUE, PR_TRUE, &defaultActionEnabled);
3832 return defaultActionEnabled;
3835 static already_AddRefed<nsIDocShellTreeItem>
3836 GetCallerDocShellTreeItem()
3838 JSContext *cx = nsContentUtils::GetCurrentJSContext();
3839 nsIDocShellTreeItem *callerItem = nsnull;
3841 if (cx) {
3842 nsCOMPtr<nsIWebNavigation> callerWebNav =
3843 do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
3845 if (callerWebNav) {
3846 CallQueryInterface(callerWebNav, &callerItem);
3850 return callerItem;
3853 PRBool
3854 nsGlobalWindow::WindowExists(const nsAString& aName,
3855 PRBool aLookForCallerOnJSStack)
3857 NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
3858 NS_PRECONDITION(mDocShell, "Must have docshell");
3860 nsCOMPtr<nsIDocShellTreeItem> caller;
3861 if (aLookForCallerOnJSStack) {
3862 caller = GetCallerDocShellTreeItem();
3865 nsCOMPtr<nsIDocShellTreeItem> docShell = do_QueryInterface(mDocShell);
3866 NS_ASSERTION(docShell,
3867 "Docshell doesn't implement nsIDocShellTreeItem?");
3869 if (!caller) {
3870 caller = docShell;
3873 nsCOMPtr<nsIDocShellTreeItem> namedItem;
3874 docShell->FindItemWithName(PromiseFlatString(aName).get(), nsnull, caller,
3875 getter_AddRefs(namedItem));
3876 return namedItem != nsnull;
3879 already_AddRefed<nsIWidget>
3880 nsGlobalWindow::GetMainWidget()
3882 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3883 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3885 nsIWidget *widget = nsnull;
3887 if (treeOwnerAsWin) {
3888 treeOwnerAsWin->GetMainWidget(&widget);
3891 return widget;
3894 nsIWidget*
3895 nsGlobalWindow::GetNearestWidget()
3897 nsIDocShell* docShell = GetDocShell();
3898 NS_ENSURE_TRUE(docShell, nsnull);
3899 nsCOMPtr<nsIPresShell> presShell;
3900 docShell->GetPresShell(getter_AddRefs(presShell));
3901 NS_ENSURE_TRUE(presShell, nsnull);
3902 nsIFrame* rootFrame = presShell->GetRootFrame();
3903 NS_ENSURE_TRUE(rootFrame, nsnull);
3904 return rootFrame->GetView()->GetNearestWidget(nsnull);
3907 NS_IMETHODIMP
3908 nsGlobalWindow::SetFullScreen(PRBool aFullScreen)
3910 FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
3912 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
3914 PRBool rootWinFullScreen;
3915 GetFullScreen(&rootWinFullScreen);
3916 // Only chrome can change our fullScreen mode.
3917 if (aFullScreen == rootWinFullScreen ||
3918 !nsContentUtils::IsCallerTrustedForWrite()) {
3919 return NS_OK;
3922 // SetFullScreen needs to be called on the root window, so get that
3923 // via the DocShell tree, and if we are not already the root,
3924 // call SetFullScreen on that window instead.
3925 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
3926 nsCOMPtr<nsIDocShellTreeItem> rootItem;
3927 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
3928 nsCOMPtr<nsIDOMWindowInternal> window = do_GetInterface(rootItem);
3929 if (!window)
3930 return NS_ERROR_FAILURE;
3931 if (rootItem != treeItem)
3932 return window->SetFullScreen(aFullScreen);
3934 // make sure we don't try to set full screen on a non-chrome window,
3935 // which might happen in embedding world
3936 PRInt32 itemType;
3937 treeItem->GetItemType(&itemType);
3938 if (itemType != nsIDocShellTreeItem::typeChrome)
3939 return NS_ERROR_FAILURE;
3941 // dispatch a "fullscreen" DOM event so that XUL apps can
3942 // respond visually if we are kicked into full screen mode
3943 if (!DispatchCustomEvent("fullscreen")) {
3944 return NS_OK;
3947 // Prevent chrome documents which are still loading from resizing
3948 // the window after we set fullscreen mode.
3949 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3950 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3951 nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwnerAsWin));
3952 if (aFullScreen && xulWin) {
3953 xulWin->SetIntrinsicallySized(PR_FALSE);
3956 nsCOMPtr<nsIWidget> widget = GetMainWidget();
3957 if (widget)
3958 widget->MakeFullScreen(aFullScreen);
3960 mFullScreen = aFullScreen;
3962 return NS_OK;
3965 NS_IMETHODIMP
3966 nsGlobalWindow::GetFullScreen(PRBool* aFullScreen)
3968 FORWARD_TO_OUTER(GetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
3970 // Get the fullscreen value of the root window, to always have the value
3971 // accurate, even when called from content.
3972 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
3973 if (treeItem) {
3974 nsCOMPtr<nsIDocShellTreeItem> rootItem;
3975 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
3976 if (rootItem != treeItem) {
3977 nsCOMPtr<nsIDOMWindowInternal> window = do_GetInterface(rootItem);
3978 if (window)
3979 return window->GetFullScreen(aFullScreen);
3983 // We are the root window, or something went wrong. Return our internal value.
3984 *aFullScreen = mFullScreen;
3985 return NS_OK;
3988 PRBool
3989 nsGlobalWindow::DOMWindowDumpEnabled()
3991 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
3992 // In optimized builds we check a pref that controls if we should
3993 // enable output from dump() or not, in debug builds it's always
3994 // enabled.
3995 return gDOMWindowDumpEnabled;
3996 #else
3997 return PR_TRUE;
3998 #endif
4001 NS_IMETHODIMP
4002 nsGlobalWindow::Dump(const nsAString& aStr)
4004 if (!DOMWindowDumpEnabled()) {
4005 return NS_OK;
4008 char *cstr = ToNewUTF8String(aStr);
4010 #if defined(XP_MAC) || defined(XP_MACOSX)
4011 // have to convert \r to \n so that printing to the console works
4012 char *c = cstr, *cEnd = cstr + strlen(cstr);
4013 while (c < cEnd) {
4014 if (*c == '\r')
4015 *c = '\n';
4016 c++;
4018 #endif
4020 if (cstr) {
4021 FILE *fp = gDumpFile ? gDumpFile : stdout;
4022 fputs(cstr, fp);
4023 fflush(fp);
4024 nsMemory::Free(cstr);
4027 return NS_OK;
4030 void
4031 nsGlobalWindow::EnsureReflowFlushAndPaint()
4033 NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
4034 "docshell!");
4036 if (!mDocShell)
4037 return;
4039 nsCOMPtr<nsIPresShell> presShell;
4040 mDocShell->GetPresShell(getter_AddRefs(presShell));
4042 if (!presShell)
4043 return;
4045 // Flush pending reflows.
4046 if (mDoc) {
4047 mDoc->FlushPendingNotifications(Flush_Layout);
4050 // Unsuppress painting.
4051 presShell->UnsuppressPainting();
4054 NS_IMETHODIMP
4055 nsGlobalWindow::GetTextZoom(float *aZoom)
4057 FORWARD_TO_OUTER(GetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
4059 if (mDocShell) {
4060 nsCOMPtr<nsIContentViewer> contentViewer;
4061 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
4062 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
4064 if (markupViewer) {
4065 return markupViewer->GetTextZoom(aZoom);
4068 return NS_ERROR_FAILURE;
4071 NS_IMETHODIMP
4072 nsGlobalWindow::SetTextZoom(float aZoom)
4074 FORWARD_TO_OUTER(SetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
4076 if (mDocShell) {
4077 nsCOMPtr<nsIContentViewer> contentViewer;
4078 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
4079 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
4081 if (markupViewer)
4082 return markupViewer->SetTextZoom(aZoom);
4084 return NS_ERROR_FAILURE;
4087 // static
4088 void
4089 nsGlobalWindow::MakeScriptDialogTitle(nsAString &aOutTitle)
4091 aOutTitle.Truncate();
4093 // Try to get a host from the running principal -- this will do the
4094 // right thing for javascript: and data: documents.
4096 nsresult rv = NS_OK;
4097 NS_ASSERTION(nsContentUtils::GetSecurityManager(),
4098 "Global Window has no security manager!");
4099 if (nsContentUtils::GetSecurityManager()) {
4100 nsCOMPtr<nsIPrincipal> principal;
4101 rv = nsContentUtils::GetSecurityManager()->
4102 GetSubjectPrincipal(getter_AddRefs(principal));
4104 if (NS_SUCCEEDED(rv) && principal) {
4105 nsCOMPtr<nsIURI> uri;
4106 rv = principal->GetURI(getter_AddRefs(uri));
4108 if (NS_SUCCEEDED(rv) && uri) {
4109 // remove user:pass for privacy and spoof prevention
4111 nsCOMPtr<nsIURIFixup> fixup(do_GetService(NS_URIFIXUP_CONTRACTID));
4112 if (fixup) {
4113 nsCOMPtr<nsIURI> fixedURI;
4114 rv = fixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
4115 if (NS_SUCCEEDED(rv) && fixedURI) {
4116 nsCAutoString host;
4117 fixedURI->GetHost(host);
4119 if (!host.IsEmpty()) {
4120 // if this URI has a host we'll show it. For other
4121 // schemes (e.g. file:) we fall back to the localized
4122 // generic string
4124 nsCAutoString prepath;
4125 fixedURI->GetPrePath(prepath);
4127 NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
4128 const PRUnichar *formatStrings[] = { ucsPrePath.get() };
4129 nsXPIDLString tempString;
4130 nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4131 "ScriptDlgHeading",
4132 formatStrings, NS_ARRAY_LENGTH(formatStrings),
4133 tempString);
4134 aOutTitle = tempString;
4140 else { // failed to get subject principal
4141 NS_WARNING("No script principal? Who is calling alert/confirm/prompt?!");
4145 if (aOutTitle.IsEmpty()) {
4146 // We didn't find a host so use the generic heading
4147 nsXPIDLString tempString;
4148 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4149 "ScriptDlgGenericHeading",
4150 tempString);
4151 aOutTitle = tempString;
4154 // Just in case
4155 if (aOutTitle.IsEmpty()) {
4156 NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
4157 aOutTitle.AssignLiteral("[Script]");
4161 // static
4162 PRBool
4163 nsGlobalWindow::CanMoveResizeWindows()
4165 if (!CanSetProperty("dom.disable_window_move_resize"))
4166 return PR_FALSE;
4168 if (gMouseDown && !gDragServiceDisabled) {
4169 nsCOMPtr<nsIDragService> ds =
4170 do_GetService("@mozilla.org/widget/dragservice;1");
4171 if (ds) {
4172 gDragServiceDisabled = PR_TRUE;
4173 ds->Suppress();
4176 return PR_TRUE;
4179 NS_IMETHODIMP
4180 nsGlobalWindow::Alert(const nsAString& aString)
4182 FORWARD_TO_OUTER(Alert, (aString), NS_ERROR_NOT_INITIALIZED);
4184 // Reset popup state while opening a modal dialog, and firing events
4185 // about the dialog, to prevent the current state from being active
4186 // the whole time a modal dialog is open.
4187 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4189 // Special handling for alert(null) in JS for backwards
4190 // compatibility.
4192 NS_NAMED_LITERAL_STRING(null_str, "null");
4194 const nsAString *str = DOMStringIsNull(aString) ? &null_str : &aString;
4196 // Before bringing up the window, unsuppress painting and flush
4197 // pending reflows.
4198 EnsureReflowFlushAndPaint();
4200 nsAutoString title;
4201 MakeScriptDialogTitle(title);
4203 // Remove non-terminating null characters from the
4204 // string. See bug #310037.
4205 nsAutoString final;
4206 nsContentUtils::StripNullChars(*str, final);
4208 nsresult rv;
4209 nsCOMPtr<nsIPromptService> promptSvc = do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv);
4210 NS_ENSURE_SUCCESS(rv, rv);
4212 return promptSvc->Alert(this, title.get(), final.get());
4215 NS_IMETHODIMP
4216 nsGlobalWindow::Confirm(const nsAString& aString, PRBool* aReturn)
4218 FORWARD_TO_OUTER(Confirm, (aString, aReturn), NS_ERROR_NOT_INITIALIZED);
4220 // Reset popup state while opening a modal dialog, and firing events
4221 // about the dialog, to prevent the current state from being active
4222 // the whole time a modal dialog is open.
4223 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4225 *aReturn = PR_FALSE;
4227 // Before bringing up the window, unsuppress painting and flush
4228 // pending reflows.
4229 EnsureReflowFlushAndPaint();
4231 nsAutoString title;
4232 MakeScriptDialogTitle(title);
4234 // Remove non-terminating null characters from the
4235 // string. See bug #310037.
4236 nsAutoString final;
4237 nsContentUtils::StripNullChars(aString, final);
4239 nsresult rv;
4240 nsCOMPtr<nsIPromptService> promptSvc = do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv);
4241 NS_ENSURE_SUCCESS(rv, rv);
4243 return promptSvc->Confirm(this, title.get(), final.get(), aReturn);
4246 NS_IMETHODIMP
4247 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
4248 nsAString& aReturn)
4250 SetDOMStringToNull(aReturn);
4252 // Reset popup state while opening a modal dialog, and firing events
4253 // about the dialog, to prevent the current state from being active
4254 // the whole time a modal dialog is open.
4255 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4257 // Before bringing up the window, unsuppress painting and flush
4258 // pending reflows.
4259 EnsureReflowFlushAndPaint();
4261 nsAutoString title;
4262 MakeScriptDialogTitle(title);
4264 // Remove non-terminating null characters from the
4265 // string. See bug #310037.
4266 nsAutoString fixedMessage, fixedInitial;
4267 nsContentUtils::StripNullChars(aMessage, fixedMessage);
4268 nsContentUtils::StripNullChars(aInitial, fixedInitial);
4270 nsresult rv;
4271 nsCOMPtr<nsIPromptService> promptSvc = do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv);
4272 NS_ENSURE_SUCCESS(rv, rv);
4274 // Pass in the default value, if any.
4275 PRUnichar *inoutValue = ToNewUnicode(fixedInitial);
4277 PRBool ok, dummy;
4278 rv = promptSvc->Prompt(this, title.get(), fixedMessage.get(),
4279 &inoutValue, nsnull, &dummy, &ok);
4280 NS_ENSURE_SUCCESS(rv, rv);
4282 nsAdoptingString outValue(inoutValue);
4284 if (ok && outValue) {
4285 aReturn.Assign(outValue);
4288 return rv;
4291 NS_IMETHODIMP
4292 nsGlobalWindow::Focus()
4294 FORWARD_TO_OUTER(Focus, (), NS_ERROR_NOT_INITIALIZED);
4296 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4297 if (!fm)
4298 return NS_OK;
4300 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
4302 PRBool isVisible = PR_FALSE;
4303 if (baseWin) {
4304 baseWin->GetVisibility(&isVisible);
4307 if (!isVisible) {
4308 // A hidden tab is being focused, ignore this call.
4309 return NS_OK;
4313 * If caller is not chrome and dom.disable_window_flip is true,
4314 * prevent bringing a window to the front if the window is not the
4315 * currently active window, but do change the currently focused
4316 * window in the focus controller so that focus is in the right
4317 * place when the window is activated again.
4320 PRBool canFocus =
4321 CanSetProperty("dom.disable_window_flip") ||
4322 RevisePopupAbuseLevel(gPopupControlState) < openAbused;
4324 nsCOMPtr<nsIDOMWindow> activeWindow;
4325 fm->GetActiveWindow(getter_AddRefs(activeWindow));
4327 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
4328 NS_ASSERTION(treeItem, "What happened?");
4329 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4330 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
4331 nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
4332 PRBool isActive = (rootWin == activeWindow);
4334 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4335 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4336 if (treeOwnerAsWin && (canFocus || isActive)) {
4337 PRBool isEnabled = PR_TRUE;
4338 if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
4339 NS_WARNING( "Should not try to set the focus on a disabled window" );
4340 return NS_OK;
4343 // XXXndeakin not sure what this is for or if it should go somewhere else
4344 nsCOMPtr<nsIEmbeddingSiteWindow> embeddingWin(do_GetInterface(treeOwnerAsWin));
4345 if (embeddingWin)
4346 embeddingWin->SetFocus();
4349 if (!mDocShell)
4350 return NS_OK;
4352 nsCOMPtr<nsIPresShell> presShell;
4353 // Don't look for a presshell if we're a root chrome window that's got
4354 // about:blank loaded. We don't want to focus our widget in that case.
4355 // XXXbz should we really be checking for IsInitialDocument() instead?
4356 PRBool lookForPresShell = PR_TRUE;
4357 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
4358 treeItem->GetItemType(&itemType);
4359 if (itemType == nsIDocShellTreeItem::typeChrome &&
4360 GetPrivateRoot() == static_cast<nsIDOMWindowInternal*>(this) &&
4361 mDocument) {
4362 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4363 NS_ASSERTION(doc, "Bogus doc?");
4364 nsIURI* ourURI = doc->GetDocumentURI();
4365 if (ourURI) {
4366 lookForPresShell = !IsAboutBlank(ourURI);
4370 if (lookForPresShell) {
4371 mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
4374 nsCOMPtr<nsIDocShellTreeItem> parentDsti;
4375 treeItem->GetParent(getter_AddRefs(parentDsti));
4377 // set the parent's current focus to the frame containing this window.
4378 nsCOMPtr<nsIDOMWindow> parent(do_GetInterface(parentDsti));
4379 if (parent) {
4380 nsCOMPtr<nsIDOMDocument> parentdomdoc;
4381 parent->GetDocument(getter_AddRefs(parentdomdoc));
4383 nsCOMPtr<nsIDocument> parentdoc = do_QueryInterface(parentdomdoc);
4384 if (!parentdoc)
4385 return NS_OK;
4387 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
4388 nsIContent* frame = parentdoc->FindContentForSubDocument(doc);
4389 nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(frame);
4390 if (frameElement) {
4391 PRUint32 flags = nsIFocusManager::FLAG_NOSCROLL;
4392 if (canFocus)
4393 flags |= nsIFocusManager::FLAG_RAISE;
4394 return fm->SetFocus(frameElement, flags);
4397 else if (canFocus) {
4398 // if there is no parent, this must be a toplevel window, so raise the
4399 // window if canFocus is true
4400 return fm->SetActiveWindow(this);
4403 return NS_OK;
4406 NS_IMETHODIMP
4407 nsGlobalWindow::Blur()
4409 FORWARD_TO_OUTER(Blur, (), NS_ERROR_NOT_INITIALIZED);
4411 // If embedding apps don't implement nsIEmbeddingSiteWindow2, we
4412 // shouldn't throw exceptions to web content.
4413 nsresult rv = NS_OK;
4415 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
4416 GetTreeOwner(getter_AddRefs(treeOwner));
4417 nsCOMPtr<nsIEmbeddingSiteWindow2> siteWindow(do_GetInterface(treeOwner));
4418 if (siteWindow) {
4419 // This method call may cause mDocShell to become nsnull.
4420 rv = siteWindow->Blur();
4422 // if the root is focused, clear the focus
4423 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4424 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
4425 if (fm && mDocument) {
4426 nsCOMPtr<nsIDOMElement> element;
4427 fm->GetFocusedElementForWindow(this, PR_FALSE, nsnull, getter_AddRefs(element));
4428 nsCOMPtr<nsIContent> content = do_QueryInterface(element);
4429 if (content == doc->GetRootElement())
4430 fm->ClearFocus(this);
4434 return rv;
4437 NS_IMETHODIMP
4438 nsGlobalWindow::Back()
4440 FORWARD_TO_OUTER(Back, (), NS_ERROR_NOT_INITIALIZED);
4442 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4443 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
4445 return webNav->GoBack();
4448 NS_IMETHODIMP
4449 nsGlobalWindow::Forward()
4451 FORWARD_TO_OUTER(Forward, (), NS_ERROR_NOT_INITIALIZED);
4453 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4454 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
4456 return webNav->GoForward();
4459 NS_IMETHODIMP
4460 nsGlobalWindow::Home()
4462 FORWARD_TO_OUTER(Home, (), NS_ERROR_NOT_INITIALIZED);
4464 if (!mDocShell)
4465 return NS_OK;
4467 nsAdoptingString homeURL =
4468 nsContentUtils::GetLocalizedStringPref(PREF_BROWSER_STARTUP_HOMEPAGE);
4470 if (homeURL.IsEmpty()) {
4471 // if all else fails, use this
4472 #ifdef DEBUG_seth
4473 printf("all else failed. using %s as the home page\n", DEFAULT_HOME_PAGE);
4474 #endif
4475 CopyASCIItoUTF16(DEFAULT_HOME_PAGE, homeURL);
4478 #ifdef MOZ_PHOENIX
4480 // Firefox lets the user specify multiple home pages to open in
4481 // individual tabs by separating them with '|'. Since we don't
4482 // have the machinery in place to easily open new tabs from here,
4483 // simply truncate the homeURL at the first '|' character to
4484 // prevent any possibilities of leaking the users list of home
4485 // pages to the first home page.
4487 // Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
4488 // fixed we can revisit this.
4489 PRInt32 firstPipe = homeURL.FindChar('|');
4491 if (firstPipe > 0) {
4492 homeURL.Truncate(firstPipe);
4495 #endif
4497 nsresult rv;
4498 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4499 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
4500 rv = webNav->LoadURI(homeURL.get(),
4501 nsIWebNavigation::LOAD_FLAGS_NONE,
4502 nsnull,
4503 nsnull,
4504 nsnull);
4505 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
4506 return NS_OK;
4509 NS_IMETHODIMP
4510 nsGlobalWindow::Stop()
4512 FORWARD_TO_OUTER(Stop, (), NS_ERROR_NOT_INITIALIZED);
4514 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4515 if (!webNav)
4516 return NS_OK;
4518 return webNav->Stop(nsIWebNavigation::STOP_ALL);
4521 NS_IMETHODIMP
4522 nsGlobalWindow::Print()
4524 #ifdef NS_PRINTING
4525 FORWARD_TO_OUTER(Print, (), NS_ERROR_NOT_INITIALIZED);
4527 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
4528 if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
4529 getter_AddRefs(webBrowserPrint)))) {
4531 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
4532 do_GetService("@mozilla.org/gfx/printsettings-service;1");
4534 nsCOMPtr<nsIPrintSettings> printSettings;
4535 if (printSettingsService) {
4536 PRBool printSettingsAreGlobal =
4537 nsContentUtils::GetBoolPref("print.use_global_printsettings", PR_FALSE);
4539 if (printSettingsAreGlobal) {
4540 printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
4542 nsXPIDLString printerName;
4543 printSettings->GetPrinterName(getter_Copies(printerName));
4544 if (printerName.IsEmpty()) {
4545 printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
4546 printSettings->SetPrinterName(printerName);
4548 printSettingsService->InitPrintSettingsFromPrinter(printerName, printSettings);
4549 printSettingsService->InitPrintSettingsFromPrefs(printSettings,
4550 PR_TRUE,
4551 nsIPrintSettings::kInitSaveAll);
4552 } else {
4553 printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
4556 EnterModalState();
4557 webBrowserPrint->Print(printSettings, nsnull);
4558 LeaveModalState();
4560 PRBool savePrintSettings =
4561 nsContentUtils::GetBoolPref("print.save_print_settings", PR_FALSE);
4562 if (printSettingsAreGlobal && savePrintSettings) {
4563 printSettingsService->
4564 SavePrintSettingsToPrefs(printSettings,
4565 PR_TRUE,
4566 nsIPrintSettings::kInitSaveAll);
4567 printSettingsService->
4568 SavePrintSettingsToPrefs(printSettings,
4569 PR_FALSE,
4570 nsIPrintSettings::kInitSavePrinterName);
4572 } else {
4573 webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
4574 webBrowserPrint->Print(printSettings, nsnull);
4577 #endif //NS_PRINTING
4579 return NS_OK;
4582 NS_IMETHODIMP
4583 nsGlobalWindow::MoveTo(PRInt32 aXPos, PRInt32 aYPos)
4585 FORWARD_TO_OUTER(MoveTo, (aXPos, aYPos), NS_ERROR_NOT_INITIALIZED);
4588 * If caller is not chrome and the user has not explicitly exempted the site,
4589 * prevent window.moveTo() by exiting early
4592 if (!CanMoveResizeWindows() || IsFrame()) {
4593 return NS_OK;
4596 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4597 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4598 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
4600 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aXPos, &aYPos),
4601 NS_ERROR_FAILURE);
4603 // mild abuse of a "size" object so we don't need more helper functions
4604 nsIntSize devPos(CSSToDevIntPixels(nsIntSize(aXPos, aYPos)));
4606 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(devPos.width, devPos.height),
4607 NS_ERROR_FAILURE);
4609 return NS_OK;
4612 NS_IMETHODIMP
4613 nsGlobalWindow::MoveBy(PRInt32 aXDif, PRInt32 aYDif)
4615 FORWARD_TO_OUTER(MoveBy, (aXDif, aYDif), NS_ERROR_NOT_INITIALIZED);
4618 * If caller is not chrome and the user has not explicitly exempted the site,
4619 * prevent window.moveBy() by exiting early
4622 if (!CanMoveResizeWindows() || IsFrame()) {
4623 return NS_OK;
4626 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4627 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4628 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
4630 // To do this correctly we have to convert what we get from GetPosition
4631 // into CSS pixels, add the arguments, do the security check, and
4632 // then convert back to device pixels for the call to SetPosition.
4634 PRInt32 x, y;
4635 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y), NS_ERROR_FAILURE);
4637 // mild abuse of a "size" object so we don't need more helper functions
4638 nsIntSize cssPos(DevToCSSIntPixels(nsIntSize(x, y)));
4640 cssPos.width += aXDif;
4641 cssPos.height += aYDif;
4643 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&cssPos.width,
4644 &cssPos.height),
4645 NS_ERROR_FAILURE);
4647 nsIntSize newDevPos(CSSToDevIntPixels(cssPos));
4649 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(newDevPos.width,
4650 newDevPos.height),
4651 NS_ERROR_FAILURE);
4653 return NS_OK;
4656 NS_IMETHODIMP
4657 nsGlobalWindow::ResizeTo(PRInt32 aWidth, PRInt32 aHeight)
4659 FORWARD_TO_OUTER(ResizeTo, (aWidth, aHeight), NS_ERROR_NOT_INITIALIZED);
4662 * If caller is not chrome and the user has not explicitly exempted the site,
4663 * prevent window.resizeTo() by exiting early
4666 if (!CanMoveResizeWindows() || IsFrame()) {
4667 return NS_OK;
4670 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4671 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4672 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
4674 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aWidth, &aHeight),
4675 NS_ERROR_FAILURE);
4677 nsIntSize devSz(CSSToDevIntPixels(nsIntSize(aWidth, aHeight)));
4679 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(devSz.width, devSz.height, PR_TRUE),
4680 NS_ERROR_FAILURE);
4682 return NS_OK;
4685 NS_IMETHODIMP
4686 nsGlobalWindow::ResizeBy(PRInt32 aWidthDif, PRInt32 aHeightDif)
4688 FORWARD_TO_OUTER(ResizeBy, (aWidthDif, aHeightDif), NS_ERROR_NOT_INITIALIZED);
4691 * If caller is not chrome and the user has not explicitly exempted the site,
4692 * prevent window.resizeBy() by exiting early
4695 if (!CanMoveResizeWindows() || IsFrame()) {
4696 return NS_OK;
4699 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4700 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4701 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
4703 PRInt32 width, height;
4704 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&width, &height), NS_ERROR_FAILURE);
4706 // To do this correctly we have to convert what we got from GetSize
4707 // into CSS pixels, add the arguments, do the security check, and
4708 // then convert back to device pixels for the call to SetSize.
4710 nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
4712 cssSize.width += aWidthDif;
4713 cssSize.height += aHeightDif;
4715 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&cssSize.width,
4716 &cssSize.height),
4717 NS_ERROR_FAILURE);
4719 nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
4721 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(newDevSize.width,
4722 newDevSize.height,
4723 PR_TRUE),
4724 NS_ERROR_FAILURE);
4726 return NS_OK;
4729 NS_IMETHODIMP
4730 nsGlobalWindow::SizeToContent()
4732 FORWARD_TO_OUTER(SizeToContent, (), NS_ERROR_NOT_INITIALIZED);
4734 if (!mDocShell) {
4735 return NS_OK;
4739 * If caller is not chrome and the user has not explicitly exempted the site,
4740 * prevent window.sizeToContent() by exiting early
4743 if (!CanMoveResizeWindows() || IsFrame()) {
4744 return NS_OK;
4747 // The content viewer does a check to make sure that it's a content
4748 // viewer for a toplevel docshell.
4750 nsCOMPtr<nsIContentViewer> cv;
4751 mDocShell->GetContentViewer(getter_AddRefs(cv));
4752 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(cv));
4753 NS_ENSURE_TRUE(markupViewer, NS_ERROR_FAILURE);
4754 NS_ENSURE_SUCCESS(markupViewer->SizeToContent(), NS_ERROR_FAILURE);
4756 return NS_OK;
4759 NS_IMETHODIMP
4760 nsGlobalWindow::GetWindowRoot(nsIDOMEventTarget **aWindowRoot)
4762 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
4763 return CallQueryInterface(root, aWindowRoot);
4766 already_AddRefed<nsPIWindowRoot>
4767 nsGlobalWindow::GetTopWindowRoot()
4769 nsIDOMWindowInternal *rootWindow = GetPrivateRoot();
4770 nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(rootWindow));
4771 if (!piWin)
4772 return nsnull;
4774 nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
4775 return window.forget();
4778 NS_IMETHODIMP
4779 nsGlobalWindow::Scroll(PRInt32 aXScroll, PRInt32 aYScroll)
4781 return ScrollTo(aXScroll, aYScroll);
4784 NS_IMETHODIMP
4785 nsGlobalWindow::ScrollTo(PRInt32 aXScroll, PRInt32 aYScroll)
4787 FlushPendingNotifications(Flush_Layout);
4788 nsIScrollableFrame *sf = GetScrollFrame();
4790 if (sf) {
4791 // Here we calculate what the max pixel value is that we can
4792 // scroll to, we do this by dividing maxint with the pixel to
4793 // twips conversion factor, and substracting 4, the 4 comes from
4794 // experimenting with this value, anything less makes the view
4795 // code not scroll correctly, I have no idea why. -- jst
4796 const PRInt32 maxpx = nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
4798 if (aXScroll > maxpx) {
4799 aXScroll = maxpx;
4802 if (aYScroll > maxpx) {
4803 aYScroll = maxpx;
4805 sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aXScroll),
4806 nsPresContext::CSSPixelsToAppUnits(aYScroll)),
4807 nsIScrollableFrame::INSTANT);
4810 return NS_OK;
4813 NS_IMETHODIMP
4814 nsGlobalWindow::ScrollBy(PRInt32 aXScrollDif, PRInt32 aYScrollDif)
4816 FlushPendingNotifications(Flush_Layout);
4817 nsIScrollableFrame *sf = GetScrollFrame();
4819 if (sf) {
4820 nsPoint scrollPos = sf->GetScrollPosition();
4821 // It seems like it would make more sense for ScrollBy to use
4822 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
4823 // Perhaps Web content does too.
4824 return ScrollTo(nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x) + aXScrollDif,
4825 nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y) + aYScrollDif);
4828 return NS_OK;
4831 NS_IMETHODIMP
4832 nsGlobalWindow::ScrollByLines(PRInt32 numLines)
4834 FlushPendingNotifications(Flush_Layout);
4835 nsIScrollableFrame *sf = GetScrollFrame();
4836 if (sf) {
4837 // It seems like it would make more sense for ScrollByLines to use
4838 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
4839 // Perhaps Web content does too.
4840 sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
4841 nsIScrollableFrame::INSTANT);
4844 return NS_OK;
4847 NS_IMETHODIMP
4848 nsGlobalWindow::ScrollByPages(PRInt32 numPages)
4850 FlushPendingNotifications(Flush_Layout);
4851 nsIScrollableFrame *sf = GetScrollFrame();
4852 if (sf) {
4853 // It seems like it would make more sense for ScrollByPages to use
4854 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
4855 // Perhaps Web content does too.
4856 sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
4857 nsIScrollableFrame::INSTANT);
4860 return NS_OK;
4863 NS_IMETHODIMP
4864 nsGlobalWindow::ClearTimeout()
4866 return ClearTimeoutOrInterval();
4869 NS_IMETHODIMP
4870 nsGlobalWindow::ClearInterval()
4872 return ClearTimeoutOrInterval();
4875 NS_IMETHODIMP
4876 nsGlobalWindow::SetTimeout(PRInt32 *_retval)
4878 return SetTimeoutOrInterval(PR_FALSE, _retval);
4881 NS_IMETHODIMP
4882 nsGlobalWindow::SetInterval(PRInt32 *_retval)
4884 return SetTimeoutOrInterval(PR_TRUE, _retval);
4887 NS_IMETHODIMP
4888 nsGlobalWindow::SetResizable(PRBool aResizable)
4890 // nop
4892 return NS_OK;
4895 static void
4896 ReportUseOfDeprecatedMethod(nsGlobalWindow* aWindow, const char* aWarning)
4898 nsCOMPtr<nsIDocument> doc = do_QueryInterface(aWindow->GetExtantDocument());
4899 nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES,
4900 aWarning,
4901 nsnull, 0,
4902 doc ? doc->GetDocumentURI() : nsnull,
4903 EmptyString(), 0, 0,
4904 nsIScriptError::warningFlag,
4905 "DOM Events");
4908 NS_IMETHODIMP
4909 nsGlobalWindow::CaptureEvents(PRInt32 aEventFlags)
4911 ReportUseOfDeprecatedMethod(this, "UseOfCaptureEventsWarning");
4912 return NS_OK;
4915 NS_IMETHODIMP
4916 nsGlobalWindow::ReleaseEvents(PRInt32 aEventFlags)
4918 ReportUseOfDeprecatedMethod(this, "UseOfReleaseEventsWarning");
4919 return NS_OK;
4922 NS_IMETHODIMP
4923 nsGlobalWindow::RouteEvent(nsIDOMEvent* aEvt)
4925 ReportUseOfDeprecatedMethod(this, "UseOfRouteEventWarning");
4926 return NS_OK;
4929 NS_IMETHODIMP
4930 nsGlobalWindow::EnableExternalCapture()
4932 return NS_ERROR_FAILURE;
4935 NS_IMETHODIMP
4936 nsGlobalWindow::DisableExternalCapture()
4938 return NS_ERROR_FAILURE;
4941 static
4942 PRBool IsPopupBlocked(nsIDOMDocument* aDoc)
4944 nsCOMPtr<nsIPopupWindowManager> pm =
4945 do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
4947 if (!pm) {
4948 return PR_FALSE;
4951 PRBool blocked = PR_TRUE;
4952 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
4954 if (doc) {
4955 PRUint32 permission = nsIPopupWindowManager::ALLOW_POPUP;
4956 pm->TestPermission(doc->GetDocumentURI(), &permission);
4957 blocked = (permission == nsIPopupWindowManager::DENY_POPUP);
4959 return blocked;
4962 static
4963 void FirePopupBlockedEvent(nsIDOMDocument* aDoc,
4964 nsIDOMWindow *aRequestingWindow, nsIURI *aPopupURI,
4965 const nsAString &aPopupWindowName,
4966 const nsAString &aPopupWindowFeatures)
4968 if (aDoc) {
4969 // Fire a "DOMPopupBlocked" event so that the UI can hear about
4970 // blocked popups.
4971 nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(aDoc));
4972 nsCOMPtr<nsIDOMEvent> event;
4973 docEvent->CreateEvent(NS_LITERAL_STRING("PopupBlockedEvents"),
4974 getter_AddRefs(event));
4975 if (event) {
4976 nsCOMPtr<nsIDOMPopupBlockedEvent> pbev(do_QueryInterface(event));
4977 pbev->InitPopupBlockedEvent(NS_LITERAL_STRING("DOMPopupBlocked"),
4978 PR_TRUE, PR_TRUE, aRequestingWindow,
4979 aPopupURI, aPopupWindowName,
4980 aPopupWindowFeatures);
4981 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
4982 privateEvent->SetTrusted(PR_TRUE);
4984 nsCOMPtr<nsIDOMEventTarget> targ(do_QueryInterface(aDoc));
4985 PRBool defaultActionEnabled;
4986 targ->DispatchEvent(event, &defaultActionEnabled);
4991 void FirePopupWindowEvent(nsIDOMDocument* aDoc)
4993 // Fire a "PopupWindow" event
4994 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
4995 nsContentUtils::DispatchTrustedEvent(doc, aDoc,
4996 NS_LITERAL_STRING("PopupWindow"),
4997 PR_TRUE, PR_TRUE);
5000 // static
5001 PRBool
5002 nsGlobalWindow::CanSetProperty(const char *aPrefName)
5004 // Chrome can set any property.
5005 if (nsContentUtils::IsCallerTrustedForWrite()) {
5006 return PR_TRUE;
5009 // If the pref is set to true, we can not set the property
5010 // and vice versa.
5011 return !nsContentUtils::GetBoolPref(aPrefName, PR_TRUE);
5014 PRBool
5015 nsGlobalWindow::PopupWhitelisted()
5017 if (!IsPopupBlocked(mDocument))
5018 return PR_TRUE;
5020 nsCOMPtr<nsIDOMWindow> parent;
5022 if (NS_FAILED(GetParent(getter_AddRefs(parent))) ||
5023 parent == static_cast<nsIDOMWindow*>(this))
5025 return PR_FALSE;
5028 return static_cast<nsGlobalWindow*>
5029 (static_cast<nsIDOMWindow*>
5030 (parent.get()))->PopupWhitelisted();
5034 * Examine the current document state to see if we're in a way that is
5035 * typically abused by web designers. The window.open code uses this
5036 * routine to determine whether to allow the new window.
5037 * Returns a value from the PopupControlState enum.
5039 PopupControlState
5040 nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
5042 FORWARD_TO_OUTER(RevisePopupAbuseLevel, (aControl), aControl);
5044 NS_ASSERTION(mDocShell, "Must have docshell");
5046 nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(mDocShell));
5048 NS_ASSERTION(item, "Docshell doesn't implement nsIDocShellTreeItem?");
5050 PRInt32 type = nsIDocShellTreeItem::typeChrome;
5051 item->GetItemType(&type);
5052 if (type != nsIDocShellTreeItem::typeContent)
5053 return openAllowed;
5055 PopupControlState abuse = aControl;
5056 switch (abuse) {
5057 case openControlled:
5058 case openAbused:
5059 case openOverridden:
5060 if (PopupWhitelisted())
5061 abuse = PopupControlState(abuse - 1);
5062 case openAllowed: break;
5063 default:
5064 NS_WARNING("Strange PopupControlState!");
5067 // limit the number of simultaneously open popups
5068 if (abuse == openAbused || abuse == openControlled) {
5069 PRInt32 popupMax = nsContentUtils::GetIntPref("dom.popup_maximum", -1);
5070 if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
5071 abuse = openOverridden;
5074 return abuse;
5077 /* If a window open is blocked, fire the appropriate DOM events.
5078 aBlocked signifies we just blocked a popup.
5079 aWindow signifies we just opened what is probably a popup.
5081 void
5082 nsGlobalWindow::FireAbuseEvents(PRBool aBlocked, PRBool aWindow,
5083 const nsAString &aPopupURL,
5084 const nsAString &aPopupWindowName,
5085 const nsAString &aPopupWindowFeatures)
5087 // fetch the URI of the window requesting the opened window
5089 nsCOMPtr<nsIDOMWindow> topWindow;
5090 GetTop(getter_AddRefs(topWindow));
5091 if (!topWindow)
5092 return;
5094 nsCOMPtr<nsIDOMDocument> topDoc;
5095 topWindow->GetDocument(getter_AddRefs(topDoc));
5097 nsCOMPtr<nsIURI> popupURI;
5099 // build the URI of the would-have-been popup window
5100 // (see nsWindowWatcher::URIfromURL)
5102 // first, fetch the opener's base URI
5104 nsIURI *baseURL = 0;
5106 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5107 nsCOMPtr<nsIDOMWindow> contextWindow;
5109 if (cx) {
5110 nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
5111 if (currentCX) {
5112 contextWindow = do_QueryInterface(currentCX->GetGlobalObject());
5115 if (!contextWindow)
5116 contextWindow = static_cast<nsIDOMWindow*>(this);
5118 nsCOMPtr<nsIDOMDocument> domdoc;
5119 contextWindow->GetDocument(getter_AddRefs(domdoc));
5120 nsCOMPtr<nsIDocument> doc(do_QueryInterface(domdoc));
5121 if (doc)
5122 baseURL = doc->GetDocBaseURI();
5124 // use the base URI to build what would have been the popup's URI
5125 nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
5126 if (ios)
5127 ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), 0, baseURL,
5128 getter_AddRefs(popupURI));
5130 // fire an event chock full of informative URIs
5131 if (aBlocked)
5132 FirePopupBlockedEvent(topDoc, this, popupURI, aPopupWindowName,
5133 aPopupWindowFeatures);
5134 if (aWindow)
5135 FirePopupWindowEvent(topDoc);
5138 NS_IMETHODIMP
5139 nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
5140 const nsAString& aOptions, nsIDOMWindow **_retval)
5142 return OpenInternal(aUrl, aName, aOptions,
5143 PR_FALSE, // aDialog
5144 PR_FALSE, // aContentModal
5145 PR_TRUE, // aCalledNoScript
5146 PR_FALSE, // aDoJSFixups
5147 nsnull, nsnull, // No args
5148 GetPrincipal(), // aCalleePrincipal
5149 nsnull, // aJSCallerContext
5150 _retval);
5153 NS_IMETHODIMP
5154 nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName,
5155 const nsAString& aOptions, nsIDOMWindow **_retval)
5157 return OpenInternal(aUrl, aName, aOptions,
5158 PR_FALSE, // aDialog
5159 PR_FALSE, // aContentModal
5160 PR_FALSE, // aCalledNoScript
5161 PR_TRUE, // aDoJSFixups
5162 nsnull, nsnull, // No args
5163 GetPrincipal(), // aCalleePrincipal
5164 nsContentUtils::GetCurrentJSContext(), // aJSCallerContext
5165 _retval);
5168 // like Open, but attaches to the new window any extra parameters past
5169 // [features] as a JS property named "arguments"
5170 NS_IMETHODIMP
5171 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
5172 const nsAString& aOptions,
5173 nsISupports* aExtraArgument, nsIDOMWindow** _retval)
5175 return OpenInternal(aUrl, aName, aOptions,
5176 PR_TRUE, // aDialog
5177 PR_FALSE, // aContentModal
5178 PR_TRUE, // aCalledNoScript
5179 PR_FALSE, // aDoJSFixups
5180 nsnull, aExtraArgument, // Arguments
5181 GetPrincipal(), // aCalleePrincipal
5182 nsnull, // aJSCallerContext
5183 _retval);
5186 NS_IMETHODIMP
5187 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
5188 const nsAString& aOptions, nsIDOMWindow** _retval)
5190 if (!nsContentUtils::IsCallerTrustedForWrite()) {
5191 return NS_ERROR_DOM_SECURITY_ERR;
5194 nsAXPCNativeCallContext *ncc = nsnull;
5195 nsresult rv = nsContentUtils::XPConnect()->
5196 GetCurrentNativeCallContext(&ncc);
5197 NS_ENSURE_SUCCESS(rv, rv);
5199 if (!ncc)
5200 return NS_ERROR_NOT_AVAILABLE;
5202 JSContext *cx = nsnull;
5204 rv = ncc->GetJSContext(&cx);
5205 NS_ENSURE_SUCCESS(rv, rv);
5207 PRUint32 argc;
5208 jsval *argv = nsnull;
5210 // XXX - need to get this as nsISupports?
5211 ncc->GetArgc(&argc);
5212 ncc->GetArgvPtr(&argv);
5214 // Strip the url, name and options from the args seen by scripts.
5215 PRUint32 argOffset = argc < 3 ? argc : 3;
5216 nsCOMPtr<nsIArray> argvArray;
5217 rv = NS_CreateJSArgv(cx, argc - argOffset, argv + argOffset,
5218 getter_AddRefs(argvArray));
5219 NS_ENSURE_SUCCESS(rv, rv);
5221 return OpenInternal(aUrl, aName, aOptions,
5222 PR_TRUE, // aDialog
5223 PR_FALSE, // aContentModal
5224 PR_FALSE, // aCalledNoScript
5225 PR_FALSE, // aDoJSFixups
5226 argvArray, nsnull, // Arguments
5227 GetPrincipal(), // aCalleePrincipal
5228 cx, // aJSCallerContext
5229 _retval);
5232 NS_IMETHODIMP
5233 nsGlobalWindow::GetFrames(nsIDOMWindow** aFrames)
5235 FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
5237 *aFrames = this;
5238 NS_ADDREF(*aFrames);
5240 FlushPendingNotifications(Flush_ContentAndNotify);
5242 return NS_OK;
5245 nsGlobalWindow*
5246 nsGlobalWindow::CallerInnerWindow()
5248 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5249 if (!cx) {
5250 NS_ERROR("Please don't call this method from C++!");
5252 return nsnull;
5255 JSObject *scope = ::JS_GetScopeChain(cx);
5256 if (!scope)
5257 return nsnull;
5259 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
5260 nsContentUtils::XPConnect()->
5261 GetWrappedNativeOfJSObject(cx, ::JS_GetGlobalForObject(cx, scope),
5262 getter_AddRefs(wrapper));
5263 if (!wrapper)
5264 return nsnull;
5266 // The calling window must be holding a reference, so we can just return a
5267 // raw pointer here and let the QI's addref be balanced by the nsCOMPtr
5268 // destructor's release.
5269 nsCOMPtr<nsPIDOMWindow> win = do_QueryWrappedNative(wrapper);
5270 if (!win)
5271 return GetCurrentInnerWindowInternal();
5272 return static_cast<nsGlobalWindow*>(win.get());
5277 * Class used to represent events generated by calls to Window.postMessage,
5278 * which asynchronously creates and dispatches events.
5280 class PostMessageEvent : public nsRunnable
5282 public:
5283 NS_DECL_NSIRUNNABLE
5285 PostMessageEvent(nsGlobalWindow* aSource,
5286 const nsAString& aCallerOrigin,
5287 const nsAString& aMessage,
5288 nsGlobalWindow* aTargetWindow,
5289 nsIURI* aProvidedOrigin,
5290 PRBool aTrustedCaller)
5291 : mSource(aSource),
5292 mCallerOrigin(aCallerOrigin),
5293 mMessage(aMessage),
5294 mTargetWindow(aTargetWindow),
5295 mProvidedOrigin(aProvidedOrigin),
5296 mTrustedCaller(aTrustedCaller)
5298 MOZ_COUNT_CTOR(PostMessageEvent);
5301 ~PostMessageEvent()
5303 MOZ_COUNT_DTOR(PostMessageEvent);
5306 private:
5307 nsRefPtr<nsGlobalWindow> mSource;
5308 nsString mCallerOrigin;
5309 nsString mMessage;
5310 nsRefPtr<nsGlobalWindow> mTargetWindow;
5311 nsCOMPtr<nsIURI> mProvidedOrigin;
5312 PRBool mTrustedCaller;
5315 NS_IMETHODIMP
5316 PostMessageEvent::Run()
5318 NS_ABORT_IF_FALSE(mTargetWindow->IsOuterWindow(),
5319 "should have been passed an outer window!");
5320 NS_ABORT_IF_FALSE(!mSource || mSource->IsOuterWindow(),
5321 "should have been passed an outer window!");
5323 nsRefPtr<nsGlobalWindow> targetWindow;
5324 if (mTargetWindow->IsClosedOrClosing() ||
5325 !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
5326 targetWindow->IsClosedOrClosing())
5327 return NS_OK;
5329 NS_ABORT_IF_FALSE(targetWindow->IsInnerWindow(),
5330 "we ordered an inner window!");
5332 // Ensure that any origin which might have been provided is the origin of this
5333 // window's document. Note that we do this *now* instead of when postMessage
5334 // is called because the target window might have been navigated to a
5335 // different location between then and now. If this check happened when
5336 // postMessage was called, it would be fairly easy for a malicious webpage to
5337 // intercept messages intended for another site by carefully timing navigation
5338 // of the target window so it changed location after postMessage but before
5339 // now.
5340 if (mProvidedOrigin) {
5341 // Get the target's origin either from its principal or, in the case the
5342 // principal doesn't carry a URI (e.g. the system principal), the target's
5343 // document.
5344 nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
5345 if (!targetPrin)
5346 return NS_OK;
5347 nsCOMPtr<nsIURI> targetURI;
5348 if (NS_FAILED(targetPrin->GetURI(getter_AddRefs(targetURI))))
5349 return NS_OK;
5350 if (!targetURI) {
5351 targetURI = targetWindow->mDoc->GetDocumentURI();
5352 if (!targetURI)
5353 return NS_OK;
5356 // Note: This is contrary to the spec with respect to file: URLs, which
5357 // the spec groups into a single origin, but given we intentionally
5358 // don't do that in other places it seems better to hold the line for
5359 // now. Long-term, we want HTML5 to address this so that we can
5360 // be compliant while being safer.
5361 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
5362 nsresult rv =
5363 ssm->CheckSameOriginURI(mProvidedOrigin, targetURI, PR_TRUE);
5364 if (NS_FAILED(rv))
5365 return NS_OK;
5369 // Create the event
5370 nsCOMPtr<nsIDOMDocumentEvent> docEvent =
5371 do_QueryInterface(targetWindow->mDocument);
5372 if (!docEvent)
5373 return NS_OK;
5374 nsCOMPtr<nsIDOMEvent> event;
5375 docEvent->CreateEvent(NS_LITERAL_STRING("MessageEvent"),
5376 getter_AddRefs(event));
5377 if (!event)
5378 return NS_OK;
5380 nsCOMPtr<nsIDOMMessageEvent> message = do_QueryInterface(event);
5381 nsresult rv = message->InitMessageEvent(NS_LITERAL_STRING("message"),
5382 PR_FALSE /* non-bubbling */,
5383 PR_TRUE /* cancelable */,
5384 mMessage,
5385 mCallerOrigin,
5386 EmptyString(),
5387 mSource);
5388 if (NS_FAILED(rv))
5389 return NS_OK;
5392 // We can't simply call dispatchEvent on the window because doing so ends
5393 // up flipping the trusted bit on the event, and we don't want that to
5394 // happen because then untrusted content can call postMessage on a chrome
5395 // window if it can get a reference to it.
5397 nsIPresShell *shell = targetWindow->mDoc->GetShell();
5398 nsRefPtr<nsPresContext> presContext;
5399 if (shell)
5400 presContext = shell->GetPresContext();
5402 nsCOMPtr<nsIPrivateDOMEvent> privEvent = do_QueryInterface(message);
5403 privEvent->SetTrusted(mTrustedCaller);
5404 nsEvent *internalEvent = privEvent->GetInternalNSEvent();
5406 nsEventStatus status = nsEventStatus_eIgnore;
5407 nsEventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow),
5408 presContext,
5409 internalEvent,
5410 message,
5411 &status);
5412 return NS_OK;
5415 NS_IMETHODIMP
5416 nsGlobalWindow::PostMessageMoz(const nsAString& aMessage, const nsAString& aOrigin)
5418 // NB: Since much of what this method does must happen at event dispatch time,
5419 // this method does not forward to the inner window, unlike most other
5420 // methods. We do this because the only time we need to refer to this
5421 // window, we need a reference to the outer window (the PostMessageEvent
5422 // ctor call), and we don't want to pay the price of forwarding to the
5423 // inner window for no actual benefit. Furthermore, this function must
5424 // only be called from script anyway, which should only have references to
5425 // outer windows (and if script has an inner window we've already lost).
5426 NS_ABORT_IF_FALSE(IsOuterWindow(), "only call this method on outer windows");
5429 // Window.postMessage is an intentional subversion of the same-origin policy.
5430 // As such, this code must be particularly careful in the information it
5431 // exposes to calling code.
5433 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5436 // First, get the caller's window
5437 nsRefPtr<nsGlobalWindow> callerInnerWin = CallerInnerWindow();
5438 if (!callerInnerWin)
5439 return NS_OK;
5440 NS_ABORT_IF_FALSE(callerInnerWin->IsInnerWindow(),
5441 "should have gotten an inner window here");
5443 // Compute the caller's origin either from its principal or, in the case the
5444 // principal doesn't carry a URI (e.g. the system principal), the caller's
5445 // document. We must get this now instead of when the event is created and
5446 // dispatched, because ultimately it is the identity of the calling window
5447 // *now* that determines who sent the message (and not an identity which might
5448 // have changed due to intervening navigations).
5449 nsIPrincipal* callerPrin = callerInnerWin->GetPrincipal();
5450 if (!callerPrin)
5451 return NS_OK;
5453 nsCOMPtr<nsIURI> callerOuterURI;
5454 if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI))))
5455 return NS_OK;
5457 nsAutoString origin;
5458 if (callerOuterURI) {
5459 // if the principal has a URI, use that to generate the origin
5460 nsContentUtils::GetUTFOrigin(callerPrin, origin);
5462 else {
5463 // otherwise use the URI of the document to generate origin
5464 nsCOMPtr<nsIDocument> doc = do_QueryInterface(callerInnerWin->mDocument);
5465 if (!doc)
5466 return NS_OK;
5467 callerOuterURI = doc->GetDocumentURI();
5468 // if the principal has a URI, use that to generate the origin
5469 nsContentUtils::GetUTFOrigin(callerOuterURI, origin);
5472 // Convert the provided origin string into a URI for comparison purposes.
5473 // "*" indicates no specific origin is required.
5474 nsCOMPtr<nsIURI> providedOrigin;
5475 if (!aOrigin.EqualsASCII("*")) {
5476 if (NS_FAILED(NS_NewURI(getter_AddRefs(providedOrigin), aOrigin)))
5477 return NS_ERROR_DOM_SYNTAX_ERR;
5478 if (NS_FAILED(providedOrigin->SetUserPass(EmptyCString())) ||
5479 NS_FAILED(providedOrigin->SetPath(EmptyCString())))
5480 return NS_OK;
5483 // Create and asynchronously dispatch a runnable which will handle actual DOM
5484 // event creation and dispatch.
5485 nsRefPtr<PostMessageEvent> event =
5486 new PostMessageEvent(nsContentUtils::IsCallerChrome()
5487 ? nsnull
5488 : callerInnerWin->GetOuterWindowInternal(),
5489 origin,
5490 aMessage,
5491 this,
5492 providedOrigin,
5493 nsContentUtils::IsCallerTrustedForWrite());
5494 return NS_DispatchToCurrentThread(event);
5497 class nsCloseEvent : public nsRunnable {
5499 nsRefPtr<nsGlobalWindow> mWindow;
5501 nsCloseEvent(nsGlobalWindow *aWindow)
5502 : mWindow(aWindow)
5505 public:
5507 static nsresult
5508 PostCloseEvent(nsGlobalWindow* aWindow) {
5509 nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow);
5510 nsresult rv = NS_DispatchToCurrentThread(ev);
5511 if (NS_SUCCEEDED(rv))
5512 aWindow->MaybeForgiveSpamCount();
5513 return rv;
5516 NS_IMETHOD Run() {
5517 if (mWindow)
5518 mWindow->ReallyCloseWindow();
5519 return NS_OK;
5524 PRBool
5525 nsGlobalWindow::CanClose()
5527 if (!mDocShell)
5528 return PR_TRUE;
5530 // Ask the content viewer whether the toplevel window can close.
5531 // If the content viewer returns false, it is responsible for calling
5532 // Close() as soon as it is possible for the window to close.
5533 // This allows us to not close the window while printing is happening.
5535 nsCOMPtr<nsIContentViewer> cv;
5536 mDocShell->GetContentViewer(getter_AddRefs(cv));
5537 if (cv) {
5538 PRBool canClose;
5539 nsresult rv = cv->PermitUnload(PR_FALSE, &canClose);
5540 if (NS_SUCCEEDED(rv) && !canClose)
5541 return PR_FALSE;
5543 rv = cv->RequestWindowClose(&canClose);
5544 if (NS_SUCCEEDED(rv) && !canClose)
5545 return PR_FALSE;
5548 return PR_TRUE;
5551 NS_IMETHODIMP
5552 nsGlobalWindow::Close()
5554 FORWARD_TO_OUTER(Close, (), NS_ERROR_NOT_INITIALIZED);
5556 if (IsFrame() || !mDocShell || IsInModalState()) {
5557 // window.close() is called on a frame in a frameset, on a window
5558 // that's already closed, or on a window for which there's
5559 // currently a modal dialog open. Ignore such calls.
5561 return NS_OK;
5564 if (mHavePendingClose) {
5565 // We're going to be closed anyway; do nothing since we don't want
5566 // to double-close
5567 return NS_OK;
5570 if (mBlockScriptedClosingFlag)
5572 // A script's popup has been blocked and we don't want
5573 // the window to be closed directly after this event,
5574 // so the user can see that there was a blocked popup.
5575 return NS_OK;
5578 // Don't allow scripts from content to close windows
5579 // that were not opened by script
5580 if (!mHadOriginalOpener && !nsContentUtils::IsCallerTrustedForWrite()) {
5581 PRBool allowClose =
5582 nsContentUtils::GetBoolPref("dom.allow_scripts_to_close_windows",
5583 PR_TRUE);
5584 if (!allowClose) {
5585 // We're blocking the close operation
5586 // report localized error msg in JS console
5587 nsContentUtils::ReportToConsole(
5588 nsContentUtils::eDOM_PROPERTIES,
5589 "WindowCloseBlockedWarning",
5590 nsnull, 0, // No params
5591 nsnull, // No URI. Not clear which URI we should be using
5592 // here anyway
5593 EmptyString(), 0, 0, // No source, or column/line number
5594 nsIScriptError::warningFlag,
5595 "DOM Window"); // Better name for the category?
5597 return NS_OK;
5601 if (!mInClose && !mIsClosed && !CanClose())
5602 return NS_OK;
5604 // Fire a DOM event notifying listeners that this window is about to
5605 // be closed. The tab UI code may choose to cancel the default
5606 // action for this event, if so, we won't actually close the window
5607 // (since the tab UI code will close the tab in stead). Sure, this
5608 // could be abused by content code, but do we care? I don't think
5609 // so...
5611 PRBool wasInClose = mInClose;
5612 mInClose = PR_TRUE;
5614 if (!DispatchCustomEvent("DOMWindowClose")) {
5615 // Someone chose to prevent the default action for this event, if
5616 // so, let's not close this window after all...
5618 mInClose = wasInClose;
5619 return NS_OK;
5622 return FinalClose();
5625 nsresult
5626 nsGlobalWindow::ForceClose()
5628 if (IsFrame() || !mDocShell) {
5629 // This may be a frame in a frameset, or a window that's already closed.
5630 // Ignore such calls.
5632 return NS_OK;
5635 if (mHavePendingClose) {
5636 // We're going to be closed anyway; do nothing since we don't want
5637 // to double-close
5638 return NS_OK;
5641 mInClose = PR_TRUE;
5643 DispatchCustomEvent("DOMWindowClose");
5645 return FinalClose();
5648 nsresult
5649 nsGlobalWindow::FinalClose()
5651 nsresult rv;
5652 // Flag that we were closed.
5653 mIsClosed = PR_TRUE;
5655 nsCOMPtr<nsIJSContextStack> stack =
5656 do_GetService(sJSStackContractID);
5658 JSContext *cx = nsnull;
5660 if (stack) {
5661 stack->Peek(&cx);
5664 if (cx) {
5665 nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
5667 if (currentCX && currentCX == GetContextInternal()) {
5668 // We ignore the return value here. If setting the termination function
5669 // fails, it's better to fail to close the window than it is to crash
5670 // (which is what would tend to happen if we did this synchronously
5671 // here).
5672 rv = currentCX->SetTerminationFunction(CloseWindow,
5673 static_cast<nsIDOMWindow *>
5674 (this));
5675 if (NS_SUCCEEDED(rv)) {
5676 mHavePendingClose = PR_TRUE;
5678 return NS_OK;
5683 // We may have plugins on the page that have issued this close from their
5684 // event loop and because we currently destroy the plugin window with
5685 // frames, we crash. So, if we are called from Javascript, post an event
5686 // to really close the window.
5687 rv = NS_ERROR_FAILURE;
5688 if (!nsContentUtils::IsCallerChrome()) {
5689 rv = nsCloseEvent::PostCloseEvent(this);
5692 if (NS_FAILED(rv)) {
5693 ReallyCloseWindow();
5694 rv = NS_OK;
5695 } else {
5696 mHavePendingClose = PR_TRUE;
5699 return rv;
5703 void
5704 nsGlobalWindow::ReallyCloseWindow()
5706 FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
5708 // Make sure we never reenter this method.
5709 mHavePendingClose = PR_TRUE;
5711 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5712 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5714 // If there's no treeOwnerAsWin, this window must already be closed.
5716 if (treeOwnerAsWin) {
5718 // but if we're a browser window we could be in some nasty
5719 // self-destroying cascade that we should mostly ignore
5721 nsCOMPtr<nsIDocShellTreeItem> docItem(do_QueryInterface(mDocShell));
5722 if (docItem) {
5723 nsCOMPtr<nsIBrowserDOMWindow> bwin;
5724 nsCOMPtr<nsIDocShellTreeItem> rootItem;
5725 docItem->GetRootTreeItem(getter_AddRefs(rootItem));
5726 nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
5727 nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
5728 if (chromeWin)
5729 chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
5731 if (rootWin) {
5732 /* Normally we destroy the entire window, but not if
5733 this DOM window belongs to a tabbed browser and doesn't
5734 correspond to a tab. This allows a well-behaved tab
5735 to destroy the container as it should but is a final measure
5736 to prevent an errant tab from doing so when it shouldn't.
5737 This works because we reach this code when we shouldn't only
5738 in the particular circumstance that we belong to a tab
5739 that has just been closed (and is therefore already missing
5740 from the list of browsers) (and has an unload handler
5741 that closes the window). */
5742 // XXXbz now that we have mHavePendingClose, is this needed?
5743 PRBool isTab = PR_FALSE;
5744 if (rootWin == this ||
5745 !bwin || (bwin->IsTabContentWindow(GetOuterWindowInternal(),
5746 &isTab), isTab))
5747 treeOwnerAsWin->Destroy();
5751 CleanUp(PR_FALSE);
5755 void
5756 nsGlobalWindow::EnterModalState()
5758 nsCOMPtr<nsIDOMWindow> top;
5759 GetTop(getter_AddRefs(top));
5761 if (!top) {
5762 NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
5764 return;
5767 nsGlobalWindow* topWin =
5768 static_cast<nsGlobalWindow*>(static_cast<nsIDOMWindow *>(top.get()));
5769 if (topWin->mModalStateDepth == 0) {
5770 NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
5772 mSuspendedDoc = do_QueryInterface(topWin->GetExtantDocument());
5773 if (mSuspendedDoc && mSuspendedDoc->EventHandlingSuppressed()) {
5774 mSuspendedDoc->SuppressEventHandling();
5775 } else {
5776 mSuspendedDoc = nsnull;
5779 topWin->mModalStateDepth++;
5781 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5783 nsIScriptContext *scx;
5784 if (cx && (scx = GetScriptContextFromJSContext(cx))) {
5785 scx->EnterModalState();
5789 // static
5790 void
5791 nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
5792 nsGlobalWindow *aWindow)
5794 nsGlobalWindow *inner;
5796 // Return early if we're frozen or have no inner window.
5797 if (!(inner = aWindow->GetCurrentInnerWindowInternal()) ||
5798 inner->IsFrozen()) {
5799 return;
5802 inner->RunTimeout(nsnull);
5804 // Check again if we're frozen since running pending timeouts
5805 // could've frozen us.
5806 if (inner->IsFrozen()) {
5807 return;
5810 nsCOMPtr<nsIDOMWindowCollection> frames;
5811 aWindow->GetFrames(getter_AddRefs(frames));
5813 if (!frames) {
5814 return;
5817 PRUint32 i, length;
5818 if (NS_FAILED(frames->GetLength(&length)) || !length) {
5819 return;
5822 for (i = 0; i < length && aTopWindow->mModalStateDepth == 0; i++) {
5823 nsCOMPtr<nsIDOMWindow> child;
5824 frames->Item(i, getter_AddRefs(child));
5826 if (!child) {
5827 return;
5830 nsGlobalWindow *childWin =
5831 static_cast<nsGlobalWindow *>
5832 (static_cast<nsIDOMWindow *>
5833 (child.get()));
5835 RunPendingTimeoutsRecursive(aTopWindow, childWin);
5839 class nsPendingTimeoutRunner : public nsRunnable
5841 public:
5842 nsPendingTimeoutRunner(nsGlobalWindow *aWindow)
5843 : mWindow(aWindow)
5845 NS_ASSERTION(mWindow, "mWindow is null.");
5848 NS_IMETHOD Run()
5850 nsGlobalWindow::RunPendingTimeoutsRecursive(mWindow, mWindow);
5852 return NS_OK;
5855 private:
5856 nsRefPtr<nsGlobalWindow> mWindow;
5859 void
5860 nsGlobalWindow::LeaveModalState()
5862 nsCOMPtr<nsIDOMWindow> top;
5863 GetTop(getter_AddRefs(top));
5865 if (!top) {
5866 NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
5868 return;
5871 nsGlobalWindow *topWin =
5872 static_cast<nsGlobalWindow *>
5873 (static_cast<nsIDOMWindow *>
5874 (top.get()));
5876 topWin->mModalStateDepth--;
5878 if (topWin->mModalStateDepth == 0) {
5879 nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
5880 if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
5881 NS_WARNING("failed to dispatch pending timeout runnable");
5883 if (mSuspendedDoc) {
5884 nsCOMPtr<nsIDocument> currentDoc =
5885 do_QueryInterface(topWin->GetExtantDocument());
5886 mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(currentDoc == mSuspendedDoc);
5887 mSuspendedDoc = nsnull;
5891 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5893 nsIScriptContext *scx;
5894 if (cx && (scx = GetScriptContextFromJSContext(cx))) {
5895 scx->LeaveModalState();
5899 PRBool
5900 nsGlobalWindow::IsInModalState()
5902 nsCOMPtr<nsIDOMWindow> top;
5903 GetTop(getter_AddRefs(top));
5905 if (!top) {
5906 NS_ERROR("Uh, IsInModalState() called w/o a reachable top window?");
5908 return PR_FALSE;
5911 return static_cast<nsGlobalWindow *>
5912 (static_cast<nsIDOMWindow *>
5913 (top.get()))->mModalStateDepth != 0;
5916 // static
5917 void
5918 nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow) {
5919 nsCOMPtr<nsIObserverService> observerService =
5920 do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
5921 if (observerService) {
5922 observerService->
5923 NotifyObservers(static_cast<nsIScriptGlobalObject*>(aWindow),
5924 DOM_WINDOW_DESTROYED_TOPIC, nsnull);
5928 class WindowDestroyedEvent : public nsRunnable
5930 public:
5931 WindowDestroyedEvent(PRUint64 aID, const char* aTopic) :
5932 mID(aID), mTopic(aTopic) {}
5934 NS_IMETHOD Run()
5936 nsCOMPtr<nsIObserverService> observerService =
5937 do_GetService("@mozilla.org/observer-service;1");
5938 if (observerService) {
5939 nsCOMPtr<nsISupportsPRUint64> wrapper =
5940 do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
5941 if (wrapper) {
5942 wrapper->SetData(mID);
5943 observerService->NotifyObservers(wrapper, mTopic.get(), nsnull);
5946 return NS_OK;
5949 private:
5950 PRUint64 mID;
5951 nsCString mTopic;
5954 void
5955 nsGlobalWindow::NotifyWindowIDDestroyed(const char* aTopic)
5957 nsRefPtr<nsIRunnable> runnable = new WindowDestroyedEvent(mWindowID, aTopic);
5958 nsresult rv = NS_DispatchToCurrentThread(runnable);
5959 if (NS_SUCCEEDED(rv)) {
5960 mNotifiedIDDestroyed = PR_TRUE;
5964 void
5965 nsGlobalWindow::InitJavaProperties()
5967 nsIScriptContext *scx = GetContextInternal();
5969 if (mDidInitJavaProperties || IsOuterWindow() || !scx || !mJSObject) {
5970 return;
5973 // Set mDidInitJavaProperties to true here even if initialization
5974 // can fail. If it fails, we won't try again...
5975 mDidInitJavaProperties = PR_TRUE;
5977 // Check whether the plugin supports NPRuntime, if so, init through
5978 // it.
5980 nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
5981 if (!host) {
5982 return;
5985 mDummyJavaPluginOwner = new nsDummyJavaPluginOwner(mDoc);
5986 if (!mDummyJavaPluginOwner) {
5987 return;
5990 host->InstantiateDummyJavaPlugin(mDummyJavaPluginOwner);
5992 // It's possible for us (or the Java plugin, rather) to process
5993 // events during the above call, which can lead to this window being
5994 // torn down or what not, so re-check that the dummy plugin is still
5995 // around.
5996 if (!mDummyJavaPluginOwner) {
5997 return;
6000 nsCOMPtr<nsIPluginInstance> dummyPlugin;
6001 mDummyJavaPluginOwner->GetInstance(*getter_AddRefs(dummyPlugin));
6003 if (dummyPlugin) {
6004 // A dummy plugin was instantiated. This means we have a Java
6005 // plugin that supports NPRuntime. For such a plugin, the plugin
6006 // instantiation code defines the Java properties for us, so we're
6007 // done here.
6009 return;
6012 // No NPRuntime enabled Java plugin found, null out the owner we
6013 // would have used in that case as it's no longer needed.
6014 mDummyJavaPluginOwner = nsnull;
6017 void*
6018 nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
6020 void* handler = nsnull;
6021 if (mCachedXBLPrototypeHandlers.IsInitialized()) {
6022 mCachedXBLPrototypeHandlers.Get(aKey, &handler);
6024 return handler;
6027 void
6028 nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
6029 nsScriptObjectHolder& aHandler)
6031 if (!mCachedXBLPrototypeHandlers.IsInitialized() &&
6032 !mCachedXBLPrototypeHandlers.Init()) {
6033 NS_ERROR("Failed to initiailize hashtable!");
6034 return;
6037 if (!mCachedXBLPrototypeHandlers.Count()) {
6038 // Can't use macros to get the participant because nsGlobalChromeWindow also
6039 // runs through this code. Use QueryInterface to get the correct objects.
6040 nsXPCOMCycleCollectionParticipant* participant;
6041 CallQueryInterface(this, &participant);
6042 NS_ASSERTION(participant,
6043 "Failed to QI to nsXPCOMCycleCollectionParticipant!");
6045 nsCOMPtr<nsISupports> thisSupports;
6046 QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
6047 getter_AddRefs(thisSupports));
6048 NS_ASSERTION(thisSupports, "Failed to QI to nsCycleCollectionISupports!");
6050 nsresult rv = nsContentUtils::HoldJSObjects(thisSupports, participant);
6051 if (NS_FAILED(rv)) {
6052 NS_ERROR("nsContentUtils::HoldJSObjects failed!");
6053 return;
6057 mCachedXBLPrototypeHandlers.Put(aKey, aHandler);
6060 NS_IMETHODIMP
6061 nsGlobalWindow::GetFrameElement(nsIDOMElement** aFrameElement)
6063 FORWARD_TO_OUTER(GetFrameElement, (aFrameElement), NS_ERROR_NOT_INITIALIZED);
6065 *aFrameElement = nsnull;
6067 nsCOMPtr<nsIDocShellTreeItem> docShellTI(do_QueryInterface(mDocShell));
6069 if (!docShellTI) {
6070 return NS_OK;
6073 nsCOMPtr<nsIDocShellTreeItem> parent;
6074 docShellTI->GetSameTypeParent(getter_AddRefs(parent));
6076 if (!parent || parent == docShellTI) {
6077 // We're at a chrome boundary, don't expose the chrome iframe
6078 // element to content code.
6080 return NS_OK;
6083 *aFrameElement = mFrameElement;
6084 NS_IF_ADDREF(*aFrameElement);
6086 return NS_OK;
6089 // Helper for converting window.showModalDialog() options (list of ';'
6090 // separated name (:|=) value pairs) to a format that's parsable by
6091 // our normal window opening code.
6093 void
6094 ConvertDialogOptions(const nsAString& aOptions, nsAString& aResult)
6096 nsAString::const_iterator end;
6097 aOptions.EndReading(end);
6099 nsAString::const_iterator iter;
6100 aOptions.BeginReading(iter);
6102 while (iter != end) {
6103 // Skip whitespace.
6104 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6105 ++iter;
6108 nsAString::const_iterator name_start = iter;
6110 // Skip characters until we find whitespace, ';', ':', or '='
6111 while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
6112 *iter != ';' &&
6113 *iter != ':' &&
6114 *iter != '=') {
6115 ++iter;
6118 nsAString::const_iterator name_end = iter;
6120 // Skip whitespace.
6121 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6122 ++iter;
6125 if (*iter == ';') {
6126 // No value found, skip the ';' and keep going.
6127 ++iter;
6129 continue;
6132 nsAString::const_iterator value_start = iter;
6133 nsAString::const_iterator value_end = iter;
6135 if (*iter == ':' || *iter == '=') {
6136 // We found name followed by ':' or '='. Look for a value.
6138 iter++; // Skip the ':' or '='
6140 // Skip whitespace.
6141 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6142 ++iter;
6145 value_start = iter;
6147 // Skip until we find whitespace, or ';'.
6148 while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
6149 *iter != ';') {
6150 ++iter;
6153 value_end = iter;
6155 // Skip whitespace.
6156 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6157 ++iter;
6161 const nsDependentSubstring& name = Substring(name_start, name_end);
6162 const nsDependentSubstring& value = Substring(value_start, value_end);
6164 if (name.LowerCaseEqualsLiteral("center")) {
6165 if (value.LowerCaseEqualsLiteral("on") ||
6166 value.LowerCaseEqualsLiteral("yes") ||
6167 value.LowerCaseEqualsLiteral("1")) {
6168 aResult.AppendLiteral(",centerscreen=1");
6170 } else if (name.LowerCaseEqualsLiteral("dialogwidth")) {
6171 if (!value.IsEmpty()) {
6172 aResult.AppendLiteral(",width=");
6173 aResult.Append(value);
6175 } else if (name.LowerCaseEqualsLiteral("dialogheight")) {
6176 if (!value.IsEmpty()) {
6177 aResult.AppendLiteral(",height=");
6178 aResult.Append(value);
6180 } else if (name.LowerCaseEqualsLiteral("dialogtop")) {
6181 if (!value.IsEmpty()) {
6182 aResult.AppendLiteral(",top=");
6183 aResult.Append(value);
6185 } else if (name.LowerCaseEqualsLiteral("dialogleft")) {
6186 if (!value.IsEmpty()) {
6187 aResult.AppendLiteral(",left=");
6188 aResult.Append(value);
6190 } else if (name.LowerCaseEqualsLiteral("resizable")) {
6191 if (value.LowerCaseEqualsLiteral("on") ||
6192 value.LowerCaseEqualsLiteral("yes") ||
6193 value.LowerCaseEqualsLiteral("1")) {
6194 aResult.AppendLiteral(",resizable=1");
6196 } else if (name.LowerCaseEqualsLiteral("scroll")) {
6197 if (value.LowerCaseEqualsLiteral("off") ||
6198 value.LowerCaseEqualsLiteral("no") ||
6199 value.LowerCaseEqualsLiteral("0")) {
6200 aResult.AppendLiteral(",scrollbars=0");
6204 if (iter == end) {
6205 break;
6208 iter++;
6212 NS_IMETHODIMP
6213 nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs,
6214 const nsAString& aOptions,
6215 nsIVariant **aRetVal)
6217 *aRetVal = nsnull;
6219 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
6221 nsCOMPtr<nsIDOMWindow> dlgWin;
6222 nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
6224 ConvertDialogOptions(aOptions, options);
6226 options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");
6228 // Before bringing up the window, unsuppress painting and flush
6229 // pending reflows.
6230 EnsureReflowFlushAndPaint();
6232 nsresult rv = OpenInternal(aURI, EmptyString(), options,
6233 PR_FALSE, // aDialog
6234 PR_TRUE, // aContentModal
6235 PR_TRUE, // aCalledNoScript
6236 PR_TRUE, // aDoJSFixups
6237 nsnull, aArgs, // args
6238 GetPrincipal(), // aCalleePrincipal
6239 nsnull, // aJSCallerContext
6240 getter_AddRefs(dlgWin));
6242 NS_ENSURE_SUCCESS(rv, rv);
6244 if (dlgWin) {
6245 nsCOMPtr<nsIPrincipal> subjectPrincipal;
6246 rv = nsContentUtils::GetSecurityManager()->
6247 GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
6248 if (NS_FAILED(rv)) {
6249 return rv;
6252 PRBool canAccess = PR_TRUE;
6254 if (subjectPrincipal) {
6255 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
6256 do_QueryInterface(dlgWin);
6257 nsCOMPtr<nsIPrincipal> dialogPrincipal;
6259 if (objPrincipal) {
6260 dialogPrincipal = objPrincipal->GetPrincipal();
6262 rv = subjectPrincipal->Subsumes(dialogPrincipal, &canAccess);
6263 NS_ENSURE_SUCCESS(rv, rv);
6264 } else {
6265 // Uh, not sure what kind of dialog this is. Prevent access to
6266 // be on the safe side...
6268 canAccess = PR_FALSE;
6272 nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(dlgWin));
6274 if (canAccess) {
6275 nsPIDOMWindow *inner = win->GetCurrentInnerWindow();
6277 nsCOMPtr<nsIDOMModalContentWindow> dlgInner(do_QueryInterface(inner));
6279 if (dlgInner) {
6280 dlgInner->GetReturnValue(aRetVal);
6284 nsRefPtr<nsGlobalWindow> winInternal =
6285 static_cast<nsGlobalWindow*>(win.get());
6286 if (winInternal->mCallCleanUpAfterModalDialogCloses) {
6287 winInternal->mCallCleanUpAfterModalDialogCloses = PR_FALSE;
6288 winInternal->CleanUp(PR_TRUE);
6292 return NS_OK;
6295 class CommandDispatcher : public nsRunnable
6297 public:
6298 CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
6299 const nsAString& aAction)
6300 : mDispatcher(aDispatcher), mAction(aAction) {}
6302 NS_IMETHOD Run()
6304 return mDispatcher->UpdateCommands(mAction);
6307 nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
6308 nsString mAction;
6311 NS_IMETHODIMP
6312 nsGlobalWindow::UpdateCommands(const nsAString& anAction)
6314 nsPIDOMWindow *rootWindow = nsGlobalWindow::GetPrivateRoot();
6315 if (!rootWindow)
6316 return NS_OK;
6318 nsCOMPtr<nsIDOMXULDocument> xulDoc =
6319 do_QueryInterface(rootWindow->GetExtantDocument());
6320 // See if we contain a XUL document.
6321 if (xulDoc) {
6322 // Retrieve the command dispatcher and call updateCommands on it.
6323 nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
6324 xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
6325 if (xulCommandDispatcher) {
6326 nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
6327 anAction));
6331 return NS_OK;
6334 PRBool
6335 nsGlobalWindow::GetBlurSuppression()
6337 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
6338 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
6339 PRBool suppress = PR_FALSE;
6340 if (treeOwnerAsWin)
6341 treeOwnerAsWin->GetBlurSuppression(&suppress);
6342 return suppress;
6345 NS_IMETHODIMP
6346 nsGlobalWindow::GetSelection(nsISelection** aSelection)
6348 FORWARD_TO_OUTER(GetSelection, (aSelection), NS_ERROR_NOT_INITIALIZED);
6350 NS_ENSURE_ARG_POINTER(aSelection);
6351 *aSelection = nsnull;
6353 if (!mDocShell)
6354 return NS_OK;
6356 nsCOMPtr<nsIPresShell> presShell;
6357 mDocShell->GetPresShell(getter_AddRefs(presShell));
6359 if (!presShell)
6360 return NS_OK;
6362 *aSelection = presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
6364 NS_IF_ADDREF(*aSelection);
6366 return NS_OK;
6369 NS_IMETHODIMP
6370 nsGlobalWindow::Find(const nsAString& aStr, PRBool aCaseSensitive,
6371 PRBool aBackwards, PRBool aWrapAround, PRBool aWholeWord,
6372 PRBool aSearchInFrames, PRBool aShowDialog,
6373 PRBool *aDidFind)
6375 FORWARD_TO_OUTER(Find, (aStr, aCaseSensitive, aBackwards, aWrapAround,
6376 aWholeWord, aSearchInFrames, aShowDialog, aDidFind),
6377 NS_ERROR_NOT_INITIALIZED);
6379 nsresult rv = NS_OK;
6380 *aDidFind = PR_FALSE;
6382 nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
6383 NS_ENSURE_TRUE(finder, NS_ERROR_FAILURE);
6385 // Set the options of the search
6386 rv = finder->SetSearchString(PromiseFlatString(aStr).get());
6387 NS_ENSURE_SUCCESS(rv, rv);
6388 finder->SetMatchCase(aCaseSensitive);
6389 finder->SetFindBackwards(aBackwards);
6390 finder->SetWrapFind(aWrapAround);
6391 finder->SetEntireWord(aWholeWord);
6392 finder->SetSearchFrames(aSearchInFrames);
6394 // the nsIWebBrowserFind is initialized to use this window
6395 // as the search root, but uses focus to set the current search
6396 // frame. If we're being called from JS (as here), this window
6397 // should be the current search frame.
6398 nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
6399 if (framesFinder) {
6400 framesFinder->SetRootSearchFrame(this); // paranoia
6401 framesFinder->SetCurrentSearchFrame(this);
6404 // The Find API does not accept empty strings. Launch the Find Dialog.
6405 if (aStr.IsEmpty() || aShowDialog) {
6406 // See if the find dialog is already up using nsIWindowMediator
6407 nsCOMPtr<nsIWindowMediator> windowMediator =
6408 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
6410 nsCOMPtr<nsIDOMWindowInternal> findDialog;
6412 if (windowMediator) {
6413 windowMediator->GetMostRecentWindow(NS_LITERAL_STRING("findInPage").get(),
6414 getter_AddRefs(findDialog));
6417 if (findDialog) {
6418 // The Find dialog is already open, bring it to the top.
6419 rv = findDialog->Focus();
6420 } else { // Open a Find dialog
6421 if (finder) {
6422 nsCOMPtr<nsIDOMWindow> dialog;
6423 rv = OpenDialog(NS_LITERAL_STRING("chrome://global/content/finddialog.xul"),
6424 NS_LITERAL_STRING("_blank"),
6425 NS_LITERAL_STRING("chrome, resizable=no, dependent=yes"),
6426 finder, getter_AddRefs(dialog));
6429 } else {
6430 // Launch the search with the passed in search string
6431 rv = finder->FindNext(aDidFind);
6432 NS_ENSURE_SUCCESS(rv, rv);
6435 return rv;
6438 static PRBool
6439 Is8bit(const nsAString& aString)
6441 static const PRUnichar EIGHT_BIT = PRUnichar(~0x00FF);
6443 nsAString::const_iterator done_reading;
6444 aString.EndReading(done_reading);
6446 // for each chunk of |aString|...
6447 PRUint32 fragmentLength = 0;
6448 nsAString::const_iterator iter;
6449 for (aString.BeginReading(iter); iter != done_reading;
6450 iter.advance(PRInt32(fragmentLength))) {
6451 fragmentLength = PRUint32(iter.size_forward());
6452 const PRUnichar* c = iter.get();
6453 const PRUnichar* fragmentEnd = c + fragmentLength;
6455 // for each character in this chunk...
6456 while (c < fragmentEnd)
6457 if (*c++ & EIGHT_BIT)
6458 return PR_FALSE;
6461 return PR_TRUE;
6464 NS_IMETHODIMP
6465 nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
6466 nsAString& aBinaryData)
6468 aBinaryData.Truncate();
6470 if (!Is8bit(aAsciiBase64String)) {
6471 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
6474 PRUint32 dataLen = aAsciiBase64String.Length();
6476 NS_LossyConvertUTF16toASCII base64(aAsciiBase64String);
6477 if (base64.Length() != dataLen) {
6478 return NS_ERROR_OUT_OF_MEMORY;
6481 PRInt32 resultLen = dataLen;
6482 if (!base64.IsEmpty() && base64[dataLen - 1] == '=') {
6483 if (base64.Length() > 1 && base64[dataLen - 2] == '=') {
6484 resultLen = dataLen - 2;
6485 } else {
6486 resultLen = dataLen - 1;
6490 resultLen = ((resultLen * 3) / 4);
6491 // Add 4 extra bytes (one is needed for sure for null termination)
6492 // to the malloc size just to make sure we don't end up writing past
6493 // the allocated memory (the PL_Base64Decode API should really
6494 // provide a guaranteed way to figure this out w/o needing to do the
6495 // above yourself).
6496 char *dest = static_cast<char *>(nsMemory::Alloc(resultLen + 4));
6497 if (!dest) {
6498 return NS_ERROR_OUT_OF_MEMORY;
6501 char *bin_data = PL_Base64Decode(base64.get(), dataLen, dest);
6503 nsresult rv = NS_OK;
6505 if (bin_data) {
6506 CopyASCIItoUTF16(Substring(bin_data, bin_data + resultLen), aBinaryData);
6507 } else {
6508 rv = NS_ERROR_DOM_INVALID_CHARACTER_ERR;
6511 nsMemory::Free(dest);
6513 return rv;
6516 NS_IMETHODIMP
6517 nsGlobalWindow::Btoa(const nsAString& aBinaryData,
6518 nsAString& aAsciiBase64String)
6520 aAsciiBase64String.Truncate();
6522 if (!Is8bit(aBinaryData)) {
6523 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
6526 char *bin_data = ToNewCString(aBinaryData);
6527 if (!bin_data) {
6528 return NS_ERROR_OUT_OF_MEMORY;
6531 PRInt32 resultLen = ((aBinaryData.Length() + 2) / 3) * 4;
6533 char *base64 = PL_Base64Encode(bin_data, aBinaryData.Length(), nsnull);
6534 if (!base64) {
6535 nsMemory::Free(bin_data);
6537 return NS_ERROR_OUT_OF_MEMORY;
6540 CopyASCIItoUTF16(nsDependentCString(base64, resultLen), aAsciiBase64String);
6542 PR_Free(base64);
6543 nsMemory::Free(bin_data);
6545 return NS_OK;
6548 //*****************************************************************************
6549 // nsGlobalWindow::nsIDOMEventTarget
6550 //*****************************************************************************
6552 NS_IMETHODIMP
6553 nsGlobalWindow::AddEventListener(const nsAString& aType,
6554 nsIDOMEventListener* aListener,
6555 PRBool aUseCapture)
6557 FORWARD_TO_INNER_CREATE(AddEventListener, (aType, aListener, aUseCapture),
6558 NS_ERROR_NOT_AVAILABLE);
6560 return AddEventListener(aType, aListener, aUseCapture, PR_FALSE, 0);
6563 NS_IMETHODIMP
6564 nsGlobalWindow::RemoveEventListener(const nsAString& aType,
6565 nsIDOMEventListener* aListener,
6566 PRBool aUseCapture)
6568 return RemoveGroupedEventListener(aType, aListener, aUseCapture, nsnull);
6571 NS_IMETHODIMP
6572 nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, PRBool* _retval)
6574 FORWARD_TO_INNER(DispatchEvent, (aEvent, _retval), NS_OK);
6576 if (!mDoc) {
6577 return NS_ERROR_FAILURE;
6580 // Obtain a presentation shell
6581 nsIPresShell *shell = mDoc->GetShell();
6582 nsRefPtr<nsPresContext> presContext;
6583 if (shell) {
6584 // Retrieve the context
6585 presContext = shell->GetPresContext();
6588 nsEventStatus status = nsEventStatus_eIgnore;
6589 nsresult rv =
6590 nsEventDispatcher::DispatchDOMEvent(GetOuterWindow(), nsnull, aEvent,
6591 presContext, &status);
6593 *_retval = (status != nsEventStatus_eConsumeNoDefault);
6594 return rv;
6597 //*****************************************************************************
6598 // nsGlobalWindow::nsIDOM3EventTarget
6599 //*****************************************************************************
6601 NS_IMETHODIMP
6602 nsGlobalWindow::AddGroupedEventListener(const nsAString & aType,
6603 nsIDOMEventListener *aListener,
6604 PRBool aUseCapture,
6605 nsIDOMEventGroup *aEvtGrp)
6607 FORWARD_TO_INNER_CREATE(AddGroupedEventListener,
6608 (aType, aListener, aUseCapture, aEvtGrp),
6609 NS_ERROR_NOT_AVAILABLE);
6611 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
6612 NS_ENSURE_STATE(manager);
6613 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
6614 return manager->AddEventListenerByType(aListener, aType, flags, aEvtGrp);
6617 NS_IMETHODIMP
6618 nsGlobalWindow::RemoveGroupedEventListener(const nsAString & aType,
6619 nsIDOMEventListener *aListener,
6620 PRBool aUseCapture,
6621 nsIDOMEventGroup *aEvtGrp)
6623 FORWARD_TO_INNER(RemoveGroupedEventListener,
6624 (aType, aListener, aUseCapture, aEvtGrp),
6625 NS_ERROR_NOT_INITIALIZED);
6627 if (mListenerManager) {
6628 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
6630 mListenerManager->RemoveEventListenerByType(aListener, aType, flags,
6631 aEvtGrp);
6633 return NS_OK;
6636 NS_IMETHODIMP
6637 nsGlobalWindow::CanTrigger(const nsAString & type, PRBool *_retval)
6639 return NS_ERROR_NOT_IMPLEMENTED;
6642 NS_IMETHODIMP
6643 nsGlobalWindow::IsRegisteredHere(const nsAString & type, PRBool *_retval)
6645 return NS_ERROR_NOT_IMPLEMENTED;
6648 NS_IMETHODIMP
6649 nsGlobalWindow::AddEventListener(const nsAString& aType,
6650 nsIDOMEventListener *aListener,
6651 PRBool aUseCapture, PRBool aWantsUntrusted,
6652 PRUint8 optional_argc)
6654 NS_ASSERTION(!aWantsUntrusted || optional_argc > 0,
6655 "Won't check if this is chrome, you want to set "
6656 "aWantsUntrusted to PR_FALSE or make the aWantsUntrusted "
6657 "explicit by making optional_argc non-zero.");
6659 if (IsOuterWindow() && mInnerWindow &&
6660 !nsContentUtils::CanCallerAccess(mInnerWindow)) {
6661 return NS_ERROR_DOM_SECURITY_ERR;
6664 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
6665 NS_ENSURE_STATE(manager);
6667 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
6669 if (aWantsUntrusted ||
6670 (optional_argc == 0 && !nsContentUtils::IsChromeDoc(mDoc))) {
6671 flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
6674 return manager->AddEventListenerByType(aListener, aType, flags, nsnull);
6677 nsresult
6678 nsGlobalWindow::AddEventListenerByIID(nsIDOMEventListener* aListener,
6679 const nsIID& aIID)
6681 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
6682 NS_ENSURE_STATE(manager);
6683 return manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
6686 nsresult
6687 nsGlobalWindow::RemoveEventListenerByIID(nsIDOMEventListener* aListener,
6688 const nsIID& aIID)
6690 FORWARD_TO_INNER(RemoveEventListenerByIID, (aListener, aIID),
6691 NS_ERROR_NOT_INITIALIZED);
6693 if (mListenerManager) {
6694 mListenerManager->RemoveEventListenerByIID(aListener, aIID,
6695 NS_EVENT_FLAG_BUBBLE);
6696 return NS_OK;
6698 return NS_ERROR_FAILURE;
6701 nsIEventListenerManager*
6702 nsGlobalWindow::GetListenerManager(PRBool aCreateIfNotFound)
6704 FORWARD_TO_INNER_CREATE(GetListenerManager, (aCreateIfNotFound), nsnull);
6706 if (!mListenerManager) {
6707 if (!aCreateIfNotFound) {
6708 return nsnull;
6711 static NS_DEFINE_CID(kEventListenerManagerCID,
6712 NS_EVENTLISTENERMANAGER_CID);
6714 mListenerManager = do_CreateInstance(kEventListenerManagerCID);
6715 if (mListenerManager) {
6716 mListenerManager->SetListenerTarget(
6717 static_cast<nsPIDOMEventTarget*>(this));
6721 return mListenerManager;
6724 nsresult
6725 nsGlobalWindow::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
6727 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
6728 NS_ENSURE_STATE(manager);
6729 return manager->GetSystemEventGroupLM(aGroup);
6732 nsIScriptContext*
6733 nsGlobalWindow::GetContextForEventHandlers(nsresult* aRv)
6735 nsIScriptContext* scx = GetContext();
6736 *aRv = scx ? NS_OK : NS_ERROR_UNEXPECTED;
6737 return scx;
6740 //*****************************************************************************
6741 // nsGlobalWindow::nsPIDOMWindow
6742 //*****************************************************************************
6744 nsPIDOMWindow*
6745 nsGlobalWindow::GetPrivateParent()
6747 FORWARD_TO_OUTER(GetPrivateParent, (), nsnull);
6749 nsCOMPtr<nsIDOMWindow> parent;
6750 GetParent(getter_AddRefs(parent));
6752 if (static_cast<nsIDOMWindow *>(this) == parent.get()) {
6753 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6754 if (!chromeElement)
6755 return nsnull; // This is ok, just means a null parent.
6757 nsIDocument* doc = chromeElement->GetDocument();
6758 if (!doc)
6759 return nsnull; // This is ok, just means a null parent.
6761 nsIScriptGlobalObject *globalObject = doc->GetScriptGlobalObject();
6762 if (!globalObject)
6763 return nsnull; // This is ok, just means a null parent.
6765 parent = do_QueryInterface(globalObject);
6768 if (parent) {
6769 return static_cast<nsGlobalWindow *>
6770 (static_cast<nsIDOMWindow*>(parent.get()));
6773 return nsnull;
6776 nsPIDOMWindow*
6777 nsGlobalWindow::GetPrivateRoot()
6779 FORWARD_TO_OUTER(GetPrivateRoot, (), nsnull);
6781 nsCOMPtr<nsIDOMWindow> top;
6782 GetTop(getter_AddRefs(top));
6784 nsCOMPtr<nsPIDOMWindow> ptop = do_QueryInterface(top);
6785 NS_ASSERTION(ptop, "cannot get ptop");
6786 if (!ptop)
6787 return nsnull;
6789 nsIDocShell *docShell = ptop->GetDocShell();
6791 // Get the chrome event handler from the doc shell, since we only
6792 // want to deal with XUL chrome handlers and not the new kind of
6793 // window root handler.
6794 nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
6795 docShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
6797 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6798 if (chromeElement) {
6799 nsIDocument* doc = chromeElement->GetDocument();
6800 if (doc) {
6801 nsIDOMWindow *parent = doc->GetWindow();
6802 if (parent) {
6803 parent->GetTop(getter_AddRefs(top));
6808 return static_cast<nsGlobalWindow *>
6809 (static_cast<nsIDOMWindow *>(top));
6813 NS_IMETHODIMP
6814 nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
6816 FORWARD_TO_OUTER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED);
6818 *aLocation = nsnull;
6820 if (!mLocation && mDocShell) {
6821 mLocation = new nsLocation(mDocShell);
6822 if (!mLocation) {
6823 return NS_ERROR_OUT_OF_MEMORY;
6827 NS_IF_ADDREF(*aLocation = mLocation);
6829 return NS_OK;
6832 void
6833 nsGlobalWindow::ActivateOrDeactivate(PRBool aActivate)
6835 // Set / unset mIsActive on the top level window, which is used for the
6836 // :-moz-window-inactive pseudoclass.
6837 nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
6838 if (!mainWidget)
6839 return;
6841 // Get the top level widget (if the main widget is a sheet, this will
6842 // be the sheet's top (non-sheet) parent).
6843 nsCOMPtr<nsIWidget> topLevelWidget = mainWidget->GetSheetWindowParent();
6844 if (!topLevelWidget) {
6845 topLevelWidget = mainWidget;
6848 // Get the top level widget's nsGlobalWindow
6849 nsCOMPtr<nsIDOMWindowInternal> topLevelWindow;
6850 if (topLevelWidget == mainWidget) {
6851 topLevelWindow = static_cast<nsIDOMWindowInternal*>(this);
6852 } else {
6853 // This is a workaround for the following problem:
6854 // When a window with an open sheet loses focus, only the sheet window
6855 // receives the NS_DEACTIVATE event. However, it's not the sheet that
6856 // should lose the active styling, but the containing top level window.
6857 void* clientData;
6858 topLevelWidget->GetClientData(clientData); // clientData is nsXULWindow
6859 nsISupports* data = static_cast<nsISupports*>(clientData);
6860 nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(data));
6861 topLevelWindow = do_GetInterface(req);
6863 if (topLevelWindow) {
6864 nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));
6865 piWin->SetActive(aActivate);
6869 static PRBool
6870 NotifyDocumentTree(nsIDocument* aDocument, void* aData)
6872 aDocument->EnumerateSubDocuments(NotifyDocumentTree, nsnull);
6873 aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
6874 return PR_TRUE;
6877 void
6878 nsGlobalWindow::SetActive(PRBool aActive)
6880 nsPIDOMWindow::SetActive(aActive);
6881 NotifyDocumentTree(mDoc, nsnull);
6884 void
6885 nsGlobalWindow::SetChromeEventHandler(nsPIDOMEventTarget* aChromeEventHandler)
6887 SetChromeEventHandlerInternal(aChromeEventHandler);
6888 if (IsOuterWindow()) {
6889 // update the chrome event handler on all our inner windows
6890 for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
6891 inner != this;
6892 inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
6893 NS_ASSERTION(inner->mOuterWindow == this, "bad outer window pointer");
6894 inner->SetChromeEventHandlerInternal(aChromeEventHandler);
6896 } else if (mOuterWindow) {
6897 // Need the cast to be able to call the protected method on a
6898 // superclass. We could make the method public instead, but it's really
6899 // better this way.
6900 static_cast<nsGlobalWindow*>(mOuterWindow)->
6901 SetChromeEventHandlerInternal(aChromeEventHandler);
6905 static PRBool IsLink(nsIContent* aContent)
6907 nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aContent);
6908 return (anchor || (aContent &&
6909 aContent->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
6910 nsGkAtoms::simple, eCaseMatters)));
6913 void
6914 nsGlobalWindow::SetFocusedNode(nsIContent* aNode,
6915 PRUint32 aFocusMethod,
6916 PRBool aNeedsFocus)
6918 FORWARD_TO_INNER_VOID(SetFocusedNode, (aNode, aFocusMethod, aNeedsFocus));
6920 NS_ASSERTION(!aNode || aNode->GetCurrentDoc() == mDoc,
6921 "setting focus to a node from the wrong document");
6923 if (mFocusedNode != aNode) {
6924 UpdateCanvasFocus(PR_FALSE, aNode);
6925 mFocusedNode = aNode;
6926 mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
6927 mShowFocusRingForContent = PR_FALSE;
6930 if (mFocusedNode) {
6931 // if a node was focused by a keypress, turn on focus rings for the
6932 // window.
6933 if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) {
6934 mFocusByKeyOccurred = PR_TRUE;
6935 } else if (
6936 // otherwise, we set mShowFocusRingForContent, as we don't want this to
6937 // be permanent for the window. On Windows, focus rings are only shown
6938 // when the FLAG_SHOWRING flag is used. On other platforms, focus rings
6939 // are only hidden for clicks on links.
6940 #ifndef XP_WIN
6941 !(mFocusMethod & nsIFocusManager::FLAG_BYMOUSE) || !IsLink(aNode) ||
6942 #endif
6943 aFocusMethod & nsIFocusManager::FLAG_SHOWRING) {
6944 mShowFocusRingForContent = PR_TRUE;
6948 if (aNeedsFocus)
6949 mNeedsFocus = aNeedsFocus;
6952 PRUint32
6953 nsGlobalWindow::GetFocusMethod()
6955 FORWARD_TO_INNER(GetFocusMethod, (), 0);
6957 return mFocusMethod;
6960 PRBool
6961 nsGlobalWindow::ShouldShowFocusRing()
6963 FORWARD_TO_INNER(ShouldShowFocusRing, (), PR_FALSE);
6965 return mShowFocusRings || mShowFocusRingForContent || mFocusByKeyOccurred;
6968 void
6969 nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
6970 UIStateChangeType aShowFocusRings)
6972 FORWARD_TO_INNER_VOID(SetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
6974 // only change the flags that have been modified
6975 if (aShowAccelerators != UIStateChangeType_NoChange)
6976 mShowAccelerators = aShowAccelerators == UIStateChangeType_Set;
6977 if (aShowFocusRings != UIStateChangeType_NoChange)
6978 mShowFocusRings = aShowFocusRings == UIStateChangeType_Set;
6980 // propagate the indicators to child windows
6981 nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(GetDocShell());
6982 if (node) {
6983 PRInt32 childCount = 0;
6984 node->GetChildCount(&childCount);
6986 for (PRInt32 i = 0; i < childCount; ++i) {
6987 nsCOMPtr<nsIDocShellTreeItem> childShell;
6988 node->GetChildAt(i, getter_AddRefs(childShell));
6989 nsCOMPtr<nsPIDOMWindow> childWindow = do_GetInterface(childShell);
6990 if (childWindow) {
6991 childWindow->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
6996 if (mHasFocus) {
6997 // send content state notifications
6998 nsCOMPtr<nsPresContext> presContext;
6999 if (mDocShell) {
7000 mDocShell->GetPresContext(getter_AddRefs(presContext));
7001 if (presContext) {
7002 presContext->EventStateManager()->
7003 SetContentState(mFocusedNode, NS_EVENT_STATE_FOCUS);
7009 void
7010 nsGlobalWindow::GetKeyboardIndicators(PRBool* aShowAccelerators,
7011 PRBool* aShowFocusRings)
7013 FORWARD_TO_INNER_VOID(GetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
7015 *aShowAccelerators = mShowAccelerators;
7016 *aShowFocusRings = mShowFocusRings;
7019 PRBool
7020 nsGlobalWindow::TakeFocus(PRBool aFocus, PRUint32 aFocusMethod)
7022 FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), PR_FALSE);
7024 if (aFocus)
7025 mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
7027 if (mHasFocus != aFocus) {
7028 mHasFocus = aFocus;
7029 UpdateCanvasFocus(PR_TRUE, mFocusedNode);
7032 // if mNeedsFocus is true, then the document has not yet received a
7033 // document-level focus event. If there is a root content node, then return
7034 // true to tell the calling focus manager that a focus event is expected. If
7035 // there is no root content node, the document hasn't loaded enough yet, or
7036 // there isn't one and there is no point in firing a focus event.
7037 if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement() != nsnull) {
7038 mNeedsFocus = PR_FALSE;
7039 return PR_TRUE;
7042 mNeedsFocus = PR_FALSE;
7043 return PR_FALSE;
7046 void
7047 nsGlobalWindow::SetReadyForFocus()
7049 FORWARD_TO_INNER_VOID(SetReadyForFocus, ());
7051 PRBool oldNeedsFocus = mNeedsFocus;
7052 mNeedsFocus = PR_FALSE;
7054 // update whether focus rings need to be shown using the state from the
7055 // root window
7056 nsPIDOMWindow* root = GetPrivateRoot();
7057 if (root) {
7058 PRBool showAccelerators, showFocusRings;
7059 root->GetKeyboardIndicators(&showAccelerators, &showFocusRings);
7060 mShowFocusRings = showFocusRings;
7063 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7064 if (fm)
7065 fm->WindowShown(this, oldNeedsFocus);
7068 void
7069 nsGlobalWindow::PageHidden()
7071 FORWARD_TO_INNER_VOID(PageHidden, ());
7073 // the window is being hidden, so tell the focus manager that the frame is
7074 // no longer valid. Use the persisted field to determine if the document
7075 // is being destroyed.
7077 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7078 if (fm)
7079 fm->WindowHidden(this);
7081 mNeedsFocus = PR_TRUE;
7084 nsresult
7085 nsGlobalWindow::DispatchSyncHashchange()
7087 FORWARD_TO_INNER(DispatchSyncHashchange, (), NS_OK);
7088 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
7089 "Must be safe to run script here.");
7091 // Don't do anything if the window is frozen.
7092 if (IsFrozen())
7093 return NS_OK;
7095 // Dispatch the hashchange event, which doesn't bubble and isn't cancelable,
7096 // to the outer window.
7097 return nsContentUtils::DispatchTrustedEvent(mDoc, GetOuterWindow(),
7098 NS_LITERAL_STRING("hashchange"),
7099 PR_FALSE, PR_FALSE);
7102 nsresult
7103 nsGlobalWindow::DispatchSyncPopState()
7105 FORWARD_TO_INNER(DispatchSyncPopState, (), NS_OK);
7107 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
7108 "Must be safe to run script here.");
7110 // Check that PopState hasn't been pref'ed off.
7111 if (!nsContentUtils::GetBoolPref(sPopStatePrefStr, PR_FALSE))
7112 return NS_OK;
7114 nsresult rv = NS_OK;
7116 // Bail if the window is frozen.
7117 if (IsFrozen()) {
7118 return NS_OK;
7121 // Bail if there's no document or the document's readystate isn't "complete".
7122 if (!mDoc) {
7123 return NS_OK;
7126 nsIDocument::ReadyState readyState = mDoc->GetReadyStateEnum();
7127 if (readyState != nsIDocument::READYSTATE_COMPLETE) {
7128 return NS_OK;
7131 // Get the document's pending state object -- it contains the data we're
7132 // going to send along with the popstate event. The object is serialized as
7133 // JSON.
7134 nsAString& stateObjJSON = mDoc->GetPendingStateObject();
7136 nsCOMPtr<nsIVariant> stateObj;
7137 // Parse the JSON, if there's any to parse.
7138 if (!stateObjJSON.IsEmpty()) {
7139 // Get the JSContext associated with our document. We need this for
7140 // deserialization.
7141 nsCOMPtr<nsIDocument> document = do_QueryInterface(mDocument);
7142 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
7144 // Get the JSContext from the document, like we do in
7145 // nsContentUtils::GetContextFromDocument().
7146 nsIScriptGlobalObject *sgo = document->GetScopeObject();
7147 NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
7149 nsIScriptContext *scx = sgo->GetContext();
7150 NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
7152 JSContext *cx = (JSContext*) scx->GetNativeContext();
7154 // If our json call triggers a JS-to-C++ call, we want that call to use cx
7155 // as the context. So we push cx onto the context stack.
7156 nsCxPusher cxPusher;
7158 jsval jsStateObj = JSVAL_NULL;
7159 // Root the container which will hold our decoded state object.
7160 nsAutoGCRoot root(&jsStateObj, &rv);
7161 NS_ENSURE_SUCCESS(rv, rv);
7163 // Deserialize the state object into an nsIVariant.
7164 nsCOMPtr<nsIJSON> json = do_GetService("@mozilla.org/dom/json;1");
7165 NS_ENSURE_TRUE(cxPusher.Push(cx), NS_ERROR_FAILURE);
7166 rv = json->DecodeToJSVal(stateObjJSON, cx, &jsStateObj);
7167 NS_ENSURE_SUCCESS(rv, rv);
7168 cxPusher.Pop();
7170 nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID());
7171 NS_ENSURE_TRUE(xpconnect, NS_ERROR_FAILURE);
7172 rv = xpconnect->JSValToVariant(cx, &jsStateObj, getter_AddRefs(stateObj));
7173 NS_ENSURE_SUCCESS(rv, rv);
7176 // Obtain a presentation shell for use in creating a popstate event.
7177 nsIPresShell *shell = mDoc->GetShell();
7178 nsRefPtr<nsPresContext> presContext;
7179 if (shell) {
7180 presContext = shell->GetPresContext();
7183 // Create a new popstate event
7184 nsCOMPtr<nsIDOMEvent> domEvent;
7185 rv = nsEventDispatcher::CreateEvent(presContext, nsnull,
7186 NS_LITERAL_STRING("popstateevent"),
7187 getter_AddRefs(domEvent));
7188 NS_ENSURE_SUCCESS(rv, rv);
7190 nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(domEvent);
7191 NS_ENSURE_TRUE(privateEvent, NS_ERROR_FAILURE);
7193 // Initialize the popstate event, which does bubble but isn't cancellable.
7194 nsCOMPtr<nsIDOMPopStateEvent> popstateEvent = do_QueryInterface(domEvent);
7195 rv = popstateEvent->InitPopStateEvent(NS_LITERAL_STRING("popstate"),
7196 PR_TRUE, PR_FALSE,
7197 stateObj);
7198 NS_ENSURE_SUCCESS(rv, rv);
7200 rv = privateEvent->SetTrusted(PR_TRUE);
7201 NS_ENSURE_SUCCESS(rv, rv);
7203 nsCOMPtr<nsIDOMEventTarget> outerWindow =
7204 do_QueryInterface(GetOuterWindow());
7205 NS_ENSURE_TRUE(outerWindow, NS_ERROR_UNEXPECTED);
7207 rv = privateEvent->SetTarget(outerWindow);
7208 NS_ENSURE_SUCCESS(rv, rv);
7210 PRBool dummy; // default action
7211 return DispatchEvent(popstateEvent, &dummy);
7214 // Find an nsICanvasFrame under aFrame. Only search the principal
7215 // child lists. aFrame must be non-null.
7216 static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
7218 nsCanvasFrame* canvasFrame = do_QueryFrame(aFrame);
7219 if (canvasFrame) {
7220 return canvasFrame;
7223 nsIFrame* kid = aFrame->GetFirstChild(nsnull);
7224 while (kid) {
7225 canvasFrame = FindCanvasFrame(kid);
7226 if (canvasFrame) {
7227 return canvasFrame;
7229 kid = kid->GetNextSibling();
7232 return nsnull;
7235 //-------------------------------------------------------
7236 // Tells the HTMLFrame/CanvasFrame that is now has focus
7237 void
7238 nsGlobalWindow::UpdateCanvasFocus(PRBool aFocusChanged, nsIContent* aNewContent)
7240 // this is called from the inner window so use GetDocShell
7241 nsIDocShell* docShell = GetDocShell();
7242 if (!docShell)
7243 return;
7245 nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
7246 if (editorDocShell) {
7247 PRBool editable;
7248 editorDocShell->GetEditable(&editable);
7249 if (editable)
7250 return;
7253 nsCOMPtr<nsIPresShell> presShell;
7254 docShell->GetPresShell(getter_AddRefs(presShell));
7255 if (!presShell || !mDocument)
7256 return;
7258 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
7259 Element *rootElement = doc->GetRootElement();
7260 if (rootElement) {
7261 if ((mHasFocus || aFocusChanged) &&
7262 (mFocusedNode == rootElement || aNewContent == rootElement)) {
7263 nsIFrame* frame = rootElement->GetPrimaryFrame();
7264 if (frame) {
7265 frame = frame->GetParent();
7266 nsCanvasFrame* canvasFrame = do_QueryFrame(frame);
7267 if (canvasFrame) {
7268 canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
7272 } else {
7273 // Look for the frame the hard way
7274 nsIFrame* frame = presShell->GetRootFrame();
7275 if (frame) {
7276 nsCanvasFrame* canvasFrame = FindCanvasFrame(frame);
7277 if (canvasFrame) {
7278 canvasFrame->SetHasFocus(PR_FALSE);
7284 //*****************************************************************************
7285 // nsGlobalWindow::nsIDOMViewCSS
7286 //*****************************************************************************
7288 NS_IMETHODIMP
7289 nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
7290 const nsAString& aPseudoElt,
7291 nsIDOMCSSStyleDeclaration** aReturn)
7293 FORWARD_TO_OUTER(GetComputedStyle, (aElt, aPseudoElt, aReturn),
7294 NS_ERROR_NOT_INITIALIZED);
7296 NS_ENSURE_ARG_POINTER(aReturn);
7297 *aReturn = nsnull;
7299 if (!aElt) {
7300 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
7303 if (!mDocShell) {
7304 return NS_OK;
7307 nsCOMPtr<nsIPresShell> presShell;
7308 mDocShell->GetPresShell(getter_AddRefs(presShell));
7310 if (!presShell) {
7311 return NS_OK;
7314 nsRefPtr<nsComputedDOMStyle> compStyle;
7315 nsresult rv = NS_NewComputedDOMStyle(aElt, aPseudoElt, presShell,
7316 getter_AddRefs(compStyle));
7317 NS_ENSURE_SUCCESS(rv, rv);
7319 *aReturn = compStyle.forget().get();
7321 return NS_OK;
7324 //*****************************************************************************
7325 // nsGlobalWindow::nsIDOMAbstractView
7326 //*****************************************************************************
7328 NS_IMETHODIMP
7329 nsGlobalWindow::GetDocument(nsIDOMDocumentView ** aDocumentView)
7331 NS_ENSURE_ARG_POINTER(aDocumentView);
7333 nsresult rv = NS_OK;
7335 if (mDocument) {
7336 rv = CallQueryInterface(mDocument, aDocumentView);
7338 else {
7339 *aDocumentView = nsnull;
7342 return rv;
7345 //*****************************************************************************
7346 // nsGlobalWindow::nsIDOMStorageWindow
7347 //*****************************************************************************
7349 NS_IMETHODIMP
7350 nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
7352 FORWARD_TO_INNER(GetSessionStorage, (aSessionStorage), NS_ERROR_UNEXPECTED);
7354 nsIPrincipal *principal = GetPrincipal();
7355 nsIDocShell* docShell = GetDocShell();
7357 if (!principal || !docShell) {
7358 return NS_OK;
7361 if (mSessionStorage) {
7362 #ifdef PR_LOGGING
7363 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7364 PR_LogPrint("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage.get());
7366 #endif
7367 nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(mSessionStorage);
7368 if (piStorage) {
7369 PRBool canAccess = piStorage->CanAccess(principal);
7370 NS_ASSERTION(canAccess,
7371 "window %x owned sessionStorage "
7372 "that could not be accessed!");
7373 if (!canAccess) {
7374 mSessionStorage = nsnull;
7379 if (!mSessionStorage) {
7380 *aSessionStorage = nsnull;
7382 nsString documentURI;
7383 nsCOMPtr<nsIDOM3Document> document3 = do_QueryInterface(mDoc);
7384 if (document3)
7385 document3->GetDocumentURI(documentURI);
7387 nsresult rv = docShell->GetSessionStorageForPrincipal(principal,
7388 documentURI,
7389 PR_TRUE,
7390 getter_AddRefs(mSessionStorage));
7391 NS_ENSURE_SUCCESS(rv, rv);
7393 #ifdef PR_LOGGING
7394 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7395 PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get());
7397 #endif
7399 if (!mSessionStorage) {
7400 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
7404 #ifdef PR_LOGGING
7405 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7406 PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get());
7408 #endif
7410 NS_ADDREF(*aSessionStorage = mSessionStorage);
7411 return NS_OK;
7414 NS_IMETHODIMP
7415 nsGlobalWindow::GetGlobalStorage(nsIDOMStorageList ** aGlobalStorage)
7417 NS_ENSURE_ARG_POINTER(aGlobalStorage);
7419 #ifdef MOZ_STORAGE
7420 if (!sGlobalStorageList) {
7421 nsresult rv = NS_NewDOMStorageList(&sGlobalStorageList);
7422 NS_ENSURE_SUCCESS(rv, rv);
7425 *aGlobalStorage = sGlobalStorageList;
7426 NS_IF_ADDREF(*aGlobalStorage);
7428 return NS_OK;
7429 #else
7430 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
7431 #endif
7434 NS_IMETHODIMP
7435 nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage)
7437 FORWARD_TO_INNER(GetLocalStorage, (aLocalStorage), NS_ERROR_UNEXPECTED);
7439 NS_ENSURE_ARG(aLocalStorage);
7441 if (!mLocalStorage) {
7442 *aLocalStorage = nsnull;
7444 nsresult rv;
7446 PRPackedBool unused;
7447 if (!nsDOMStorage::CanUseStorage(&unused))
7448 return NS_ERROR_DOM_SECURITY_ERR;
7450 nsIPrincipal *principal = GetPrincipal();
7451 if (!principal)
7452 return NS_OK;
7454 nsCOMPtr<nsIDOMStorageManager> storageManager =
7455 do_GetService("@mozilla.org/dom/storagemanager;1", &rv);
7456 NS_ENSURE_SUCCESS(rv, rv);
7458 nsString documentURI;
7459 nsCOMPtr<nsIDOM3Document> document3 = do_QueryInterface(mDoc);
7460 if (document3)
7461 document3->GetDocumentURI(documentURI);
7463 rv = storageManager->GetLocalStorageForPrincipal(principal,
7464 documentURI,
7465 getter_AddRefs(mLocalStorage));
7466 NS_ENSURE_SUCCESS(rv, rv);
7469 NS_ADDREF(*aLocalStorage = mLocalStorage);
7470 return NS_OK;
7473 NS_IMETHODIMP
7474 nsGlobalWindow::GetMoz_indexedDB(nsIIDBFactory** _retval)
7476 if (!mIndexedDB) {
7477 mIndexedDB = mozilla::dom::indexedDB::IDBFactory::Create();
7478 NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_FAILURE);
7481 nsCOMPtr<nsIIDBFactory> request(mIndexedDB);
7482 request.forget(_retval);
7483 return NS_OK;
7486 //*****************************************************************************
7487 // nsGlobalWindow::nsIInterfaceRequestor
7488 //*****************************************************************************
7490 NS_IMETHODIMP
7491 nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
7493 NS_ENSURE_ARG_POINTER(aSink);
7494 *aSink = nsnull;
7496 if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
7497 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
7499 if (mDocShell) {
7500 nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(mDocShell));
7501 if (docCharset) {
7502 *aSink = docCharset;
7503 NS_ADDREF(((nsISupports *) *aSink));
7507 else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
7508 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
7510 if (mDocShell) {
7511 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
7512 if (webNav) {
7513 *aSink = webNav;
7514 NS_ADDREF(((nsISupports *) *aSink));
7518 #ifdef NS_PRINTING
7519 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
7520 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
7522 if (mDocShell) {
7523 nsCOMPtr<nsIContentViewer> viewer;
7524 mDocShell->GetContentViewer(getter_AddRefs(viewer));
7525 if (viewer) {
7526 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
7527 if (webBrowserPrint) {
7528 *aSink = webBrowserPrint;
7529 NS_ADDREF(((nsISupports *) *aSink));
7534 #endif
7535 else if (aIID.Equals(NS_GET_IID(nsIScriptEventManager))) {
7536 if (mDoc) {
7537 nsIScriptEventManager* mgr = mDoc->GetScriptEventManager();
7538 if (mgr) {
7539 *aSink = mgr;
7540 NS_ADDREF(((nsISupports *) *aSink));
7544 else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils))) {
7545 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
7547 nsCOMPtr<nsISupports> utils(do_QueryReferent(mWindowUtils));
7548 if (utils) {
7549 *aSink = utils;
7550 NS_ADDREF(((nsISupports *) *aSink));
7551 } else {
7552 nsDOMWindowUtils *utilObj = new nsDOMWindowUtils(this);
7553 nsCOMPtr<nsISupports> utilsIfc =
7554 NS_ISUPPORTS_CAST(nsIDOMWindowUtils *, utilObj);
7555 if (utilsIfc) {
7556 mWindowUtils = do_GetWeakReference(utilsIfc);
7557 *aSink = utilsIfc;
7558 NS_ADDREF(((nsISupports *) *aSink));
7562 else {
7563 return QueryInterface(aIID, aSink);
7566 return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
7569 void
7570 nsGlobalWindow::FireOfflineStatusEvent()
7572 if (!mDoc)
7573 return;
7574 nsAutoString name;
7575 if (NS_IsOffline()) {
7576 name.AssignLiteral("offline");
7577 } else {
7578 name.AssignLiteral("online");
7580 // The event is fired at the body element, or if there is no body element,
7581 // at the document.
7582 nsCOMPtr<nsISupports> eventTarget = mDoc.get();
7583 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDoc);
7584 if (htmlDoc) {
7585 nsCOMPtr<nsIDOMHTMLElement> body;
7586 htmlDoc->GetBody(getter_AddRefs(body));
7587 if (body) {
7588 eventTarget = body;
7591 else {
7592 nsCOMPtr<nsIDOMElement> documentElement;
7593 mDocument->GetDocumentElement(getter_AddRefs(documentElement));
7594 if(documentElement) {
7595 eventTarget = documentElement;
7598 nsContentUtils::DispatchTrustedEvent(mDoc, eventTarget, name, PR_TRUE, PR_FALSE);
7601 nsresult
7602 nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
7603 const PRUnichar* aData)
7605 if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
7606 if (IsFrozen()) {
7607 // if an even number of notifications arrive while we're frozen,
7608 // we don't need to fire.
7609 mFireOfflineStatusChangeEventOnThaw = !mFireOfflineStatusChangeEventOnThaw;
7610 } else {
7611 FireOfflineStatusEvent();
7613 return NS_OK;
7616 if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage-changed")) {
7617 nsIPrincipal *principal;
7618 nsresult rv;
7620 principal = GetPrincipal();
7621 if (principal) {
7622 // A global storage object changed, check to see if it's one
7623 // this window can access.
7625 nsCOMPtr<nsIURI> codebase;
7626 principal->GetURI(getter_AddRefs(codebase));
7628 if (!codebase) {
7629 return NS_OK;
7632 nsCAutoString currentDomain;
7633 rv = codebase->GetAsciiHost(currentDomain);
7634 if (NS_FAILED(rv)) {
7635 return NS_OK;
7638 if (!nsDOMStorageList::CanAccessDomain(NS_ConvertUTF16toUTF8(aData),
7639 currentDomain)) {
7640 // This window can't reach the global storage object for the
7641 // domain for which the change happened, so don't fire any
7642 // events in this window.
7644 return NS_OK;
7648 nsAutoString domain(aData);
7650 if (IsFrozen()) {
7651 // This window is frozen, rather than firing the events here,
7652 // store the domain in which the change happened and fire the
7653 // events if we're ever thawed.
7655 if (!mPendingStorageEventsObsolete) {
7656 mPendingStorageEventsObsolete = new nsDataHashtable<nsStringHashKey, PRBool>;
7657 NS_ENSURE_TRUE(mPendingStorageEventsObsolete, NS_ERROR_OUT_OF_MEMORY);
7659 rv = mPendingStorageEventsObsolete->Init();
7660 NS_ENSURE_SUCCESS(rv, rv);
7663 mPendingStorageEventsObsolete->Put(domain, PR_TRUE);
7665 return NS_OK;
7668 nsRefPtr<nsDOMStorageEventObsolete> event = new nsDOMStorageEventObsolete();
7669 NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
7671 rv = event->InitStorageEvent(NS_LITERAL_STRING("storage"), PR_FALSE, PR_FALSE, domain);
7672 NS_ENSURE_SUCCESS(rv, rv);
7674 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
7676 nsCOMPtr<nsIDOMEventTarget> target;
7678 if (htmlDoc) {
7679 nsCOMPtr<nsIDOMHTMLElement> body;
7680 htmlDoc->GetBody(getter_AddRefs(body));
7682 target = do_QueryInterface(body);
7685 if (!target) {
7686 target = this;
7689 PRBool defaultActionEnabled;
7690 target->DispatchEvent((nsIDOMStorageEventObsolete *)event, &defaultActionEnabled);
7692 return NS_OK;
7695 if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage2-changed")) {
7696 nsIPrincipal *principal;
7697 nsresult rv;
7699 nsCOMPtr<nsIDOMStorageEvent> event = do_QueryInterface(aSubject, &rv);
7700 NS_ENSURE_SUCCESS(rv, rv);
7702 nsCOMPtr<nsIDOMStorage> changingStorage;
7703 rv = event->GetStorageArea(getter_AddRefs(changingStorage));
7704 NS_ENSURE_SUCCESS(rv, rv);
7706 nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(changingStorage);
7707 nsPIDOMStorage::nsDOMStorageType storageType = pistorage->StorageType();
7709 principal = GetPrincipal();
7710 switch (storageType)
7712 case nsPIDOMStorage::SessionStorage:
7714 if (SameCOMIdentity(mSessionStorage, changingStorage)) {
7715 // Do not fire any events for the same storage object, it's not shared
7716 // among windows, see nsGlobalWindow::GetSessionStoarge()
7717 return NS_OK;
7720 nsCOMPtr<nsIDOMStorage> storage = mSessionStorage;
7721 if (!storage) {
7722 nsIDocShell* docShell = GetDocShell();
7723 if (principal && docShell) {
7724 // No need to pass documentURI here, it's only needed when we want
7725 // to create a new storage, the third paramater would be PR_TRUE
7726 docShell->GetSessionStorageForPrincipal(principal,
7727 EmptyString(),
7728 PR_FALSE,
7729 getter_AddRefs(storage));
7733 if (!pistorage->IsForkOf(storage)) {
7734 // This storage event is coming from a different doc shell,
7735 // i.e. it is a clone, ignore this event.
7736 return NS_OK;
7739 #ifdef PR_LOGGING
7740 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7741 PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p", this, mSessionStorage.get(), pistorage.get());
7743 #endif
7745 break;
7747 case nsPIDOMStorage::LocalStorage:
7749 if (SameCOMIdentity(mLocalStorage, changingStorage)) {
7750 // Do not fire any events for the same storage object, it's not shared
7751 // among windows, see nsGlobalWindow::GetLocalStoarge()
7752 return NS_OK;
7755 // Allow event fire only for the same principal storages
7756 // XXX We have to use EqualsIgnoreDomain after bug 495337 lands
7757 nsIPrincipal *storagePrincipal = pistorage->Principal();
7758 PRBool equals;
7760 rv = storagePrincipal->Equals(principal, &equals);
7761 NS_ENSURE_SUCCESS(rv, rv);
7763 if (!equals)
7764 return NS_OK;
7766 break;
7768 default:
7769 return NS_OK;
7772 if (IsFrozen()) {
7773 // This window is frozen, rather than firing the events here,
7774 // store the domain in which the change happened and fire the
7775 // events if we're ever thawed.
7777 mPendingStorageEvents.AppendElement(event);
7778 return NS_OK;
7781 PRBool defaultActionEnabled;
7782 DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled);
7784 return NS_OK;
7787 NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
7788 return NS_ERROR_FAILURE;
7791 static PLDHashOperator
7792 FirePendingStorageEvents(const nsAString& aKey, PRBool aData, void *userArg)
7794 nsGlobalWindow *win = static_cast<nsGlobalWindow *>(userArg);
7796 nsCOMPtr<nsIDOMStorage> storage;
7797 win->GetSessionStorage(getter_AddRefs(storage));
7799 if (storage) {
7800 win->Observe(storage, "dom-storage-changed",
7801 aKey.IsEmpty() ? nsnull : PromiseFlatString(aKey).get());
7804 return PL_DHASH_NEXT;
7807 nsresult
7808 nsGlobalWindow::FireDelayedDOMEvents()
7810 FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
7812 for (PRUint32 i = 0; i < mPendingStorageEvents.Length(); ++i) {
7813 Observe(mPendingStorageEvents[i], "dom-storage2-changed", nsnull);
7816 if (mPendingStorageEventsObsolete) {
7817 // Fire pending storage events.
7818 mPendingStorageEventsObsolete->EnumerateRead(FirePendingStorageEvents, this);
7820 delete mPendingStorageEventsObsolete;
7821 mPendingStorageEventsObsolete = nsnull;
7824 if (mApplicationCache) {
7825 static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
7828 if (mFireOfflineStatusChangeEventOnThaw) {
7829 mFireOfflineStatusChangeEventOnThaw = PR_FALSE;
7830 FireOfflineStatusEvent();
7833 nsCOMPtr<nsIDocShellTreeNode> node =
7834 do_QueryInterface(GetDocShell());
7835 if (node) {
7836 PRInt32 childCount = 0;
7837 node->GetChildCount(&childCount);
7839 for (PRInt32 i = 0; i < childCount; ++i) {
7840 nsCOMPtr<nsIDocShellTreeItem> childShell;
7841 node->GetChildAt(i, getter_AddRefs(childShell));
7842 NS_ASSERTION(childShell, "null child shell");
7844 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
7845 if (pWin) {
7846 nsGlobalWindow *win =
7847 static_cast<nsGlobalWindow*>
7848 (static_cast<nsPIDOMWindow*>(pWin));
7849 win->FireDelayedDOMEvents();
7854 return NS_OK;
7857 //*****************************************************************************
7858 // nsGlobalWindow: Window Control Functions
7859 //*****************************************************************************
7861 nsIDOMWindowInternal *
7862 nsGlobalWindow::GetParentInternal()
7864 FORWARD_TO_OUTER(GetParentInternal, (), nsnull);
7866 nsIDOMWindowInternal *parentInternal = nsnull;
7868 nsCOMPtr<nsIDOMWindow> parent;
7869 GetParent(getter_AddRefs(parent));
7871 if (parent && parent != static_cast<nsIDOMWindow *>(this)) {
7872 nsCOMPtr<nsIDOMWindowInternal> tmp(do_QueryInterface(parent));
7873 NS_ASSERTION(parent, "Huh, parent not an nsIDOMWindowInternal?");
7875 parentInternal = tmp;
7878 return parentInternal;
7881 // static
7882 void
7883 nsGlobalWindow::CloseBlockScriptTerminationFunc(nsISupports *aRef)
7885 nsGlobalWindow* pwin = static_cast<nsGlobalWindow*>
7886 (static_cast<nsPIDOMWindow*>(aRef));
7887 pwin->mBlockScriptedClosingFlag = PR_FALSE;
7890 nsresult
7891 nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
7892 const nsAString& aOptions, PRBool aDialog,
7893 PRBool aContentModal, PRBool aCalledNoScript,
7894 PRBool aDoJSFixups, nsIArray *argv,
7895 nsISupports *aExtraArgument,
7896 nsIPrincipal *aCalleePrincipal,
7897 JSContext *aJSCallerContext,
7898 nsIDOMWindow **aReturn)
7900 FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog,
7901 aContentModal, aCalledNoScript, aDoJSFixups,
7902 argv, aExtraArgument, aCalleePrincipal,
7903 aJSCallerContext, aReturn),
7904 NS_ERROR_NOT_INITIALIZED);
7906 #ifdef NS_DEBUG
7907 PRUint32 argc = 0;
7908 if (argv)
7909 argv->GetLength(&argc);
7910 #endif
7911 NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
7912 "Can't pass in arguments both ways");
7913 NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
7914 "Can't pass JS args when called via the noscript methods");
7915 NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
7916 "Shouldn't have caller context when called noscript");
7918 *aReturn = nsnull;
7920 nsCOMPtr<nsIWebBrowserChrome> chrome;
7921 GetWebBrowserChrome(getter_AddRefs(chrome));
7922 if (!chrome) {
7923 // No chrome means we don't want to go through with this open call
7924 // -- see nsIWindowWatcher.idl
7925 return NS_ERROR_NOT_AVAILABLE;
7928 NS_ASSERTION(mDocShell, "Must have docshell here");
7930 const PRBool checkForPopup =
7931 !aDialog && !WindowExists(aName, !aCalledNoScript);
7933 // Note: it's very important that this be an nsXPIDLCString, since we want
7934 // .get() on it to return nsnull until we write stuff to it. The window
7935 // watcher expects a null URL string if there is no URL to load.
7936 nsXPIDLCString url;
7937 nsresult rv = NS_OK;
7939 // It's important to do this security check before determining whether this
7940 // window opening should be blocked, to ensure that we don't FireAbuseEvents
7941 // for a window opening that wouldn't have succeeded in the first place.
7942 if (!aUrl.IsEmpty()) {
7943 AppendUTF16toUTF8(aUrl, url);
7945 /* Check whether the URI is allowed, but not for dialogs --
7946 see bug 56851. The security of this function depends on
7947 window.openDialog being inaccessible from web scripts */
7948 if (url.get() && !aDialog)
7949 rv = SecurityCheckURL(url.get());
7952 if (NS_FAILED(rv))
7953 return rv;
7955 PopupControlState abuseLevel = gPopupControlState;
7956 if (checkForPopup) {
7957 abuseLevel = RevisePopupAbuseLevel(abuseLevel);
7958 if (abuseLevel >= openAbused) {
7959 if (aJSCallerContext) {
7960 // If script in some other window is doing a window.open on us and
7961 // it's being blocked, then it's OK to close us afterwards, probably.
7962 // But if we're doing a window.open on ourselves and block the popup,
7963 // prevent this window from closing until after this script terminates
7964 // so that whatever popup blocker UI the app has will be visible.
7965 if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
7966 mBlockScriptedClosingFlag = PR_TRUE;
7967 mContext->SetTerminationFunction(CloseBlockScriptTerminationFunc,
7968 static_cast<nsPIDOMWindow*>
7969 (this));
7973 FireAbuseEvents(PR_TRUE, PR_FALSE, aUrl, aName, aOptions);
7974 return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
7978 nsCOMPtr<nsIDOMWindow> domReturn;
7980 nsCOMPtr<nsIWindowWatcher> wwatch =
7981 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
7982 NS_ENSURE_TRUE(wwatch, rv);
7984 NS_ConvertUTF16toUTF8 options(aOptions);
7985 NS_ConvertUTF16toUTF8 name(aName);
7987 const char *options_ptr = aOptions.IsEmpty() ? nsnull : options.get();
7988 const char *name_ptr = aName.IsEmpty() ? nsnull : name.get();
7991 // Reset popup state while opening a window to prevent the
7992 // current state from being active the whole time a modal
7993 // dialog is open.
7994 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
7996 if (!aCalledNoScript) {
7997 nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
7998 NS_ASSERTION(pwwatch,
7999 "Unable to open windows from JS because window watcher "
8000 "is broken");
8001 NS_ENSURE_TRUE(pwwatch, NS_ERROR_UNEXPECTED);
8003 rv = pwwatch->OpenWindowJS(this, url.get(), name_ptr, options_ptr,
8004 aDialog, argv,
8005 getter_AddRefs(domReturn));
8006 } else {
8007 // Push a null JSContext here so that the window watcher won't screw us
8008 // up. We do NOT want this case looking at the JS context on the stack
8009 // when searching. Compare comments on
8010 // nsIDOMWindowInternal::OpenWindow and nsIWindowWatcher::OpenWindow.
8011 nsCOMPtr<nsIJSContextStack> stack;
8013 if (!aContentModal) {
8014 stack = do_GetService(sJSStackContractID);
8017 if (stack) {
8018 rv = stack->Push(nsnull);
8019 NS_ENSURE_SUCCESS(rv, rv);
8022 rv = wwatch->OpenWindow(this, url.get(), name_ptr, options_ptr,
8023 aExtraArgument, getter_AddRefs(domReturn));
8025 if (stack) {
8026 JSContext* cx;
8027 stack->Pop(&cx);
8028 NS_ASSERTION(!cx, "Unexpected JSContext popped!");
8033 NS_ENSURE_SUCCESS(rv, rv);
8035 // success!
8037 domReturn.swap(*aReturn);
8039 if (aDoJSFixups) {
8040 nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
8041 if (!chrome_win) {
8042 // A new non-chrome window was created from a call to
8043 // window.open() from JavaScript, make sure there's a document in
8044 // the new window. We do this by simply asking the new window for
8045 // its document, this will synchronously create an empty document
8046 // if there is no document in the window.
8047 // XXXbz should this just use EnsureInnerWindow()?
8048 #ifdef DEBUG_jst
8050 nsCOMPtr<nsPIDOMWindow> pidomwin(do_QueryInterface(*aReturn));
8052 nsIDOMDocument *temp = pidomwin->GetExtantDocument();
8054 NS_ASSERTION(temp, "No document in new window!!!");
8056 #endif
8058 nsCOMPtr<nsIDOMDocument> doc;
8059 (*aReturn)->GetDocument(getter_AddRefs(doc));
8063 if (checkForPopup) {
8064 if (abuseLevel >= openControlled) {
8065 nsGlobalWindow *opened = static_cast<nsGlobalWindow *>(*aReturn);
8066 if (!opened->IsPopupSpamWindow()) {
8067 opened->SetPopupSpamWindow(PR_TRUE);
8068 ++gOpenPopupSpamCount;
8071 if (abuseLevel >= openAbused)
8072 FireAbuseEvents(PR_FALSE, PR_TRUE, aUrl, aName, aOptions);
8075 return rv;
8078 // static
8079 void
8080 nsGlobalWindow::CloseWindow(nsISupports *aWindow)
8082 nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow));
8084 nsGlobalWindow* globalWin =
8085 static_cast<nsGlobalWindow *>
8086 (static_cast<nsPIDOMWindow*>(win));
8088 // Need to post an event for closing, otherwise window and
8089 // presshell etc. may get destroyed while creating frames, bug 338897.
8090 nsCloseEvent::PostCloseEvent(globalWin);
8091 // else if OOM, better not to close. That might cause a crash.
8094 // static
8095 void
8096 nsGlobalWindow::ClearWindowScope(nsISupports *aWindow)
8098 nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aWindow));
8099 nsIScriptContext *scx = sgo->GetContext();
8100 if (scx) {
8101 scx->ClearScope(sgo->GetGlobalJSObject(), PR_TRUE);
8105 //*****************************************************************************
8106 // nsGlobalWindow: Timeout Functions
8107 //*****************************************************************************
8109 PRUint32 sNestingLevel;
8111 nsresult
8112 nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
8113 PRInt32 interval,
8114 PRBool aIsInterval, PRInt32 *aReturn)
8116 FORWARD_TO_INNER(SetTimeoutOrInterval, (aHandler, interval, aIsInterval, aReturn),
8117 NS_ERROR_NOT_INITIALIZED);
8119 // If we don't have a document (we could have been unloaded since
8120 // the call to setTimeout was made), do nothing.
8121 if (!mDocument) {
8122 return NS_OK;
8125 PRUint32 nestingLevel = sNestingLevel + 1;
8126 if (interval < DOM_MIN_TIMEOUT_VALUE) {
8127 if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
8128 // Don't allow timeouts less than DOM_MIN_TIMEOUT_VALUE from
8129 // now...
8131 interval = DOM_MIN_TIMEOUT_VALUE;
8133 else if (interval < 0) {
8134 // Clamp negative intervals to 0.
8136 interval = 0;
8140 NS_ASSERTION(interval >= 0, "DOM_MIN_TIMEOUT_VALUE lies");
8141 PRUint32 realInterval = interval;
8143 // Make sure we don't proceed with a interval larger than our timer
8144 // code can handle.
8145 if (realInterval > PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE)) {
8146 realInterval = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
8149 nsTimeout *timeout = new nsTimeout();
8150 if (!timeout)
8151 return NS_ERROR_OUT_OF_MEMORY;
8153 // Increment the timeout's reference count to represent this function's hold
8154 // on the timeout.
8155 timeout->AddRef();
8157 if (aIsInterval) {
8158 timeout->mInterval = realInterval;
8160 timeout->mScriptHandler = aHandler;
8162 // Get principal of currently executing code, save for execution of timeout.
8163 // If our principals subsume the subject principal then use the subject
8164 // principal. Otherwise, use our principal to avoid running script in
8165 // elevated principals.
8167 nsCOMPtr<nsIPrincipal> subjectPrincipal;
8168 nsresult rv;
8169 rv = nsContentUtils::GetSecurityManager()->
8170 GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
8171 if (NS_FAILED(rv)) {
8172 timeout->Release();
8174 return NS_ERROR_FAILURE;
8177 PRBool subsumes = PR_FALSE;
8178 nsCOMPtr<nsIPrincipal> ourPrincipal = GetPrincipal();
8180 // Note the direction of this test: We don't allow setTimeouts running with
8181 // chrome privileges on content windows, but we do allow setTimeouts running
8182 // with content privileges on chrome windows (where they can't do very much,
8183 // of course).
8184 rv = ourPrincipal->Subsumes(subjectPrincipal, &subsumes);
8185 if (NS_FAILED(rv)) {
8186 timeout->Release();
8188 return NS_ERROR_FAILURE;
8191 if (subsumes) {
8192 timeout->mPrincipal = subjectPrincipal;
8193 } else {
8194 timeout->mPrincipal = ourPrincipal;
8197 PRTime delta = (PRTime)realInterval * PR_USEC_PER_MSEC;
8199 if (!IsFrozen() && !mTimeoutsSuspendDepth) {
8200 // If we're not currently frozen, then we set timeout->mWhen to be the
8201 // actual firing time of the timer (i.e., now + delta). We also actually
8202 // create a timer and fire it off.
8204 timeout->mWhen = PR_Now() + delta;
8206 timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
8207 if (NS_FAILED(rv)) {
8208 timeout->Release();
8210 return rv;
8213 rv = timeout->mTimer->InitWithFuncCallback(TimerCallback, timeout,
8214 realInterval,
8215 nsITimer::TYPE_ONE_SHOT);
8216 if (NS_FAILED(rv)) {
8217 timeout->Release();
8219 return rv;
8222 // The timeout is now also held in the timer's closure.
8223 timeout->AddRef();
8224 } else {
8225 // If we are frozen, however, then we instead simply set timeout->mWhen to
8226 // be the "time remaining" in the timeout (i.e., the interval itself). We
8227 // don't create a timer for it, since that will happen when we are thawed
8228 // and the timeout will then get a timer and run to completion.
8230 timeout->mWhen = delta;
8233 timeout->mWindow = this;
8235 if (!aIsInterval) {
8236 timeout->mNestingLevel = nestingLevel;
8239 // No popups from timeouts by default
8240 timeout->mPopupState = openAbused;
8242 if (gRunningTimeoutDepth == 0 && gPopupControlState < openAbused) {
8243 // This timeout is *not* set from another timeout and it's set
8244 // while popups are enabled. Propagate the state to the timeout if
8245 // its delay (interval) is equal to or less than what
8246 // "dom.disable_open_click_delay" is set to (in ms).
8248 PRInt32 delay =
8249 nsContentUtils::GetIntPref("dom.disable_open_click_delay");
8251 if (interval <= delay) {
8252 timeout->mPopupState = gPopupControlState;
8256 InsertTimeoutIntoList(timeout);
8258 timeout->mPublicId = ++mTimeoutPublicIdCounter;
8259 *aReturn = timeout->mPublicId;
8261 // Our hold on the timeout is expiring. Note that this should not actually
8262 // free the timeout (since the list should have taken ownership as well).
8263 timeout->Release();
8265 return NS_OK;
8269 nsresult
8270 nsGlobalWindow::SetTimeoutOrInterval(PRBool aIsInterval, PRInt32 *aReturn)
8272 // This needs to forward to the inner window, but since the current
8273 // inner may not be the inner in the calling scope, we need to treat
8274 // this specially here as we don't want timeouts registered in a
8275 // dying inner window to get registered and run on the current inner
8276 // window. To get this right, we need to forward this call to the
8277 // inner window that's calling window.setTimeout().
8279 if (IsOuterWindow()) {
8280 nsGlobalWindow* callerInner = CallerInnerWindow();
8281 NS_ENSURE_TRUE(callerInner, NS_ERROR_NOT_AVAILABLE);
8283 // If the caller and the callee share the same outer window,
8284 // forward to the callee inner. Else, we forward to the current
8285 // inner (e.g. someone is calling setTimeout() on a reference to
8286 // some other window).
8288 if (callerInner->GetOuterWindow() == this &&
8289 callerInner->IsInnerWindow()) {
8290 return callerInner->SetTimeoutOrInterval(aIsInterval, aReturn);
8293 FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
8294 NS_ERROR_NOT_INITIALIZED);
8297 PRInt32 interval = 0;
8298 PRBool isInterval = aIsInterval;
8299 nsCOMPtr<nsIScriptTimeoutHandler> handler;
8300 nsresult rv = NS_CreateJSTimeoutHandler(this,
8301 &isInterval,
8302 &interval,
8303 getter_AddRefs(handler));
8304 if (NS_FAILED(rv))
8305 return (rv == NS_ERROR_DOM_TYPE_ERR) ? NS_OK : rv;
8307 return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
8310 // static
8311 void
8312 nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
8314 // If a modal dialog is open for this window, return early. Pending
8315 // timeouts will run when the modal dialog is dismissed.
8316 if (IsInModalState() || mTimeoutsSuspendDepth) {
8317 return;
8320 NS_TIME_FUNCTION;
8322 NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
8323 NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
8325 nsTimeout *nextTimeout, *timeout;
8326 nsTimeout *last_expired_timeout, *last_insertion_point;
8327 nsTimeout dummy_timeout;
8328 PRUint32 firingDepth = mTimeoutFiringDepth + 1;
8330 // Make sure that the window and the script context don't go away as
8331 // a result of running timeouts
8332 nsCOMPtr<nsIScriptGlobalObject> windowKungFuDeathGrip(this);
8334 // A native timer has gone off. See which of our timeouts need
8335 // servicing
8336 PRTime now = PR_Now();
8337 PRTime deadline;
8339 if (aTimeout && aTimeout->mWhen > now) {
8340 // The OS timer fired early (yikes!), and possibly out of order
8341 // too. Set |deadline| to be the time when the OS timer *should*
8342 // have fired so that any timers that *should* have fired before
8343 // aTimeout *will* be fired now. This happens most of the time on
8344 // Win2k.
8346 deadline = aTimeout->mWhen;
8347 } else {
8348 deadline = now;
8351 // The timeout list is kept in deadline order. Discover the latest
8352 // timeout whose deadline has expired. On some platforms, native
8353 // timeout events fire "early", so we need to test the timer as well
8354 // as the deadline.
8355 last_expired_timeout = nsnull;
8356 for (timeout = FirstTimeout(); IsTimeout(timeout); timeout = timeout->Next()) {
8357 if (((timeout == aTimeout) || (timeout->mWhen <= deadline)) &&
8358 (timeout->mFiringDepth == 0)) {
8359 // Mark any timeouts that are on the list to be fired with the
8360 // firing depth so that we can reentrantly run timeouts
8361 timeout->mFiringDepth = firingDepth;
8362 last_expired_timeout = timeout;
8366 // Maybe the timeout that the event was fired for has been deleted
8367 // and there are no others timeouts with deadlines that make them
8368 // eligible for execution yet. Go away.
8369 if (!last_expired_timeout) {
8370 return;
8373 // Insert a dummy timeout into the list of timeouts between the
8374 // portion of the list that we are about to process now and those
8375 // timeouts that will be processed in a future call to
8376 // win_run_timeout(). This dummy timeout serves as the head of the
8377 // list for any timeouts inserted as a result of running a timeout.
8378 dummy_timeout.mFiringDepth = firingDepth;
8379 PR_INSERT_AFTER(&dummy_timeout, last_expired_timeout);
8381 // Don't let ClearWindowTimeouts throw away our stack-allocated
8382 // dummy timeout.
8383 dummy_timeout.AddRef();
8384 dummy_timeout.AddRef();
8386 last_insertion_point = mTimeoutInsertionPoint;
8387 mTimeoutInsertionPoint = &dummy_timeout;
8389 for (timeout = FirstTimeout();
8390 timeout != &dummy_timeout && !IsFrozen();
8391 timeout = nextTimeout) {
8392 nextTimeout = timeout->Next();
8394 if (timeout->mFiringDepth != firingDepth) {
8395 // We skip the timeout since it's on the list to run at another
8396 // depth.
8398 continue;
8401 if (mTimeoutsSuspendDepth) {
8402 // Some timer did suspend us. Make sure the
8403 // rest of the timers get executed later.
8404 timeout->mFiringDepth = 0;
8405 continue;
8408 // The timeout is on the list to run at this depth, go ahead and
8409 // process it.
8411 // Get the script context (a strong ref to prevent it going away)
8412 // for this timeout and ensure the script language is enabled.
8413 nsCOMPtr<nsIScriptContext> scx = GetScriptContextInternal(
8414 timeout->mScriptHandler->GetScriptTypeID());
8416 if (!scx) {
8417 // No context means this window was closed or never properly
8418 // initialized for this language.
8419 continue;
8422 // The "scripts disabled" concept is still a little vague wrt
8423 // multiple languages. Prepare for the day when languages can be
8424 // disabled independently of the other languages...
8425 if (!scx->GetScriptsEnabled()) {
8426 // Scripts were enabled once in this window (unless aTimeout ==
8427 // nsnull) but now scripts are disabled (we might be in
8428 // print-preview, for instance), this means we shouldn't run any
8429 // timeouts at this point.
8431 // If scripts are enabled for this language in this window again
8432 // we'll fire the timeouts that are due at that point.
8433 continue;
8436 // This timeout is good to run
8437 nsTimeout *last_running_timeout = mRunningTimeout;
8438 mRunningTimeout = timeout;
8439 timeout->mRunning = PR_TRUE;
8441 // Push this timeout's popup control state, which should only be
8442 // eabled the first time a timeout fires that was created while
8443 // popups were enabled and with a delay less than
8444 // "dom.disable_open_click_delay".
8445 nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
8447 // Clear the timeout's popup state, if any, to prevent interval
8448 // timeouts from repeatedly opening poups.
8449 timeout->mPopupState = openAbused;
8451 // Hold on to the timeout in case mExpr or mFunObj releases its
8452 // doc.
8453 timeout->AddRef();
8455 ++gRunningTimeoutDepth;
8456 ++mTimeoutFiringDepth;
8458 PRBool trackNestingLevel = !timeout->mInterval;
8459 PRUint32 nestingLevel;
8460 if (trackNestingLevel) {
8461 nestingLevel = sNestingLevel;
8462 sNestingLevel = timeout->mNestingLevel;
8465 nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
8466 void *scriptObject = handler->GetScriptObject();
8467 if (!scriptObject) {
8468 // Evaluate the timeout expression.
8469 const PRUnichar *script = handler->GetHandlerText();
8470 NS_ASSERTION(script, "timeout has no script nor handler text!");
8472 const char *filename = nsnull;
8473 PRUint32 lineNo = 0;
8474 handler->GetLocation(&filename, &lineNo);
8476 NS_TIME_FUNCTION_MARK("(file: %s, line: %d)", filename, lineNo);
8478 PRBool is_undefined;
8479 scx->EvaluateString(nsDependentString(script),
8480 GetScriptGlobal(handler->GetScriptTypeID()),
8481 timeout->mPrincipal, filename, lineNo,
8482 handler->GetScriptVersion(), nsnull,
8483 &is_undefined);
8484 } else {
8485 // Let the script handler know about the "secret" final argument that
8486 // indicates timeout lateness in milliseconds
8487 PRTime lateness = now - timeout->mWhen;
8489 // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
8490 // PRTime to make the division do the right thing on 64-bit
8491 // platforms whether lateness is positive or negative.
8492 handler->SetLateness((PRIntervalTime)(lateness /
8493 (PRTime)PR_USEC_PER_MSEC));
8495 nsCOMPtr<nsIVariant> dummy;
8496 nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
8497 scx->CallEventHandler(me,
8498 GetScriptGlobal(handler->GetScriptTypeID()),
8499 scriptObject, handler->GetArgv(),
8500 // XXXmarkh - consider allowing CallEventHandler to
8501 // accept nsnull?
8502 getter_AddRefs(dummy));
8505 handler = nsnull; // drop reference before dropping timeout refs.
8507 if (trackNestingLevel) {
8508 sNestingLevel = nestingLevel;
8511 --mTimeoutFiringDepth;
8512 --gRunningTimeoutDepth;
8514 mRunningTimeout = last_running_timeout;
8515 timeout->mRunning = PR_FALSE;
8517 // We ignore any failures from calling EvaluateString() or
8518 // CallEventHandler() on the context here since we're in a loop
8519 // where we're likely to be running timeouts whose OS timers
8520 // didn't fire in time and we don't want to not fire those timers
8521 // now just because execution of one timer failed. We can't
8522 // propagate the error to anyone who cares about it from this
8523 // point anyway, and the script context should have already reported
8524 // the script error in the usual way - so we just drop it.
8526 // If all timeouts were cleared and |timeout != aTimeout| then
8527 // |timeout| may be the last reference to the timeout so check if
8528 // it was cleared before releasing it.
8529 PRBool timeout_was_cleared = timeout->mCleared;
8531 timeout->Release();
8533 if (timeout_was_cleared) {
8534 // The running timeout's window was cleared, this means that
8535 // ClearAllTimeouts() was called from a *nested* call, possibly
8536 // through a timeout that fired while a modal (to this window)
8537 // dialog was open or through other non-obvious paths.
8539 mTimeoutInsertionPoint = last_insertion_point;
8541 return;
8544 PRBool isInterval = PR_FALSE;
8546 // If we have a regular interval timer, we re-schedule the
8547 // timeout, accounting for clock drift.
8548 if (timeout->mInterval) {
8549 // Compute time to next timeout for interval timer.
8550 PRTime nextInterval = (PRTime)timeout->mInterval * PR_USEC_PER_MSEC;
8552 // Make sure nextInterval is at least DOM_MIN_TIMEOUT_VALUE.
8553 // Note: We must cast the rhs expression to PRTime to work
8554 // around what looks like a compiler bug on x86_64.
8555 if (nextInterval < (PRTime)(DOM_MIN_TIMEOUT_VALUE * PR_USEC_PER_MSEC)) {
8556 nextInterval = DOM_MIN_TIMEOUT_VALUE * PR_USEC_PER_MSEC;
8559 // If we're running pending timeouts because they've been temporarily
8560 // disabled (!aTimeout), set the next interval to be relative to "now",
8561 // and not to when the timeout that was pending should have fired. Also
8562 // check if the next interval timeout is overdue. If so, then restart
8563 // the interval from now.
8564 if (!aTimeout || nextInterval + timeout->mWhen <= now)
8565 nextInterval += now;
8566 else
8567 nextInterval += timeout->mWhen;
8569 PRTime delay = nextInterval - PR_Now();
8571 // And make sure delay is nonnegative; that might happen if the timer
8572 // thread is firing our timers somewhat early.
8573 if (delay < 0) {
8574 delay = 0;
8577 if (timeout->mTimer) {
8578 timeout->mWhen = nextInterval;
8580 // Reschedule the OS timer. Don't bother returning any error
8581 // codes if this fails since the callers of this method
8582 // doesn't care about them nobody who cares about them
8583 // anyways.
8585 // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
8586 // PRTime to make the division do the right thing on 64-bit
8587 // platforms whether delay is positive or negative (which we
8588 // know is always positive here, but cast anyways for
8589 // consistency).
8590 nsresult rv = timeout->mTimer->
8591 InitWithFuncCallback(TimerCallback, timeout,
8592 (PRInt32)(delay / (PRTime)PR_USEC_PER_MSEC),
8593 nsITimer::TYPE_ONE_SHOT);
8595 if (NS_FAILED(rv)) {
8596 NS_ERROR("Error initializing timer for DOM timeout!");
8598 // We failed to initialize the new OS timer, this timer does
8599 // us no good here so we just cancel it (just in case) and
8600 // null out the pointer to the OS timer, this will release the
8601 // OS timer. As we continue executing the code below we'll end
8602 // up deleting the timeout since it's not an interval timeout
8603 // any more (since timeout->mTimer == nsnull).
8604 timeout->mTimer->Cancel();
8605 timeout->mTimer = nsnull;
8607 // Now that the OS timer no longer has a reference to the
8608 // timeout we need to drop that reference.
8609 timeout->Release();
8611 } else {
8612 NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth,
8613 "How'd our timer end up null if we're not frozen or "
8614 "suspended?");
8616 timeout->mWhen = delay;
8617 isInterval = PR_TRUE;
8621 if (timeout->mTimer) {
8622 if (timeout->mInterval) {
8623 isInterval = PR_TRUE;
8624 } else {
8625 // The timeout still has an OS timer, and it's not an
8626 // interval, that means that the OS timer could still fire (if
8627 // it didn't already, i.e. aTimeout == timeout), cancel the OS
8628 // timer and release its reference to the timeout.
8629 timeout->mTimer->Cancel();
8630 timeout->mTimer = nsnull;
8632 timeout->Release();
8636 // Running a timeout can cause another timeout to be deleted, so
8637 // we need to reset the pointer to the following timeout.
8638 nextTimeout = timeout->Next();
8640 PR_REMOVE_LINK(timeout);
8642 if (isInterval) {
8643 // Reschedule an interval timeout. Insert interval timeout
8644 // onto list sorted in deadline order.
8645 // AddRefs timeout.
8646 InsertTimeoutIntoList(timeout);
8649 // Release the timeout struct since it's possibly out of the list
8650 timeout->Release();
8653 // Take the dummy timeout off the head of the list
8654 PR_REMOVE_LINK(&dummy_timeout);
8656 mTimeoutInsertionPoint = last_insertion_point;
8659 nsrefcnt
8660 nsTimeout::Release()
8662 if (--mRefCnt > 0)
8663 return mRefCnt;
8665 // language specific cleanup done as mScriptHandler destructs...
8667 // Kill the timer if it is still alive.
8668 if (mTimer) {
8669 mTimer->Cancel();
8670 mTimer = nsnull;
8673 delete this;
8674 return 0;
8677 nsrefcnt
8678 nsTimeout::AddRef()
8680 return ++mRefCnt;
8684 nsresult
8685 nsGlobalWindow::ClearTimeoutOrInterval(PRInt32 aTimerID)
8687 FORWARD_TO_INNER(ClearTimeoutOrInterval, (aTimerID), NS_ERROR_NOT_INITIALIZED);
8689 PRUint32 public_id = (PRUint32)aTimerID;
8690 nsTimeout *timeout;
8692 for (timeout = FirstTimeout();
8693 IsTimeout(timeout);
8694 timeout = timeout->Next()) {
8695 if (timeout->mPublicId == public_id) {
8696 if (timeout->mRunning) {
8697 /* We're running from inside the timeout. Mark this
8698 timeout for deferred deletion by the code in
8699 RunTimeout() */
8700 timeout->mInterval = 0;
8702 else {
8703 /* Delete the timeout from the pending timeout list */
8704 PR_REMOVE_LINK(timeout);
8706 if (timeout->mTimer) {
8707 timeout->mTimer->Cancel();
8708 timeout->mTimer = nsnull;
8709 timeout->Release();
8711 timeout->Release();
8713 break;
8717 return NS_OK;
8720 // A JavaScript specific version.
8721 nsresult
8722 nsGlobalWindow::ClearTimeoutOrInterval()
8724 FORWARD_TO_INNER(ClearTimeoutOrInterval, (), NS_ERROR_NOT_INITIALIZED);
8726 nsresult rv = NS_OK;
8727 nsAXPCNativeCallContext *ncc = nsnull;
8729 rv = nsContentUtils::XPConnect()->
8730 GetCurrentNativeCallContext(&ncc);
8731 NS_ENSURE_SUCCESS(rv, rv);
8733 if (!ncc)
8734 return NS_ERROR_NOT_AVAILABLE;
8736 JSContext *cx = nsnull;
8738 rv = ncc->GetJSContext(&cx);
8739 NS_ENSURE_SUCCESS(rv, rv);
8741 PRUint32 argc;
8743 ncc->GetArgc(&argc);
8745 if (argc < 1) {
8746 // No arguments, return early.
8748 return NS_OK;
8751 jsval *argv = nsnull;
8753 ncc->GetArgvPtr(&argv);
8755 int32 timer_id;
8757 JSAutoRequest ar(cx);
8759 // XXXjst: Can we deal with this w/o using GetCurrentNativeCallContext()
8760 if (argv[0] == JSVAL_VOID || !::JS_ValueToInt32(cx, argv[0], &timer_id) ||
8761 timer_id <= 0) {
8762 // Undefined or non-positive number passed as argument, return
8763 // early. Make sure that JS_ValueToInt32 didn't set an exception.
8765 ::JS_ClearPendingException(cx);
8766 return NS_OK;
8769 return ClearTimeoutOrInterval(timer_id);
8772 void
8773 nsGlobalWindow::ClearAllTimeouts()
8775 nsTimeout *timeout, *nextTimeout;
8777 for (timeout = FirstTimeout(); IsTimeout(timeout); timeout = nextTimeout) {
8778 /* If RunTimeout() is higher up on the stack for this
8779 window, e.g. as a result of document.write from a timeout,
8780 then we need to reset the list insertion point for
8781 newly-created timeouts in case the user adds a timeout,
8782 before we pop the stack back to RunTimeout. */
8783 if (mRunningTimeout == timeout)
8784 mTimeoutInsertionPoint = nsnull;
8786 nextTimeout = timeout->Next();
8788 if (timeout->mTimer) {
8789 timeout->mTimer->Cancel();
8790 timeout->mTimer = nsnull;
8792 // Drop the count since the timer isn't going to hold on
8793 // anymore.
8794 timeout->Release();
8797 // Set timeout->mCleared to true to indicate that the timeout was
8798 // cleared and taken out of the list of timeouts
8799 timeout->mCleared = PR_TRUE;
8801 // Drop the count since we're removing it from the list.
8802 timeout->Release();
8805 // Clear out our list
8806 PR_INIT_CLIST(&mTimeouts);
8809 void
8810 nsGlobalWindow::InsertTimeoutIntoList(nsTimeout *aTimeout)
8812 NS_ASSERTION(IsInnerWindow(),
8813 "InsertTimeoutIntoList() called on outer window!");
8815 // Start at mLastTimeout and go backwards. Don't go further than
8816 // mTimeoutInsertionPoint, though. This optimizes for the common case of
8817 // insertion at the end.
8818 nsTimeout* prevSibling;
8819 for (prevSibling = LastTimeout();
8820 IsTimeout(prevSibling) && prevSibling != mTimeoutInsertionPoint &&
8821 prevSibling->mWhen > aTimeout->mWhen;
8822 prevSibling = prevSibling->Prev()) {
8823 /* Do nothing; just searching */
8826 // Now link in aTimeout after prevSibling.
8827 PR_INSERT_AFTER(aTimeout, prevSibling);
8829 aTimeout->mFiringDepth = 0;
8831 // Increment the timeout's reference count since it's now held on to
8832 // by the list
8833 aTimeout->AddRef();
8836 // static
8837 void
8838 nsGlobalWindow::TimerCallback(nsITimer *aTimer, void *aClosure)
8840 nsTimeout *timeout = (nsTimeout *)aClosure;
8842 // Hold on to the timeout to ensure it doesn't go away while it's
8843 // being handled (aka kungFuDeathGrip).
8844 timeout->AddRef();
8846 timeout->mWindow->RunTimeout(timeout);
8848 // Drop our reference to the timeout now that we're done with it.
8849 timeout->Release();
8852 //*****************************************************************************
8853 // nsGlobalWindow: Helper Functions
8854 //*****************************************************************************
8856 nsresult
8857 nsGlobalWindow::GetTreeOwner(nsIDocShellTreeOwner **aTreeOwner)
8859 FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
8861 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
8863 // If there's no docShellAsItem, this window must have been closed,
8864 // in that case there is no tree owner.
8866 if (!docShellAsItem) {
8867 *aTreeOwner = nsnull;
8869 return NS_OK;
8872 return docShellAsItem->GetTreeOwner(aTreeOwner);
8875 nsresult
8876 nsGlobalWindow::GetTreeOwner(nsIBaseWindow **aTreeOwner)
8878 FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
8880 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
8881 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
8883 // If there's no docShellAsItem, this window must have been closed,
8884 // in that case there is no tree owner.
8886 if (docShellAsItem) {
8887 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
8890 if (!treeOwner) {
8891 *aTreeOwner = nsnull;
8892 return NS_OK;
8895 return CallQueryInterface(treeOwner, aTreeOwner);
8898 nsresult
8899 nsGlobalWindow::GetWebBrowserChrome(nsIWebBrowserChrome **aBrowserChrome)
8901 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
8902 GetTreeOwner(getter_AddRefs(treeOwner));
8904 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner));
8905 NS_IF_ADDREF(*aBrowserChrome = browserChrome);
8907 return NS_OK;
8910 nsIScrollableFrame *
8911 nsGlobalWindow::GetScrollFrame()
8913 FORWARD_TO_OUTER(GetScrollFrame, (), nsnull);
8915 if (!mDocShell) {
8916 return nsnull;
8919 nsCOMPtr<nsIPresShell> presShell;
8920 mDocShell->GetPresShell(getter_AddRefs(presShell));
8921 if (presShell) {
8922 return presShell->GetRootScrollFrameAsScrollable();
8924 return nsnull;
8927 nsresult
8928 nsGlobalWindow::BuildURIfromBase(const char *aURL, nsIURI **aBuiltURI,
8929 PRBool *aFreeSecurityPass,
8930 JSContext **aCXused)
8932 nsIScriptContext *scx = GetContextInternal();
8933 JSContext *cx = nsnull;
8935 *aBuiltURI = nsnull;
8936 *aFreeSecurityPass = PR_FALSE;
8937 if (aCXused)
8938 *aCXused = nsnull;
8940 // get JSContext
8941 NS_ASSERTION(scx, "opening window missing its context");
8942 NS_ASSERTION(mDocument, "opening window missing its document");
8943 if (!scx || !mDocument)
8944 return NS_ERROR_FAILURE;
8946 nsCOMPtr<nsIDOMChromeWindow> chrome_win =
8947 do_QueryInterface(static_cast<nsIDOMWindow *>(this));
8949 if (nsContentUtils::IsCallerChrome() && !chrome_win) {
8950 // If open() is called from chrome on a non-chrome window, we'll
8951 // use the context from the window on which open() is being called
8952 // to prevent giving chrome priveleges to new windows opened in
8953 // such a way. This also makes us get the appropriate base URI for
8954 // the below URI resolution code.
8956 cx = (JSContext *)scx->GetNativeContext();
8957 } else {
8958 // get the JSContext from the call stack
8959 nsCOMPtr<nsIThreadJSContextStack> stack(do_GetService(sJSStackContractID));
8960 if (stack)
8961 stack->Peek(&cx);
8964 /* resolve the URI, which could be relative to the calling window
8965 (note the algorithm to get the base URI should match the one
8966 used to actually kick off the load in nsWindowWatcher.cpp). */
8967 nsCAutoString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
8968 nsIURI* baseURI = nsnull;
8969 nsCOMPtr<nsIURI> uriToLoad;
8970 nsCOMPtr<nsIDOMWindow> sourceWindow;
8972 if (cx) {
8973 nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx);
8974 if (scriptcx)
8975 sourceWindow = do_QueryInterface(scriptcx->GetGlobalObject());
8978 if (!sourceWindow) {
8979 sourceWindow = do_QueryInterface(NS_ISUPPORTS_CAST(nsIDOMWindow *, this));
8980 *aFreeSecurityPass = PR_TRUE;
8983 if (sourceWindow) {
8984 nsCOMPtr<nsIDOMDocument> domDoc;
8985 sourceWindow->GetDocument(getter_AddRefs(domDoc));
8986 nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
8987 if (doc) {
8988 baseURI = doc->GetDocBaseURI();
8989 charset = doc->GetDocumentCharacterSet();
8993 if (aCXused)
8994 *aCXused = cx;
8995 return NS_NewURI(aBuiltURI, nsDependentCString(aURL), charset.get(), baseURI);
8998 nsresult
8999 nsGlobalWindow::SecurityCheckURL(const char *aURL)
9001 JSContext *cx;
9002 PRBool freePass;
9003 nsCOMPtr<nsIURI> uri;
9005 if (NS_FAILED(BuildURIfromBase(aURL, getter_AddRefs(uri), &freePass, &cx)))
9006 return NS_ERROR_FAILURE;
9008 if (!freePass && NS_FAILED(nsContentUtils::GetSecurityManager()->
9009 CheckLoadURIFromScript(cx, uri)))
9010 return NS_ERROR_FAILURE;
9012 return NS_OK;
9015 void
9016 nsGlobalWindow::FlushPendingNotifications(mozFlushType aType)
9018 if (mDoc) {
9019 mDoc->FlushPendingNotifications(aType);
9023 void
9024 nsGlobalWindow::EnsureSizeUpToDate()
9026 // If we're a subframe, make sure our size is up to date. It's OK that this
9027 // crosses the content/chrome boundary, since chrome can have pending reflows
9028 // too.
9029 nsGlobalWindow *parent =
9030 static_cast<nsGlobalWindow *>(GetPrivateParent());
9031 if (parent) {
9032 parent->FlushPendingNotifications(Flush_Layout);
9036 nsresult
9037 nsGlobalWindow::SaveWindowState(nsISupports **aState)
9039 NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
9041 *aState = nsnull;
9043 if (!mContext || !mJSObject) {
9044 // The window may be getting torn down; don't bother saving state.
9045 return NS_OK;
9048 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
9049 NS_ASSERTION(inner, "No inner window to save");
9051 // Don't do anything else to this inner window! After this point, all
9052 // calls to SetTimeoutOrInterval will create entries in the timeout
9053 // list that will only run after this window has come out of the bfcache.
9054 // Also, while we're frozen, we won't dispatch online/offline events
9055 // to the page.
9056 inner->Freeze();
9058 // Remember the outer window's XPConnect prototype.
9059 nsCOMPtr<nsIClassInfo> ci =
9060 do_QueryInterface((nsIScriptGlobalObject *)this);
9061 nsCOMPtr<nsIXPConnectJSObjectHolder> proto;
9062 nsresult rv = nsContentUtils::XPConnect()->
9063 GetWrappedNativePrototype((JSContext *)mContext->GetNativeContext(),
9064 mJSObject, ci, getter_AddRefs(proto));
9065 NS_ENSURE_SUCCESS(rv, rv);
9067 nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
9068 mInnerWindowHolder,
9069 mNavigator,
9070 mLocation,
9071 proto);
9072 NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
9074 #ifdef DEBUG_PAGE_CACHE
9075 printf("saving window state, state = %p\n", (void*)state);
9076 #endif
9078 state.swap(*aState);
9079 return NS_OK;
9082 nsresult
9083 nsGlobalWindow::RestoreWindowState(nsISupports *aState)
9085 NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
9087 if (!mContext || !mJSObject) {
9088 // The window may be getting torn down; don't bother restoring state.
9089 return NS_OK;
9092 nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
9093 NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
9095 #ifdef DEBUG_PAGE_CACHE
9096 printf("restoring window state, state = %p\n", (void*)holder);
9097 #endif
9099 // And we're ready to go!
9100 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
9102 // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
9103 // it easy to tell which link was last clicked when going back a page.
9104 nsIContent* focusedNode = inner->GetFocusedNode();
9105 if (IsLink(focusedNode)) {
9106 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
9107 if (fm) {
9108 nsCOMPtr<nsIDOMElement> focusedElement(do_QueryInterface(focusedNode));
9109 fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
9110 nsIFocusManager::FLAG_SHOWRING);
9114 inner->Thaw();
9116 holder->DidRestoreWindow();
9118 return NS_OK;
9121 void
9122 nsGlobalWindow::SuspendTimeouts(PRUint32 aIncrease,
9123 PRBool aFreezeChildren)
9125 FORWARD_TO_INNER_VOID(SuspendTimeouts, (aIncrease, aFreezeChildren));
9127 PRBool suspended = (mTimeoutsSuspendDepth != 0);
9128 mTimeoutsSuspendDepth += aIncrease;
9130 if (!suspended) {
9131 nsDOMThreadService* dts = nsDOMThreadService::get();
9132 if (dts) {
9133 dts->SuspendWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
9136 PRTime now = PR_Now();
9137 for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
9138 // Change mWhen to be the time remaining for this timer.
9139 if (t->mWhen > now)
9140 t->mWhen -= now;
9141 else
9142 t->mWhen = 0;
9144 // Drop the XPCOM timer; we'll reschedule when restoring the state.
9145 if (t->mTimer) {
9146 t->mTimer->Cancel();
9147 t->mTimer = nsnull;
9149 // Drop the reference that the timer's closure had on this timeout, we'll
9150 // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
9151 // passing null for the context, since this shouldn't actually release this
9152 // timeout.
9153 t->Release();
9158 // Suspend our children as well.
9159 nsCOMPtr<nsIDocShellTreeNode> node(do_QueryInterface(GetDocShell()));
9160 if (node) {
9161 PRInt32 childCount = 0;
9162 node->GetChildCount(&childCount);
9164 for (PRInt32 i = 0; i < childCount; ++i) {
9165 nsCOMPtr<nsIDocShellTreeItem> childShell;
9166 node->GetChildAt(i, getter_AddRefs(childShell));
9167 NS_ASSERTION(childShell, "null child shell");
9169 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
9170 if (pWin) {
9171 nsGlobalWindow *win =
9172 static_cast<nsGlobalWindow*>
9173 (static_cast<nsPIDOMWindow*>(pWin));
9174 NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
9175 nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
9177 // This is a bit hackish. Only freeze/suspend windows which are truly our
9178 // subwindows.
9179 nsCOMPtr<nsIContent> frame = do_QueryInterface(pWin->GetFrameElementInternal());
9180 if (!mDoc || !frame || mDoc != frame->GetOwnerDoc() || !inner) {
9181 continue;
9184 win->SuspendTimeouts(aIncrease, aFreezeChildren);
9186 if (inner && aFreezeChildren) {
9187 inner->Freeze();
9194 nsresult
9195 nsGlobalWindow::ResumeTimeouts(PRBool aThawChildren)
9197 FORWARD_TO_INNER(ResumeTimeouts, (), NS_ERROR_NOT_INITIALIZED);
9199 NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!");
9200 --mTimeoutsSuspendDepth;
9201 PRBool shouldResume = (mTimeoutsSuspendDepth == 0);
9202 nsresult rv;
9204 if (shouldResume) {
9205 nsDOMThreadService* dts = nsDOMThreadService::get();
9206 if (dts) {
9207 dts->ResumeWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
9210 // Restore all of the timeouts, using the stored time remaining
9211 // (stored in timeout->mWhen).
9213 PRTime now = PR_Now();
9215 #ifdef DEBUG
9216 PRBool _seenDummyTimeout = PR_FALSE;
9217 #endif
9219 for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
9220 // There's a chance we're being called with RunTimeout on the stack in which
9221 // case we have a dummy timeout in the list that *must not* be resumed. It
9222 // can be identified by a null mWindow.
9223 if (!t->mWindow) {
9224 #ifdef DEBUG
9225 NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
9226 _seenDummyTimeout = PR_TRUE;
9227 #endif
9228 continue;
9231 // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
9232 // PRTime to make the division do the right thing on 64-bit
9233 // platforms whether t->mWhen is positive or negative (which is
9234 // likely to always be positive here, but cast anyways for
9235 // consistency).
9236 PRUint32 delay =
9237 NS_MAX(((PRUint32)(t->mWhen / (PRTime)PR_USEC_PER_MSEC)),
9238 (PRUint32)DOM_MIN_TIMEOUT_VALUE);
9240 // Set mWhen back to the time when the timer is supposed to
9241 // fire.
9242 t->mWhen += now;
9244 t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
9245 NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
9247 rv = t->mTimer->InitWithFuncCallback(TimerCallback, t, delay,
9248 nsITimer::TYPE_ONE_SHOT);
9249 if (NS_FAILED(rv)) {
9250 t->mTimer = nsnull;
9251 return rv;
9254 // Add a reference for the new timer's closure.
9255 t->AddRef();
9259 // Resume our children as well.
9260 nsCOMPtr<nsIDocShellTreeNode> node =
9261 do_QueryInterface(GetDocShell());
9262 if (node) {
9263 PRInt32 childCount = 0;
9264 node->GetChildCount(&childCount);
9266 for (PRInt32 i = 0; i < childCount; ++i) {
9267 nsCOMPtr<nsIDocShellTreeItem> childShell;
9268 node->GetChildAt(i, getter_AddRefs(childShell));
9269 NS_ASSERTION(childShell, "null child shell");
9271 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
9272 if (pWin) {
9273 nsGlobalWindow *win =
9274 static_cast<nsGlobalWindow*>
9275 (static_cast<nsPIDOMWindow*>(pWin));
9277 NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
9278 nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
9280 // This is a bit hackish. Only thaw/resume windows which are truly our
9281 // subwindows.
9282 nsCOMPtr<nsIContent> frame = do_QueryInterface(pWin->GetFrameElementInternal());
9283 if (!mDoc || !frame || mDoc != frame->GetOwnerDoc() || !inner) {
9284 continue;
9287 if (inner && aThawChildren) {
9288 inner->Thaw();
9291 rv = win->ResumeTimeouts(aThawChildren);
9292 NS_ENSURE_SUCCESS(rv, rv);
9297 return NS_OK;
9300 PRUint32
9301 nsGlobalWindow::TimeoutSuspendCount()
9303 FORWARD_TO_INNER(TimeoutSuspendCount, (), 0);
9304 return mTimeoutsSuspendDepth;
9307 NS_IMETHODIMP
9308 nsGlobalWindow::GetScriptTypeID(PRUint32 *aScriptType)
9310 NS_ERROR("No default script type here - ask some element");
9311 return nsIProgrammingLanguage::UNKNOWN;
9314 NS_IMETHODIMP
9315 nsGlobalWindow::SetScriptTypeID(PRUint32 aScriptType)
9317 NS_ERROR("Can't change default script type for a document");
9318 return NS_ERROR_NOT_IMPLEMENTED;
9321 void
9322 nsGlobalWindow::SetHasOrientationEventListener()
9324 nsCOMPtr<nsIAccelerometer> ac =
9325 do_GetService(NS_ACCELEROMETER_CONTRACTID);
9327 if (ac) {
9328 mHasAcceleration = PR_TRUE;
9329 ac->AddWindowListener(this);
9333 // nsGlobalChromeWindow implementation
9335 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
9336 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
9337 nsGlobalWindow)
9338 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBrowserDOMWindow)
9339 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMessageManager)
9340 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
9342 DOMCI_DATA(ChromeWindow, nsGlobalChromeWindow)
9343 DOMCI_DATA(InnerChromeWindow, nsGlobalChromeWindow)
9345 // QueryInterface implementation for nsGlobalChromeWindow
9346 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)
9347 NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
9348 WINDOW_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)
9349 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
9351 NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
9352 NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
9354 NS_IMETHODIMP
9355 nsGlobalChromeWindow::GetWindowState(PRUint16* aWindowState)
9357 *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
9359 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9361 PRInt32 aMode = 0;
9363 if (widget) {
9364 nsresult rv = widget->GetSizeMode(&aMode);
9365 NS_ENSURE_SUCCESS(rv, rv);
9368 switch (aMode) {
9369 case nsSizeMode_Minimized:
9370 *aWindowState = nsIDOMChromeWindow::STATE_MINIMIZED;
9371 break;
9372 case nsSizeMode_Maximized:
9373 *aWindowState = nsIDOMChromeWindow::STATE_MAXIMIZED;
9374 break;
9375 case nsSizeMode_Fullscreen:
9376 *aWindowState = nsIDOMChromeWindow::STATE_FULLSCREEN;
9377 break;
9378 case nsSizeMode_Normal:
9379 *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
9380 break;
9381 default:
9382 NS_WARNING("Illegal window state for this chrome window");
9383 break;
9386 return NS_OK;
9389 NS_IMETHODIMP
9390 nsGlobalChromeWindow::Maximize()
9392 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9393 nsresult rv = NS_OK;
9395 if (widget) {
9396 rv = widget->SetSizeMode(nsSizeMode_Maximized);
9399 return rv;
9402 NS_IMETHODIMP
9403 nsGlobalChromeWindow::Minimize()
9405 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9406 nsresult rv = NS_OK;
9408 if (widget)
9409 rv = widget->SetSizeMode(nsSizeMode_Minimized);
9411 return rv;
9414 NS_IMETHODIMP
9415 nsGlobalChromeWindow::Restore()
9417 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9418 nsresult rv = NS_OK;
9420 if (widget) {
9421 rv = widget->SetSizeMode(nsSizeMode_Normal);
9424 return rv;
9427 NS_IMETHODIMP
9428 nsGlobalChromeWindow::GetAttention()
9430 return GetAttentionWithCycleCount(-1);
9433 NS_IMETHODIMP
9434 nsGlobalChromeWindow::GetAttentionWithCycleCount(PRInt32 aCycleCount)
9436 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9437 nsresult rv = NS_OK;
9439 if (widget) {
9440 rv = widget->GetAttention(aCycleCount);
9443 return rv;
9446 NS_IMETHODIMP
9447 nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent)
9449 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9450 if (!widget) {
9451 return NS_OK;
9454 nsCOMPtr<nsIPrivateDOMEvent> privEvent = do_QueryInterface(aMouseDownEvent);
9455 NS_ENSURE_TRUE(privEvent, NS_ERROR_FAILURE);
9456 nsEvent *internalEvent = privEvent->GetInternalNSEvent();
9457 NS_ENSURE_TRUE(internalEvent &&
9458 internalEvent->eventStructType == NS_MOUSE_EVENT,
9459 NS_ERROR_FAILURE);
9460 nsMouseEvent *mouseEvent = static_cast<nsMouseEvent*>(internalEvent);
9462 return widget->BeginMoveDrag(mouseEvent);
9465 //Note: This call will lock the cursor, it will not change as it moves.
9466 //To unlock, the cursor must be set back to CURSOR_AUTO.
9467 NS_IMETHODIMP
9468 nsGlobalChromeWindow::SetCursor(const nsAString& aCursor)
9470 FORWARD_TO_OUTER_CHROME(SetCursor, (aCursor), NS_ERROR_NOT_INITIALIZED);
9472 nsresult rv = NS_OK;
9473 PRInt32 cursor;
9475 // use C strings to keep the code/data size down
9476 NS_ConvertUTF16toUTF8 cursorString(aCursor);
9478 if (cursorString.Equals("auto"))
9479 cursor = NS_STYLE_CURSOR_AUTO;
9480 else {
9481 nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
9482 if (eCSSKeyword_UNKNOWN == keyword ||
9483 !nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
9484 // XXX remove the following three values (leave return NS_OK) after 1.8
9485 // XXX since they should have been -moz- prefixed (covered by FindKeyword).
9486 // XXX (also remove |cursorString| at that point?).
9487 if (cursorString.Equals("grab"))
9488 cursor = NS_STYLE_CURSOR_GRAB;
9489 else if (cursorString.Equals("grabbing"))
9490 cursor = NS_STYLE_CURSOR_GRABBING;
9491 else if (cursorString.Equals("spinning"))
9492 cursor = NS_STYLE_CURSOR_SPINNING;
9493 else
9494 return NS_OK;
9498 nsRefPtr<nsPresContext> presContext;
9499 if (mDocShell) {
9500 mDocShell->GetPresContext(getter_AddRefs(presContext));
9503 if (presContext) {
9504 // Need root widget.
9505 nsCOMPtr<nsIPresShell> presShell;
9506 mDocShell->GetPresShell(getter_AddRefs(presShell));
9507 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
9509 nsIViewManager* vm = presShell->GetViewManager();
9510 NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
9512 nsIView *rootView;
9513 vm->GetRootView(rootView);
9514 NS_ENSURE_TRUE(rootView, NS_ERROR_FAILURE);
9516 nsIWidget* widget = rootView->GetNearestWidget(nsnull);
9517 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
9519 // Call esm and set cursor.
9520 rv = presContext->EventStateManager()->SetCursor(cursor, nsnull,
9521 PR_FALSE, 0.0f, 0.0f,
9522 widget, PR_TRUE);
9525 return rv;
9528 NS_IMETHODIMP
9529 nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
9531 FORWARD_TO_OUTER_CHROME(GetBrowserDOMWindow, (aBrowserWindow),
9532 NS_ERROR_NOT_INITIALIZED);
9534 NS_ENSURE_ARG_POINTER(aBrowserWindow);
9536 *aBrowserWindow = mBrowserDOMWindow;
9537 NS_IF_ADDREF(*aBrowserWindow);
9538 return NS_OK;
9541 NS_IMETHODIMP
9542 nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow *aBrowserWindow)
9544 FORWARD_TO_OUTER_CHROME(SetBrowserDOMWindow, (aBrowserWindow),
9545 NS_ERROR_NOT_INITIALIZED);
9547 mBrowserDOMWindow = aBrowserWindow;
9548 return NS_OK;
9551 NS_IMETHODIMP
9552 nsGlobalChromeWindow::NotifyDefaultButtonLoaded(nsIDOMElement* aDefaultButton)
9554 #ifdef MOZ_XUL
9555 NS_ENSURE_ARG(aDefaultButton);
9557 // Don't snap to a disabled button.
9558 nsCOMPtr<nsIDOMXULControlElement> xulControl =
9559 do_QueryInterface(aDefaultButton);
9560 NS_ENSURE_TRUE(xulControl, NS_ERROR_FAILURE);
9561 PRBool disabled;
9562 nsresult rv = xulControl->GetDisabled(&disabled);
9563 NS_ENSURE_SUCCESS(rv, rv);
9564 if (disabled)
9565 return NS_OK;
9567 // Get the button rect in screen coordinates.
9568 nsCOMPtr<nsIContent> content(do_QueryInterface(aDefaultButton));
9569 NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
9570 nsIFrame *frame = content->GetPrimaryFrame();
9571 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
9572 nsIntRect buttonRect = frame->GetScreenRect();
9574 // Get the widget rect in screen coordinates.
9575 nsIWidget *widget = GetNearestWidget();
9576 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
9577 nsIntRect widgetRect;
9578 rv = widget->GetScreenBounds(widgetRect);
9579 NS_ENSURE_SUCCESS(rv, rv);
9581 // Convert the buttonRect coordinates from screen to the widget.
9582 buttonRect -= widgetRect.TopLeft();
9583 rv = widget->OnDefaultButtonLoaded(buttonRect);
9584 if (rv == NS_ERROR_NOT_IMPLEMENTED)
9585 return NS_OK;
9586 return rv;
9587 #else
9588 return NS_ERROR_NOT_IMPLEMENTED;
9589 #endif
9592 NS_IMETHODIMP
9593 nsGlobalChromeWindow::GetMessageManager(nsIChromeFrameMessageManager** aManager)
9595 FORWARD_TO_INNER_CHROME(GetMessageManager, (aManager), NS_ERROR_FAILURE);
9596 if (!mMessageManager) {
9597 nsIScriptContext* scx = GetContextInternal();
9598 NS_ENSURE_STATE(scx);
9599 JSContext* cx = (JSContext *)scx->GetNativeContext();
9600 NS_ENSURE_STATE(cx);
9601 nsCOMPtr<nsIChromeFrameMessageManager> globalMM =
9602 do_GetService("@mozilla.org/globalmessagemanager;1");
9603 mMessageManager =
9604 new nsFrameMessageManager(PR_TRUE,
9605 nsnull,
9606 nsnull,
9607 nsnull,
9608 nsnull,
9609 static_cast<nsFrameMessageManager*>(globalMM.get()),
9610 cx);
9611 NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
9613 CallQueryInterface(mMessageManager, aManager);
9614 return NS_OK;
9617 // nsGlobalModalWindow implementation
9619 // QueryInterface implementation for nsGlobalModalWindow
9620 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalModalWindow)
9621 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalModalWindow,
9622 nsGlobalWindow)
9623 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReturnValue)
9624 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
9626 DOMCI_DATA(ModalContentWindow, nsGlobalModalWindow)
9627 DOMCI_DATA(InnerModalContentWindow, nsGlobalModalWindow)
9629 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalModalWindow)
9630 NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
9631 WINDOW_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow)
9632 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
9634 NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
9635 NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
9638 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalModalWindow,
9639 nsGlobalWindow)
9640 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReturnValue)
9641 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
9644 NS_IMETHODIMP
9645 nsGlobalModalWindow::GetDialogArguments(nsIArray **aArguments)
9647 FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments),
9648 NS_ERROR_NOT_INITIALIZED);
9650 PRBool subsumes = PR_FALSE;
9651 nsIPrincipal *self = GetPrincipal();
9652 if (self && NS_SUCCEEDED(self->Subsumes(mArgumentsOrigin, &subsumes)) &&
9653 subsumes) {
9654 NS_IF_ADDREF(*aArguments = mArguments);
9655 } else {
9656 *aArguments = nsnull;
9659 return NS_OK;
9662 NS_IMETHODIMP
9663 nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
9665 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
9667 NS_IF_ADDREF(*aRetVal = mReturnValue);
9669 return NS_OK;
9672 NS_IMETHODIMP
9673 nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
9675 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK);
9677 mReturnValue = aRetVal;
9679 return NS_OK;
9682 nsresult
9683 nsGlobalModalWindow::SetNewDocument(nsIDocument *aDocument,
9684 nsISupports *aState)
9686 // If we're loading a new document into a modal dialog, clear the
9687 // return value that was set, if any, by the current document.
9688 if (aDocument) {
9689 mReturnValue = nsnull;
9692 return nsGlobalWindow::SetNewDocument(aDocument, aState);
9695 //*****************************************************************************
9696 // nsGlobalWindow: Creator Function (This should go away)
9697 //*****************************************************************************
9699 nsresult
9700 NS_NewScriptGlobalObject(PRBool aIsChrome, PRBool aIsModalContentWindow,
9701 nsIScriptGlobalObject **aResult)
9703 *aResult = nsnull;
9705 nsGlobalWindow *global;
9707 if (aIsChrome) {
9708 global = new nsGlobalChromeWindow(nsnull);
9709 } else if (aIsModalContentWindow) {
9710 global = new nsGlobalModalWindow(nsnull);
9711 } else {
9712 global = new nsGlobalWindow(nsnull);
9715 NS_ENSURE_TRUE(global, NS_ERROR_OUT_OF_MEMORY);
9717 NS_ADDREF(*aResult = global);
9719 return NS_OK;
9722 //*****************************************************************************
9723 //*** nsNavigator: Object Management
9724 //*****************************************************************************
9726 nsNavigator::nsNavigator(nsIDocShell *aDocShell)
9727 : mDocShell(aDocShell)
9731 nsNavigator::~nsNavigator()
9735 //*****************************************************************************
9736 // nsNavigator::nsISupports
9737 //*****************************************************************************
9740 DOMCI_DATA(Navigator, nsNavigator)
9742 // QueryInterface implementation for nsNavigator
9743 NS_INTERFACE_MAP_BEGIN(nsNavigator)
9744 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNavigator)
9745 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigator)
9746 NS_INTERFACE_MAP_ENTRY(nsIDOMClientInformation)
9747 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorGeolocation)
9748 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
9749 NS_INTERFACE_MAP_END
9752 NS_IMPL_ADDREF(nsNavigator)
9753 NS_IMPL_RELEASE(nsNavigator)
9756 void
9757 nsNavigator::SetDocShell(nsIDocShell *aDocShell)
9759 mDocShell = aDocShell;
9760 if (mPlugins)
9761 mPlugins->SetDocShell(aDocShell);
9763 // if there is a page transition, make sure delete the geolocation object
9764 if (mGeolocation)
9766 mGeolocation->Shutdown();
9767 mGeolocation = nsnull;
9771 //*****************************************************************************
9772 // nsNavigator::nsIDOMNavigator
9773 //*****************************************************************************
9775 NS_IMETHODIMP
9776 nsNavigator::GetUserAgent(nsAString& aUserAgent)
9778 nsresult rv;
9779 nsCOMPtr<nsIHttpProtocolHandler>
9780 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9781 if (NS_SUCCEEDED(rv)) {
9782 nsCAutoString ua;
9783 rv = service->GetUserAgent(ua);
9784 CopyASCIItoUTF16(ua, aUserAgent);
9787 return rv;
9790 NS_IMETHODIMP
9791 nsNavigator::GetAppCodeName(nsAString& aAppCodeName)
9793 nsresult rv;
9794 nsCOMPtr<nsIHttpProtocolHandler>
9795 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9796 if (NS_SUCCEEDED(rv)) {
9797 nsCAutoString appName;
9798 rv = service->GetAppName(appName);
9799 CopyASCIItoUTF16(appName, aAppCodeName);
9802 return rv;
9805 NS_IMETHODIMP
9806 nsNavigator::GetAppVersion(nsAString& aAppVersion)
9808 if (!nsContentUtils::IsCallerTrustedForRead()) {
9809 const nsAdoptingCString& override =
9810 nsContentUtils::GetCharPref("general.appversion.override");
9812 if (override) {
9813 CopyUTF8toUTF16(override, aAppVersion);
9814 return NS_OK;
9818 nsresult rv;
9819 nsCOMPtr<nsIHttpProtocolHandler>
9820 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9821 if (NS_SUCCEEDED(rv)) {
9822 nsCAutoString str;
9823 rv = service->GetAppVersion(str);
9824 CopyASCIItoUTF16(str, aAppVersion);
9825 if (NS_FAILED(rv))
9826 return rv;
9828 aAppVersion.AppendLiteral(" (");
9830 rv = service->GetPlatform(str);
9831 if (NS_FAILED(rv))
9832 return rv;
9834 AppendASCIItoUTF16(str, aAppVersion);
9836 aAppVersion.Append(PRUnichar(')'));
9839 return rv;
9842 NS_IMETHODIMP
9843 nsNavigator::GetAppName(nsAString& aAppName)
9845 if (!nsContentUtils::IsCallerTrustedForRead()) {
9846 const nsAdoptingCString& override =
9847 nsContentUtils::GetCharPref("general.appname.override");
9849 if (override) {
9850 CopyUTF8toUTF16(override, aAppName);
9851 return NS_OK;
9855 aAppName.AssignLiteral("Netscape");
9856 return NS_OK;
9859 NS_IMETHODIMP
9860 nsNavigator::GetLanguage(nsAString& aLanguage)
9862 nsresult rv;
9863 nsCOMPtr<nsIHttpProtocolHandler>
9864 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9865 if (NS_SUCCEEDED(rv)) {
9866 nsCAutoString lang;
9867 rv = service->GetLanguage(lang);
9868 CopyASCIItoUTF16(lang, aLanguage);
9871 return rv;
9874 NS_IMETHODIMP
9875 nsNavigator::GetPlatform(nsAString& aPlatform)
9877 if (!nsContentUtils::IsCallerTrustedForRead()) {
9878 const nsAdoptingCString& override =
9879 nsContentUtils::GetCharPref("general.platform.override");
9881 if (override) {
9882 CopyUTF8toUTF16(override, aPlatform);
9883 return NS_OK;
9887 nsresult rv;
9888 nsCOMPtr<nsIHttpProtocolHandler>
9889 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9890 if (NS_SUCCEEDED(rv)) {
9891 // sorry for the #if platform ugliness, but Communicator is
9892 // likewise hardcoded and we're seeking backward compatibility
9893 // here (bug 47080)
9894 #if defined(_WIN64)
9895 aPlatform.AssignLiteral("Win64");
9896 #elif defined(WIN32)
9897 aPlatform.AssignLiteral("Win32");
9898 #elif defined(XP_MACOSX) && defined(__ppc__)
9899 aPlatform.AssignLiteral("MacPPC");
9900 #elif defined(XP_MACOSX) && defined(__i386__)
9901 aPlatform.AssignLiteral("MacIntel");
9902 #elif defined(XP_MACOSX) && defined(__x86_64__)
9903 aPlatform.AssignLiteral("MacIntel");
9904 #elif defined(XP_OS2)
9905 aPlatform.AssignLiteral("OS/2");
9906 #else
9907 // XXX Communicator uses compiled-in build-time string defines
9908 // to indicate the platform it was compiled *for*, not what it is
9909 // currently running *on* which is what this does.
9910 nsCAutoString plat;
9911 rv = service->GetOscpu(plat);
9912 CopyASCIItoUTF16(plat, aPlatform);
9913 #endif
9916 return rv;
9919 NS_IMETHODIMP
9920 nsNavigator::GetOscpu(nsAString& aOSCPU)
9922 if (!nsContentUtils::IsCallerTrustedForRead()) {
9923 const nsAdoptingCString& override =
9924 nsContentUtils::GetCharPref("general.oscpu.override");
9926 if (override) {
9927 CopyUTF8toUTF16(override, aOSCPU);
9928 return NS_OK;
9932 nsresult rv;
9933 nsCOMPtr<nsIHttpProtocolHandler>
9934 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9935 if (NS_SUCCEEDED(rv)) {
9936 nsCAutoString oscpu;
9937 rv = service->GetOscpu(oscpu);
9938 CopyASCIItoUTF16(oscpu, aOSCPU);
9941 return rv;
9944 NS_IMETHODIMP
9945 nsNavigator::GetVendor(nsAString& aVendor)
9947 nsresult rv;
9948 nsCOMPtr<nsIHttpProtocolHandler>
9949 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9950 if (NS_SUCCEEDED(rv)) {
9951 nsCAutoString vendor;
9952 rv = service->GetVendor(vendor);
9953 CopyASCIItoUTF16(vendor, aVendor);
9956 return rv;
9960 NS_IMETHODIMP
9961 nsNavigator::GetVendorSub(nsAString& aVendorSub)
9963 nsresult rv;
9964 nsCOMPtr<nsIHttpProtocolHandler>
9965 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9966 if (NS_SUCCEEDED(rv)) {
9967 nsCAutoString vendor;
9968 rv = service->GetVendorSub(vendor);
9969 CopyASCIItoUTF16(vendor, aVendorSub);
9972 return rv;
9975 NS_IMETHODIMP
9976 nsNavigator::GetProduct(nsAString& aProduct)
9978 nsresult rv;
9979 nsCOMPtr<nsIHttpProtocolHandler>
9980 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9981 if (NS_SUCCEEDED(rv)) {
9982 nsCAutoString product;
9983 rv = service->GetProduct(product);
9984 CopyASCIItoUTF16(product, aProduct);
9987 return rv;
9990 NS_IMETHODIMP
9991 nsNavigator::GetProductSub(nsAString& aProductSub)
9993 if (!nsContentUtils::IsCallerTrustedForRead()) {
9994 const nsAdoptingCString& override =
9995 nsContentUtils::GetCharPref("general.productSub.override");
9997 if (override) {
9998 CopyUTF8toUTF16(override, aProductSub);
9999 return NS_OK;
10000 } else {
10001 // 'general.useragent.productSub' backwards compatible with 1.8 branch.
10002 const nsAdoptingCString& override2 =
10003 nsContentUtils::GetCharPref("general.useragent.productSub");
10005 if (override2) {
10006 CopyUTF8toUTF16(override2, aProductSub);
10007 return NS_OK;
10012 nsresult rv;
10013 nsCOMPtr<nsIHttpProtocolHandler>
10014 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10015 if (NS_SUCCEEDED(rv)) {
10016 nsCAutoString productSub;
10017 rv = service->GetProductSub(productSub);
10018 CopyASCIItoUTF16(productSub, aProductSub);
10021 return rv;
10024 NS_IMETHODIMP
10025 nsNavigator::GetSecurityPolicy(nsAString& aSecurityPolicy)
10027 return NS_OK;
10030 NS_IMETHODIMP
10031 nsNavigator::GetMimeTypes(nsIDOMMimeTypeArray **aMimeTypes)
10033 if (!mMimeTypes) {
10034 mMimeTypes = new nsMimeTypeArray(this);
10035 if (!mMimeTypes) {
10036 return NS_ERROR_OUT_OF_MEMORY;
10040 NS_ADDREF(*aMimeTypes = mMimeTypes);
10042 return NS_OK;
10045 NS_IMETHODIMP
10046 nsNavigator::GetPlugins(nsIDOMPluginArray **aPlugins)
10048 if (!mPlugins) {
10049 mPlugins = new nsPluginArray(this, mDocShell);
10050 if (!mPlugins) {
10051 return NS_ERROR_OUT_OF_MEMORY;
10055 NS_ADDREF(*aPlugins = mPlugins);
10057 return NS_OK;
10060 // values for the network.cookie.cookieBehavior pref are documented in
10061 // nsCookieService.cpp.
10062 #define COOKIE_BEHAVIOR_REJECT 2
10064 NS_IMETHODIMP
10065 nsNavigator::GetCookieEnabled(PRBool *aCookieEnabled)
10067 *aCookieEnabled =
10068 (nsContentUtils::GetIntPref("network.cookie.cookieBehavior",
10069 COOKIE_BEHAVIOR_REJECT) !=
10070 COOKIE_BEHAVIOR_REJECT);
10072 return NS_OK;
10075 NS_IMETHODIMP
10076 nsNavigator::GetOnLine(PRBool* aOnline)
10078 NS_PRECONDITION(aOnline, "Null out param");
10080 *aOnline = !NS_IsOffline();
10081 return NS_OK;
10084 NS_IMETHODIMP
10085 nsNavigator::GetBuildID(nsAString& aBuildID)
10087 if (!nsContentUtils::IsCallerTrustedForRead()) {
10088 const nsAdoptingCString& override =
10089 nsContentUtils::GetCharPref("general.buildID.override");
10091 if (override) {
10092 CopyUTF8toUTF16(override, aBuildID);
10093 return NS_OK;
10097 nsCOMPtr<nsIXULAppInfo> appInfo =
10098 do_GetService("@mozilla.org/xre/app-info;1");
10099 if (!appInfo)
10100 return NS_ERROR_NOT_IMPLEMENTED;
10102 nsCAutoString buildID;
10103 nsresult rv = appInfo->GetAppBuildID(buildID);
10104 if (NS_FAILED(rv))
10105 return rv;
10107 aBuildID.Truncate();
10108 AppendASCIItoUTF16(buildID, aBuildID);
10109 return NS_OK;
10112 NS_IMETHODIMP
10113 nsNavigator::JavaEnabled(PRBool *aReturn)
10115 // Return true if we have a handler for "application/x-java-vm",
10116 // otherwise return false.
10117 *aReturn = PR_FALSE;
10119 if (!mMimeTypes) {
10120 mMimeTypes = new nsMimeTypeArray(this);
10121 if (!mMimeTypes)
10122 return NS_ERROR_OUT_OF_MEMORY;
10125 RefreshMIMEArray();
10127 PRUint32 count;
10128 mMimeTypes->GetLength(&count);
10129 for (PRUint32 i = 0; i < count; i++) {
10130 nsresult rv;
10131 nsIDOMMimeType* type = mMimeTypes->GetItemAt(i, &rv);
10132 nsAutoString mimeString;
10133 if (type && NS_SUCCEEDED(type->GetType(mimeString))) {
10134 if (mimeString.EqualsLiteral("application/x-java-vm")) {
10135 *aReturn = PR_TRUE;
10136 break;
10141 return NS_OK;
10144 NS_IMETHODIMP
10145 nsNavigator::TaintEnabled(PRBool *aReturn)
10147 *aReturn = PR_FALSE;
10148 return NS_OK;
10151 void
10152 nsNavigator::LoadingNewDocument()
10154 // Release these so that they will be recreated for the
10155 // new document (if requested). The plugins or mime types
10156 // arrays may have changed. See bug 150087.
10157 mMimeTypes = nsnull;
10158 mPlugins = nsnull;
10160 if (mGeolocation)
10162 mGeolocation->Shutdown();
10163 mGeolocation = nsnull;
10167 nsresult
10168 nsNavigator::RefreshMIMEArray()
10170 nsresult rv = NS_OK;
10171 if (mMimeTypes)
10172 rv = mMimeTypes->Refresh();
10173 return rv;
10176 //*****************************************************************************
10177 // nsNavigator::nsIDOMClientInformation
10178 //*****************************************************************************
10180 NS_IMETHODIMP
10181 nsNavigator::RegisterContentHandler(const nsAString& aMIMEType,
10182 const nsAString& aURI,
10183 const nsAString& aTitle)
10185 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
10186 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
10187 if (registrar && mDocShell) {
10188 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10189 if (contentDOMWindow)
10190 return registrar->RegisterContentHandler(aMIMEType, aURI, aTitle,
10191 contentDOMWindow);
10194 return NS_OK;
10197 NS_IMETHODIMP
10198 nsNavigator::RegisterProtocolHandler(const nsAString& aProtocol,
10199 const nsAString& aURI,
10200 const nsAString& aTitle)
10202 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
10203 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
10204 if (registrar && mDocShell) {
10205 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10206 if (contentDOMWindow)
10207 return registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle,
10208 contentDOMWindow);
10211 return NS_OK;
10215 NS_IMETHODIMP
10216 nsNavigator::MozIsLocallyAvailable(const nsAString &aURI,
10217 PRBool aWhenOffline,
10218 PRBool *aIsAvailable)
10220 nsCOMPtr<nsIURI> uri;
10221 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI);
10222 NS_ENSURE_SUCCESS(rv, rv);
10224 // This method of checking the cache will only work for http/https urls
10225 PRBool match;
10226 rv = uri->SchemeIs("http", &match);
10227 NS_ENSURE_SUCCESS(rv, rv);
10228 if (!match) {
10229 rv = uri->SchemeIs("https", &match);
10230 NS_ENSURE_SUCCESS(rv, rv);
10231 if (!match) return NS_ERROR_DOM_BAD_URI;
10234 // Same origin check
10235 nsCOMPtr<nsIJSContextStack> stack = do_GetService(sJSStackContractID);
10236 NS_ENSURE_TRUE(stack, NS_ERROR_FAILURE);
10238 JSContext *cx = nsnull;
10239 rv = stack->Peek(&cx);
10240 NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
10242 rv = nsContentUtils::GetSecurityManager()->CheckSameOrigin(cx, uri);
10243 NS_ENSURE_SUCCESS(rv, rv);
10245 // these load flags cause an error to be thrown if there is no
10246 // valid cache entry, and skip the load if there is.
10247 // if the cache is busy, assume that it is not yet available rather
10248 // than waiting for it to become available.
10249 PRUint32 loadFlags = nsIChannel::INHIBIT_CACHING |
10250 nsICachingChannel::LOAD_NO_NETWORK_IO |
10251 nsICachingChannel::LOAD_ONLY_IF_MODIFIED |
10252 nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
10254 if (aWhenOffline) {
10255 loadFlags |= nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE |
10256 nsICachingChannel::LOAD_ONLY_FROM_CACHE |
10257 nsIRequest::LOAD_FROM_CACHE;
10260 nsCOMPtr<nsIChannel> channel;
10261 rv = NS_NewChannel(getter_AddRefs(channel), uri,
10262 nsnull, nsnull, nsnull, loadFlags);
10263 NS_ENSURE_SUCCESS(rv, rv);
10265 nsCOMPtr<nsIInputStream> stream;
10266 rv = channel->Open(getter_AddRefs(stream));
10267 NS_ENSURE_SUCCESS(rv, rv);
10269 stream->Close();
10271 nsresult status;
10272 rv = channel->GetStatus(&status);
10273 NS_ENSURE_SUCCESS(rv, rv);
10275 if (NS_SUCCEEDED(status)) {
10276 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
10277 rv = httpChannel->GetRequestSucceeded(aIsAvailable);
10278 NS_ENSURE_SUCCESS(rv, rv);
10279 } else {
10280 *aIsAvailable = PR_FALSE;
10283 return NS_OK;
10286 //*****************************************************************************
10287 // nsNavigator::nsIDOMNavigatorGeolocation
10288 //*****************************************************************************
10290 NS_IMETHODIMP nsNavigator::GetGeolocation(nsIDOMGeoGeolocation **_retval)
10292 NS_ENSURE_ARG_POINTER(_retval);
10293 *_retval = nsnull;
10295 if (mGeolocation) {
10296 NS_ADDREF(*_retval = mGeolocation);
10297 return NS_OK;
10300 if (!mDocShell)
10301 return NS_ERROR_FAILURE;
10303 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10304 if (!contentDOMWindow)
10305 return NS_ERROR_FAILURE;
10307 mGeolocation = new nsGeolocation();
10308 if (!mGeolocation)
10309 return NS_ERROR_FAILURE;
10311 if (NS_FAILED(mGeolocation->Init(contentDOMWindow)))
10312 return NS_ERROR_FAILURE;
10314 NS_ADDREF(*_retval = mGeolocation);
10315 return NS_OK;