follow up to bug 588735, missing sdk ifdefing. a=nobug.
[mozilla-central.git] / dom / base / nsGlobalWindow.cpp
blobd687ed70689a93562534540b7440198bc2e58d54
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 #include "nsRefreshDriver.h"
227 #ifdef PR_LOGGING
228 static PRLogModuleInfo* gDOMLeakPRLog;
229 #endif
231 using namespace mozilla::dom;
232 using mozilla::TimeStamp;
233 using mozilla::TimeDuration;
235 nsIDOMStorageList *nsGlobalWindow::sGlobalStorageList = nsnull;
237 static nsIEntropyCollector *gEntropyCollector = nsnull;
238 static PRInt32 gRefCnt = 0;
239 static PRInt32 gOpenPopupSpamCount = 0;
240 static PopupControlState gPopupControlState = openAbused;
241 static PRInt32 gRunningTimeoutDepth = 0;
242 static PRPackedBool gMouseDown = PR_FALSE;
243 static PRPackedBool gDragServiceDisabled = PR_FALSE;
244 static FILE *gDumpFile = nsnull;
245 static PRUint64 gNextWindowID = 0;
247 #ifdef DEBUG
248 static PRUint32 gSerialCounter = 0;
249 #endif
251 #ifdef DEBUG_jst
252 PRInt32 gTimeoutCnt = 0;
253 #endif
255 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
256 static PRBool gDOMWindowDumpEnabled = PR_FALSE;
257 #endif
259 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
260 #define DEBUG_PAGE_CACHE
261 #endif
263 // The shortest interval/timeout we permit
264 #define DOM_MIN_TIMEOUT_VALUE 10 // 10ms
266 // The number of nested timeouts before we start clamping. HTML5 says 1, WebKit
267 // uses 5.
268 #define DOM_CLAMP_TIMEOUT_NESTING_LEVEL 5
270 // The longest interval (as PRIntervalTime) we permit, or that our
271 // timer code can handle, really. See DELAY_INTERVAL_LIMIT in
272 // nsTimerImpl.h for details.
273 #define DOM_MAX_TIMEOUT_VALUE PR_BIT(8 * sizeof(PRIntervalTime) - 1)
275 #define FORWARD_TO_OUTER(method, args, err_rval) \
276 PR_BEGIN_MACRO \
277 if (IsInnerWindow()) { \
278 nsGlobalWindow *outer = GetOuterWindowInternal(); \
279 if (!outer) { \
280 NS_WARNING("No outer window available!"); \
281 return err_rval; \
283 return outer->method args; \
285 PR_END_MACRO
287 #define FORWARD_TO_OUTER_VOID(method, args) \
288 PR_BEGIN_MACRO \
289 if (IsInnerWindow()) { \
290 nsGlobalWindow *outer = GetOuterWindowInternal(); \
291 if (!outer) { \
292 NS_WARNING("No outer window available!"); \
293 return; \
295 outer->method args; \
296 return; \
298 PR_END_MACRO
300 #define FORWARD_TO_OUTER_CHROME(method, args, err_rval) \
301 PR_BEGIN_MACRO \
302 if (IsInnerWindow()) { \
303 nsGlobalWindow *outer = GetOuterWindowInternal(); \
304 if (!outer) { \
305 NS_WARNING("No outer window available!"); \
306 return err_rval; \
308 return ((nsGlobalChromeWindow *)outer)->method args; \
310 PR_END_MACRO
312 #define FORWARD_TO_INNER_CHROME(method, args, err_rval) \
313 PR_BEGIN_MACRO \
314 if (IsOuterWindow()) { \
315 if (!mInnerWindow) { \
316 NS_WARNING("No inner window available!"); \
317 return err_rval; \
319 return ((nsGlobalChromeWindow *)mInnerWindow)->method args; \
321 PR_END_MACRO
323 #define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
324 PR_BEGIN_MACRO \
325 if (IsInnerWindow()) { \
326 nsGlobalWindow *outer = GetOuterWindowInternal(); \
327 if (!outer) { \
328 NS_WARNING("No outer window available!"); \
329 return err_rval; \
331 return ((nsGlobalModalWindow *)outer)->method args; \
333 PR_END_MACRO
335 #define FORWARD_TO_INNER(method, args, err_rval) \
336 PR_BEGIN_MACRO \
337 if (IsOuterWindow()) { \
338 if (!mInnerWindow) { \
339 NS_WARNING("No inner window available!"); \
340 return err_rval; \
342 return GetCurrentInnerWindowInternal()->method args; \
344 PR_END_MACRO
346 #define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval) \
347 PR_BEGIN_MACRO \
348 if (IsOuterWindow()) { \
349 if (!mInnerWindow) { \
350 NS_WARNING("No inner window available!"); \
351 return err_rval; \
353 return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \
355 PR_END_MACRO
357 #define FORWARD_TO_INNER_VOID(method, args) \
358 PR_BEGIN_MACRO \
359 if (IsOuterWindow()) { \
360 if (!mInnerWindow) { \
361 NS_WARNING("No inner window available!"); \
362 return; \
364 GetCurrentInnerWindowInternal()->method args; \
365 return; \
367 PR_END_MACRO
369 // Same as FORWARD_TO_INNER, but this will create a fresh inner if an
370 // inner doesn't already exists.
371 #define FORWARD_TO_INNER_CREATE(method, args, err_rval) \
372 PR_BEGIN_MACRO \
373 if (IsOuterWindow()) { \
374 if (!mInnerWindow) { \
375 if (mIsClosed) { \
376 return err_rval; \
378 nsCOMPtr<nsIDOMDocument> doc; \
379 nsresult fwdic_nr = GetDocument(getter_AddRefs(doc)); \
380 NS_ENSURE_SUCCESS(fwdic_nr, err_rval); \
381 if (!mInnerWindow) { \
382 return err_rval; \
385 return GetCurrentInnerWindowInternal()->method args; \
387 PR_END_MACRO
389 // CIDs
390 static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
392 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
394 static const char kCryptoContractID[] = NS_CRYPTO_CONTRACTID;
395 static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
397 static const char sPopStatePrefStr[] = "browser.history.allowPopState";
399 static PRBool
400 IsAboutBlank(nsIURI* aURI)
402 NS_PRECONDITION(aURI, "Must have URI");
404 // GetSpec can be expensive for some URIs, so check the scheme first.
405 PRBool isAbout = PR_FALSE;
406 if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
407 return PR_FALSE;
410 nsCAutoString str;
411 aURI->GetSpec(str);
412 return str.EqualsLiteral("about:blank");
415 class nsDummyJavaPluginOwner : public nsIPluginInstanceOwner
417 public:
418 nsDummyJavaPluginOwner(nsIDocument *aDocument)
419 : mDocument(aDocument)
423 void Destroy();
425 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
426 NS_DECL_NSIPLUGININSTANCEOWNER
428 NS_IMETHOD GetURL(const char *aURL, const char *aTarget,
429 nsIInputStream *aPostStream,
430 void *aHeadersData, PRUint32 aHeadersDataLen);
431 NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg);
432 NPError ShowNativeContextMenu(NPMenu* menu, void* event);
433 NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
434 double *destX, double *destY, NPCoordinateSpace destSpace);
435 void SendIdleEvent();
437 NS_DECL_CYCLE_COLLECTION_CLASS(nsDummyJavaPluginOwner)
439 private:
440 nsCOMPtr<nsIPluginInstance> mInstance;
441 nsCOMPtr<nsIDocument> mDocument;
444 NS_IMPL_CYCLE_COLLECTION_2(nsDummyJavaPluginOwner, mDocument, mInstance)
446 // QueryInterface implementation for nsDummyJavaPluginOwner
447 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDummyJavaPluginOwner)
448 NS_INTERFACE_MAP_ENTRY(nsISupports)
449 NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner)
450 NS_INTERFACE_MAP_END
452 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDummyJavaPluginOwner)
453 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDummyJavaPluginOwner)
456 void
457 nsDummyJavaPluginOwner::Destroy()
459 // If we have a plugin instance, stop it and destroy it now.
460 if (mInstance) {
461 mInstance->Stop();
462 mInstance->InvalidateOwner();
463 mInstance = nsnull;
466 mDocument = nsnull;
469 NS_IMETHODIMP
470 nsDummyJavaPluginOwner::SetInstance(nsIPluginInstance *aInstance)
472 mInstance = aInstance;
474 return NS_OK;
477 NS_IMETHODIMP
478 nsDummyJavaPluginOwner::GetInstance(nsIPluginInstance *&aInstance)
480 NS_IF_ADDREF(aInstance = mInstance);
482 return NS_OK;
485 NS_IMETHODIMP
486 nsDummyJavaPluginOwner::GetWindow(NPWindow *&aWindow)
488 aWindow = nsnull;
490 return NS_OK;
493 NS_IMETHODIMP
494 nsDummyJavaPluginOwner::GetMode(PRInt32 *aMode)
496 // This is wrong, but there's no better alternative.
497 *aMode = NP_EMBED;
499 return NS_ERROR_NOT_IMPLEMENTED;
502 NS_IMETHODIMP
503 nsDummyJavaPluginOwner::CreateWidget(void)
505 return NS_ERROR_NOT_IMPLEMENTED;
508 NS_IMETHODIMP
509 nsDummyJavaPluginOwner::GetURL(const char *aURL, const char *aTarget,
510 nsIInputStream *aPostStream,
511 void *aHeadersData, PRUint32 aHeadersDataLen)
513 return NS_ERROR_NOT_IMPLEMENTED;
516 NS_IMETHODIMP
517 nsDummyJavaPluginOwner::ShowStatus(const char *aStatusMsg)
519 return NS_ERROR_NOT_IMPLEMENTED;
522 NS_IMETHODIMP
523 nsDummyJavaPluginOwner::ShowStatus(const PRUnichar *aStatusMsg)
525 return NS_ERROR_NOT_IMPLEMENTED;
528 NPError
529 nsDummyJavaPluginOwner::ShowNativeContextMenu(NPMenu* menu, void* event)
531 return NPERR_GENERIC_ERROR;
534 NPBool
535 nsDummyJavaPluginOwner::ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
536 double *destX, double *destY, NPCoordinateSpace destSpace)
538 return PR_FALSE;
541 NS_IMETHODIMP
542 nsDummyJavaPluginOwner::GetDocument(nsIDocument **aDocument)
544 NS_IF_ADDREF(*aDocument = mDocument);
546 return NS_OK;
549 NS_IMETHODIMP
550 nsDummyJavaPluginOwner::InvalidateRect(NPRect *invalidRect)
552 return NS_ERROR_NOT_IMPLEMENTED;
555 NS_IMETHODIMP
556 nsDummyJavaPluginOwner::InvalidateRegion(NPRegion invalidRegion)
558 return NS_ERROR_NOT_IMPLEMENTED;
561 NS_IMETHODIMP
562 nsDummyJavaPluginOwner::ForceRedraw()
564 return NS_ERROR_NOT_IMPLEMENTED;
567 NS_IMETHODIMP
568 nsDummyJavaPluginOwner::GetNetscapeWindow(void *value)
570 return NS_ERROR_NOT_IMPLEMENTED;
573 NS_IMETHODIMP
574 nsDummyJavaPluginOwner::SetEventModel(PRInt32 eventModel)
576 return NS_ERROR_NOT_IMPLEMENTED;
579 void
580 nsDummyJavaPluginOwner::SendIdleEvent()
585 * An indirect observer object that means we don't have to implement nsIObserver
586 * on nsGlobalWindow, where any script could see it.
588 class nsGlobalWindowObserver : public nsIObserver {
589 public:
590 nsGlobalWindowObserver(nsGlobalWindow* aWindow) : mWindow(aWindow) {}
591 NS_DECL_ISUPPORTS
592 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData)
594 if (!mWindow)
595 return NS_OK;
596 return mWindow->Observe(aSubject, aTopic, aData);
598 void Forget() { mWindow = nsnull; }
599 private:
600 nsGlobalWindow* mWindow;
603 NS_IMPL_ISUPPORTS1(nsGlobalWindowObserver, nsIObserver)
605 nsTimeout::nsTimeout()
607 #ifdef DEBUG_jst
609 extern int gTimeoutCnt;
611 ++gTimeoutCnt;
613 #endif
615 memset(this, 0, sizeof(*this));
617 MOZ_COUNT_CTOR(nsTimeout);
620 nsTimeout::~nsTimeout()
622 #ifdef DEBUG_jst
624 extern int gTimeoutCnt;
626 --gTimeoutCnt;
628 #endif
630 MOZ_COUNT_DTOR(nsTimeout);
633 NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout)
634 NS_IMPL_CYCLE_COLLECTION_UNLINK_NATIVE_0(nsTimeout)
635 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsTimeout)
636 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWindow,
637 nsIScriptGlobalObject)
638 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrincipal)
639 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptHandler)
640 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
641 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
642 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
644 nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
645 : mFrameElement(nsnull), mDocShell(nsnull), mModalStateDepth(0),
646 mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(PR_FALSE),
647 mIsHandlingResizeEvent(PR_FALSE), mIsInnerWindow(aOuterWindow != nsnull),
648 mMayHavePaintEventListener(PR_FALSE), mMayHaveTouchEventListener(PR_FALSE),
649 mMayHaveAudioAvailableEventListener(PR_FALSE), mIsModalContentWindow(PR_FALSE),
650 mIsActive(PR_FALSE), mInnerWindow(nsnull), mOuterWindow(aOuterWindow) {}
652 nsPIDOMWindow::~nsPIDOMWindow() {}
654 //*****************************************************************************
655 //*** nsGlobalWindow: Object Management
656 //*****************************************************************************
658 nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
659 : nsPIDOMWindow(aOuterWindow),
660 mIsFrozen(PR_FALSE),
661 mDidInitJavaProperties(PR_FALSE),
662 mFullScreen(PR_FALSE),
663 mIsClosed(PR_FALSE),
664 mInClose(PR_FALSE),
665 mHavePendingClose(PR_FALSE),
666 mHadOriginalOpener(PR_FALSE),
667 mIsPopupSpam(PR_FALSE),
668 mBlockScriptedClosingFlag(PR_FALSE),
669 mFireOfflineStatusChangeEventOnThaw(PR_FALSE),
670 mCreatingInnerWindow(PR_FALSE),
671 mIsChrome(PR_FALSE),
672 mNeedsFocus(PR_TRUE),
673 mHasFocus(PR_FALSE),
674 #if defined(XP_MAC) || defined(XP_MACOSX)
675 mShowAccelerators(PR_FALSE),
676 mShowFocusRings(PR_FALSE),
677 #else
678 mShowAccelerators(PR_TRUE),
679 mShowFocusRings(PR_TRUE),
680 #endif
681 mShowFocusRingForContent(PR_FALSE),
682 mFocusByKeyOccurred(PR_FALSE),
683 mHasAcceleration(PR_FALSE),
684 mNotifiedIDDestroyed(PR_FALSE),
685 mTimeoutInsertionPoint(nsnull),
686 mTimeoutPublicIdCounter(1),
687 mTimeoutFiringDepth(0),
688 mJSObject(nsnull),
689 mPendingStorageEventsObsolete(nsnull),
690 mTimeoutsSuspendDepth(0),
691 mFocusMethod(0)
692 #ifdef DEBUG
693 , mSetOpenerWindowCalled(PR_FALSE)
694 #endif
695 , mCleanedUp(PR_FALSE)
696 , mCallCleanUpAfterModalDialogCloses(PR_FALSE)
697 , mWindowID(gNextWindowID++)
699 nsLayoutStatics::AddRef();
701 // Initialize the PRCList (this).
702 PR_INIT_CLIST(this);
704 // Initialize timeout storage
705 PR_INIT_CLIST(&mTimeouts);
707 if (aOuterWindow) {
708 // |this| is an inner window, add this inner window to the outer
709 // window list of inners.
710 PR_INSERT_AFTER(this, aOuterWindow);
712 mObserver = new nsGlobalWindowObserver(this);
713 if (mObserver) {
714 NS_ADDREF(mObserver);
715 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
716 if (os) {
717 // Watch for online/offline status changes so we can fire events. Use
718 // a strong reference.
719 os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
720 PR_FALSE);
722 // Watch for dom-storage-changed so we can fire storage
723 // events. Use a strong reference.
724 os->AddObserver(mObserver, "dom-storage2-changed", PR_FALSE);
725 os->AddObserver(mObserver, "dom-storage-changed", PR_FALSE);
728 } else {
729 // |this| is an outer window. Outer windows start out frozen and
730 // remain frozen until they get an inner window, so freeze this
731 // outer window here.
732 Freeze();
734 mObserver = nsnull;
737 // We could have failed the first time through trying
738 // to create the entropy collector, so we should
739 // try to get one until we succeed.
741 gRefCnt++;
743 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
744 if (gRefCnt == 1) {
745 static const char* prefName = "browser.dom.window.dump.enabled";
746 nsContentUtils::AddBoolPrefVarCache(prefName, &gDOMWindowDumpEnabled);
747 gDOMWindowDumpEnabled = nsContentUtils::GetBoolPref(prefName);
749 #endif
751 if (gDumpFile == nsnull) {
752 const nsAdoptingCString& fname =
753 nsContentUtils::GetCharPref("browser.dom.window.dump.file");
754 if (!fname.IsEmpty()) {
755 // if this fails to open, Dump() knows to just go to stdout
756 // on null.
757 gDumpFile = fopen(fname, "wb+");
758 } else {
759 gDumpFile = stdout;
763 if (!gEntropyCollector) {
764 CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
767 #ifdef DEBUG
768 printf("++DOMWINDOW == %d (%p) [serial = %d] [outer = %p]\n", gRefCnt,
769 static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
770 ++gSerialCounter, static_cast<void*>(aOuterWindow));
771 mSerial = gSerialCounter;
772 #endif
774 #ifdef PR_LOGGING
775 if (!gDOMLeakPRLog)
776 gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
778 if (gDOMLeakPRLog)
779 PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
780 ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
781 #endif
784 nsGlobalWindow::~nsGlobalWindow()
786 if (!--gRefCnt) {
787 NS_IF_RELEASE(gEntropyCollector);
789 #ifdef DEBUG
790 nsCAutoString url;
791 if (mLastOpenedURI) {
792 mLastOpenedURI->GetSpec(url);
795 printf("--DOMWINDOW == %d (%p) [serial = %d] [outer = %p] [url = %s]\n",
796 gRefCnt, static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
797 mSerial, static_cast<void*>(mOuterWindow), url.get());
798 #endif
800 #ifdef PR_LOGGING
801 if (gDOMLeakPRLog)
802 PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
803 ("DOMWINDOW %p destroyed", this));
804 #endif
806 if (mObserver) {
807 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
808 if (os) {
809 os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
810 os->RemoveObserver(mObserver, "dom-storage2-changed");
811 os->RemoveObserver(mObserver, "dom-storage-changed");
814 // Drop its reference to this dying window, in case for some bogus reason
815 // the object stays around.
816 mObserver->Forget();
817 NS_RELEASE(mObserver);
820 if (IsOuterWindow()) {
821 // An outer window is destroyed with inner windows still possibly
822 // alive, iterate through the inner windows and null out their
823 // back pointer to this outer, and pull them out of the list of
824 // inner windows.
826 nsGlobalWindow *w;
827 while ((w = (nsGlobalWindow *)PR_LIST_HEAD(this)) != this) {
828 NS_ASSERTION(w->mOuterWindow == this, "Uh, bad outer window pointer?");
830 w->mOuterWindow = nsnull;
832 PR_REMOVE_AND_INIT_LINK(w);
834 } else {
835 if (mListenerManager) {
836 mListenerManager->Disconnect();
837 mListenerManager = nsnull;
840 // An inner window is destroyed, pull it out of the outer window's
841 // list if inner windows.
843 PR_REMOVE_LINK(this);
845 // If our outer window's inner window is this window, null out the
846 // outer window's reference to this window that's being deleted.
847 nsGlobalWindow *outer = GetOuterWindowInternal();
848 if (outer && outer->mInnerWindow == this) {
849 outer->mInnerWindow = nsnull;
853 mDocument = nsnull; // Forces Release
854 mDoc = nsnull;
856 NS_ASSERTION(!mArguments, "mArguments wasn't cleaned up properly!");
858 CleanUp(PR_TRUE);
860 #ifdef DEBUG
861 nsCycleCollector_DEBUG_wasFreed(static_cast<nsIScriptGlobalObject*>(this));
862 #endif
864 delete mPendingStorageEventsObsolete;
866 nsLayoutStatics::Release();
869 // static
870 void
871 nsGlobalWindow::ShutDown()
873 NS_IF_RELEASE(sGlobalStorageList);
875 if (gDumpFile && gDumpFile != stdout) {
876 fclose(gDumpFile);
878 gDumpFile = nsnull;
881 // static
882 void
883 nsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow* aWindow)
885 if (aWindow->mCachedXBLPrototypeHandlers.IsInitialized() &&
886 aWindow->mCachedXBLPrototypeHandlers.Count() > 0) {
887 aWindow->mCachedXBLPrototypeHandlers.Clear();
889 nsCOMPtr<nsISupports> supports;
890 aWindow->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
891 getter_AddRefs(supports));
892 NS_ASSERTION(supports, "Failed to QI to nsCycleCollectionISupports?!");
894 nsContentUtils::DropJSObjects(supports);
898 void
899 nsGlobalWindow::MaybeForgiveSpamCount()
901 if (IsOuterWindow() &&
902 IsPopupSpamWindow())
904 SetPopupSpamWindow(PR_FALSE);
905 --gOpenPopupSpamCount;
906 NS_ASSERTION(gOpenPopupSpamCount >= 0,
907 "Unbalanced decrement of gOpenPopupSpamCount");
911 void
912 nsGlobalWindow::CleanUp(PRBool aIgnoreModalDialog)
914 if (IsOuterWindow() && !aIgnoreModalDialog) {
915 nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
916 nsCOMPtr<nsIDOMModalContentWindow>
917 dlg(do_QueryInterface(static_cast<nsPIDOMWindow*>(inner)));
918 if (dlg) {
919 // The window we're trying to clean up is the outer window of a
920 // modal dialog. Defer cleanup until the window closes, and let
921 // ShowModalDialog take care of calling CleanUp.
922 mCallCleanUpAfterModalDialogCloses = PR_TRUE;
923 return;
927 // Guarantee idempotence.
928 if (mCleanedUp)
929 return;
930 mCleanedUp = PR_TRUE;
932 mNavigator = nsnull;
933 mScreen = nsnull;
934 mHistory = nsnull;
935 mMenubar = nsnull;
936 mToolbar = nsnull;
937 mLocationbar = nsnull;
938 mPersonalbar = nsnull;
939 mStatusbar = nsnull;
940 mScrollbars = nsnull;
941 mLocation = nsnull;
942 mFrames = nsnull;
943 mApplicationCache = nsnull;
944 mIndexedDB = nsnull;
946 ClearControllers();
948 mOpener = nsnull; // Forces Release
949 if (mContext) {
950 #ifdef DEBUG
951 nsCycleCollector_DEBUG_shouldBeFreed(mContext);
952 #endif
953 mContext = nsnull; // Forces Release
955 mChromeEventHandler = nsnull; // Forces Release
956 mParentTarget = nsnull;
958 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
960 if (inner) {
961 inner->CleanUp(aIgnoreModalDialog);
964 if (mHasAcceleration) {
965 nsCOMPtr<nsIAccelerometer> ac = do_GetService(NS_ACCELEROMETER_CONTRACTID);
966 if (ac)
967 ac->RemoveWindowListener(this);
970 if (mIsChrome && static_cast<nsGlobalChromeWindow*>(this)->mMessageManager) {
971 static_cast<nsFrameMessageManager*>(
972 static_cast<nsGlobalChromeWindow*>(
973 this)->mMessageManager.get())->Disconnect();
976 mInnerWindowHolder = nsnull;
977 mArguments = nsnull;
978 mArgumentsLast = nsnull;
979 mArgumentsOrigin = nsnull;
981 CleanupCachedXBLHandlers(this);
983 #ifdef DEBUG
984 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
985 #endif
988 void
989 nsGlobalWindow::ClearControllers()
991 if (mControllers) {
992 PRUint32 count;
993 mControllers->GetControllerCount(&count);
995 while (count--) {
996 nsCOMPtr<nsIController> controller;
997 mControllers->GetControllerAt(count, getter_AddRefs(controller));
999 nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller);
1000 if (context)
1001 context->SetCommandContext(nsnull);
1004 mControllers = nsnull;
1008 class ClearScopeEvent : public nsRunnable
1010 public:
1011 ClearScopeEvent(nsGlobalWindow *innerWindow)
1012 : mInnerWindow(innerWindow) {
1015 NS_IMETHOD Run()
1017 mInnerWindow->ReallyClearScope(this);
1018 return NS_OK;
1021 private:
1022 nsRefPtr<nsGlobalWindow> mInnerWindow;
1025 void
1026 nsGlobalWindow::ReallyClearScope(nsRunnable *aRunnable)
1028 NS_ASSERTION(IsInnerWindow(), "Must be an inner window");
1030 nsIScriptContext *jsscx = GetContextInternal();
1031 if (jsscx && jsscx->GetExecutingScript()) {
1032 if (!aRunnable) {
1033 aRunnable = new ClearScopeEvent(this);
1034 if (!aRunnable) {
1035 // The only reason that we clear scope here is to try to prevent
1036 // leaks. Failing to clear scope might mean that we'll leak more
1037 // but if we don't have enough memory to allocate a ClearScopeEvent
1038 // we probably don't have to worry about this anyway.
1039 return;
1043 NS_DispatchToMainThread(aRunnable);
1044 return;
1047 NotifyWindowIDDestroyed("inner-window-destroyed");
1048 nsIScriptContext *scx = GetContextInternal();
1049 if (scx) {
1050 scx->ClearScope(mJSObject, PR_TRUE);
1054 void
1055 nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
1057 NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
1059 // Kill all of the workers for this window.
1060 nsDOMThreadService* dts = nsDOMThreadService::get();
1061 if (dts) {
1062 nsIScriptContext *scx = GetContextInternal();
1064 JSContext *cx = scx ? (JSContext *)scx->GetNativeContext() : nsnull;
1066 // Have to suspend this request here because CancelWorkersForGlobal will
1067 // lock until the worker has died and that could cause a deadlock.
1068 JSAutoSuspendRequest asr(cx);
1070 dts->CancelWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
1073 ClearAllTimeouts();
1075 mChromeEventHandler = nsnull;
1077 if (mListenerManager) {
1078 mListenerManager->Disconnect();
1079 mListenerManager = nsnull;
1082 mLocation = nsnull;
1084 if (mDocument) {
1085 NS_ASSERTION(mDoc, "Why is mDoc null?");
1087 // Remember the document's principal.
1088 mDocumentPrincipal = mDoc->NodePrincipal();
1091 #ifdef DEBUG
1092 if (mDocument)
1093 nsCycleCollector_DEBUG_shouldBeFreed(nsCOMPtr<nsISupports>(do_QueryInterface(mDocument)));
1094 #endif
1096 // Make sure that this is called before we null out the document.
1097 NotifyDOMWindowDestroyed(this);
1099 // Remove our reference to the document and the document principal.
1100 mDocument = nsnull;
1101 mDoc = nsnull;
1103 if (mApplicationCache) {
1104 static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
1105 mApplicationCache = nsnull;
1108 mIndexedDB = nsnull;
1110 if (aClearScope) {
1111 // NB: This might not clear our scope, but fire an event to do so
1112 // instead.
1113 ReallyClearScope(nsnull);
1116 if (mDummyJavaPluginOwner) {
1117 // Tear down the dummy java plugin.
1119 // XXXjst: On a general note, should windows with java stuff in
1120 // them ever even make it into the fast-back cache?
1122 mDummyJavaPluginOwner->Destroy();
1124 mDummyJavaPluginOwner = nsnull;
1127 CleanupCachedXBLHandlers(this);
1129 #ifdef DEBUG
1130 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
1131 #endif
1134 //*****************************************************************************
1135 // nsGlobalWindow::nsISupports
1136 //*****************************************************************************
1138 #define WINDOW_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(_class) \
1139 if (aIID.Equals(NS_GET_IID(nsIClassInfo)) || \
1140 aIID.Equals(NS_GET_IID(nsXPCClassInfo))) { \
1141 foundInterface = NS_GetDOMClassInfoInstance(IsInnerWindow() \
1142 ? eDOMClassInfo_Inner##_class##_id \
1143 : eDOMClassInfo_##_class##_id);\
1144 if (!foundInterface) { \
1145 *aInstancePtr = nsnull; \
1146 return NS_ERROR_OUT_OF_MEMORY; \
1148 } else
1150 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)
1152 DOMCI_DATA(Window, nsGlobalWindow)
1153 DOMCI_DATA(InnerWindow, nsGlobalWindow)
1155 // QueryInterface implementation for nsGlobalWindow
1156 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
1157 // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
1158 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObject)
1159 NS_INTERFACE_MAP_ENTRY(nsIDOMWindowInternal)
1160 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
1161 NS_INTERFACE_MAP_ENTRY(nsIDOMWindow2)
1162 NS_INTERFACE_MAP_ENTRY(nsIDOMJSWindow)
1163 NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
1164 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
1165 NS_INTERFACE_MAP_ENTRY(nsPIDOMEventTarget)
1166 NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
1167 NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
1168 NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
1169 NS_INTERFACE_MAP_ENTRY(nsPIDOMWindow)
1170 NS_INTERFACE_MAP_ENTRY(nsIDOMViewCSS)
1171 NS_INTERFACE_MAP_ENTRY(nsIDOMAbstractView)
1172 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageWindow)
1173 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
1174 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
1175 WINDOW_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
1176 NS_INTERFACE_MAP_END
1179 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGlobalWindow, nsIScriptGlobalObject)
1180 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsGlobalWindow,
1181 nsIScriptGlobalObject)
1184 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGlobalWindow)
1185 if (tmp->mDoc && nsCCUncollectableMarker::InGeneration(
1186 cb, tmp->mDoc->GetMarkedCCGeneration())) {
1187 return NS_SUCCESS_INTERRUPTED_TRAVERSE;
1190 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
1192 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mControllers)
1193 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArguments)
1194 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArgumentsLast)
1196 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInnerWindowHolder)
1198 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOpenerScriptPrincipal)
1199 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListenerManager)
1201 for (nsTimeout* timeout = tmp->FirstTimeout();
1202 tmp->IsTimeout(timeout);
1203 timeout = timeout->Next()) {
1204 cb.NoteNativeChild(timeout, &NS_CYCLE_COLLECTION_NAME(nsTimeout));
1207 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSessionStorage)
1208 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mApplicationCache)
1209 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocumentPrincipal)
1210 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDoc)
1212 // Traverse stuff from nsPIDOMWindow
1213 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChromeEventHandler)
1214 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParentTarget)
1215 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
1216 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFrameElement)
1218 // Traverse mDummyJavaPluginOwner
1219 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDummyJavaPluginOwner)
1221 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFocusedNode)
1223 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1225 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
1226 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
1228 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mControllers)
1229 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArguments)
1230 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mArgumentsLast)
1232 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInnerWindowHolder)
1234 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOpenerScriptPrincipal)
1235 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mListenerManager)
1236 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSessionStorage)
1237 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mApplicationCache)
1238 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocumentPrincipal)
1240 // Unlink stuff from nsPIDOMWindow
1241 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChromeEventHandler)
1242 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParentTarget)
1243 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
1244 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFrameElement)
1246 // Unlink mDummyJavaPluginOwner
1247 if (tmp->mDummyJavaPluginOwner) {
1248 tmp->mDummyJavaPluginOwner->Destroy();
1249 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDummyJavaPluginOwner)
1252 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFocusedNode)
1254 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1256 struct TraceData
1258 TraceData(TraceCallback& aCallback, void* aClosure) :
1259 callback(aCallback), closure(aClosure) {}
1261 TraceCallback& callback;
1262 void* closure;
1265 static PLDHashOperator
1266 TraceXBLHandlers(const void* aKey, void* aData, void* aClosure)
1268 TraceData* data = static_cast<TraceData*>(aClosure);
1269 data->callback(nsIProgrammingLanguage::JAVASCRIPT, aData, data->closure);
1270 return PL_DHASH_NEXT;
1273 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
1274 if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
1275 TraceData data(aCallback, aClosure);
1276 tmp->mCachedXBLPrototypeHandlers.EnumerateRead(TraceXBLHandlers, &data);
1278 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1280 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsGlobalWindow)
1281 nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
1282 NS_IMPL_CYCLE_COLLECTION_ROOT_END
1284 //*****************************************************************************
1285 // nsGlobalWindow::nsIScriptGlobalObject
1286 //*****************************************************************************
1288 nsresult
1289 nsGlobalWindow::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aScriptContext)
1291 NS_ASSERTION(lang_id == nsIProgrammingLanguage::JAVASCRIPT,
1292 "We don't support this language ID");
1293 NS_ASSERTION(IsOuterWindow(), "Uh, SetScriptContext() called on inner window!");
1295 NS_ASSERTION(!aScriptContext || !mContext, "Bad call to SetContext()!");
1297 if (aScriptContext) {
1298 // should probably assert the context is clean???
1299 aScriptContext->WillInitializeContext();
1301 nsresult rv = aScriptContext->InitContext();
1302 NS_ENSURE_SUCCESS(rv, rv);
1304 if (IsFrame()) {
1305 // This window is a [i]frame, don't bother GC'ing when the
1306 // frame's context is destroyed since a GC will happen when the
1307 // frameset or host document is destroyed anyway.
1309 aScriptContext->SetGCOnDestruction(PR_FALSE);
1313 mContext = aScriptContext;
1314 return NS_OK;
1317 nsresult
1318 nsGlobalWindow::EnsureScriptEnvironment(PRUint32 aLangID)
1320 NS_ASSERTION(aLangID == nsIProgrammingLanguage::JAVASCRIPT,
1321 "We don't support this language ID");
1322 FORWARD_TO_OUTER(EnsureScriptEnvironment, (aLangID), NS_ERROR_NOT_INITIALIZED);
1324 if (mJSObject)
1325 return NS_OK;
1327 NS_ASSERTION(!GetCurrentInnerWindowInternal(),
1328 "mJSObject is null, but we have an inner window?");
1330 nsCOMPtr<nsIScriptRuntime> scriptRuntime;
1331 nsresult rv = NS_GetScriptRuntimeByID(aLangID, getter_AddRefs(scriptRuntime));
1332 NS_ENSURE_SUCCESS(rv, rv);
1334 nsCOMPtr<nsIScriptContext> context;
1335 rv = scriptRuntime->CreateContext(getter_AddRefs(context));
1336 NS_ENSURE_SUCCESS(rv, rv);
1338 return SetScriptContext(aLangID, context);
1341 nsIScriptContext *
1342 nsGlobalWindow::GetScriptContext(PRUint32 lang)
1344 NS_ASSERTION(lang == nsIProgrammingLanguage::JAVASCRIPT,
1345 "We don't support this language ID");
1347 FORWARD_TO_OUTER(GetScriptContext, (lang), nsnull);
1348 return mContext;
1351 void *
1352 nsGlobalWindow::GetScriptGlobal(PRUint32 lang)
1354 NS_ASSERTION(lang == nsIProgrammingLanguage::JAVASCRIPT,
1355 "We don't support this language ID");
1356 return mJSObject;
1359 nsIScriptContext *
1360 nsGlobalWindow::GetContext()
1362 FORWARD_TO_OUTER(GetContext, (), nsnull);
1364 // check GetContext is indeed identical to GetScriptContext()
1365 NS_ASSERTION(mContext == GetScriptContext(nsIProgrammingLanguage::JAVASCRIPT),
1366 "GetContext confused?");
1367 return mContext;
1370 JSObject *
1371 nsGlobalWindow::GetGlobalJSObject()
1373 NS_ASSERTION(mJSObject == GetScriptGlobal(nsIProgrammingLanguage::JAVASCRIPT),
1374 "GetGlobalJSObject confused?");
1375 return FastGetGlobalJSObject();
1378 PRBool
1379 nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
1381 // We reuse the inner window when:
1382 // a. We are currently at our original document.
1383 // b. At least one of the following conditions are true:
1384 // -- We are not currently a content window (i.e., we're currently a chrome
1385 // window).
1386 // -- The new document is the same as the old document. This means that we're
1387 // getting called from document.open().
1388 // -- The new document has the same origin as what we have loaded right now.
1390 if (!mDoc || !aNewDocument) {
1391 return PR_FALSE;
1394 if (!mDoc->IsInitialDocument()) {
1395 return PR_FALSE;
1398 NS_ASSERTION(IsAboutBlank(mDoc->GetDocumentURI()),
1399 "How'd this happen?");
1401 // Great, we're the original document, check for one of the other
1402 // conditions.
1403 if (mDoc == aNewDocument) {
1404 // aClearScopeHint is false.
1405 return PR_TRUE;
1408 PRBool equal;
1409 if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
1410 &equal)) &&
1411 equal) {
1412 // The origin is the same.
1413 return PR_TRUE;
1416 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
1418 if (treeItem) {
1419 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
1420 treeItem->GetItemType(&itemType);
1422 // If we're a chrome window, then we want to reuse the inner window.
1423 return itemType == nsIDocShellTreeItem::typeChrome;
1426 // No treeItem: don't reuse the current inner window.
1427 return PR_FALSE;
1430 void
1431 nsGlobalWindow::SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal)
1433 FORWARD_TO_OUTER_VOID(SetOpenerScriptPrincipal, (aPrincipal));
1435 if (mDoc) {
1436 if (!mDoc->IsInitialDocument()) {
1437 // We have a document already, and it's not the original one. Bail out.
1438 // Do NOT set mOpenerScriptPrincipal in this case, just to be safe.
1439 return;
1442 #ifdef DEBUG
1443 // We better have an about:blank document loaded at this point. Otherwise,
1444 // something is really weird.
1445 nsCOMPtr<nsIURI> uri;
1446 mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
1447 NS_ASSERTION(uri && IsAboutBlank(uri) &&
1448 IsAboutBlank(mDoc->GetDocumentURI()),
1449 "Unexpected original document");
1450 #endif
1452 // Set the opener principal on our document; given the above check, this
1453 // is safe.
1454 mDoc->SetPrincipal(aPrincipal);
1457 mOpenerScriptPrincipal = aPrincipal;
1460 nsIPrincipal*
1461 nsGlobalWindow::GetOpenerScriptPrincipal()
1463 FORWARD_TO_OUTER(GetOpenerScriptPrincipal, (), nsnull);
1465 return mOpenerScriptPrincipal;
1468 PopupControlState
1469 PushPopupControlState(PopupControlState aState, PRBool aForce)
1471 PopupControlState oldState = gPopupControlState;
1473 if (aState < gPopupControlState || aForce) {
1474 gPopupControlState = aState;
1477 return oldState;
1480 void
1481 PopPopupControlState(PopupControlState aState)
1483 gPopupControlState = aState;
1486 PopupControlState
1487 nsGlobalWindow::PushPopupControlState(PopupControlState aState,
1488 PRBool aForce) const
1490 return ::PushPopupControlState(aState, aForce);
1493 void
1494 nsGlobalWindow::PopPopupControlState(PopupControlState aState) const
1496 ::PopPopupControlState(aState);
1499 PopupControlState
1500 nsGlobalWindow::GetPopupControlState() const
1502 return gPopupControlState;
1505 #define WINDOWSTATEHOLDER_IID \
1506 {0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}
1508 class WindowStateHolder : public nsISupports
1510 public:
1511 NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
1512 NS_DECL_ISUPPORTS
1514 WindowStateHolder(nsGlobalWindow *aWindow,
1515 nsIXPConnectJSObjectHolder *aHolder,
1516 nsNavigator *aNavigator,
1517 nsIXPConnectJSObjectHolder *aOuterProto,
1518 nsIXPConnectJSObjectHolder *aOuterRealProto);
1520 nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
1521 nsIXPConnectJSObjectHolder *GetInnerWindowHolder()
1522 { return mInnerWindowHolder; }
1524 nsNavigator* GetNavigator() { return mNavigator; }
1525 nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
1526 nsIXPConnectJSObjectHolder* GetOuterRealProto() { return mOuterRealProto; }
1528 void DidRestoreWindow()
1530 mInnerWindow = nsnull;
1532 mInnerWindowHolder = nsnull;
1533 mNavigator = nsnull;
1534 mOuterProto = nsnull;
1535 mOuterRealProto = nsnull;
1538 protected:
1539 ~WindowStateHolder();
1541 nsGlobalWindow *mInnerWindow;
1542 // We hold onto this to make sure the inner window doesn't go away. The outer
1543 // window ends up recalculating it anyway.
1544 nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
1545 nsRefPtr<nsNavigator> mNavigator;
1546 nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
1547 nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterRealProto;
1550 NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
1552 WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
1553 nsIXPConnectJSObjectHolder *aHolder,
1554 nsNavigator *aNavigator,
1555 nsIXPConnectJSObjectHolder *aOuterProto,
1556 nsIXPConnectJSObjectHolder *aOuterRealProto)
1557 : mInnerWindow(aWindow),
1558 mNavigator(aNavigator),
1559 mOuterProto(aOuterProto),
1560 mOuterRealProto(aOuterRealProto)
1562 NS_PRECONDITION(aWindow, "null window");
1563 NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
1565 mInnerWindowHolder = aHolder;
1567 aWindow->SuspendTimeouts();
1570 WindowStateHolder::~WindowStateHolder()
1572 if (mInnerWindow) {
1573 // This window was left in the bfcache and is now going away. We need to
1574 // free it up.
1575 // Note that FreeInnerObjects may already have been called on the
1576 // inner window if its outer has already had SetDocShell(null)
1577 // called. In this case the contexts will all be null and the
1578 // PR_TRUE for aClearScope won't do anything; this is OK since
1579 // SetDocShell(null) already did it.
1580 mInnerWindow->FreeInnerObjects(PR_TRUE);
1584 NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder)
1586 nsresult
1587 nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
1588 nsISupports* aState)
1590 NS_TIME_FUNCTION;
1592 NS_PRECONDITION(mDocumentPrincipal == nsnull,
1593 "mDocumentPrincipal prematurely set!");
1595 if (!aDocument) {
1596 NS_ERROR("SetNewDocument(null) called!");
1598 return NS_ERROR_INVALID_ARG;
1601 if (IsInnerWindow()) {
1602 if (!mOuterWindow) {
1603 return NS_ERROR_NOT_INITIALIZED;
1606 // Refuse to set a new document if the call came from an inner
1607 // window that's not the current inner window.
1608 if (mOuterWindow->GetCurrentInnerWindow() != this) {
1609 return NS_ERROR_NOT_AVAILABLE;
1612 return GetOuterWindowInternal()->SetNewDocument(aDocument, aState);
1615 NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
1617 if (IsFrozen()) {
1618 // This outer is now getting its first inner, thaw the outer now
1619 // that it's ready and is getting an inner window.
1621 Thaw();
1624 // XXX Brain transplant outer window JSObject and create new one!
1626 NS_ASSERTION(!GetCurrentInnerWindow() ||
1627 GetCurrentInnerWindow()->GetExtantDocument() == mDocument,
1628 "Uh, mDocument doesn't match the current inner window "
1629 "document!");
1631 nsresult rv = NS_OK;
1633 nsCOMPtr<nsIDocument> oldDoc(do_QueryInterface(mDocument));
1635 nsIScriptContext *scx = GetContextInternal();
1636 NS_ENSURE_TRUE(scx, NS_ERROR_NOT_INITIALIZED);
1638 JSContext *cx = (JSContext *)scx->GetNativeContext();
1640 // clear smartcard events, our document has gone away.
1641 if (mCrypto) {
1642 mCrypto->SetEnableSmartCardEvents(PR_FALSE);
1645 if (!mDocument) {
1646 // First document load.
1648 // Get our private root. If it is equal to us, then we need to
1649 // attach our global key bindings that handles browser scrolling
1650 // and other browser commands.
1651 nsIDOMWindowInternal *internal = nsGlobalWindow::GetPrivateRoot();
1653 if (internal == static_cast<nsIDOMWindowInternal *>(this)) {
1654 nsCOMPtr<nsIXBLService> xblService = do_GetService("@mozilla.org/xbl;1");
1655 if (xblService) {
1656 nsCOMPtr<nsPIDOMEventTarget> piTarget =
1657 do_QueryInterface(mChromeEventHandler);
1658 xblService->AttachGlobalKeyHandler(piTarget);
1663 /* No mDocShell means we're already been partially closed down. When that
1664 happens, setting status isn't a big requirement, so don't. (Doesn't happen
1665 under normal circumstances, but bug 49615 describes a case.) */
1667 nsContentUtils::AddScriptRunner(
1668 NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus));
1670 PRBool reUseInnerWindow = WouldReuseInnerWindow(aDocument);
1672 // Remember the old document's principal.
1673 nsIPrincipal *oldPrincipal = nsnull;
1674 if (oldDoc) {
1675 oldPrincipal = oldDoc->NodePrincipal();
1678 // Drop our reference to the navigator object unless we're reusing
1679 // the existing inner window or the new document is from the same
1680 // origin as the old document.
1681 if (!reUseInnerWindow && mNavigator && oldPrincipal) {
1682 PRBool equal;
1683 rv = oldPrincipal->Equals(aDocument->NodePrincipal(), &equal);
1685 if (NS_FAILED(rv) || !equal) {
1686 // Different origins. Release the navigator object so it gets
1687 // recreated for the new document. The plugins or mime types
1688 // arrays may have changed. See bug 150087.
1689 mNavigator->SetDocShell(nsnull);
1691 mNavigator = nsnull;
1695 if (mNavigator && aDocument != oldDoc) {
1696 // We didn't drop our reference to our old navigator object and
1697 // we're loading a new document. Notify the navigator object about
1698 // the new document load so that it can make sure it is ready for
1699 // the new document.
1701 mNavigator->LoadingNewDocument();
1704 // Set mDocument even if this is an outer window to avoid
1705 // having to *always* reach into the inner window to find the
1706 // document.
1707 mDocument = do_QueryInterface(aDocument);
1708 mDoc = aDocument;
1710 #ifdef DEBUG
1711 mLastOpenedURI = aDocument->GetDocumentURI();
1712 #endif
1714 mContext->WillInitializeContext();
1716 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
1718 nsRefPtr<nsGlobalWindow> newInnerWindow;
1720 PRBool thisChrome = IsChromeWindow();
1721 nsCOMPtr<nsIXPConnectJSObjectHolder> navigatorHolder;
1722 jsval nav;
1724 PRBool isChrome = PR_FALSE;
1726 nsCxPusher cxPusher;
1727 if (!cxPusher.Push(cx)) {
1728 return NS_ERROR_FAILURE;
1731 JSAutoRequest ar(cx);
1733 nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
1734 NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
1736 // Make sure to clear scope on the outer window *before* we
1737 // initialize the new inner window. If we don't, things
1738 // (Object.prototype etc) could leak from the old outer to the new
1739 // inner scope.
1740 mContext->ClearScope(mJSObject, PR_FALSE);
1742 // This code should not be called during shutdown any more (now that
1743 // we don't ever call SetNewDocument(nsnull), so no need to null
1744 // check xpc here.
1745 nsIXPConnect *xpc = nsContentUtils::XPConnect();
1746 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
1747 if (reUseInnerWindow) {
1748 // We're reusing the current inner window.
1749 NS_ASSERTION(!currentInner->IsFrozen(),
1750 "We should never be reusing a shared inner window");
1751 newInnerWindow = currentInner;
1753 if (aDocument != oldDoc) {
1754 nsCommonWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject);
1756 } else {
1757 if (aState) {
1758 newInnerWindow = wsh->GetInnerWindow();
1759 mInnerWindowHolder = wsh->GetInnerWindowHolder();
1761 NS_ASSERTION(newInnerWindow, "Got a state without inner window");
1763 // These assignments addref.
1764 mNavigator = wsh->GetNavigator();
1766 if (mNavigator) {
1767 // Update mNavigator's docshell pointer now.
1768 mNavigator->SetDocShell(mDocShell);
1769 mNavigator->LoadingNewDocument();
1771 } else if (thisChrome) {
1772 newInnerWindow = new nsGlobalChromeWindow(this);
1773 isChrome = PR_TRUE;
1774 } else if (mIsModalContentWindow) {
1775 newInnerWindow = new nsGlobalModalWindow(this);
1776 } else {
1777 newInnerWindow = new nsGlobalWindow(this);
1780 if (currentInner && currentInner->mJSObject) {
1781 if (mNavigator && !aState) {
1782 // Hold on to the navigator wrapper so that we can set
1783 // window.navigator in the new window to point to the same
1784 // object (assuming we didn't change origins etc). See bug
1785 // 163645 for more on why we need this.
1787 nsIDOMNavigator* navigator =
1788 static_cast<nsIDOMNavigator*>(mNavigator.get());
1789 nsContentUtils::WrapNative(cx, currentInner->mJSObject, navigator,
1790 &NS_GET_IID(nsIDOMNavigator), &nav,
1791 getter_AddRefs(navigatorHolder));
1795 if (!aState) {
1796 // This is redundant if we're restoring from a previous inner window.
1797 nsIScriptGlobalObject *sgo =
1798 (nsIScriptGlobalObject *)newInnerWindow.get();
1800 // Freeze the outer window and null out the inner window so
1801 // that initializing classes on the new inner doesn't end up
1802 // reaching into the old inner window for classes etc.
1804 // [This happens with Object.prototype when XPConnect creates
1805 // a temporary global while initializing classes; the reason
1806 // being that xpconnect creates the temp global w/o a parent
1807 // and proto, which makes the JS engine look up classes in
1808 // cx->globalObject, i.e. this outer window].
1810 mInnerWindow = nsnull;
1812 Freeze();
1813 mCreatingInnerWindow = PR_TRUE;
1814 // Every script context we are initialized with must create a
1815 // new global.
1816 void *&newGlobal = (void *&)newInnerWindow->mJSObject;
1817 nsCOMPtr<nsIXPConnectJSObjectHolder> &holder = mInnerWindowHolder;
1818 rv = mContext->CreateNativeGlobalForInner(sgo, isChrome,
1819 aDocument->NodePrincipal(),
1820 &newGlobal,
1821 getter_AddRefs(holder));
1822 NS_ASSERTION(NS_SUCCEEDED(rv) && newGlobal && holder,
1823 "Failed to get script global and holder");
1825 mCreatingInnerWindow = PR_FALSE;
1826 Thaw();
1828 NS_ENSURE_SUCCESS(rv, rv);
1831 if (currentInner && currentInner->mJSObject) {
1832 PRBool termFuncSet = PR_FALSE;
1834 if (oldDoc == aDocument) {
1835 // Suspend the current context's request before Pop() resumes the old
1836 // context's request.
1837 JSAutoSuspendRequest asr(cx);
1839 // Pop our context here so that we get the correct one for the
1840 // termination function.
1841 cxPusher.Pop();
1843 JSContext *oldCx = nsContentUtils::GetCurrentJSContext();
1845 nsIScriptContext *callerScx;
1846 if (oldCx && (callerScx = GetScriptContextFromJSContext(oldCx))) {
1847 // We're called from document.open() (and document.open() is
1848 // called from JS), clear the scope etc in a termination
1849 // function on the calling context to prevent clearing the
1850 // calling scope.
1851 NS_ASSERTION(!currentInner->IsFrozen(),
1852 "How does this opened window get into session history");
1854 JSAutoRequest ar(oldCx);
1856 callerScx->SetTerminationFunction(ClearWindowScope,
1857 static_cast<nsIDOMWindow *>
1858 (currentInner));
1860 termFuncSet = PR_TRUE;
1863 // Re-push our context.
1864 cxPusher.Push(cx);
1867 // Don't clear scope on our current inner window if it's going to be
1868 // held in the bfcache.
1869 if (!currentInner->IsFrozen()) {
1870 // Skip the ClearScope if we set a termination function to do
1871 // it ourselves, later.
1872 currentInner->FreeInnerObjects(!termFuncSet);
1876 mInnerWindow = newInnerWindow;
1878 if (!mJSObject) {
1879 mContext->CreateOuterObject(this, newInnerWindow);
1880 mContext->DidInitializeContext();
1881 mJSObject = (JSObject *)mContext->GetNativeGlobal();
1882 } else {
1883 // XXX New global object and brain transplant!
1884 rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
1885 getter_AddRefs(wrapper));
1886 NS_ENSURE_SUCCESS(rv, rv);
1888 // Restore our object's prototype to its original value so we're sure to
1889 // update it under ReparentWrappedNativeIfFound.
1890 JSObject *proto;
1891 wrapper->GetJSObjectPrototype(&proto);
1892 if (!JS_SetPrototype(cx, mJSObject, proto)) {
1893 NS_ERROR("Can't set prototype");
1894 return NS_ERROR_UNEXPECTED;
1897 nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
1898 xpc->ReparentWrappedNativeIfFound(cx, currentInner->mJSObject,
1899 newInnerWindow->mJSObject,
1900 ToSupports(this),
1901 getter_AddRefs(holder));
1903 if (aState) {
1904 if (nsIXPConnectJSObjectHolder *holder = wsh->GetOuterRealProto()) {
1905 holder->GetJSObject(&proto);
1906 } else {
1907 proto = nsnull;
1910 if (!JS_SetPrototype(cx, mJSObject, proto)) {
1911 NS_ERROR("can't set prototype");
1912 return NS_ERROR_FAILURE;
1918 if (!aState && !reUseInnerWindow) {
1919 // Loading a new page and creating a new inner window, *not*
1920 // restoring from session history.
1922 // InitClassesWithNewWrappedGlobal() (via CreateNativeGlobalForInner)
1923 // for the new inner window
1924 // sets the global object in cx to be the new wrapped global. We
1925 // don't want that, but re-initializing the outer window will
1926 // fix that for us. And perhaps more importantly, this will
1927 // ensure that the outer window gets a new prototype so we don't
1928 // leak prototype properties from the old inner window to the
1929 // new one.
1930 mContext->InitOuterWindow();
1932 // Now that both the the inner and outer windows are initialized
1933 // let the script context do its magic to hook them together.
1934 mContext->ConnectToInner(newInnerWindow, mJSObject);
1936 nsCOMPtr<nsIContent> frame = do_QueryInterface(GetFrameElementInternal());
1937 if (frame && frame->GetOwnerDoc()) {
1938 nsPIDOMWindow* parentWindow = frame->GetOwnerDoc()->GetWindow();
1939 if (parentWindow && parentWindow->TimeoutSuspendCount()) {
1940 SuspendTimeouts(parentWindow->TimeoutSuspendCount());
1945 // Tell the contexts we have completed setting up the doc.
1946 // Add an extra ref in case we release mContext during GC.
1947 nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
1948 nsCOMPtr<nsIDOMDocument> dd(do_QueryInterface(aDocument));
1949 mContext->DidSetDocument(dd, newInnerWindow->mJSObject);
1951 // Now that the prototype is all set up, install the global scope
1952 // polluter. This must happen after the above prototype fixup. If
1953 // the GSP was to be installed on the inner window's real
1954 // prototype (as it would be if this was done before the prototype
1955 // fixup above) we would end up holding the GSP alive (through
1956 // XPConnect's internal marking of wrapper prototypes) as long as
1957 // the inner window was around, and if the GSP had properties on
1958 // it that held an element alive we'd hold the document alive,
1959 // which could hold event handlers alive, which hold the context
1960 // alive etc.
1962 if ((!reUseInnerWindow || aDocument != oldDoc) && !aState) {
1963 nsCOMPtr<nsIHTMLDocument> html_doc(do_QueryInterface(mDocument));
1964 nsCommonWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject,
1965 html_doc);
1968 if (aDocument) {
1969 aDocument->SetScriptGlobalObject(newInnerWindow);
1972 if (!aState) {
1973 if (reUseInnerWindow) {
1974 if (newInnerWindow->mDoc != aDocument) {
1975 newInnerWindow->mDocument = do_QueryInterface(aDocument);
1976 newInnerWindow->mDoc = aDocument;
1978 // We're reusing the inner window for a new document. In this
1979 // case we don't clear the inner window's scope, but we must
1980 // make sure the cached document property gets updated.
1982 // XXXmarkh - tell other languages about this?
1983 ::JS_DeleteProperty(cx, currentInner->mJSObject, "document");
1985 } else {
1986 rv = newInnerWindow->InnerSetNewDocument(aDocument);
1987 NS_ENSURE_SUCCESS(rv, rv);
1989 // Initialize DOM classes etc on the inner window.
1990 rv = mContext->InitClasses(mJSObject);
1991 NS_ENSURE_SUCCESS(rv, rv);
1993 if (navigatorHolder) {
1994 // Restore window.navigator onto the new inner window.
1996 ::JS_DefineProperty(cx, newInnerWindow->mJSObject, "navigator",
1997 nav, nsnull, nsnull,
1998 JSPROP_ENUMERATE | JSPROP_PERMANENT |
1999 JSPROP_READONLY);
2001 // The Navigator's prototype object keeps a reference to the
2002 // window in which it was first created and can thus cause that
2003 // window to stay alive for too long. Reparenting it here allows
2004 // the window to be collected sooner.
2005 nsIDOMNavigator* navigator =
2006 static_cast<nsIDOMNavigator*>(mNavigator);
2008 xpc->
2009 ReparentWrappedNativeIfFound(cx, JSVAL_TO_OBJECT(nav),
2010 newInnerWindow->mJSObject,
2011 navigator,
2012 getter_AddRefs(navigatorHolder));
2016 if (mArguments) {
2017 newInnerWindow->DefineArgumentsProperty(mArguments);
2018 newInnerWindow->mArguments = mArguments;
2019 newInnerWindow->mArgumentsOrigin = mArgumentsOrigin;
2021 mArguments = nsnull;
2022 mArgumentsOrigin = nsnull;
2025 // Give the new inner window our chrome event handler (since it
2026 // doesn't have one).
2027 newInnerWindow->mChromeEventHandler = mChromeEventHandler;
2030 mContext->GC();
2031 mContext->DidInitializeContext();
2033 if (!wrapper) {
2034 rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
2035 getter_AddRefs(wrapper));
2036 NS_ENSURE_SUCCESS(rv, rv);
2039 rv = xpc->UpdateXOWs((JSContext *)GetContextInternal()->GetNativeContext(),
2040 wrapper, nsIXPConnect::XPC_XOW_NAVIGATED);
2041 NS_ENSURE_SUCCESS(rv, rv);
2043 if (!aState && !reUseInnerWindow) {
2044 nsContentUtils::AddScriptRunner(
2045 NS_NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated));
2048 return NS_OK;
2051 void
2052 nsGlobalWindow::DispatchDOMWindowCreated()
2054 if (!mDoc || !mDocument) {
2055 return;
2058 // Fire DOMWindowCreated at chrome event listeners
2059 nsContentUtils::DispatchChromeEvent(mDoc, mDocument, NS_LITERAL_STRING("DOMWindowCreated"),
2060 PR_TRUE /* bubbles */,
2061 PR_FALSE /* not cancellable */);
2063 nsCOMPtr<nsIObserverService> observerService =
2064 mozilla::services::GetObserverService();
2065 if (observerService) {
2066 nsAutoString origin;
2067 nsIPrincipal* principal = mDoc->NodePrincipal();
2068 nsContentUtils::GetUTFOrigin(principal, origin);
2069 observerService->
2070 NotifyObservers(static_cast<nsIDOMWindow*>(this),
2071 nsContentUtils::IsSystemPrincipal(principal) ?
2072 "chrome-document-global-created" :
2073 "content-document-global-created",
2074 origin.get());
2078 void
2079 nsGlobalWindow::ClearStatus()
2081 SetStatus(EmptyString());
2082 SetDefaultStatus(EmptyString());
2085 nsresult
2086 nsGlobalWindow::InnerSetNewDocument(nsIDocument* aDocument)
2088 NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows");
2090 #ifdef PR_LOGGING
2091 if (aDocument && gDOMLeakPRLog &&
2092 PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
2093 nsIURI *uri = aDocument->GetDocumentURI();
2094 nsCAutoString spec;
2095 if (uri)
2096 uri->GetSpec(spec);
2097 PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get());
2099 #endif
2101 mDocument = do_QueryInterface(aDocument);
2102 mDoc = aDocument;
2103 mLocalStorage = nsnull;
2104 mSessionStorage = nsnull;
2106 #ifdef DEBUG
2107 mLastOpenedURI = aDocument->GetDocumentURI();
2108 #endif
2110 // Clear our mutation bitfield.
2111 mMutationBits = 0;
2113 return NS_OK;
2116 void
2117 nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
2119 NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
2121 if (aDocShell == mDocShell)
2122 return;
2124 // SetDocShell(nsnull) means the window is being torn down. Drop our
2125 // reference to the script context, allowing it to be deleted
2126 // later. Meanwhile, keep our weak reference to the script object
2127 // (mJSObject) so that it can be retrieved later (until it is
2128 // finalized by the JS GC).
2130 if (!aDocShell) {
2131 NS_ASSERTION(PR_CLIST_IS_EMPTY(&mTimeouts),
2132 "Uh, outer window holds timeouts!");
2134 // Call FreeInnerObjects on all inner windows, not just the current
2135 // one, since some could be held by WindowStateHolder objects that
2136 // are GC-owned.
2137 for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
2138 inner != this;
2139 inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
2140 NS_ASSERTION(inner->mOuterWindow == this, "bad outer window pointer");
2141 inner->FreeInnerObjects(PR_TRUE);
2144 // Make sure that this is called before we null out the document.
2145 NotifyDOMWindowDestroyed(this);
2147 NotifyWindowIDDestroyed("outer-window-destroyed");
2149 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
2151 if (currentInner) {
2152 NS_ASSERTION(mDoc, "Must have doc!");
2154 // Remember the document's principal.
2155 mDocumentPrincipal = mDoc->NodePrincipal();
2157 // Release our document reference
2158 mDocument = nsnull;
2159 mDoc = nsnull;
2162 if (mContext) {
2163 mContext->ClearScope(mJSObject, PR_TRUE);
2166 ClearControllers();
2168 mChromeEventHandler = nsnull; // force release now
2170 if (mArguments) {
2171 // We got no new document after someone called
2172 // SetArguments(), drop our reference to the arguments.
2173 mArguments = nsnull;
2174 mArgumentsLast = nsnull;
2175 mArgumentsOrigin = nsnull;
2178 if (mContext) {
2179 mContext->GC();
2180 mContext->FinalizeContext();
2181 mContext = nsnull;
2184 #ifdef DEBUG
2185 nsCycleCollector_DEBUG_shouldBeFreed(mContext);
2186 nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
2187 #endif
2190 mDocShell = aDocShell; // Weak Reference
2192 if (mNavigator)
2193 mNavigator->SetDocShell(aDocShell);
2194 if (mHistory)
2195 mHistory->SetDocShell(aDocShell);
2196 if (mFrames)
2197 mFrames->SetDocShell(aDocShell);
2198 if (mScreen)
2199 mScreen->SetDocShell(aDocShell);
2201 // tell our member elements about the new browserwindow
2202 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2203 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2204 if (mMenubar) {
2205 mMenubar->SetWebBrowserChrome(browserChrome);
2207 if (mToolbar) {
2208 mToolbar->SetWebBrowserChrome(browserChrome);
2210 if (mLocationbar) {
2211 mLocationbar->SetWebBrowserChrome(browserChrome);
2213 if (mPersonalbar) {
2214 mPersonalbar->SetWebBrowserChrome(browserChrome);
2216 if (mStatusbar) {
2217 mStatusbar->SetWebBrowserChrome(browserChrome);
2219 if (mScrollbars) {
2220 mScrollbars->SetWebBrowserChrome(browserChrome);
2223 if (!mDocShell) {
2224 MaybeForgiveSpamCount();
2225 CleanUp(PR_FALSE);
2226 } else {
2227 // Get our enclosing chrome shell and retrieve its global window impl, so
2228 // that we can do some forwarding to the chrome document.
2229 nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
2230 mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
2231 mChromeEventHandler = do_QueryInterface(chromeEventHandler);
2232 if (!mChromeEventHandler) {
2233 // We have no chrome event handler. If we have a parent,
2234 // get our chrome event handler from the parent. If
2235 // we don't have a parent, then we need to make a new
2236 // window root object that will function as a chrome event
2237 // handler and receive all events that occur anywhere inside
2238 // our window.
2239 nsCOMPtr<nsIDOMWindow> parentWindow;
2240 GetParent(getter_AddRefs(parentWindow));
2241 if (parentWindow.get() != static_cast<nsIDOMWindow*>(this)) {
2242 nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(parentWindow));
2243 mChromeEventHandler = piWindow->GetChromeEventHandler();
2245 else NS_NewWindowRoot(this, getter_AddRefs(mChromeEventHandler));
2250 void
2251 nsGlobalWindow::SetOpenerWindow(nsIDOMWindowInternal* aOpener,
2252 PRBool aOriginalOpener)
2254 FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
2256 NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
2257 "aOriginalOpener is true, but not first call to "
2258 "SetOpenerWindow!");
2259 NS_ASSERTION(aOpener || !aOriginalOpener,
2260 "Shouldn't set mHadOriginalOpener if aOpener is null");
2262 mOpener = do_GetWeakReference(aOpener);
2263 NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
2265 if (aOriginalOpener) {
2266 mHadOriginalOpener = PR_TRUE;
2269 #ifdef DEBUG
2270 mSetOpenerWindowCalled = PR_TRUE;
2271 #endif
2274 void
2275 nsGlobalWindow::UpdateParentTarget()
2277 nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(mChromeEventHandler);
2278 if (flo) {
2279 nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
2280 if (fl) {
2281 mParentTarget = fl->GetTabChildGlobalAsEventTarget();
2284 if (!mParentTarget) {
2285 mParentTarget = mChromeEventHandler;
2289 nsresult
2290 nsGlobalWindow::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
2292 NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
2293 static PRUint32 count = 0;
2294 PRUint32 msg = aVisitor.mEvent->message;
2296 aVisitor.mCanHandle = PR_TRUE;
2297 aVisitor.mForceContentDispatch = PR_TRUE; //FIXME! Bug 329119
2298 if ((msg == NS_MOUSE_MOVE) && gEntropyCollector) {
2299 //Chances are this counter will overflow during the life of the
2300 //process, but that's OK for our case. Means we get a little
2301 //more entropy.
2302 if (count++ % 100 == 0) {
2303 //Since the high bits seem to be zero's most of the time,
2304 //let's only take the lowest half of the point structure.
2305 PRInt16 myCoord[2];
2307 myCoord[0] = aVisitor.mEvent->refPoint.x;
2308 myCoord[1] = aVisitor.mEvent->refPoint.y;
2309 gEntropyCollector->RandomUpdate((void*)myCoord, sizeof(myCoord));
2310 gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
2311 sizeof(PRUint32));
2313 } else if (msg == NS_RESIZE_EVENT) {
2314 mIsHandlingResizeEvent = PR_TRUE;
2315 } else if (msg == NS_MOUSE_BUTTON_DOWN &&
2316 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2317 gMouseDown = PR_TRUE;
2318 } else if (msg == NS_MOUSE_BUTTON_UP &&
2319 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2320 gMouseDown = PR_FALSE;
2321 if (gDragServiceDisabled) {
2322 nsCOMPtr<nsIDragService> ds =
2323 do_GetService("@mozilla.org/widget/dragservice;1");
2324 if (ds) {
2325 gDragServiceDisabled = PR_FALSE;
2326 ds->Unsuppress();
2331 aVisitor.mParentTarget = GetParentTarget();
2332 return NS_OK;
2335 nsresult
2336 nsGlobalWindow::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
2338 NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
2340 // Return early if there is nothing to do.
2341 switch (aVisitor.mEvent->message) {
2342 case NS_RESIZE_EVENT:
2343 case NS_PAGE_UNLOAD:
2344 case NS_LOAD:
2345 break;
2346 default:
2347 return NS_OK;
2350 /* mChromeEventHandler and mContext go dangling in the middle of this
2351 function under some circumstances (events that destroy the window)
2352 without this addref. */
2353 nsCOMPtr<nsPIDOMEventTarget> kungFuDeathGrip1(mChromeEventHandler);
2354 nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
2356 if (aVisitor.mEvent->message == NS_RESIZE_EVENT) {
2357 mIsHandlingResizeEvent = PR_FALSE;
2358 } else if (aVisitor.mEvent->message == NS_PAGE_UNLOAD &&
2359 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2360 // Execute bindingdetached handlers before we tear ourselves
2361 // down.
2362 if (mDocument) {
2363 NS_ASSERTION(mDoc, "Must have doc");
2364 mDoc->BindingManager()->ExecuteDetachedHandlers();
2366 mIsDocumentLoaded = PR_FALSE;
2367 } else if (aVisitor.mEvent->message == NS_LOAD &&
2368 NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2369 // This is page load event since load events don't propagate to |window|.
2370 // @see nsDocument::PreHandleEvent.
2371 mIsDocumentLoaded = PR_TRUE;
2373 nsCOMPtr<nsIContent> content(do_QueryInterface(GetFrameElementInternal()));
2374 nsCOMPtr<nsIDocShellTreeItem> treeItem =
2375 do_QueryInterface(GetDocShell());
2377 PRInt32 itemType = nsIDocShellTreeItem::typeChrome;
2379 if (treeItem) {
2380 treeItem->GetItemType(&itemType);
2383 if (content && GetParentInternal() &&
2384 itemType != nsIDocShellTreeItem::typeChrome) {
2385 // If we're not in chrome, or at a chrome boundary, fire the
2386 // onload event for the frame element.
2388 nsEventStatus status = nsEventStatus_eIgnore;
2389 nsEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), NS_LOAD);
2390 event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
2392 // Most of the time we could get a pres context to pass in here,
2393 // but not always (i.e. if this window is not shown there won't
2394 // be a pres context available). Since we're not firing a GUI
2395 // event we don't need a pres context anyway so we just pass
2396 // null as the pres context all the time here.
2398 nsEventDispatcher::Dispatch(content, nsnull, &event, nsnull, &status);
2402 return NS_OK;
2405 nsresult
2406 nsGlobalWindow::DispatchDOMEvent(nsEvent* aEvent,
2407 nsIDOMEvent* aDOMEvent,
2408 nsPresContext* aPresContext,
2409 nsEventStatus* aEventStatus)
2411 return
2412 nsEventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow*>(this),
2413 aEvent, aDOMEvent, aPresContext,
2414 aEventStatus);
2417 void
2418 nsGlobalWindow::OnFinalize(PRUint32 aLangID, void *aObject)
2420 NS_ASSERTION(aLangID == nsIProgrammingLanguage::JAVASCRIPT,
2421 "We don't support this language ID");
2423 if (aObject == mJSObject) {
2424 mJSObject = nsnull;
2428 void
2429 nsGlobalWindow::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
2431 FORWARD_TO_INNER_VOID(SetScriptsEnabled, (aEnabled, aFireTimeouts));
2433 if (aEnabled && aFireTimeouts) {
2434 // Scripts are enabled (again?) on this context, run timeouts that
2435 // fired on this context while scripts were disabled.
2436 void (nsGlobalWindow::*run)() = &nsGlobalWindow::RunTimeout;
2437 NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, run));
2441 nsresult
2442 nsGlobalWindow::SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin)
2444 FORWARD_TO_OUTER(SetArguments, (aArguments, aOrigin),
2445 NS_ERROR_NOT_INITIALIZED);
2447 // Hold on to the arguments so that we can re-set them once the next
2448 // document is loaded.
2449 mArguments = aArguments;
2450 mArgumentsOrigin = aOrigin;
2452 nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
2454 if (!mIsModalContentWindow) {
2455 mArgumentsLast = aArguments;
2456 } else if (currentInner) {
2457 // SetArguments() is being called on a modal content window that
2458 // already has an inner window. This can happen when loading
2459 // javascript: URIs as modal content dialogs. In this case, we'll
2460 // set up the dialog window, both inner and outer, before we call
2461 // SetArguments() on the window, so to deal with that, make sure
2462 // here that the arguments are propagated to the inner window.
2464 currentInner->mArguments = aArguments;
2465 currentInner->mArgumentsOrigin = aOrigin;
2468 return currentInner ?
2469 currentInner->DefineArgumentsProperty(aArguments) : NS_OK;
2472 nsresult
2473 nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
2475 JSContext *cx;
2476 nsIScriptContext *ctx = GetOuterWindowInternal()->mContext;
2477 NS_ENSURE_TRUE(aArguments && ctx &&
2478 (cx = (JSContext *)ctx->GetNativeContext()),
2479 NS_ERROR_NOT_INITIALIZED);
2481 if (mIsModalContentWindow) {
2482 // Modal content windows don't have an "arguments" property, they
2483 // have a "dialogArguments" property which is handled
2484 // separately. See nsCommonWindowSH::NewResolve().
2486 return NS_OK;
2489 return GetContextInternal()->SetProperty(mJSObject, "arguments", aArguments);
2492 //*****************************************************************************
2493 // nsGlobalWindow::nsIScriptObjectPrincipal
2494 //*****************************************************************************
2496 nsIPrincipal*
2497 nsGlobalWindow::GetPrincipal()
2499 if (mDoc) {
2500 // If we have a document, get the principal from the document
2501 return mDoc->NodePrincipal();
2504 if (mDocumentPrincipal) {
2505 return mDocumentPrincipal;
2508 // If we don't have a principal and we don't have a document we
2509 // ask the parent window for the principal. This can happen when
2510 // loading a frameset that has a <frame src="javascript:xxx">, in
2511 // that case the global window is used in JS before we've loaded
2512 // a document into the window.
2514 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
2515 do_QueryInterface(GetParentInternal());
2517 if (objPrincipal) {
2518 return objPrincipal->GetPrincipal();
2521 return nsnull;
2524 //*****************************************************************************
2525 // nsGlobalWindow::nsIDOMWindow
2526 //*****************************************************************************
2528 NS_IMETHODIMP
2529 nsGlobalWindow::GetDocument(nsIDOMDocument** aDocument)
2531 // This method *should* forward calls to the outer window, but since
2532 // there's nothing here that *depends* on anything in the outer
2533 // (GetDocShell() eliminates that dependency), we won't do that to
2534 // avoid the extra virtual function call.
2536 // lazily instantiate an about:blank document if necessary, and if
2537 // we have what it takes to do so. Note that domdoc here is the same
2538 // thing as our mDocument, but we don't have to explicitly set the
2539 // member variable because the docshell has already called
2540 // SetNewDocument().
2541 nsIDocShell *docShell;
2542 if (!mDocument && (docShell = GetDocShell()))
2543 nsCOMPtr<nsIDOMDocument> domdoc(do_GetInterface(docShell));
2545 NS_IF_ADDREF(*aDocument = mDocument);
2547 return NS_OK;
2550 //*****************************************************************************
2551 // nsGlobalWindow::nsIDOMWindowInternal
2552 //*****************************************************************************
2554 NS_IMETHODIMP
2555 nsGlobalWindow::GetWindow(nsIDOMWindowInternal** aWindow)
2557 FORWARD_TO_OUTER(GetWindow, (aWindow), NS_ERROR_NOT_INITIALIZED);
2559 *aWindow = static_cast<nsIDOMWindowInternal *>(this);
2560 NS_ADDREF(*aWindow);
2561 return NS_OK;
2564 NS_IMETHODIMP
2565 nsGlobalWindow::GetSelf(nsIDOMWindowInternal** aWindow)
2567 FORWARD_TO_OUTER(GetSelf, (aWindow), NS_ERROR_NOT_INITIALIZED);
2569 *aWindow = static_cast<nsIDOMWindowInternal *>(this);
2570 NS_ADDREF(*aWindow);
2571 return NS_OK;
2574 NS_IMETHODIMP
2575 nsGlobalWindow::GetNavigator(nsIDOMNavigator** aNavigator)
2577 FORWARD_TO_OUTER(GetNavigator, (aNavigator), NS_ERROR_NOT_INITIALIZED);
2579 *aNavigator = nsnull;
2581 if (!mNavigator) {
2582 mNavigator = new nsNavigator(mDocShell);
2583 if (!mNavigator) {
2584 return NS_ERROR_OUT_OF_MEMORY;
2588 NS_ADDREF(*aNavigator = mNavigator);
2590 return NS_OK;
2593 NS_IMETHODIMP
2594 nsGlobalWindow::GetScreen(nsIDOMScreen** aScreen)
2596 FORWARD_TO_OUTER(GetScreen, (aScreen), NS_ERROR_NOT_INITIALIZED);
2598 *aScreen = nsnull;
2600 if (!mScreen && mDocShell) {
2601 mScreen = new nsScreen(mDocShell);
2602 if (!mScreen) {
2603 return NS_ERROR_OUT_OF_MEMORY;
2607 NS_IF_ADDREF(*aScreen = mScreen);
2609 return NS_OK;
2612 NS_IMETHODIMP
2613 nsGlobalWindow::GetHistory(nsIDOMHistory** aHistory)
2615 FORWARD_TO_OUTER(GetHistory, (aHistory), NS_ERROR_NOT_INITIALIZED);
2617 *aHistory = nsnull;
2619 if (!mHistory && mDocShell) {
2620 mHistory = new nsHistory(mDocShell);
2621 if (!mHistory) {
2622 return NS_ERROR_OUT_OF_MEMORY;
2626 NS_IF_ADDREF(*aHistory = mHistory);
2627 return NS_OK;
2630 NS_IMETHODIMP
2631 nsGlobalWindow::GetParent(nsIDOMWindow** aParent)
2633 FORWARD_TO_OUTER(GetParent, (aParent), NS_ERROR_NOT_INITIALIZED);
2635 *aParent = nsnull;
2636 if (!mDocShell)
2637 return NS_OK;
2639 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
2640 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
2642 nsCOMPtr<nsIDocShellTreeItem> parent;
2643 docShellAsItem->GetSameTypeParent(getter_AddRefs(parent));
2645 if (parent) {
2646 nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(parent));
2647 NS_ENSURE_SUCCESS(CallQueryInterface(globalObject.get(), aParent),
2648 NS_ERROR_FAILURE);
2650 else {
2651 *aParent = static_cast<nsIDOMWindowInternal *>(this);
2652 NS_ADDREF(*aParent);
2654 return NS_OK;
2657 NS_IMETHODIMP
2658 nsGlobalWindow::GetTop(nsIDOMWindow** aTop)
2660 FORWARD_TO_OUTER(GetTop, (aTop), NS_ERROR_NOT_INITIALIZED);
2662 nsresult ret = NS_OK;
2664 *aTop = nsnull;
2665 if (mDocShell) {
2666 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
2667 nsCOMPtr<nsIDocShellTreeItem> root;
2668 docShellAsItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
2670 if (root) {
2671 nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(root));
2672 CallQueryInterface(globalObject.get(), aTop);
2676 return ret;
2679 NS_IMETHODIMP
2680 nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
2682 FORWARD_TO_OUTER(GetContent, (aContent), NS_ERROR_NOT_INITIALIZED);
2684 *aContent = nsnull;
2686 nsCOMPtr<nsIDocShellTreeItem> primaryContent;
2688 if (!nsContentUtils::IsCallerChrome()) {
2689 // If we're called by non-chrome code, make sure we don't return
2690 // the primary content window if the calling tab is hidden. In
2691 // such a case we return the same-type root in the hidden tab,
2692 // which is "good enough", for now.
2693 nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
2695 if (baseWin) {
2696 PRBool visible = PR_FALSE;
2697 baseWin->GetVisibility(&visible);
2699 if (!visible) {
2700 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
2702 treeItem->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
2707 if (!primaryContent) {
2708 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
2709 GetTreeOwner(getter_AddRefs(treeOwner));
2710 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
2712 treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
2715 nsCOMPtr<nsIDOMWindowInternal> domWindow(do_GetInterface(primaryContent));
2716 NS_IF_ADDREF(*aContent = domWindow);
2718 return NS_OK;
2721 NS_IMETHODIMP
2722 nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
2724 FORWARD_TO_OUTER(GetPrompter, (aPrompt), NS_ERROR_NOT_INITIALIZED);
2726 if (!mDocShell)
2727 return NS_ERROR_FAILURE;
2729 nsCOMPtr<nsIPrompt> prompter(do_GetInterface(mDocShell));
2730 NS_ENSURE_TRUE(prompter, NS_ERROR_NO_INTERFACE);
2732 NS_ADDREF(*aPrompt = prompter);
2733 return NS_OK;
2736 NS_IMETHODIMP
2737 nsGlobalWindow::GetMenubar(nsIDOMBarProp** aMenubar)
2739 FORWARD_TO_OUTER(GetMenubar, (aMenubar), NS_ERROR_NOT_INITIALIZED);
2741 *aMenubar = nsnull;
2743 if (!mMenubar) {
2744 mMenubar = new nsMenubarProp();
2745 if (!mMenubar) {
2746 return NS_ERROR_OUT_OF_MEMORY;
2749 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2750 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2752 mMenubar->SetWebBrowserChrome(browserChrome);
2755 NS_ADDREF(*aMenubar = mMenubar);
2757 return NS_OK;
2760 NS_IMETHODIMP
2761 nsGlobalWindow::GetToolbar(nsIDOMBarProp** aToolbar)
2763 FORWARD_TO_OUTER(GetToolbar, (aToolbar), NS_ERROR_NOT_INITIALIZED);
2765 *aToolbar = nsnull;
2767 if (!mToolbar) {
2768 mToolbar = new nsToolbarProp();
2769 if (!mToolbar) {
2770 return NS_ERROR_OUT_OF_MEMORY;
2773 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2774 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2776 mToolbar->SetWebBrowserChrome(browserChrome);
2779 NS_ADDREF(*aToolbar = mToolbar);
2781 return NS_OK;
2784 NS_IMETHODIMP
2785 nsGlobalWindow::GetLocationbar(nsIDOMBarProp** aLocationbar)
2787 FORWARD_TO_OUTER(GetLocationbar, (aLocationbar), NS_ERROR_NOT_INITIALIZED);
2789 *aLocationbar = nsnull;
2791 if (!mLocationbar) {
2792 mLocationbar = new nsLocationbarProp();
2793 if (!mLocationbar) {
2794 return NS_ERROR_OUT_OF_MEMORY;
2797 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2798 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2800 mLocationbar->SetWebBrowserChrome(browserChrome);
2803 NS_ADDREF(*aLocationbar = mLocationbar);
2805 return NS_OK;
2808 NS_IMETHODIMP
2809 nsGlobalWindow::GetPersonalbar(nsIDOMBarProp** aPersonalbar)
2811 FORWARD_TO_OUTER(GetPersonalbar, (aPersonalbar), NS_ERROR_NOT_INITIALIZED);
2813 *aPersonalbar = nsnull;
2815 if (!mPersonalbar) {
2816 mPersonalbar = new nsPersonalbarProp();
2817 if (!mPersonalbar) {
2818 return NS_ERROR_OUT_OF_MEMORY;
2821 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2822 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2824 mPersonalbar->SetWebBrowserChrome(browserChrome);
2827 NS_ADDREF(*aPersonalbar = mPersonalbar);
2829 return NS_OK;
2832 NS_IMETHODIMP
2833 nsGlobalWindow::GetStatusbar(nsIDOMBarProp** aStatusbar)
2835 FORWARD_TO_OUTER(GetStatusbar, (aStatusbar), NS_ERROR_NOT_INITIALIZED);
2837 *aStatusbar = nsnull;
2839 if (!mStatusbar) {
2840 mStatusbar = new nsStatusbarProp();
2841 if (!mStatusbar) {
2842 return NS_ERROR_OUT_OF_MEMORY;
2845 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2846 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2848 mStatusbar->SetWebBrowserChrome(browserChrome);
2851 NS_ADDREF(*aStatusbar = mStatusbar);
2853 return NS_OK;
2856 NS_IMETHODIMP
2857 nsGlobalWindow::GetScrollbars(nsIDOMBarProp** aScrollbars)
2859 FORWARD_TO_OUTER(GetScrollbars, (aScrollbars), NS_ERROR_NOT_INITIALIZED);
2861 *aScrollbars = nsnull;
2863 if (!mScrollbars) {
2864 mScrollbars = new nsScrollbarsProp(this);
2865 if (!mScrollbars) {
2866 return NS_ERROR_OUT_OF_MEMORY;
2869 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
2870 GetWebBrowserChrome(getter_AddRefs(browserChrome));
2872 mScrollbars->SetWebBrowserChrome(browserChrome);
2875 NS_ADDREF(*aScrollbars = mScrollbars);
2877 return NS_OK;
2880 NS_IMETHODIMP
2881 nsGlobalWindow::GetClosed(PRBool* aClosed)
2883 FORWARD_TO_OUTER(GetClosed, (aClosed), NS_ERROR_NOT_INITIALIZED);
2885 // If someone called close(), or if we don't have a docshell, we're
2886 // closed.
2887 *aClosed = mIsClosed || !mDocShell;
2889 return NS_OK;
2892 NS_IMETHODIMP
2893 nsGlobalWindow::GetFrames(nsIDOMWindowCollection** aFrames)
2895 FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
2897 *aFrames = nsnull;
2899 if (!mFrames && mDocShell) {
2900 mFrames = new nsDOMWindowList(mDocShell);
2901 if (!mFrames) {
2902 return NS_ERROR_OUT_OF_MEMORY;
2906 *aFrames = static_cast<nsIDOMWindowCollection *>(mFrames);
2907 NS_IF_ADDREF(*aFrames);
2908 return NS_OK;
2911 NS_IMETHODIMP
2912 nsGlobalWindow::GetApplicationCache(nsIDOMOfflineResourceList **aApplicationCache)
2914 FORWARD_TO_INNER(GetApplicationCache, (aApplicationCache), NS_ERROR_UNEXPECTED);
2916 NS_ENSURE_ARG_POINTER(aApplicationCache);
2918 if (!mApplicationCache) {
2919 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(GetDocShell()));
2920 if (!webNav) {
2921 return NS_ERROR_FAILURE;
2924 nsCOMPtr<nsIURI> uri;
2925 nsresult rv = webNav->GetCurrentURI(getter_AddRefs(uri));
2926 NS_ENSURE_SUCCESS(rv, rv);
2928 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
2929 nsCOMPtr<nsIURI> manifestURI;
2930 nsContentUtils::GetOfflineAppManifest(doc, getter_AddRefs(manifestURI));
2932 nsIScriptContext* scriptContext = GetContext();
2933 NS_ENSURE_STATE(scriptContext);
2935 nsRefPtr<nsDOMOfflineResourceList> applicationCache =
2936 new nsDOMOfflineResourceList(manifestURI, uri, this, scriptContext);
2937 NS_ENSURE_TRUE(applicationCache, NS_ERROR_OUT_OF_MEMORY);
2939 applicationCache->Init();
2941 mApplicationCache = applicationCache;
2944 NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
2946 return NS_OK;
2949 NS_IMETHODIMP
2950 nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
2952 FORWARD_TO_OUTER(GetCrypto, (aCrypto), NS_ERROR_NOT_INITIALIZED);
2954 if (!mCrypto) {
2955 mCrypto = do_CreateInstance(kCryptoContractID);
2958 NS_IF_ADDREF(*aCrypto = mCrypto);
2960 return NS_OK;
2963 NS_IMETHODIMP
2964 nsGlobalWindow::GetPkcs11(nsIDOMPkcs11** aPkcs11)
2966 *aPkcs11 = nsnull;
2967 return NS_OK;
2970 NS_IMETHODIMP
2971 nsGlobalWindow::GetControllers(nsIControllers** aResult)
2973 FORWARD_TO_OUTER(GetControllers, (aResult), NS_ERROR_NOT_INITIALIZED);
2975 if (!mControllers) {
2976 nsresult rv;
2977 mControllers = do_CreateInstance(kXULControllersCID, &rv);
2978 NS_ENSURE_SUCCESS(rv, rv);
2980 // Add in the default controller
2981 nsCOMPtr<nsIController> controller = do_CreateInstance(
2982 NS_WINDOWCONTROLLER_CONTRACTID, &rv);
2983 NS_ENSURE_SUCCESS(rv, rv);
2985 mControllers->InsertControllerAt(0, controller);
2986 nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
2987 if (!controllerContext) return NS_ERROR_FAILURE;
2989 controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
2992 *aResult = mControllers;
2993 NS_ADDREF(*aResult);
2994 return NS_OK;
2997 NS_IMETHODIMP
2998 nsGlobalWindow::GetOpener(nsIDOMWindowInternal** aOpener)
3000 FORWARD_TO_OUTER(GetOpener, (aOpener), NS_ERROR_NOT_INITIALIZED);
3002 *aOpener = nsnull;
3004 nsCOMPtr<nsPIDOMWindow> opener = do_QueryReferent(mOpener);
3005 if (!opener) {
3006 return NS_OK;
3009 // First, check if we were called from a privileged chrome script
3010 if (nsContentUtils::IsCallerTrustedForRead()) {
3011 NS_ADDREF(*aOpener = opener);
3012 return NS_OK;
3015 nsCOMPtr<nsPIDOMWindow> openerPwin(do_QueryInterface(opener));
3016 if (!openerPwin) {
3017 return NS_OK;
3020 // First, ensure that we're not handing back a chrome window.
3021 nsGlobalWindow *win = static_cast<nsGlobalWindow *>(openerPwin.get());
3022 if (win->IsChromeWindow()) {
3023 return NS_OK;
3026 // We don't want to reveal the opener if the opener is a mail window,
3027 // because opener can be used to spoof the contents of a message (bug 105050).
3028 // So, we look in the opener's root docshell to see if it's a mail window.
3029 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
3030 do_QueryInterface(openerPwin->GetDocShell());
3032 if (docShellAsItem) {
3033 nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
3034 docShellAsItem->GetRootTreeItem(getter_AddRefs(openerRootItem));
3035 nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
3036 if (openerRootDocShell) {
3037 PRUint32 appType;
3038 nsresult rv = openerRootDocShell->GetAppType(&appType);
3039 if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
3040 *aOpener = opener;
3045 NS_IF_ADDREF(*aOpener);
3046 return NS_OK;
3049 NS_IMETHODIMP
3050 nsGlobalWindow::SetOpener(nsIDOMWindowInternal* aOpener)
3052 // check if we were called from a privileged chrome script.
3053 // If not, opener is settable only to null.
3054 if (aOpener && !nsContentUtils::IsCallerTrustedForWrite()) {
3055 return NS_OK;
3058 SetOpenerWindow(aOpener, PR_FALSE);
3060 return NS_OK;
3063 NS_IMETHODIMP
3064 nsGlobalWindow::GetStatus(nsAString& aStatus)
3066 FORWARD_TO_OUTER(GetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
3068 aStatus = mStatus;
3069 return NS_OK;
3072 NS_IMETHODIMP
3073 nsGlobalWindow::SetStatus(const nsAString& aStatus)
3075 FORWARD_TO_OUTER(SetStatus, (aStatus), NS_ERROR_NOT_INITIALIZED);
3078 * If caller is not chrome and dom.disable_window_status_change is true,
3079 * prevent setting window.status by exiting early
3082 if (!CanSetProperty("dom.disable_window_status_change")) {
3083 return NS_OK;
3086 mStatus = aStatus;
3088 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3089 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3090 if(browserChrome) {
3091 browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,
3092 PromiseFlatString(aStatus).get());
3095 return NS_OK;
3098 NS_IMETHODIMP
3099 nsGlobalWindow::GetDefaultStatus(nsAString& aDefaultStatus)
3101 FORWARD_TO_OUTER(GetDefaultStatus, (aDefaultStatus),
3102 NS_ERROR_NOT_INITIALIZED);
3104 aDefaultStatus = mDefaultStatus;
3105 return NS_OK;
3108 NS_IMETHODIMP
3109 nsGlobalWindow::SetDefaultStatus(const nsAString& aDefaultStatus)
3111 FORWARD_TO_OUTER(SetDefaultStatus, (aDefaultStatus),
3112 NS_ERROR_NOT_INITIALIZED);
3115 * If caller is not chrome and dom.disable_window_status_change is true,
3116 * prevent setting window.defaultStatus by exiting early
3119 if (!CanSetProperty("dom.disable_window_status_change")) {
3120 return NS_OK;
3123 mDefaultStatus = aDefaultStatus;
3125 nsCOMPtr<nsIWebBrowserChrome> browserChrome;
3126 GetWebBrowserChrome(getter_AddRefs(browserChrome));
3127 if (browserChrome) {
3128 browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT_DEFAULT,
3129 PromiseFlatString(aDefaultStatus).get());
3132 return NS_OK;
3135 NS_IMETHODIMP
3136 nsGlobalWindow::GetName(nsAString& aName)
3138 FORWARD_TO_OUTER(GetName, (aName), NS_ERROR_NOT_INITIALIZED);
3140 nsXPIDLString name;
3141 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3142 if (docShellAsItem)
3143 docShellAsItem->GetName(getter_Copies(name));
3145 aName.Assign(name);
3146 return NS_OK;
3149 NS_IMETHODIMP
3150 nsGlobalWindow::SetName(const nsAString& aName)
3152 FORWARD_TO_OUTER(SetName, (aName), NS_ERROR_NOT_INITIALIZED);
3154 nsresult result = NS_OK;
3155 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3156 if (docShellAsItem)
3157 result = docShellAsItem->SetName(PromiseFlatString(aName).get());
3158 return result;
3161 // Helper functions used by many methods below.
3162 PRInt32
3163 nsGlobalWindow::DevToCSSIntPixels(PRInt32 px)
3165 if (!mDocShell)
3166 return px; // assume 1:1
3168 nsRefPtr<nsPresContext> presContext;
3169 mDocShell->GetPresContext(getter_AddRefs(presContext));
3170 if (!presContext)
3171 return px;
3173 return presContext->DevPixelsToIntCSSPixels(px);
3176 PRInt32
3177 nsGlobalWindow::CSSToDevIntPixels(PRInt32 px)
3179 if (!mDocShell)
3180 return px; // assume 1:1
3182 nsRefPtr<nsPresContext> presContext;
3183 mDocShell->GetPresContext(getter_AddRefs(presContext));
3184 if (!presContext)
3185 return px;
3187 return presContext->CSSPixelsToDevPixels(px);
3190 nsIntSize
3191 nsGlobalWindow::DevToCSSIntPixels(nsIntSize px)
3193 if (!mDocShell)
3194 return px; // assume 1:1
3196 nsRefPtr<nsPresContext> presContext;
3197 mDocShell->GetPresContext(getter_AddRefs(presContext));
3198 if (!presContext)
3199 return px;
3201 return nsIntSize(
3202 presContext->DevPixelsToIntCSSPixels(px.width),
3203 presContext->DevPixelsToIntCSSPixels(px.height));
3206 nsIntSize
3207 nsGlobalWindow::CSSToDevIntPixels(nsIntSize px)
3209 if (!mDocShell)
3210 return px; // assume 1:1
3212 nsRefPtr<nsPresContext> presContext;
3213 mDocShell->GetPresContext(getter_AddRefs(presContext));
3214 if (!presContext)
3215 return px;
3217 return nsIntSize(
3218 presContext->CSSPixelsToDevPixels(px.width),
3219 presContext->CSSPixelsToDevPixels(px.height));
3223 NS_IMETHODIMP
3224 nsGlobalWindow::GetInnerWidth(PRInt32* aInnerWidth)
3226 FORWARD_TO_OUTER(GetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
3228 NS_ENSURE_STATE(mDocShell);
3230 EnsureSizeUpToDate();
3232 nsCOMPtr<nsIBaseWindow> docShellWin(do_QueryInterface(mDocShell));
3233 nsRefPtr<nsPresContext> presContext;
3234 mDocShell->GetPresContext(getter_AddRefs(presContext));
3236 if (docShellWin && presContext) {
3237 PRInt32 width, notused;
3238 docShellWin->GetSize(&width, &notused);
3239 *aInnerWidth = nsPresContext::
3240 AppUnitsToIntCSSPixels(presContext->DevPixelsToAppUnits(width));
3241 } else {
3242 *aInnerWidth = 0;
3245 return NS_OK;
3248 NS_IMETHODIMP
3249 nsGlobalWindow::SetInnerWidth(PRInt32 aInnerWidth)
3251 FORWARD_TO_OUTER(SetInnerWidth, (aInnerWidth), NS_ERROR_NOT_INITIALIZED);
3253 NS_ENSURE_STATE(mDocShell);
3256 * If caller is not chrome and the user has not explicitly exempted the site,
3257 * prevent setting window.innerWidth by exiting early
3260 if (!CanMoveResizeWindows() || IsFrame()) {
3261 return NS_OK;
3264 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3265 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
3267 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
3268 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
3269 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
3271 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aInnerWidth, nsnull),
3272 NS_ERROR_FAILURE);
3274 PRInt32 width = CSSToDevIntPixels(aInnerWidth);
3276 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3277 PRInt32 notused, height = 0;
3278 docShellAsWin->GetSize(&notused, &height);
3280 NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, width, height),
3281 NS_ERROR_FAILURE);
3283 return NS_OK;
3286 NS_IMETHODIMP
3287 nsGlobalWindow::GetInnerHeight(PRInt32* aInnerHeight)
3289 FORWARD_TO_OUTER(GetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
3291 NS_ENSURE_STATE(mDocShell);
3293 EnsureSizeUpToDate();
3295 nsCOMPtr<nsIBaseWindow> docShellWin(do_QueryInterface(mDocShell));
3296 nsRefPtr<nsPresContext> presContext;
3297 mDocShell->GetPresContext(getter_AddRefs(presContext));
3299 if (docShellWin && presContext) {
3300 PRInt32 height, notused;
3301 docShellWin->GetSize(&notused, &height);
3302 *aInnerHeight = nsPresContext::
3303 AppUnitsToIntCSSPixels(presContext->DevPixelsToAppUnits(height));
3304 } else {
3305 *aInnerHeight = 0;
3307 return NS_OK;
3310 NS_IMETHODIMP
3311 nsGlobalWindow::SetInnerHeight(PRInt32 aInnerHeight)
3313 FORWARD_TO_OUTER(SetInnerHeight, (aInnerHeight), NS_ERROR_NOT_INITIALIZED);
3315 NS_ENSURE_STATE(mDocShell);
3318 * If caller is not chrome and the user has not explicitly exempted the site,
3319 * prevent setting window.innerHeight by exiting early
3322 if (!CanMoveResizeWindows() || IsFrame()) {
3323 return NS_OK;
3326 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
3327 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
3329 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
3330 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
3331 NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
3333 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(nsnull, &aInnerHeight),
3334 NS_ERROR_FAILURE);
3336 PRInt32 height = CSSToDevIntPixels(aInnerHeight);
3338 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
3339 PRInt32 width = 0, notused;
3340 docShellAsWin->GetSize(&width, &notused);
3342 NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, width, height),
3343 NS_ERROR_FAILURE);
3345 return NS_OK;
3348 nsresult
3349 nsGlobalWindow::GetOuterSize(nsIntSize* aSizeCSSPixels)
3351 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3352 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3353 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3355 nsGlobalWindow* rootWindow =
3356 static_cast<nsGlobalWindow *>(GetPrivateRoot());
3357 if (rootWindow) {
3358 rootWindow->FlushPendingNotifications(Flush_Layout);
3361 nsIntSize sizeDevPixels;
3362 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&sizeDevPixels.width,
3363 &sizeDevPixels.height),
3364 NS_ERROR_FAILURE);
3366 *aSizeCSSPixels = DevToCSSIntPixels(sizeDevPixels);
3367 return NS_OK;
3370 NS_IMETHODIMP
3371 nsGlobalWindow::GetOuterWidth(PRInt32* aOuterWidth)
3373 FORWARD_TO_OUTER(GetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
3375 nsIntSize sizeCSSPixels;
3376 nsresult rv = GetOuterSize(&sizeCSSPixels);
3377 NS_ENSURE_SUCCESS(rv, rv);
3379 *aOuterWidth = sizeCSSPixels.width;
3380 return NS_OK;
3383 NS_IMETHODIMP
3384 nsGlobalWindow::GetOuterHeight(PRInt32* aOuterHeight)
3386 FORWARD_TO_OUTER(GetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
3388 nsIntSize sizeCSSPixels;
3389 nsresult rv = GetOuterSize(&sizeCSSPixels);
3390 NS_ENSURE_SUCCESS(rv, rv);
3392 *aOuterHeight = sizeCSSPixels.height;
3393 return NS_OK;
3396 nsresult
3397 nsGlobalWindow::SetOuterSize(PRInt32 aLengthCSSPixels, PRBool aIsWidth)
3400 * If caller is not chrome and the user has not explicitly exempted the site,
3401 * prevent setting window.outerWidth by exiting early
3404 if (!CanMoveResizeWindows() || IsFrame()) {
3405 return NS_OK;
3408 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3409 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3410 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3412 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(
3413 aIsWidth ? &aLengthCSSPixels : nsnull,
3414 aIsWidth ? nsnull : &aLengthCSSPixels),
3415 NS_ERROR_FAILURE);
3417 PRInt32 width, height;
3418 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&width, &height), NS_ERROR_FAILURE);
3420 PRInt32 lengthDevPixels = CSSToDevIntPixels(aLengthCSSPixels);
3421 if (aIsWidth) {
3422 width = lengthDevPixels;
3423 } else {
3424 height = lengthDevPixels;
3426 return treeOwnerAsWin->SetSize(width, height, PR_TRUE);
3429 NS_IMETHODIMP
3430 nsGlobalWindow::SetOuterWidth(PRInt32 aOuterWidth)
3432 FORWARD_TO_OUTER(SetOuterWidth, (aOuterWidth), NS_ERROR_NOT_INITIALIZED);
3434 return SetOuterSize(aOuterWidth, PR_TRUE);
3437 NS_IMETHODIMP
3438 nsGlobalWindow::SetOuterHeight(PRInt32 aOuterHeight)
3440 FORWARD_TO_OUTER(SetOuterHeight, (aOuterHeight), NS_ERROR_NOT_INITIALIZED);
3442 return SetOuterSize(aOuterHeight, PR_FALSE);
3445 NS_IMETHODIMP
3446 nsGlobalWindow::GetScreenX(PRInt32* aScreenX)
3448 FORWARD_TO_OUTER(GetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3450 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3451 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3452 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3454 PRInt32 x, y;
3456 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3457 NS_ERROR_FAILURE);
3459 *aScreenX = DevToCSSIntPixels(x);
3460 return NS_OK;
3463 nsRect
3464 nsGlobalWindow::GetInnerScreenRect()
3466 if (!mDocShell)
3467 return nsRect();
3469 nsGlobalWindow* rootWindow =
3470 static_cast<nsGlobalWindow*>(GetPrivateRoot());
3471 if (rootWindow) {
3472 rootWindow->FlushPendingNotifications(Flush_Layout);
3475 nsCOMPtr<nsIPresShell> presShell;
3476 mDocShell->GetPresShell(getter_AddRefs(presShell));
3477 if (!presShell)
3478 return nsRect();
3479 nsIFrame* rootFrame = presShell->GetRootFrame();
3480 if (!rootFrame)
3481 return nsRect();
3483 return rootFrame->GetScreenRectInAppUnits();
3486 NS_IMETHODIMP
3487 nsGlobalWindow::GetMozInnerScreenX(float* aScreenX)
3489 FORWARD_TO_OUTER(GetMozInnerScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3491 nsRect r = GetInnerScreenRect();
3492 *aScreenX = nsPresContext::AppUnitsToFloatCSSPixels(r.x);
3493 return NS_OK;
3496 NS_IMETHODIMP
3497 nsGlobalWindow::GetMozInnerScreenY(float* aScreenY)
3499 FORWARD_TO_OUTER(GetMozInnerScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3501 nsRect r = GetInnerScreenRect();
3502 *aScreenY = nsPresContext::AppUnitsToFloatCSSPixels(r.y);
3503 return NS_OK;
3506 NS_IMETHODIMP
3507 nsGlobalWindow::GetMozPaintCount(PRUint64* aResult)
3509 FORWARD_TO_OUTER(GetMozPaintCount, (aResult), NS_ERROR_NOT_INITIALIZED);
3511 *aResult = 0;
3513 if (!mDocShell)
3514 return NS_OK;
3516 nsCOMPtr<nsIPresShell> presShell;
3517 mDocShell->GetPresShell(getter_AddRefs(presShell));
3518 if (!presShell)
3519 return NS_OK;
3521 *aResult = presShell->GetPaintCount();
3522 return NS_OK;
3525 NS_IMETHODIMP
3526 nsGlobalWindow::MozRequestAnimationFrame()
3528 FORWARD_TO_INNER(MozRequestAnimationFrame, (), NS_ERROR_NOT_INITIALIZED);
3530 if (!mDoc) {
3531 return NS_OK;
3534 mDoc->ScheduleBeforePaintEvent();
3535 return NS_OK;
3538 NS_IMETHODIMP
3539 nsGlobalWindow::GetMozAnimationStartTime(PRInt64 *aTime)
3541 FORWARD_TO_INNER(GetMozAnimationStartTime, (aTime), NS_ERROR_NOT_INITIALIZED);
3543 if (mDoc) {
3544 nsIPresShell* presShell = mDoc->GetShell();
3545 if (presShell) {
3546 *aTime = presShell->GetPresContext()->RefreshDriver()->
3547 MostRecentRefreshEpochTime() / PR_USEC_PER_MSEC;
3548 return NS_OK;
3552 // If all else fails, just be compatible with Date.now()
3553 *aTime = JS_Now() / PR_USEC_PER_MSEC;
3554 return NS_OK;
3557 NS_IMETHODIMP
3558 nsGlobalWindow::SetScreenX(PRInt32 aScreenX)
3560 FORWARD_TO_OUTER(SetScreenX, (aScreenX), NS_ERROR_NOT_INITIALIZED);
3563 * If caller is not chrome and the user has not explicitly exempted the site,
3564 * prevent setting window.screenX by exiting early
3567 if (!CanMoveResizeWindows() || IsFrame()) {
3568 return NS_OK;
3571 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3572 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3573 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3575 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aScreenX, nsnull),
3576 NS_ERROR_FAILURE);
3578 PRInt32 x, y;
3579 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3580 NS_ERROR_FAILURE);
3582 x = CSSToDevIntPixels(aScreenX);
3584 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(x, y),
3585 NS_ERROR_FAILURE);
3587 return NS_OK;
3590 NS_IMETHODIMP
3591 nsGlobalWindow::GetScreenY(PRInt32* aScreenY)
3593 FORWARD_TO_OUTER(GetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3595 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3596 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3597 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3599 PRInt32 x, y;
3601 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3602 NS_ERROR_FAILURE);
3604 *aScreenY = DevToCSSIntPixels(y);
3605 return NS_OK;
3608 NS_IMETHODIMP
3609 nsGlobalWindow::SetScreenY(PRInt32 aScreenY)
3611 FORWARD_TO_OUTER(SetScreenY, (aScreenY), NS_ERROR_NOT_INITIALIZED);
3614 * If caller is not chrome and the user has not explicitly exempted the site,
3615 * prevent setting window.screenY by exiting early
3618 if (!CanMoveResizeWindows() || IsFrame()) {
3619 return NS_OK;
3622 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3623 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3624 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
3626 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(nsnull, &aScreenY),
3627 NS_ERROR_FAILURE);
3629 PRInt32 x, y;
3630 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y),
3631 NS_ERROR_FAILURE);
3633 y = CSSToDevIntPixels(aScreenY);
3635 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(x, y),
3636 NS_ERROR_FAILURE);
3638 return NS_OK;
3641 // NOTE: Arguments to this function should have values scaled to
3642 // CSS pixels, not device pixels.
3643 nsresult
3644 nsGlobalWindow::CheckSecurityWidthAndHeight(PRInt32* aWidth, PRInt32* aHeight)
3646 #ifdef MOZ_XUL
3647 if (!nsContentUtils::IsCallerTrustedForWrite()) {
3648 // if attempting to resize the window, hide any open popups
3649 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
3650 nsContentUtils::HidePopupsInDocument(doc);
3652 #endif
3654 // This one is easy. Just ensure the variable is greater than 100;
3655 if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
3656 // Check security state for use in determing window dimensions
3658 if (!nsContentUtils::IsCallerTrustedForWrite()) {
3659 //sec check failed
3660 if (aWidth && *aWidth < 100) {
3661 *aWidth = 100;
3663 if (aHeight && *aHeight < 100) {
3664 *aHeight = 100;
3669 return NS_OK;
3672 // NOTE: Arguments to this function should have values scaled to
3673 // CSS pixels, not device pixels.
3674 nsresult
3675 nsGlobalWindow::CheckSecurityLeftAndTop(PRInt32* aLeft, PRInt32* aTop)
3677 // This one is harder. We have to get the screen size and window dimensions.
3679 // Check security state for use in determing window dimensions
3681 if (!nsContentUtils::IsCallerTrustedForWrite()) {
3682 #ifdef MOZ_XUL
3683 // if attempting to move the window, hide any open popups
3684 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
3685 nsContentUtils::HidePopupsInDocument(doc);
3686 #endif
3688 nsGlobalWindow* rootWindow =
3689 static_cast<nsGlobalWindow*>(GetPrivateRoot());
3690 if (rootWindow) {
3691 rootWindow->FlushPendingNotifications(Flush_Layout);
3694 nsCOMPtr<nsIBaseWindow> treeOwner;
3695 GetTreeOwner(getter_AddRefs(treeOwner));
3697 nsCOMPtr<nsIDOMScreen> screen;
3698 GetScreen(getter_AddRefs(screen));
3700 if (treeOwner && screen) {
3701 PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
3702 PRInt32 winLeft, winTop, winWidth, winHeight;
3704 // Get the window size
3705 treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
3707 // convert those values to CSS pixels
3708 // XXX four separate retrievals of the prescontext
3709 winLeft = DevToCSSIntPixels(winLeft);
3710 winTop = DevToCSSIntPixels(winTop);
3711 winWidth = DevToCSSIntPixels(winWidth);
3712 winHeight = DevToCSSIntPixels(winHeight);
3714 // Get the screen dimensions
3715 // XXX This should use nsIScreenManager once it's fully fleshed out.
3716 screen->GetAvailLeft(&screenLeft);
3717 screen->GetAvailWidth(&screenWidth);
3718 screen->GetAvailHeight(&screenHeight);
3719 #if defined(XP_MAC) || defined(XP_MACOSX)
3720 /* The mac's coordinate system is different from the assumed Windows'
3721 system. It offsets by the height of the menubar so that a window
3722 placed at (0,0) will be entirely visible. Unfortunately that
3723 correction is made elsewhere (in Widget) and the meaning of
3724 the Avail... coordinates is overloaded. Here we allow a window
3725 to be placed at (0,0) because it does make sense to do so.
3727 screen->GetTop(&screenTop);
3728 #else
3729 screen->GetAvailTop(&screenTop);
3730 #endif
3732 if (aLeft) {
3733 if (screenLeft+screenWidth < *aLeft+winWidth)
3734 *aLeft = screenLeft+screenWidth - winWidth;
3735 if (screenLeft > *aLeft)
3736 *aLeft = screenLeft;
3738 if (aTop) {
3739 if (screenTop+screenHeight < *aTop+winHeight)
3740 *aTop = screenTop+screenHeight - winHeight;
3741 if (screenTop > *aTop)
3742 *aTop = screenTop;
3744 } else {
3745 if (aLeft)
3746 *aLeft = 0;
3747 if (aTop)
3748 *aTop = 0;
3752 return NS_OK;
3755 NS_IMETHODIMP
3756 nsGlobalWindow::GetPageXOffset(PRInt32* aPageXOffset)
3758 return GetScrollX(aPageXOffset);
3761 NS_IMETHODIMP
3762 nsGlobalWindow::GetPageYOffset(PRInt32* aPageYOffset)
3764 return GetScrollY(aPageYOffset);
3767 nsresult
3768 nsGlobalWindow::GetScrollMaxXY(PRInt32* aScrollMaxX, PRInt32* aScrollMaxY)
3770 FORWARD_TO_OUTER(GetScrollMaxXY, (aScrollMaxX, aScrollMaxY),
3771 NS_ERROR_NOT_INITIALIZED);
3773 FlushPendingNotifications(Flush_Layout);
3774 nsIScrollableFrame *sf = GetScrollFrame();
3775 if (!sf)
3776 return NS_OK;
3778 nsRect scrollRange = sf->GetScrollRange();
3780 if (aScrollMaxX)
3781 *aScrollMaxX = NS_MAX(0,
3782 (PRInt32)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.XMost())));
3783 if (aScrollMaxY)
3784 *aScrollMaxY = NS_MAX(0,
3785 (PRInt32)floor(nsPresContext::AppUnitsToFloatCSSPixels(scrollRange.YMost())));
3787 return NS_OK;
3790 NS_IMETHODIMP
3791 nsGlobalWindow::GetScrollMaxX(PRInt32* aScrollMaxX)
3793 NS_ENSURE_ARG_POINTER(aScrollMaxX);
3794 *aScrollMaxX = 0;
3795 return GetScrollMaxXY(aScrollMaxX, nsnull);
3798 NS_IMETHODIMP
3799 nsGlobalWindow::GetScrollMaxY(PRInt32* aScrollMaxY)
3801 NS_ENSURE_ARG_POINTER(aScrollMaxY);
3802 *aScrollMaxY = 0;
3803 return GetScrollMaxXY(nsnull, aScrollMaxY);
3806 nsresult
3807 nsGlobalWindow::GetScrollXY(PRInt32* aScrollX, PRInt32* aScrollY,
3808 PRBool aDoFlush)
3810 FORWARD_TO_OUTER(GetScrollXY, (aScrollX, aScrollY, aDoFlush),
3811 NS_ERROR_NOT_INITIALIZED);
3813 if (aDoFlush) {
3814 FlushPendingNotifications(Flush_Layout);
3815 } else {
3816 EnsureSizeUpToDate();
3819 nsIScrollableFrame *sf = GetScrollFrame();
3820 if (!sf)
3821 return NS_OK;
3823 nsPoint scrollPos = sf->GetScrollPosition();
3824 if (scrollPos != nsPoint(0,0) && !aDoFlush) {
3825 // Oh, well. This is the expensive case -- the window is scrolled and we
3826 // didn't actually flush yet. Repeat, but with a flush, since the content
3827 // may get shorter and hence our scroll position may decrease.
3828 return GetScrollXY(aScrollX, aScrollY, PR_TRUE);
3831 if (aScrollX)
3832 *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
3833 if (aScrollY)
3834 *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
3836 return NS_OK;
3839 NS_IMETHODIMP
3840 nsGlobalWindow::GetScrollX(PRInt32* aScrollX)
3842 NS_ENSURE_ARG_POINTER(aScrollX);
3843 *aScrollX = 0;
3844 return GetScrollXY(aScrollX, nsnull, PR_FALSE);
3847 NS_IMETHODIMP
3848 nsGlobalWindow::GetScrollY(PRInt32* aScrollY)
3850 NS_ENSURE_ARG_POINTER(aScrollY);
3851 *aScrollY = 0;
3852 return GetScrollXY(nsnull, aScrollY, PR_FALSE);
3855 NS_IMETHODIMP
3856 nsGlobalWindow::GetLength(PRUint32* aLength)
3858 nsCOMPtr<nsIDOMWindowCollection> frames;
3859 if (NS_SUCCEEDED(GetFrames(getter_AddRefs(frames))) && frames) {
3860 return frames->GetLength(aLength);
3862 return NS_ERROR_FAILURE;
3865 PRBool
3866 nsGlobalWindow::DispatchCustomEvent(const char *aEventName)
3868 PRBool defaultActionEnabled = PR_TRUE;
3869 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
3870 nsContentUtils::DispatchTrustedEvent(doc,
3871 static_cast<nsIScriptGlobalObject*>(this),
3872 NS_ConvertASCIItoUTF16(aEventName),
3873 PR_TRUE, PR_TRUE, &defaultActionEnabled);
3875 return defaultActionEnabled;
3878 static already_AddRefed<nsIDocShellTreeItem>
3879 GetCallerDocShellTreeItem()
3881 JSContext *cx = nsContentUtils::GetCurrentJSContext();
3882 nsIDocShellTreeItem *callerItem = nsnull;
3884 if (cx) {
3885 nsCOMPtr<nsIWebNavigation> callerWebNav =
3886 do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
3888 if (callerWebNav) {
3889 CallQueryInterface(callerWebNav, &callerItem);
3893 return callerItem;
3896 PRBool
3897 nsGlobalWindow::WindowExists(const nsAString& aName,
3898 PRBool aLookForCallerOnJSStack)
3900 NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
3901 NS_PRECONDITION(mDocShell, "Must have docshell");
3903 nsCOMPtr<nsIDocShellTreeItem> caller;
3904 if (aLookForCallerOnJSStack) {
3905 caller = GetCallerDocShellTreeItem();
3908 nsCOMPtr<nsIDocShellTreeItem> docShell = do_QueryInterface(mDocShell);
3909 NS_ASSERTION(docShell,
3910 "Docshell doesn't implement nsIDocShellTreeItem?");
3912 if (!caller) {
3913 caller = docShell;
3916 nsCOMPtr<nsIDocShellTreeItem> namedItem;
3917 docShell->FindItemWithName(PromiseFlatString(aName).get(), nsnull, caller,
3918 getter_AddRefs(namedItem));
3919 return namedItem != nsnull;
3922 already_AddRefed<nsIWidget>
3923 nsGlobalWindow::GetMainWidget()
3925 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3926 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3928 nsIWidget *widget = nsnull;
3930 if (treeOwnerAsWin) {
3931 treeOwnerAsWin->GetMainWidget(&widget);
3934 return widget;
3937 nsIWidget*
3938 nsGlobalWindow::GetNearestWidget()
3940 nsIDocShell* docShell = GetDocShell();
3941 NS_ENSURE_TRUE(docShell, nsnull);
3942 nsCOMPtr<nsIPresShell> presShell;
3943 docShell->GetPresShell(getter_AddRefs(presShell));
3944 NS_ENSURE_TRUE(presShell, nsnull);
3945 nsIFrame* rootFrame = presShell->GetRootFrame();
3946 NS_ENSURE_TRUE(rootFrame, nsnull);
3947 return rootFrame->GetView()->GetNearestWidget(nsnull);
3950 NS_IMETHODIMP
3951 nsGlobalWindow::SetFullScreen(PRBool aFullScreen)
3953 FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
3955 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
3957 PRBool rootWinFullScreen;
3958 GetFullScreen(&rootWinFullScreen);
3959 // Only chrome can change our fullScreen mode.
3960 if (aFullScreen == rootWinFullScreen ||
3961 !nsContentUtils::IsCallerTrustedForWrite()) {
3962 return NS_OK;
3965 // SetFullScreen needs to be called on the root window, so get that
3966 // via the DocShell tree, and if we are not already the root,
3967 // call SetFullScreen on that window instead.
3968 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
3969 nsCOMPtr<nsIDocShellTreeItem> rootItem;
3970 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
3971 nsCOMPtr<nsIDOMWindowInternal> window = do_GetInterface(rootItem);
3972 if (!window)
3973 return NS_ERROR_FAILURE;
3974 if (rootItem != treeItem)
3975 return window->SetFullScreen(aFullScreen);
3977 // make sure we don't try to set full screen on a non-chrome window,
3978 // which might happen in embedding world
3979 PRInt32 itemType;
3980 treeItem->GetItemType(&itemType);
3981 if (itemType != nsIDocShellTreeItem::typeChrome)
3982 return NS_ERROR_FAILURE;
3984 // If we are already in full screen mode, just return.
3985 if (mFullScreen == aFullScreen)
3986 return NS_OK;
3988 // dispatch a "fullscreen" DOM event so that XUL apps can
3989 // respond visually if we are kicked into full screen mode
3990 if (!DispatchCustomEvent("fullscreen")) {
3991 return NS_OK;
3994 // Prevent chrome documents which are still loading from resizing
3995 // the window after we set fullscreen mode.
3996 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
3997 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
3998 nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwnerAsWin));
3999 if (aFullScreen && xulWin) {
4000 xulWin->SetIntrinsicallySized(PR_FALSE);
4003 // Set this before so if widget sends an event indicating its
4004 // gone full screen, the state trap above works.
4005 mFullScreen = aFullScreen;
4007 nsCOMPtr<nsIWidget> widget = GetMainWidget();
4008 if (widget)
4009 widget->MakeFullScreen(aFullScreen);
4011 return NS_OK;
4014 NS_IMETHODIMP
4015 nsGlobalWindow::GetFullScreen(PRBool* aFullScreen)
4017 FORWARD_TO_OUTER(GetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
4019 // Get the fullscreen value of the root window, to always have the value
4020 // accurate, even when called from content.
4021 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
4022 if (treeItem) {
4023 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4024 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
4025 if (rootItem != treeItem) {
4026 nsCOMPtr<nsIDOMWindowInternal> window = do_GetInterface(rootItem);
4027 if (window)
4028 return window->GetFullScreen(aFullScreen);
4032 // We are the root window, or something went wrong. Return our internal value.
4033 *aFullScreen = mFullScreen;
4034 return NS_OK;
4037 PRBool
4038 nsGlobalWindow::DOMWindowDumpEnabled()
4040 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
4041 // In optimized builds we check a pref that controls if we should
4042 // enable output from dump() or not, in debug builds it's always
4043 // enabled.
4044 return gDOMWindowDumpEnabled;
4045 #else
4046 return PR_TRUE;
4047 #endif
4050 NS_IMETHODIMP
4051 nsGlobalWindow::Dump(const nsAString& aStr)
4053 if (!DOMWindowDumpEnabled()) {
4054 return NS_OK;
4057 char *cstr = ToNewUTF8String(aStr);
4059 #if defined(XP_MAC) || defined(XP_MACOSX)
4060 // have to convert \r to \n so that printing to the console works
4061 char *c = cstr, *cEnd = cstr + strlen(cstr);
4062 while (c < cEnd) {
4063 if (*c == '\r')
4064 *c = '\n';
4065 c++;
4067 #endif
4069 if (cstr) {
4070 FILE *fp = gDumpFile ? gDumpFile : stdout;
4071 fputs(cstr, fp);
4072 fflush(fp);
4073 nsMemory::Free(cstr);
4076 return NS_OK;
4079 void
4080 nsGlobalWindow::EnsureReflowFlushAndPaint()
4082 NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
4083 "docshell!");
4085 if (!mDocShell)
4086 return;
4088 nsCOMPtr<nsIPresShell> presShell;
4089 mDocShell->GetPresShell(getter_AddRefs(presShell));
4091 if (!presShell)
4092 return;
4094 // Flush pending reflows.
4095 if (mDoc) {
4096 mDoc->FlushPendingNotifications(Flush_Layout);
4099 // Unsuppress painting.
4100 presShell->UnsuppressPainting();
4103 NS_IMETHODIMP
4104 nsGlobalWindow::GetTextZoom(float *aZoom)
4106 FORWARD_TO_OUTER(GetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
4108 if (mDocShell) {
4109 nsCOMPtr<nsIContentViewer> contentViewer;
4110 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
4111 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
4113 if (markupViewer) {
4114 return markupViewer->GetTextZoom(aZoom);
4117 return NS_ERROR_FAILURE;
4120 NS_IMETHODIMP
4121 nsGlobalWindow::SetTextZoom(float aZoom)
4123 FORWARD_TO_OUTER(SetTextZoom, (aZoom), NS_ERROR_NOT_INITIALIZED);
4125 if (mDocShell) {
4126 nsCOMPtr<nsIContentViewer> contentViewer;
4127 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
4128 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(contentViewer));
4130 if (markupViewer)
4131 return markupViewer->SetTextZoom(aZoom);
4133 return NS_ERROR_FAILURE;
4136 // static
4137 void
4138 nsGlobalWindow::MakeScriptDialogTitle(nsAString &aOutTitle)
4140 aOutTitle.Truncate();
4142 // Try to get a host from the running principal -- this will do the
4143 // right thing for javascript: and data: documents.
4145 nsresult rv = NS_OK;
4146 NS_ASSERTION(nsContentUtils::GetSecurityManager(),
4147 "Global Window has no security manager!");
4148 if (nsContentUtils::GetSecurityManager()) {
4149 nsCOMPtr<nsIPrincipal> principal;
4150 rv = nsContentUtils::GetSecurityManager()->
4151 GetSubjectPrincipal(getter_AddRefs(principal));
4153 if (NS_SUCCEEDED(rv) && principal) {
4154 nsCOMPtr<nsIURI> uri;
4155 rv = principal->GetURI(getter_AddRefs(uri));
4157 if (NS_SUCCEEDED(rv) && uri) {
4158 // remove user:pass for privacy and spoof prevention
4160 nsCOMPtr<nsIURIFixup> fixup(do_GetService(NS_URIFIXUP_CONTRACTID));
4161 if (fixup) {
4162 nsCOMPtr<nsIURI> fixedURI;
4163 rv = fixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
4164 if (NS_SUCCEEDED(rv) && fixedURI) {
4165 nsCAutoString host;
4166 fixedURI->GetHost(host);
4168 if (!host.IsEmpty()) {
4169 // if this URI has a host we'll show it. For other
4170 // schemes (e.g. file:) we fall back to the localized
4171 // generic string
4173 nsCAutoString prepath;
4174 fixedURI->GetPrePath(prepath);
4176 NS_ConvertUTF8toUTF16 ucsPrePath(prepath);
4177 const PRUnichar *formatStrings[] = { ucsPrePath.get() };
4178 nsXPIDLString tempString;
4179 nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4180 "ScriptDlgHeading",
4181 formatStrings, NS_ARRAY_LENGTH(formatStrings),
4182 tempString);
4183 aOutTitle = tempString;
4189 else { // failed to get subject principal
4190 NS_WARNING("No script principal? Who is calling alert/confirm/prompt?!");
4194 if (aOutTitle.IsEmpty()) {
4195 // We didn't find a host so use the generic heading
4196 nsXPIDLString tempString;
4197 nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
4198 "ScriptDlgGenericHeading",
4199 tempString);
4200 aOutTitle = tempString;
4203 // Just in case
4204 if (aOutTitle.IsEmpty()) {
4205 NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");
4206 aOutTitle.AssignLiteral("[Script]");
4210 // static
4211 PRBool
4212 nsGlobalWindow::CanMoveResizeWindows()
4214 if (!CanSetProperty("dom.disable_window_move_resize"))
4215 return PR_FALSE;
4217 if (gMouseDown && !gDragServiceDisabled) {
4218 nsCOMPtr<nsIDragService> ds =
4219 do_GetService("@mozilla.org/widget/dragservice;1");
4220 if (ds) {
4221 gDragServiceDisabled = PR_TRUE;
4222 ds->Suppress();
4225 return PR_TRUE;
4228 NS_IMETHODIMP
4229 nsGlobalWindow::Alert(const nsAString& aString)
4231 FORWARD_TO_OUTER(Alert, (aString), NS_ERROR_NOT_INITIALIZED);
4233 // Reset popup state while opening a modal dialog, and firing events
4234 // about the dialog, to prevent the current state from being active
4235 // the whole time a modal dialog is open.
4236 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4238 // Special handling for alert(null) in JS for backwards
4239 // compatibility.
4241 NS_NAMED_LITERAL_STRING(null_str, "null");
4243 const nsAString *str = DOMStringIsNull(aString) ? &null_str : &aString;
4245 // Before bringing up the window, unsuppress painting and flush
4246 // pending reflows.
4247 EnsureReflowFlushAndPaint();
4249 nsAutoString title;
4250 MakeScriptDialogTitle(title);
4252 // Remove non-terminating null characters from the
4253 // string. See bug #310037.
4254 nsAutoString final;
4255 nsContentUtils::StripNullChars(*str, final);
4257 nsresult rv;
4258 nsCOMPtr<nsIPromptService> promptSvc = do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv);
4259 NS_ENSURE_SUCCESS(rv, rv);
4261 return promptSvc->Alert(this, title.get(), final.get());
4264 NS_IMETHODIMP
4265 nsGlobalWindow::Confirm(const nsAString& aString, PRBool* aReturn)
4267 FORWARD_TO_OUTER(Confirm, (aString, aReturn), NS_ERROR_NOT_INITIALIZED);
4269 // Reset popup state while opening a modal dialog, and firing events
4270 // about the dialog, to prevent the current state from being active
4271 // the whole time a modal dialog is open.
4272 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4274 *aReturn = PR_FALSE;
4276 // Before bringing up the window, unsuppress painting and flush
4277 // pending reflows.
4278 EnsureReflowFlushAndPaint();
4280 nsAutoString title;
4281 MakeScriptDialogTitle(title);
4283 // Remove non-terminating null characters from the
4284 // string. See bug #310037.
4285 nsAutoString final;
4286 nsContentUtils::StripNullChars(aString, final);
4288 nsresult rv;
4289 nsCOMPtr<nsIPromptService> promptSvc = do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv);
4290 NS_ENSURE_SUCCESS(rv, rv);
4292 return promptSvc->Confirm(this, title.get(), final.get(), aReturn);
4295 NS_IMETHODIMP
4296 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
4297 nsAString& aReturn)
4299 SetDOMStringToNull(aReturn);
4301 // Reset popup state while opening a modal dialog, and firing events
4302 // about the dialog, to prevent the current state from being active
4303 // the whole time a modal dialog is open.
4304 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
4306 // Before bringing up the window, unsuppress painting and flush
4307 // pending reflows.
4308 EnsureReflowFlushAndPaint();
4310 nsAutoString title;
4311 MakeScriptDialogTitle(title);
4313 // Remove non-terminating null characters from the
4314 // string. See bug #310037.
4315 nsAutoString fixedMessage, fixedInitial;
4316 nsContentUtils::StripNullChars(aMessage, fixedMessage);
4317 nsContentUtils::StripNullChars(aInitial, fixedInitial);
4319 nsresult rv;
4320 nsCOMPtr<nsIPromptService> promptSvc = do_GetService("@mozilla.org/embedcomp/prompt-service;1", &rv);
4321 NS_ENSURE_SUCCESS(rv, rv);
4323 // Pass in the default value, if any.
4324 PRUnichar *inoutValue = ToNewUnicode(fixedInitial);
4326 PRBool ok, dummy;
4327 rv = promptSvc->Prompt(this, title.get(), fixedMessage.get(),
4328 &inoutValue, nsnull, &dummy, &ok);
4329 NS_ENSURE_SUCCESS(rv, rv);
4331 nsAdoptingString outValue(inoutValue);
4333 if (ok && outValue) {
4334 aReturn.Assign(outValue);
4337 return rv;
4340 NS_IMETHODIMP
4341 nsGlobalWindow::Focus()
4343 FORWARD_TO_OUTER(Focus, (), NS_ERROR_NOT_INITIALIZED);
4345 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4346 if (!fm)
4347 return NS_OK;
4349 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
4351 PRBool isVisible = PR_FALSE;
4352 if (baseWin) {
4353 baseWin->GetVisibility(&isVisible);
4356 if (!isVisible) {
4357 // A hidden tab is being focused, ignore this call.
4358 return NS_OK;
4362 * If caller is not chrome and dom.disable_window_flip is true,
4363 * prevent bringing a window to the front if the window is not the
4364 * currently active window, but do change the currently focused
4365 * window in the focus controller so that focus is in the right
4366 * place when the window is activated again.
4369 PRBool canFocus =
4370 CanSetProperty("dom.disable_window_flip") ||
4371 RevisePopupAbuseLevel(gPopupControlState) < openAbused;
4373 nsCOMPtr<nsIDOMWindow> activeWindow;
4374 fm->GetActiveWindow(getter_AddRefs(activeWindow));
4376 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
4377 NS_ASSERTION(treeItem, "What happened?");
4378 nsCOMPtr<nsIDocShellTreeItem> rootItem;
4379 treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
4380 nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
4381 PRBool isActive = (rootWin == activeWindow);
4383 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4384 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4385 if (treeOwnerAsWin && (canFocus || isActive)) {
4386 PRBool isEnabled = PR_TRUE;
4387 if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
4388 NS_WARNING( "Should not try to set the focus on a disabled window" );
4389 return NS_OK;
4392 // XXXndeakin not sure what this is for or if it should go somewhere else
4393 nsCOMPtr<nsIEmbeddingSiteWindow> embeddingWin(do_GetInterface(treeOwnerAsWin));
4394 if (embeddingWin)
4395 embeddingWin->SetFocus();
4398 if (!mDocShell)
4399 return NS_OK;
4401 nsCOMPtr<nsIPresShell> presShell;
4402 // Don't look for a presshell if we're a root chrome window that's got
4403 // about:blank loaded. We don't want to focus our widget in that case.
4404 // XXXbz should we really be checking for IsInitialDocument() instead?
4405 PRBool lookForPresShell = PR_TRUE;
4406 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
4407 treeItem->GetItemType(&itemType);
4408 if (itemType == nsIDocShellTreeItem::typeChrome &&
4409 GetPrivateRoot() == static_cast<nsIDOMWindowInternal*>(this) &&
4410 mDocument) {
4411 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
4412 NS_ASSERTION(doc, "Bogus doc?");
4413 nsIURI* ourURI = doc->GetDocumentURI();
4414 if (ourURI) {
4415 lookForPresShell = !IsAboutBlank(ourURI);
4419 if (lookForPresShell) {
4420 mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
4423 nsCOMPtr<nsIDocShellTreeItem> parentDsti;
4424 treeItem->GetParent(getter_AddRefs(parentDsti));
4426 // set the parent's current focus to the frame containing this window.
4427 nsCOMPtr<nsIDOMWindow> parent(do_GetInterface(parentDsti));
4428 if (parent) {
4429 nsCOMPtr<nsIDOMDocument> parentdomdoc;
4430 parent->GetDocument(getter_AddRefs(parentdomdoc));
4432 nsCOMPtr<nsIDocument> parentdoc = do_QueryInterface(parentdomdoc);
4433 if (!parentdoc)
4434 return NS_OK;
4436 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
4437 nsIContent* frame = parentdoc->FindContentForSubDocument(doc);
4438 nsCOMPtr<nsIDOMElement> frameElement = do_QueryInterface(frame);
4439 if (frameElement) {
4440 PRUint32 flags = nsIFocusManager::FLAG_NOSCROLL;
4441 if (canFocus)
4442 flags |= nsIFocusManager::FLAG_RAISE;
4443 return fm->SetFocus(frameElement, flags);
4446 else if (canFocus) {
4447 // if there is no parent, this must be a toplevel window, so raise the
4448 // window if canFocus is true
4449 return fm->SetActiveWindow(this);
4452 return NS_OK;
4455 NS_IMETHODIMP
4456 nsGlobalWindow::Blur()
4458 FORWARD_TO_OUTER(Blur, (), NS_ERROR_NOT_INITIALIZED);
4460 // If embedding apps don't implement nsIEmbeddingSiteWindow2, we
4461 // shouldn't throw exceptions to web content.
4462 nsresult rv = NS_OK;
4464 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
4465 GetTreeOwner(getter_AddRefs(treeOwner));
4466 nsCOMPtr<nsIEmbeddingSiteWindow2> siteWindow(do_GetInterface(treeOwner));
4467 if (siteWindow) {
4468 // This method call may cause mDocShell to become nsnull.
4469 rv = siteWindow->Blur();
4471 // if the root is focused, clear the focus
4472 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
4473 nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
4474 if (fm && mDocument) {
4475 nsCOMPtr<nsIDOMElement> element;
4476 fm->GetFocusedElementForWindow(this, PR_FALSE, nsnull, getter_AddRefs(element));
4477 nsCOMPtr<nsIContent> content = do_QueryInterface(element);
4478 if (content == doc->GetRootElement())
4479 fm->ClearFocus(this);
4483 return rv;
4486 NS_IMETHODIMP
4487 nsGlobalWindow::Back()
4489 FORWARD_TO_OUTER(Back, (), NS_ERROR_NOT_INITIALIZED);
4491 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4492 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
4494 return webNav->GoBack();
4497 NS_IMETHODIMP
4498 nsGlobalWindow::Forward()
4500 FORWARD_TO_OUTER(Forward, (), NS_ERROR_NOT_INITIALIZED);
4502 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4503 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
4505 return webNav->GoForward();
4508 NS_IMETHODIMP
4509 nsGlobalWindow::Home()
4511 FORWARD_TO_OUTER(Home, (), NS_ERROR_NOT_INITIALIZED);
4513 if (!mDocShell)
4514 return NS_OK;
4516 nsAdoptingString homeURL =
4517 nsContentUtils::GetLocalizedStringPref(PREF_BROWSER_STARTUP_HOMEPAGE);
4519 if (homeURL.IsEmpty()) {
4520 // if all else fails, use this
4521 #ifdef DEBUG_seth
4522 printf("all else failed. using %s as the home page\n", DEFAULT_HOME_PAGE);
4523 #endif
4524 CopyASCIItoUTF16(DEFAULT_HOME_PAGE, homeURL);
4527 #ifdef MOZ_PHOENIX
4529 // Firefox lets the user specify multiple home pages to open in
4530 // individual tabs by separating them with '|'. Since we don't
4531 // have the machinery in place to easily open new tabs from here,
4532 // simply truncate the homeURL at the first '|' character to
4533 // prevent any possibilities of leaking the users list of home
4534 // pages to the first home page.
4536 // Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is
4537 // fixed we can revisit this.
4538 PRInt32 firstPipe = homeURL.FindChar('|');
4540 if (firstPipe > 0) {
4541 homeURL.Truncate(firstPipe);
4544 #endif
4546 nsresult rv;
4547 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4548 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
4549 rv = webNav->LoadURI(homeURL.get(),
4550 nsIWebNavigation::LOAD_FLAGS_NONE,
4551 nsnull,
4552 nsnull,
4553 nsnull);
4554 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
4555 return NS_OK;
4558 NS_IMETHODIMP
4559 nsGlobalWindow::Stop()
4561 FORWARD_TO_OUTER(Stop, (), NS_ERROR_NOT_INITIALIZED);
4563 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
4564 if (!webNav)
4565 return NS_OK;
4567 return webNav->Stop(nsIWebNavigation::STOP_ALL);
4570 NS_IMETHODIMP
4571 nsGlobalWindow::Print()
4573 #ifdef NS_PRINTING
4574 FORWARD_TO_OUTER(Print, (), NS_ERROR_NOT_INITIALIZED);
4576 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
4577 if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
4578 getter_AddRefs(webBrowserPrint)))) {
4580 nsCOMPtr<nsIPrintSettingsService> printSettingsService =
4581 do_GetService("@mozilla.org/gfx/printsettings-service;1");
4583 nsCOMPtr<nsIPrintSettings> printSettings;
4584 if (printSettingsService) {
4585 PRBool printSettingsAreGlobal =
4586 nsContentUtils::GetBoolPref("print.use_global_printsettings", PR_FALSE);
4588 if (printSettingsAreGlobal) {
4589 printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));
4591 nsXPIDLString printerName;
4592 printSettings->GetPrinterName(getter_Copies(printerName));
4593 if (printerName.IsEmpty()) {
4594 printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
4595 printSettings->SetPrinterName(printerName);
4597 printSettingsService->InitPrintSettingsFromPrinter(printerName, printSettings);
4598 printSettingsService->InitPrintSettingsFromPrefs(printSettings,
4599 PR_TRUE,
4600 nsIPrintSettings::kInitSaveAll);
4601 } else {
4602 printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
4605 EnterModalState();
4606 webBrowserPrint->Print(printSettings, nsnull);
4607 LeaveModalState();
4609 PRBool savePrintSettings =
4610 nsContentUtils::GetBoolPref("print.save_print_settings", PR_FALSE);
4611 if (printSettingsAreGlobal && savePrintSettings) {
4612 printSettingsService->
4613 SavePrintSettingsToPrefs(printSettings,
4614 PR_TRUE,
4615 nsIPrintSettings::kInitSaveAll);
4616 printSettingsService->
4617 SavePrintSettingsToPrefs(printSettings,
4618 PR_FALSE,
4619 nsIPrintSettings::kInitSavePrinterName);
4621 } else {
4622 webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
4623 webBrowserPrint->Print(printSettings, nsnull);
4626 #endif //NS_PRINTING
4628 return NS_OK;
4631 NS_IMETHODIMP
4632 nsGlobalWindow::MoveTo(PRInt32 aXPos, PRInt32 aYPos)
4634 FORWARD_TO_OUTER(MoveTo, (aXPos, aYPos), NS_ERROR_NOT_INITIALIZED);
4637 * If caller is not chrome and the user has not explicitly exempted the site,
4638 * prevent window.moveTo() by exiting early
4641 if (!CanMoveResizeWindows() || IsFrame()) {
4642 return NS_OK;
4645 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4646 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4647 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
4649 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&aXPos, &aYPos),
4650 NS_ERROR_FAILURE);
4652 // mild abuse of a "size" object so we don't need more helper functions
4653 nsIntSize devPos(CSSToDevIntPixels(nsIntSize(aXPos, aYPos)));
4655 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(devPos.width, devPos.height),
4656 NS_ERROR_FAILURE);
4658 return NS_OK;
4661 NS_IMETHODIMP
4662 nsGlobalWindow::MoveBy(PRInt32 aXDif, PRInt32 aYDif)
4664 FORWARD_TO_OUTER(MoveBy, (aXDif, aYDif), NS_ERROR_NOT_INITIALIZED);
4667 * If caller is not chrome and the user has not explicitly exempted the site,
4668 * prevent window.moveBy() by exiting early
4671 if (!CanMoveResizeWindows() || IsFrame()) {
4672 return NS_OK;
4675 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4676 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4677 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
4679 // To do this correctly we have to convert what we get from GetPosition
4680 // into CSS pixels, add the arguments, do the security check, and
4681 // then convert back to device pixels for the call to SetPosition.
4683 PRInt32 x, y;
4684 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetPosition(&x, &y), NS_ERROR_FAILURE);
4686 // mild abuse of a "size" object so we don't need more helper functions
4687 nsIntSize cssPos(DevToCSSIntPixels(nsIntSize(x, y)));
4689 cssPos.width += aXDif;
4690 cssPos.height += aYDif;
4692 NS_ENSURE_SUCCESS(CheckSecurityLeftAndTop(&cssPos.width,
4693 &cssPos.height),
4694 NS_ERROR_FAILURE);
4696 nsIntSize newDevPos(CSSToDevIntPixels(cssPos));
4698 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetPosition(newDevPos.width,
4699 newDevPos.height),
4700 NS_ERROR_FAILURE);
4702 return NS_OK;
4705 NS_IMETHODIMP
4706 nsGlobalWindow::ResizeTo(PRInt32 aWidth, PRInt32 aHeight)
4708 FORWARD_TO_OUTER(ResizeTo, (aWidth, aHeight), NS_ERROR_NOT_INITIALIZED);
4711 * If caller is not chrome and the user has not explicitly exempted the site,
4712 * prevent window.resizeTo() by exiting early
4715 if (!CanMoveResizeWindows() || IsFrame()) {
4716 return NS_OK;
4719 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4720 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4721 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
4723 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&aWidth, &aHeight),
4724 NS_ERROR_FAILURE);
4726 nsIntSize devSz(CSSToDevIntPixels(nsIntSize(aWidth, aHeight)));
4728 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(devSz.width, devSz.height, PR_TRUE),
4729 NS_ERROR_FAILURE);
4731 return NS_OK;
4734 NS_IMETHODIMP
4735 nsGlobalWindow::ResizeBy(PRInt32 aWidthDif, PRInt32 aHeightDif)
4737 FORWARD_TO_OUTER(ResizeBy, (aWidthDif, aHeightDif), NS_ERROR_NOT_INITIALIZED);
4740 * If caller is not chrome and the user has not explicitly exempted the site,
4741 * prevent window.resizeBy() by exiting early
4744 if (!CanMoveResizeWindows() || IsFrame()) {
4745 return NS_OK;
4748 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
4749 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
4750 NS_ENSURE_TRUE(treeOwnerAsWin, NS_ERROR_FAILURE);
4752 PRInt32 width, height;
4753 NS_ENSURE_SUCCESS(treeOwnerAsWin->GetSize(&width, &height), NS_ERROR_FAILURE);
4755 // To do this correctly we have to convert what we got from GetSize
4756 // into CSS pixels, add the arguments, do the security check, and
4757 // then convert back to device pixels for the call to SetSize.
4759 nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
4761 cssSize.width += aWidthDif;
4762 cssSize.height += aHeightDif;
4764 NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&cssSize.width,
4765 &cssSize.height),
4766 NS_ERROR_FAILURE);
4768 nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
4770 NS_ENSURE_SUCCESS(treeOwnerAsWin->SetSize(newDevSize.width,
4771 newDevSize.height,
4772 PR_TRUE),
4773 NS_ERROR_FAILURE);
4775 return NS_OK;
4778 NS_IMETHODIMP
4779 nsGlobalWindow::SizeToContent()
4781 FORWARD_TO_OUTER(SizeToContent, (), NS_ERROR_NOT_INITIALIZED);
4783 if (!mDocShell) {
4784 return NS_OK;
4788 * If caller is not chrome and the user has not explicitly exempted the site,
4789 * prevent window.sizeToContent() by exiting early
4792 if (!CanMoveResizeWindows() || IsFrame()) {
4793 return NS_OK;
4796 // The content viewer does a check to make sure that it's a content
4797 // viewer for a toplevel docshell.
4799 nsCOMPtr<nsIContentViewer> cv;
4800 mDocShell->GetContentViewer(getter_AddRefs(cv));
4801 nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(cv));
4802 NS_ENSURE_TRUE(markupViewer, NS_ERROR_FAILURE);
4803 NS_ENSURE_SUCCESS(markupViewer->SizeToContent(), NS_ERROR_FAILURE);
4805 return NS_OK;
4808 NS_IMETHODIMP
4809 nsGlobalWindow::GetWindowRoot(nsIDOMEventTarget **aWindowRoot)
4811 nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
4812 return CallQueryInterface(root, aWindowRoot);
4815 already_AddRefed<nsPIWindowRoot>
4816 nsGlobalWindow::GetTopWindowRoot()
4818 nsIDOMWindowInternal *rootWindow = GetPrivateRoot();
4819 nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(rootWindow));
4820 if (!piWin)
4821 return nsnull;
4823 nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
4824 return window.forget();
4827 NS_IMETHODIMP
4828 nsGlobalWindow::Scroll(PRInt32 aXScroll, PRInt32 aYScroll)
4830 return ScrollTo(aXScroll, aYScroll);
4833 NS_IMETHODIMP
4834 nsGlobalWindow::ScrollTo(PRInt32 aXScroll, PRInt32 aYScroll)
4836 FlushPendingNotifications(Flush_Layout);
4837 nsIScrollableFrame *sf = GetScrollFrame();
4839 if (sf) {
4840 // Here we calculate what the max pixel value is that we can
4841 // scroll to, we do this by dividing maxint with the pixel to
4842 // twips conversion factor, and substracting 4, the 4 comes from
4843 // experimenting with this value, anything less makes the view
4844 // code not scroll correctly, I have no idea why. -- jst
4845 const PRInt32 maxpx = nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff) - 4;
4847 if (aXScroll > maxpx) {
4848 aXScroll = maxpx;
4851 if (aYScroll > maxpx) {
4852 aYScroll = maxpx;
4854 sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aXScroll),
4855 nsPresContext::CSSPixelsToAppUnits(aYScroll)),
4856 nsIScrollableFrame::INSTANT);
4859 return NS_OK;
4862 NS_IMETHODIMP
4863 nsGlobalWindow::ScrollBy(PRInt32 aXScrollDif, PRInt32 aYScrollDif)
4865 FlushPendingNotifications(Flush_Layout);
4866 nsIScrollableFrame *sf = GetScrollFrame();
4868 if (sf) {
4869 nsPoint scrollPos = sf->GetScrollPosition();
4870 // It seems like it would make more sense for ScrollBy to use
4871 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
4872 // Perhaps Web content does too.
4873 return ScrollTo(nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x) + aXScrollDif,
4874 nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y) + aYScrollDif);
4877 return NS_OK;
4880 NS_IMETHODIMP
4881 nsGlobalWindow::ScrollByLines(PRInt32 numLines)
4883 FlushPendingNotifications(Flush_Layout);
4884 nsIScrollableFrame *sf = GetScrollFrame();
4885 if (sf) {
4886 // It seems like it would make more sense for ScrollByLines to use
4887 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
4888 // Perhaps Web content does too.
4889 sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
4890 nsIScrollableFrame::INSTANT);
4893 return NS_OK;
4896 NS_IMETHODIMP
4897 nsGlobalWindow::ScrollByPages(PRInt32 numPages)
4899 FlushPendingNotifications(Flush_Layout);
4900 nsIScrollableFrame *sf = GetScrollFrame();
4901 if (sf) {
4902 // It seems like it would make more sense for ScrollByPages to use
4903 // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
4904 // Perhaps Web content does too.
4905 sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
4906 nsIScrollableFrame::INSTANT);
4909 return NS_OK;
4912 NS_IMETHODIMP
4913 nsGlobalWindow::ClearTimeout()
4915 return ClearTimeoutOrInterval();
4918 NS_IMETHODIMP
4919 nsGlobalWindow::ClearInterval()
4921 return ClearTimeoutOrInterval();
4924 NS_IMETHODIMP
4925 nsGlobalWindow::SetTimeout(PRInt32 *_retval)
4927 return SetTimeoutOrInterval(PR_FALSE, _retval);
4930 NS_IMETHODIMP
4931 nsGlobalWindow::SetInterval(PRInt32 *_retval)
4933 return SetTimeoutOrInterval(PR_TRUE, _retval);
4936 NS_IMETHODIMP
4937 nsGlobalWindow::SetResizable(PRBool aResizable)
4939 // nop
4941 return NS_OK;
4944 static void
4945 ReportUseOfDeprecatedMethod(nsGlobalWindow* aWindow, const char* aWarning)
4947 nsCOMPtr<nsIDocument> doc = do_QueryInterface(aWindow->GetExtantDocument());
4948 nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES,
4949 aWarning,
4950 nsnull, 0,
4951 doc ? doc->GetDocumentURI() : nsnull,
4952 EmptyString(), 0, 0,
4953 nsIScriptError::warningFlag,
4954 "DOM Events");
4957 NS_IMETHODIMP
4958 nsGlobalWindow::CaptureEvents(PRInt32 aEventFlags)
4960 ReportUseOfDeprecatedMethod(this, "UseOfCaptureEventsWarning");
4961 return NS_OK;
4964 NS_IMETHODIMP
4965 nsGlobalWindow::ReleaseEvents(PRInt32 aEventFlags)
4967 ReportUseOfDeprecatedMethod(this, "UseOfReleaseEventsWarning");
4968 return NS_OK;
4971 NS_IMETHODIMP
4972 nsGlobalWindow::RouteEvent(nsIDOMEvent* aEvt)
4974 ReportUseOfDeprecatedMethod(this, "UseOfRouteEventWarning");
4975 return NS_OK;
4978 NS_IMETHODIMP
4979 nsGlobalWindow::EnableExternalCapture()
4981 return NS_ERROR_FAILURE;
4984 NS_IMETHODIMP
4985 nsGlobalWindow::DisableExternalCapture()
4987 return NS_ERROR_FAILURE;
4990 static
4991 PRBool IsPopupBlocked(nsIDOMDocument* aDoc)
4993 nsCOMPtr<nsIPopupWindowManager> pm =
4994 do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
4996 if (!pm) {
4997 return PR_FALSE;
5000 PRBool blocked = PR_TRUE;
5001 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
5003 if (doc) {
5004 PRUint32 permission = nsIPopupWindowManager::ALLOW_POPUP;
5005 pm->TestPermission(doc->GetDocumentURI(), &permission);
5006 blocked = (permission == nsIPopupWindowManager::DENY_POPUP);
5008 return blocked;
5011 /* static */
5012 void
5013 nsGlobalWindow::FirePopupBlockedEvent(nsIDOMDocument* aDoc,
5014 nsIDOMWindow *aRequestingWindow, nsIURI *aPopupURI,
5015 const nsAString &aPopupWindowName,
5016 const nsAString &aPopupWindowFeatures)
5018 if (aDoc) {
5019 // Fire a "DOMPopupBlocked" event so that the UI can hear about
5020 // blocked popups.
5021 nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(aDoc));
5022 nsCOMPtr<nsIDOMEvent> event;
5023 docEvent->CreateEvent(NS_LITERAL_STRING("PopupBlockedEvents"),
5024 getter_AddRefs(event));
5025 if (event) {
5026 nsCOMPtr<nsIDOMPopupBlockedEvent> pbev(do_QueryInterface(event));
5027 pbev->InitPopupBlockedEvent(NS_LITERAL_STRING("DOMPopupBlocked"),
5028 PR_TRUE, PR_TRUE, aRequestingWindow,
5029 aPopupURI, aPopupWindowName,
5030 aPopupWindowFeatures);
5031 nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
5032 privateEvent->SetTrusted(PR_TRUE);
5034 nsCOMPtr<nsIDOMEventTarget> targ(do_QueryInterface(aDoc));
5035 PRBool defaultActionEnabled;
5036 targ->DispatchEvent(event, &defaultActionEnabled);
5041 void FirePopupWindowEvent(nsIDOMDocument* aDoc)
5043 // Fire a "PopupWindow" event
5044 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
5045 nsContentUtils::DispatchTrustedEvent(doc, aDoc,
5046 NS_LITERAL_STRING("PopupWindow"),
5047 PR_TRUE, PR_TRUE);
5050 // static
5051 PRBool
5052 nsGlobalWindow::CanSetProperty(const char *aPrefName)
5054 // Chrome can set any property.
5055 if (nsContentUtils::IsCallerTrustedForWrite()) {
5056 return PR_TRUE;
5059 // If the pref is set to true, we can not set the property
5060 // and vice versa.
5061 return !nsContentUtils::GetBoolPref(aPrefName, PR_TRUE);
5064 PRBool
5065 nsGlobalWindow::PopupWhitelisted()
5067 if (!IsPopupBlocked(mDocument))
5068 return PR_TRUE;
5070 nsCOMPtr<nsIDOMWindow> parent;
5072 if (NS_FAILED(GetParent(getter_AddRefs(parent))) ||
5073 parent == static_cast<nsIDOMWindow*>(this))
5075 return PR_FALSE;
5078 return static_cast<nsGlobalWindow*>
5079 (static_cast<nsIDOMWindow*>
5080 (parent.get()))->PopupWhitelisted();
5084 * Examine the current document state to see if we're in a way that is
5085 * typically abused by web designers. The window.open code uses this
5086 * routine to determine whether to allow the new window.
5087 * Returns a value from the PopupControlState enum.
5089 PopupControlState
5090 nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
5092 FORWARD_TO_OUTER(RevisePopupAbuseLevel, (aControl), aControl);
5094 NS_ASSERTION(mDocShell, "Must have docshell");
5096 nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(mDocShell));
5098 NS_ASSERTION(item, "Docshell doesn't implement nsIDocShellTreeItem?");
5100 PRInt32 type = nsIDocShellTreeItem::typeChrome;
5101 item->GetItemType(&type);
5102 if (type != nsIDocShellTreeItem::typeContent)
5103 return openAllowed;
5105 PopupControlState abuse = aControl;
5106 switch (abuse) {
5107 case openControlled:
5108 case openAbused:
5109 case openOverridden:
5110 if (PopupWhitelisted())
5111 abuse = PopupControlState(abuse - 1);
5112 case openAllowed: break;
5113 default:
5114 NS_WARNING("Strange PopupControlState!");
5117 // limit the number of simultaneously open popups
5118 if (abuse == openAbused || abuse == openControlled) {
5119 PRInt32 popupMax = nsContentUtils::GetIntPref("dom.popup_maximum", -1);
5120 if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
5121 abuse = openOverridden;
5124 return abuse;
5127 /* If a window open is blocked, fire the appropriate DOM events.
5128 aBlocked signifies we just blocked a popup.
5129 aWindow signifies we just opened what is probably a popup.
5131 void
5132 nsGlobalWindow::FireAbuseEvents(PRBool aBlocked, PRBool aWindow,
5133 const nsAString &aPopupURL,
5134 const nsAString &aPopupWindowName,
5135 const nsAString &aPopupWindowFeatures)
5137 // fetch the URI of the window requesting the opened window
5139 nsCOMPtr<nsIDOMWindow> topWindow;
5140 GetTop(getter_AddRefs(topWindow));
5141 if (!topWindow)
5142 return;
5144 nsCOMPtr<nsIDOMDocument> topDoc;
5145 topWindow->GetDocument(getter_AddRefs(topDoc));
5147 nsCOMPtr<nsIURI> popupURI;
5149 // build the URI of the would-have-been popup window
5150 // (see nsWindowWatcher::URIfromURL)
5152 // first, fetch the opener's base URI
5154 nsIURI *baseURL = 0;
5156 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5157 nsCOMPtr<nsIDOMWindow> contextWindow;
5159 if (cx) {
5160 nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
5161 if (currentCX) {
5162 contextWindow = do_QueryInterface(currentCX->GetGlobalObject());
5165 if (!contextWindow)
5166 contextWindow = static_cast<nsIDOMWindow*>(this);
5168 nsCOMPtr<nsIDOMDocument> domdoc;
5169 contextWindow->GetDocument(getter_AddRefs(domdoc));
5170 nsCOMPtr<nsIDocument> doc(do_QueryInterface(domdoc));
5171 if (doc)
5172 baseURL = doc->GetDocBaseURI();
5174 // use the base URI to build what would have been the popup's URI
5175 nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
5176 if (ios)
5177 ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), 0, baseURL,
5178 getter_AddRefs(popupURI));
5180 // fire an event chock full of informative URIs
5181 if (aBlocked)
5182 FirePopupBlockedEvent(topDoc, this, popupURI, aPopupWindowName,
5183 aPopupWindowFeatures);
5184 if (aWindow)
5185 FirePopupWindowEvent(topDoc);
5188 NS_IMETHODIMP
5189 nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
5190 const nsAString& aOptions, nsIDOMWindow **_retval)
5192 return OpenInternal(aUrl, aName, aOptions,
5193 PR_FALSE, // aDialog
5194 PR_FALSE, // aContentModal
5195 PR_TRUE, // aCalledNoScript
5196 PR_FALSE, // aDoJSFixups
5197 nsnull, nsnull, // No args
5198 GetPrincipal(), // aCalleePrincipal
5199 nsnull, // aJSCallerContext
5200 _retval);
5203 NS_IMETHODIMP
5204 nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName,
5205 const nsAString& aOptions, nsIDOMWindow **_retval)
5207 return OpenInternal(aUrl, aName, aOptions,
5208 PR_FALSE, // aDialog
5209 PR_FALSE, // aContentModal
5210 PR_FALSE, // aCalledNoScript
5211 PR_TRUE, // aDoJSFixups
5212 nsnull, nsnull, // No args
5213 GetPrincipal(), // aCalleePrincipal
5214 nsContentUtils::GetCurrentJSContext(), // aJSCallerContext
5215 _retval);
5218 // like Open, but attaches to the new window any extra parameters past
5219 // [features] as a JS property named "arguments"
5220 NS_IMETHODIMP
5221 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
5222 const nsAString& aOptions,
5223 nsISupports* aExtraArgument, nsIDOMWindow** _retval)
5225 return OpenInternal(aUrl, aName, aOptions,
5226 PR_TRUE, // aDialog
5227 PR_FALSE, // aContentModal
5228 PR_TRUE, // aCalledNoScript
5229 PR_FALSE, // aDoJSFixups
5230 nsnull, aExtraArgument, // Arguments
5231 GetPrincipal(), // aCalleePrincipal
5232 nsnull, // aJSCallerContext
5233 _retval);
5236 NS_IMETHODIMP
5237 nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
5238 const nsAString& aOptions, nsIDOMWindow** _retval)
5240 if (!nsContentUtils::IsCallerTrustedForWrite()) {
5241 return NS_ERROR_DOM_SECURITY_ERR;
5244 nsAXPCNativeCallContext *ncc = nsnull;
5245 nsresult rv = nsContentUtils::XPConnect()->
5246 GetCurrentNativeCallContext(&ncc);
5247 NS_ENSURE_SUCCESS(rv, rv);
5249 if (!ncc)
5250 return NS_ERROR_NOT_AVAILABLE;
5252 JSContext *cx = nsnull;
5254 rv = ncc->GetJSContext(&cx);
5255 NS_ENSURE_SUCCESS(rv, rv);
5257 PRUint32 argc;
5258 jsval *argv = nsnull;
5260 // XXX - need to get this as nsISupports?
5261 ncc->GetArgc(&argc);
5262 ncc->GetArgvPtr(&argv);
5264 // Strip the url, name and options from the args seen by scripts.
5265 PRUint32 argOffset = argc < 3 ? argc : 3;
5266 nsCOMPtr<nsIArray> argvArray;
5267 rv = NS_CreateJSArgv(cx, argc - argOffset, argv + argOffset,
5268 getter_AddRefs(argvArray));
5269 NS_ENSURE_SUCCESS(rv, rv);
5271 return OpenInternal(aUrl, aName, aOptions,
5272 PR_TRUE, // aDialog
5273 PR_FALSE, // aContentModal
5274 PR_FALSE, // aCalledNoScript
5275 PR_FALSE, // aDoJSFixups
5276 argvArray, nsnull, // Arguments
5277 GetPrincipal(), // aCalleePrincipal
5278 cx, // aJSCallerContext
5279 _retval);
5282 NS_IMETHODIMP
5283 nsGlobalWindow::GetFrames(nsIDOMWindow** aFrames)
5285 FORWARD_TO_OUTER(GetFrames, (aFrames), NS_ERROR_NOT_INITIALIZED);
5287 *aFrames = this;
5288 NS_ADDREF(*aFrames);
5290 FlushPendingNotifications(Flush_ContentAndNotify);
5292 return NS_OK;
5295 nsGlobalWindow*
5296 nsGlobalWindow::CallerInnerWindow()
5298 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5299 if (!cx) {
5300 NS_ERROR("Please don't call this method from C++!");
5302 return nsnull;
5305 JSObject *scope = ::JS_GetScopeChain(cx);
5306 if (!scope)
5307 return nsnull;
5309 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
5310 nsContentUtils::XPConnect()->
5311 GetWrappedNativeOfJSObject(cx, ::JS_GetGlobalForObject(cx, scope),
5312 getter_AddRefs(wrapper));
5313 if (!wrapper)
5314 return nsnull;
5316 // The calling window must be holding a reference, so we can just return a
5317 // raw pointer here and let the QI's addref be balanced by the nsCOMPtr
5318 // destructor's release.
5319 nsCOMPtr<nsPIDOMWindow> win = do_QueryWrappedNative(wrapper);
5320 if (!win)
5321 return GetCurrentInnerWindowInternal();
5322 return static_cast<nsGlobalWindow*>(win.get());
5327 * Class used to represent events generated by calls to Window.postMessage,
5328 * which asynchronously creates and dispatches events.
5330 class PostMessageEvent : public nsRunnable
5332 public:
5333 NS_DECL_NSIRUNNABLE
5335 PostMessageEvent(nsGlobalWindow* aSource,
5336 const nsAString& aCallerOrigin,
5337 const nsAString& aMessage,
5338 nsGlobalWindow* aTargetWindow,
5339 nsIURI* aProvidedOrigin,
5340 PRBool aTrustedCaller)
5341 : mSource(aSource),
5342 mCallerOrigin(aCallerOrigin),
5343 mMessage(aMessage),
5344 mTargetWindow(aTargetWindow),
5345 mProvidedOrigin(aProvidedOrigin),
5346 mTrustedCaller(aTrustedCaller)
5348 MOZ_COUNT_CTOR(PostMessageEvent);
5351 ~PostMessageEvent()
5353 MOZ_COUNT_DTOR(PostMessageEvent);
5356 private:
5357 nsRefPtr<nsGlobalWindow> mSource;
5358 nsString mCallerOrigin;
5359 nsString mMessage;
5360 nsRefPtr<nsGlobalWindow> mTargetWindow;
5361 nsCOMPtr<nsIURI> mProvidedOrigin;
5362 PRBool mTrustedCaller;
5365 NS_IMETHODIMP
5366 PostMessageEvent::Run()
5368 NS_ABORT_IF_FALSE(mTargetWindow->IsOuterWindow(),
5369 "should have been passed an outer window!");
5370 NS_ABORT_IF_FALSE(!mSource || mSource->IsOuterWindow(),
5371 "should have been passed an outer window!");
5373 nsRefPtr<nsGlobalWindow> targetWindow;
5374 if (mTargetWindow->IsClosedOrClosing() ||
5375 !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
5376 targetWindow->IsClosedOrClosing())
5377 return NS_OK;
5379 NS_ABORT_IF_FALSE(targetWindow->IsInnerWindow(),
5380 "we ordered an inner window!");
5382 // Ensure that any origin which might have been provided is the origin of this
5383 // window's document. Note that we do this *now* instead of when postMessage
5384 // is called because the target window might have been navigated to a
5385 // different location between then and now. If this check happened when
5386 // postMessage was called, it would be fairly easy for a malicious webpage to
5387 // intercept messages intended for another site by carefully timing navigation
5388 // of the target window so it changed location after postMessage but before
5389 // now.
5390 if (mProvidedOrigin) {
5391 // Get the target's origin either from its principal or, in the case the
5392 // principal doesn't carry a URI (e.g. the system principal), the target's
5393 // document.
5394 nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
5395 if (!targetPrin)
5396 return NS_OK;
5397 nsCOMPtr<nsIURI> targetURI;
5398 if (NS_FAILED(targetPrin->GetURI(getter_AddRefs(targetURI))))
5399 return NS_OK;
5400 if (!targetURI) {
5401 targetURI = targetWindow->mDoc->GetDocumentURI();
5402 if (!targetURI)
5403 return NS_OK;
5406 // Note: This is contrary to the spec with respect to file: URLs, which
5407 // the spec groups into a single origin, but given we intentionally
5408 // don't do that in other places it seems better to hold the line for
5409 // now. Long-term, we want HTML5 to address this so that we can
5410 // be compliant while being safer.
5411 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
5412 nsresult rv =
5413 ssm->CheckSameOriginURI(mProvidedOrigin, targetURI, PR_TRUE);
5414 if (NS_FAILED(rv))
5415 return NS_OK;
5419 // Create the event
5420 nsCOMPtr<nsIDOMDocumentEvent> docEvent =
5421 do_QueryInterface(targetWindow->mDocument);
5422 if (!docEvent)
5423 return NS_OK;
5424 nsCOMPtr<nsIDOMEvent> event;
5425 docEvent->CreateEvent(NS_LITERAL_STRING("MessageEvent"),
5426 getter_AddRefs(event));
5427 if (!event)
5428 return NS_OK;
5430 nsCOMPtr<nsIDOMMessageEvent> message = do_QueryInterface(event);
5431 nsresult rv = message->InitMessageEvent(NS_LITERAL_STRING("message"),
5432 PR_FALSE /* non-bubbling */,
5433 PR_TRUE /* cancelable */,
5434 mMessage,
5435 mCallerOrigin,
5436 EmptyString(),
5437 mSource);
5438 if (NS_FAILED(rv))
5439 return NS_OK;
5442 // We can't simply call dispatchEvent on the window because doing so ends
5443 // up flipping the trusted bit on the event, and we don't want that to
5444 // happen because then untrusted content can call postMessage on a chrome
5445 // window if it can get a reference to it.
5447 nsIPresShell *shell = targetWindow->mDoc->GetShell();
5448 nsRefPtr<nsPresContext> presContext;
5449 if (shell)
5450 presContext = shell->GetPresContext();
5452 nsCOMPtr<nsIPrivateDOMEvent> privEvent = do_QueryInterface(message);
5453 privEvent->SetTrusted(mTrustedCaller);
5454 nsEvent *internalEvent = privEvent->GetInternalNSEvent();
5456 nsEventStatus status = nsEventStatus_eIgnore;
5457 nsEventDispatcher::Dispatch(static_cast<nsPIDOMWindow*>(mTargetWindow),
5458 presContext,
5459 internalEvent,
5460 message,
5461 &status);
5462 return NS_OK;
5465 NS_IMETHODIMP
5466 nsGlobalWindow::PostMessageMoz(const nsAString& aMessage, const nsAString& aOrigin)
5468 // NB: Since much of what this method does must happen at event dispatch time,
5469 // this method does not forward to the inner window, unlike most other
5470 // methods. We do this because the only time we need to refer to this
5471 // window, we need a reference to the outer window (the PostMessageEvent
5472 // ctor call), and we don't want to pay the price of forwarding to the
5473 // inner window for no actual benefit. Furthermore, this function must
5474 // only be called from script anyway, which should only have references to
5475 // outer windows (and if script has an inner window we've already lost).
5476 NS_ABORT_IF_FALSE(IsOuterWindow(), "only call this method on outer windows");
5479 // Window.postMessage is an intentional subversion of the same-origin policy.
5480 // As such, this code must be particularly careful in the information it
5481 // exposes to calling code.
5483 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html
5486 // First, get the caller's window
5487 nsRefPtr<nsGlobalWindow> callerInnerWin = CallerInnerWindow();
5488 if (!callerInnerWin)
5489 return NS_OK;
5490 NS_ABORT_IF_FALSE(callerInnerWin->IsInnerWindow(),
5491 "should have gotten an inner window here");
5493 // Compute the caller's origin either from its principal or, in the case the
5494 // principal doesn't carry a URI (e.g. the system principal), the caller's
5495 // document. We must get this now instead of when the event is created and
5496 // dispatched, because ultimately it is the identity of the calling window
5497 // *now* that determines who sent the message (and not an identity which might
5498 // have changed due to intervening navigations).
5499 nsIPrincipal* callerPrin = callerInnerWin->GetPrincipal();
5500 if (!callerPrin)
5501 return NS_OK;
5503 nsCOMPtr<nsIURI> callerOuterURI;
5504 if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI))))
5505 return NS_OK;
5507 nsAutoString origin;
5508 if (callerOuterURI) {
5509 // if the principal has a URI, use that to generate the origin
5510 nsContentUtils::GetUTFOrigin(callerPrin, origin);
5512 else {
5513 // otherwise use the URI of the document to generate origin
5514 nsCOMPtr<nsIDocument> doc = do_QueryInterface(callerInnerWin->mDocument);
5515 if (!doc)
5516 return NS_OK;
5517 callerOuterURI = doc->GetDocumentURI();
5518 // if the principal has a URI, use that to generate the origin
5519 nsContentUtils::GetUTFOrigin(callerOuterURI, origin);
5522 // Convert the provided origin string into a URI for comparison purposes.
5523 // "*" indicates no specific origin is required.
5524 nsCOMPtr<nsIURI> providedOrigin;
5525 if (!aOrigin.EqualsASCII("*")) {
5526 if (NS_FAILED(NS_NewURI(getter_AddRefs(providedOrigin), aOrigin)))
5527 return NS_ERROR_DOM_SYNTAX_ERR;
5528 if (NS_FAILED(providedOrigin->SetUserPass(EmptyCString())) ||
5529 NS_FAILED(providedOrigin->SetPath(EmptyCString())))
5530 return NS_OK;
5533 // Create and asynchronously dispatch a runnable which will handle actual DOM
5534 // event creation and dispatch.
5535 nsRefPtr<PostMessageEvent> event =
5536 new PostMessageEvent(nsContentUtils::IsCallerChrome()
5537 ? nsnull
5538 : callerInnerWin->GetOuterWindowInternal(),
5539 origin,
5540 aMessage,
5541 this,
5542 providedOrigin,
5543 nsContentUtils::IsCallerTrustedForWrite());
5544 return NS_DispatchToCurrentThread(event);
5547 class nsCloseEvent : public nsRunnable {
5549 nsRefPtr<nsGlobalWindow> mWindow;
5551 nsCloseEvent(nsGlobalWindow *aWindow)
5552 : mWindow(aWindow)
5555 public:
5557 static nsresult
5558 PostCloseEvent(nsGlobalWindow* aWindow) {
5559 nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow);
5560 nsresult rv = NS_DispatchToCurrentThread(ev);
5561 if (NS_SUCCEEDED(rv))
5562 aWindow->MaybeForgiveSpamCount();
5563 return rv;
5566 NS_IMETHOD Run() {
5567 if (mWindow)
5568 mWindow->ReallyCloseWindow();
5569 return NS_OK;
5574 PRBool
5575 nsGlobalWindow::CanClose()
5577 if (!mDocShell)
5578 return PR_TRUE;
5580 // Ask the content viewer whether the toplevel window can close.
5581 // If the content viewer returns false, it is responsible for calling
5582 // Close() as soon as it is possible for the window to close.
5583 // This allows us to not close the window while printing is happening.
5585 nsCOMPtr<nsIContentViewer> cv;
5586 mDocShell->GetContentViewer(getter_AddRefs(cv));
5587 if (cv) {
5588 PRBool canClose;
5589 nsresult rv = cv->PermitUnload(PR_FALSE, &canClose);
5590 if (NS_SUCCEEDED(rv) && !canClose)
5591 return PR_FALSE;
5593 rv = cv->RequestWindowClose(&canClose);
5594 if (NS_SUCCEEDED(rv) && !canClose)
5595 return PR_FALSE;
5598 return PR_TRUE;
5601 NS_IMETHODIMP
5602 nsGlobalWindow::Close()
5604 FORWARD_TO_OUTER(Close, (), NS_ERROR_NOT_INITIALIZED);
5606 if (IsFrame() || !mDocShell || IsInModalState()) {
5607 // window.close() is called on a frame in a frameset, on a window
5608 // that's already closed, or on a window for which there's
5609 // currently a modal dialog open. Ignore such calls.
5611 return NS_OK;
5614 if (mHavePendingClose) {
5615 // We're going to be closed anyway; do nothing since we don't want
5616 // to double-close
5617 return NS_OK;
5620 if (mBlockScriptedClosingFlag)
5622 // A script's popup has been blocked and we don't want
5623 // the window to be closed directly after this event,
5624 // so the user can see that there was a blocked popup.
5625 return NS_OK;
5628 // Don't allow scripts from content to close windows
5629 // that were not opened by script
5630 if (!mHadOriginalOpener && !nsContentUtils::IsCallerTrustedForWrite()) {
5631 PRBool allowClose =
5632 nsContentUtils::GetBoolPref("dom.allow_scripts_to_close_windows",
5633 PR_TRUE);
5634 if (!allowClose) {
5635 // We're blocking the close operation
5636 // report localized error msg in JS console
5637 nsContentUtils::ReportToConsole(
5638 nsContentUtils::eDOM_PROPERTIES,
5639 "WindowCloseBlockedWarning",
5640 nsnull, 0, // No params
5641 nsnull, // No URI. Not clear which URI we should be using
5642 // here anyway
5643 EmptyString(), 0, 0, // No source, or column/line number
5644 nsIScriptError::warningFlag,
5645 "DOM Window"); // Better name for the category?
5647 return NS_OK;
5651 if (!mInClose && !mIsClosed && !CanClose())
5652 return NS_OK;
5654 // Fire a DOM event notifying listeners that this window is about to
5655 // be closed. The tab UI code may choose to cancel the default
5656 // action for this event, if so, we won't actually close the window
5657 // (since the tab UI code will close the tab in stead). Sure, this
5658 // could be abused by content code, but do we care? I don't think
5659 // so...
5661 PRBool wasInClose = mInClose;
5662 mInClose = PR_TRUE;
5664 if (!DispatchCustomEvent("DOMWindowClose")) {
5665 // Someone chose to prevent the default action for this event, if
5666 // so, let's not close this window after all...
5668 mInClose = wasInClose;
5669 return NS_OK;
5672 return FinalClose();
5675 nsresult
5676 nsGlobalWindow::ForceClose()
5678 if (IsFrame() || !mDocShell) {
5679 // This may be a frame in a frameset, or a window that's already closed.
5680 // Ignore such calls.
5682 return NS_OK;
5685 if (mHavePendingClose) {
5686 // We're going to be closed anyway; do nothing since we don't want
5687 // to double-close
5688 return NS_OK;
5691 mInClose = PR_TRUE;
5693 DispatchCustomEvent("DOMWindowClose");
5695 return FinalClose();
5698 nsresult
5699 nsGlobalWindow::FinalClose()
5701 nsresult rv;
5702 // Flag that we were closed.
5703 mIsClosed = PR_TRUE;
5705 nsCOMPtr<nsIJSContextStack> stack =
5706 do_GetService(sJSStackContractID);
5708 JSContext *cx = nsnull;
5710 if (stack) {
5711 stack->Peek(&cx);
5714 if (cx) {
5715 nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
5717 if (currentCX && currentCX == GetContextInternal()) {
5718 // We ignore the return value here. If setting the termination function
5719 // fails, it's better to fail to close the window than it is to crash
5720 // (which is what would tend to happen if we did this synchronously
5721 // here).
5722 rv = currentCX->SetTerminationFunction(CloseWindow,
5723 static_cast<nsIDOMWindow *>
5724 (this));
5725 if (NS_SUCCEEDED(rv)) {
5726 mHavePendingClose = PR_TRUE;
5728 return NS_OK;
5733 // We may have plugins on the page that have issued this close from their
5734 // event loop and because we currently destroy the plugin window with
5735 // frames, we crash. So, if we are called from Javascript, post an event
5736 // to really close the window.
5737 rv = NS_ERROR_FAILURE;
5738 if (!nsContentUtils::IsCallerChrome()) {
5739 rv = nsCloseEvent::PostCloseEvent(this);
5742 if (NS_FAILED(rv)) {
5743 ReallyCloseWindow();
5744 rv = NS_OK;
5745 } else {
5746 mHavePendingClose = PR_TRUE;
5749 return rv;
5753 void
5754 nsGlobalWindow::ReallyCloseWindow()
5756 FORWARD_TO_OUTER_VOID(ReallyCloseWindow, ());
5758 // Make sure we never reenter this method.
5759 mHavePendingClose = PR_TRUE;
5761 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
5762 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
5764 // If there's no treeOwnerAsWin, this window must already be closed.
5766 if (treeOwnerAsWin) {
5768 // but if we're a browser window we could be in some nasty
5769 // self-destroying cascade that we should mostly ignore
5771 nsCOMPtr<nsIDocShellTreeItem> docItem(do_QueryInterface(mDocShell));
5772 if (docItem) {
5773 nsCOMPtr<nsIBrowserDOMWindow> bwin;
5774 nsCOMPtr<nsIDocShellTreeItem> rootItem;
5775 docItem->GetRootTreeItem(getter_AddRefs(rootItem));
5776 nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
5777 nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
5778 if (chromeWin)
5779 chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
5781 if (rootWin) {
5782 /* Normally we destroy the entire window, but not if
5783 this DOM window belongs to a tabbed browser and doesn't
5784 correspond to a tab. This allows a well-behaved tab
5785 to destroy the container as it should but is a final measure
5786 to prevent an errant tab from doing so when it shouldn't.
5787 This works because we reach this code when we shouldn't only
5788 in the particular circumstance that we belong to a tab
5789 that has just been closed (and is therefore already missing
5790 from the list of browsers) (and has an unload handler
5791 that closes the window). */
5792 // XXXbz now that we have mHavePendingClose, is this needed?
5793 PRBool isTab = PR_FALSE;
5794 if (rootWin == this ||
5795 !bwin || (bwin->IsTabContentWindow(GetOuterWindowInternal(),
5796 &isTab), isTab))
5797 treeOwnerAsWin->Destroy();
5801 CleanUp(PR_FALSE);
5805 void
5806 nsGlobalWindow::EnterModalState()
5808 nsCOMPtr<nsIDOMWindow> top;
5809 GetTop(getter_AddRefs(top));
5811 if (!top) {
5812 NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");
5814 return;
5817 nsGlobalWindow* topWin =
5818 static_cast<nsGlobalWindow*>(static_cast<nsIDOMWindow *>(top.get()));
5819 if (topWin->mModalStateDepth == 0) {
5820 NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
5822 mSuspendedDoc = do_QueryInterface(topWin->GetExtantDocument());
5823 if (mSuspendedDoc && mSuspendedDoc->EventHandlingSuppressed()) {
5824 mSuspendedDoc->SuppressEventHandling();
5825 } else {
5826 mSuspendedDoc = nsnull;
5829 topWin->mModalStateDepth++;
5831 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5833 nsIScriptContext *scx;
5834 if (cx && (scx = GetScriptContextFromJSContext(cx))) {
5835 scx->EnterModalState();
5839 // static
5840 void
5841 nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
5842 nsGlobalWindow *aWindow)
5844 nsGlobalWindow *inner;
5846 // Return early if we're frozen or have no inner window.
5847 if (!(inner = aWindow->GetCurrentInnerWindowInternal()) ||
5848 inner->IsFrozen()) {
5849 return;
5852 inner->RunTimeout(nsnull);
5854 // Check again if we're frozen since running pending timeouts
5855 // could've frozen us.
5856 if (inner->IsFrozen()) {
5857 return;
5860 nsCOMPtr<nsIDOMWindowCollection> frames;
5861 aWindow->GetFrames(getter_AddRefs(frames));
5863 if (!frames) {
5864 return;
5867 PRUint32 i, length;
5868 if (NS_FAILED(frames->GetLength(&length)) || !length) {
5869 return;
5872 for (i = 0; i < length && aTopWindow->mModalStateDepth == 0; i++) {
5873 nsCOMPtr<nsIDOMWindow> child;
5874 frames->Item(i, getter_AddRefs(child));
5876 if (!child) {
5877 return;
5880 nsGlobalWindow *childWin =
5881 static_cast<nsGlobalWindow *>
5882 (static_cast<nsIDOMWindow *>
5883 (child.get()));
5885 RunPendingTimeoutsRecursive(aTopWindow, childWin);
5889 class nsPendingTimeoutRunner : public nsRunnable
5891 public:
5892 nsPendingTimeoutRunner(nsGlobalWindow *aWindow)
5893 : mWindow(aWindow)
5895 NS_ASSERTION(mWindow, "mWindow is null.");
5898 NS_IMETHOD Run()
5900 nsGlobalWindow::RunPendingTimeoutsRecursive(mWindow, mWindow);
5902 return NS_OK;
5905 private:
5906 nsRefPtr<nsGlobalWindow> mWindow;
5909 void
5910 nsGlobalWindow::LeaveModalState()
5912 nsCOMPtr<nsIDOMWindow> top;
5913 GetTop(getter_AddRefs(top));
5915 if (!top) {
5916 NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
5918 return;
5921 nsGlobalWindow *topWin =
5922 static_cast<nsGlobalWindow *>
5923 (static_cast<nsIDOMWindow *>
5924 (top.get()));
5926 topWin->mModalStateDepth--;
5928 if (topWin->mModalStateDepth == 0) {
5929 nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
5930 if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
5931 NS_WARNING("failed to dispatch pending timeout runnable");
5933 if (mSuspendedDoc) {
5934 nsCOMPtr<nsIDocument> currentDoc =
5935 do_QueryInterface(topWin->GetExtantDocument());
5936 mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(currentDoc == mSuspendedDoc);
5937 mSuspendedDoc = nsnull;
5941 JSContext *cx = nsContentUtils::GetCurrentJSContext();
5943 nsIScriptContext *scx;
5944 if (cx && (scx = GetScriptContextFromJSContext(cx))) {
5945 scx->LeaveModalState();
5949 PRBool
5950 nsGlobalWindow::IsInModalState()
5952 nsCOMPtr<nsIDOMWindow> top;
5953 GetTop(getter_AddRefs(top));
5955 if (!top) {
5956 NS_ERROR("Uh, IsInModalState() called w/o a reachable top window?");
5958 return PR_FALSE;
5961 return static_cast<nsGlobalWindow *>
5962 (static_cast<nsIDOMWindow *>
5963 (top.get()))->mModalStateDepth != 0;
5966 // static
5967 void
5968 nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow) {
5969 nsCOMPtr<nsIObserverService> observerService =
5970 do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
5971 if (observerService) {
5972 observerService->
5973 NotifyObservers(static_cast<nsIScriptGlobalObject*>(aWindow),
5974 DOM_WINDOW_DESTROYED_TOPIC, nsnull);
5978 class WindowDestroyedEvent : public nsRunnable
5980 public:
5981 WindowDestroyedEvent(PRUint64 aID, const char* aTopic) :
5982 mID(aID), mTopic(aTopic) {}
5984 NS_IMETHOD Run()
5986 nsCOMPtr<nsIObserverService> observerService =
5987 do_GetService("@mozilla.org/observer-service;1");
5988 if (observerService) {
5989 nsCOMPtr<nsISupportsPRUint64> wrapper =
5990 do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
5991 if (wrapper) {
5992 wrapper->SetData(mID);
5993 observerService->NotifyObservers(wrapper, mTopic.get(), nsnull);
5996 return NS_OK;
5999 private:
6000 PRUint64 mID;
6001 nsCString mTopic;
6004 void
6005 nsGlobalWindow::NotifyWindowIDDestroyed(const char* aTopic)
6007 nsRefPtr<nsIRunnable> runnable = new WindowDestroyedEvent(mWindowID, aTopic);
6008 nsresult rv = NS_DispatchToCurrentThread(runnable);
6009 if (NS_SUCCEEDED(rv)) {
6010 mNotifiedIDDestroyed = PR_TRUE;
6014 void
6015 nsGlobalWindow::InitJavaProperties()
6017 nsIScriptContext *scx = GetContextInternal();
6019 if (mDidInitJavaProperties || IsOuterWindow() || !scx || !mJSObject) {
6020 return;
6023 // Set mDidInitJavaProperties to true here even if initialization
6024 // can fail. If it fails, we won't try again...
6025 mDidInitJavaProperties = PR_TRUE;
6027 // Check whether the plugin supports NPRuntime, if so, init through
6028 // it.
6030 nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
6031 if (!host) {
6032 return;
6035 mDummyJavaPluginOwner = new nsDummyJavaPluginOwner(mDoc);
6036 if (!mDummyJavaPluginOwner) {
6037 return;
6040 host->InstantiateDummyJavaPlugin(mDummyJavaPluginOwner);
6042 // It's possible for us (or the Java plugin, rather) to process
6043 // events during the above call, which can lead to this window being
6044 // torn down or what not, so re-check that the dummy plugin is still
6045 // around.
6046 if (!mDummyJavaPluginOwner) {
6047 return;
6050 nsCOMPtr<nsIPluginInstance> dummyPlugin;
6051 mDummyJavaPluginOwner->GetInstance(*getter_AddRefs(dummyPlugin));
6053 if (dummyPlugin) {
6054 // A dummy plugin was instantiated. This means we have a Java
6055 // plugin that supports NPRuntime. For such a plugin, the plugin
6056 // instantiation code defines the Java properties for us, so we're
6057 // done here.
6059 return;
6062 // No NPRuntime enabled Java plugin found, null out the owner we
6063 // would have used in that case as it's no longer needed.
6064 mDummyJavaPluginOwner = nsnull;
6067 void*
6068 nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
6070 void* handler = nsnull;
6071 if (mCachedXBLPrototypeHandlers.IsInitialized()) {
6072 mCachedXBLPrototypeHandlers.Get(aKey, &handler);
6074 return handler;
6077 void
6078 nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
6079 nsScriptObjectHolder& aHandler)
6081 if (!mCachedXBLPrototypeHandlers.IsInitialized() &&
6082 !mCachedXBLPrototypeHandlers.Init()) {
6083 NS_ERROR("Failed to initiailize hashtable!");
6084 return;
6087 if (!mCachedXBLPrototypeHandlers.Count()) {
6088 // Can't use macros to get the participant because nsGlobalChromeWindow also
6089 // runs through this code. Use QueryInterface to get the correct objects.
6090 nsXPCOMCycleCollectionParticipant* participant;
6091 CallQueryInterface(this, &participant);
6092 NS_ASSERTION(participant,
6093 "Failed to QI to nsXPCOMCycleCollectionParticipant!");
6095 nsCOMPtr<nsISupports> thisSupports;
6096 QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
6097 getter_AddRefs(thisSupports));
6098 NS_ASSERTION(thisSupports, "Failed to QI to nsCycleCollectionISupports!");
6100 nsresult rv = nsContentUtils::HoldJSObjects(thisSupports, participant);
6101 if (NS_FAILED(rv)) {
6102 NS_ERROR("nsContentUtils::HoldJSObjects failed!");
6103 return;
6107 mCachedXBLPrototypeHandlers.Put(aKey, aHandler);
6110 NS_IMETHODIMP
6111 nsGlobalWindow::GetFrameElement(nsIDOMElement** aFrameElement)
6113 FORWARD_TO_OUTER(GetFrameElement, (aFrameElement), NS_ERROR_NOT_INITIALIZED);
6115 *aFrameElement = nsnull;
6117 nsCOMPtr<nsIDocShellTreeItem> docShellTI(do_QueryInterface(mDocShell));
6119 if (!docShellTI) {
6120 return NS_OK;
6123 nsCOMPtr<nsIDocShellTreeItem> parent;
6124 docShellTI->GetSameTypeParent(getter_AddRefs(parent));
6126 if (!parent || parent == docShellTI) {
6127 // We're at a chrome boundary, don't expose the chrome iframe
6128 // element to content code.
6130 return NS_OK;
6133 *aFrameElement = mFrameElement;
6134 NS_IF_ADDREF(*aFrameElement);
6136 return NS_OK;
6139 // Helper for converting window.showModalDialog() options (list of ';'
6140 // separated name (:|=) value pairs) to a format that's parsable by
6141 // our normal window opening code.
6143 void
6144 ConvertDialogOptions(const nsAString& aOptions, nsAString& aResult)
6146 nsAString::const_iterator end;
6147 aOptions.EndReading(end);
6149 nsAString::const_iterator iter;
6150 aOptions.BeginReading(iter);
6152 while (iter != end) {
6153 // Skip whitespace.
6154 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6155 ++iter;
6158 nsAString::const_iterator name_start = iter;
6160 // Skip characters until we find whitespace, ';', ':', or '='
6161 while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
6162 *iter != ';' &&
6163 *iter != ':' &&
6164 *iter != '=') {
6165 ++iter;
6168 nsAString::const_iterator name_end = iter;
6170 // Skip whitespace.
6171 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6172 ++iter;
6175 if (*iter == ';') {
6176 // No value found, skip the ';' and keep going.
6177 ++iter;
6179 continue;
6182 nsAString::const_iterator value_start = iter;
6183 nsAString::const_iterator value_end = iter;
6185 if (*iter == ':' || *iter == '=') {
6186 // We found name followed by ':' or '='. Look for a value.
6188 iter++; // Skip the ':' or '='
6190 // Skip whitespace.
6191 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6192 ++iter;
6195 value_start = iter;
6197 // Skip until we find whitespace, or ';'.
6198 while (iter != end && !nsCRT::IsAsciiSpace(*iter) &&
6199 *iter != ';') {
6200 ++iter;
6203 value_end = iter;
6205 // Skip whitespace.
6206 while (nsCRT::IsAsciiSpace(*iter) && iter != end) {
6207 ++iter;
6211 const nsDependentSubstring& name = Substring(name_start, name_end);
6212 const nsDependentSubstring& value = Substring(value_start, value_end);
6214 if (name.LowerCaseEqualsLiteral("center")) {
6215 if (value.LowerCaseEqualsLiteral("on") ||
6216 value.LowerCaseEqualsLiteral("yes") ||
6217 value.LowerCaseEqualsLiteral("1")) {
6218 aResult.AppendLiteral(",centerscreen=1");
6220 } else if (name.LowerCaseEqualsLiteral("dialogwidth")) {
6221 if (!value.IsEmpty()) {
6222 aResult.AppendLiteral(",width=");
6223 aResult.Append(value);
6225 } else if (name.LowerCaseEqualsLiteral("dialogheight")) {
6226 if (!value.IsEmpty()) {
6227 aResult.AppendLiteral(",height=");
6228 aResult.Append(value);
6230 } else if (name.LowerCaseEqualsLiteral("dialogtop")) {
6231 if (!value.IsEmpty()) {
6232 aResult.AppendLiteral(",top=");
6233 aResult.Append(value);
6235 } else if (name.LowerCaseEqualsLiteral("dialogleft")) {
6236 if (!value.IsEmpty()) {
6237 aResult.AppendLiteral(",left=");
6238 aResult.Append(value);
6240 } else if (name.LowerCaseEqualsLiteral("resizable")) {
6241 if (value.LowerCaseEqualsLiteral("on") ||
6242 value.LowerCaseEqualsLiteral("yes") ||
6243 value.LowerCaseEqualsLiteral("1")) {
6244 aResult.AppendLiteral(",resizable=1");
6246 } else if (name.LowerCaseEqualsLiteral("scroll")) {
6247 if (value.LowerCaseEqualsLiteral("off") ||
6248 value.LowerCaseEqualsLiteral("no") ||
6249 value.LowerCaseEqualsLiteral("0")) {
6250 aResult.AppendLiteral(",scrollbars=0");
6254 if (iter == end) {
6255 break;
6258 iter++;
6262 NS_IMETHODIMP
6263 nsGlobalWindow::ShowModalDialog(const nsAString& aURI, nsIVariant *aArgs,
6264 const nsAString& aOptions,
6265 nsIVariant **aRetVal)
6267 *aRetVal = nsnull;
6269 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
6271 nsCOMPtr<nsIDOMWindow> dlgWin;
6272 nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
6274 ConvertDialogOptions(aOptions, options);
6276 options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");
6278 // Before bringing up the window, unsuppress painting and flush
6279 // pending reflows.
6280 EnsureReflowFlushAndPaint();
6282 nsresult rv = OpenInternal(aURI, EmptyString(), options,
6283 PR_FALSE, // aDialog
6284 PR_TRUE, // aContentModal
6285 PR_TRUE, // aCalledNoScript
6286 PR_TRUE, // aDoJSFixups
6287 nsnull, aArgs, // args
6288 GetPrincipal(), // aCalleePrincipal
6289 nsnull, // aJSCallerContext
6290 getter_AddRefs(dlgWin));
6292 NS_ENSURE_SUCCESS(rv, rv);
6294 if (dlgWin) {
6295 nsCOMPtr<nsIPrincipal> subjectPrincipal;
6296 rv = nsContentUtils::GetSecurityManager()->
6297 GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
6298 if (NS_FAILED(rv)) {
6299 return rv;
6302 PRBool canAccess = PR_TRUE;
6304 if (subjectPrincipal) {
6305 nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
6306 do_QueryInterface(dlgWin);
6307 nsCOMPtr<nsIPrincipal> dialogPrincipal;
6309 if (objPrincipal) {
6310 dialogPrincipal = objPrincipal->GetPrincipal();
6312 rv = subjectPrincipal->Subsumes(dialogPrincipal, &canAccess);
6313 NS_ENSURE_SUCCESS(rv, rv);
6314 } else {
6315 // Uh, not sure what kind of dialog this is. Prevent access to
6316 // be on the safe side...
6318 canAccess = PR_FALSE;
6322 nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(dlgWin));
6324 if (canAccess) {
6325 nsPIDOMWindow *inner = win->GetCurrentInnerWindow();
6327 nsCOMPtr<nsIDOMModalContentWindow> dlgInner(do_QueryInterface(inner));
6329 if (dlgInner) {
6330 dlgInner->GetReturnValue(aRetVal);
6334 nsRefPtr<nsGlobalWindow> winInternal =
6335 static_cast<nsGlobalWindow*>(win.get());
6336 if (winInternal->mCallCleanUpAfterModalDialogCloses) {
6337 winInternal->mCallCleanUpAfterModalDialogCloses = PR_FALSE;
6338 winInternal->CleanUp(PR_TRUE);
6342 return NS_OK;
6345 class CommandDispatcher : public nsRunnable
6347 public:
6348 CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher,
6349 const nsAString& aAction)
6350 : mDispatcher(aDispatcher), mAction(aAction) {}
6352 NS_IMETHOD Run()
6354 return mDispatcher->UpdateCommands(mAction);
6357 nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
6358 nsString mAction;
6361 NS_IMETHODIMP
6362 nsGlobalWindow::UpdateCommands(const nsAString& anAction)
6364 nsPIDOMWindow *rootWindow = nsGlobalWindow::GetPrivateRoot();
6365 if (!rootWindow)
6366 return NS_OK;
6368 nsCOMPtr<nsIDOMXULDocument> xulDoc =
6369 do_QueryInterface(rootWindow->GetExtantDocument());
6370 // See if we contain a XUL document.
6371 if (xulDoc) {
6372 // Retrieve the command dispatcher and call updateCommands on it.
6373 nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
6374 xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
6375 if (xulCommandDispatcher) {
6376 nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
6377 anAction));
6381 return NS_OK;
6384 PRBool
6385 nsGlobalWindow::GetBlurSuppression()
6387 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
6388 GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
6389 PRBool suppress = PR_FALSE;
6390 if (treeOwnerAsWin)
6391 treeOwnerAsWin->GetBlurSuppression(&suppress);
6392 return suppress;
6395 NS_IMETHODIMP
6396 nsGlobalWindow::GetSelection(nsISelection** aSelection)
6398 FORWARD_TO_OUTER(GetSelection, (aSelection), NS_ERROR_NOT_INITIALIZED);
6400 NS_ENSURE_ARG_POINTER(aSelection);
6401 *aSelection = nsnull;
6403 if (!mDocShell)
6404 return NS_OK;
6406 nsCOMPtr<nsIPresShell> presShell;
6407 mDocShell->GetPresShell(getter_AddRefs(presShell));
6409 if (!presShell)
6410 return NS_OK;
6412 *aSelection = presShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
6414 NS_IF_ADDREF(*aSelection);
6416 return NS_OK;
6419 NS_IMETHODIMP
6420 nsGlobalWindow::Find(const nsAString& aStr, PRBool aCaseSensitive,
6421 PRBool aBackwards, PRBool aWrapAround, PRBool aWholeWord,
6422 PRBool aSearchInFrames, PRBool aShowDialog,
6423 PRBool *aDidFind)
6425 FORWARD_TO_OUTER(Find, (aStr, aCaseSensitive, aBackwards, aWrapAround,
6426 aWholeWord, aSearchInFrames, aShowDialog, aDidFind),
6427 NS_ERROR_NOT_INITIALIZED);
6429 nsresult rv = NS_OK;
6430 *aDidFind = PR_FALSE;
6432 nsCOMPtr<nsIWebBrowserFind> finder(do_GetInterface(mDocShell));
6433 NS_ENSURE_TRUE(finder, NS_ERROR_FAILURE);
6435 // Set the options of the search
6436 rv = finder->SetSearchString(PromiseFlatString(aStr).get());
6437 NS_ENSURE_SUCCESS(rv, rv);
6438 finder->SetMatchCase(aCaseSensitive);
6439 finder->SetFindBackwards(aBackwards);
6440 finder->SetWrapFind(aWrapAround);
6441 finder->SetEntireWord(aWholeWord);
6442 finder->SetSearchFrames(aSearchInFrames);
6444 // the nsIWebBrowserFind is initialized to use this window
6445 // as the search root, but uses focus to set the current search
6446 // frame. If we're being called from JS (as here), this window
6447 // should be the current search frame.
6448 nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
6449 if (framesFinder) {
6450 framesFinder->SetRootSearchFrame(this); // paranoia
6451 framesFinder->SetCurrentSearchFrame(this);
6454 // The Find API does not accept empty strings. Launch the Find Dialog.
6455 if (aStr.IsEmpty() || aShowDialog) {
6456 // See if the find dialog is already up using nsIWindowMediator
6457 nsCOMPtr<nsIWindowMediator> windowMediator =
6458 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
6460 nsCOMPtr<nsIDOMWindowInternal> findDialog;
6462 if (windowMediator) {
6463 windowMediator->GetMostRecentWindow(NS_LITERAL_STRING("findInPage").get(),
6464 getter_AddRefs(findDialog));
6467 if (findDialog) {
6468 // The Find dialog is already open, bring it to the top.
6469 rv = findDialog->Focus();
6470 } else { // Open a Find dialog
6471 if (finder) {
6472 nsCOMPtr<nsIDOMWindow> dialog;
6473 rv = OpenDialog(NS_LITERAL_STRING("chrome://global/content/finddialog.xul"),
6474 NS_LITERAL_STRING("_blank"),
6475 NS_LITERAL_STRING("chrome, resizable=no, dependent=yes"),
6476 finder, getter_AddRefs(dialog));
6479 } else {
6480 // Launch the search with the passed in search string
6481 rv = finder->FindNext(aDidFind);
6482 NS_ENSURE_SUCCESS(rv, rv);
6485 return rv;
6488 static PRBool
6489 Is8bit(const nsAString& aString)
6491 static const PRUnichar EIGHT_BIT = PRUnichar(~0x00FF);
6493 nsAString::const_iterator done_reading;
6494 aString.EndReading(done_reading);
6496 // for each chunk of |aString|...
6497 PRUint32 fragmentLength = 0;
6498 nsAString::const_iterator iter;
6499 for (aString.BeginReading(iter); iter != done_reading;
6500 iter.advance(PRInt32(fragmentLength))) {
6501 fragmentLength = PRUint32(iter.size_forward());
6502 const PRUnichar* c = iter.get();
6503 const PRUnichar* fragmentEnd = c + fragmentLength;
6505 // for each character in this chunk...
6506 while (c < fragmentEnd)
6507 if (*c++ & EIGHT_BIT)
6508 return PR_FALSE;
6511 return PR_TRUE;
6514 NS_IMETHODIMP
6515 nsGlobalWindow::Atob(const nsAString& aAsciiBase64String,
6516 nsAString& aBinaryData)
6518 aBinaryData.Truncate();
6520 if (!Is8bit(aAsciiBase64String)) {
6521 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
6524 PRUint32 dataLen = aAsciiBase64String.Length();
6526 NS_LossyConvertUTF16toASCII base64(aAsciiBase64String);
6527 if (base64.Length() != dataLen) {
6528 return NS_ERROR_OUT_OF_MEMORY;
6531 PRInt32 resultLen = dataLen;
6532 if (!base64.IsEmpty() && base64[dataLen - 1] == '=') {
6533 if (base64.Length() > 1 && base64[dataLen - 2] == '=') {
6534 resultLen = dataLen - 2;
6535 } else {
6536 resultLen = dataLen - 1;
6540 resultLen = ((resultLen * 3) / 4);
6541 // Add 4 extra bytes (one is needed for sure for null termination)
6542 // to the malloc size just to make sure we don't end up writing past
6543 // the allocated memory (the PL_Base64Decode API should really
6544 // provide a guaranteed way to figure this out w/o needing to do the
6545 // above yourself).
6546 char *dest = static_cast<char *>(nsMemory::Alloc(resultLen + 4));
6547 if (!dest) {
6548 return NS_ERROR_OUT_OF_MEMORY;
6551 char *bin_data = PL_Base64Decode(base64.get(), dataLen, dest);
6553 nsresult rv = NS_OK;
6555 if (bin_data) {
6556 CopyASCIItoUTF16(Substring(bin_data, bin_data + resultLen), aBinaryData);
6557 } else {
6558 rv = NS_ERROR_DOM_INVALID_CHARACTER_ERR;
6561 nsMemory::Free(dest);
6563 return rv;
6566 NS_IMETHODIMP
6567 nsGlobalWindow::Btoa(const nsAString& aBinaryData,
6568 nsAString& aAsciiBase64String)
6570 aAsciiBase64String.Truncate();
6572 if (!Is8bit(aBinaryData)) {
6573 return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
6576 char *bin_data = ToNewCString(aBinaryData);
6577 if (!bin_data) {
6578 return NS_ERROR_OUT_OF_MEMORY;
6581 PRInt32 resultLen = ((aBinaryData.Length() + 2) / 3) * 4;
6583 char *base64 = PL_Base64Encode(bin_data, aBinaryData.Length(), nsnull);
6584 if (!base64) {
6585 nsMemory::Free(bin_data);
6587 return NS_ERROR_OUT_OF_MEMORY;
6590 CopyASCIItoUTF16(nsDependentCString(base64, resultLen), aAsciiBase64String);
6592 PR_Free(base64);
6593 nsMemory::Free(bin_data);
6595 return NS_OK;
6598 //*****************************************************************************
6599 // nsGlobalWindow::nsIDOMEventTarget
6600 //*****************************************************************************
6602 NS_IMETHODIMP
6603 nsGlobalWindow::AddEventListener(const nsAString& aType,
6604 nsIDOMEventListener* aListener,
6605 PRBool aUseCapture)
6607 FORWARD_TO_INNER_CREATE(AddEventListener, (aType, aListener, aUseCapture),
6608 NS_ERROR_NOT_AVAILABLE);
6610 return AddEventListener(aType, aListener, aUseCapture, PR_FALSE, 0);
6613 NS_IMETHODIMP
6614 nsGlobalWindow::RemoveEventListener(const nsAString& aType,
6615 nsIDOMEventListener* aListener,
6616 PRBool aUseCapture)
6618 return RemoveGroupedEventListener(aType, aListener, aUseCapture, nsnull);
6621 NS_IMETHODIMP
6622 nsGlobalWindow::DispatchEvent(nsIDOMEvent* aEvent, PRBool* _retval)
6624 FORWARD_TO_INNER(DispatchEvent, (aEvent, _retval), NS_OK);
6626 if (!mDoc) {
6627 return NS_ERROR_FAILURE;
6630 // Obtain a presentation shell
6631 nsIPresShell *shell = mDoc->GetShell();
6632 nsRefPtr<nsPresContext> presContext;
6633 if (shell) {
6634 // Retrieve the context
6635 presContext = shell->GetPresContext();
6638 nsEventStatus status = nsEventStatus_eIgnore;
6639 nsresult rv =
6640 nsEventDispatcher::DispatchDOMEvent(GetOuterWindow(), nsnull, aEvent,
6641 presContext, &status);
6643 *_retval = (status != nsEventStatus_eConsumeNoDefault);
6644 return rv;
6647 //*****************************************************************************
6648 // nsGlobalWindow::nsIDOM3EventTarget
6649 //*****************************************************************************
6651 NS_IMETHODIMP
6652 nsGlobalWindow::AddGroupedEventListener(const nsAString & aType,
6653 nsIDOMEventListener *aListener,
6654 PRBool aUseCapture,
6655 nsIDOMEventGroup *aEvtGrp)
6657 FORWARD_TO_INNER_CREATE(AddGroupedEventListener,
6658 (aType, aListener, aUseCapture, aEvtGrp),
6659 NS_ERROR_NOT_AVAILABLE);
6661 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
6662 NS_ENSURE_STATE(manager);
6663 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
6664 return manager->AddEventListenerByType(aListener, aType, flags, aEvtGrp);
6667 NS_IMETHODIMP
6668 nsGlobalWindow::RemoveGroupedEventListener(const nsAString & aType,
6669 nsIDOMEventListener *aListener,
6670 PRBool aUseCapture,
6671 nsIDOMEventGroup *aEvtGrp)
6673 FORWARD_TO_INNER(RemoveGroupedEventListener,
6674 (aType, aListener, aUseCapture, aEvtGrp),
6675 NS_ERROR_NOT_INITIALIZED);
6677 if (mListenerManager) {
6678 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
6680 mListenerManager->RemoveEventListenerByType(aListener, aType, flags,
6681 aEvtGrp);
6683 return NS_OK;
6686 NS_IMETHODIMP
6687 nsGlobalWindow::CanTrigger(const nsAString & type, PRBool *_retval)
6689 return NS_ERROR_NOT_IMPLEMENTED;
6692 NS_IMETHODIMP
6693 nsGlobalWindow::IsRegisteredHere(const nsAString & type, PRBool *_retval)
6695 return NS_ERROR_NOT_IMPLEMENTED;
6698 NS_IMETHODIMP
6699 nsGlobalWindow::AddEventListener(const nsAString& aType,
6700 nsIDOMEventListener *aListener,
6701 PRBool aUseCapture, PRBool aWantsUntrusted,
6702 PRUint8 optional_argc)
6704 NS_ASSERTION(!aWantsUntrusted || optional_argc > 0,
6705 "Won't check if this is chrome, you want to set "
6706 "aWantsUntrusted to PR_FALSE or make the aWantsUntrusted "
6707 "explicit by making optional_argc non-zero.");
6709 if (IsOuterWindow() && mInnerWindow &&
6710 !nsContentUtils::CanCallerAccess(mInnerWindow)) {
6711 return NS_ERROR_DOM_SECURITY_ERR;
6714 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
6715 NS_ENSURE_STATE(manager);
6717 PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
6719 if (aWantsUntrusted ||
6720 (optional_argc == 0 && !nsContentUtils::IsChromeDoc(mDoc))) {
6721 flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
6724 return manager->AddEventListenerByType(aListener, aType, flags, nsnull);
6727 nsresult
6728 nsGlobalWindow::AddEventListenerByIID(nsIDOMEventListener* aListener,
6729 const nsIID& aIID)
6731 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
6732 NS_ENSURE_STATE(manager);
6733 return manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
6736 nsresult
6737 nsGlobalWindow::RemoveEventListenerByIID(nsIDOMEventListener* aListener,
6738 const nsIID& aIID)
6740 FORWARD_TO_INNER(RemoveEventListenerByIID, (aListener, aIID),
6741 NS_ERROR_NOT_INITIALIZED);
6743 if (mListenerManager) {
6744 mListenerManager->RemoveEventListenerByIID(aListener, aIID,
6745 NS_EVENT_FLAG_BUBBLE);
6746 return NS_OK;
6748 return NS_ERROR_FAILURE;
6751 nsIEventListenerManager*
6752 nsGlobalWindow::GetListenerManager(PRBool aCreateIfNotFound)
6754 FORWARD_TO_INNER_CREATE(GetListenerManager, (aCreateIfNotFound), nsnull);
6756 if (!mListenerManager) {
6757 if (!aCreateIfNotFound) {
6758 return nsnull;
6761 static NS_DEFINE_CID(kEventListenerManagerCID,
6762 NS_EVENTLISTENERMANAGER_CID);
6764 mListenerManager = do_CreateInstance(kEventListenerManagerCID);
6765 if (mListenerManager) {
6766 mListenerManager->SetListenerTarget(
6767 static_cast<nsPIDOMEventTarget*>(this));
6771 return mListenerManager;
6774 nsresult
6775 nsGlobalWindow::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
6777 nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
6778 NS_ENSURE_STATE(manager);
6779 return manager->GetSystemEventGroupLM(aGroup);
6782 nsIScriptContext*
6783 nsGlobalWindow::GetContextForEventHandlers(nsresult* aRv)
6785 nsIScriptContext* scx = GetContext();
6786 *aRv = scx ? NS_OK : NS_ERROR_UNEXPECTED;
6787 return scx;
6790 //*****************************************************************************
6791 // nsGlobalWindow::nsPIDOMWindow
6792 //*****************************************************************************
6794 nsPIDOMWindow*
6795 nsGlobalWindow::GetPrivateParent()
6797 FORWARD_TO_OUTER(GetPrivateParent, (), nsnull);
6799 nsCOMPtr<nsIDOMWindow> parent;
6800 GetParent(getter_AddRefs(parent));
6802 if (static_cast<nsIDOMWindow *>(this) == parent.get()) {
6803 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6804 if (!chromeElement)
6805 return nsnull; // This is ok, just means a null parent.
6807 nsIDocument* doc = chromeElement->GetDocument();
6808 if (!doc)
6809 return nsnull; // This is ok, just means a null parent.
6811 nsIScriptGlobalObject *globalObject = doc->GetScriptGlobalObject();
6812 if (!globalObject)
6813 return nsnull; // This is ok, just means a null parent.
6815 parent = do_QueryInterface(globalObject);
6818 if (parent) {
6819 return static_cast<nsGlobalWindow *>
6820 (static_cast<nsIDOMWindow*>(parent.get()));
6823 return nsnull;
6826 nsPIDOMWindow*
6827 nsGlobalWindow::GetPrivateRoot()
6829 FORWARD_TO_OUTER(GetPrivateRoot, (), nsnull);
6831 nsCOMPtr<nsIDOMWindow> top;
6832 GetTop(getter_AddRefs(top));
6834 nsCOMPtr<nsPIDOMWindow> ptop = do_QueryInterface(top);
6835 NS_ASSERTION(ptop, "cannot get ptop");
6836 if (!ptop)
6837 return nsnull;
6839 nsIDocShell *docShell = ptop->GetDocShell();
6841 // Get the chrome event handler from the doc shell, since we only
6842 // want to deal with XUL chrome handlers and not the new kind of
6843 // window root handler.
6844 nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
6845 docShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
6847 nsCOMPtr<nsIContent> chromeElement(do_QueryInterface(mChromeEventHandler));
6848 if (chromeElement) {
6849 nsIDocument* doc = chromeElement->GetDocument();
6850 if (doc) {
6851 nsIDOMWindow *parent = doc->GetWindow();
6852 if (parent) {
6853 parent->GetTop(getter_AddRefs(top));
6858 return static_cast<nsGlobalWindow *>
6859 (static_cast<nsIDOMWindow *>(top));
6863 NS_IMETHODIMP
6864 nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
6866 FORWARD_TO_INNER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED);
6868 *aLocation = nsnull;
6870 nsIDocShell *docShell = GetDocShell();
6871 if (!mLocation && docShell) {
6872 mLocation = new nsLocation(docShell);
6873 if (!mLocation) {
6874 return NS_ERROR_OUT_OF_MEMORY;
6878 NS_IF_ADDREF(*aLocation = mLocation);
6880 return NS_OK;
6883 void
6884 nsGlobalWindow::ActivateOrDeactivate(PRBool aActivate)
6886 // Set / unset mIsActive on the top level window, which is used for the
6887 // :-moz-window-inactive pseudoclass.
6888 nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
6889 if (!mainWidget)
6890 return;
6892 // Get the top level widget (if the main widget is a sheet, this will
6893 // be the sheet's top (non-sheet) parent).
6894 nsCOMPtr<nsIWidget> topLevelWidget = mainWidget->GetSheetWindowParent();
6895 if (!topLevelWidget) {
6896 topLevelWidget = mainWidget;
6899 // Get the top level widget's nsGlobalWindow
6900 nsCOMPtr<nsIDOMWindowInternal> topLevelWindow;
6901 if (topLevelWidget == mainWidget) {
6902 topLevelWindow = static_cast<nsIDOMWindowInternal*>(this);
6903 } else {
6904 // This is a workaround for the following problem:
6905 // When a window with an open sheet loses focus, only the sheet window
6906 // receives the NS_DEACTIVATE event. However, it's not the sheet that
6907 // should lose the active styling, but the containing top level window.
6908 void* clientData;
6909 topLevelWidget->GetClientData(clientData); // clientData is nsXULWindow
6910 nsISupports* data = static_cast<nsISupports*>(clientData);
6911 nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(data));
6912 topLevelWindow = do_GetInterface(req);
6914 if (topLevelWindow) {
6915 nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(topLevelWindow));
6916 piWin->SetActive(aActivate);
6920 static PRBool
6921 NotifyDocumentTree(nsIDocument* aDocument, void* aData)
6923 aDocument->EnumerateSubDocuments(NotifyDocumentTree, nsnull);
6924 aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
6925 return PR_TRUE;
6928 void
6929 nsGlobalWindow::SetActive(PRBool aActive)
6931 nsPIDOMWindow::SetActive(aActive);
6932 NotifyDocumentTree(mDoc, nsnull);
6935 void nsGlobalWindow::MaybeUpdateTouchState()
6937 FORWARD_TO_INNER_VOID(MaybeUpdateTouchState, ());
6939 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
6941 nsCOMPtr<nsIDOMWindow> focusedWindow;
6942 fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
6944 if(this == focusedWindow) {
6945 UpdateTouchState();
6949 void nsGlobalWindow::UpdateTouchState()
6951 FORWARD_TO_INNER_VOID(UpdateTouchState, ());
6953 nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
6954 if (!mainWidget)
6955 return;
6957 if (mMayHaveTouchEventListener) {
6958 mainWidget->RegisterTouchWindow();
6959 } else {
6960 mainWidget->UnregisterTouchWindow();
6964 void
6965 nsGlobalWindow::SetChromeEventHandler(nsPIDOMEventTarget* aChromeEventHandler)
6967 SetChromeEventHandlerInternal(aChromeEventHandler);
6968 if (IsOuterWindow()) {
6969 // update the chrome event handler on all our inner windows
6970 for (nsGlobalWindow *inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
6971 inner != this;
6972 inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
6973 NS_ASSERTION(inner->mOuterWindow == this, "bad outer window pointer");
6974 inner->SetChromeEventHandlerInternal(aChromeEventHandler);
6976 } else if (mOuterWindow) {
6977 // Need the cast to be able to call the protected method on a
6978 // superclass. We could make the method public instead, but it's really
6979 // better this way.
6980 static_cast<nsGlobalWindow*>(mOuterWindow)->
6981 SetChromeEventHandlerInternal(aChromeEventHandler);
6985 static PRBool IsLink(nsIContent* aContent)
6987 nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aContent);
6988 return (anchor || (aContent &&
6989 aContent->AttrValueIs(kNameSpaceID_XLink, nsGkAtoms::type,
6990 nsGkAtoms::simple, eCaseMatters)));
6993 void
6994 nsGlobalWindow::SetFocusedNode(nsIContent* aNode,
6995 PRUint32 aFocusMethod,
6996 PRBool aNeedsFocus)
6998 FORWARD_TO_INNER_VOID(SetFocusedNode, (aNode, aFocusMethod, aNeedsFocus));
7000 NS_ASSERTION(!aNode || aNode->GetCurrentDoc() == mDoc,
7001 "setting focus to a node from the wrong document");
7003 if (mFocusedNode != aNode) {
7004 UpdateCanvasFocus(PR_FALSE, aNode);
7005 mFocusedNode = aNode;
7006 mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
7007 mShowFocusRingForContent = PR_FALSE;
7010 if (mFocusedNode) {
7011 // if a node was focused by a keypress, turn on focus rings for the
7012 // window.
7013 if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) {
7014 mFocusByKeyOccurred = PR_TRUE;
7015 } else if (
7016 // otherwise, we set mShowFocusRingForContent, as we don't want this to
7017 // be permanent for the window. On Windows, focus rings are only shown
7018 // when the FLAG_SHOWRING flag is used. On other platforms, focus rings
7019 // are only hidden for clicks on links.
7020 #ifndef XP_WIN
7021 !(mFocusMethod & nsIFocusManager::FLAG_BYMOUSE) || !IsLink(aNode) ||
7022 #endif
7023 aFocusMethod & nsIFocusManager::FLAG_SHOWRING) {
7024 mShowFocusRingForContent = PR_TRUE;
7028 if (aNeedsFocus)
7029 mNeedsFocus = aNeedsFocus;
7032 PRUint32
7033 nsGlobalWindow::GetFocusMethod()
7035 FORWARD_TO_INNER(GetFocusMethod, (), 0);
7037 return mFocusMethod;
7040 PRBool
7041 nsGlobalWindow::ShouldShowFocusRing()
7043 FORWARD_TO_INNER(ShouldShowFocusRing, (), PR_FALSE);
7045 return mShowFocusRings || mShowFocusRingForContent || mFocusByKeyOccurred;
7048 void
7049 nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
7050 UIStateChangeType aShowFocusRings)
7052 FORWARD_TO_INNER_VOID(SetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
7054 // only change the flags that have been modified
7055 if (aShowAccelerators != UIStateChangeType_NoChange)
7056 mShowAccelerators = aShowAccelerators == UIStateChangeType_Set;
7057 if (aShowFocusRings != UIStateChangeType_NoChange)
7058 mShowFocusRings = aShowFocusRings == UIStateChangeType_Set;
7060 // propagate the indicators to child windows
7061 nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(GetDocShell());
7062 if (node) {
7063 PRInt32 childCount = 0;
7064 node->GetChildCount(&childCount);
7066 for (PRInt32 i = 0; i < childCount; ++i) {
7067 nsCOMPtr<nsIDocShellTreeItem> childShell;
7068 node->GetChildAt(i, getter_AddRefs(childShell));
7069 nsCOMPtr<nsPIDOMWindow> childWindow = do_GetInterface(childShell);
7070 if (childWindow) {
7071 childWindow->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
7076 if (mHasFocus) {
7077 // send content state notifications
7078 nsCOMPtr<nsPresContext> presContext;
7079 if (mDocShell) {
7080 mDocShell->GetPresContext(getter_AddRefs(presContext));
7081 if (presContext) {
7082 presContext->EventStateManager()->
7083 SetContentState(mFocusedNode, NS_EVENT_STATE_FOCUS);
7089 void
7090 nsGlobalWindow::GetKeyboardIndicators(PRBool* aShowAccelerators,
7091 PRBool* aShowFocusRings)
7093 FORWARD_TO_INNER_VOID(GetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
7095 *aShowAccelerators = mShowAccelerators;
7096 *aShowFocusRings = mShowFocusRings;
7099 PRBool
7100 nsGlobalWindow::TakeFocus(PRBool aFocus, PRUint32 aFocusMethod)
7102 FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), PR_FALSE);
7104 if (aFocus)
7105 mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
7107 if (mHasFocus != aFocus) {
7108 mHasFocus = aFocus;
7109 UpdateCanvasFocus(PR_TRUE, mFocusedNode);
7112 // if mNeedsFocus is true, then the document has not yet received a
7113 // document-level focus event. If there is a root content node, then return
7114 // true to tell the calling focus manager that a focus event is expected. If
7115 // there is no root content node, the document hasn't loaded enough yet, or
7116 // there isn't one and there is no point in firing a focus event.
7117 if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement() != nsnull) {
7118 mNeedsFocus = PR_FALSE;
7119 return PR_TRUE;
7122 mNeedsFocus = PR_FALSE;
7123 return PR_FALSE;
7126 void
7127 nsGlobalWindow::SetReadyForFocus()
7129 FORWARD_TO_INNER_VOID(SetReadyForFocus, ());
7131 PRBool oldNeedsFocus = mNeedsFocus;
7132 mNeedsFocus = PR_FALSE;
7134 // update whether focus rings need to be shown using the state from the
7135 // root window
7136 nsPIDOMWindow* root = GetPrivateRoot();
7137 if (root) {
7138 PRBool showAccelerators, showFocusRings;
7139 root->GetKeyboardIndicators(&showAccelerators, &showFocusRings);
7140 mShowFocusRings = showFocusRings;
7143 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7144 if (fm)
7145 fm->WindowShown(this, oldNeedsFocus);
7148 void
7149 nsGlobalWindow::PageHidden()
7151 FORWARD_TO_INNER_VOID(PageHidden, ());
7153 // the window is being hidden, so tell the focus manager that the frame is
7154 // no longer valid. Use the persisted field to determine if the document
7155 // is being destroyed.
7157 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7158 if (fm)
7159 fm->WindowHidden(this);
7161 mNeedsFocus = PR_TRUE;
7164 nsresult
7165 nsGlobalWindow::DispatchSyncHashchange()
7167 FORWARD_TO_INNER(DispatchSyncHashchange, (), NS_OK);
7168 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
7169 "Must be safe to run script here.");
7171 // Don't do anything if the window is frozen.
7172 if (IsFrozen())
7173 return NS_OK;
7175 // Dispatch the hashchange event, which doesn't bubble and isn't cancelable,
7176 // to the outer window.
7177 return nsContentUtils::DispatchTrustedEvent(mDoc, GetOuterWindow(),
7178 NS_LITERAL_STRING("hashchange"),
7179 PR_FALSE, PR_FALSE);
7182 nsresult
7183 nsGlobalWindow::DispatchSyncPopState()
7185 FORWARD_TO_INNER(DispatchSyncPopState, (), NS_OK);
7187 NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
7188 "Must be safe to run script here.");
7190 // Check that PopState hasn't been pref'ed off.
7191 if (!nsContentUtils::GetBoolPref(sPopStatePrefStr, PR_FALSE))
7192 return NS_OK;
7194 nsresult rv = NS_OK;
7196 // Bail if the window is frozen.
7197 if (IsFrozen()) {
7198 return NS_OK;
7201 // Bail if there's no document or the document's readystate isn't "complete".
7202 if (!mDoc) {
7203 return NS_OK;
7206 nsIDocument::ReadyState readyState = mDoc->GetReadyStateEnum();
7207 if (readyState != nsIDocument::READYSTATE_COMPLETE) {
7208 return NS_OK;
7211 // Get the document's pending state object -- it contains the data we're
7212 // going to send along with the popstate event. The object is serialized as
7213 // JSON.
7214 nsAString& stateObjJSON = mDoc->GetPendingStateObject();
7216 nsCOMPtr<nsIVariant> stateObj;
7217 // Parse the JSON, if there's any to parse.
7218 if (!stateObjJSON.IsEmpty()) {
7219 // Get the JSContext associated with our document. We need this for
7220 // deserialization.
7221 nsCOMPtr<nsIDocument> document = do_QueryInterface(mDocument);
7222 NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
7224 // Get the JSContext from the document, like we do in
7225 // nsContentUtils::GetContextFromDocument().
7226 nsIScriptGlobalObject *sgo = document->GetScopeObject();
7227 NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
7229 nsIScriptContext *scx = sgo->GetContext();
7230 NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
7232 JSContext *cx = (JSContext*) scx->GetNativeContext();
7234 // If our json call triggers a JS-to-C++ call, we want that call to use cx
7235 // as the context. So we push cx onto the context stack.
7236 nsCxPusher cxPusher;
7238 jsval jsStateObj = JSVAL_NULL;
7239 // Root the container which will hold our decoded state object.
7240 nsAutoGCRoot root(&jsStateObj, &rv);
7241 NS_ENSURE_SUCCESS(rv, rv);
7243 // Deserialize the state object into an nsIVariant.
7244 nsCOMPtr<nsIJSON> json = do_GetService("@mozilla.org/dom/json;1");
7245 NS_ENSURE_TRUE(cxPusher.Push(cx), NS_ERROR_FAILURE);
7246 rv = json->DecodeToJSVal(stateObjJSON, cx, &jsStateObj);
7247 NS_ENSURE_SUCCESS(rv, rv);
7248 cxPusher.Pop();
7250 nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID());
7251 NS_ENSURE_TRUE(xpconnect, NS_ERROR_FAILURE);
7252 rv = xpconnect->JSValToVariant(cx, &jsStateObj, getter_AddRefs(stateObj));
7253 NS_ENSURE_SUCCESS(rv, rv);
7256 // Obtain a presentation shell for use in creating a popstate event.
7257 nsIPresShell *shell = mDoc->GetShell();
7258 nsRefPtr<nsPresContext> presContext;
7259 if (shell) {
7260 presContext = shell->GetPresContext();
7263 // Create a new popstate event
7264 nsCOMPtr<nsIDOMEvent> domEvent;
7265 rv = nsEventDispatcher::CreateEvent(presContext, nsnull,
7266 NS_LITERAL_STRING("popstateevent"),
7267 getter_AddRefs(domEvent));
7268 NS_ENSURE_SUCCESS(rv, rv);
7270 nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(domEvent);
7271 NS_ENSURE_TRUE(privateEvent, NS_ERROR_FAILURE);
7273 // Initialize the popstate event, which does bubble but isn't cancellable.
7274 nsCOMPtr<nsIDOMPopStateEvent> popstateEvent = do_QueryInterface(domEvent);
7275 rv = popstateEvent->InitPopStateEvent(NS_LITERAL_STRING("popstate"),
7276 PR_TRUE, PR_FALSE,
7277 stateObj);
7278 NS_ENSURE_SUCCESS(rv, rv);
7280 rv = privateEvent->SetTrusted(PR_TRUE);
7281 NS_ENSURE_SUCCESS(rv, rv);
7283 nsCOMPtr<nsIDOMEventTarget> outerWindow =
7284 do_QueryInterface(GetOuterWindow());
7285 NS_ENSURE_TRUE(outerWindow, NS_ERROR_UNEXPECTED);
7287 rv = privateEvent->SetTarget(outerWindow);
7288 NS_ENSURE_SUCCESS(rv, rv);
7290 PRBool dummy; // default action
7291 return DispatchEvent(popstateEvent, &dummy);
7294 // Find an nsICanvasFrame under aFrame. Only search the principal
7295 // child lists. aFrame must be non-null.
7296 static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
7298 nsCanvasFrame* canvasFrame = do_QueryFrame(aFrame);
7299 if (canvasFrame) {
7300 return canvasFrame;
7303 nsIFrame* kid = aFrame->GetFirstChild(nsnull);
7304 while (kid) {
7305 canvasFrame = FindCanvasFrame(kid);
7306 if (canvasFrame) {
7307 return canvasFrame;
7309 kid = kid->GetNextSibling();
7312 return nsnull;
7315 //-------------------------------------------------------
7316 // Tells the HTMLFrame/CanvasFrame that is now has focus
7317 void
7318 nsGlobalWindow::UpdateCanvasFocus(PRBool aFocusChanged, nsIContent* aNewContent)
7320 // this is called from the inner window so use GetDocShell
7321 nsIDocShell* docShell = GetDocShell();
7322 if (!docShell)
7323 return;
7325 nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
7326 if (editorDocShell) {
7327 PRBool editable;
7328 editorDocShell->GetEditable(&editable);
7329 if (editable)
7330 return;
7333 nsCOMPtr<nsIPresShell> presShell;
7334 docShell->GetPresShell(getter_AddRefs(presShell));
7335 if (!presShell || !mDocument)
7336 return;
7338 nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
7339 Element *rootElement = doc->GetRootElement();
7340 if (rootElement) {
7341 if ((mHasFocus || aFocusChanged) &&
7342 (mFocusedNode == rootElement || aNewContent == rootElement)) {
7343 nsIFrame* frame = rootElement->GetPrimaryFrame();
7344 if (frame) {
7345 frame = frame->GetParent();
7346 nsCanvasFrame* canvasFrame = do_QueryFrame(frame);
7347 if (canvasFrame) {
7348 canvasFrame->SetHasFocus(mHasFocus && rootElement == aNewContent);
7352 } else {
7353 // Look for the frame the hard way
7354 nsIFrame* frame = presShell->GetRootFrame();
7355 if (frame) {
7356 nsCanvasFrame* canvasFrame = FindCanvasFrame(frame);
7357 if (canvasFrame) {
7358 canvasFrame->SetHasFocus(PR_FALSE);
7364 //*****************************************************************************
7365 // nsGlobalWindow::nsIDOMViewCSS
7366 //*****************************************************************************
7368 NS_IMETHODIMP
7369 nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
7370 const nsAString& aPseudoElt,
7371 nsIDOMCSSStyleDeclaration** aReturn)
7373 FORWARD_TO_OUTER(GetComputedStyle, (aElt, aPseudoElt, aReturn),
7374 NS_ERROR_NOT_INITIALIZED);
7376 NS_ENSURE_ARG_POINTER(aReturn);
7377 *aReturn = nsnull;
7379 if (!aElt) {
7380 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
7383 if (!mDocShell) {
7384 return NS_OK;
7387 nsCOMPtr<nsIPresShell> presShell;
7388 mDocShell->GetPresShell(getter_AddRefs(presShell));
7390 if (!presShell) {
7391 return NS_OK;
7394 nsRefPtr<nsComputedDOMStyle> compStyle;
7395 nsresult rv = NS_NewComputedDOMStyle(aElt, aPseudoElt, presShell,
7396 getter_AddRefs(compStyle));
7397 NS_ENSURE_SUCCESS(rv, rv);
7399 *aReturn = compStyle.forget().get();
7401 return NS_OK;
7404 //*****************************************************************************
7405 // nsGlobalWindow::nsIDOMAbstractView
7406 //*****************************************************************************
7408 NS_IMETHODIMP
7409 nsGlobalWindow::GetDocument(nsIDOMDocumentView ** aDocumentView)
7411 NS_ENSURE_ARG_POINTER(aDocumentView);
7413 nsresult rv = NS_OK;
7415 if (mDocument) {
7416 rv = CallQueryInterface(mDocument, aDocumentView);
7418 else {
7419 *aDocumentView = nsnull;
7422 return rv;
7425 //*****************************************************************************
7426 // nsGlobalWindow::nsIDOMStorageWindow
7427 //*****************************************************************************
7429 NS_IMETHODIMP
7430 nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
7432 FORWARD_TO_INNER(GetSessionStorage, (aSessionStorage), NS_ERROR_UNEXPECTED);
7434 nsIPrincipal *principal = GetPrincipal();
7435 nsIDocShell* docShell = GetDocShell();
7437 if (!principal || !docShell) {
7438 return NS_OK;
7441 if (mSessionStorage) {
7442 #ifdef PR_LOGGING
7443 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7444 PR_LogPrint("nsGlobalWindow %p has %p sessionStorage", this, mSessionStorage.get());
7446 #endif
7447 nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(mSessionStorage);
7448 if (piStorage) {
7449 PRBool canAccess = piStorage->CanAccess(principal);
7450 NS_ASSERTION(canAccess,
7451 "window %x owned sessionStorage "
7452 "that could not be accessed!");
7453 if (!canAccess) {
7454 mSessionStorage = nsnull;
7459 if (!mSessionStorage) {
7460 *aSessionStorage = nsnull;
7462 nsString documentURI;
7463 nsCOMPtr<nsIDOM3Document> document3 = do_QueryInterface(mDoc);
7464 if (document3)
7465 document3->GetDocumentURI(documentURI);
7467 nsresult rv = docShell->GetSessionStorageForPrincipal(principal,
7468 documentURI,
7469 PR_TRUE,
7470 getter_AddRefs(mSessionStorage));
7471 NS_ENSURE_SUCCESS(rv, rv);
7473 #ifdef PR_LOGGING
7474 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7475 PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get());
7477 #endif
7479 if (!mSessionStorage) {
7480 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
7484 #ifdef PR_LOGGING
7485 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7486 PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get());
7488 #endif
7490 NS_ADDREF(*aSessionStorage = mSessionStorage);
7491 return NS_OK;
7494 NS_IMETHODIMP
7495 nsGlobalWindow::GetGlobalStorage(nsIDOMStorageList ** aGlobalStorage)
7497 NS_ENSURE_ARG_POINTER(aGlobalStorage);
7499 #ifdef MOZ_STORAGE
7500 if (!sGlobalStorageList) {
7501 nsresult rv = NS_NewDOMStorageList(&sGlobalStorageList);
7502 NS_ENSURE_SUCCESS(rv, rv);
7505 *aGlobalStorage = sGlobalStorageList;
7506 NS_IF_ADDREF(*aGlobalStorage);
7508 return NS_OK;
7509 #else
7510 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
7511 #endif
7514 NS_IMETHODIMP
7515 nsGlobalWindow::GetLocalStorage(nsIDOMStorage ** aLocalStorage)
7517 FORWARD_TO_INNER(GetLocalStorage, (aLocalStorage), NS_ERROR_UNEXPECTED);
7519 NS_ENSURE_ARG(aLocalStorage);
7521 if (!mLocalStorage) {
7522 *aLocalStorage = nsnull;
7524 nsresult rv;
7526 PRPackedBool unused;
7527 if (!nsDOMStorage::CanUseStorage(&unused))
7528 return NS_ERROR_DOM_SECURITY_ERR;
7530 nsIPrincipal *principal = GetPrincipal();
7531 if (!principal)
7532 return NS_OK;
7534 nsCOMPtr<nsIDOMStorageManager> storageManager =
7535 do_GetService("@mozilla.org/dom/storagemanager;1", &rv);
7536 NS_ENSURE_SUCCESS(rv, rv);
7538 nsString documentURI;
7539 nsCOMPtr<nsIDOM3Document> document3 = do_QueryInterface(mDoc);
7540 if (document3)
7541 document3->GetDocumentURI(documentURI);
7543 rv = storageManager->GetLocalStorageForPrincipal(principal,
7544 documentURI,
7545 getter_AddRefs(mLocalStorage));
7546 NS_ENSURE_SUCCESS(rv, rv);
7549 NS_ADDREF(*aLocalStorage = mLocalStorage);
7550 return NS_OK;
7553 NS_IMETHODIMP
7554 nsGlobalWindow::GetMoz_indexedDB(nsIIDBFactory** _retval)
7556 if (!mIndexedDB) {
7557 mIndexedDB = mozilla::dom::indexedDB::IDBFactory::Create();
7558 NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_FAILURE);
7561 nsCOMPtr<nsIIDBFactory> request(mIndexedDB);
7562 request.forget(_retval);
7563 return NS_OK;
7566 //*****************************************************************************
7567 // nsGlobalWindow::nsIInterfaceRequestor
7568 //*****************************************************************************
7570 NS_IMETHODIMP
7571 nsGlobalWindow::GetInterface(const nsIID & aIID, void **aSink)
7573 NS_ENSURE_ARG_POINTER(aSink);
7574 *aSink = nsnull;
7576 if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
7577 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
7579 if (mDocShell) {
7580 nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(mDocShell));
7581 if (docCharset) {
7582 *aSink = docCharset;
7583 NS_ADDREF(((nsISupports *) *aSink));
7587 else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
7588 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
7590 if (mDocShell) {
7591 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
7592 if (webNav) {
7593 *aSink = webNav;
7594 NS_ADDREF(((nsISupports *) *aSink));
7598 #ifdef NS_PRINTING
7599 else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
7600 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
7602 if (mDocShell) {
7603 nsCOMPtr<nsIContentViewer> viewer;
7604 mDocShell->GetContentViewer(getter_AddRefs(viewer));
7605 if (viewer) {
7606 nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
7607 if (webBrowserPrint) {
7608 *aSink = webBrowserPrint;
7609 NS_ADDREF(((nsISupports *) *aSink));
7614 #endif
7615 else if (aIID.Equals(NS_GET_IID(nsIScriptEventManager))) {
7616 if (mDoc) {
7617 nsIScriptEventManager* mgr = mDoc->GetScriptEventManager();
7618 if (mgr) {
7619 *aSink = mgr;
7620 NS_ADDREF(((nsISupports *) *aSink));
7624 else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils))) {
7625 FORWARD_TO_OUTER(GetInterface, (aIID, aSink), NS_ERROR_NOT_INITIALIZED);
7627 nsCOMPtr<nsISupports> utils(do_QueryReferent(mWindowUtils));
7628 if (utils) {
7629 *aSink = utils;
7630 NS_ADDREF(((nsISupports *) *aSink));
7631 } else {
7632 nsDOMWindowUtils *utilObj = new nsDOMWindowUtils(this);
7633 nsCOMPtr<nsISupports> utilsIfc =
7634 NS_ISUPPORTS_CAST(nsIDOMWindowUtils *, utilObj);
7635 if (utilsIfc) {
7636 mWindowUtils = do_GetWeakReference(utilsIfc);
7637 *aSink = utilsIfc;
7638 NS_ADDREF(((nsISupports *) *aSink));
7642 else {
7643 return QueryInterface(aIID, aSink);
7646 return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
7649 void
7650 nsGlobalWindow::FireOfflineStatusEvent()
7652 if (!mDoc)
7653 return;
7654 nsAutoString name;
7655 if (NS_IsOffline()) {
7656 name.AssignLiteral("offline");
7657 } else {
7658 name.AssignLiteral("online");
7660 // The event is fired at the body element, or if there is no body element,
7661 // at the document.
7662 nsCOMPtr<nsISupports> eventTarget = mDoc.get();
7663 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDoc);
7664 if (htmlDoc) {
7665 nsCOMPtr<nsIDOMHTMLElement> body;
7666 htmlDoc->GetBody(getter_AddRefs(body));
7667 if (body) {
7668 eventTarget = body;
7671 else {
7672 nsCOMPtr<nsIDOMElement> documentElement;
7673 mDocument->GetDocumentElement(getter_AddRefs(documentElement));
7674 if(documentElement) {
7675 eventTarget = documentElement;
7678 nsContentUtils::DispatchTrustedEvent(mDoc, eventTarget, name, PR_TRUE, PR_FALSE);
7681 nsresult
7682 nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
7683 const PRUnichar* aData)
7685 if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
7686 if (IsFrozen()) {
7687 // if an even number of notifications arrive while we're frozen,
7688 // we don't need to fire.
7689 mFireOfflineStatusChangeEventOnThaw = !mFireOfflineStatusChangeEventOnThaw;
7690 } else {
7691 FireOfflineStatusEvent();
7693 return NS_OK;
7696 if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage-changed")) {
7697 nsIPrincipal *principal;
7698 nsresult rv;
7700 principal = GetPrincipal();
7701 if (principal) {
7702 // A global storage object changed, check to see if it's one
7703 // this window can access.
7705 nsCOMPtr<nsIURI> codebase;
7706 principal->GetURI(getter_AddRefs(codebase));
7708 if (!codebase) {
7709 return NS_OK;
7712 nsCAutoString currentDomain;
7713 rv = codebase->GetAsciiHost(currentDomain);
7714 if (NS_FAILED(rv)) {
7715 return NS_OK;
7718 if (!nsDOMStorageList::CanAccessDomain(NS_ConvertUTF16toUTF8(aData),
7719 currentDomain)) {
7720 // This window can't reach the global storage object for the
7721 // domain for which the change happened, so don't fire any
7722 // events in this window.
7724 return NS_OK;
7728 nsAutoString domain(aData);
7730 if (IsFrozen()) {
7731 // This window is frozen, rather than firing the events here,
7732 // store the domain in which the change happened and fire the
7733 // events if we're ever thawed.
7735 if (!mPendingStorageEventsObsolete) {
7736 mPendingStorageEventsObsolete = new nsDataHashtable<nsStringHashKey, PRBool>;
7737 NS_ENSURE_TRUE(mPendingStorageEventsObsolete, NS_ERROR_OUT_OF_MEMORY);
7739 rv = mPendingStorageEventsObsolete->Init();
7740 NS_ENSURE_SUCCESS(rv, rv);
7743 mPendingStorageEventsObsolete->Put(domain, PR_TRUE);
7745 return NS_OK;
7748 nsRefPtr<nsDOMStorageEventObsolete> event = new nsDOMStorageEventObsolete();
7749 NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
7751 rv = event->InitStorageEvent(NS_LITERAL_STRING("storage"), PR_FALSE, PR_FALSE, domain);
7752 NS_ENSURE_SUCCESS(rv, rv);
7754 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
7756 nsCOMPtr<nsIDOMEventTarget> target;
7758 if (htmlDoc) {
7759 nsCOMPtr<nsIDOMHTMLElement> body;
7760 htmlDoc->GetBody(getter_AddRefs(body));
7762 target = do_QueryInterface(body);
7765 if (!target) {
7766 target = this;
7769 PRBool defaultActionEnabled;
7770 target->DispatchEvent((nsIDOMStorageEventObsolete *)event, &defaultActionEnabled);
7772 return NS_OK;
7775 if (IsInnerWindow() && !nsCRT::strcmp(aTopic, "dom-storage2-changed")) {
7776 nsIPrincipal *principal;
7777 nsresult rv;
7779 nsCOMPtr<nsIDOMStorageEvent> event = do_QueryInterface(aSubject, &rv);
7780 NS_ENSURE_SUCCESS(rv, rv);
7782 nsCOMPtr<nsIDOMStorage> changingStorage;
7783 rv = event->GetStorageArea(getter_AddRefs(changingStorage));
7784 NS_ENSURE_SUCCESS(rv, rv);
7786 nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(changingStorage);
7787 nsPIDOMStorage::nsDOMStorageType storageType = pistorage->StorageType();
7789 principal = GetPrincipal();
7790 switch (storageType)
7792 case nsPIDOMStorage::SessionStorage:
7794 if (SameCOMIdentity(mSessionStorage, changingStorage)) {
7795 // Do not fire any events for the same storage object, it's not shared
7796 // among windows, see nsGlobalWindow::GetSessionStoarge()
7797 return NS_OK;
7800 nsCOMPtr<nsIDOMStorage> storage = mSessionStorage;
7801 if (!storage) {
7802 nsIDocShell* docShell = GetDocShell();
7803 if (principal && docShell) {
7804 // No need to pass documentURI here, it's only needed when we want
7805 // to create a new storage, the third paramater would be PR_TRUE
7806 docShell->GetSessionStorageForPrincipal(principal,
7807 EmptyString(),
7808 PR_FALSE,
7809 getter_AddRefs(storage));
7813 if (!pistorage->IsForkOf(storage)) {
7814 // This storage event is coming from a different doc shell,
7815 // i.e. it is a clone, ignore this event.
7816 return NS_OK;
7819 #ifdef PR_LOGGING
7820 if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
7821 PR_LogPrint("nsGlobalWindow %p with sessionStorage %p passing event from %p", this, mSessionStorage.get(), pistorage.get());
7823 #endif
7825 break;
7827 case nsPIDOMStorage::LocalStorage:
7829 if (SameCOMIdentity(mLocalStorage, changingStorage)) {
7830 // Do not fire any events for the same storage object, it's not shared
7831 // among windows, see nsGlobalWindow::GetLocalStoarge()
7832 return NS_OK;
7835 // Allow event fire only for the same principal storages
7836 // XXX We have to use EqualsIgnoreDomain after bug 495337 lands
7837 nsIPrincipal *storagePrincipal = pistorage->Principal();
7838 PRBool equals;
7840 rv = storagePrincipal->Equals(principal, &equals);
7841 NS_ENSURE_SUCCESS(rv, rv);
7843 if (!equals)
7844 return NS_OK;
7846 break;
7848 default:
7849 return NS_OK;
7852 if (IsFrozen()) {
7853 // This window is frozen, rather than firing the events here,
7854 // store the domain in which the change happened and fire the
7855 // events if we're ever thawed.
7857 mPendingStorageEvents.AppendElement(event);
7858 return NS_OK;
7861 PRBool defaultActionEnabled;
7862 DispatchEvent((nsIDOMStorageEvent *)event, &defaultActionEnabled);
7864 return NS_OK;
7867 NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
7868 return NS_ERROR_FAILURE;
7871 static PLDHashOperator
7872 FirePendingStorageEvents(const nsAString& aKey, PRBool aData, void *userArg)
7874 nsGlobalWindow *win = static_cast<nsGlobalWindow *>(userArg);
7876 nsCOMPtr<nsIDOMStorage> storage;
7877 win->GetSessionStorage(getter_AddRefs(storage));
7879 if (storage) {
7880 win->Observe(storage, "dom-storage-changed",
7881 aKey.IsEmpty() ? nsnull : PromiseFlatString(aKey).get());
7884 return PL_DHASH_NEXT;
7887 nsresult
7888 nsGlobalWindow::FireDelayedDOMEvents()
7890 FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
7892 for (PRUint32 i = 0; i < mPendingStorageEvents.Length(); ++i) {
7893 Observe(mPendingStorageEvents[i], "dom-storage2-changed", nsnull);
7896 if (mPendingStorageEventsObsolete) {
7897 // Fire pending storage events.
7898 mPendingStorageEventsObsolete->EnumerateRead(FirePendingStorageEvents, this);
7900 delete mPendingStorageEventsObsolete;
7901 mPendingStorageEventsObsolete = nsnull;
7904 if (mApplicationCache) {
7905 static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
7908 if (mFireOfflineStatusChangeEventOnThaw) {
7909 mFireOfflineStatusChangeEventOnThaw = PR_FALSE;
7910 FireOfflineStatusEvent();
7913 nsCOMPtr<nsIDocShellTreeNode> node =
7914 do_QueryInterface(GetDocShell());
7915 if (node) {
7916 PRInt32 childCount = 0;
7917 node->GetChildCount(&childCount);
7919 for (PRInt32 i = 0; i < childCount; ++i) {
7920 nsCOMPtr<nsIDocShellTreeItem> childShell;
7921 node->GetChildAt(i, getter_AddRefs(childShell));
7922 NS_ASSERTION(childShell, "null child shell");
7924 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
7925 if (pWin) {
7926 nsGlobalWindow *win =
7927 static_cast<nsGlobalWindow*>
7928 (static_cast<nsPIDOMWindow*>(pWin));
7929 win->FireDelayedDOMEvents();
7934 return NS_OK;
7937 //*****************************************************************************
7938 // nsGlobalWindow: Window Control Functions
7939 //*****************************************************************************
7941 nsIDOMWindowInternal *
7942 nsGlobalWindow::GetParentInternal()
7944 FORWARD_TO_OUTER(GetParentInternal, (), nsnull);
7946 nsIDOMWindowInternal *parentInternal = nsnull;
7948 nsCOMPtr<nsIDOMWindow> parent;
7949 GetParent(getter_AddRefs(parent));
7951 if (parent && parent != static_cast<nsIDOMWindow *>(this)) {
7952 nsCOMPtr<nsIDOMWindowInternal> tmp(do_QueryInterface(parent));
7953 NS_ASSERTION(parent, "Huh, parent not an nsIDOMWindowInternal?");
7955 parentInternal = tmp;
7958 return parentInternal;
7961 // static
7962 void
7963 nsGlobalWindow::CloseBlockScriptTerminationFunc(nsISupports *aRef)
7965 nsGlobalWindow* pwin = static_cast<nsGlobalWindow*>
7966 (static_cast<nsPIDOMWindow*>(aRef));
7967 pwin->mBlockScriptedClosingFlag = PR_FALSE;
7970 nsresult
7971 nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
7972 const nsAString& aOptions, PRBool aDialog,
7973 PRBool aContentModal, PRBool aCalledNoScript,
7974 PRBool aDoJSFixups, nsIArray *argv,
7975 nsISupports *aExtraArgument,
7976 nsIPrincipal *aCalleePrincipal,
7977 JSContext *aJSCallerContext,
7978 nsIDOMWindow **aReturn)
7980 FORWARD_TO_OUTER(OpenInternal, (aUrl, aName, aOptions, aDialog,
7981 aContentModal, aCalledNoScript, aDoJSFixups,
7982 argv, aExtraArgument, aCalleePrincipal,
7983 aJSCallerContext, aReturn),
7984 NS_ERROR_NOT_INITIALIZED);
7986 #ifdef NS_DEBUG
7987 PRUint32 argc = 0;
7988 if (argv)
7989 argv->GetLength(&argc);
7990 #endif
7991 NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
7992 "Can't pass in arguments both ways");
7993 NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
7994 "Can't pass JS args when called via the noscript methods");
7995 NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
7996 "Shouldn't have caller context when called noscript");
7998 *aReturn = nsnull;
8000 nsCOMPtr<nsIWebBrowserChrome> chrome;
8001 GetWebBrowserChrome(getter_AddRefs(chrome));
8002 if (!chrome) {
8003 // No chrome means we don't want to go through with this open call
8004 // -- see nsIWindowWatcher.idl
8005 return NS_ERROR_NOT_AVAILABLE;
8008 NS_ASSERTION(mDocShell, "Must have docshell here");
8010 const PRBool checkForPopup =
8011 !aDialog && !WindowExists(aName, !aCalledNoScript);
8013 // Note: it's very important that this be an nsXPIDLCString, since we want
8014 // .get() on it to return nsnull until we write stuff to it. The window
8015 // watcher expects a null URL string if there is no URL to load.
8016 nsXPIDLCString url;
8017 nsresult rv = NS_OK;
8019 // It's important to do this security check before determining whether this
8020 // window opening should be blocked, to ensure that we don't FireAbuseEvents
8021 // for a window opening that wouldn't have succeeded in the first place.
8022 if (!aUrl.IsEmpty()) {
8023 AppendUTF16toUTF8(aUrl, url);
8025 /* Check whether the URI is allowed, but not for dialogs --
8026 see bug 56851. The security of this function depends on
8027 window.openDialog being inaccessible from web scripts */
8028 if (url.get() && !aDialog)
8029 rv = SecurityCheckURL(url.get());
8032 if (NS_FAILED(rv))
8033 return rv;
8035 PopupControlState abuseLevel = gPopupControlState;
8036 if (checkForPopup) {
8037 abuseLevel = RevisePopupAbuseLevel(abuseLevel);
8038 if (abuseLevel >= openAbused) {
8039 if (aJSCallerContext) {
8040 // If script in some other window is doing a window.open on us and
8041 // it's being blocked, then it's OK to close us afterwards, probably.
8042 // But if we're doing a window.open on ourselves and block the popup,
8043 // prevent this window from closing until after this script terminates
8044 // so that whatever popup blocker UI the app has will be visible.
8045 if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
8046 mBlockScriptedClosingFlag = PR_TRUE;
8047 mContext->SetTerminationFunction(CloseBlockScriptTerminationFunc,
8048 static_cast<nsPIDOMWindow*>
8049 (this));
8053 FireAbuseEvents(PR_TRUE, PR_FALSE, aUrl, aName, aOptions);
8054 return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
8058 nsCOMPtr<nsIDOMWindow> domReturn;
8060 nsCOMPtr<nsIWindowWatcher> wwatch =
8061 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
8062 NS_ENSURE_TRUE(wwatch, rv);
8064 NS_ConvertUTF16toUTF8 options(aOptions);
8065 NS_ConvertUTF16toUTF8 name(aName);
8067 const char *options_ptr = aOptions.IsEmpty() ? nsnull : options.get();
8068 const char *name_ptr = aName.IsEmpty() ? nsnull : name.get();
8071 // Reset popup state while opening a window to prevent the
8072 // current state from being active the whole time a modal
8073 // dialog is open.
8074 nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
8076 if (!aCalledNoScript) {
8077 nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
8078 NS_ASSERTION(pwwatch,
8079 "Unable to open windows from JS because window watcher "
8080 "is broken");
8081 NS_ENSURE_TRUE(pwwatch, NS_ERROR_UNEXPECTED);
8083 rv = pwwatch->OpenWindowJS(this, url.get(), name_ptr, options_ptr,
8084 aDialog, argv,
8085 getter_AddRefs(domReturn));
8086 } else {
8087 // Push a null JSContext here so that the window watcher won't screw us
8088 // up. We do NOT want this case looking at the JS context on the stack
8089 // when searching. Compare comments on
8090 // nsIDOMWindowInternal::OpenWindow and nsIWindowWatcher::OpenWindow.
8091 nsCOMPtr<nsIJSContextStack> stack;
8093 if (!aContentModal) {
8094 stack = do_GetService(sJSStackContractID);
8097 if (stack) {
8098 rv = stack->Push(nsnull);
8099 NS_ENSURE_SUCCESS(rv, rv);
8102 rv = wwatch->OpenWindow(this, url.get(), name_ptr, options_ptr,
8103 aExtraArgument, getter_AddRefs(domReturn));
8105 if (stack) {
8106 JSContext* cx;
8107 stack->Pop(&cx);
8108 NS_ASSERTION(!cx, "Unexpected JSContext popped!");
8113 NS_ENSURE_SUCCESS(rv, rv);
8115 // success!
8117 domReturn.swap(*aReturn);
8119 if (aDoJSFixups) {
8120 nsCOMPtr<nsIDOMChromeWindow> chrome_win(do_QueryInterface(*aReturn));
8121 if (!chrome_win) {
8122 // A new non-chrome window was created from a call to
8123 // window.open() from JavaScript, make sure there's a document in
8124 // the new window. We do this by simply asking the new window for
8125 // its document, this will synchronously create an empty document
8126 // if there is no document in the window.
8127 // XXXbz should this just use EnsureInnerWindow()?
8128 #ifdef DEBUG_jst
8130 nsCOMPtr<nsPIDOMWindow> pidomwin(do_QueryInterface(*aReturn));
8132 nsIDOMDocument *temp = pidomwin->GetExtantDocument();
8134 NS_ASSERTION(temp, "No document in new window!!!");
8136 #endif
8138 nsCOMPtr<nsIDOMDocument> doc;
8139 (*aReturn)->GetDocument(getter_AddRefs(doc));
8143 if (checkForPopup) {
8144 if (abuseLevel >= openControlled) {
8145 nsGlobalWindow *opened = static_cast<nsGlobalWindow *>(*aReturn);
8146 if (!opened->IsPopupSpamWindow()) {
8147 opened->SetPopupSpamWindow(PR_TRUE);
8148 ++gOpenPopupSpamCount;
8151 if (abuseLevel >= openAbused)
8152 FireAbuseEvents(PR_FALSE, PR_TRUE, aUrl, aName, aOptions);
8155 return rv;
8158 // static
8159 void
8160 nsGlobalWindow::CloseWindow(nsISupports *aWindow)
8162 nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow));
8164 nsGlobalWindow* globalWin =
8165 static_cast<nsGlobalWindow *>
8166 (static_cast<nsPIDOMWindow*>(win));
8168 // Need to post an event for closing, otherwise window and
8169 // presshell etc. may get destroyed while creating frames, bug 338897.
8170 nsCloseEvent::PostCloseEvent(globalWin);
8171 // else if OOM, better not to close. That might cause a crash.
8174 // static
8175 void
8176 nsGlobalWindow::ClearWindowScope(nsISupports *aWindow)
8178 nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aWindow));
8179 nsIScriptContext *scx = sgo->GetContext();
8180 if (scx) {
8181 scx->ClearScope(sgo->GetGlobalJSObject(), PR_TRUE);
8185 //*****************************************************************************
8186 // nsGlobalWindow: Timeout Functions
8187 //*****************************************************************************
8189 PRUint32 sNestingLevel;
8191 nsresult
8192 nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
8193 PRInt32 interval,
8194 PRBool aIsInterval, PRInt32 *aReturn)
8196 FORWARD_TO_INNER(SetTimeoutOrInterval, (aHandler, interval, aIsInterval, aReturn),
8197 NS_ERROR_NOT_INITIALIZED);
8199 // If we don't have a document (we could have been unloaded since
8200 // the call to setTimeout was made), do nothing.
8201 if (!mDocument) {
8202 return NS_OK;
8205 PRUint32 nestingLevel = sNestingLevel + 1;
8206 if (interval < DOM_MIN_TIMEOUT_VALUE) {
8207 if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
8208 // Don't allow timeouts less than DOM_MIN_TIMEOUT_VALUE from
8209 // now...
8211 interval = DOM_MIN_TIMEOUT_VALUE;
8213 else if (interval < 0) {
8214 // Clamp negative intervals to 0.
8216 interval = 0;
8220 NS_ASSERTION(interval >= 0, "DOM_MIN_TIMEOUT_VALUE lies");
8221 PRUint32 realInterval = interval;
8223 // Make sure we don't proceed with a interval larger than our timer
8224 // code can handle.
8225 if (realInterval > PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE)) {
8226 realInterval = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
8229 nsTimeout *timeout = new nsTimeout();
8230 if (!timeout)
8231 return NS_ERROR_OUT_OF_MEMORY;
8233 // Increment the timeout's reference count to represent this function's hold
8234 // on the timeout.
8235 timeout->AddRef();
8237 if (aIsInterval) {
8238 timeout->mInterval = realInterval;
8240 timeout->mScriptHandler = aHandler;
8242 // Get principal of currently executing code, save for execution of timeout.
8243 // If our principals subsume the subject principal then use the subject
8244 // principal. Otherwise, use our principal to avoid running script in
8245 // elevated principals.
8247 nsCOMPtr<nsIPrincipal> subjectPrincipal;
8248 nsresult rv;
8249 rv = nsContentUtils::GetSecurityManager()->
8250 GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
8251 if (NS_FAILED(rv)) {
8252 timeout->Release();
8254 return NS_ERROR_FAILURE;
8257 PRBool subsumes = PR_FALSE;
8258 nsCOMPtr<nsIPrincipal> ourPrincipal = GetPrincipal();
8260 // Note the direction of this test: We don't allow setTimeouts running with
8261 // chrome privileges on content windows, but we do allow setTimeouts running
8262 // with content privileges on chrome windows (where they can't do very much,
8263 // of course).
8264 rv = ourPrincipal->Subsumes(subjectPrincipal, &subsumes);
8265 if (NS_FAILED(rv)) {
8266 timeout->Release();
8268 return NS_ERROR_FAILURE;
8271 if (subsumes) {
8272 timeout->mPrincipal = subjectPrincipal;
8273 } else {
8274 timeout->mPrincipal = ourPrincipal;
8277 TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
8279 if (!IsFrozen() && !mTimeoutsSuspendDepth) {
8280 // If we're not currently frozen, then we set timeout->mWhen to be the
8281 // actual firing time of the timer (i.e., now + delta). We also actually
8282 // create a timer and fire it off.
8284 timeout->mWhen = TimeStamp::Now() + delta;
8286 timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
8287 if (NS_FAILED(rv)) {
8288 timeout->Release();
8290 return rv;
8293 rv = timeout->mTimer->InitWithFuncCallback(TimerCallback, timeout,
8294 realInterval,
8295 nsITimer::TYPE_ONE_SHOT);
8296 if (NS_FAILED(rv)) {
8297 timeout->Release();
8299 return rv;
8302 // The timeout is now also held in the timer's closure.
8303 timeout->AddRef();
8304 } else {
8305 // If we are frozen, however, then we instead simply set
8306 // timeout->mTimeRemaining to be the "time remaining" in the timeout (i.e.,
8307 // the interval itself). We don't create a timer for it, since that will
8308 // happen when we are thawed and the timeout will then get a timer and run
8309 // to completion.
8311 timeout->mTimeRemaining = delta;
8314 timeout->mWindow = this;
8316 if (!aIsInterval) {
8317 timeout->mNestingLevel = nestingLevel;
8320 // No popups from timeouts by default
8321 timeout->mPopupState = openAbused;
8323 if (gRunningTimeoutDepth == 0 && gPopupControlState < openAbused) {
8324 // This timeout is *not* set from another timeout and it's set
8325 // while popups are enabled. Propagate the state to the timeout if
8326 // its delay (interval) is equal to or less than what
8327 // "dom.disable_open_click_delay" is set to (in ms).
8329 PRInt32 delay =
8330 nsContentUtils::GetIntPref("dom.disable_open_click_delay");
8332 if (interval <= delay) {
8333 timeout->mPopupState = gPopupControlState;
8337 InsertTimeoutIntoList(timeout);
8339 timeout->mPublicId = ++mTimeoutPublicIdCounter;
8340 *aReturn = timeout->mPublicId;
8342 // Our hold on the timeout is expiring. Note that this should not actually
8343 // free the timeout (since the list should have taken ownership as well).
8344 timeout->Release();
8346 return NS_OK;
8350 nsresult
8351 nsGlobalWindow::SetTimeoutOrInterval(PRBool aIsInterval, PRInt32 *aReturn)
8353 // This needs to forward to the inner window, but since the current
8354 // inner may not be the inner in the calling scope, we need to treat
8355 // this specially here as we don't want timeouts registered in a
8356 // dying inner window to get registered and run on the current inner
8357 // window. To get this right, we need to forward this call to the
8358 // inner window that's calling window.setTimeout().
8360 if (IsOuterWindow()) {
8361 nsGlobalWindow* callerInner = CallerInnerWindow();
8362 NS_ENSURE_TRUE(callerInner, NS_ERROR_NOT_AVAILABLE);
8364 // If the caller and the callee share the same outer window,
8365 // forward to the callee inner. Else, we forward to the current
8366 // inner (e.g. someone is calling setTimeout() on a reference to
8367 // some other window).
8369 if (callerInner->GetOuterWindow() == this &&
8370 callerInner->IsInnerWindow()) {
8371 return callerInner->SetTimeoutOrInterval(aIsInterval, aReturn);
8374 FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
8375 NS_ERROR_NOT_INITIALIZED);
8378 PRInt32 interval = 0;
8379 PRBool isInterval = aIsInterval;
8380 nsCOMPtr<nsIScriptTimeoutHandler> handler;
8381 nsresult rv = NS_CreateJSTimeoutHandler(this,
8382 &isInterval,
8383 &interval,
8384 getter_AddRefs(handler));
8385 if (NS_FAILED(rv))
8386 return (rv == NS_ERROR_DOM_TYPE_ERR) ? NS_OK : rv;
8388 return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
8391 // static
8392 void
8393 nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
8395 // If a modal dialog is open for this window, return early. Pending
8396 // timeouts will run when the modal dialog is dismissed.
8397 if (IsInModalState() || mTimeoutsSuspendDepth) {
8398 return;
8401 NS_TIME_FUNCTION;
8403 NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
8404 NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
8406 nsTimeout *nextTimeout, *timeout;
8407 nsTimeout *last_expired_timeout, *last_insertion_point;
8408 nsTimeout dummy_timeout;
8409 PRUint32 firingDepth = mTimeoutFiringDepth + 1;
8411 // Make sure that the window and the script context don't go away as
8412 // a result of running timeouts
8413 nsCOMPtr<nsIScriptGlobalObject> windowKungFuDeathGrip(this);
8415 // A native timer has gone off. See which of our timeouts need
8416 // servicing
8417 TimeStamp now = TimeStamp::Now();
8418 TimeStamp deadline;
8420 if (aTimeout && aTimeout->mWhen > now) {
8421 // The OS timer fired early (yikes!), and possibly out of order
8422 // too. Set |deadline| to be the time when the OS timer *should*
8423 // have fired so that any timers that *should* have fired before
8424 // aTimeout *will* be fired now. This happens most of the time on
8425 // Win2k.
8427 deadline = aTimeout->mWhen;
8428 } else {
8429 deadline = now;
8432 // The timeout list is kept in deadline order. Discover the latest
8433 // timeout whose deadline has expired. On some platforms, native
8434 // timeout events fire "early", so we need to test the timer as well
8435 // as the deadline.
8436 last_expired_timeout = nsnull;
8437 for (timeout = FirstTimeout(); IsTimeout(timeout); timeout = timeout->Next()) {
8438 if (((timeout == aTimeout) || (timeout->mWhen <= deadline)) &&
8439 (timeout->mFiringDepth == 0)) {
8440 // Mark any timeouts that are on the list to be fired with the
8441 // firing depth so that we can reentrantly run timeouts
8442 timeout->mFiringDepth = firingDepth;
8443 last_expired_timeout = timeout;
8447 // Maybe the timeout that the event was fired for has been deleted
8448 // and there are no others timeouts with deadlines that make them
8449 // eligible for execution yet. Go away.
8450 if (!last_expired_timeout) {
8451 return;
8454 // Insert a dummy timeout into the list of timeouts between the
8455 // portion of the list that we are about to process now and those
8456 // timeouts that will be processed in a future call to
8457 // win_run_timeout(). This dummy timeout serves as the head of the
8458 // list for any timeouts inserted as a result of running a timeout.
8459 dummy_timeout.mFiringDepth = firingDepth;
8460 dummy_timeout.mWhen = now;
8461 PR_INSERT_AFTER(&dummy_timeout, last_expired_timeout);
8463 // Don't let ClearWindowTimeouts throw away our stack-allocated
8464 // dummy timeout.
8465 dummy_timeout.AddRef();
8466 dummy_timeout.AddRef();
8468 last_insertion_point = mTimeoutInsertionPoint;
8469 mTimeoutInsertionPoint = &dummy_timeout;
8471 for (timeout = FirstTimeout();
8472 timeout != &dummy_timeout && !IsFrozen();
8473 timeout = nextTimeout) {
8474 nextTimeout = timeout->Next();
8476 if (timeout->mFiringDepth != firingDepth) {
8477 // We skip the timeout since it's on the list to run at another
8478 // depth.
8480 continue;
8483 if (mTimeoutsSuspendDepth) {
8484 // Some timer did suspend us. Make sure the
8485 // rest of the timers get executed later.
8486 timeout->mFiringDepth = 0;
8487 continue;
8490 // The timeout is on the list to run at this depth, go ahead and
8491 // process it.
8493 // Get the script context (a strong ref to prevent it going away)
8494 // for this timeout and ensure the script language is enabled.
8495 nsCOMPtr<nsIScriptContext> scx = GetScriptContextInternal(
8496 timeout->mScriptHandler->GetScriptTypeID());
8498 if (!scx) {
8499 // No context means this window was closed or never properly
8500 // initialized for this language.
8501 continue;
8504 // The "scripts disabled" concept is still a little vague wrt
8505 // multiple languages. Prepare for the day when languages can be
8506 // disabled independently of the other languages...
8507 if (!scx->GetScriptsEnabled()) {
8508 // Scripts were enabled once in this window (unless aTimeout ==
8509 // nsnull) but now scripts are disabled (we might be in
8510 // print-preview, for instance), this means we shouldn't run any
8511 // timeouts at this point.
8513 // If scripts are enabled for this language in this window again
8514 // we'll fire the timeouts that are due at that point.
8515 continue;
8518 // This timeout is good to run
8519 nsTimeout *last_running_timeout = mRunningTimeout;
8520 mRunningTimeout = timeout;
8521 timeout->mRunning = PR_TRUE;
8523 // Push this timeout's popup control state, which should only be
8524 // eabled the first time a timeout fires that was created while
8525 // popups were enabled and with a delay less than
8526 // "dom.disable_open_click_delay".
8527 nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
8529 // Clear the timeout's popup state, if any, to prevent interval
8530 // timeouts from repeatedly opening poups.
8531 timeout->mPopupState = openAbused;
8533 // Hold on to the timeout in case mExpr or mFunObj releases its
8534 // doc.
8535 timeout->AddRef();
8537 ++gRunningTimeoutDepth;
8538 ++mTimeoutFiringDepth;
8540 PRBool trackNestingLevel = !timeout->mInterval;
8541 PRUint32 nestingLevel;
8542 if (trackNestingLevel) {
8543 nestingLevel = sNestingLevel;
8544 sNestingLevel = timeout->mNestingLevel;
8547 nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
8548 void *scriptObject = handler->GetScriptObject();
8549 if (!scriptObject) {
8550 // Evaluate the timeout expression.
8551 const PRUnichar *script = handler->GetHandlerText();
8552 NS_ASSERTION(script, "timeout has no script nor handler text!");
8554 const char *filename = nsnull;
8555 PRUint32 lineNo = 0;
8556 handler->GetLocation(&filename, &lineNo);
8558 NS_TIME_FUNCTION_MARK("(file: %s, line: %d)", filename, lineNo);
8560 PRBool is_undefined;
8561 scx->EvaluateString(nsDependentString(script),
8562 GetScriptGlobal(handler->GetScriptTypeID()),
8563 timeout->mPrincipal, filename, lineNo,
8564 handler->GetScriptVersion(), nsnull,
8565 &is_undefined);
8566 } else {
8567 // Let the script handler know about the "secret" final argument that
8568 // indicates timeout lateness in milliseconds
8569 TimeDuration lateness = now - timeout->mWhen;
8571 handler->SetLateness(lateness.ToMilliseconds());
8573 nsCOMPtr<nsIVariant> dummy;
8574 nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
8575 scx->CallEventHandler(me,
8576 GetScriptGlobal(handler->GetScriptTypeID()),
8577 scriptObject, handler->GetArgv(),
8578 // XXXmarkh - consider allowing CallEventHandler to
8579 // accept nsnull?
8580 getter_AddRefs(dummy));
8583 handler = nsnull; // drop reference before dropping timeout refs.
8585 if (trackNestingLevel) {
8586 sNestingLevel = nestingLevel;
8589 --mTimeoutFiringDepth;
8590 --gRunningTimeoutDepth;
8592 mRunningTimeout = last_running_timeout;
8593 timeout->mRunning = PR_FALSE;
8595 // We ignore any failures from calling EvaluateString() or
8596 // CallEventHandler() on the context here since we're in a loop
8597 // where we're likely to be running timeouts whose OS timers
8598 // didn't fire in time and we don't want to not fire those timers
8599 // now just because execution of one timer failed. We can't
8600 // propagate the error to anyone who cares about it from this
8601 // point anyway, and the script context should have already reported
8602 // the script error in the usual way - so we just drop it.
8604 // If all timeouts were cleared and |timeout != aTimeout| then
8605 // |timeout| may be the last reference to the timeout so check if
8606 // it was cleared before releasing it.
8607 PRBool timeout_was_cleared = timeout->mCleared;
8609 timeout->Release();
8611 if (timeout_was_cleared) {
8612 // The running timeout's window was cleared, this means that
8613 // ClearAllTimeouts() was called from a *nested* call, possibly
8614 // through a timeout that fired while a modal (to this window)
8615 // dialog was open or through other non-obvious paths.
8617 mTimeoutInsertionPoint = last_insertion_point;
8619 return;
8622 PRBool isInterval = PR_FALSE;
8624 // If we have a regular interval timer, we re-schedule the
8625 // timeout, accounting for clock drift.
8626 if (timeout->mInterval) {
8627 // Compute time to next timeout for interval timer.
8628 // Make sure nextInterval is at least DOM_MIN_TIMEOUT_VALUE.
8629 TimeDuration nextInterval =
8630 TimeDuration::FromMilliseconds(NS_MAX(timeout->mInterval,
8631 PRUint32(DOM_MIN_TIMEOUT_VALUE)));
8633 // If we're running pending timeouts because they've been temporarily
8634 // disabled (!aTimeout), set the next interval to be relative to "now",
8635 // and not to when the timeout that was pending should have fired. Also
8636 // check if the next interval timeout is overdue. If so, then restart
8637 // the interval from now.
8638 TimeStamp firingTime;
8639 if (!aTimeout || timeout->mWhen + nextInterval <= now)
8640 firingTime = now + nextInterval;
8641 else
8642 firingTime = timeout->mWhen + nextInterval;
8644 TimeDuration delay = firingTime - TimeStamp::Now();
8646 // And make sure delay is nonnegative; that might happen if the timer
8647 // thread is firing our timers somewhat early.
8648 if (delay < TimeDuration(0)) {
8649 delay = TimeDuration(0);
8652 if (timeout->mTimer) {
8653 timeout->mWhen = firingTime;
8655 // Reschedule the OS timer. Don't bother returning any error
8656 // codes if this fails since the callers of this method
8657 // doesn't care about them nobody who cares about them
8658 // anyways.
8660 // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed
8661 // PRTime to make the division do the right thing on 64-bit
8662 // platforms whether delay is positive or negative (which we
8663 // know is always positive here, but cast anyways for
8664 // consistency).
8665 nsresult rv = timeout->mTimer->
8666 InitWithFuncCallback(TimerCallback, timeout,
8667 delay.ToMilliseconds(),
8668 nsITimer::TYPE_ONE_SHOT);
8670 if (NS_FAILED(rv)) {
8671 NS_ERROR("Error initializing timer for DOM timeout!");
8673 // We failed to initialize the new OS timer, this timer does
8674 // us no good here so we just cancel it (just in case) and
8675 // null out the pointer to the OS timer, this will release the
8676 // OS timer. As we continue executing the code below we'll end
8677 // up deleting the timeout since it's not an interval timeout
8678 // any more (since timeout->mTimer == nsnull).
8679 timeout->mTimer->Cancel();
8680 timeout->mTimer = nsnull;
8682 // Now that the OS timer no longer has a reference to the
8683 // timeout we need to drop that reference.
8684 timeout->Release();
8686 } else {
8687 NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth,
8688 "How'd our timer end up null if we're not frozen or "
8689 "suspended?");
8691 timeout->mTimeRemaining = delay;
8692 isInterval = PR_TRUE;
8696 if (timeout->mTimer) {
8697 if (timeout->mInterval) {
8698 isInterval = PR_TRUE;
8699 } else {
8700 // The timeout still has an OS timer, and it's not an
8701 // interval, that means that the OS timer could still fire (if
8702 // it didn't already, i.e. aTimeout == timeout), cancel the OS
8703 // timer and release its reference to the timeout.
8704 timeout->mTimer->Cancel();
8705 timeout->mTimer = nsnull;
8707 timeout->Release();
8711 // Running a timeout can cause another timeout to be deleted, so
8712 // we need to reset the pointer to the following timeout.
8713 nextTimeout = timeout->Next();
8715 PR_REMOVE_LINK(timeout);
8717 if (isInterval) {
8718 // Reschedule an interval timeout. Insert interval timeout
8719 // onto list sorted in deadline order.
8720 // AddRefs timeout.
8721 InsertTimeoutIntoList(timeout);
8724 // Release the timeout struct since it's possibly out of the list
8725 timeout->Release();
8728 // Take the dummy timeout off the head of the list
8729 PR_REMOVE_LINK(&dummy_timeout);
8731 mTimeoutInsertionPoint = last_insertion_point;
8734 nsrefcnt
8735 nsTimeout::Release()
8737 if (--mRefCnt > 0)
8738 return mRefCnt;
8740 // language specific cleanup done as mScriptHandler destructs...
8742 // Kill the timer if it is still alive.
8743 if (mTimer) {
8744 mTimer->Cancel();
8745 mTimer = nsnull;
8748 delete this;
8749 return 0;
8752 nsrefcnt
8753 nsTimeout::AddRef()
8755 return ++mRefCnt;
8759 nsresult
8760 nsGlobalWindow::ClearTimeoutOrInterval(PRInt32 aTimerID)
8762 FORWARD_TO_INNER(ClearTimeoutOrInterval, (aTimerID), NS_ERROR_NOT_INITIALIZED);
8764 PRUint32 public_id = (PRUint32)aTimerID;
8765 nsTimeout *timeout;
8767 for (timeout = FirstTimeout();
8768 IsTimeout(timeout);
8769 timeout = timeout->Next()) {
8770 if (timeout->mPublicId == public_id) {
8771 if (timeout->mRunning) {
8772 /* We're running from inside the timeout. Mark this
8773 timeout for deferred deletion by the code in
8774 RunTimeout() */
8775 timeout->mInterval = 0;
8777 else {
8778 /* Delete the timeout from the pending timeout list */
8779 PR_REMOVE_LINK(timeout);
8781 if (timeout->mTimer) {
8782 timeout->mTimer->Cancel();
8783 timeout->mTimer = nsnull;
8784 timeout->Release();
8786 timeout->Release();
8788 break;
8792 return NS_OK;
8795 // A JavaScript specific version.
8796 nsresult
8797 nsGlobalWindow::ClearTimeoutOrInterval()
8799 FORWARD_TO_INNER(ClearTimeoutOrInterval, (), NS_ERROR_NOT_INITIALIZED);
8801 nsresult rv = NS_OK;
8802 nsAXPCNativeCallContext *ncc = nsnull;
8804 rv = nsContentUtils::XPConnect()->
8805 GetCurrentNativeCallContext(&ncc);
8806 NS_ENSURE_SUCCESS(rv, rv);
8808 if (!ncc)
8809 return NS_ERROR_NOT_AVAILABLE;
8811 JSContext *cx = nsnull;
8813 rv = ncc->GetJSContext(&cx);
8814 NS_ENSURE_SUCCESS(rv, rv);
8816 PRUint32 argc;
8818 ncc->GetArgc(&argc);
8820 if (argc < 1) {
8821 // No arguments, return early.
8823 return NS_OK;
8826 jsval *argv = nsnull;
8828 ncc->GetArgvPtr(&argv);
8830 int32 timer_id;
8832 JSAutoRequest ar(cx);
8834 // XXXjst: Can we deal with this w/o using GetCurrentNativeCallContext()
8835 if (argv[0] == JSVAL_VOID || !::JS_ValueToInt32(cx, argv[0], &timer_id) ||
8836 timer_id <= 0) {
8837 // Undefined or non-positive number passed as argument, return
8838 // early. Make sure that JS_ValueToInt32 didn't set an exception.
8840 ::JS_ClearPendingException(cx);
8841 return NS_OK;
8844 return ClearTimeoutOrInterval(timer_id);
8847 void
8848 nsGlobalWindow::ClearAllTimeouts()
8850 nsTimeout *timeout, *nextTimeout;
8852 for (timeout = FirstTimeout(); IsTimeout(timeout); timeout = nextTimeout) {
8853 /* If RunTimeout() is higher up on the stack for this
8854 window, e.g. as a result of document.write from a timeout,
8855 then we need to reset the list insertion point for
8856 newly-created timeouts in case the user adds a timeout,
8857 before we pop the stack back to RunTimeout. */
8858 if (mRunningTimeout == timeout)
8859 mTimeoutInsertionPoint = nsnull;
8861 nextTimeout = timeout->Next();
8863 if (timeout->mTimer) {
8864 timeout->mTimer->Cancel();
8865 timeout->mTimer = nsnull;
8867 // Drop the count since the timer isn't going to hold on
8868 // anymore.
8869 timeout->Release();
8872 // Set timeout->mCleared to true to indicate that the timeout was
8873 // cleared and taken out of the list of timeouts
8874 timeout->mCleared = PR_TRUE;
8876 // Drop the count since we're removing it from the list.
8877 timeout->Release();
8880 // Clear out our list
8881 PR_INIT_CLIST(&mTimeouts);
8884 void
8885 nsGlobalWindow::InsertTimeoutIntoList(nsTimeout *aTimeout)
8887 NS_ASSERTION(IsInnerWindow(),
8888 "InsertTimeoutIntoList() called on outer window!");
8890 // Start at mLastTimeout and go backwards. Don't go further than
8891 // mTimeoutInsertionPoint, though. This optimizes for the common case of
8892 // insertion at the end.
8893 nsTimeout* prevSibling;
8894 for (prevSibling = LastTimeout();
8895 IsTimeout(prevSibling) && prevSibling != mTimeoutInsertionPoint &&
8896 // This condition needs to match the one in SetTimeoutOrInterval that
8897 // determines whether to set mWhen or mTimeRemaining.
8898 ((IsFrozen() || mTimeoutsSuspendDepth) ?
8899 prevSibling->mTimeRemaining > aTimeout->mTimeRemaining :
8900 prevSibling->mWhen > aTimeout->mWhen);
8901 prevSibling = prevSibling->Prev()) {
8902 /* Do nothing; just searching */
8905 // Now link in aTimeout after prevSibling.
8906 PR_INSERT_AFTER(aTimeout, prevSibling);
8908 aTimeout->mFiringDepth = 0;
8910 // Increment the timeout's reference count since it's now held on to
8911 // by the list
8912 aTimeout->AddRef();
8915 // static
8916 void
8917 nsGlobalWindow::TimerCallback(nsITimer *aTimer, void *aClosure)
8919 nsTimeout *timeout = (nsTimeout *)aClosure;
8921 // Hold on to the timeout to ensure it doesn't go away while it's
8922 // being handled (aka kungFuDeathGrip).
8923 timeout->AddRef();
8925 timeout->mWindow->RunTimeout(timeout);
8927 // Drop our reference to the timeout now that we're done with it.
8928 timeout->Release();
8931 //*****************************************************************************
8932 // nsGlobalWindow: Helper Functions
8933 //*****************************************************************************
8935 nsresult
8936 nsGlobalWindow::GetTreeOwner(nsIDocShellTreeOwner **aTreeOwner)
8938 FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
8940 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
8942 // If there's no docShellAsItem, this window must have been closed,
8943 // in that case there is no tree owner.
8945 if (!docShellAsItem) {
8946 *aTreeOwner = nsnull;
8948 return NS_OK;
8951 return docShellAsItem->GetTreeOwner(aTreeOwner);
8954 nsresult
8955 nsGlobalWindow::GetTreeOwner(nsIBaseWindow **aTreeOwner)
8957 FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
8959 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
8960 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
8962 // If there's no docShellAsItem, this window must have been closed,
8963 // in that case there is no tree owner.
8965 if (docShellAsItem) {
8966 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
8969 if (!treeOwner) {
8970 *aTreeOwner = nsnull;
8971 return NS_OK;
8974 return CallQueryInterface(treeOwner, aTreeOwner);
8977 nsresult
8978 nsGlobalWindow::GetWebBrowserChrome(nsIWebBrowserChrome **aBrowserChrome)
8980 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
8981 GetTreeOwner(getter_AddRefs(treeOwner));
8983 nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner));
8984 NS_IF_ADDREF(*aBrowserChrome = browserChrome);
8986 return NS_OK;
8989 nsIScrollableFrame *
8990 nsGlobalWindow::GetScrollFrame()
8992 FORWARD_TO_OUTER(GetScrollFrame, (), nsnull);
8994 if (!mDocShell) {
8995 return nsnull;
8998 nsCOMPtr<nsIPresShell> presShell;
8999 mDocShell->GetPresShell(getter_AddRefs(presShell));
9000 if (presShell) {
9001 return presShell->GetRootScrollFrameAsScrollable();
9003 return nsnull;
9006 nsresult
9007 nsGlobalWindow::BuildURIfromBase(const char *aURL, nsIURI **aBuiltURI,
9008 PRBool *aFreeSecurityPass,
9009 JSContext **aCXused)
9011 nsIScriptContext *scx = GetContextInternal();
9012 JSContext *cx = nsnull;
9014 *aBuiltURI = nsnull;
9015 *aFreeSecurityPass = PR_FALSE;
9016 if (aCXused)
9017 *aCXused = nsnull;
9019 // get JSContext
9020 NS_ASSERTION(scx, "opening window missing its context");
9021 NS_ASSERTION(mDocument, "opening window missing its document");
9022 if (!scx || !mDocument)
9023 return NS_ERROR_FAILURE;
9025 nsCOMPtr<nsIDOMChromeWindow> chrome_win =
9026 do_QueryInterface(static_cast<nsIDOMWindow *>(this));
9028 if (nsContentUtils::IsCallerChrome() && !chrome_win) {
9029 // If open() is called from chrome on a non-chrome window, we'll
9030 // use the context from the window on which open() is being called
9031 // to prevent giving chrome priveleges to new windows opened in
9032 // such a way. This also makes us get the appropriate base URI for
9033 // the below URI resolution code.
9035 cx = (JSContext *)scx->GetNativeContext();
9036 } else {
9037 // get the JSContext from the call stack
9038 nsCOMPtr<nsIThreadJSContextStack> stack(do_GetService(sJSStackContractID));
9039 if (stack)
9040 stack->Peek(&cx);
9043 /* resolve the URI, which could be relative to the calling window
9044 (note the algorithm to get the base URI should match the one
9045 used to actually kick off the load in nsWindowWatcher.cpp). */
9046 nsCAutoString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
9047 nsIURI* baseURI = nsnull;
9048 nsCOMPtr<nsIURI> uriToLoad;
9049 nsCOMPtr<nsIDOMWindow> sourceWindow;
9051 if (cx) {
9052 nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx);
9053 if (scriptcx)
9054 sourceWindow = do_QueryInterface(scriptcx->GetGlobalObject());
9057 if (!sourceWindow) {
9058 sourceWindow = do_QueryInterface(NS_ISUPPORTS_CAST(nsIDOMWindow *, this));
9059 *aFreeSecurityPass = PR_TRUE;
9062 if (sourceWindow) {
9063 nsCOMPtr<nsIDOMDocument> domDoc;
9064 sourceWindow->GetDocument(getter_AddRefs(domDoc));
9065 nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
9066 if (doc) {
9067 baseURI = doc->GetDocBaseURI();
9068 charset = doc->GetDocumentCharacterSet();
9072 if (aCXused)
9073 *aCXused = cx;
9074 return NS_NewURI(aBuiltURI, nsDependentCString(aURL), charset.get(), baseURI);
9077 nsresult
9078 nsGlobalWindow::SecurityCheckURL(const char *aURL)
9080 JSContext *cx;
9081 PRBool freePass;
9082 nsCOMPtr<nsIURI> uri;
9084 if (NS_FAILED(BuildURIfromBase(aURL, getter_AddRefs(uri), &freePass, &cx)))
9085 return NS_ERROR_FAILURE;
9087 if (!freePass && NS_FAILED(nsContentUtils::GetSecurityManager()->
9088 CheckLoadURIFromScript(cx, uri)))
9089 return NS_ERROR_FAILURE;
9091 return NS_OK;
9094 void
9095 nsGlobalWindow::FlushPendingNotifications(mozFlushType aType)
9097 if (mDoc) {
9098 mDoc->FlushPendingNotifications(aType);
9102 void
9103 nsGlobalWindow::EnsureSizeUpToDate()
9105 // If we're a subframe, make sure our size is up to date. It's OK that this
9106 // crosses the content/chrome boundary, since chrome can have pending reflows
9107 // too.
9108 nsGlobalWindow *parent =
9109 static_cast<nsGlobalWindow *>(GetPrivateParent());
9110 if (parent) {
9111 parent->FlushPendingNotifications(Flush_Layout);
9115 nsresult
9116 nsGlobalWindow::SaveWindowState(nsISupports **aState)
9118 NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state");
9120 *aState = nsnull;
9122 if (!mContext || !mJSObject) {
9123 // The window may be getting torn down; don't bother saving state.
9124 return NS_OK;
9127 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
9128 NS_ASSERTION(inner, "No inner window to save");
9130 // Don't do anything else to this inner window! After this point, all
9131 // calls to SetTimeoutOrInterval will create entries in the timeout
9132 // list that will only run after this window has come out of the bfcache.
9133 // Also, while we're frozen, we won't dispatch online/offline events
9134 // to the page.
9135 inner->Freeze();
9137 // Remember the outer window's prototype.
9138 JSContext *cx = (JSContext *)mContext->GetNativeContext();
9139 JSAutoRequest req(cx);
9141 nsIXPConnect *xpc = nsContentUtils::XPConnect();
9143 nsCOMPtr<nsIClassInfo> ci =
9144 do_QueryInterface((nsIScriptGlobalObject *)this);
9145 nsCOMPtr<nsIXPConnectJSObjectHolder> proto;
9146 nsresult rv = xpc->GetWrappedNativePrototype(cx, mJSObject, ci,
9147 getter_AddRefs(proto));
9148 NS_ENSURE_SUCCESS(rv, rv);
9150 JSObject *realProto = JS_GetPrototype(cx, mJSObject);
9151 nsCOMPtr<nsIXPConnectJSObjectHolder> realProtoHolder;
9152 if (realProto) {
9153 rv = xpc->HoldObject(cx, realProto, getter_AddRefs(realProtoHolder));
9154 NS_ENSURE_SUCCESS(rv, rv);
9157 nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
9158 mInnerWindowHolder,
9159 mNavigator,
9160 proto,
9161 realProtoHolder);
9162 NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
9164 JSObject *wnProto;
9165 proto->GetJSObject(&wnProto);
9166 if (!JS_SetPrototype(cx, mJSObject, wnProto)) {
9167 return NS_ERROR_FAILURE;
9170 #ifdef DEBUG_PAGE_CACHE
9171 printf("saving window state, state = %p\n", (void*)state);
9172 #endif
9174 state.swap(*aState);
9175 return NS_OK;
9178 nsresult
9179 nsGlobalWindow::RestoreWindowState(nsISupports *aState)
9181 NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window");
9183 if (!mContext || !mJSObject) {
9184 // The window may be getting torn down; don't bother restoring state.
9185 return NS_OK;
9188 nsCOMPtr<WindowStateHolder> holder = do_QueryInterface(aState);
9189 NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE);
9191 #ifdef DEBUG_PAGE_CACHE
9192 printf("restoring window state, state = %p\n", (void*)holder);
9193 #endif
9195 // And we're ready to go!
9196 nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
9198 // if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes
9199 // it easy to tell which link was last clicked when going back a page.
9200 nsIContent* focusedNode = inner->GetFocusedNode();
9201 if (IsLink(focusedNode)) {
9202 nsIFocusManager* fm = nsFocusManager::GetFocusManager();
9203 if (fm) {
9204 nsCOMPtr<nsIDOMElement> focusedElement(do_QueryInterface(focusedNode));
9205 fm->SetFocus(focusedElement, nsIFocusManager::FLAG_NOSCROLL |
9206 nsIFocusManager::FLAG_SHOWRING);
9210 inner->Thaw();
9212 holder->DidRestoreWindow();
9214 return NS_OK;
9217 void
9218 nsGlobalWindow::SuspendTimeouts(PRUint32 aIncrease,
9219 PRBool aFreezeChildren)
9221 FORWARD_TO_INNER_VOID(SuspendTimeouts, (aIncrease, aFreezeChildren));
9223 PRBool suspended = (mTimeoutsSuspendDepth != 0);
9224 mTimeoutsSuspendDepth += aIncrease;
9226 if (!suspended) {
9227 nsDOMThreadService* dts = nsDOMThreadService::get();
9228 if (dts) {
9229 dts->SuspendWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
9232 TimeStamp now = TimeStamp::Now();
9233 for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
9234 // Set mTimeRemaining to be the time remaining for this timer.
9235 if (t->mWhen > now)
9236 t->mTimeRemaining = t->mWhen - now;
9237 else
9238 t->mTimeRemaining = TimeDuration(0);
9240 // Drop the XPCOM timer; we'll reschedule when restoring the state.
9241 if (t->mTimer) {
9242 t->mTimer->Cancel();
9243 t->mTimer = nsnull;
9245 // Drop the reference that the timer's closure had on this timeout, we'll
9246 // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
9247 // passing null for the context, since this shouldn't actually release this
9248 // timeout.
9249 t->Release();
9254 // Suspend our children as well.
9255 nsCOMPtr<nsIDocShellTreeNode> node(do_QueryInterface(GetDocShell()));
9256 if (node) {
9257 PRInt32 childCount = 0;
9258 node->GetChildCount(&childCount);
9260 for (PRInt32 i = 0; i < childCount; ++i) {
9261 nsCOMPtr<nsIDocShellTreeItem> childShell;
9262 node->GetChildAt(i, getter_AddRefs(childShell));
9263 NS_ASSERTION(childShell, "null child shell");
9265 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
9266 if (pWin) {
9267 nsGlobalWindow *win =
9268 static_cast<nsGlobalWindow*>
9269 (static_cast<nsPIDOMWindow*>(pWin));
9270 NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
9271 nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
9273 // This is a bit hackish. Only freeze/suspend windows which are truly our
9274 // subwindows.
9275 nsCOMPtr<nsIContent> frame = do_QueryInterface(pWin->GetFrameElementInternal());
9276 if (!mDoc || !frame || mDoc != frame->GetOwnerDoc() || !inner) {
9277 continue;
9280 win->SuspendTimeouts(aIncrease, aFreezeChildren);
9282 if (inner && aFreezeChildren) {
9283 inner->Freeze();
9290 nsresult
9291 nsGlobalWindow::ResumeTimeouts(PRBool aThawChildren)
9293 FORWARD_TO_INNER(ResumeTimeouts, (), NS_ERROR_NOT_INITIALIZED);
9295 NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!");
9296 --mTimeoutsSuspendDepth;
9297 PRBool shouldResume = (mTimeoutsSuspendDepth == 0);
9298 nsresult rv;
9300 if (shouldResume) {
9301 nsDOMThreadService* dts = nsDOMThreadService::get();
9302 if (dts) {
9303 dts->ResumeWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
9306 // Restore all of the timeouts, using the stored time remaining
9307 // (stored in timeout->mTimeRemaining).
9309 TimeStamp now = TimeStamp::Now();
9311 #ifdef DEBUG
9312 PRBool _seenDummyTimeout = PR_FALSE;
9313 #endif
9315 for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
9316 // There's a chance we're being called with RunTimeout on the stack in which
9317 // case we have a dummy timeout in the list that *must not* be resumed. It
9318 // can be identified by a null mWindow.
9319 if (!t->mWindow) {
9320 #ifdef DEBUG
9321 NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
9322 _seenDummyTimeout = PR_TRUE;
9323 #endif
9324 continue;
9327 // XXXbz the combination of the way |delay| and |t->mWhen| are set here
9328 // makes no sense. Are we trying to impose that min timeout value or
9329 // not???
9330 PRUint32 delay =
9331 NS_MAX(PRInt32(t->mTimeRemaining.ToMilliseconds()),
9332 DOM_MIN_TIMEOUT_VALUE);
9334 // Set mWhen back to the time when the timer is supposed to
9335 // fire.
9336 t->mWhen = now + t->mTimeRemaining;
9338 t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
9339 NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
9341 rv = t->mTimer->InitWithFuncCallback(TimerCallback, t, delay,
9342 nsITimer::TYPE_ONE_SHOT);
9343 if (NS_FAILED(rv)) {
9344 t->mTimer = nsnull;
9345 return rv;
9348 // Add a reference for the new timer's closure.
9349 t->AddRef();
9353 // Resume our children as well.
9354 nsCOMPtr<nsIDocShellTreeNode> node =
9355 do_QueryInterface(GetDocShell());
9356 if (node) {
9357 PRInt32 childCount = 0;
9358 node->GetChildCount(&childCount);
9360 for (PRInt32 i = 0; i < childCount; ++i) {
9361 nsCOMPtr<nsIDocShellTreeItem> childShell;
9362 node->GetChildAt(i, getter_AddRefs(childShell));
9363 NS_ASSERTION(childShell, "null child shell");
9365 nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
9366 if (pWin) {
9367 nsGlobalWindow *win =
9368 static_cast<nsGlobalWindow*>
9369 (static_cast<nsPIDOMWindow*>(pWin));
9371 NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
9372 nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
9374 // This is a bit hackish. Only thaw/resume windows which are truly our
9375 // subwindows.
9376 nsCOMPtr<nsIContent> frame = do_QueryInterface(pWin->GetFrameElementInternal());
9377 if (!mDoc || !frame || mDoc != frame->GetOwnerDoc() || !inner) {
9378 continue;
9381 if (inner && aThawChildren) {
9382 inner->Thaw();
9385 rv = win->ResumeTimeouts(aThawChildren);
9386 NS_ENSURE_SUCCESS(rv, rv);
9391 return NS_OK;
9394 PRUint32
9395 nsGlobalWindow::TimeoutSuspendCount()
9397 FORWARD_TO_INNER(TimeoutSuspendCount, (), 0);
9398 return mTimeoutsSuspendDepth;
9401 NS_IMETHODIMP
9402 nsGlobalWindow::GetScriptTypeID(PRUint32 *aScriptType)
9404 NS_ERROR("No default script type here - ask some element");
9405 return nsIProgrammingLanguage::UNKNOWN;
9408 NS_IMETHODIMP
9409 nsGlobalWindow::SetScriptTypeID(PRUint32 aScriptType)
9411 NS_ERROR("Can't change default script type for a document");
9412 return NS_ERROR_NOT_IMPLEMENTED;
9415 void
9416 nsGlobalWindow::SetHasOrientationEventListener()
9418 nsCOMPtr<nsIAccelerometer> ac =
9419 do_GetService(NS_ACCELEROMETER_CONTRACTID);
9421 if (ac) {
9422 mHasAcceleration = PR_TRUE;
9423 ac->AddWindowListener(this);
9427 // nsGlobalChromeWindow implementation
9429 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
9430 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
9431 nsGlobalWindow)
9432 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBrowserDOMWindow)
9433 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMessageManager)
9434 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
9436 DOMCI_DATA(ChromeWindow, nsGlobalChromeWindow)
9437 DOMCI_DATA(InnerChromeWindow, nsGlobalChromeWindow)
9439 // QueryInterface implementation for nsGlobalChromeWindow
9440 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)
9441 NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)
9442 WINDOW_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)
9443 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
9445 NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
9446 NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)
9448 NS_IMETHODIMP
9449 nsGlobalChromeWindow::GetWindowState(PRUint16* aWindowState)
9451 *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
9453 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9455 PRInt32 aMode = 0;
9457 if (widget) {
9458 nsresult rv = widget->GetSizeMode(&aMode);
9459 NS_ENSURE_SUCCESS(rv, rv);
9462 switch (aMode) {
9463 case nsSizeMode_Minimized:
9464 *aWindowState = nsIDOMChromeWindow::STATE_MINIMIZED;
9465 break;
9466 case nsSizeMode_Maximized:
9467 *aWindowState = nsIDOMChromeWindow::STATE_MAXIMIZED;
9468 break;
9469 case nsSizeMode_Fullscreen:
9470 *aWindowState = nsIDOMChromeWindow::STATE_FULLSCREEN;
9471 break;
9472 case nsSizeMode_Normal:
9473 *aWindowState = nsIDOMChromeWindow::STATE_NORMAL;
9474 break;
9475 default:
9476 NS_WARNING("Illegal window state for this chrome window");
9477 break;
9480 return NS_OK;
9483 NS_IMETHODIMP
9484 nsGlobalChromeWindow::Maximize()
9486 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9487 nsresult rv = NS_OK;
9489 if (widget) {
9490 rv = widget->SetSizeMode(nsSizeMode_Maximized);
9493 return rv;
9496 NS_IMETHODIMP
9497 nsGlobalChromeWindow::Minimize()
9499 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9500 nsresult rv = NS_OK;
9502 if (widget)
9503 rv = widget->SetSizeMode(nsSizeMode_Minimized);
9505 return rv;
9508 NS_IMETHODIMP
9509 nsGlobalChromeWindow::Restore()
9511 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9512 nsresult rv = NS_OK;
9514 if (widget) {
9515 rv = widget->SetSizeMode(nsSizeMode_Normal);
9518 return rv;
9521 NS_IMETHODIMP
9522 nsGlobalChromeWindow::GetAttention()
9524 return GetAttentionWithCycleCount(-1);
9527 NS_IMETHODIMP
9528 nsGlobalChromeWindow::GetAttentionWithCycleCount(PRInt32 aCycleCount)
9530 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9531 nsresult rv = NS_OK;
9533 if (widget) {
9534 rv = widget->GetAttention(aCycleCount);
9537 return rv;
9540 NS_IMETHODIMP
9541 nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent)
9543 nsCOMPtr<nsIWidget> widget = GetMainWidget();
9544 if (!widget) {
9545 return NS_OK;
9548 nsCOMPtr<nsIPrivateDOMEvent> privEvent = do_QueryInterface(aMouseDownEvent);
9549 NS_ENSURE_TRUE(privEvent, NS_ERROR_FAILURE);
9550 nsEvent *internalEvent = privEvent->GetInternalNSEvent();
9551 NS_ENSURE_TRUE(internalEvent &&
9552 internalEvent->eventStructType == NS_MOUSE_EVENT,
9553 NS_ERROR_FAILURE);
9554 nsMouseEvent *mouseEvent = static_cast<nsMouseEvent*>(internalEvent);
9556 return widget->BeginMoveDrag(mouseEvent);
9559 //Note: This call will lock the cursor, it will not change as it moves.
9560 //To unlock, the cursor must be set back to CURSOR_AUTO.
9561 NS_IMETHODIMP
9562 nsGlobalChromeWindow::SetCursor(const nsAString& aCursor)
9564 FORWARD_TO_OUTER_CHROME(SetCursor, (aCursor), NS_ERROR_NOT_INITIALIZED);
9566 nsresult rv = NS_OK;
9567 PRInt32 cursor;
9569 // use C strings to keep the code/data size down
9570 NS_ConvertUTF16toUTF8 cursorString(aCursor);
9572 if (cursorString.Equals("auto"))
9573 cursor = NS_STYLE_CURSOR_AUTO;
9574 else {
9575 nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aCursor);
9576 if (eCSSKeyword_UNKNOWN == keyword ||
9577 !nsCSSProps::FindKeyword(keyword, nsCSSProps::kCursorKTable, cursor)) {
9578 // XXX remove the following three values (leave return NS_OK) after 1.8
9579 // XXX since they should have been -moz- prefixed (covered by FindKeyword).
9580 // XXX (also remove |cursorString| at that point?).
9581 if (cursorString.Equals("grab"))
9582 cursor = NS_STYLE_CURSOR_GRAB;
9583 else if (cursorString.Equals("grabbing"))
9584 cursor = NS_STYLE_CURSOR_GRABBING;
9585 else if (cursorString.Equals("spinning"))
9586 cursor = NS_STYLE_CURSOR_SPINNING;
9587 else
9588 return NS_OK;
9592 nsRefPtr<nsPresContext> presContext;
9593 if (mDocShell) {
9594 mDocShell->GetPresContext(getter_AddRefs(presContext));
9597 if (presContext) {
9598 // Need root widget.
9599 nsCOMPtr<nsIPresShell> presShell;
9600 mDocShell->GetPresShell(getter_AddRefs(presShell));
9601 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
9603 nsIViewManager* vm = presShell->GetViewManager();
9604 NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
9606 nsIView *rootView;
9607 vm->GetRootView(rootView);
9608 NS_ENSURE_TRUE(rootView, NS_ERROR_FAILURE);
9610 nsIWidget* widget = rootView->GetNearestWidget(nsnull);
9611 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
9613 // Call esm and set cursor.
9614 rv = presContext->EventStateManager()->SetCursor(cursor, nsnull,
9615 PR_FALSE, 0.0f, 0.0f,
9616 widget, PR_TRUE);
9619 return rv;
9622 NS_IMETHODIMP
9623 nsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow **aBrowserWindow)
9625 FORWARD_TO_OUTER_CHROME(GetBrowserDOMWindow, (aBrowserWindow),
9626 NS_ERROR_NOT_INITIALIZED);
9628 NS_ENSURE_ARG_POINTER(aBrowserWindow);
9630 *aBrowserWindow = mBrowserDOMWindow;
9631 NS_IF_ADDREF(*aBrowserWindow);
9632 return NS_OK;
9635 NS_IMETHODIMP
9636 nsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow *aBrowserWindow)
9638 FORWARD_TO_OUTER_CHROME(SetBrowserDOMWindow, (aBrowserWindow),
9639 NS_ERROR_NOT_INITIALIZED);
9641 mBrowserDOMWindow = aBrowserWindow;
9642 return NS_OK;
9645 NS_IMETHODIMP
9646 nsGlobalChromeWindow::NotifyDefaultButtonLoaded(nsIDOMElement* aDefaultButton)
9648 #ifdef MOZ_XUL
9649 NS_ENSURE_ARG(aDefaultButton);
9651 // Don't snap to a disabled button.
9652 nsCOMPtr<nsIDOMXULControlElement> xulControl =
9653 do_QueryInterface(aDefaultButton);
9654 NS_ENSURE_TRUE(xulControl, NS_ERROR_FAILURE);
9655 PRBool disabled;
9656 nsresult rv = xulControl->GetDisabled(&disabled);
9657 NS_ENSURE_SUCCESS(rv, rv);
9658 if (disabled)
9659 return NS_OK;
9661 // Get the button rect in screen coordinates.
9662 nsCOMPtr<nsIContent> content(do_QueryInterface(aDefaultButton));
9663 NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
9664 nsIFrame *frame = content->GetPrimaryFrame();
9665 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
9666 nsIntRect buttonRect = frame->GetScreenRect();
9668 // Get the widget rect in screen coordinates.
9669 nsIWidget *widget = GetNearestWidget();
9670 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);
9671 nsIntRect widgetRect;
9672 rv = widget->GetScreenBounds(widgetRect);
9673 NS_ENSURE_SUCCESS(rv, rv);
9675 // Convert the buttonRect coordinates from screen to the widget.
9676 buttonRect -= widgetRect.TopLeft();
9677 rv = widget->OnDefaultButtonLoaded(buttonRect);
9678 if (rv == NS_ERROR_NOT_IMPLEMENTED)
9679 return NS_OK;
9680 return rv;
9681 #else
9682 return NS_ERROR_NOT_IMPLEMENTED;
9683 #endif
9686 NS_IMETHODIMP
9687 nsGlobalChromeWindow::GetMessageManager(nsIChromeFrameMessageManager** aManager)
9689 FORWARD_TO_INNER_CHROME(GetMessageManager, (aManager), NS_ERROR_FAILURE);
9690 if (!mMessageManager) {
9691 nsIScriptContext* scx = GetContextInternal();
9692 NS_ENSURE_STATE(scx);
9693 JSContext* cx = (JSContext *)scx->GetNativeContext();
9694 NS_ENSURE_STATE(cx);
9695 nsCOMPtr<nsIChromeFrameMessageManager> globalMM =
9696 do_GetService("@mozilla.org/globalmessagemanager;1");
9697 mMessageManager =
9698 new nsFrameMessageManager(PR_TRUE,
9699 nsnull,
9700 nsnull,
9701 nsnull,
9702 nsnull,
9703 static_cast<nsFrameMessageManager*>(globalMM.get()),
9704 cx);
9705 NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
9707 CallQueryInterface(mMessageManager, aManager);
9708 return NS_OK;
9711 // nsGlobalModalWindow implementation
9713 // QueryInterface implementation for nsGlobalModalWindow
9714 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalModalWindow)
9715 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalModalWindow,
9716 nsGlobalWindow)
9717 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReturnValue)
9718 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
9720 DOMCI_DATA(ModalContentWindow, nsGlobalModalWindow)
9721 DOMCI_DATA(InnerModalContentWindow, nsGlobalModalWindow)
9723 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalModalWindow)
9724 NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)
9725 WINDOW_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ModalContentWindow)
9726 NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)
9728 NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
9729 NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
9732 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalModalWindow,
9733 nsGlobalWindow)
9734 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReturnValue)
9735 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
9738 NS_IMETHODIMP
9739 nsGlobalModalWindow::GetDialogArguments(nsIArray **aArguments)
9741 FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments),
9742 NS_ERROR_NOT_INITIALIZED);
9744 PRBool subsumes = PR_FALSE;
9745 nsIPrincipal *self = GetPrincipal();
9746 if (self && NS_SUCCEEDED(self->Subsumes(mArgumentsOrigin, &subsumes)) &&
9747 subsumes) {
9748 NS_IF_ADDREF(*aArguments = mArguments);
9749 } else {
9750 *aArguments = nsnull;
9753 return NS_OK;
9756 NS_IMETHODIMP
9757 nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
9759 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
9761 NS_IF_ADDREF(*aRetVal = mReturnValue);
9763 return NS_OK;
9766 NS_IMETHODIMP
9767 nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal)
9769 FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK);
9771 mReturnValue = aRetVal;
9773 return NS_OK;
9776 nsresult
9777 nsGlobalModalWindow::SetNewDocument(nsIDocument *aDocument,
9778 nsISupports *aState)
9780 // If we're loading a new document into a modal dialog, clear the
9781 // return value that was set, if any, by the current document.
9782 if (aDocument) {
9783 mReturnValue = nsnull;
9786 return nsGlobalWindow::SetNewDocument(aDocument, aState);
9789 //*****************************************************************************
9790 // nsGlobalWindow: Creator Function (This should go away)
9791 //*****************************************************************************
9793 nsresult
9794 NS_NewScriptGlobalObject(PRBool aIsChrome, PRBool aIsModalContentWindow,
9795 nsIScriptGlobalObject **aResult)
9797 *aResult = nsnull;
9799 nsGlobalWindow *global;
9801 if (aIsChrome) {
9802 global = new nsGlobalChromeWindow(nsnull);
9803 } else if (aIsModalContentWindow) {
9804 global = new nsGlobalModalWindow(nsnull);
9805 } else {
9806 global = new nsGlobalWindow(nsnull);
9809 NS_ENSURE_TRUE(global, NS_ERROR_OUT_OF_MEMORY);
9811 NS_ADDREF(*aResult = global);
9813 return NS_OK;
9816 //*****************************************************************************
9817 //*** nsNavigator: Object Management
9818 //*****************************************************************************
9820 nsNavigator::nsNavigator(nsIDocShell *aDocShell)
9821 : mDocShell(aDocShell)
9825 nsNavigator::~nsNavigator()
9827 if (mMimeTypes)
9828 mMimeTypes->Invalidate();
9829 if (mPlugins)
9830 mPlugins->Invalidate();
9833 //*****************************************************************************
9834 // nsNavigator::nsISupports
9835 //*****************************************************************************
9838 DOMCI_DATA(Navigator, nsNavigator)
9840 // QueryInterface implementation for nsNavigator
9841 NS_INTERFACE_MAP_BEGIN(nsNavigator)
9842 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNavigator)
9843 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigator)
9844 NS_INTERFACE_MAP_ENTRY(nsIDOMClientInformation)
9845 NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorGeolocation)
9846 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
9847 NS_INTERFACE_MAP_END
9850 NS_IMPL_ADDREF(nsNavigator)
9851 NS_IMPL_RELEASE(nsNavigator)
9854 void
9855 nsNavigator::SetDocShell(nsIDocShell *aDocShell)
9857 mDocShell = aDocShell;
9858 if (mPlugins)
9859 mPlugins->SetDocShell(aDocShell);
9861 // if there is a page transition, make sure delete the geolocation object
9862 if (mGeolocation)
9864 mGeolocation->Shutdown();
9865 mGeolocation = nsnull;
9869 //*****************************************************************************
9870 // nsNavigator::nsIDOMNavigator
9871 //*****************************************************************************
9873 NS_IMETHODIMP
9874 nsNavigator::GetUserAgent(nsAString& aUserAgent)
9876 nsresult rv;
9877 nsCOMPtr<nsIHttpProtocolHandler>
9878 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9879 if (NS_SUCCEEDED(rv)) {
9880 nsCAutoString ua;
9881 rv = service->GetUserAgent(ua);
9882 CopyASCIItoUTF16(ua, aUserAgent);
9885 return rv;
9888 NS_IMETHODIMP
9889 nsNavigator::GetAppCodeName(nsAString& aAppCodeName)
9891 nsresult rv;
9892 nsCOMPtr<nsIHttpProtocolHandler>
9893 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9894 if (NS_SUCCEEDED(rv)) {
9895 nsCAutoString appName;
9896 rv = service->GetAppName(appName);
9897 CopyASCIItoUTF16(appName, aAppCodeName);
9900 return rv;
9903 NS_IMETHODIMP
9904 nsNavigator::GetAppVersion(nsAString& aAppVersion)
9906 if (!nsContentUtils::IsCallerTrustedForRead()) {
9907 const nsAdoptingCString& override =
9908 nsContentUtils::GetCharPref("general.appversion.override");
9910 if (override) {
9911 CopyUTF8toUTF16(override, aAppVersion);
9912 return NS_OK;
9916 nsresult rv;
9917 nsCOMPtr<nsIHttpProtocolHandler>
9918 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9919 if (NS_SUCCEEDED(rv)) {
9920 nsCAutoString str;
9921 rv = service->GetAppVersion(str);
9922 CopyASCIItoUTF16(str, aAppVersion);
9923 if (NS_FAILED(rv))
9924 return rv;
9926 aAppVersion.AppendLiteral(" (");
9928 rv = service->GetPlatform(str);
9929 if (NS_FAILED(rv))
9930 return rv;
9932 AppendASCIItoUTF16(str, aAppVersion);
9934 aAppVersion.Append(PRUnichar(')'));
9937 return rv;
9940 NS_IMETHODIMP
9941 nsNavigator::GetAppName(nsAString& aAppName)
9943 if (!nsContentUtils::IsCallerTrustedForRead()) {
9944 const nsAdoptingCString& override =
9945 nsContentUtils::GetCharPref("general.appname.override");
9947 if (override) {
9948 CopyUTF8toUTF16(override, aAppName);
9949 return NS_OK;
9953 aAppName.AssignLiteral("Netscape");
9954 return NS_OK;
9957 NS_IMETHODIMP
9958 nsNavigator::GetLanguage(nsAString& aLanguage)
9960 nsresult rv;
9961 nsCOMPtr<nsIHttpProtocolHandler>
9962 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9963 if (NS_SUCCEEDED(rv)) {
9964 nsCAutoString lang;
9965 rv = service->GetLanguage(lang);
9966 CopyASCIItoUTF16(lang, aLanguage);
9969 return rv;
9972 NS_IMETHODIMP
9973 nsNavigator::GetPlatform(nsAString& aPlatform)
9975 if (!nsContentUtils::IsCallerTrustedForRead()) {
9976 const nsAdoptingCString& override =
9977 nsContentUtils::GetCharPref("general.platform.override");
9979 if (override) {
9980 CopyUTF8toUTF16(override, aPlatform);
9981 return NS_OK;
9985 nsresult rv;
9986 nsCOMPtr<nsIHttpProtocolHandler>
9987 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
9988 if (NS_SUCCEEDED(rv)) {
9989 // sorry for the #if platform ugliness, but Communicator is
9990 // likewise hardcoded and we're seeking backward compatibility
9991 // here (bug 47080)
9992 #if defined(_WIN64)
9993 aPlatform.AssignLiteral("Win64");
9994 #elif defined(WIN32)
9995 aPlatform.AssignLiteral("Win32");
9996 #elif defined(XP_MACOSX) && defined(__ppc__)
9997 aPlatform.AssignLiteral("MacPPC");
9998 #elif defined(XP_MACOSX) && defined(__i386__)
9999 aPlatform.AssignLiteral("MacIntel");
10000 #elif defined(XP_MACOSX) && defined(__x86_64__)
10001 aPlatform.AssignLiteral("MacIntel");
10002 #elif defined(XP_OS2)
10003 aPlatform.AssignLiteral("OS/2");
10004 #else
10005 // XXX Communicator uses compiled-in build-time string defines
10006 // to indicate the platform it was compiled *for*, not what it is
10007 // currently running *on* which is what this does.
10008 nsCAutoString plat;
10009 rv = service->GetOscpu(plat);
10010 CopyASCIItoUTF16(plat, aPlatform);
10011 #endif
10014 return rv;
10017 NS_IMETHODIMP
10018 nsNavigator::GetOscpu(nsAString& aOSCPU)
10020 if (!nsContentUtils::IsCallerTrustedForRead()) {
10021 const nsAdoptingCString& override =
10022 nsContentUtils::GetCharPref("general.oscpu.override");
10024 if (override) {
10025 CopyUTF8toUTF16(override, aOSCPU);
10026 return NS_OK;
10030 nsresult rv;
10031 nsCOMPtr<nsIHttpProtocolHandler>
10032 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10033 if (NS_SUCCEEDED(rv)) {
10034 nsCAutoString oscpu;
10035 rv = service->GetOscpu(oscpu);
10036 CopyASCIItoUTF16(oscpu, aOSCPU);
10039 return rv;
10042 NS_IMETHODIMP
10043 nsNavigator::GetVendor(nsAString& aVendor)
10045 nsresult rv;
10046 nsCOMPtr<nsIHttpProtocolHandler>
10047 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10048 if (NS_SUCCEEDED(rv)) {
10049 nsCAutoString vendor;
10050 rv = service->GetVendor(vendor);
10051 CopyASCIItoUTF16(vendor, aVendor);
10054 return rv;
10058 NS_IMETHODIMP
10059 nsNavigator::GetVendorSub(nsAString& aVendorSub)
10061 nsresult rv;
10062 nsCOMPtr<nsIHttpProtocolHandler>
10063 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10064 if (NS_SUCCEEDED(rv)) {
10065 nsCAutoString vendor;
10066 rv = service->GetVendorSub(vendor);
10067 CopyASCIItoUTF16(vendor, aVendorSub);
10070 return rv;
10073 NS_IMETHODIMP
10074 nsNavigator::GetProduct(nsAString& aProduct)
10076 nsresult rv;
10077 nsCOMPtr<nsIHttpProtocolHandler>
10078 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10079 if (NS_SUCCEEDED(rv)) {
10080 nsCAutoString product;
10081 rv = service->GetProduct(product);
10082 CopyASCIItoUTF16(product, aProduct);
10085 return rv;
10088 NS_IMETHODIMP
10089 nsNavigator::GetProductSub(nsAString& aProductSub)
10091 if (!nsContentUtils::IsCallerTrustedForRead()) {
10092 const nsAdoptingCString& override =
10093 nsContentUtils::GetCharPref("general.productSub.override");
10095 if (override) {
10096 CopyUTF8toUTF16(override, aProductSub);
10097 return NS_OK;
10098 } else {
10099 // 'general.useragent.productSub' backwards compatible with 1.8 branch.
10100 const nsAdoptingCString& override2 =
10101 nsContentUtils::GetCharPref("general.useragent.productSub");
10103 if (override2) {
10104 CopyUTF8toUTF16(override2, aProductSub);
10105 return NS_OK;
10110 nsresult rv;
10111 nsCOMPtr<nsIHttpProtocolHandler>
10112 service(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
10113 if (NS_SUCCEEDED(rv)) {
10114 nsCAutoString productSub;
10115 rv = service->GetProductSub(productSub);
10116 CopyASCIItoUTF16(productSub, aProductSub);
10119 return rv;
10122 NS_IMETHODIMP
10123 nsNavigator::GetSecurityPolicy(nsAString& aSecurityPolicy)
10125 return NS_OK;
10128 NS_IMETHODIMP
10129 nsNavigator::GetMimeTypes(nsIDOMMimeTypeArray **aMimeTypes)
10131 if (!mMimeTypes) {
10132 mMimeTypes = new nsMimeTypeArray(this);
10133 if (!mMimeTypes) {
10134 return NS_ERROR_OUT_OF_MEMORY;
10138 NS_ADDREF(*aMimeTypes = mMimeTypes);
10140 return NS_OK;
10143 NS_IMETHODIMP
10144 nsNavigator::GetPlugins(nsIDOMPluginArray **aPlugins)
10146 if (!mPlugins) {
10147 mPlugins = new nsPluginArray(this, mDocShell);
10148 if (!mPlugins) {
10149 return NS_ERROR_OUT_OF_MEMORY;
10153 NS_ADDREF(*aPlugins = mPlugins);
10155 return NS_OK;
10158 // values for the network.cookie.cookieBehavior pref are documented in
10159 // nsCookieService.cpp.
10160 #define COOKIE_BEHAVIOR_REJECT 2
10162 NS_IMETHODIMP
10163 nsNavigator::GetCookieEnabled(PRBool *aCookieEnabled)
10165 *aCookieEnabled =
10166 (nsContentUtils::GetIntPref("network.cookie.cookieBehavior",
10167 COOKIE_BEHAVIOR_REJECT) !=
10168 COOKIE_BEHAVIOR_REJECT);
10170 return NS_OK;
10173 NS_IMETHODIMP
10174 nsNavigator::GetOnLine(PRBool* aOnline)
10176 NS_PRECONDITION(aOnline, "Null out param");
10178 *aOnline = !NS_IsOffline();
10179 return NS_OK;
10182 NS_IMETHODIMP
10183 nsNavigator::GetBuildID(nsAString& aBuildID)
10185 if (!nsContentUtils::IsCallerTrustedForRead()) {
10186 const nsAdoptingCString& override =
10187 nsContentUtils::GetCharPref("general.buildID.override");
10189 if (override) {
10190 CopyUTF8toUTF16(override, aBuildID);
10191 return NS_OK;
10195 nsCOMPtr<nsIXULAppInfo> appInfo =
10196 do_GetService("@mozilla.org/xre/app-info;1");
10197 if (!appInfo)
10198 return NS_ERROR_NOT_IMPLEMENTED;
10200 nsCAutoString buildID;
10201 nsresult rv = appInfo->GetAppBuildID(buildID);
10202 if (NS_FAILED(rv))
10203 return rv;
10205 aBuildID.Truncate();
10206 AppendASCIItoUTF16(buildID, aBuildID);
10207 return NS_OK;
10210 NS_IMETHODIMP
10211 nsNavigator::JavaEnabled(PRBool *aReturn)
10213 // Return true if we have a handler for "application/x-java-vm",
10214 // otherwise return false.
10215 *aReturn = PR_FALSE;
10217 if (!mMimeTypes) {
10218 mMimeTypes = new nsMimeTypeArray(this);
10219 if (!mMimeTypes)
10220 return NS_ERROR_OUT_OF_MEMORY;
10223 RefreshMIMEArray();
10225 PRUint32 count;
10226 mMimeTypes->GetLength(&count);
10227 for (PRUint32 i = 0; i < count; i++) {
10228 nsresult rv;
10229 nsIDOMMimeType* type = mMimeTypes->GetItemAt(i, &rv);
10230 nsAutoString mimeString;
10231 if (type && NS_SUCCEEDED(type->GetType(mimeString))) {
10232 if (mimeString.EqualsLiteral("application/x-java-vm")) {
10233 *aReturn = PR_TRUE;
10234 break;
10239 return NS_OK;
10242 NS_IMETHODIMP
10243 nsNavigator::TaintEnabled(PRBool *aReturn)
10245 *aReturn = PR_FALSE;
10246 return NS_OK;
10249 void
10250 nsNavigator::LoadingNewDocument()
10252 // Release these so that they will be recreated for the
10253 // new document (if requested). The plugins or mime types
10254 // arrays may have changed. See bug 150087.
10255 if (mMimeTypes) {
10256 mMimeTypes->Invalidate();
10257 mMimeTypes = nsnull;
10260 if (mPlugins) {
10261 mPlugins->Invalidate();
10262 mPlugins = nsnull;
10265 if (mGeolocation)
10267 mGeolocation->Shutdown();
10268 mGeolocation = nsnull;
10272 nsresult
10273 nsNavigator::RefreshMIMEArray()
10275 nsresult rv = NS_OK;
10276 if (mMimeTypes)
10277 rv = mMimeTypes->Refresh();
10278 return rv;
10281 //*****************************************************************************
10282 // nsNavigator::nsIDOMClientInformation
10283 //*****************************************************************************
10285 NS_IMETHODIMP
10286 nsNavigator::RegisterContentHandler(const nsAString& aMIMEType,
10287 const nsAString& aURI,
10288 const nsAString& aTitle)
10290 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
10291 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
10292 if (registrar && mDocShell) {
10293 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10294 if (contentDOMWindow)
10295 return registrar->RegisterContentHandler(aMIMEType, aURI, aTitle,
10296 contentDOMWindow);
10299 return NS_OK;
10302 NS_IMETHODIMP
10303 nsNavigator::RegisterProtocolHandler(const nsAString& aProtocol,
10304 const nsAString& aURI,
10305 const nsAString& aTitle)
10307 nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
10308 do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
10309 if (registrar && mDocShell) {
10310 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10311 if (contentDOMWindow)
10312 return registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle,
10313 contentDOMWindow);
10316 return NS_OK;
10320 NS_IMETHODIMP
10321 nsNavigator::MozIsLocallyAvailable(const nsAString &aURI,
10322 PRBool aWhenOffline,
10323 PRBool *aIsAvailable)
10325 nsCOMPtr<nsIURI> uri;
10326 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI);
10327 NS_ENSURE_SUCCESS(rv, rv);
10329 // This method of checking the cache will only work for http/https urls
10330 PRBool match;
10331 rv = uri->SchemeIs("http", &match);
10332 NS_ENSURE_SUCCESS(rv, rv);
10333 if (!match) {
10334 rv = uri->SchemeIs("https", &match);
10335 NS_ENSURE_SUCCESS(rv, rv);
10336 if (!match) return NS_ERROR_DOM_BAD_URI;
10339 // Same origin check
10340 nsCOMPtr<nsIJSContextStack> stack = do_GetService(sJSStackContractID);
10341 NS_ENSURE_TRUE(stack, NS_ERROR_FAILURE);
10343 JSContext *cx = nsnull;
10344 rv = stack->Peek(&cx);
10345 NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
10347 rv = nsContentUtils::GetSecurityManager()->CheckSameOrigin(cx, uri);
10348 NS_ENSURE_SUCCESS(rv, rv);
10350 // these load flags cause an error to be thrown if there is no
10351 // valid cache entry, and skip the load if there is.
10352 // if the cache is busy, assume that it is not yet available rather
10353 // than waiting for it to become available.
10354 PRUint32 loadFlags = nsIChannel::INHIBIT_CACHING |
10355 nsICachingChannel::LOAD_NO_NETWORK_IO |
10356 nsICachingChannel::LOAD_ONLY_IF_MODIFIED |
10357 nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
10359 if (aWhenOffline) {
10360 loadFlags |= nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE |
10361 nsICachingChannel::LOAD_ONLY_FROM_CACHE |
10362 nsIRequest::LOAD_FROM_CACHE;
10365 nsCOMPtr<nsIChannel> channel;
10366 rv = NS_NewChannel(getter_AddRefs(channel), uri,
10367 nsnull, nsnull, nsnull, loadFlags);
10368 NS_ENSURE_SUCCESS(rv, rv);
10370 nsCOMPtr<nsIInputStream> stream;
10371 rv = channel->Open(getter_AddRefs(stream));
10372 NS_ENSURE_SUCCESS(rv, rv);
10374 stream->Close();
10376 nsresult status;
10377 rv = channel->GetStatus(&status);
10378 NS_ENSURE_SUCCESS(rv, rv);
10380 if (NS_SUCCEEDED(status)) {
10381 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
10382 rv = httpChannel->GetRequestSucceeded(aIsAvailable);
10383 NS_ENSURE_SUCCESS(rv, rv);
10384 } else {
10385 *aIsAvailable = PR_FALSE;
10388 return NS_OK;
10391 //*****************************************************************************
10392 // nsNavigator::nsIDOMNavigatorGeolocation
10393 //*****************************************************************************
10395 NS_IMETHODIMP nsNavigator::GetGeolocation(nsIDOMGeoGeolocation **_retval)
10397 NS_ENSURE_ARG_POINTER(_retval);
10398 *_retval = nsnull;
10400 if (mGeolocation) {
10401 NS_ADDREF(*_retval = mGeolocation);
10402 return NS_OK;
10405 if (!mDocShell)
10406 return NS_ERROR_FAILURE;
10408 nsCOMPtr<nsIDOMWindow> contentDOMWindow(do_GetInterface(mDocShell));
10409 if (!contentDOMWindow)
10410 return NS_ERROR_FAILURE;
10412 mGeolocation = new nsGeolocation();
10413 if (!mGeolocation)
10414 return NS_ERROR_FAILURE;
10416 if (NS_FAILED(mGeolocation->Init(contentDOMWindow)))
10417 return NS_ERROR_FAILURE;
10419 NS_ADDREF(*_retval = mGeolocation);
10420 return NS_OK;